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

kimgio

  • kimgio
rgb.cpp
1 // kimgio module for SGI images
2 //
3 // Copyright (C) 2004 Melchior FRANZ <mfranz@kde.org>
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the Lesser GNU General Public License as
7 // published by the Free Software Foundation; either version 2 of the
8 // License, or (at your option) any later version.
9 
10 
11 /* this code supports:
12  * reading:
13  * everything, except images with 1 dimension or images with
14  * mapmode != NORMAL (e.g. dithered); Images with 16 bit
15  * precision or more than 4 layers are stripped down.
16  * writing:
17  * Run Length Encoded (RLE) or Verbatim (uncompressed)
18  * (whichever is smaller)
19  *
20  * Please report if you come across rgb/rgba/sgi/bw files that aren't
21  * recognized. Also report applications that can't deal with images
22  * saved by this filter.
23  */
24 
25 
26 #include "rgb.h"
27 #include <tqimage.h>
28 #include <kdebug.h>
29 
30 
32 
33 
34 TDE_EXPORT void kimgio_rgb_read(TQImageIO *io)
35 {
36  SGIImage sgi(io);
37  TQImage img;
38 
39  if (!sgi.readImage(img)) {
40  io->setImage(TQImage());
41  io->setStatus(-1);
42  return;
43  }
44 
45  io->setImage(img);
46  io->setStatus(0);
47 }
48 
49 
50 TDE_EXPORT void kimgio_rgb_write(TQImageIO *io)
51 {
52  SGIImage sgi(io);
53  TQImage img = io->image();
54 
55  if (!sgi.writeImage(img))
56  io->setStatus(-1);
57 
58  io->setStatus(0);
59 }
60 
61 
63 
64 
65 SGIImage::SGIImage(TQImageIO *io) :
66  m_io(io),
67  m_starttab(0),
68  m_lengthtab(0)
69 {
70  m_dev = io->ioDevice();
71  m_stream.setDevice(m_dev);
72 }
73 
74 
75 SGIImage::~SGIImage()
76 {
77  delete[] m_starttab;
78  delete[] m_lengthtab;
79 }
80 
81 
83 
84 
85 bool SGIImage::getRow(uchar *dest)
86 {
87  int n, i;
88  if (!m_rle) {
89  for (i = 0; i < m_xsize; i++) {
90  if (m_pos >= m_data.end())
91  return false;
92  dest[i] = uchar(*m_pos);
93  m_pos += m_bpc;
94  }
95  return true;
96  }
97 
98  for (i = 0; i < m_xsize;) {
99  if (m_bpc == 2)
100  m_pos++;
101  n = *m_pos & 0x7f;
102  if (!n)
103  break;
104 
105  if (*m_pos++ & 0x80) {
106  for (; i < m_xsize && n--; i++) {
107  *dest++ = *m_pos;
108  m_pos += m_bpc;
109  }
110  } else {
111  for (; i < m_xsize && n--; i++)
112  *dest++ = *m_pos;
113 
114  m_pos += m_bpc;
115  }
116  }
117  return i == m_xsize;
118 }
119 
120 
121 bool SGIImage::readData(TQImage& img)
122 {
123  TQRgb *c;
124  TQ_UINT32 *start = m_starttab;
125  TQByteArray lguard(m_xsize);
126  uchar *line = (uchar *)lguard.data();
127  unsigned x, y;
128 
129  if (!m_rle)
130  m_pos = m_data.begin();
131 
132  for (y = 0; y < m_ysize; y++) {
133  if (m_rle)
134  m_pos = m_data.begin() + *start++;
135  if (!getRow(line))
136  return false;
137  c = (TQRgb *)img.scanLine(m_ysize - y - 1);
138  for (x = 0; x < m_xsize; x++, c++)
139  *c = tqRgb(line[x], line[x], line[x]);
140  }
141 
142  if (m_zsize == 1)
143  return true;
144 
145  if (m_zsize != 2) {
146  for (y = 0; y < m_ysize; y++) {
147  if (m_rle)
148  m_pos = m_data.begin() + *start++;
149  if (!getRow(line))
150  return false;
151  c = (TQRgb *)img.scanLine(m_ysize - y - 1);
152  for (x = 0; x < m_xsize; x++, c++)
153  *c = tqRgb(tqRed(*c), line[x], line[x]);
154  }
155 
156  for (y = 0; y < m_ysize; y++) {
157  if (m_rle)
158  m_pos = m_data.begin() + *start++;
159  if (!getRow(line))
160  return false;
161  c = (TQRgb *)img.scanLine(m_ysize - y - 1);
162  for (x = 0; x < m_xsize; x++, c++)
163  *c = tqRgb(tqRed(*c), tqGreen(*c), line[x]);
164  }
165 
166  if (m_zsize == 3)
167  return true;
168  }
169 
170  for (y = 0; y < m_ysize; y++) {
171  if (m_rle)
172  m_pos = m_data.begin() + *start++;
173  if (!getRow(line))
174  return false;
175  c = (TQRgb *)img.scanLine(m_ysize - y - 1);
176  for (x = 0; x < m_xsize; x++, c++)
177  *c = tqRgba(tqRed(*c), tqGreen(*c), tqBlue(*c), line[x]);
178  }
179 
180  return true;
181 }
182 
183 
184 bool SGIImage::readImage(TQImage& img)
185 {
186  TQ_INT8 u8;
187  TQ_INT16 u16;
188  TQ_INT32 u32;
189 
190  kdDebug(399) << "reading '" << m_io->fileName() << '\'' << endl;
191 
192  // magic
193  m_stream >> u16;
194  if (u16 != 0x01da)
195  return false;
196 
197  // verbatim/rle
198  m_stream >> m_rle;
199  kdDebug(399) << (m_rle ? "RLE" : "verbatim") << endl;
200  if (m_rle > 1)
201  return false;
202 
203  // bytes per channel
204  m_stream >> m_bpc;
205  kdDebug(399) << "bytes per channel: " << int(m_bpc) << endl;
206  if (m_bpc == 1)
207  ;
208  else if (m_bpc == 2)
209  kdDebug(399) << "dropping least significant byte" << endl;
210  else
211  return false;
212 
213  // number of dimensions
214  m_stream >> m_dim;
215  kdDebug(399) << "dimensions: " << m_dim << endl;
216  if (m_dim < 1 || m_dim > 3)
217  return false;
218 
219  m_stream >> m_xsize >> m_ysize >> m_zsize >> m_pixmin >> m_pixmax >> u32;
220  kdDebug(399) << "x: " << m_xsize << endl;
221  kdDebug(399) << "y: " << m_ysize << endl;
222  kdDebug(399) << "z: " << m_zsize << endl;
223 
224  // name
225  m_stream.readRawBytes(m_imagename, 80);
226  m_imagename[79] = '\0';
227  m_io->setDescription(m_imagename);
228 
229  m_stream >> m_colormap;
230  kdDebug(399) << "colormap: " << m_colormap << endl;
231  if (m_colormap != NORMAL)
232  return false; // only NORMAL supported
233 
234  for (int i = 0; i < 404; i++)
235  m_stream >> u8;
236 
237  if (m_dim == 1) {
238  kdDebug(399) << "1-dimensional images aren't supported yet" << endl;
239  return false;
240  }
241 
242  if( m_stream.atEnd())
243  return false;
244 
245  m_numrows = m_ysize * m_zsize;
246 
247  if (!img.create(m_xsize, m_ysize, 32)) {
248  kdDebug(399) << "cannot create image" << endl;
249  return false;
250  }
251 
252  if (m_zsize == 2 || m_zsize == 4)
253  img.setAlphaBuffer(true);
254  else if (m_zsize > 4)
255  kdDebug(399) << "using first 4 of " << m_zsize << " channels" << endl;
256 
257  if (m_rle) {
258  uint l;
259  m_starttab = new TQ_UINT32[m_numrows];
260  for (l = 0; !m_stream.atEnd() && l < m_numrows; l++) {
261  m_stream >> m_starttab[l];
262  m_starttab[l] -= 512 + m_numrows * 2 * sizeof(TQ_UINT32);
263  }
264 
265  m_lengthtab = new TQ_UINT32[m_numrows];
266  for (l = 0; l < m_numrows; l++)
267  m_stream >> m_lengthtab[l];
268  }
269 
270  m_data = m_dev->readAll();
271 
272  // sanity check
273  if (m_rle)
274  for (uint o = 0; o < m_numrows; o++)
275  // don't change to greater-or-equal!
276  if (m_starttab[o] + m_lengthtab[o] > m_data.size()) {
277  kdDebug(399) << "image corrupt (sanity check failed)" << endl;
278  return false;
279  }
280 
281  if (!readData(img)) {
282  kdDebug(399) << "image corrupt (incomplete scanline)" << endl;
283  return false;
284  }
285 
286  return true;
287 }
288 
289 
291 
292 
293 // TODO remove; for debugging purposes only
294 void RLEData::print(TQString desc) const
295 {
296  TQString s = desc + ": ";
297  for (uint i = 0; i < size(); i++)
298  s += TQString::number(at(i)) + ",";
299  kdDebug() << "--- " << s << endl;
300 }
301 
302 
303 void RLEData::write(TQDataStream& s)
304 {
305  for (unsigned i = 0; i < size(); i++)
306  s << at(i);
307 }
308 
309 
310 bool RLEData::operator<(const RLEData& b) const
311 {
312  uchar ac, bc;
313  for (unsigned i = 0; i < TQMIN(size(), b.size()); i++) {
314  ac = at(i);
315  bc = b[i];
316  if (ac != bc)
317  return ac < bc;
318  }
319  return size() < b.size();
320 }
321 
322 
323 uint RLEMap::insert(const uchar *d, uint l)
324 {
325  RLEData data = RLEData(d, l, m_offset);
326  Iterator it = find(data);
327  if (it != end())
328  return it.data();
329 
330  m_offset += l;
331  return TQMap<RLEData, uint>::insert(data, m_counter++).data();
332 }
333 
334 
335 TQPtrVector<RLEData> RLEMap::vector()
336 {
337  TQPtrVector<RLEData> v(size());
338  for (Iterator it = begin(); it != end(); ++it)
339  v.insert(it.data(), &it.key());
340 
341  return v;
342 }
343 
344 
345 uchar SGIImage::intensity(uchar c)
346 {
347  if (c < m_pixmin)
348  m_pixmin = c;
349  if (c > m_pixmax)
350  m_pixmax = c;
351  return c;
352 }
353 
354 
355 uint SGIImage::compact(uchar *d, uchar *s)
356 {
357  uchar *dest = d, *src = s, patt, *t, *end = s + m_xsize;
358  int i, n;
359  while (src < end) {
360  for (n = 0, t = src; t + 2 < end && !(*t == t[1] && *t == t[2]); t++)
361  n++;
362 
363  while (n) {
364  i = n > 126 ? 126 : n;
365  n -= i;
366  *dest++ = 0x80 | i;
367  while (i--)
368  *dest++ = *src++;
369  }
370 
371  if (src == end)
372  break;
373 
374  patt = *src++;
375  for (n = 1; src < end && *src == patt; src++)
376  n++;
377 
378  while (n) {
379  i = n > 126 ? 126 : n;
380  n -= i;
381  *dest++ = i;
382  *dest++ = patt;
383  }
384  }
385  *dest++ = 0;
386  return dest - d;
387 }
388 
389 
390 bool SGIImage::scanData(const TQImage& img)
391 {
392  TQ_UINT32 *start = m_starttab;
393  TQCString lineguard(m_xsize * 2);
394  TQCString bufguard(m_xsize);
395  uchar *line = (uchar *)lineguard.data();
396  uchar *buf = (uchar *)bufguard.data();
397  TQRgb *c;
398  unsigned x, y;
399  uint len;
400 
401  for (y = 0; y < m_ysize; y++) {
402  c = reinterpret_cast<TQRgb *>(const_cast<TQImage&>(img).scanLine(m_ysize - y - 1));
403  for (x = 0; x < m_xsize; x++)
404  buf[x] = intensity(tqRed(*c++));
405  len = compact(line, buf);
406  *start++ = m_rlemap.insert(line, len);
407  }
408 
409  if (m_zsize == 1)
410  return true;
411 
412  if (m_zsize != 2) {
413  for (y = 0; y < m_ysize; y++) {
414  c = reinterpret_cast<TQRgb *>(const_cast<TQImage&>(img).scanLine(m_ysize - y - 1));
415  for (x = 0; x < m_xsize; x++)
416  buf[x] = intensity(tqGreen(*c++));
417  len = compact(line, buf);
418  *start++ = m_rlemap.insert(line, len);
419  }
420 
421  for (y = 0; y < m_ysize; y++) {
422  c = reinterpret_cast<TQRgb *>(const_cast<TQImage&>(img).scanLine(m_ysize - y - 1));
423  for (x = 0; x < m_xsize; x++)
424  buf[x] = intensity(tqBlue(*c++));
425  len = compact(line, buf);
426  *start++ = m_rlemap.insert(line, len);
427  }
428 
429  if (m_zsize == 3)
430  return true;
431  }
432 
433  for (y = 0; y < m_ysize; y++) {
434  c = reinterpret_cast<TQRgb *>(const_cast<TQImage&>(img).scanLine(m_ysize - y - 1));
435  for (x = 0; x < m_xsize; x++)
436  buf[x] = intensity(tqAlpha(*c++));
437  len = compact(line, buf);
438  *start++ = m_rlemap.insert(line, len);
439  }
440 
441  return true;
442 }
443 
444 
445 void SGIImage::writeHeader()
446 {
447  m_stream << TQ_UINT16(0x01da);
448  m_stream << m_rle << m_bpc << m_dim;
449  m_stream << m_xsize << m_ysize << m_zsize;
450  m_stream << m_pixmin << m_pixmax;
451  m_stream << TQ_UINT32(0);
452 
453  uint i;
454  TQString desc = m_io->description();
455  kdDebug(399) << "Description: " << desc << endl;
456  desc.truncate(79);
457 
458  for (i = 0; i < desc.length(); i++)
459  m_imagename[i] = desc.latin1()[i];
460  for (; i < 80; i++)
461  m_imagename[i] = '\0';
462  m_stream.writeRawBytes(m_imagename, 80);
463 
464  m_stream << m_colormap;
465  for (i = 0; i < 404; i++)
466  m_stream << TQ_UINT8(0);
467 }
468 
469 
470 void SGIImage::writeRle()
471 {
472  m_rle = 1;
473  kdDebug(399) << "writing RLE data" << endl;
474  writeHeader();
475  uint i;
476 
477  // write start table
478  for (i = 0; i < m_numrows; i++)
479  m_stream << TQ_UINT32(m_rlevector[m_starttab[i]]->offset());
480 
481  // write length table
482  for (i = 0; i < m_numrows; i++)
483  m_stream << TQ_UINT32(m_rlevector[m_starttab[i]]->size());
484 
485  // write data
486  for (i = 0; i < m_rlevector.size(); i++)
487  m_rlevector[i]->write(m_stream);
488 }
489 
490 
491 void SGIImage::writeVerbatim(const TQImage& img)
492 {
493  m_rle = 0;
494  kdDebug(399) << "writing verbatim data" << endl;
495  writeHeader();
496 
497  TQRgb *c;
498  unsigned x, y;
499 
500  for (y = 0; y < m_ysize; y++) {
501  c = reinterpret_cast<TQRgb *>(const_cast<TQImage&>(img).scanLine(m_ysize - y - 1));
502  for (x = 0; x < m_xsize; x++)
503  m_stream << TQ_UINT8(tqRed(*c++));
504  }
505 
506  if (m_zsize == 1)
507  return;
508 
509  if (m_zsize != 2) {
510  for (y = 0; y < m_ysize; y++) {
511  c = reinterpret_cast<TQRgb *>(const_cast<TQImage&>(img).scanLine(m_ysize - y - 1));
512  for (x = 0; x < m_xsize; x++)
513  m_stream << TQ_UINT8(tqGreen(*c++));
514  }
515 
516  for (y = 0; y < m_ysize; y++) {
517  c = reinterpret_cast<TQRgb *>(const_cast<TQImage&>(img).scanLine(m_ysize - y - 1));
518  for (x = 0; x < m_xsize; x++)
519  m_stream << TQ_UINT8(tqBlue(*c++));
520  }
521 
522  if (m_zsize == 3)
523  return;
524  }
525 
526  for (y = 0; y < m_ysize; y++) {
527  c = reinterpret_cast<TQRgb *>(const_cast<TQImage&>(img).scanLine(m_ysize - y - 1));
528  for (x = 0; x < m_xsize; x++)
529  m_stream << TQ_UINT8(tqAlpha(*c++));
530  }
531 }
532 
533 
534 bool SGIImage::writeImage(TQImage& img)
535 {
536  kdDebug(399) << "writing '" << m_io->fileName() << '\'' << endl;
537 
538  if (img.allGray())
539  m_dim = 2, m_zsize = 1;
540  else
541  m_dim = 3, m_zsize = 3;
542 
543  if (img.hasAlphaBuffer())
544  m_dim = 3, m_zsize++;
545 
546  img = img.convertDepth(32);
547  if (img.isNull()) {
548  kdDebug(399) << "can't convert image to depth 32" << endl;
549  return false;
550  }
551 
552  m_bpc = 1;
553  m_xsize = img.width();
554  m_ysize = img.height();
555  m_pixmin = ~0;
556  m_pixmax = 0;
557  m_colormap = NORMAL;
558 
559  m_numrows = m_ysize * m_zsize;
560 
561  m_starttab = new TQ_UINT32[m_numrows];
562  m_rlemap.setBaseOffset(512 + m_numrows * 2 * sizeof(TQ_UINT32));
563 
564  if (!scanData(img)) {
565  kdDebug(399) << "this can't happen" << endl;
566  return false;
567  }
568 
569  m_rlevector = m_rlemap.vector();
570 
571  long verbatim_size = m_numrows * m_xsize;
572  long rle_size = m_numrows * 2 * sizeof(TQ_UINT32);
573  for (uint i = 0; i < m_rlevector.size(); i++)
574  rle_size += m_rlevector[i]->size();
575 
576  kdDebug(399) << "minimum intensity: " << m_pixmin << endl;
577  kdDebug(399) << "maximum intensity: " << m_pixmax << endl;
578  kdDebug(399) << "saved scanlines: " << m_numrows - m_rlemap.size() << endl;
579  kdDebug(399) << "total savings: " << (verbatim_size - rle_size) << " bytes" << endl;
580  kdDebug(399) << "compression: " << (rle_size * 100.0 / verbatim_size) << '%' << endl;
581 
582  if (verbatim_size <= rle_size || m_io->quality() > 50)
583  writeVerbatim(img);
584  else
585  writeRle();
586  return true;
587 }
588 
589 

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.1
This website is maintained by Timothy Pearson.