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

KImgIO

pic_read.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 #include <algorithm>
00033 
00041 bool picReadHeader(QIODevice *dev, PICHeader *hdr, bool peek) {
00042     int result = 0;
00043     if (peek) {
00044         result = dev->peek((char*) hdr, HEADER_SIZE);
00045     } else {
00046         result = dev->read((char*) hdr, HEADER_SIZE);
00047     }
00048 
00049     hdr->magic = ntohl(hdr->magic);
00050     hdr->width = ntohs(hdr->width);
00051     hdr->height = ntohs(hdr->height);
00052     hdr->fields = ntohs(hdr->fields);
00053 
00054     if (hdr->magic != PIC_MAGIC_NUMBER || strncmp(hdr->id, "PICT", 4)) {
00055         return false;
00056     }
00057 
00058     return result == HEADER_SIZE;
00059 }
00060 
00061 #define CHANNEL_BYTE(ch, mask) (( ch & mask) ? 1 : 0)
00062 
00068 static int channels2bpp(char channels) {
00069     return CHANNEL_BYTE(channels, RED)
00070             + CHANNEL_BYTE(channels, GREEN)
00071             + CHANNEL_BYTE(channels, BLUE)
00072             + CHANNEL_BYTE(channels, ALPHA);
00073 }
00074 
00081 static bool readChannels(QIODevice *dev, PICChannel *channels, int &bpp) {
00082     int c = 0;
00083     memset(channels, 0, sizeof ( PICChannel) *8);
00084     do {
00085         int result = dev->read((char*) & channels[c], CHANNEL_SIZE);
00086         if (result != CHANNEL_SIZE) {
00087             return false;
00088         } else {
00089             bpp += channels2bpp(channels[c].channel);
00090             c++;
00091         }
00092     }    while (channels[c - 1].chained);
00093     return true;
00094 }
00095 
00101 inline static void makeComponentMap(unsigned channel, unsigned char *cmap) {
00102     std::fill(cmap, cmap + 8, 0);
00103 
00104     unsigned compos[] = {ALPHA, BLUE, GREEN, RED};
00105     unsigned rgba[] = {3, 2, 1, 0};
00106     unsigned pos = 0;
00107     for (unsigned compo = 0; compo < 4; compo++) {
00108         if (CHANNEL_BYTE(channel, compos[compo])) {
00109             cmap[pos++] = rgba[compo];
00110         }
00111     }
00112 }
00113 
00121 inline static void pic2RGBA(unsigned char *src_pixel, unsigned char *target_pixel, unsigned char *cmap, unsigned components) {
00122     for (unsigned i = 0; i < components; i++) {
00123         target_pixel[cmap[i]] = src_pixel[i];
00124     }
00125 }
00126 
00132 inline static unsigned getNumChannels(PICChannel *channels) {
00133     unsigned result = 0;
00134     for (unsigned i = 0; i < 8; i++) {
00135         if (channels[i].channel != 0) {
00136             result++;
00137         } else {
00138             return result;
00139         }
00140     }
00141     return result;
00142 }
00143 
00152 static int decodeRLE(QIODevice *dev, void *row, unsigned max, unsigned bpp, unsigned channels) {
00153     unsigned char buf[512];
00154     unsigned *ptr = (unsigned *) row;
00155     unsigned char component_map[8];
00156     unsigned len = 0;
00157 
00158     makeComponentMap(channels, component_map);
00159 
00160     if (dev->read((char*) buf, 1) != 1) {
00161         return -1;
00162     }
00163 
00164     /* If last bit is 1, then it is 2 to 127 repetitions */
00165     if (buf[0] > 128) {
00166         len = buf[0] - 127;
00167         if (len > max) {
00168             return -1;
00169         }
00170         unsigned count = dev->read((char*) buf, bpp);
00171         if (count != bpp) {
00172             return -1;
00173         }
00174         for (unsigned i = 0; i < len; i++) {
00175             pic2RGBA(buf, (unsigned char*) (ptr + i), component_map, bpp);
00176         }
00177     }        /* If the value is exactly 10000000, it means that it is more than 127 repetitions */
00178     else if (buf[0] == 128) {
00179         unsigned count = dev->read((char*) buf, bpp + 2);
00180         if (count != bpp + 2) {
00181             return -1;
00182         }
00183         len = (buf[0] << 8) | buf[1];
00184         if (len > max) {
00185             return -1;
00186         }
00187         for (unsigned i = 0; i < len; i++) {
00188             pic2RGBA(buf + 2, (unsigned char*) (ptr + i), component_map, bpp);
00189         }
00190     }        
00191     else {
00192         len = buf[0] + 1;
00193         if (len > max) {
00194             return -1;
00195         }
00196         unsigned count = dev->read((char*) buf, len * bpp);
00197         if (count != len * bpp) {
00198             return -1;
00199         }
00200         for (unsigned i = 0; i < len; i++) {
00201             pic2RGBA(buf + (i * bpp), (unsigned char*) (ptr + i), component_map, bpp);
00202         }
00203     }
00204     return len;
00205 }
00206 
00215 static bool readRow(QIODevice *dev, unsigned *row, unsigned width, PICChannel *channels) {
00216     for (int c = 0; channels[c].channel != 0; c++) {
00217         unsigned remain = width;
00218         unsigned bpp = channels2bpp(channels[c].channel);
00219         if (channels[c].type == (int) RLE) {
00220             unsigned *rowpos = row;
00221             while (remain > 0) {
00222                 int readed = decodeRLE(dev, rowpos, remain, bpp, channels[c].channel);
00223                 if (readed < 0) {
00224                     return false;
00225                 }
00226                 remain -= readed;
00227                 rowpos += readed;
00228             }
00229         } else {
00230             unsigned char component_map[8];
00231             unsigned count = dev->read((char*) row, width * bpp);
00232             if (count != width * bpp) {
00233                 return false;
00234             }
00235 
00236             makeComponentMap(channels[c].channel, component_map);
00237             for (unsigned i = 0; i < width; i++) {
00238                 pic2RGBA(((unsigned char*) row) + (i * bpp), (unsigned char*) (row + i), component_map, bpp);
00239             }
00240         }
00241     }
00242     return true;
00243 }
00244 
00245 #define FAIL() { \
00246     std::cout << "ERROR Reading PIC!" << std::endl; \
00247     return; \
00248 }
00249 
00250 bool hasAlpha(PICChannel *channels) {
00251     int channel = 0;
00252     do {
00253         if (CHANNEL_BYTE(channels[channel].channel, ALPHA)) {
00254             return true;
00255         }
00256         channel++;
00257     }    while (channels[channel - 1].chained);
00258     return false;
00259 }
00260 
00264 void pic_read(QIODevice *dev, QImage *result) {
00265     PICHeader header;
00266     PICChannel channels[8];
00267     int bpp = 0;
00268     if (!picReadHeader(dev, &header) || !readChannels(dev, channels, bpp)) {
00269         FAIL();
00270     }
00271     QImage img(header.width, header.height, QImage::Format_ARGB32);
00272 
00273     for (int r = 0; r < header.height; r++) {
00274         unsigned *row = (unsigned*) img.scanLine(r);
00275         std::fill(row, row + header.width, 0);
00276         if (!readRow(dev, row, header.width, channels)) {
00277             FAIL();
00278         }
00279     }
00280     //  img->setAlphaBuffer(hasAlpha(channels));
00281     *result = img;
00282 }

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