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 }
KDE 4.6 API Reference