From beda4440ab82ed4e8f7568fd5a19d8d595b748a3 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jos=C3=A9=20Fonseca?= Date: Thu, 12 Sep 2013 17:25:04 +0100 Subject: [PATCH] image: Support reading PFM images. --- gui/retracer.cpp | 13 +++++--- image/image.hpp | 14 +++++++- image/image_pnm.cpp | 78 ++++++++++++++++++++++++++++++++++++++------- 3 files changed, 88 insertions(+), 17 deletions(-) diff --git a/gui/retracer.cpp b/gui/retracer.cpp index cb0bad3..b42446b 100644 --- a/gui/retracer.cpp +++ b/gui/retracer.cpp @@ -395,9 +395,7 @@ void Retracer::run() */ while (!io.atEnd()) { - unsigned channels = 0; - unsigned width = 0; - unsigned height = 0; + image::PNMInfo info; char header[512]; qint64 headerSize = 0; @@ -414,14 +412,19 @@ void Retracer::run() headerSize += headerRead; } - const char *headerEnd = image::readPNMHeader(header, headerSize, &channels, &width, &height); + const char *headerEnd = image::readPNMHeader(header, headerSize, info); // if invalid PNM header was encountered, ... - if (header == headerEnd) { + if (headerEnd == NULL || + info.channelType != image::TYPE_UNORM8) { qDebug() << "error: invalid snapshot stream encountered"; break; } + unsigned channels = info.channels; + unsigned width = info.width; + unsigned height = info.height; + // qDebug() << "channels: " << channels << ", width: " << width << ", height: " << height"; QImage snapshot = QImage(width, height, channels == 1 ? QImage::Format_Mono : QImage::Format_RGB888); diff --git a/image/image.hpp b/image/image.hpp index 1b21acd..857e062 100644 --- a/image/image.hpp +++ b/image/image.hpp @@ -126,8 +126,20 @@ readPNG(std::istream &is); Image * readPNG(const char *filename); + +struct PNMInfo +{ + unsigned width; + unsigned height; + unsigned channels; + ChannelType channelType; +}; + const char * -readPNMHeader(const char *buffer, size_t size, unsigned *channels, unsigned *width, unsigned *height); +readPNMHeader(const char *buffer, size_t size, PNMInfo &info); + +Image * +readPNM(const char *buffer, size_t bufferSize); } /* namespace image */ diff --git a/image/image_pnm.cpp b/image/image_pnm.cpp index a0638dc..df88c58 100644 --- a/image/image_pnm.cpp +++ b/image/image_pnm.cpp @@ -67,6 +67,8 @@ Image::writePNM(std::ostream &os, const char *comment) const outChannels = 3; } break; + default: + assert(0); } os << identifier << "\n"; @@ -189,24 +191,49 @@ Image::writePNM(const char *filename, const char *comment) const } +/** + * Parse PNM header. + * + * Returns pointer to data start, or NULL on failure. + */ const char * -readPNMHeader(const char *buffer, size_t bufferSize, unsigned *channels, unsigned *width, unsigned *height) +readPNMHeader(const char *buffer, size_t bufferSize, PNMInfo &info) { - *channels = 0; - *width = 0; - *height = 0; + info.channels = 0; + info.width = 0; + info.height = 0; const char *currentBuffer = buffer; const char *nextBuffer; // parse number of channels - int scannedChannels = sscanf(currentBuffer, "P%d\n", channels); + char c; + int scannedChannels = sscanf(currentBuffer, "P%c\n", &c); if (scannedChannels != 1) { // validate scanning of channels // invalid channel line - return buffer; + return NULL; } // convert channel token to number of channels - *channels = (*channels == 5) ? 1 : 3; + switch (c) { + case '5': + info.channels = 1; + info.channelType = TYPE_UNORM8; + break; + case '6': + info.channels = 3; + info.channelType = TYPE_UNORM8; + break; + case 'f': + info.channels = 1; + info.channelType = TYPE_FLOAT; + break; + case 'F': + info.channels = 3; + info.channelType = TYPE_FLOAT; + break; + default: + return NULL; + } // advance past channel line nextBuffer = (const char *) memchr((const void *) currentBuffer, '\n', bufferSize) + 1; @@ -222,10 +249,10 @@ readPNMHeader(const char *buffer, size_t bufferSize, unsigned *channels, unsigne } // parse dimensions of image - int scannedDimensions = sscanf(currentBuffer, "%d %d\n", width, height); + int scannedDimensions = sscanf(currentBuffer, "%u %u\n", &info.width, &info.height); if (scannedDimensions != 2) { // validate scanning of dimensions // invalid dimension line - return buffer; + return NULL; } // advance past dimension line @@ -233,11 +260,40 @@ readPNMHeader(const char *buffer, size_t bufferSize, unsigned *channels, unsigne bufferSize -= nextBuffer - currentBuffer; currentBuffer = nextBuffer; - // skip over "255\n" at end of header - nextBuffer = (const char *) memchr((const void *) currentBuffer, '\n', bufferSize) + 1; + if (info.channelType == TYPE_UNORM8) { + // skip over "255\n" at end of header + nextBuffer = (const char *) memchr((const void *) currentBuffer, '\n', bufferSize) + 1; + } // return start of image data return nextBuffer; } + +Image * +readPNM(const char *buffer, size_t bufferSize) +{ + PNMInfo info; + + const char *headerEnd = readPNMHeader(buffer, bufferSize, info); + + // if invalid PNM header was encountered, ... + if (headerEnd == NULL) { + std::cerr << "error: invalid PNM header"; + return NULL; + } + + Image *image = new Image(info.width, info.height, info.channels, false, info.channelType); + + size_t rowBytes = info.width * image->bytesPerPixel; + for (unsigned char *row = image->start(); row != image->end(); row += image->stride()) { + memcpy(row, headerEnd, rowBytes); + headerEnd += rowBytes; + } + + return image; +} + + + } /* namespace image */ -- 2.43.0