added Bitmap I/O support for the PPM file format
parent
25b538d1dc
commit
4b1abec7f6
|
@ -223,6 +223,16 @@ public:
|
|||
*/
|
||||
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
|
||||
*
|
||||
|
@ -1115,6 +1125,12 @@ protected:
|
|||
/// Write a file using the PFM file format
|
||||
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
|
||||
void readTGA(Stream *stream);
|
||||
|
||||
|
|
|
@ -305,6 +305,8 @@ Bitmap::Bitmap(EFileFormat format, Stream *stream, const std::string &prefix) :
|
|||
format = ERGBE;
|
||||
} else if (start[0] == 'P' && (start[1] == 'F' || start[1] == 'f')) {
|
||||
format = EPFM;
|
||||
} else if (start[0] == 'P' && start[1] == '6') {
|
||||
format = EPPM;
|
||||
#if defined(MTS_HAS_LIBJPEG)
|
||||
} else if (start[0] == 0xFF && start[1] == 0xD8) {
|
||||
format = EJPEG;
|
||||
|
@ -334,6 +336,7 @@ Bitmap::Bitmap(EFileFormat format, Stream *stream, const std::string &prefix) :
|
|||
case EOpenEXR: readOpenEXR(stream, prefix); break;
|
||||
case ERGBE: readRGBE(stream); break;
|
||||
case EPFM: readPFM(stream); break;
|
||||
case EPPM: readPPM(stream); break;
|
||||
case ETGA: readTGA(stream); break;
|
||||
case EPNG: readPNG(stream); break;
|
||||
default:
|
||||
|
@ -356,6 +359,7 @@ void Bitmap::write(EFileFormat format, Stream *stream, int compression) const {
|
|||
case EOpenEXR: writeOpenEXR(stream); break;
|
||||
case ERGBE: writeRGBE(stream); break;
|
||||
case EPFM: writePFM(stream); break;
|
||||
case EPPM: writePPM(stream); break;
|
||||
default:
|
||||
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() {
|
||||
#if defined(MTS_HAS_OPENEXR)
|
||||
/* Prevent races during the OpenEXR initialization */
|
||||
|
|
|
@ -1364,6 +1364,7 @@ void export_core() {
|
|||
.value("EOpenEXR", Bitmap::EOpenEXR)
|
||||
.value("ETGA", Bitmap::ETGA)
|
||||
.value("EPFM", Bitmap::EPFM)
|
||||
.value("EPPM", Bitmap::EPPM)
|
||||
.value("ERGBE", Bitmap::ERGBE)
|
||||
.value("EBMP", Bitmap::EBMP)
|
||||
.value("EJPEG", Bitmap::EJPEG)
|
||||
|
|
|
@ -585,8 +585,8 @@ void MainWindow::on_actionOpen_triggered() {
|
|||
QSettings settings;
|
||||
QStringList fileNames = QFileDialog::getOpenFileNames(this, QString(),
|
||||
settings.value("fileDir").toString(),
|
||||
tr("All supported formats (*.xml *.exr *.rgbe *.hdr *.pfm *.png *.jpg *.jpeg);;"
|
||||
"Mitsuba scenes (*.xml);;High dynamic-range images (*.exr *.rgbe *.hdr *.pfm);;"
|
||||
tr("All supported formats (*.xml *.exr *.rgbe *.hdr *.pfm *.ppm *.png *.jpg *.jpeg);;"
|
||||
"Mitsuba scenes (*.xml);;High dynamic-range images (*.exr *.rgbe *.hdr *.pfm *.ppm);;"
|
||||
"Low dynamic-range images (*.png *.jpg *.jpeg)"));
|
||||
|
||||
QStringList::ConstIterator it = fileNames.constBegin();
|
||||
|
@ -605,8 +605,8 @@ void MainWindow::onOpenDialogClose(int reason) { /* unused */ }
|
|||
|
||||
void MainWindow::on_actionOpen_triggered() {
|
||||
QFileDialog *dialog = new QFileDialog(this, Qt::Sheet);
|
||||
dialog->setNameFilter(tr("All supported formats (*.xml *.exr *.rgbe *.hdr *.pfm *.png *.jpg *.jpeg);;"
|
||||
"Mitsuba scenes (*.xml);;High dynamic-range images (*.exr *.rgbe *.hdr *.pfm);;Low "
|
||||
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 *.ppm);;Low "
|
||||
"dynamic-range images (*.png *.jpg *.jpeg)"));
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
dialog->setAcceptMode(QFileDialog::AcceptOpen);
|
||||
|
@ -1498,6 +1498,7 @@ void MainWindow::on_actionExportImage_triggered() {
|
|||
"High dynamic range OpenEXR image (*.exr);;"
|
||||
"High dynamic range Radiance RGBE image (*.rgbe *.hdr);;"
|
||||
"High dynamic range Portable Float Map image (*.pfm);;"
|
||||
"High dynamic range Portable Pixel Map image (*.ppm);;"
|
||||
"Tonemapped low dynamic range image (*.png *.jpg *.jpeg)"));
|
||||
if (!fileName.isEmpty()) {
|
||||
QSettings settings;
|
||||
|
@ -1516,6 +1517,7 @@ void MainWindow::on_actionExportImage_triggered() {
|
|||
"High dynamic range OpenEXR image (*.exr);;"
|
||||
"High dynamic range Radiance RGBE image (*.rgbe *.hdr);;"
|
||||
"High dynamic range Portable Float Map image (*.pfm);;"
|
||||
"High dynamic range Portable Pixel Map image (*.ppm);;"
|
||||
"Tonemapped low dynamic range image (*.png *.jpg *.jpeg)"));
|
||||
|
||||
QSettings settings;
|
||||
|
@ -1554,23 +1556,27 @@ void MainWindow::onExportDialogClose(int reason) {
|
|||
|
||||
void MainWindow::exportImage(const QString &fileName) {
|
||||
if (!fileName.isEmpty()) {
|
||||
Bitmap::EComponentFormat compFormat = Bitmap::EInvalid;
|
||||
Bitmap::EFileFormat format;
|
||||
bool isHDR = true;
|
||||
|
||||
if (fileName.endsWith(".exr")) {
|
||||
format = Bitmap::EOpenEXR;
|
||||
} else if (fileName.endsWith(".png") || fileName == "__clipboard__") {
|
||||
format = Bitmap::EPNG;
|
||||
isHDR = false;
|
||||
compFormat = Bitmap::EUInt8;
|
||||
} else if (fileName.endsWith(".hdr") || fileName.endsWith(".rgbe")) {
|
||||
format = Bitmap::ERGBE;
|
||||
} else if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")) {
|
||||
format = Bitmap::EJPEG;
|
||||
isHDR = false;
|
||||
compFormat = Bitmap::EUInt8;
|
||||
} else if (fileName.endsWith(".pfm")) {
|
||||
format = Bitmap::EPFM;
|
||||
} else if (fileName.endsWith(".ppm")) {
|
||||
format = Bitmap::EPPM;
|
||||
compFormat = Bitmap::EUInt16;
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1581,7 +1587,7 @@ void MainWindow::exportImage(const QString &fileName) {
|
|||
ui->glView->downloadFramebuffer();
|
||||
|
||||
ref<Bitmap> bitmap = ctx->framebuffer;
|
||||
if (!isHDR) {
|
||||
if (compFormat == Bitmap::EUInt8 || compFormat == Bitmap::EUInt16) {
|
||||
/* Tonemap the image */
|
||||
if (ctx->toneMappingMethod == EReinhard) {
|
||||
Float logAvgLuminance = 0, maxLuminance = 0; /* Unused */
|
||||
|
@ -1592,7 +1598,7 @@ void MainWindow::exportImage(const QString &fileName) {
|
|||
ctx->reinhardKey, burn);
|
||||
}
|
||||
|
||||
bitmap = bitmap->convert(Bitmap::ERGB, Bitmap::EUInt8,
|
||||
bitmap = bitmap->convert(Bitmap::ERGB, compFormat,
|
||||
ctx->srgb ? (Float) -1 : ctx->gamma,
|
||||
ctx->toneMappingMethod == EReinhard
|
||||
? (Float) 1.0f : std::pow((Float) 2, ctx->exposure));
|
||||
|
|
|
@ -67,7 +67,7 @@ void SceneLoader::run() {
|
|||
m_result->diffuseReceivers = settings.value("preview_diffuseReceivers", false).toBool();
|
||||
|
||||
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 */
|
||||
ref<FileStream> fs = new FileStream(toFsPath(m_filename), FileStream::EReadOnly);
|
||||
ref<Bitmap> bitmap = new Bitmap(Bitmap::EAuto, fs);
|
||||
|
|
Loading…
Reference in New Issue