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