added Bitmap I/O support for the PPM file format

metadata
Wenzel Jakob 2014-03-02 21:06:25 +01:00
parent 25b538d1dc
commit 4b1abec7f6
5 changed files with 86 additions and 11 deletions

View File

@ -223,6 +223,16 @@ public:
*/ */
EPFM, EPFM,
/**
* \brief PPM (Portable Pixel Map) image format
*
* The following is supported
* <ul>
* <li>Loading and saving of \ref EUInt8 and \ref EUInt16 - based RGB bitmaps</li>
* </ul>
*/
EPPM,
/** /**
* \brief Joint Photographic Experts Group file format * \brief Joint Photographic Experts Group file format
* *
@ -1115,6 +1125,12 @@ protected:
/// Write a file using the PFM file format /// Write a file using the PFM file format
void writePFM(Stream *stream) const; void writePFM(Stream *stream) const;
/// Read a file stored using the PPM file format
void readPPM(Stream *stream);
/// Write a file using the PPM file format
void writePPM(Stream *stream) const;
/// Read a file stored using the TGA file format /// Read a file stored using the TGA file format
void readTGA(Stream *stream); void readTGA(Stream *stream);

View File

@ -305,6 +305,8 @@ Bitmap::Bitmap(EFileFormat format, Stream *stream, const std::string &prefix) :
format = ERGBE; format = ERGBE;
} else if (start[0] == 'P' && (start[1] == 'F' || start[1] == 'f')) { } else if (start[0] == 'P' && (start[1] == 'F' || start[1] == 'f')) {
format = EPFM; format = EPFM;
} else if (start[0] == 'P' && start[1] == '6') {
format = EPPM;
#if defined(MTS_HAS_LIBJPEG) #if defined(MTS_HAS_LIBJPEG)
} else if (start[0] == 0xFF && start[1] == 0xD8) { } else if (start[0] == 0xFF && start[1] == 0xD8) {
format = EJPEG; format = EJPEG;
@ -334,6 +336,7 @@ Bitmap::Bitmap(EFileFormat format, Stream *stream, const std::string &prefix) :
case EOpenEXR: readOpenEXR(stream, prefix); break; case EOpenEXR: readOpenEXR(stream, prefix); break;
case ERGBE: readRGBE(stream); break; case ERGBE: readRGBE(stream); break;
case EPFM: readPFM(stream); break; case EPFM: readPFM(stream); break;
case EPPM: readPPM(stream); break;
case ETGA: readTGA(stream); break; case ETGA: readTGA(stream); break;
case EPNG: readPNG(stream); break; case EPNG: readPNG(stream); break;
default: default:
@ -356,6 +359,7 @@ void Bitmap::write(EFileFormat format, Stream *stream, int compression) const {
case EOpenEXR: writeOpenEXR(stream); break; case EOpenEXR: writeOpenEXR(stream); break;
case ERGBE: writeRGBE(stream); break; case ERGBE: writeRGBE(stream); break;
case EPFM: writePFM(stream); break; case EPFM: writePFM(stream); break;
case EPPM: writePPM(stream); break;
default: default:
Log(EError, "Bitmap::write(): Invalid file format!"); Log(EError, "Bitmap::write(): Invalid file format!");
} }
@ -3402,6 +3406,54 @@ void Bitmap::writePFM(Stream *stream) const {
} }
} }
void Bitmap::readPPM(Stream *stream) {
int field = 0, nChars = 0;
std::string fields[4];
while (field < 4) {
char c = stream->readChar();
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
if (nChars != 0) {
nChars = 0;
++field;
}
} else {
fields[field] += c;
++nChars;
}
}
if (fields[0] != "P6")
Log(EError, "readPPM(): invalid format!");
int intValues[3];
for (int i=0; i<3; ++i) {
char *end_ptr = NULL;
intValues[i] = strtol(fields[i+1].c_str(), &end_ptr, 10);
if (*end_ptr != '\0')
SLog(EError, "readPPM(): unable to parse the file header!");
}
m_size.x = intValues[0];
m_size.y = intValues[1];
m_pixelFormat = ERGB;
m_channelCount = 3;
m_gamma = -1.0f;
m_ownsData = true;
m_componentFormat = intValues[2] <= 0xFF ? EUInt8 : EUInt16;
size_t size = getBufferSize();
m_data = static_cast<uint8_t *>(allocAligned(size));
stream->read(m_data, size);
}
void Bitmap::writePPM(Stream *stream) const {
if (m_pixelFormat != ERGB || (m_componentFormat != EUInt8 && m_componentFormat != EUInt16))
Log(EError, "writePPM(): Only 8 or 16-bit RGB images are supported");
stream->writeLine(formatString("P6\n%i\n%i\n%i\n", m_size.x, m_size.y,
m_componentFormat == EUInt8 ? 0xFF : 0xFFFF).c_str());
stream->write(m_data, getBufferSize());
}
void Bitmap::staticInitialization() { void Bitmap::staticInitialization() {
#if defined(MTS_HAS_OPENEXR) #if defined(MTS_HAS_OPENEXR)
/* Prevent races during the OpenEXR initialization */ /* Prevent races during the OpenEXR initialization */

View File

@ -1364,6 +1364,7 @@ void export_core() {
.value("EOpenEXR", Bitmap::EOpenEXR) .value("EOpenEXR", Bitmap::EOpenEXR)
.value("ETGA", Bitmap::ETGA) .value("ETGA", Bitmap::ETGA)
.value("EPFM", Bitmap::EPFM) .value("EPFM", Bitmap::EPFM)
.value("EPPM", Bitmap::EPPM)
.value("ERGBE", Bitmap::ERGBE) .value("ERGBE", Bitmap::ERGBE)
.value("EBMP", Bitmap::EBMP) .value("EBMP", Bitmap::EBMP)
.value("EJPEG", Bitmap::EJPEG) .value("EJPEG", Bitmap::EJPEG)

View File

@ -585,8 +585,8 @@ void MainWindow::on_actionOpen_triggered() {
QSettings settings; QSettings settings;
QStringList fileNames = QFileDialog::getOpenFileNames(this, QString(), QStringList fileNames = QFileDialog::getOpenFileNames(this, QString(),
settings.value("fileDir").toString(), settings.value("fileDir").toString(),
tr("All supported formats (*.xml *.exr *.rgbe *.hdr *.pfm *.png *.jpg *.jpeg);;" tr("All supported formats (*.xml *.exr *.rgbe *.hdr *.pfm *.ppm *.png *.jpg *.jpeg);;"
"Mitsuba scenes (*.xml);;High dynamic-range images (*.exr *.rgbe *.hdr *.pfm);;" "Mitsuba scenes (*.xml);;High dynamic-range images (*.exr *.rgbe *.hdr *.pfm *.ppm);;"
"Low dynamic-range images (*.png *.jpg *.jpeg)")); "Low dynamic-range images (*.png *.jpg *.jpeg)"));
QStringList::ConstIterator it = fileNames.constBegin(); QStringList::ConstIterator it = fileNames.constBegin();
@ -605,8 +605,8 @@ void MainWindow::onOpenDialogClose(int reason) { /* unused */ }
void MainWindow::on_actionOpen_triggered() { void MainWindow::on_actionOpen_triggered() {
QFileDialog *dialog = new QFileDialog(this, Qt::Sheet); QFileDialog *dialog = new QFileDialog(this, Qt::Sheet);
dialog->setNameFilter(tr("All supported formats (*.xml *.exr *.rgbe *.hdr *.pfm *.png *.jpg *.jpeg);;" dialog->setNameFilter(tr("All supported formats (*.xml *.exr *.rgbe *.hdr *.pfm *.ppm *.png *.jpg *.jpeg);;"
"Mitsuba scenes (*.xml);;High dynamic-range images (*.exr *.rgbe *.hdr *.pfm);;Low " "Mitsuba scenes (*.xml);;High dynamic-range images (*.exr *.rgbe *.hdr *.pfm *.ppm);;Low "
"dynamic-range images (*.png *.jpg *.jpeg)")); "dynamic-range images (*.png *.jpg *.jpeg)"));
dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->setAcceptMode(QFileDialog::AcceptOpen); dialog->setAcceptMode(QFileDialog::AcceptOpen);
@ -1498,6 +1498,7 @@ void MainWindow::on_actionExportImage_triggered() {
"High dynamic range OpenEXR image (*.exr);;" "High dynamic range OpenEXR image (*.exr);;"
"High dynamic range Radiance RGBE image (*.rgbe *.hdr);;" "High dynamic range Radiance RGBE image (*.rgbe *.hdr);;"
"High dynamic range Portable Float Map image (*.pfm);;" "High dynamic range Portable Float Map image (*.pfm);;"
"High dynamic range Portable Pixel Map image (*.ppm);;"
"Tonemapped low dynamic range image (*.png *.jpg *.jpeg)")); "Tonemapped low dynamic range image (*.png *.jpg *.jpeg)"));
if (!fileName.isEmpty()) { if (!fileName.isEmpty()) {
QSettings settings; QSettings settings;
@ -1516,6 +1517,7 @@ void MainWindow::on_actionExportImage_triggered() {
"High dynamic range OpenEXR image (*.exr);;" "High dynamic range OpenEXR image (*.exr);;"
"High dynamic range Radiance RGBE image (*.rgbe *.hdr);;" "High dynamic range Radiance RGBE image (*.rgbe *.hdr);;"
"High dynamic range Portable Float Map image (*.pfm);;" "High dynamic range Portable Float Map image (*.pfm);;"
"High dynamic range Portable Pixel Map image (*.ppm);;"
"Tonemapped low dynamic range image (*.png *.jpg *.jpeg)")); "Tonemapped low dynamic range image (*.png *.jpg *.jpeg)"));
QSettings settings; QSettings settings;
@ -1554,23 +1556,27 @@ void MainWindow::onExportDialogClose(int reason) {
void MainWindow::exportImage(const QString &fileName) { void MainWindow::exportImage(const QString &fileName) {
if (!fileName.isEmpty()) { if (!fileName.isEmpty()) {
Bitmap::EComponentFormat compFormat = Bitmap::EInvalid;
Bitmap::EFileFormat format; Bitmap::EFileFormat format;
bool isHDR = true;
if (fileName.endsWith(".exr")) { if (fileName.endsWith(".exr")) {
format = Bitmap::EOpenEXR; format = Bitmap::EOpenEXR;
} else if (fileName.endsWith(".png") || fileName == "__clipboard__") { } else if (fileName.endsWith(".png") || fileName == "__clipboard__") {
format = Bitmap::EPNG; format = Bitmap::EPNG;
isHDR = false; compFormat = Bitmap::EUInt8;
} else if (fileName.endsWith(".hdr") || fileName.endsWith(".rgbe")) { } else if (fileName.endsWith(".hdr") || fileName.endsWith(".rgbe")) {
format = Bitmap::ERGBE; format = Bitmap::ERGBE;
} else if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")) { } else if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")) {
format = Bitmap::EJPEG; format = Bitmap::EJPEG;
isHDR = false; compFormat = Bitmap::EUInt8;
} else if (fileName.endsWith(".pfm")) { } else if (fileName.endsWith(".pfm")) {
format = Bitmap::EPFM; format = Bitmap::EPFM;
} else if (fileName.endsWith(".ppm")) {
format = Bitmap::EPPM;
compFormat = Bitmap::EUInt16;
} else { } else {
SLog(EError, "Unknown file type -- the filename must end in either" SLog(EError, "Unknown file type -- the filename must end in either"
" .exr, .rgbe, .hdr, .pfm, .png, .jpg, or .jpeg"); " .exr, .rgbe, .hdr, .pfm, .ppm, .png, .jpg, or .jpeg");
return; return;
} }
@ -1581,7 +1587,7 @@ void MainWindow::exportImage(const QString &fileName) {
ui->glView->downloadFramebuffer(); ui->glView->downloadFramebuffer();
ref<Bitmap> bitmap = ctx->framebuffer; ref<Bitmap> bitmap = ctx->framebuffer;
if (!isHDR) { if (compFormat == Bitmap::EUInt8 || compFormat == Bitmap::EUInt16) {
/* Tonemap the image */ /* Tonemap the image */
if (ctx->toneMappingMethod == EReinhard) { if (ctx->toneMappingMethod == EReinhard) {
Float logAvgLuminance = 0, maxLuminance = 0; /* Unused */ Float logAvgLuminance = 0, maxLuminance = 0; /* Unused */
@ -1592,7 +1598,7 @@ void MainWindow::exportImage(const QString &fileName) {
ctx->reinhardKey, burn); ctx->reinhardKey, burn);
} }
bitmap = bitmap->convert(Bitmap::ERGB, Bitmap::EUInt8, bitmap = bitmap->convert(Bitmap::ERGB, compFormat,
ctx->srgb ? (Float) -1 : ctx->gamma, ctx->srgb ? (Float) -1 : ctx->gamma,
ctx->toneMappingMethod == EReinhard ctx->toneMappingMethod == EReinhard
? (Float) 1.0f : std::pow((Float) 2, ctx->exposure)); ? (Float) 1.0f : std::pow((Float) 2, ctx->exposure));

View File

@ -67,7 +67,7 @@ void SceneLoader::run() {
m_result->diffuseReceivers = settings.value("preview_diffuseReceivers", false).toBool(); m_result->diffuseReceivers = settings.value("preview_diffuseReceivers", false).toBool();
if (suffix == "exr" || suffix == "png" || suffix == "jpg" || suffix == "jpeg" || if (suffix == "exr" || suffix == "png" || suffix == "jpg" || suffix == "jpeg" ||
suffix == "hdr" || suffix == "rgbe" || suffix == "pfm") { suffix == "hdr" || suffix == "rgbe" || suffix == "pfm" || suffix == "ppm") {
/* This is an image, not a scene */ /* This is an image, not a scene */
ref<FileStream> fs = new FileStream(toFsPath(m_filename), FileStream::EReadOnly); ref<FileStream> fs = new FileStream(toFsPath(m_filename), FileStream::EReadOnly);
ref<Bitmap> bitmap = new Bitmap(Bitmap::EAuto, fs); ref<Bitmap> bitmap = new Bitmap(Bitmap::EAuto, fs);