18 #include <tqapplication.h>
19 #include <tqmemarray.h>
20 #include <tqpaintdevicemetrics.h>
22 #include <tdelibs_export.h>
31 enum Type { Icon = 1, Cursor };
37 inline TQDataStream& operator >>( TQDataStream& s, IcoHeader& h )
39 return s >> h.reserved >> h.type >> h.count;
46 static const TQ_UINT32 Size = 40;
52 enum Compression { RGB = 0 };
53 TQ_UINT32 biCompression;
54 TQ_UINT32 biSizeImage;
55 TQ_UINT32 biXPelsPerMeter;
56 TQ_UINT32 biYPelsPerMeter;
58 TQ_UINT32 biClrImportant;
60 const TQ_UINT32 BMP_INFOHDR::Size;
62 TQDataStream& operator >>( TQDataStream &s, BMP_INFOHDR &bi )
65 if ( bi.biSize == BMP_INFOHDR::Size )
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;
76 TQDataStream &operator<<( TQDataStream &s,
const BMP_INFOHDR &bi )
79 s << bi.biWidth << bi.biHeight;
82 s << bi.biCompression;
84 s << bi.biXPelsPerMeter << bi.biYPelsPerMeter;
85 s << bi.biClrUsed << bi.biClrImportant;
102 inline TQDataStream& operator >>( TQDataStream& s, IconRec& r )
104 return s >> r.width >> r.height >> r.colors
105 >> r.hotspotX >> r.hotspotY >> r.size >> r.offset;
108 struct LessDifference
110 LessDifference(
unsigned s,
unsigned c )
111 : size( s ), colors( c ) {}
113 bool operator ()(
const IconRec& lhs,
const IconRec& rhs )
const
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 )
123 if ( lhs.colors == 0 )
return true;
124 else if ( rhs.colors == 0 )
return false;
125 else return lhs.colors > rhs.colors;
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 ) );
140 bool loadFromDIB( TQDataStream& stream,
const IconRec& rec, TQImage& icon )
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;
151 unsigned paletteSize, paletteEntries;
153 if (header.biBitCount > 8)
160 paletteSize = (1 << header.biBitCount);
161 paletteEntries = paletteSize;
162 if (header.biClrUsed && header.biClrUsed < paletteSize)
163 paletteEntries = header.biClrUsed;
168 icon.create( rec.width, rec.height, 32 );
169 if ( icon.isNull() )
return false;
170 icon.setAlphaBuffer(
true );
172 TQMemArray< TQRgb > colorTable( paletteSize );
174 colorTable.fill( TQRgb( 0 ) );
175 for (
unsigned i = 0; i < paletteEntries; ++i )
177 unsigned char rgb[ 4 ];
178 stream.readRawBytes(
reinterpret_cast< char*
>( &rgb ),
180 colorTable[ i ] = tqRgb( rgb[ 2 ], rgb[ 1 ], rgb[ 0 ] );
183 unsigned bpl = ( rec.width * header.biBitCount + 31 ) / 32 * 4;
185 unsigned char* buf =
new unsigned char[ bpl ];
186 unsigned char** lines = icon.jumpTable();
187 for (
unsigned y = rec.height; !stream.atEnd() && y--; )
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 )
195 for (
unsigned x = 0; x < rec.width; ++x )
197 ( pixel[ x / 8 ] >> ( 7 - ( x & 0x07 ) ) ) & 1 ];
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 ];
205 for (
unsigned x = 0; x < rec.width; ++x )
206 *p++ = colorTable[ pixel[ x ] ];
209 for (
unsigned x = 0; x < rec.width; ++x )
210 *p++ = tqRgb( pixel[ 3 * x + 2 ],
215 for (
unsigned x = 0; x < rec.width; ++x )
216 *p++ = tqRgba( pixel[ 4 * x + 2 ],
225 if ( header.biBitCount < 32 )
228 bpl = ( rec.width + 31 ) / 32 * 4;
229 buf =
new unsigned char[ bpl ];
230 for (
unsigned y = rec.height; y--; )
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 ) )
244 extern "C" TDE_EXPORT
void kimgio_ico_read( TQImageIO* io )
246 TQIODevice::Offset offset = io->ioDevice()->at();
248 TQDataStream stream( io->ioDevice() );
249 stream.setByteOrder( TQDataStream::LittleEndian );
252 if ( stream.atEnd() || !header.count ||
253 ( header.type != IcoHeader::Icon && header.type != IcoHeader::Cursor) )
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() )
262 TQStringList params = TQStringList::split(
';', io->parameters() );
263 TQMap< TQString, TQString > options;
264 for ( TQStringList::ConstIterator it = params.begin();
265 it != params.end(); ++it )
267 TQStringList tmp = TQStringList::split(
'=', *it );
268 if ( tmp.count() == 2 ) options[ tmp[ 0 ] ] = tmp[ 1 ];
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();
278 typedef std::vector< IconRec > IconList;
280 for (
unsigned i = 0; i < header.count; ++i )
282 if ( stream.atEnd() )
return;
285 icons.push_back( rec );
287 IconList::const_iterator selected;
288 if (requestedIndex >= 0) {
289 selected = std::min( icons.begin() + requestedIndex, icons.end() );
291 selected = std::min_element( icons.begin(), icons.end(),
292 LessDifference( requestedSize, requestedColors ) );
294 if ( stream.atEnd() || selected == icons.end() ||
295 offset + selected->offset > io->ioDevice()->size() )
298 io->ioDevice()->at( offset + selected->offset );
300 if ( loadFromDIB( stream, *selected, icon ) )
302 icon.setText(
"X-Index", 0, TQString::number( selected - icons.begin() ) );
303 if ( header.type == IcoHeader::Cursor )
305 icon.setText(
"X-HotspotX", 0, TQString::number( selected->hotspotX ) );
306 icon.setText(
"X-HotspotY", 0, TQString::number( selected->hotspotY ) );
314 void kimgio_ico_write(TQImageIO *io)
316 if (io->image().isNull())
320 TQDataStream dib(dibData, IO_ReadWrite);
321 dib.setByteOrder(TQDataStream::LittleEndian);
323 TQImage pixels = io->image();
325 if (io->image().hasAlphaBuffer())
326 mask = io->image().createAlphaMask();
328 mask = io->image().createHeuristicMask();
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 );
334 if (!qt_write_dib(dib, pixels))
337 uint hdrPos = dib.device()->at();
338 if (!qt_write_dib(dib, mask))
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);
343 TQDataStream ico(io->ioDevice());
344 ico.setByteOrder(TQDataStream::LittleEndian);
349 ico << hdr.reserved << hdr.type << hdr.count;
351 rec.width = io->image().width();
352 rec.height = io->image().height();
353 if (io->image().numColors() <= 16)
355 else if (io->image().depth() <= 8)
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;
367 BMP_INFOHDR dibHeader;
370 dibHeader.biHeight = io->image().height() << 1;
374 ico.writeRawBytes(dibData.data(), dibData.size());