/* This file is part of the KDE project Copyright (C) 2005 Christoph Hormann Copyright (C) 2005 Ignacio Castaņo This program is free software; you can redistribute it and/or modify it under the terms of the Lesser GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. */ #include "hdr.h" #include #include #include #include typedef TQ_UINT8 uchar; namespace { // Private. #define MAXLINE 1024 #define MINELEN 8 // minimum scanline length for encoding #define MAXELEN 0x7fff // maximum scanline length for encoding static inline uchar ClipToByte(float value) { if (value > 255.0f) return 255; //else if (value < 0.0f) return 0; // we know value is positive. return uchar(value); } // read an old style line from the hdr image file // if 'first' is true the first byte is already read static bool Read_Old_Line (uchar * image, int width, TQDataStream & s) { int rshift = 0; int i; while (width > 0) { s >> image[0]; s >> image[1]; s >> image[2]; s >> image[3]; if (s.atEnd()) return false; if ((image[0] == 1) && (image[1] == 1) && (image[2] == 1)) { for (i = image[3] << rshift; i > 0; i--) { //memcpy(image, image-4, 4); (uint &)image[0] = (uint &)image[0-4]; image += 4; width--; } rshift += 8; } else { image += 4; width--; rshift = 0; } } return true; } static void RGBE_To_QRgbLine(uchar * image, QRgb * scanline, int width) { for (int j = 0; j < width; j++) { // v = ldexp(1.0, int(image[3]) - 128); float v; int e = int(image[3]) - 128; if( e > 0 ) { v = float(1 << e); } else { v = 1.0f / float(1 << -e); } scanline[j] = tqRgb( ClipToByte(float(image[0]) * v), ClipToByte(float(image[1]) * v), ClipToByte(float(image[2]) * v) ); image += 4; } } // Load the HDR image. static bool LoadHDR( TQDataStream & s, const int width, const int height, TQImage & img ) { uchar val, code; // Create dst image. if( !img.create( width, height, 32 ) ) { return false; } TQMemArray image( width * 4 ); for (int cline = 0; cline < height; cline++) { QRgb * scanline = (QRgb *) img.scanLine( cline ); // determine scanline type if ((width < MINELEN) || (MAXELEN < width)) { Read_Old_Line(image.data(), width, s); RGBE_To_QRgbLine(image.data(), scanline, width); continue; } s >> val; if (s.atEnd()) { return true; } if (val != 2) { s.tqdevice()->tqat( s.tqdevice()->tqat() - 1 ); Read_Old_Line(image.data(), width, s); RGBE_To_QRgbLine(image.data(), scanline, width); continue; } s >> image[1]; s >> image[2]; s >> image[3]; if (s.atEnd()) { return true; } if ((image[1] != 2) || (image[2] & 128)) { image[0] = 2; Read_Old_Line(image.data()+4, width-1, s); RGBE_To_QRgbLine(image.data(), scanline, width); continue; } if ((image[2] << 8 | image[3]) != width) { return false; } // read each component for (int i = 0; i < 4; i++) { for (int j = 0; j < width; ) { s >> code; if (s.atEnd()) { return false; } if (code > 128) { // run code &= 127; s >> val; while( code != 0 ) { image[i + j * 4] = val; j++; code--; } } else { // non-run while( code != 0 ) { s >> image[i + j * 4]; j++; code--; } } } } RGBE_To_QRgbLine(image.data(), scanline, width); } return true; } } // namespace KDE_EXPORT void kimgio_hdr_read( TQImageIO * io ) { int len; char line[MAXLINE]; //bool validHeader = false; bool validFormat = false; // Parse header do { len = io->ioDevice()->readLine(line, MAXLINE); /*if (strcmp(line, "#?RADIANCE\n") == 0 || strcmp(line, "#?RGBE\n") == 0) { validHeader = true; }*/ if (strcmp(line, "FORMAT=32-bit_rle_rgbe\n") == 0) { validFormat = true; } } while((len > 0) && (line[0] != '\n')); if( /*!validHeader ||*/ !validFormat ) { kdDebug(399) << "Unknown HDR format." << endl; io->setImage( TQImage() ); io->setqStatus( -1 ); return; } io->ioDevice()->readLine(line, MAXLINE); char s1[3], s2[3]; int width, height; if (sscanf(line, "%2[+-XY] %d %2[+-XY] %d\n", s1, &height, s2, &width) != 4) //if( sscanf(line, "-Y %d +X %d", &height, &width) < 2 ) { kdDebug(399) << "Invalid HDR file." << endl; io->setImage( TQImage() ); io->setqStatus( -1 ); return; } TQDataStream s( io->ioDevice() ); TQImage img; if( !LoadHDR(s, width, height, img) ) { kdDebug(399) << "Error loading HDR file." << endl; io->setImage( TQImage() ); io->setqStatus( -1 ); return; } io->setImage( img ); io->setqStatus( 0 ); } KDE_EXPORT void kimgio_hdr_write( TQImageIO * ) { // intentionally not implemented (since writing low dynamic range data to a HDR file is nonsense.) }