/* QGL HDR Ivan Pelipenko peri4ko@yandex.ru This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "hdr_p.h" #include #include #define RGBE_DATA_RED 2 #define RGBE_DATA_GREEN 1 #define RGBE_DATA_BLUE 0 /* number of floats per pixel */ #define RGBE_DATA_SIZE 3 void rgbe2float(float * red, float * green, float * blue, uchar rgbe[4]) { float f; if (rgbe[3]) { f = static_cast(ldexp(1.0, rgbe[3] - (int)(128 + 8))); *red = rgbe[0] * f; *green = rgbe[1] * f; *blue = rgbe[2] * f; } else *red = *green = *blue = 0.0; } /* simple read routine. will not correctly handle run length encoding */ bool RGBE_ReadPixels(QDataStream * fp, float * data, int numpixels) { uchar rgbe[4]; while (numpixels-- > 0) { if (fp->readRawData((char *)rgbe, sizeof(rgbe)) < 1) return false; rgbe2float(&data[RGBE_DATA_RED], &data[RGBE_DATA_GREEN], &data[RGBE_DATA_BLUE], rgbe); data += RGBE_DATA_SIZE; } return true; } bool RGBE_ReadPixels_RLE(QDataStream * fp, float * data, int scanline_width, int num_scanlines) { uchar rgbe[4], *ptr, *ptr_end; int i, count; uchar buf[2]; QByteArray scanline_buffer; if ((scanline_width < 8) || (scanline_width > 0x7fff)) /* run length encoding is not allowed so read flat*/ return RGBE_ReadPixels(fp, data, scanline_width * num_scanlines); scanline_buffer.resize(4 * scanline_width); /* read in each successive scanline */ while (num_scanlines > 0) { if (fp->readRawData((char *)rgbe, sizeof(rgbe)) < 1) { return false; } if ((rgbe[0] != 2) || (rgbe[1] != 2) || (rgbe[2] & 0x80)) { /* this file is not run length encoded */ rgbe2float(&data[RGBE_DATA_RED], &data[RGBE_DATA_GREEN], &data[RGBE_DATA_BLUE], rgbe); data += RGBE_DATA_SIZE; return RGBE_ReadPixels(fp, data, scanline_width * num_scanlines - 1); } if ((((int)rgbe[2]) << 8 | rgbe[3]) != scanline_width) { return false; } ptr = (uchar *)scanline_buffer.data(); /* read each of the four channels for the scanline into the buffer */ for (i = 0; i < 4; i++) { ptr_end = (uchar *)scanline_buffer.data() + ((i + 1) * scanline_width); while (ptr < ptr_end) { if (fp->readRawData((char *)buf, sizeof(buf[0]) * 2) < 1) { return false; } if (buf[0] > 128) { /* a run of the same value */ count = buf[0] - 128; if ((count == 0) || (count > ptr_end - ptr)) { return false; } while (count-- > 0) *ptr++ = buf[1]; } else { /* a non-run */ count = buf[0]; if ((count == 0) || (count > ptr_end - ptr)) { return false; } *ptr++ = buf[1]; if (--count > 0) { if (fp->readRawData((char *)ptr, sizeof(*ptr) * count) < 1) { return false; } ptr += count; } } } } /* now convert data from buffer into floats */ for (i = 0; i < scanline_width; i++) { rgbe[0] = scanline_buffer[i]; rgbe[1] = scanline_buffer[i + scanline_width]; rgbe[2] = scanline_buffer[i + 2 * scanline_width]; rgbe[3] = scanline_buffer[i + 3 * scanline_width]; rgbe2float(&data[RGBE_DATA_RED], &data[RGBE_DATA_GREEN], &data[RGBE_DATA_BLUE], rgbe); data += RGBE_DATA_SIZE; } num_scanlines--; } return true; }