00001 #include "png_slave.h"
00002
00003 #include "thumbnailtool.h"
00004
00005 #include <qobject.h>
00006 #include <qfile.h>
00007 #include <qimage.h>
00008 #include <qpixmap.h>
00009 #include <qstring.h>
00010
00011
00012
00013
00014 PHUNK_VIEW_INTERFACE( "PNG", PNGSlave );
00015
00016 #define CHUNK_SIZE(data, index) ((data[index ]<<24) + (data[index+1]<<16) + \
00017 (data[index+2]<< 8) + data[index+3])
00018 #define CHUNK_TYPE(data, index) &data[index+4]
00019 #define CHUNK_HEADER_SIZE 12
00020 #define CHUNK_DATA(data, index, offset) data[8+index+offset]
00021
00022
00023
00024
00025 static const char* knownTranslations[]
00026 #ifdef __GNUC__
00027 __attribute__((unused))
00028 #endif
00029 = {
00030 QT_TR_NOOP("Title"),
00031 QT_TR_NOOP("Author"),
00032 QT_TR_NOOP("Description"),
00033 QT_TR_NOOP("Copyright"),
00034 QT_TR_NOOP("Creation Time"),
00035 QT_TR_NOOP("Software"),
00036 QT_TR_NOOP("Disclaimer"),
00037 QT_TR_NOOP("Warning"),
00038 QT_TR_NOOP("Source"),
00039 QT_TR_NOOP("Comment")
00040 };
00041
00042
00043 static const char* colors[] = {
00044 QT_TR_NOOP("Grayscale"),
00045 QT_TR_NOOP("Unknown"),
00046 QT_TR_NOOP("RGB"),
00047 QT_TR_NOOP("Palette"),
00048 QT_TR_NOOP("Grayscale/Alpha"),
00049 QT_TR_NOOP("Unknown"),
00050 QT_TR_NOOP("RGB/Alpha")
00051 };
00052
00053
00054 static const char* compressions[] =
00055 {
00056 QT_TR_NOOP("Deflate")
00057 };
00058
00059
00060 static const char* interlaceModes[] = {
00061 QT_TR_NOOP("None"),
00062 QT_TR_NOOP("Adam7")
00063 };
00064
00065
00066 static void read_comment( const QString& inf,
00067 bool readComments, QString& str ) {
00068 QFile f(inf);
00069 if (!f.exists()) return;
00070 if (!f.open(IO_ReadOnly)) return;
00071
00072 if (f.size() < 26) return;
00073
00074
00075
00076 uchar *data = new uchar[f.size()+1];
00077 f.readBlock(reinterpret_cast<char*>(data), f.size());
00078 data[f.size()]='\n';
00079
00080
00081 if (data[0] == 137 && data[1] == 80 && data[2] == 78 && data[3] == 71 &&
00082 data[4] == 13 && data[5] == 10 && data[6] == 26 && data[7] == 10 )
00083 {
00084
00085
00086 if (!strncmp((char*)&data[12], "IHDR", 4))
00087 {
00088
00089 ulong x,y;
00090 x = (data[16]<<24) + (data[17]<<16) + (data[18]<<8) + data[19];
00091 y = (data[20]<<24) + (data[21]<<16) + (data[22]<<8) + data[23];
00092
00093 uint type = data[25];
00094 uint bpp = data[24];
00095
00096
00097
00098 switch (type)
00099 {
00100 case 0: break;
00101 case 2: bpp *= 3; break;
00102 case 3: break;
00103 case 4: bpp *= 2; break;
00104 case 6: bpp *= 4; break;
00105
00106 default:
00107 bpp = 0;
00108 }
00109
00110
00111 str = QObject::tr("Dimensions: %1x%2\n" ).arg(x).arg(y);
00112 str += QObject::tr("Depth: %1\n" ).arg(bpp);
00113 str += QObject::tr("ColorMode: %1\n").arg(
00114 (type < sizeof(colors)/sizeof(colors[0]))
00115 ? QObject::tr(colors[data[25]]) : QObject::tr("Unknown") );
00116
00117 str += QObject::tr("Compression: %1\n").arg(
00118 (data[26] < sizeof(compressions)/sizeof(compressions[0]))
00119 ? QObject::tr(compressions[data[26]]) : QObject::tr("Unknown") );
00120
00121 str += QObject::tr("InterlaceMode: %1\n" ).arg(
00122 (data[28] < sizeof(interlaceModes)/sizeof(interlaceModes[0]))
00123 ? QObject::tr(interlaceModes[data[28]]) : QObject::tr("Unknown"));
00124 }
00125
00126 if ( readComments ) {
00127 uint index = 8;
00128 index += CHUNK_SIZE(data, index) + CHUNK_HEADER_SIZE;
00129
00130 while(index<f.size()-12)
00131 {
00132 while (index < f.size() - 12 &&
00133 strncmp((char*)CHUNK_TYPE(data,index), "tEXt", 4))
00134 {
00135 if (!strncmp((char*)CHUNK_TYPE(data,index), "IEND", 4))
00136 goto end;
00137
00138 index += CHUNK_SIZE(data, index) + CHUNK_HEADER_SIZE;
00139 }
00140
00141 if (index < f.size() - 12)
00142 {
00143
00144
00145
00146
00147 uchar* key = &CHUNK_DATA(data,index,0);
00148
00149 int keysize=0;
00150 for (;key[keysize]!=0; keysize++)
00151
00152
00153 if (8+index+keysize>=f.size())
00154 goto end;
00155
00156
00157 uchar* text = &CHUNK_DATA(data,index, keysize+1);
00158 uint textsize = CHUNK_SIZE(data, index)-keysize-1;
00159
00160
00161
00162 uint firstIndex = (uint)(text - data);
00163 uint onePastLastIndex = firstIndex + textsize;
00164
00165 if ( onePastLastIndex > f.size() || onePastLastIndex <= firstIndex)
00166 goto end;
00167
00168 QByteArray arr(textsize);
00169 arr = QByteArray(textsize).duplicate((const char*)text,
00170 textsize);
00171 str += QObject::tr(
00172 QString(reinterpret_cast<char*>(key)),
00173 QString(arr) );
00174
00175 index += CHUNK_SIZE(data, index) + CHUNK_HEADER_SIZE;
00176 }
00177 }
00178 }
00179 }
00180 end:
00181 delete[] data;
00182
00183 }
00184
00185
00186 PNGSlave::PNGSlave()
00187 : SlaveInterface("png")
00188 {
00189 }
00190 PNGSlave::~PNGSlave() {
00191 }
00192 QString PNGSlave::iconViewName( const QString& path) {
00193 QString str;
00194 read_comment( path, false, str );
00195 return str;
00196 }
00197
00198 QString PNGSlave::fullImageInfo( const QString& path) {
00199 QString str = "<qt>";
00200 read_comment( path, true, str );
00201 str += "</qt>";
00202 return str;
00203 }
00204
00205
00206 QPixmap PNGSlave::pixmap( const QString& path, int width, int height) {
00207 QImage img; img.load( path );
00208 if ( img.isNull() )
00209 return QPixmap();
00210 else
00211 return ThumbNailTool::scaleImage( img, width,height );
00212 }