diff options
author | Jose Fonseca <jfonseca@vmware.com> | 2016-05-05 11:09:52 +0100 |
---|---|---|
committer | Jose Fonseca <jfonseca@vmware.com> | 2016-05-05 11:09:52 +0100 |
commit | bceafecaa6a3e606dfc31c0016cecb9e82d5cab8 (patch) | |
tree | 7dbe09eb4846dc76a1ac7c4dbf976fd30fa04da2 /lib | |
parent | be6cf883b322b52371f7a45bea4d0339ed2fc29d (diff) |
image: Move into lib.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/image/CMakeLists.txt | 18 | ||||
-rw-r--r-- | lib/image/README.markdown | 2 | ||||
-rw-r--r-- | lib/image/image.hpp | 156 | ||||
-rw-r--r-- | lib/image/image_bmp.cpp | 142 | ||||
-rw-r--r-- | lib/image/image_md5.cpp | 64 | ||||
-rw-r--r-- | lib/image/image_png.cpp | 277 | ||||
-rw-r--r-- | lib/image/image_pnm.cpp | 319 | ||||
-rw-r--r-- | lib/image/image_raw.cpp | 66 |
9 files changed, 1045 insertions, 0 deletions
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 3ce90a6e..813e180a 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory (guids) add_subdirectory (highlight) +add_subdirectory (image) diff --git a/lib/image/CMakeLists.txt b/lib/image/CMakeLists.txt new file mode 100644 index 00000000..1cc3c4ce --- /dev/null +++ b/lib/image/CMakeLists.txt @@ -0,0 +1,18 @@ +include_directories ( + ${PNG_INCLUDE_DIR} + ${MD5_INCLUDE_DIR} +) + +add_library (image STATIC + image.hpp + image_bmp.cpp + image_png.cpp + image_pnm.cpp + image_raw.cpp + image_md5.cpp +) + +target_link_libraries (image + ${PNG_LIBRARIES} + ${MD5_LIBRARIES} +) diff --git a/lib/image/README.markdown b/lib/image/README.markdown new file mode 100644 index 00000000..b2909713 --- /dev/null +++ b/lib/image/README.markdown @@ -0,0 +1,2 @@ +This directory contains a class to represent and manipulate images, in memory +or disk. diff --git a/lib/image/image.hpp b/lib/image/image.hpp new file mode 100644 index 00000000..e6f0d226 --- /dev/null +++ b/lib/image/image.hpp @@ -0,0 +1,156 @@ +/************************************************************************** + * + * Copyright 2008-2010 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + +/* + * Image I/O. + */ + +#pragma once + + +#include <iostream> + +#include <string> + + +namespace image { + + +enum ChannelType { + TYPE_UNORM8 = 0, + TYPE_FLOAT +}; + + +class Image { +public: + unsigned width; + unsigned height; + unsigned channels; + ChannelType channelType; + unsigned bytesPerChannel; + unsigned bytesPerPixel; + + // Flipped vertically or not + bool flipped; + + // Pixels in RGBA format + unsigned char *pixels; + + std::string label; + + inline Image(unsigned w, unsigned h, unsigned c = 4, bool f = false, ChannelType t = TYPE_UNORM8) : + width(w), + height(h), + channels(c), + channelType(t), + bytesPerChannel(t == TYPE_FLOAT ? 4 : 1), + bytesPerPixel(channels * bytesPerChannel), + flipped(f), + pixels(new unsigned char[h*w*bytesPerPixel]) + {} + + inline ~Image() { + delete [] pixels; + } + + // Absolute stride + inline unsigned + _stride() const { + return width*bytesPerPixel; + } + + inline unsigned char *start(void) { + return flipped ? pixels + (height - 1)*_stride() : pixels; + } + + inline const unsigned char *start(void) const { + return flipped ? pixels + (height - 1)*_stride() : pixels; + } + + inline unsigned char *end(void) { + return flipped ? pixels - _stride() : pixels + height*_stride(); + } + + inline const unsigned char *end(void) const { + return flipped ? pixels - _stride() : pixels + height*_stride(); + } + + inline signed stride(void) const { + return flipped ? -(signed)_stride() : _stride(); + } + + bool + writeBMP(const char *filename) const; + + void + writePNM(std::ostream &os, const char *comment = NULL) const; + + bool + writePNM(const char *filename, const char *comment = NULL) const; + + void + writeMD5(std::ostream &os) const; + + bool + writePNG(std::ostream &os, bool strip_alpha = false) const; + + bool + writePNG(const char *filename, bool strip_alpha = false) const; + + void + writeRAW(std::ostream &os) const; + + bool + writeRAW(const char *filename) const; +}; + + +Image * +readPNG(std::istream &is); + +Image * +readPNG(const char *filename); + + +struct PNMInfo +{ + unsigned width; + unsigned height; + unsigned channels; + ChannelType channelType; + int commentNumber; +}; + +const char * +readPNMHeader(const char *buffer, size_t size, PNMInfo &info); + +Image * +readPNM(const char *buffer, size_t bufferSize); + + +} /* namespace image */ + + diff --git a/lib/image/image_bmp.cpp b/lib/image/image_bmp.cpp new file mode 100644 index 00000000..d349be06 --- /dev/null +++ b/lib/image/image_bmp.cpp @@ -0,0 +1,142 @@ +/************************************************************************** + * + * Copyright 2011 Jose Fonseca + * Copyright 2008-2010 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + + +#include <assert.h> +#include <stdint.h> + +#include <fstream> + +#include "image.hpp" + + +namespace image { + + +#pragma pack(push,2) +struct FileHeader { + uint16_t bfType; + uint32_t bfSize; + uint16_t bfReserved1; + uint16_t bfReserved2; + uint32_t bfOffBits; +}; +#pragma pack(pop) + +struct InfoHeader { + uint32_t biSize; + int32_t biWidth; + int32_t biHeight; + uint16_t biPlanes; + uint16_t biBitCount; + uint32_t biCompression; + uint32_t biSizeImage; + int32_t biXPelsPerMeter; + int32_t biYPelsPerMeter; + uint32_t biClrUsed; + uint32_t biClrImportant; +}; + +struct Pixel { + uint8_t rgbBlue; + uint8_t rgbGreen; + uint8_t rgbRed; + uint8_t rgbAlpha; +}; + + +bool +Image::writeBMP(const char *filename) const { + assert(channels == 4); + assert(channelType == TYPE_UNORM8); + + struct FileHeader bmfh; + struct InfoHeader bmih; + unsigned x, y; + + bmfh.bfType = 0x4d42; + bmfh.bfSize = 14 + 40 + height*width*4; + bmfh.bfReserved1 = 0; + bmfh.bfReserved2 = 0; + bmfh.bfOffBits = 14 + 40; + + bmih.biSize = 40; + bmih.biWidth = width; + bmih.biHeight = height; + bmih.biPlanes = 1; + bmih.biBitCount = 32; + bmih.biCompression = 0; + bmih.biSizeImage = height*width*4; + bmih.biXPelsPerMeter = 0; + bmih.biYPelsPerMeter = 0; + bmih.biClrUsed = 0; + bmih.biClrImportant = 0; + + std::ofstream stream(filename, std::ofstream::binary); + + if (!stream) { + return false; + } + + stream.write((const char *)&bmfh, 14); + stream.write((const char *)&bmih, 40); + + unsigned stride = width*4; + + if (flipped) { + for (y = 0; y < height; ++y) { + const unsigned char *ptr = pixels + y * stride; + for (x = 0; x < width; ++x) { + struct Pixel pixel; + pixel.rgbRed = ptr[x*4 + 0]; + pixel.rgbGreen = ptr[x*4 + 1]; + pixel.rgbBlue = ptr[x*4 + 2]; + pixel.rgbAlpha = ptr[x*4 + 3]; + stream.write((const char *)&pixel, 4); + } + } + } else { + y = height; + while (y--) { + const unsigned char *ptr = pixels + y * stride; + for (x = 0; x < width; ++x) { + struct Pixel pixel; + pixel.rgbRed = ptr[x*4 + 0]; + pixel.rgbGreen = ptr[x*4 + 1]; + pixel.rgbBlue = ptr[x*4 + 2]; + pixel.rgbAlpha = ptr[x*4 + 3]; + stream.write((const char *)&pixel, 4); + } + } + } + + stream.close(); + + return true; +} + + +} /* namespace image */ diff --git a/lib/image/image_md5.cpp b/lib/image/image_md5.cpp new file mode 100644 index 00000000..85141e18 --- /dev/null +++ b/lib/image/image_md5.cpp @@ -0,0 +1,64 @@ +/************************************************************************** + * + * Copyright (C) 2013 Intel Corporation. All rights reversed. + * Author: Meng Mengmeng <mengmeng.meng@intel.com> + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + + +#include <fstream> +#include "image.hpp" + +#include "md5.h" + + +using namespace std; +namespace image { + + +void +Image::writeMD5(std::ostream &os) const { + struct MD5Context md5c; + MD5Init(&md5c); + const unsigned char *row; + unsigned len = width*bytesPerPixel; + for (row = start(); row != end(); row += stride()) { + MD5Update(&md5c, (unsigned char *)row, len); + } + unsigned char signature[16]; + MD5Final(signature, &md5c); + + const char hex[] = "0123456789ABCDEF"; + char csig[33]; + for(int i = 0; i < sizeof signature; i++){ + csig[2*i ] = hex[signature[i] >> 4]; + csig[2*i + 1] = hex[signature[i] & 0xf]; + } + csig[32] = '\0'; + + os << csig; + os << "\n"; +} + + +} /* namespace image */ + diff --git a/lib/image/image_png.cpp b/lib/image/image_png.cpp new file mode 100644 index 00000000..72b9f9a8 --- /dev/null +++ b/lib/image/image_png.cpp @@ -0,0 +1,277 @@ +/************************************************************************** + * + * Copyright 2011 Jose Fonseca + * Copyright 2008-2010 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + + +#include <zlib.h> +#include <png.h> + +#include <assert.h> +#include <stdint.h> +#include <stdlib.h> +#include <math.h> + +#include <fstream> + +#include "image.hpp" + + +namespace image { + + +static const int png_compression_level = Z_BEST_SPEED; + + +static void +pngWriteCallback(png_structp png_ptr, png_bytep data, png_size_t length) +{ + std::ostream *os = (std::ostream *) png_get_io_ptr(png_ptr); + os->write((const char *)data, length); +} + + +static inline uint8_t +floatToUnorm8(float c) +{ + if (c <= 0.0f) { + return 0; + } + if (c >= 1.0f) { + return 255; + } + return c * 255.0f + 0.5f; +} + + +static inline uint8_t +floatToSRGB(float c) +{ + if (c <= 0.0f) { + return 0; + } + if (c >= 1.0f) { + return 255; + } + if (c <= 0.0031308f) { + c *= 12.92f; + } else { + c = 1.055f * powf(c, 1.0f/2.4f) - 0.055f; + } + return c * 255.0f + 0.5f; +} + + +bool +Image::writePNG(std::ostream &os, bool strip_alpha) const +{ + png_structp png_ptr; + png_infop info_ptr; + int color_type; + + switch (channels) { + case 4: + color_type = strip_alpha ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA; + break; + case 3: + color_type = PNG_COLOR_TYPE_RGB; + break; + case 2: + color_type = PNG_COLOR_TYPE_GRAY_ALPHA; + break; + case 1: + color_type = PNG_COLOR_TYPE_GRAY; + break; + default: + assert(0); + goto no_png; + } + + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) + goto no_png; + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + png_destroy_write_struct(&png_ptr, NULL); + goto no_png; + } + + if (setjmp(png_jmpbuf(png_ptr))) { + png_destroy_write_struct(&png_ptr, &info_ptr); + goto no_png; + } + + png_set_write_fn(png_ptr, &os, pngWriteCallback, NULL); + + png_set_IHDR(png_ptr, info_ptr, width, height, 8, + color_type, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + png_set_compression_level(png_ptr, png_compression_level); + + png_write_info(png_ptr, info_ptr); + + if (channels == 4 && strip_alpha) { + png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); + } + + switch (channelType) { + case TYPE_UNORM8: + for (const unsigned char *row = start(); row != end(); row += stride()) { + png_write_rows(png_ptr, (png_bytepp) &row, 1); + } + break; + case TYPE_FLOAT: + png_bytep rowUnorm8 = new png_byte[width * channels]; + for (const unsigned char *row = start(); row != end(); row += stride()) { + const float *rowFloat = (const float *)row; + for (unsigned x = 0, i = 0; x < width; ++x) { + for (unsigned channel = 0; channel < channels; ++channel, ++i) { + float c = rowFloat[i]; + bool srgb = channels >= 3 && channel < 3; + rowUnorm8[i] = srgb ? floatToSRGB(c) : floatToUnorm8(c); + } + } + png_write_rows(png_ptr, (png_bytepp) &rowUnorm8, 1); + } + delete [] rowUnorm8; + break; + } + + png_write_end(png_ptr, info_ptr); + png_destroy_write_struct(&png_ptr, &info_ptr); + + return true; + +no_png: + return false; +} + + +bool +Image::writePNG(const char *filename, bool strip_alpha) const +{ + std::ofstream os(filename, std::ofstream::binary); + if (!os) { + return false; + } + return writePNG(os, strip_alpha); +} + + +static void +pngReadCallback(png_structp png_ptr, png_bytep data, png_size_t length) +{ + std::istream *os = (std::istream *) png_get_io_ptr(png_ptr); + os->read((char *)data, length); +} + + +Image * +readPNG(std::istream &is) +{ + png_structp png_ptr; + png_infop info_ptr; + png_infop end_info; + unsigned channels; + Image *image; + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) + goto no_png; + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + png_destroy_read_struct(&png_ptr, NULL, NULL); + goto no_png; + } + + end_info = png_create_info_struct(png_ptr); + if (!end_info) { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + goto no_png; + } + + if (setjmp(png_jmpbuf(png_ptr))) { + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + goto no_png; + } + + png_set_read_fn(png_ptr, &is, pngReadCallback); + + png_read_info(png_ptr, info_ptr); + + png_uint_32 width, height; + int bit_depth, color_type, interlace_type, compression_type, filter_method; + + png_get_IHDR(png_ptr, info_ptr, + &width, &height, + &bit_depth, &color_type, &interlace_type, + &compression_type, &filter_method); + + /* Convert to RGBA8 */ + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_palette_to_rgb(png_ptr); + if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) + png_set_expand_gray_1_2_4_to_8(png_ptr); + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) + png_set_tRNS_to_alpha(png_ptr); + if (bit_depth == 16) + png_set_strip_16(png_ptr); + + channels = png_get_channels(png_ptr, info_ptr); + image = new Image(width, height, channels); + if (!image) + goto no_image; + + assert(png_get_rowbytes(png_ptr, info_ptr) == width*channels); + for (unsigned y = 0; y < height; ++y) { + png_bytep row = (png_bytep)(image->pixels + y*width*channels); + png_read_row(png_ptr, row, NULL); + } + + png_read_end(png_ptr, info_ptr); + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + + return image; + +no_image: + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); +no_png: + return NULL; +} + +Image * +readPNG(const char *filename) +{ + std::ifstream is(filename, std::ifstream::binary); + if (!is) { + return NULL; + } + return readPNG(filename); +} + + +} /* namespace image */ diff --git a/lib/image/image_pnm.cpp b/lib/image/image_pnm.cpp new file mode 100644 index 00000000..14c1e558 --- /dev/null +++ b/lib/image/image_pnm.cpp @@ -0,0 +1,319 @@ +/************************************************************************** + * + * Copyright 2011 Jose Fonseca + * Copyright 2008-2010 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + + +#include <assert.h> +#include <string.h> +#include <stdint.h> +#include <stdio.h> +#include <algorithm> + +#include <fstream> + +#include "image.hpp" + + +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 if (channels <= 3) { + identifier = "PF"; + outChannels = 3; + } else { + // Non-standard extension for 4 floats + identifier = "PX"; + outChannels = 4; + } + break; + default: + assert(0); + return; + } + + os << identifier << "\n"; + + if (comment) { + os << "#" << comment << "\n"; + } + os << width << " " << height << "\n"; + + if (channelType == TYPE_UNORM8) { + os << "255" << "\n"; + } else { + os << "1" << "\n"; + } + + const unsigned char *row; + + 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*bytesPerPixel); + } + } else { + /* + * Need to add/remove channels, one pixel at a time. + */ + + unsigned char *tmp = new unsigned char[width*outChannels*bytesPerChannel]; + + 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); + } + } 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); + } + } else { + assert(0); + } + } else { + /* + * General path for float images. + */ + + unsigned copyChannels = std::min(channels, outChannels); + + assert(channelType == TYPE_FLOAT); + + for (row = start(); row != end(); row += stride()) { + const float *src = (const float *)row; + float *dst = (float *)tmp; + for (unsigned x = 0; x < width; ++x) { + unsigned channel = 0; + for (; channel < copyChannels; ++channel) { + *dst++ = *src++; + } + for (; channel < outChannels; ++channel) { + *dst++ = 0; + } + } + os.write((const char *)tmp, width*outChannels*bytesPerChannel); + } + } + + delete [] tmp; + } +} + + +bool +Image::writePNM(const char *filename, const char *comment) const +{ + std::ofstream os(filename, std::ofstream::binary); + if (!os) { + return false; + } + writePNM(os, comment); + return true; +} + + +/** + * Parse PNM header. + * + * Returns pointer to data start, or NULL on failure. + */ +const char * +readPNMHeader(const char *buffer, size_t bufferSize, PNMInfo &info) +{ + info.channels = 0; + info.width = 0; + info.height = 0; + info.commentNumber = -1; + + const char *currentBuffer = buffer; + const char *nextBuffer; + + // parse number of channels + char c; + int scannedChannels = sscanf(currentBuffer, "P%c\n", &c); + if (scannedChannels != 1) { // validate scanning of channels + // invalid channel line + return NULL; + } + // convert channel token to number of channels + 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; + case 'X': + info.channels = 4; + info.channelType = TYPE_FLOAT; + break; + default: + return NULL; + } + + // advance past channel line + nextBuffer = (const char *) memchr((const void *) currentBuffer, '\n', bufferSize) + 1; + bufferSize -= nextBuffer - currentBuffer; + currentBuffer = nextBuffer; + + // skip over optional comment + if (*currentBuffer == '#') { + // advance past '#' + currentBuffer += 1; + bufferSize += 1; + + // actually try to read a number + sscanf(currentBuffer, "%d", &info.commentNumber); + + // advance past comment line + nextBuffer = (const char *) memchr((const void *) currentBuffer, '\n', bufferSize) + 1; + bufferSize -= nextBuffer - currentBuffer; + currentBuffer = nextBuffer; + } + + // parse dimensions of image + int scannedDimensions = sscanf(currentBuffer, "%u %u\n", &info.width, &info.height); + if (scannedDimensions != 2) { // validate scanning of dimensions + // invalid dimension line + return NULL; + } + + // advance past dimension line + nextBuffer = (const char *) memchr((const void *) currentBuffer, '\n', bufferSize) + 1; + bufferSize -= nextBuffer - currentBuffer; + currentBuffer = nextBuffer; + + // skip scale factor / endianness line + 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 */ diff --git a/lib/image/image_raw.cpp b/lib/image/image_raw.cpp new file mode 100644 index 00000000..4d8d363f --- /dev/null +++ b/lib/image/image_raw.cpp @@ -0,0 +1,66 @@ +/************************************************************************** + * + * Copyright (C) 2013 Intel Corporation. All rights reversed. + * Author: Shuang He <shuang.he@intel.com> + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + + +#include <assert.h> +#include <string.h> +#include <stdint.h> +#include <stdio.h> + +#include <fstream> + +#include "image.hpp" + + +namespace image { + + +void +Image::writeRAW(std::ostream &os) const +{ + assert(channelType == TYPE_UNORM8); + + const unsigned char *row; + + for (row = start(); row != end(); row += stride()) { + os.write((const char *)row, width*bytesPerPixel); + } +} + + +bool +Image::writeRAW(const char *filename) const +{ + std::ofstream os(filename, std::ofstream::binary); + if (!os) { + return false; + } + writeRAW(os); + return true; +} + + +} /* namespace image */ |