• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kimgio
 

kimgio

  • kimgio
ico.cpp
1
2/*
3 * $Id$
4 * kimgio import filter for MS Windows .ico files
5 *
6 * Distributed under the terms of the LGPL
7 * Copyright (c) 2000 Malte Starostik <malte@kde.org>
8 *
9 */
10
11#include <cstring>
12#include <cstdlib>
13#include <algorithm>
14#include <vector>
15
16#include <tqimage.h>
17#include <tqbitmap.h>
18#include <tqapplication.h>
19#include <tqmemarray.h>
20#include <tqpaintdevicemetrics.h>
21
22#include <tdelibs_export.h>
23
24#include "ico.h"
25
26namespace
27{
28 // Global header
29 struct IcoHeader
30 {
31 enum Type { Icon = 1, Cursor };
32 TQ_UINT16 reserved;
33 TQ_UINT16 type;
34 TQ_UINT16 count;
35 };
36
37 inline TQDataStream& operator >>( TQDataStream& s, IcoHeader& h )
38 {
39 return s >> h.reserved >> h.type >> h.count;
40 }
41
42 // Based on qt_read_dib et al. from qimage.cpp
43 // (c) 1992-2002 Trolltech AS.
44 struct BMP_INFOHDR
45 {
46 static const TQ_UINT32 Size = 40;
47 TQ_UINT32 biSize; // size of this struct
48 TQ_UINT32 biWidth; // pixmap width
49 TQ_UINT32 biHeight; // pixmap height
50 TQ_UINT16 biPlanes; // should be 1
51 TQ_UINT16 biBitCount; // number of bits per pixel
52 enum Compression { RGB = 0 };
53 TQ_UINT32 biCompression; // compression method
54 TQ_UINT32 biSizeImage; // size of image
55 TQ_UINT32 biXPelsPerMeter; // horizontal resolution
56 TQ_UINT32 biYPelsPerMeter; // vertical resolution
57 TQ_UINT32 biClrUsed; // number of colors used
58 TQ_UINT32 biClrImportant; // number of important colors
59 };
60 const TQ_UINT32 BMP_INFOHDR::Size;
61
62 TQDataStream& operator >>( TQDataStream &s, BMP_INFOHDR &bi )
63 {
64 s >> bi.biSize;
65 if ( bi.biSize == BMP_INFOHDR::Size )
66 {
67 s >> bi.biWidth >> bi.biHeight >> bi.biPlanes >> bi.biBitCount;
68 s >> bi.biCompression >> bi.biSizeImage;
69 s >> bi.biXPelsPerMeter >> bi.biYPelsPerMeter;
70 s >> bi.biClrUsed >> bi.biClrImportant;
71 }
72 return s;
73 }
74
75#if 0
76 TQDataStream &operator<<( TQDataStream &s, const BMP_INFOHDR &bi )
77 {
78 s << bi.biSize;
79 s << bi.biWidth << bi.biHeight;
80 s << bi.biPlanes;
81 s << bi.biBitCount;
82 s << bi.biCompression;
83 s << bi.biSizeImage;
84 s << bi.biXPelsPerMeter << bi.biYPelsPerMeter;
85 s << bi.biClrUsed << bi.biClrImportant;
86 return s;
87 }
88#endif
89
90 // Header for every icon in the file
91 struct IconRec
92 {
93 unsigned char width;
94 unsigned char height;
95 TQ_UINT16 colors;
96 TQ_UINT16 hotspotX;
97 TQ_UINT16 hotspotY;
98 TQ_UINT32 size;
99 TQ_UINT32 offset;
100 };
101
102 inline TQDataStream& operator >>( TQDataStream& s, IconRec& r )
103 {
104 return s >> r.width >> r.height >> r.colors
105 >> r.hotspotX >> r.hotspotY >> r.size >> r.offset;
106 }
107
108 struct LessDifference
109 {
110 LessDifference( unsigned s, unsigned c )
111 : size( s ), colors( c ) {}
112
113 bool operator ()( const IconRec& lhs, const IconRec& rhs ) const
114 {
115 // closest size match precedes everything else
116 if ( std::abs( int( lhs.width - size ) ) <
117 std::abs( int( rhs.width - size ) ) ) return true;
118 else if ( std::abs( int( lhs.width - size ) ) >
119 std::abs( int( rhs.width - size ) ) ) return false;
120 else if ( colors == 0 )
121 {
122 // high/true color requested
123 if ( lhs.colors == 0 ) return true;
124 else if ( rhs.colors == 0 ) return false;
125 else return lhs.colors > rhs.colors;
126 }
127 else
128 {
129 // indexed icon requested
130 if ( lhs.colors == 0 && rhs.colors == 0 ) return false;
131 else if ( lhs.colors == 0 ) return false;
132 else return std::abs( int( lhs.colors - colors ) ) <
133 std::abs( int( rhs.colors - colors ) );
134 }
135 }
136 unsigned size;
137 unsigned colors;
138 };
139
140 bool loadFromDIB( TQDataStream& stream, const IconRec& rec, TQImage& icon )
141 {
142 BMP_INFOHDR header;
143 stream >> header;
144 if ( stream.atEnd() || header.biSize != BMP_INFOHDR::Size ||
145 header.biSize > rec.size ||
146 header.biCompression != BMP_INFOHDR::RGB ||
147 ( header.biBitCount != 1 && header.biBitCount != 4 &&
148 header.biBitCount != 8 && header.biBitCount != 24 &&
149 header.biBitCount != 32 ) ) return false;
150
151 unsigned paletteSize, paletteEntries;
152
153 if (header.biBitCount > 8)
154 {
155 paletteEntries = 0;
156 paletteSize = 0;
157 }
158 else
159 {
160 paletteSize = (1 << header.biBitCount);
161 paletteEntries = paletteSize;
162 if (header.biClrUsed && header.biClrUsed < paletteSize)
163 paletteEntries = header.biClrUsed;
164 }
165
166 // Always create a 32-bit image to get the mask right
167 // Note: this is safe as rec.width, rec.height are bytes
168 icon.create( rec.width, rec.height, 32 );
169 if ( icon.isNull() ) return false;
170 icon.setAlphaBuffer( true );
171
172 TQMemArray< TQRgb > colorTable( paletteSize );
173
174 colorTable.fill( TQRgb( 0 ) );
175 for ( unsigned i = 0; i < paletteEntries; ++i )
176 {
177 unsigned char rgb[ 4 ];
178 stream.readRawBytes( reinterpret_cast< char* >( &rgb ),
179 sizeof( rgb ) );
180 colorTable[ i ] = tqRgb( rgb[ 2 ], rgb[ 1 ], rgb[ 0 ] );
181 }
182
183 unsigned bpl = ( rec.width * header.biBitCount + 31 ) / 32 * 4;
184
185 unsigned char* buf = new unsigned char[ bpl ];
186 unsigned char** lines = icon.jumpTable();
187 for ( unsigned y = rec.height; !stream.atEnd() && y--; )
188 {
189 stream.readRawBytes( reinterpret_cast< char* >( buf ), bpl );
190 unsigned char* pixel = buf;
191 TQRgb* p = reinterpret_cast< TQRgb* >( lines[ y ] );
192 switch ( header.biBitCount )
193 {
194 case 1:
195 for ( unsigned x = 0; x < rec.width; ++x )
196 *p++ = colorTable[
197 ( pixel[ x / 8 ] >> ( 7 - ( x & 0x07 ) ) ) & 1 ];
198 break;
199 case 4:
200 for ( unsigned x = 0; x < rec.width; ++x )
201 if ( x & 1 ) *p++ = colorTable[ pixel[ x / 2 ] & 0x0f ];
202 else *p++ = colorTable[ pixel[ x / 2 ] >> 4 ];
203 break;
204 case 8:
205 for ( unsigned x = 0; x < rec.width; ++x )
206 *p++ = colorTable[ pixel[ x ] ];
207 break;
208 case 24:
209 for ( unsigned x = 0; x < rec.width; ++x )
210 *p++ = tqRgb( pixel[ 3 * x + 2 ],
211 pixel[ 3 * x + 1 ],
212 pixel[ 3 * x ] );
213 break;
214 case 32:
215 for ( unsigned x = 0; x < rec.width; ++x )
216 *p++ = tqRgba( pixel[ 4 * x + 2 ],
217 pixel[ 4 * x + 1 ],
218 pixel[ 4 * x ],
219 pixel[ 4 * x + 3] );
220 break;
221 }
222 }
223 delete[] buf;
224
225 if ( header.biBitCount < 32 )
226 {
227 // Traditional 1-bit mask
228 bpl = ( rec.width + 31 ) / 32 * 4;
229 buf = new unsigned char[ bpl ];
230 for ( unsigned y = rec.height; y--; )
231 {
232 stream.readRawBytes( reinterpret_cast< char* >( buf ), bpl );
233 TQRgb* p = reinterpret_cast< TQRgb* >( lines[ y ] );
234 for ( unsigned x = 0; x < rec.width; ++x, ++p )
235 if ( ( ( buf[ x / 8 ] >> ( 7 - ( x & 0x07 ) ) ) & 1 ) )
236 *p &= TQT_RGB_MASK;
237 }
238 delete[] buf;
239 }
240 return true;
241 }
242}
243
244extern "C" TDE_EXPORT void kimgio_ico_read( TQImageIO* io )
245{
246 TQIODevice::Offset offset = io->ioDevice()->at();
247
248 TQDataStream stream( io->ioDevice() );
249 stream.setByteOrder( TQDataStream::LittleEndian );
250 IcoHeader header;
251 stream >> header;
252 if ( stream.atEnd() || !header.count ||
253 ( header.type != IcoHeader::Icon && header.type != IcoHeader::Cursor) )
254 return;
255
256 TQPaintDeviceMetrics metrics( TQApplication::desktop() );
257 unsigned requestedSize = 32;
258 unsigned requestedColors = metrics.depth() > 8 ? 0 : metrics.depth();
259 int requestedIndex = -1;
260 if ( io->parameters() )
261 {
262 TQStringList params = TQStringList::split( ';', io->parameters() );
263 TQMap< TQString, TQString > options;
264 for ( TQStringList::ConstIterator it = params.begin();
265 it != params.end(); ++it )
266 {
267 TQStringList tmp = TQStringList::split( '=', *it );
268 if ( tmp.count() == 2 ) options[ tmp[ 0 ] ] = tmp[ 1 ];
269 }
270 if ( options[ "index" ].toUInt() )
271 requestedIndex = options[ "index" ].toUInt();
272 if ( options[ "size" ].toUInt() )
273 requestedSize = options[ "size" ].toUInt();
274 if ( options[ "colors" ].toUInt() )
275 requestedColors = options[ "colors" ].toUInt();
276 }
277
278 typedef std::vector< IconRec > IconList;
279 IconList icons;
280 for ( unsigned i = 0; i < header.count; ++i )
281 {
282 if ( stream.atEnd() ) return;
283 IconRec rec;
284 stream >> rec;
285 icons.push_back( rec );
286 }
287 IconList::const_iterator selected;
288 if (requestedIndex >= 0) {
289 selected = std::min( icons.begin() + requestedIndex, icons.end() );
290 } else {
291 selected = std::min_element( icons.begin(), icons.end(),
292 LessDifference( requestedSize, requestedColors ) );
293 }
294 if ( stream.atEnd() || selected == icons.end() ||
295 offset + selected->offset > io->ioDevice()->size() )
296 return;
297
298 io->ioDevice()->at( offset + selected->offset );
299 TQImage icon;
300 if ( loadFromDIB( stream, *selected, icon ) )
301 {
302 icon.setText( "X-Index", 0, TQString::number( selected - icons.begin() ) );
303 if ( header.type == IcoHeader::Cursor )
304 {
305 icon.setText( "X-HotspotX", 0, TQString::number( selected->hotspotX ) );
306 icon.setText( "X-HotspotY", 0, TQString::number( selected->hotspotY ) );
307 }
308 io->setImage(icon);
309 io->setStatus(0);
310 }
311}
312
313#if 0
314void kimgio_ico_write(TQImageIO *io)
315{
316 if (io->image().isNull())
317 return;
318
319 TQByteArray dibData;
320 TQDataStream dib(dibData, IO_ReadWrite);
321 dib.setByteOrder(TQDataStream::LittleEndian);
322
323 TQImage pixels = io->image();
324 TQImage mask;
325 if (io->image().hasAlphaBuffer())
326 mask = io->image().createAlphaMask();
327 else
328 mask = io->image().createHeuristicMask();
329 mask.invertPixels();
330 for ( int y = 0; y < pixels.height(); ++y )
331 for ( int x = 0; x < pixels.width(); ++x )
332 if ( mask.pixel( x, y ) == 0 ) pixels.setPixel( x, y, 0 );
333
334 if (!qt_write_dib(dib, pixels))
335 return;
336
337 uint hdrPos = dib.device()->at();
338 if (!qt_write_dib(dib, mask))
339 return;
340 memmove(dibData.data() + hdrPos, dibData.data() + hdrPos + BMP_WIN + 8, dibData.size() - hdrPos - BMP_WIN - 8);
341 dibData.resize(dibData.size() - BMP_WIN - 8);
342
343 TQDataStream ico(io->ioDevice());
344 ico.setByteOrder(TQDataStream::LittleEndian);
345 IcoHeader hdr;
346 hdr.reserved = 0;
347 hdr.type = Icon;
348 hdr.count = 1;
349 ico << hdr.reserved << hdr.type << hdr.count;
350 IconRec rec;
351 rec.width = io->image().width();
352 rec.height = io->image().height();
353 if (io->image().numColors() <= 16)
354 rec.colors = 16;
355 else if (io->image().depth() <= 8)
356 rec.colors = 256;
357 else
358 rec.colors = 0;
359 rec.hotspotX = 0;
360 rec.hotspotY = 0;
361 rec.dibSize = dibData.size();
362 ico << rec.width << rec.height << rec.colors
363 << rec.hotspotX << rec.hotspotY << rec.dibSize;
364 rec.dibOffset = ico.device()->at() + sizeof(rec.dibOffset);
365 ico << rec.dibOffset;
366
367 BMP_INFOHDR dibHeader;
368 dib.device()->at(0);
369 dib >> dibHeader;
370 dibHeader.biHeight = io->image().height() << 1;
371 dib.device()->at(0);
372 dib << dibHeader;
373
374 ico.writeRawBytes(dibData.data(), dibData.size());
375 io->setStatus(0);
376}
377#endif

kimgio

Skip menu "kimgio"
  • Main Page
  • File List
  • Related Pages

kimgio

Skip menu "kimgio"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for kimgio by doxygen 1.9.4
This website is maintained by Timothy Pearson.