• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

KImgIO

psd.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE project
00002    Copyright (C) 2003 Ignacio Castaņo <castano@ludicon.com>
00003 
00004    This program is free software; you can redistribute it and/or
00005    modify it under the terms of the Lesser GNU General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This code is based on Thacher Ulrich PSD loading code released
00010    on public domain. See: http://tulrich.com/geekstuff/
00011 */
00012 
00013 /* this code supports:
00014  * reading:
00015  *     rle and raw psd files
00016  * writing:
00017  *     not supported
00018  */
00019 
00020 #include "psd.h"
00021 
00022 #include <qimage.h>
00023 #include <qdatastream.h>
00024 
00025 #include <kdebug.h>
00026 
00027 typedef Q_UINT32 uint;
00028 typedef Q_UINT16 ushort;
00029 typedef Q_UINT8 uchar;
00030 
00031 namespace { // Private.
00032 
00033     enum ColorMode {
00034         CM_BITMAP = 0,
00035         CM_GRAYSCALE = 1,
00036         CM_INDEXED = 2,
00037         CM_RGB = 3,
00038         CM_CMYK = 4,
00039         CM_MULTICHANNEL = 7,
00040         CM_DUOTONE = 8,
00041         CM_LABCOLOR = 9
00042     };
00043 
00044     struct PSDHeader {
00045         uint signature;
00046         ushort version;
00047         uchar reserved[6];
00048         ushort channel_count;
00049         uint height;
00050         uint width;
00051         ushort depth;
00052         ushort color_mode;
00053     };
00054     
00055     static QDataStream & operator>> ( QDataStream & s, PSDHeader & header )
00056     {
00057         s >> header.signature;
00058         s >> header.version;
00059         for( int i = 0; i < 6; i++ ) {
00060             s >> header.reserved[i];
00061         }
00062         s >> header.channel_count;
00063         s >> header.height;
00064         s >> header.width;
00065         s >> header.depth;
00066         s >> header.color_mode;
00067         return s;
00068     }
00069         static bool seekBy(QDataStream& s, unsigned int bytes)
00070         {
00071                 char buf[4096];
00072                 while (bytes) {
00073                         unsigned int num= QMIN(bytes,sizeof(buf));
00074                         unsigned int l = num;
00075                         s.readRawBytes(buf, l);
00076                         if(l != num)
00077                           return false;
00078                         bytes -= num;
00079                 }
00080                 return true;
00081         }
00082 
00083     // Check that the header is a valid PSD.
00084     static bool IsValid( const PSDHeader & header )
00085     {
00086         if( header.signature != 0x38425053 ) {  // '8BPS'
00087             return false;
00088         }
00089         return true;
00090     }
00091 
00092     // Check that the header is supported.
00093     static bool IsSupported( const PSDHeader & header )
00094     {
00095         if( header.version != 1 ) {
00096             return false;
00097         }
00098         if( header.channel_count > 16 ) {
00099             return false;
00100         }
00101         if( header.depth != 8 ) {
00102             return false;
00103         }
00104         if( header.color_mode != CM_RGB ) {
00105             return false;
00106         }
00107         return true;
00108     }
00109 
00110     // Load the PSD image.
00111     static bool LoadPSD( QDataStream & s, const PSDHeader & header, QImage & img )
00112     {
00113         // Create dst image.
00114         if( !img.create( header.width, header.height, 32 )) {
00115             return false;
00116         }
00117     
00118         uint tmp;
00119 
00120         // Skip mode data.
00121         s >> tmp;
00122         s.device()->at( s.device()->at() + tmp );
00123 
00124         // Skip image resources.
00125         s >> tmp;
00126         s.device()->at( s.device()->at() + tmp );
00127 
00128         // Skip the reserved data.
00129         s >> tmp;
00130         s.device()->at( s.device()->at() + tmp );
00131         
00132         // Find out if the data is compressed.
00133         // Known values:
00134         //   0: no compression
00135         //   1: RLE compressed
00136         ushort compression;
00137         s >> compression;
00138         
00139         if( compression > 1 ) {
00140             // Unknown compression type.
00141             return false;
00142         }
00143 
00144         uint channel_num = header.channel_count;
00145         
00146         // Clear the image.
00147         if( channel_num < 4 ) {
00148             img.fill(qRgba(0, 0, 0, 0xFF));
00149         }
00150         else {
00151             // Enable alpha.        
00152             img.setAlphaBuffer( true );
00153             
00154             // Ignore the other channels.
00155             channel_num = 4;            
00156         }
00157         
00158         const uint pixel_count = header.height * header.width;
00159         
00160         static const uint components[4] = {2, 1, 0, 3}; // @@ Is this endian dependant?
00161         
00162         if( compression ) {
00163         
00164             // Skip row lengths.
00165                         if(!seekBy(s, header.height*header.channel_count*sizeof(ushort)))
00166                                 return false;
00167 
00168             // Read RLE data.                       
00169             for(uint channel = 0; channel < channel_num; channel++) {
00170             
00171                 uchar * ptr = img.bits() + components[channel];
00172                 
00173                 uint count = 0;
00174                 while( count < pixel_count ) {
00175                     uchar c;
00176                                         if(s.atEnd())
00177                                                 return false;
00178                     s >> c;
00179                     uint len = c;
00180                     
00181                     if( len < 128 ) {
00182                         // Copy next len+1 bytes literally.
00183                         len++;
00184                         count += len;
00185                                                 if ( count > pixel_count )
00186                                                         return false;
00187 
00188                         while( len != 0 ) {
00189                             s >> *ptr;
00190                             ptr += 4;
00191                             len--;
00192                         }
00193                     } 
00194                     else if( len > 128 ) {
00195                         // Next -len+1 bytes in the dest are replicated from next source byte.
00196                         // (Interpret len as a negative 8-bit int.)
00197                         len ^= 0xFF;
00198                         len += 2;
00199                         count += len;
00200                                                 if(s.atEnd() || count > pixel_count)
00201                                                         return false;
00202                         uchar val;
00203                         s >> val;
00204                         while( len != 0 ) {
00205                             *ptr = val;
00206                             ptr += 4;
00207                             len--;
00208                         }
00209                     }
00210                     else if( len == 128 ) {
00211                         // No-op.
00212                     }
00213                 }
00214             }
00215         }
00216         else {
00217             // We're at the raw image data.  It's each channel in order (Red, Green, Blue, Alpha, ...)
00218             // where each channel consists of an 8-bit value for each pixel in the image.
00219 
00220             // Read the data by channel.
00221             for(uint channel = 0; channel < channel_num; channel++) {
00222 
00223                 uchar * ptr = img.bits() + components[channel];
00224             
00225                 // Read the data.
00226                 uint count = pixel_count;
00227                 while( count != 0 ) {
00228                     s >> *ptr;
00229                     ptr += 4;
00230                     count--;
00231                 }
00232             }
00233         }
00234 
00235         return true;
00236     }
00237 
00238 } // Private
00239 
00240 
00241 void kimgio_psd_read( QImageIO *io )
00242 {
00243     QDataStream s( io->ioDevice() );
00244     s.setByteOrder( QDataStream::BigEndian );
00245 
00246     PSDHeader header;
00247     s >> header;
00248 
00249     // Check image file format.
00250     if( s.atEnd() || !IsValid( header ) ) {
00251         kdDebug(399) << "This PSD file is not valid." << endl;
00252         io->setImage( 0 );
00253         io->setStatus( -1 );
00254         return;
00255     }
00256 
00257     // Check if it's a supported format.
00258     if( !IsSupported( header ) ) {
00259         kdDebug(399) << "This PSD file is not supported." << endl;
00260         io->setImage( 0 );
00261         io->setStatus( -1 );
00262         return;
00263     }
00264 
00265     QImage img;
00266     if( !LoadPSD(s, header, img) ) {
00267         kdDebug(399) << "Error loading PSD file." << endl;
00268         io->setImage( 0 );
00269         io->setStatus( -1 );
00270         return;
00271     }
00272 
00273     io->setImage( img );
00274     io->setStatus( 0 );
00275 }
00276 
00277 
00278 void kimgio_psd_write( QImageIO * )
00279 {
00280     // TODO Stub!
00281 }
00282 

KImgIO

Skip menu "KImgIO"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal