// -*- C++;indent-tabs-mode: t; tab-width: 4; c-basic-offset: 4; -*- /** * KImageIO Routines to read (and perhaps in the future, write) images * in the high dynamic range EXR format. * Copyright (c) 2003, Brad Hards * * This library is distributed under the conditions of the GNU LGPL. * * $Id$ */ #include "config.h" #ifdef HAVE_EXR #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "exr.h" using namespace Imf; /* this does a conversion from the ILM Half (equal to Nvidia Half) * format into the normal 32 bit pixel format. Process is from the * ILM code. */ QRgb RgbaToQrgba(struct Rgba imagePixel) { float r,g,b,a; // 1) Compensate for fogging by subtracting defog // from the raw pixel values. // Response: We work with defog of 0.0, so this is a no-op // 2) Multiply the defogged pixel values by // 2^(exposure + 2.47393). // Response: We work with exposure of 0.0. // (2^2.47393) is 5.55555 r = imagePixel.r * 5.55555; g = imagePixel.g * 5.55555; b = imagePixel.b * 5.55555; a = imagePixel.a * 5.55555; // 3) Values, which are now 1.0, are called "middle gray". // If defog and exposure are both set to 0.0, then // middle gray corresponds to a raw pixel value of 0.18. // In step 6, middle gray values will be mapped to an // intensity 3.5 f-stops below the display's maximum // intensity. // Response: no apparent content. // 4) Apply a knee function. The knee function has two // parameters, kneeLow and kneeHigh. Pixel values // below 2^kneeLow are not changed by the knee // function. Pixel values above kneeLow are lowered // according to a logarithmic curve, such that the // value 2^kneeHigh is mapped to 2^3.5 (in step 6, // this value will be mapped to the the display's // maximum intensity). // Response: kneeLow = 0.0 (2^0.0 => 1); kneeHigh = 5.0 (2^5 =>32) if (r > 1.0) r = 1.0 + Imath::Math::log ((r-1.0) * 0.184874 + 1) / 0.184874; if (g > 1.0) g = 1.0 + Imath::Math::log ((g-1.0) * 0.184874 + 1) / 0.184874; if (b > 1.0) b = 1.0 + Imath::Math::log ((b-1.0) * 0.184874 + 1) / 0.184874; if (a > 1.0) a = 1.0 + Imath::Math::log ((a-1.0) * 0.184874 + 1) / 0.184874; // // 5) Gamma-correct the pixel values, assuming that the // screen's gamma is 0.4545 (or 1/2.2). r = Imath::Math::pow (r, 0.4545); g = Imath::Math::pow (g, 0.4545); b = Imath::Math::pow (b, 0.4545); a = Imath::Math::pow (a, 0.4545); // 6) Scale the values such that pixels middle gray // pixels are mapped to 84.66 (or 3.5 f-stops below // the display's maximum intensity). // // 7) Clamp the values to [0, 255]. return qRgba( char (Imath::clamp ( r * 84.66f, 0.f, 255.f ) ), char (Imath::clamp ( g * 84.66f, 0.f, 255.f ) ), char (Imath::clamp ( b * 84.66f, 0.f, 255.f ) ), char (Imath::clamp ( a * 84.66f, 0.f, 255.f ) ) ); } KDE_EXPORT void kimgio_exr_read( TQImageIO *io ) { try { int width, height; // This won't work if io is not TQFile ! RgbaInputFile file (TQFile::encodeName(io->fileName())); Imath::Box2i dw = file.dataWindow(); width = dw.max.x - dw.min.x + 1; height = dw.max.y - dw.min.y + 1; Array2D pixels; pixels.resizeErase (height, width); file.setFrameBuffer (&pixels[0][0] - dw.min.x - dw.min.y * width, 1, width); file.readPixels (dw.min.y, dw.max.y); TQImage image(width, height, 32, 0, TQImage::BigEndian); if( image.isNull()) return; // somehow copy pixels into image for ( int y=0; y < height; y++ ) { for ( int x=0; x < width; x++ ) { // copy pixels(x,y) into image(x,y) image.setPixel( x, y, RgbaToQrgba( pixels[y][x] ) ); } } io->setImage( image ); io->setStatus( 0 ); } catch (const std::exception &exc) { kdDebug(399) << exc.what() << endl; return; } } KDE_EXPORT void kimgio_exr_write(TQImageIO *) { // TODO: stub } #endif