Diffstat (limited to 'noncore/graphics/opie-eye/slave/png_slave.cpp') (more/less context) (show whitespace changes)
-rw-r--r-- | noncore/graphics/opie-eye/slave/png_slave.cpp | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/noncore/graphics/opie-eye/slave/png_slave.cpp b/noncore/graphics/opie-eye/slave/png_slave.cpp new file mode 100644 index 0000000..72b93cc --- a/dev/null +++ b/noncore/graphics/opie-eye/slave/png_slave.cpp | |||
@@ -0,0 +1,210 @@ | |||
1 | #include "png_slave.h" | ||
2 | |||
3 | #include "thumbnailtool.h" | ||
4 | |||
5 | #include <qobject.h> | ||
6 | #include <qfile.h> | ||
7 | #include <qimage.h> | ||
8 | #include <qpixmap.h> | ||
9 | #include <qstring.h> | ||
10 | |||
11 | /* | ||
12 | * GPLv2 from kfile plugin | ||
13 | */ | ||
14 | PHUNK_VIEW_INTERFACE( "PNG", PNGSlave ); | ||
15 | |||
16 | #define CHUNK_SIZE(data, index) ((data[index ]<<24) + (data[index+1]<<16) + \ | ||
17 | (data[index+2]<< 8) + data[index+3]) | ||
18 | #define CHUNK_TYPE(data, index) &data[index+4] | ||
19 | #define CHUNK_HEADER_SIZE 12 | ||
20 | #define CHUNK_DATA(data, index, offset) data[8+index+offset] | ||
21 | |||
22 | /* TRANSLATOR QObject */ | ||
23 | |||
24 | // known translations for common png keys | ||
25 | static const char* knownTranslations[] | ||
26 | #ifdef __GNUC__ | ||
27 | __attribute__((unused)) | ||
28 | #endif | ||
29 | = { | ||
30 | QT_TR_NOOP("Title"), | ||
31 | QT_TR_NOOP("Author"), | ||
32 | QT_TR_NOOP("Description"), | ||
33 | QT_TR_NOOP("Copyright"), | ||
34 | QT_TR_NOOP("Creation Time"), | ||
35 | QT_TR_NOOP("Software"), | ||
36 | QT_TR_NOOP("Disclaimer"), | ||
37 | QT_TR_NOOP("Warning"), | ||
38 | QT_TR_NOOP("Source"), | ||
39 | QT_TR_NOOP("Comment") | ||
40 | }; | ||
41 | |||
42 | // and for the colors | ||
43 | static const char* colors[] = { | ||
44 | QT_TR_NOOP("Grayscale"), | ||
45 | QT_TR_NOOP("Unknown"), | ||
46 | QT_TR_NOOP("RGB"), | ||
47 | QT_TR_NOOP("Palette"), | ||
48 | QT_TR_NOOP("Grayscale/Alpha"), | ||
49 | QT_TR_NOOP("Unknown"), | ||
50 | QT_TR_NOOP("RGB/Alpha") | ||
51 | }; | ||
52 | |||
53 | // and compressions | ||
54 | static const char* compressions[] = | ||
55 | { | ||
56 | QT_TR_NOOP("Deflate") | ||
57 | }; | ||
58 | |||
59 | // interlaced modes | ||
60 | static const char* interlaceModes[] = { | ||
61 | QT_TR_NOOP("None"), | ||
62 | QT_TR_NOOP("Adam7") | ||
63 | }; | ||
64 | |||
65 | |||
66 | static void read_comment( const QString& inf, | ||
67 | bool readComments, QString& str ) { | ||
68 | QFile f(inf); | ||
69 | f.open(IO_ReadOnly); | ||
70 | |||
71 | if (f.size() < 26) return; | ||
72 | // the technical group will be read from the first 26 bytes. If the file | ||
73 | // is smaller, we can't even read this. | ||
74 | |||
75 | uchar *data = new uchar[f.size()+1]; | ||
76 | f.readBlock(reinterpret_cast<char*>(data), f.size()); | ||
77 | data[f.size()]='\n'; | ||
78 | |||
79 | // find the start | ||
80 | if (data[0] == 137 && data[1] == 80 && data[2] == 78 && data[3] == 71 && | ||
81 | data[4] == 13 && data[5] == 10 && data[6] == 26 && data[7] == 10 ) | ||
82 | { | ||
83 | // ok | ||
84 | // the IHDR chunk should be the first | ||
85 | if (!strncmp((char*)&data[12], "IHDR", 4)) | ||
86 | { | ||
87 | // we found it, get the dimensions | ||
88 | ulong x,y; | ||
89 | x = (data[16]<<24) + (data[17]<<16) + (data[18]<<8) + data[19]; | ||
90 | y = (data[20]<<24) + (data[21]<<16) + (data[22]<<8) + data[23]; | ||
91 | |||
92 | uint type = data[25]; | ||
93 | uint bpp = data[24]; | ||
94 | |||
95 | // the bpp are only per channel, so we need to multiply the with | ||
96 | // the channel count | ||
97 | switch (type) | ||
98 | { | ||
99 | case 0: break; // Grayscale | ||
100 | case 2: bpp *= 3; break; // RGB | ||
101 | case 3: break; // palette | ||
102 | case 4: bpp *= 2; break; // grayscale w. alpha | ||
103 | case 6: bpp *= 4; break; // RGBA | ||
104 | |||
105 | default: // we don't get any sensible value here | ||
106 | bpp = 0; | ||
107 | } | ||
108 | |||
109 | |||
110 | str = QObject::tr("Dimensions: %1x%2\n" ).arg(x).arg(y); | ||
111 | str += QObject::tr("Depth: %1\n" ).arg(bpp); | ||
112 | str += QObject::tr("ColorMode: %1\n").arg( | ||
113 | (type < sizeof(colors)/sizeof(colors[0])) | ||
114 | ? QObject::tr(colors[data[25]]) : QObject::tr("Unknown") ); | ||
115 | |||
116 | str += QObject::tr("Compression: %1\n").arg( | ||
117 | (data[26] < sizeof(compressions)/sizeof(compressions[0])) | ||
118 | ? QObject::tr(compressions[data[26]]) : QObject::tr("Unknown") ); | ||
119 | |||
120 | str += QObject::tr("InterlaceMode: %1\n" ).arg( | ||
121 | (data[28] < sizeof(interlaceModes)/sizeof(interlaceModes[0])) | ||
122 | ? QObject::tr(interlaceModes[data[28]]) : QObject::tr("Unknown")); | ||
123 | } | ||
124 | |||
125 | if ( readComments ) { | ||
126 | uint index = 8; | ||
127 | index += CHUNK_SIZE(data, index) + CHUNK_HEADER_SIZE; | ||
128 | |||
129 | while(index<f.size()-12) | ||
130 | { | ||
131 | while (index < f.size() - 12 && | ||
132 | strncmp((char*)CHUNK_TYPE(data,index), "tEXt", 4)) | ||
133 | { | ||
134 | if (!strncmp((char*)CHUNK_TYPE(data,index), "IEND", 4)) | ||
135 | goto end; | ||
136 | |||
137 | index += CHUNK_SIZE(data, index) + CHUNK_HEADER_SIZE; | ||
138 | } | ||
139 | |||
140 | if (index < f.size() - 12) | ||
141 | { | ||
142 | // we found a tEXt field | ||
143 | // get the key, it's a null terminated string at the | ||
144 | // chunk start | ||
145 | |||
146 | uchar* key = &CHUNK_DATA(data,index,0); | ||
147 | |||
148 | int keysize=0; | ||
149 | for (;key[keysize]!=0; keysize++) | ||
150 | // look if we reached the end of the file | ||
151 | // (it might be corrupted) | ||
152 | if (8+index+keysize>=f.size()) | ||
153 | goto end; | ||
154 | |||
155 | // the text comes after the key, but isn't null terminated | ||
156 | uchar* text = &CHUNK_DATA(data,index, keysize+1); | ||
157 | uint textsize = CHUNK_SIZE(data, index)-keysize-1; | ||
158 | |||
159 | // security check, also considering overflow wraparound from the addition -- | ||
160 | // we may endup with a /smaller/ index if we wrap all the way around | ||
161 | uint firstIndex = (uint)(text - data); | ||
162 | uint onePastLastIndex = firstIndex + textsize; | ||
163 | |||
164 | if ( onePastLastIndex > f.size() || onePastLastIndex <= firstIndex) | ||
165 | goto end; | ||
166 | |||
167 | QByteArray arr(textsize); | ||
168 | arr = QByteArray(textsize).duplicate((const char*)text, | ||
169 | textsize); | ||
170 | str += QObject::tr( | ||
171 | QString(reinterpret_cast<char*>(key)), | ||
172 | QString(arr) ); | ||
173 | |||
174 | index += CHUNK_SIZE(data, index) + CHUNK_HEADER_SIZE; | ||
175 | } | ||
176 | } | ||
177 | } | ||
178 | } | ||
179 | end: | ||
180 | delete[] data; | ||
181 | |||
182 | } | ||
183 | |||
184 | |||
185 | PNGSlave::PNGSlave() | ||
186 | : SlaveInterface("png") | ||
187 | { | ||
188 | } | ||
189 | PNGSlave::~PNGSlave() { | ||
190 | } | ||
191 | QString PNGSlave::iconViewName( const QString& path) { | ||
192 | QString str; | ||
193 | read_comment( path, false, str ); | ||
194 | return str; | ||
195 | } | ||
196 | |||
197 | QString PNGSlave::fullImageInfo( const QString& path) { | ||
198 | QString str; | ||
199 | read_comment( path, true, str ); | ||
200 | return str; | ||
201 | } | ||
202 | |||
203 | |||
204 | QPixmap PNGSlave::pixmap( const QString& path, int width, int height) { | ||
205 | QImage img; img.load( path ); | ||
206 | if ( img.isNull() ) | ||
207 | return QPixmap(); | ||
208 | else | ||
209 | return ThumbNailTool::scaleImage( img, width,height ); | ||
210 | } | ||