Alex Merry c9ca1f1862 Rename headers to end with _p.h
Frameworks have a convention of naming uninstalled headers in src/ with
a _p at the end of the name, to make it clear they are not part of the
API. None of the headers in KImageFormats are installed, so it is not
really necessary to follow this convention, but we follow it anyway for
the benefit of both humans and tools (like kapidox).
2014-08-03 18:08:49 +01:00

239 lines
5.9 KiB
C++

/* This file is part of the KDE project
Copyright (C) 2005 Christoph Hormann <chris_hormann@gmx.de>
Copyright (C) 2005 Ignacio Castaño <castanyo@yahoo.es>
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_p.h"
#include <QImage>
#include <QtCore/QDataStream>
#include <QDebug>
typedef Q_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, QDataStream &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] = qRgb(ClipToByte(float(image[0]) * v),
ClipToByte(float(image[1]) * v),
ClipToByte(float(image[2]) * v));
image += 4;
}
}
// Load the HDR image.
static bool LoadHDR(QDataStream &s, const int width, const int height, QImage &img)
{
uchar val, code;
// Create dst image.
if (!img.create(width, height, 32)) {
return false;
}
QMemArray<uchar> 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.device()->at(s.device()->at() - 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
Q_DECL_EXPORT void kimgio_hdr_read(QImageIO *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) {
// qDebug() << "Unknown HDR format.";
io->setImage(0);
io->setStatus(-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 )
{
// qDebug() << "Invalid HDR file.";
io->setImage(0);
io->setStatus(-1);
return;
}
QDataStream s(io->ioDevice());
QImage img;
if (!LoadHDR(s, width, height, img)) {
// qDebug() << "Error loading HDR file.";
io->setImage(0);
io->setStatus(-1);
return;
}
io->setImage(img);
io->setStatus(0);
}
Q_DECL_EXPORT void kimgio_hdr_write(QImageIO *)
{
// intentionally not implemented (since writing low dynamic range data to a HDR file is nonsense.)
}