psd.cpp
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 <tqimage.h> 00023 #include <tqdatastream.h> 00024 00025 #include <kdebug.h> 00026 00027 typedef TQ_UINT32 uint; 00028 typedef TQ_UINT16 ushort; 00029 typedef TQ_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 TQDataStream & operator>> ( TQDataStream & 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(TQDataStream& s, unsigned int bytes) 00070 { 00071 char buf[4096]; 00072 while (bytes) { 00073 unsigned int num= TQMIN(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( TQDataStream & s, const PSDHeader & header, TQImage & 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(tqRgba(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( TQImageIO *io ) 00242 { 00243 TQDataStream s( io->ioDevice() ); 00244 s.setByteOrder( TQDataStream::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( TQImage() ); 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( TQImage() ); 00261 io->setStatus( -1 ); 00262 return; 00263 } 00264 00265 TQImage img; 00266 if( !LoadPSD(s, header, img) ) { 00267 kdDebug(399) << "Error loading PSD file." << endl; 00268 io->setImage( TQImage() ); 00269 io->setStatus( -1 ); 00270 return; 00271 } 00272 00273 io->setImage( img ); 00274 io->setStatus( 0 ); 00275 } 00276 00277 00278 void kimgio_psd_write( TQImageIO * ) 00279 { 00280 // TODO Stub! 00281 } 00282