hdr.cpp
00001 /* This file is part of the KDE project 00002 Copyright (C) 2005 Christoph Hormann <chris_hormann@gmx.de> 00003 Copyright (C) 2005 Ignacio Castaņo <castanyo@yahoo.es> 00004 00005 This program is free software; you can redistribute it and/or 00006 modify it under the terms of the Lesser GNU General Public 00007 License as published by the Free Software Foundation; either 00008 version 2 of the License, or (at your option) any later version. 00009 */ 00010 00011 #include "hdr.h" 00012 00013 #include <tqimage.h> 00014 #include <tqdatastream.h> 00015 00016 #include <kdebug.h> 00017 #include <kglobal.h> 00018 00019 typedef TQ_UINT8 uchar; 00020 00021 namespace { // Private. 00022 00023 #define MAXLINE 1024 00024 #define MINELEN 8 // minimum scanline length for encoding 00025 #define MAXELEN 0x7fff // maximum scanline length for encoding 00026 00027 static inline uchar ClipToByte(float value) 00028 { 00029 if (value > 255.0f) return 255; 00030 //else if (value < 0.0f) return 0; // we know value is positive. 00031 return uchar(value); 00032 } 00033 00034 // read an old style line from the hdr image file 00035 // if 'first' is true the first byte is already read 00036 static bool Read_Old_Line (uchar * image, int width, TQDataStream & s) 00037 { 00038 int rshift = 0; 00039 int i; 00040 00041 while (width > 0) 00042 { 00043 s >> image[0]; 00044 s >> image[1]; 00045 s >> image[2]; 00046 s >> image[3]; 00047 00048 if (s.atEnd()) return false; 00049 00050 if ((image[0] == 1) && (image[1] == 1) && (image[2] == 1)) 00051 { 00052 for (i = image[3] << rshift; i > 0; i--) 00053 { 00054 //memcpy(image, image-4, 4); 00055 (uint &)image[0] = (uint &)image[0-4]; 00056 image += 4; 00057 width--; 00058 } 00059 rshift += 8; 00060 } 00061 else 00062 { 00063 image += 4; 00064 width--; 00065 rshift = 0; 00066 } 00067 } 00068 return true; 00069 } 00070 00071 00072 static void RGBE_To_QRgbLine(uchar * image, QRgb * scanline, int width) 00073 { 00074 for (int j = 0; j < width; j++) 00075 { 00076 // v = ldexp(1.0, int(image[3]) - 128); 00077 float v; 00078 int e = int(image[3]) - 128; 00079 if( e > 0 ) 00080 { 00081 v = float(1 << e); 00082 } 00083 else 00084 { 00085 v = 1.0f / float(1 << -e); 00086 } 00087 00088 scanline[j] = tqRgb( ClipToByte(float(image[0]) * v), 00089 ClipToByte(float(image[1]) * v), 00090 ClipToByte(float(image[2]) * v) ); 00091 00092 image += 4; 00093 } 00094 } 00095 00096 // Load the HDR image. 00097 static bool LoadHDR( TQDataStream & s, const int width, const int height, TQImage & img ) 00098 { 00099 uchar val, code; 00100 00101 // Create dst image. 00102 if( !img.create( width, height, 32 ) ) 00103 { 00104 return false; 00105 } 00106 00107 TQMemArray<uchar> image( width * 4 ); 00108 00109 for (int cline = 0; cline < height; cline++) 00110 { 00111 QRgb * scanline = (QRgb *) img.scanLine( cline ); 00112 00113 // determine scanline type 00114 if ((width < MINELEN) || (MAXELEN < width)) 00115 { 00116 Read_Old_Line(image.data(), width, s); 00117 RGBE_To_QRgbLine(image.data(), scanline, width); 00118 continue; 00119 } 00120 00121 s >> val; 00122 00123 if (s.atEnd()) 00124 { 00125 return true; 00126 } 00127 00128 if (val != 2) 00129 { 00130 s.device()->at( s.device()->at() - 1 ); 00131 Read_Old_Line(image.data(), width, s); 00132 RGBE_To_QRgbLine(image.data(), scanline, width); 00133 continue; 00134 } 00135 00136 s >> image[1]; 00137 s >> image[2]; 00138 s >> image[3]; 00139 00140 if (s.atEnd()) 00141 { 00142 return true; 00143 } 00144 00145 if ((image[1] != 2) || (image[2] & 128)) 00146 { 00147 image[0] = 2; 00148 Read_Old_Line(image.data()+4, width-1, s); 00149 RGBE_To_QRgbLine(image.data(), scanline, width); 00150 continue; 00151 } 00152 00153 if ((image[2] << 8 | image[3]) != width) 00154 { 00155 return false; 00156 } 00157 00158 // read each component 00159 for (int i = 0; i < 4; i++) 00160 { 00161 for (int j = 0; j < width; ) 00162 { 00163 s >> code; 00164 if (s.atEnd()) 00165 { 00166 return false; 00167 } 00168 if (code > 128) 00169 { 00170 // run 00171 code &= 127; 00172 s >> val; 00173 while( code != 0 ) 00174 { 00175 image[i + j * 4] = val; 00176 j++; 00177 code--; 00178 } 00179 } 00180 else 00181 { 00182 // non-run 00183 while( code != 0 ) 00184 { 00185 s >> image[i + j * 4]; 00186 j++; 00187 code--; 00188 } 00189 } 00190 } 00191 } 00192 00193 RGBE_To_QRgbLine(image.data(), scanline, width); 00194 } 00195 00196 return true; 00197 } 00198 00199 } // namespace 00200 00201 00202 KDE_EXPORT void kimgio_hdr_read( TQImageIO * io ) 00203 { 00204 int len; 00205 char line[MAXLINE]; 00206 //bool validHeader = false; 00207 bool validFormat = false; 00208 00209 // Parse header 00210 do { 00211 len = io->ioDevice()->readLine(line, MAXLINE); 00212 00213 /*if (strcmp(line, "#?RADIANCE\n") == 0 || strcmp(line, "#?RGBE\n") == 0) 00214 { 00215 validHeader = true; 00216 }*/ 00217 if (strcmp(line, "FORMAT=32-bit_rle_rgbe\n") == 0) 00218 { 00219 validFormat = true; 00220 } 00221 00222 } while((len > 0) && (line[0] != '\n')); 00223 00224 if( !validFormat ) 00225 { 00226 kdDebug(399) << "Unknown HDR format." << endl; 00227 io->setImage( TQImage() ); 00228 io->setStatus( -1 ); 00229 return; 00230 } 00231 00232 io->ioDevice()->readLine(line, MAXLINE); 00233 00234 char s1[3], s2[3]; 00235 int width, height; 00236 if (sscanf(line, "%2[+-XY] %d %2[+-XY] %d\n", s1, &height, s2, &width) != 4) 00237 //if( sscanf(line, "-Y %d +X %d", &height, &width) < 2 ) 00238 { 00239 kdDebug(399) << "Invalid HDR file." << endl; 00240 io->setImage( TQImage() ); 00241 io->setStatus( -1 ); 00242 return; 00243 } 00244 00245 TQDataStream s( io->ioDevice() ); 00246 00247 TQImage img; 00248 if( !LoadHDR(s, width, height, img) ) 00249 { 00250 kdDebug(399) << "Error loading HDR file." << endl; 00251 io->setImage( TQImage() ); 00252 io->setStatus( -1 ); 00253 return; 00254 } 00255 00256 io->setImage( img ); 00257 io->setStatus( 0 ); 00258 } 00259 00260 00261 KDE_EXPORT void kimgio_hdr_write( TQImageIO * ) 00262 { 00263 // intentionally not implemented (since writing low dynamic range data to a HDR file is nonsense.) 00264 } 00265