KImgIO
psd.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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 {
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
00084 static bool IsValid( const PSDHeader & header )
00085 {
00086 if( header.signature != 0x38425053 ) {
00087 return false;
00088 }
00089 return true;
00090 }
00091
00092
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
00111 static bool LoadPSD( QDataStream & s, const PSDHeader & header, QImage & img )
00112 {
00113
00114 if( !img.create( header.width, header.height, 32 )) {
00115 return false;
00116 }
00117
00118 uint tmp;
00119
00120
00121 s >> tmp;
00122 s.device()->at( s.device()->at() + tmp );
00123
00124
00125 s >> tmp;
00126 s.device()->at( s.device()->at() + tmp );
00127
00128
00129 s >> tmp;
00130 s.device()->at( s.device()->at() + tmp );
00131
00132
00133
00134
00135
00136 ushort compression;
00137 s >> compression;
00138
00139 if( compression > 1 ) {
00140
00141 return false;
00142 }
00143
00144 uint channel_num = header.channel_count;
00145
00146
00147 if( channel_num < 4 ) {
00148 img.fill(qRgba(0, 0, 0, 0xFF));
00149 }
00150 else {
00151
00152 img.setAlphaBuffer( true );
00153
00154
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};
00161
00162 if( compression ) {
00163
00164
00165 if(!seekBy(s, header.height*header.channel_count*sizeof(ushort)))
00166 return false;
00167
00168
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
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
00196
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
00212 }
00213 }
00214 }
00215 }
00216 else {
00217
00218
00219
00220
00221 for(uint channel = 0; channel < channel_num; channel++) {
00222
00223 uchar * ptr = img.bits() + components[channel];
00224
00225
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 }
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
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
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
00281 }
00282