• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

KImgIO

pic_write.cpp

Go to the documentation of this file.
00001 
00021 /* This code is based on the GIMP-PIC plugin by Halfdan Ingvarsson,
00022  * and relicensed from GPL to LGPL to accomodate the KDE licensing policy
00023  * with his permission.
00024  * These is the original copyright:
00025  * Copyright (C) 1998 Halfdan Ingvarsson
00026  */
00027 
00028 #include "pic_rw.h"
00029 #include <netinet/in.h>
00030 #include <iostream>
00031 #include <qimage.h>
00032 
00042 static bool writeHeader(QIODevice *dev, std::string msg, unsigned width, unsigned height, bool alpha) {
00043     PICHeader h;
00044     PICChannel c;
00045     unsigned count = 0;
00046 
00047     memset(&h, 0, sizeof (PICHeader));
00048     h.magic = htonl(PIC_MAGIC_NUMBER);
00049     h.version = 3.71f;
00050     strcpy(h.comment, msg.c_str());
00051     strncpy(h.id, "PICT", 4);
00052     h.width = htons(width);
00053     h.height = htons(height);
00054     h.ratio = 1.0f;
00055     h.fields = htons(BOTH);
00056     count = dev->write((const char*) & h, sizeof (PICHeader));
00057     if (count != sizeof (PICHeader)) {
00058         return false;
00059     }
00060 
00061     memset(&c, 0, sizeof (PICChannel));
00062     c.size = 8;
00063     c.type = RLE;
00064     c.channel = RED | GREEN | BLUE;
00065     if (alpha) {
00066         c.chained = 1;
00067     }
00068     count = dev->write((const char*) & c, sizeof (PICChannel));
00069     if (count != sizeof (PICChannel)) {
00070         return false;
00071     }
00072 
00073     if (alpha) {
00074         c.channel = ALPHA;
00075         c.chained = 0;
00076         count = dev->write((const char*) & c, sizeof (PICChannel));
00077         if (count != sizeof (PICChannel)) {
00078             return false;
00079         }
00080     }
00081     return true;
00082 }
00083 
00084 inline unsigned convertABGRtoRGBA(unsigned pixel) {
00085     unsigned r = pixel & 0xFF;
00086     unsigned g = (pixel >> 8) & 0xFF;
00087     unsigned b = (pixel >> 16) & 0xFF;
00088     unsigned a = (pixel >> 24) & 0xFF;
00089     return a | (b << 8) | (g << 16) | (r << 24);
00090 }
00091 
00103 static bool encodeRLE(const unsigned *image, unsigned char *output, bool rgb, unsigned max, unsigned &oConsumed, unsigned &oProduced) {
00104     const unsigned *in = image;
00105     unsigned char *out = output;
00106     unsigned count = 0;
00107     unsigned channels = 3;
00108     unsigned offset = 1;
00109     unsigned mask = 0x00FFFFFF;
00110     if (!rgb) {
00111         channels = 1;
00112         offset = 0;
00113         mask = 0xFF000000;
00114     }
00115     for (; (*in & mask) == (*image & mask) && count < 65536 && count < max; in++, count++) {
00116     }
00117     if (count > 127) {
00118         /* Sequence of > 127 identical pixels */
00119         *out++ = 128;
00120         *out++ = count >> 8;
00121         *out++ = count & 0xFF;
00122         unsigned pixel = convertABGRtoRGBA(*image);
00123         memcpy(out, ((char*) & pixel) + offset, channels);
00124         out += channels;
00125         oConsumed = count;
00126         oProduced = out - output;
00127     }
00128     else if (count > 1) {
00129         /* Sequece of < 128 identical pixels */
00130         *out++ = (count + 127);
00131         unsigned pixel = convertABGRtoRGBA(*image);
00132         memcpy(out, ((char*) & pixel) + offset, channels);
00133         out += channels;
00134         oConsumed = count;
00135         oProduced = out - output;
00136     }
00137     else {
00138         in = image + 1;
00139         unsigned previous = *image;
00140         count = 0;
00141         while ((*in & mask) != (previous & mask) && count < 128 && count < max) {
00142             previous = *in;
00143             in++;
00144             count++;
00145         }
00146         // This only happens when it is the end of the row, and it is ok
00147         if (count == 0) {
00148             count = 1;
00149         }
00150         *out++ = (count - 1);
00151         in = image;
00152         for (unsigned c = 0; c < count; ++c) {
00153             unsigned pixel = convertABGRtoRGBA(*in);
00154             memcpy(out, ((char*) & pixel) + offset, channels);
00155             out += channels;
00156             in++;
00157         }
00158         oConsumed = count;
00159         oProduced = out - output;
00160     }
00161     return true;
00162 }
00163 
00168 static bool writeRow(QIODevice *dev, unsigned *row, unsigned width, bool alpha) {
00169     unsigned char *buf = new unsigned char[width * 4];
00170     unsigned posIn = 0;
00171     unsigned posOut = 0;
00172 
00173     memset(buf, 0, width * 4);
00174 
00175     unsigned consumed = 0;
00176     unsigned produced = 0;
00177 
00178     /* Write the RGB part of the scanline */
00179     while (posIn < width) {
00180         if (!encodeRLE(row + posIn, buf + posOut, true, width - posIn, consumed, produced)) {
00181             delete[] buf;
00182             return false;
00183         }
00184         posIn += consumed;
00185         posOut += produced;
00186     }
00187 
00188     /* Write the alpha channel */
00189     if (alpha) {
00190         posIn = 0;
00191         while (posIn < width) {
00192             if (!encodeRLE(row + posIn, buf + posOut, false, width - posIn, consumed, produced)) {
00193                 delete[] buf;
00194                 return false;
00195             }
00196             posIn += consumed;
00197             posOut += produced;
00198         }
00199     }
00200 
00201     dev->write((const char*) buf, posOut);
00202     delete[] buf;
00203     return true;
00204 }
00205 
00206 #define FAIL() { \
00207     std::cout << "ERROR Writing PIC!" << std::endl; \
00208     return; \
00209 }
00210 
00212 
00213 void pic_write(QIODevice *dev, const QImage *img) {
00214     bool alpha = img->hasAlphaChannel();
00215     if (!writeHeader(dev, "Created with KDE", img->width(), img->height(), alpha)) {
00216         FAIL();
00217     }
00218 
00219     for (int r = 0; r < img->height(); r++) {
00220         unsigned *row = (unsigned*) img->scanLine(r);
00221         if (!writeRow(dev, row, img->width(), alpha)) {
00222             FAIL();
00223         }
00224     }
00225 }

KImgIO

Skip menu "KImgIO"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal