• 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 
26 namespace
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< QRgb > colorTable( paletteSize );
173 
174  colorTable.fill( QRgb( 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  QRgb* p = reinterpret_cast< QRgb* >( 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  QRgb* p = reinterpret_cast< QRgb* >( lines[ y ] );
234  for ( unsigned x = 0; x < rec.width; ++x, ++p )
235  if ( ( ( buf[ x / 8 ] >> ( 7 - ( x & 0x07 ) ) ) & 1 ) )
236  *p &= TQRGB_MASK;
237  }
238  delete[] buf;
239  }
240  return true;
241  }
242 }
243 
244 extern "C" KDE_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
314 void 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
  •     tdecore
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  • tdeioslave
  •   http
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for kimgio by doxygen 1.8.8
This website is maintained by Timothy Pearson.