• 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
34TDE_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
50TDE_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
65SGIImage::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
75SGIImage::~SGIImage()
76{
77 delete[] m_starttab;
78 delete[] m_lengthtab;
79}
80
81
83
84
85bool 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
121bool 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
184bool 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
294void 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
303void RLEData::write(TQDataStream& s)
304{
305 for (unsigned i = 0; i < size(); i++)
306 s << at(i);
307}
308
309
310bool 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
323uint 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
335TQPtrVector<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
345uchar 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
355uint 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
390bool 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
445void 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
470void 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
491void 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
534bool 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.4
This website is maintained by Timothy Pearson.