X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=image%2Fimage_pnm.cpp;h=a0638dc59356c58840b03a539e80a7dead4049ba;hb=dfd413a5f54bd450850b5e84886949bcdf85b1e7;hp=9e9d0e1be9cb3542a63814730a081354000c20cf;hpb=08473e50e90059e75d6e7bce7e12be8bf6dd028b;p=apitrace diff --git a/image/image_pnm.cpp b/image/image_pnm.cpp index 9e9d0e1..a0638dc 100644 --- a/image/image_pnm.cpp +++ b/image/image_pnm.cpp @@ -40,73 +40,138 @@ namespace image { /** * http://en.wikipedia.org/wiki/Netpbm_format * http://netpbm.sourceforge.net/doc/ppm.html + * http://netpbm.sourceforge.net/doc/pfm.html */ void Image::writePNM(std::ostream &os, const char *comment) const { + const char *identifier; + unsigned outChannels; + + switch (channelType) { + case TYPE_UNORM8: + if (channels == 1) { + identifier = "P5"; + outChannels = 1; + } else { + identifier = "P6"; + outChannels = 3; + } + break; + case TYPE_FLOAT: + if (channels == 1) { + identifier = "Pf"; + outChannels = 1; + } else { + identifier = "PF"; + outChannels = 3; + } + break; + } + + os << identifier << "\n"; - os << (channels == 1 ? "P5" : "P6") << "\n"; if (comment) { os << "#" << comment << "\n"; } os << width << " " << height << "\n"; - os << "255" << "\n"; + + if (channelType == TYPE_UNORM8) { + os << "255" << "\n"; + } const unsigned char *row; - if (channels == 1 || channels == 3) { + if (channels == outChannels) { + /* + * Write whole pixel spans straight from the image buffer. + */ + for (row = start(); row != end(); row += stride()) { - os.write((const char *)row, width*channels); + os.write((const char *)row, width*bytesPerPixel); } } else { - unsigned char *tmp = new unsigned char[width*3]; - if (channels == 4) { - for (row = start(); row != end(); row += stride()) { - const uint32_t *src = (const uint32_t *)row; - uint32_t *dst = (uint32_t *)tmp; - unsigned x; - for (x = 0; x + 4 <= width; x += 4) { - /* - * It's much faster to access dwords than bytes. - * - * FIXME: Big-endian version. - */ - - uint32_t rgba0 = *src++ & 0xffffff; - uint32_t rgba1 = *src++ & 0xffffff; - uint32_t rgba2 = *src++ & 0xffffff; - uint32_t rgba3 = *src++ & 0xffffff; - uint32_t rgb0 = rgba0 - | (rgba1 << 24); - uint32_t rgb1 = (rgba1 >> 8) - | (rgba2 << 16); - uint32_t rgb2 = (rgba2 >> 16) - | (rgba3 << 8); - *dst++ = rgb0; - *dst++ = rgb1; - *dst++ = rgb2; + /* + * Need to add/remove channels, one pixel at a time. + */ + + unsigned char *tmp = new unsigned char[width*bytesPerPixel]; + + if (channelType == TYPE_UNORM8) { + /* + * Optimized path for 8bit unorms. + */ + + if (channels == 4) { + for (row = start(); row != end(); row += stride()) { + const uint32_t *src = (const uint32_t *)row; + uint32_t *dst = (uint32_t *)tmp; + unsigned x; + for (x = 0; x + 4 <= width; x += 4) { + /* + * It's much faster to access dwords than bytes. + * + * FIXME: Big-endian version. + */ + + uint32_t rgba0 = *src++ & 0xffffff; + uint32_t rgba1 = *src++ & 0xffffff; + uint32_t rgba2 = *src++ & 0xffffff; + uint32_t rgba3 = *src++ & 0xffffff; + uint32_t rgb0 = rgba0 + | (rgba1 << 24); + uint32_t rgb1 = (rgba1 >> 8) + | (rgba2 << 16); + uint32_t rgb2 = (rgba2 >> 16) + | (rgba3 << 8); + *dst++ = rgb0; + *dst++ = rgb1; + *dst++ = rgb2; + } + for (; x < width; ++x) { + tmp[x*3 + 0] = row[x*4 + 0]; + tmp[x*3 + 1] = row[x*4 + 1]; + tmp[x*3 + 2] = row[x*4 + 2]; + } + os.write((const char *)tmp, width*3); } - for (; x < width; ++x) { - tmp[x*3 + 0] = row[x*4 + 0]; - tmp[x*3 + 1] = row[x*4 + 1]; - tmp[x*3 + 2] = row[x*4 + 2]; + } else if (channels == 2) { + for (row = start(); row != end(); row += stride()) { + const unsigned char *src = row; + unsigned char *dst = tmp; + for (unsigned x = 0; x < width; ++x) { + *dst++ = *src++; + *dst++ = *src++; + *dst++ = 0; + } + os.write((const char *)tmp, width*3); } - os.write((const char *)tmp, width*3); + } else { + assert(0); } - } else if (channels == 2) { + } else { + /* + * General path for float images. + */ + + assert(channelType == TYPE_FLOAT); + for (row = start(); row != end(); row += stride()) { - const unsigned char *src = row; - unsigned char *dst = tmp; + const float *src = (const float *)row; + float *dst = (float *)tmp; for (unsigned x = 0; x < width; ++x) { - *dst++ = *src++; - *dst++ = *src++; - *dst++ = 0; + unsigned channel = 0; + for (; channel < channels; ++channel) { + *dst++ = *src++; + } + for (; channel < channels; ++channel) { + *dst++ = 0; + } } - os.write((const char *)tmp, width*3); + os.write((const char *)tmp, width*bytesPerPixel); } - } else { - assert(0); } + delete [] tmp; } }