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

KImgIO

ras.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE project
00002    Copyright (C) 2003 Dominik Seichter <domseichter@web.de>
00003    Copyright (C) 2004 Ignacio CastaƱo <castano@ludicon.com>
00004    Copyright (C) 2010 Troy Unrau <troy@kde.org>
00005 
00006    This program is free software; you can redistribute it and/or
00007    modify it under the terms of the Lesser GNU General Public
00008    License as published by the Free Software Foundation; either
00009    version 2 of the License, or (at your option) any later version.
00010 */
00011 
00012 #include "ras.h"
00013 
00014 #include <QtGui/QImage>
00015 #include <QtCore/QDataStream>
00016 
00017 #include <kdebug.h>
00018 
00019 namespace { // Private.
00020     // format info from http://www.fileformat.info/format/sunraster/egff.htm
00021 
00022     // Header format of saved files.
00023     quint32 rasMagicBigEndian = 0x59a66a95;
00024     // quint32 rasMagicLittleEndian = 0x956aa659; # used to support wrong encoded files
00025     
00026     enum RASType {
00027         RAS_TYPE_OLD            = 0x0,
00028         RAS_TYPE_STANDARD       = 0x1,
00029         RAS_TYPE_BYTE_ENCODED       = 0x2,
00030         RAS_TYPE_RGB_FORMAT     = 0x3,
00031         RAS_TYPE_TIFF_FORMAT        = 0x4,
00032         RAS_TYPE_IFF_FORMAT     = 0x5,
00033         RAS_TYPE_EXPERIMENTAL       = 0xFFFF
00034     };
00035     
00036     enum RASColorMapType {
00037         RAS_COLOR_MAP_TYPE_NONE     = 0x0,
00038         RAS_COLOR_MAP_TYPE_RGB      = 0x1,
00039         RAS_COLOR_MAP_TYPE_RAW      = 0x2
00040     };
00041     
00042     struct RasHeader {
00043       quint32 MagicNumber;
00044       quint32 Width;
00045       quint32 Height;
00046       quint32 Depth;
00047       quint32 Length;
00048       quint32 Type;
00049       quint32 ColorMapType;
00050       quint32 ColorMapLength;
00051       enum { SIZE = 32 }; // 8 fields of four bytes each
00052     };
00053 
00054     static QDataStream & operator>> ( QDataStream & s, RasHeader & head )
00055     {
00056         s >> head.MagicNumber;
00057         s >> head.Width;
00058         s >> head.Height;
00059         s >> head.Depth;
00060         s >> head.Length;
00061         s >> head.Type;
00062         s >> head.ColorMapType;
00063         s >> head.ColorMapLength;
00064         /*qDebug() << "MagicNumber: " << head.MagicNumber
00065                  << "Width: " << head.Width
00066                  << "Height: " << head.Height
00067                  << "Depth: " << head.Depth
00068                  << "Length: " << head.Length
00069                  << "Type: " << head.Type
00070                  << "ColorMapType: " << head.ColorMapType
00071                  << "ColorMapLength: " << head.ColorMapLength;*/
00072         return s;
00073     }
00074 
00075     static bool IsSupported( const RasHeader & head )
00076     {
00077             // check magic number
00078         if ( head.MagicNumber != rasMagicBigEndian) {
00079           return false;
00080         }
00081         // check for an appropriate depth
00082         // we support 8bit+palette, 24bit and 32bit ONLY!
00083         // TODO: add support for 1bit
00084         if ( ! ((head.Depth == 8 && head.ColorMapType == 1)
00085                  || head.Depth == 24 || head.Depth == 32) ){
00086           return false;
00087         }
00088         // the Type field adds support for RLE(BGR), RGB and other encodings
00089         // we support Type 1: Normal(BGR) and Type 3: Normal(RGB) ONLY!
00090         // TODO: add support for Type 2: RLE(BGR) & Type 4,5: TIFF/IFF
00091         if ( ! (head.Type == 1 || head.Type == 3) ){
00092           return false;
00093         }
00094         // Old files didn't have Length set - reject them for now
00095         // TODO: add length recalculation to support old files
00096         if ( !head.Length ) {
00097           return false;
00098         }
00099         return true;
00100     }
00101 
00102     static bool LoadRAS( QDataStream & s, const RasHeader & ras, QImage &img )
00103     {
00104         s.device()->seek(RasHeader::SIZE);
00105         // Read palette if needed.
00106             QVector<quint8> palette(ras.ColorMapLength);
00107         if ( ras.ColorMapType == 1 ) {
00108         for (quint32 i = 0; i < ras.ColorMapLength; ++i) { s >> palette[i]; }
00109         }
00110         
00111         // each line must be a factor of 16 bits, so they may contain padding
00112         // this will be 1 if padding required, 0 otherwise
00113         int paddingrequired = (ras.Width*(ras.Depth/8) % 2);
00114         
00115         // qDebug() << "paddingrequired: " << paddingrequired;
00116         // don't trust ras.Length
00117             QVector<quint8> input(ras.Length);
00118         
00119         int i = 0;
00120         while ( ! s.atEnd()) {
00121         s >> input[i];
00122         // I guess we need to find out if we're at the end of a line
00123         if ( paddingrequired && i != 0 && !(i % (ras.Width*(ras.Depth/8))) ) {
00124           s >> input[i];
00125         }
00126         i++;
00127           }
00128         
00129         // Allocate image
00130         img = QImage(ras.Width, ras.Height, QImage::Format_ARGB32);
00131 
00132             // Reconstruct image from RGB palette if we have a palette
00133         // TODO: make generic so it works with 24bit or 32bit palettes
00134         if ( ras.ColorMapType == 1 && ras.Depth == 8) {
00135         quint8 red, green, blue;
00136         for ( quint32 y = 0; y < ras.Height; y++ ){
00137           for ( quint32 x = 0; x < ras.Width; x++ ) {
00138             red = palette[(int)input[y*ras.Width + x]];
00139             green = palette[(int)input[y*ras.Width + x] + (ras.ColorMapLength/3)];
00140             blue = palette[(int)input[y*ras.Width + x] + 2*(ras.ColorMapLength/3)];
00141             img.setPixel(x, y, qRgb(red, green, blue));
00142           }
00143         }
00144         
00145         }
00146         
00147         if ( ras.ColorMapType == 0 && ras.Depth == 24 && (ras.Type == 1 || ras.Type == 2)) {
00148         quint8 red, green, blue;
00149         for ( quint32 y = 0; y < ras.Height; y++ ){
00150           for ( quint32 x = 0; x < ras.Width; x++ ) {
00151             red = input[y*3*ras.Width + x*3 + 2];
00152             green = input[y*3*ras.Width + x*3 + 1];
00153             blue = input[y*3*ras.Width + x*3];
00154             img.setPixel(x, y, qRgb(red, green, blue));
00155           }
00156         }
00157         }
00158 
00159         if ( ras.ColorMapType == 0 && ras.Depth == 24 && ras.Type == 3) {
00160         quint8 red, green, blue;
00161         for ( quint32 y = 0; y < ras.Height; y++ ){
00162           for ( quint32 x = 0; x < ras.Width; x++ ) {
00163             red = input[y*3*ras.Width + x*3];
00164             green = input[y*3*ras.Width + x*3 + 1];
00165             blue = input[y*3*ras.Width + x*3 + 2];
00166             img.setPixel(x, y, qRgb(red, green, blue));
00167           }
00168         }
00169         }
00170 
00171         if ( ras.ColorMapType == 0 && ras.Depth == 32 && (ras.Type == 1 || ras.Type == 2)) {
00172         quint8 red, green, blue;
00173         for ( quint32 y = 0; y < ras.Height; y++ ){
00174           for ( quint32 x = 0; x < ras.Width; x++ ) {
00175             red = input[y*4*ras.Width + x*4 + 3];
00176             green = input[y*4*ras.Width + x*4 + 2];
00177             blue = input[y*4*ras.Width + x*4 + 1];
00178             img.setPixel(x, y, qRgb(red, green, blue));
00179           }
00180         }
00181         }
00182         
00183         if ( ras.ColorMapType == 0 && ras.Depth == 32 && ras.Type == 3 ) {
00184         quint8 red, green, blue;
00185         for ( quint32 y = 0; y < ras.Height; y++ ){
00186           for ( quint32 x = 0; x < ras.Width; x++ ) {
00187             red = input[y*4*ras.Width + x*4 + 1];
00188             green = input[y*4*ras.Width + x*4 + 2];
00189             blue = input[y*4*ras.Width + x*4 + 3];
00190             img.setPixel(x, y, qRgb(red, green, blue));
00191           }
00192         }
00193         }
00194         
00195             return true;
00196     }
00197 } // namespace
00198 
00199 RASHandler::RASHandler()
00200 {
00201 }
00202 
00203 QByteArray RASHandler::name() const
00204 {
00205     return "ras";
00206 }
00207 
00208 bool RASHandler::canRead() const
00209 {
00210     if (canRead(device())) {
00211         setFormat("ras");
00212         return true;
00213     }
00214     return false;
00215 }
00216 
00217 bool RASHandler::canRead(QIODevice *device)
00218 {
00219     if (!device) {
00220         qWarning("RASHandler::canRead() called with no device");
00221         return false;
00222     }
00223     
00224     if (device->isSequential()) {
00225         qWarning("Reading ras files from sequential devices not supported");
00226         return false;
00227         }
00228         
00229     qint64 oldPos = device->pos();
00230     QByteArray head = device->read(RasHeader::SIZE); // header is exactly 32 bytes, always FIXME
00231     int readBytes = head.size(); // this should always be 32 bytes
00232 
00233     device->seek(oldPos);
00234     
00235     if (readBytes < RasHeader::SIZE) {
00236         return false;
00237     }
00238 
00239     QDataStream stream(head);
00240     stream.setByteOrder(QDataStream::BigEndian);
00241     RasHeader ras;
00242     stream >> ras;
00243     return IsSupported(ras);   
00244 }
00245     
00246 bool RASHandler::read(QImage *outImage)
00247 {
00248     QDataStream s( device() );
00249     s.setByteOrder( QDataStream::BigEndian );
00250 
00251     // Read image header.
00252     RasHeader ras;
00253     s >> ras;
00254     // TODO: add support for old versions of RAS where Length may be zero in header
00255     s.device()->seek( RasHeader::SIZE + ras.Length + ras.ColorMapLength );
00256     
00257     // Check image file format. Type 2 is RLE, which causing seeking to be silly.
00258     if( !s.atEnd() && ras.Type != 2) {
00259         kDebug(399) << "This RAS file is not valid, or an older version of the format.";
00260         return false;
00261     }
00262 
00263     // Check supported file types.
00264     if( !IsSupported(ras) ) {
00265         kDebug(399) << "This RAS file is not supported.";
00266         return false;
00267     }
00268 
00269     QImage img;
00270     bool result = LoadRAS(s, ras, img);
00271 
00272     if( result == false ) {
00273         kDebug(399) << "Error loading RAS file.";
00274         return false;
00275     }
00276 
00277     *outImage = img;
00278     return true;
00279 }
00280 /*
00281 bool RASHandler::write(const QImage &image){
00282   return false;
00283 }*/
00284 
00285 class RASPlugin : public QImageIOPlugin
00286 {
00287 public:
00288     QStringList keys() const;
00289     Capabilities capabilities(QIODevice *device, const QByteArray &format) const;
00290     QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const;
00291 };
00292 
00293 QStringList RASPlugin::keys() const
00294 {
00295     return QStringList() << "ras" << "RAS";
00296 }
00297 
00298 QImageIOPlugin::Capabilities RASPlugin::capabilities(QIODevice *device, const QByteArray &format) const
00299 {
00300   
00301     if (format == "ras" || format == "RAS")
00302         return Capabilities(CanRead);
00303 //         return Capabilities(CanRead | CanWrite);
00304     if (!format.isEmpty())
00305         return 0;
00306     if (!device->isOpen())
00307         return 0;
00308 
00309     Capabilities cap;   
00310     if (device->isReadable() && RASHandler::canRead(device))
00311         cap |= CanRead;
00312     if (device->isWritable())
00313         cap |= CanWrite;
00314     return cap;
00315 }
00316 
00317 QImageIOHandler *RASPlugin::create(QIODevice *device, const QByteArray &format) const
00318 {
00319     QImageIOHandler *handler = new RASHandler;
00320     handler->setDevice(device);
00321     handler->setFormat(format);
00322     return handler;
00323 }
00324 
00325 
00326 Q_EXPORT_STATIC_PLUGIN(RASPlugin)
00327 Q_EXPORT_PLUGIN2(ras, RASPlugin)

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