]> git.cworth.org Git - apitrace/commitdiff
image: Move image code into its own module.
authorJosé Fonseca <jose.r.fonseca@gmail.com>
Fri, 7 Dec 2012 07:33:05 +0000 (07:33 +0000)
committerJosé Fonseca <jose.r.fonseca@gmail.com>
Fri, 7 Dec 2012 07:33:05 +0000 (07:33 +0000)
15 files changed:
CMakeLists.txt
cli/CMakeLists.txt
common/image.cpp [deleted file]
common/image.hpp [deleted file]
common/image_bmp.cpp [deleted file]
common/image_png.cpp [deleted file]
common/image_pnm.cpp [deleted file]
gui/CMakeLists.txt
gui/retracer.cpp
image/image.cpp [new file with mode: 0644]
image/image.hpp [new file with mode: 0644]
image/image_bmp.cpp [new file with mode: 0644]
image/image_png.cpp [new file with mode: 0644]
image/image_pnm.cpp [new file with mode: 0644]
retrace/CMakeLists.txt

index 1c4094f6357730dd85351a000b8b3807fa1aa912..e31cb54fe51a1a7b522f252dd6a81b801098172f 100644 (file)
@@ -206,8 +206,6 @@ set (PNG_DEFINITIONS "")
 set (PNG_LIBRARIES png_bundled)
 
 add_subdirectory (thirdparty/libpng EXCLUDE_FROM_ALL)
-include_directories (${PNG_INCLUDE_DIR})
-add_definitions (${PNG_DEFINITIONS})
 
 if (MSVC)
     add_subdirectory (thirdparty/getopt EXCLUDE_FROM_ALL)
@@ -321,10 +319,6 @@ add_library (common STATIC
     common/trace_writer_model.cpp
     common/trace_loader.cpp
     common/trace_profiler.cpp
-    common/image.cpp
-    common/image_bmp.cpp
-    common/image_pnm.cpp
-    common/image_png.cpp
     common/trace_option.cpp
     common/${os}
 )
@@ -348,6 +342,7 @@ endif ()
 add_subdirectory (dispatch)
 add_subdirectory (helpers)
 add_subdirectory (wrappers)
+add_subdirectory (image)
 add_subdirectory (retrace)
 
 
index 521886b7fc827af2d638a03c3c06f9e0c0b19d28..a01d3aed11e72b0da42276c3552e8935b525787c 100644 (file)
@@ -16,7 +16,6 @@ add_executable (apitrace
 
 target_link_libraries (apitrace
     common
-    ${PNG_LIBRARIES}
     ${ZLIB_LIBRARIES}
     ${SNAPPY_LIBRARIES}
     ${GETOPT_LIBRARIES}
diff --git a/common/image.cpp b/common/image.cpp
deleted file mode 100644 (file)
index e692313..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/**************************************************************************
- *
- * 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 <math.h>
-
-#include <algorithm>
-
-#include "image.hpp"
-
-
-namespace image {
-
-
-double Image::compare(Image &ref)
-{
-    if (width != ref.width ||
-        height != ref.height ||
-        channels < 3 ||
-        ref.channels < 3) {
-        return 0.0;
-    }
-
-    // Ignore missing alpha when comparing RGB w/ RGBA, but enforce an equal
-    // number of channels otherwise.
-    unsigned minChannels = std::min(channels, ref.channels);
-    if (channels != ref.channels && minChannels < 3) {
-        return 0.0;
-    }
-
-    const unsigned char *pSrc = start();
-    const unsigned char *pRef = ref.start();
-
-    unsigned long long error = 0;
-    for (unsigned y = 0; y < height; ++y) {
-        for (unsigned  x = 0; x < width; ++x) {
-            // FIXME: Ignore alpha channel until we are able to pick a visual
-            // that matches the traces
-            for (unsigned  c = 0; c < minChannels; ++c) {
-                int delta = pSrc[x*channels + c] - pRef[x*ref.channels + c];
-                error += delta*delta;
-            }
-        }
-
-        pSrc += stride();
-        pRef += ref.stride();
-    }
-
-    double numerator = error*2 + 1;
-    double denominator = height*width*minChannels*255ULL*255ULL*2;
-    double quotient = numerator/denominator;
-
-    // Precision in bits
-    double precision = -log(quotient)/log(2.0);
-
-    return precision;
-}
-
-
-} /* namespace image */
diff --git a/common/image.hpp b/common/image.hpp
deleted file mode 100644 (file)
index 7dd18c1..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/**************************************************************************
- *
- * 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.
- */
-
-#ifndef _IMAGE_HPP_
-#define _IMAGE_HPP_
-
-
-#include <fstream>
-
-
-namespace image {
-
-
-class Image {
-public:
-    unsigned width;
-    unsigned height;
-    unsigned channels;
-
-    // Flipped vertically or not
-    bool flipped;
-
-    // Pixels in RGBA format
-    unsigned char *pixels;
-
-    inline Image(unsigned w, unsigned h, unsigned c = 4, bool f = false) : 
-        width(w),
-        height(h),
-        channels(c),
-        flipped(f),
-        pixels(new unsigned char[h*w*c])
-    {}
-
-    inline ~Image() {
-        delete [] pixels;
-    }
-
-    inline unsigned char *start(void) {
-        return flipped ? pixels + (height - 1)*width*channels : pixels;
-    }
-
-    inline const unsigned char *start(void) const {
-        return flipped ? pixels + (height - 1)*width*channels : pixels;
-    }
-
-    inline unsigned char *end(void) {
-        return flipped ? pixels - width*channels : pixels + height*width*channels;
-    }
-
-    inline const unsigned char *end(void) const {
-        return flipped ? pixels - width*channels : pixels + height*width*channels;
-    }
-
-    inline signed stride(void) const {
-        return flipped ? -(signed)(width*channels) : width*channels;
-    }
-
-    bool writeBMP(const char *filename) const;
-
-    void writePNM(std::ostream &os, const char *comment = NULL) const;
-
-    inline bool writePNM(const char *filename, const char *comment = NULL) const {
-        std::ofstream os(filename, std::ofstream::binary);
-        if (!os) {
-            return false;
-        }
-        writePNM(os, comment);
-        return true;
-    }
-
-    bool
-    writePNG(std::ostream &os) const;
-
-    inline bool
-    writePNG(const char *filename) const {
-        std::ofstream os(filename, std::ofstream::binary);
-        if (!os) {
-            return false;
-        }
-        return writePNG(os);
-    }
-
-    double compare(Image &ref);
-};
-
-
-Image *
-readPNG(const char *filename);
-
-const char *
-readPNMHeader(const char *buffer, size_t size, unsigned *channels, unsigned *width, unsigned *height);
-
-
-} /* namespace image */
-
-
-#endif /* _IMAGE_HPP_ */
diff --git a/common/image_bmp.cpp b/common/image_bmp.cpp
deleted file mode 100644 (file)
index e0c6428..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-/**************************************************************************
- *
- * 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 "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);
-
-    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/common/image_png.cpp b/common/image_png.cpp
deleted file mode 100644 (file)
index dba07d4..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-/**************************************************************************
- *
- * 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 <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);
-}
-
-bool
-Image::writePNG(std::ostream &os) const
-{
-    png_structp png_ptr;
-    png_infop info_ptr;
-    int color_type;
-
-    switch (channels) {
-    case 4:
-        color_type = 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 (!flipped) {
-        for (unsigned y = 0; y < height; ++y) {
-            png_bytep row = (png_bytep)(pixels + y*width*channels);
-            png_write_rows(png_ptr, &row, 1);
-        }
-    } else {
-        unsigned y = height;
-        while (y--) {
-            png_bytep row = (png_bytep)(pixels + y*width*channels);
-            png_write_rows(png_ptr, &row, 1);
-        }
-    }
-
-    png_write_end(png_ptr, info_ptr);
-    png_destroy_write_struct(&png_ptr, &info_ptr);
-
-    return true;
-
-no_png:
-    return false;
-}
-
-
-Image *
-readPNG(const char *filename)
-{
-    FILE *fp;
-    png_structp png_ptr;
-    png_infop info_ptr;
-    png_infop end_info;
-    Image *image;
-
-    fp = fopen(filename, "rb");
-    if (!fp)
-        goto no_fp;
-
-    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_init_io(png_ptr, fp);
-
-    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);
-
-    image = new Image(width, height);
-    if (!image)
-        goto no_image;
-
-    /* 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);
-
-    for (unsigned y = 0; y < height; ++y) {
-        png_bytep row = (png_bytep)(image->pixels + y*width*4);
-        png_read_row(png_ptr, row, NULL);
-    }
-
-    png_read_end(png_ptr, info_ptr);
-    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
-    fclose(fp);
-    return image;
-
-no_image:
-    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
-no_png:
-    fclose(fp);
-no_fp:
-    return NULL;
-}
-
-
-
-} /* namespace image */
diff --git a/common/image_pnm.cpp b/common/image_pnm.cpp
deleted file mode 100644 (file)
index f9cd05d..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-/**************************************************************************
- *
- * 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 "image.hpp"
-
-
-namespace image {
-
-/**
- * http://en.wikipedia.org/wiki/Netpbm_format
- * http://netpbm.sourceforge.net/doc/ppm.html
- */
-void
-Image::writePNM(std::ostream &os, const char *comment) const {
-    assert(channels == 1 || channels >= 3);
-
-    os << (channels == 1 ? "P5" : "P6") << "\n";
-    if (comment) {
-        os << "#" << comment << "\n";
-    }
-    os << width << " " << height << "\n";
-    os << "255" << "\n";
-
-    const unsigned char *row;
-
-    if (channels == 1 || channels == 3) {
-        for (row = start(); row != end(); row += stride()) {
-            os.write((const char *)row, width*channels);
-        }
-    } 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;
-                }
-                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);
-        }
-        delete [] tmp;
-    }
-}
-
-const char *
-readPNMHeader(const char *buffer, size_t bufferSize, unsigned *channels, unsigned *width, unsigned *height)
-{
-    *channels = 0;
-    *width = 0;
-    *height = 0;
-
-    const char *currentBuffer = buffer;
-    const char *nextBuffer;
-
-    // parse number of channels
-    int scannedChannels = sscanf(currentBuffer, "P%d\n", channels);
-    if (scannedChannels != 1) { // validate scanning of channels
-        // invalid channel line
-        return buffer;
-    }
-    // convert channel token to number of channels
-    *channels = (*channels == 5) ? 1 : 3;
-
-    // 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 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, "%d %d\n", width, height);
-    if (scannedDimensions != 2) { // validate scanning of dimensions
-        // invalid dimension line
-        return buffer;
-    }
-
-    // advance past dimension line
-    nextBuffer = (const char *) memchr((const void *) currentBuffer, '\n', bufferSize) + 1;
-    bufferSize -= nextBuffer - currentBuffer;
-    currentBuffer = nextBuffer;
-
-    // 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;
-}
-
-} /* namespace image */
index ee18d81be8148bb903fb1edc6c9dbf87a23628f0..773d344549462fba25f4d403121ba42942b52ecc 100644 (file)
@@ -58,7 +58,13 @@ QT4_WRAP_UI(qapitrace_UIS_H ${qapitrace_UIS})
 
 #add_app_icon(qapitrace_SRCS ../icons/hi*-qapitrace.png)
 link_directories(${LINK_DIRECTORIES} ${QJSON_LIBRARY_DIRS})
-include_directories(${QT_INCLUDES} ${QJSON_INCLUDE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/..)
+include_directories(
+    ${CMAKE_CURRENT_BINARY_DIR}
+    ${CMAKE_CURRENT_SOURCE_DIR}
+    ${CMAKE_SOURCE_DIR}
+    ${QJSON_INCLUDE_DIR}
+    ${QT_INCLUDES}
+)
 
 if (WIN32)
     # Use Windows subsystem (i.e., no console).
@@ -68,8 +74,8 @@ endif ()
 add_executable(qapitrace ${qapitrace_SUBSYSTEM} ${qapitrace_SRCS} ${qapitrace_UIS_H})
 
 target_link_libraries (qapitrace
+    image
     common
-    ${PNG_LIBRARIES}
     ${ZLIB_LIBRARIES}
     ${SNAPPY_LIBRARIES}
     ${QJSON_LIBRARIES}
index 213704b8e61ef0a4f6a200c8da5d48cb37818d83..c6698f75e709c8cb769514ceebe22d74de2f2642 100644 (file)
@@ -3,7 +3,7 @@
 #include "apitracecall.h"
 #include "thumbnail.h"
 
-#include "image.hpp"
+#include "image/image.hpp"
 
 #include "trace_profiler.hpp"
 
diff --git a/image/image.cpp b/image/image.cpp
new file mode 100644 (file)
index 0000000..e692313
--- /dev/null
@@ -0,0 +1,84 @@
+/**************************************************************************
+ *
+ * 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 <math.h>
+
+#include <algorithm>
+
+#include "image.hpp"
+
+
+namespace image {
+
+
+double Image::compare(Image &ref)
+{
+    if (width != ref.width ||
+        height != ref.height ||
+        channels < 3 ||
+        ref.channels < 3) {
+        return 0.0;
+    }
+
+    // Ignore missing alpha when comparing RGB w/ RGBA, but enforce an equal
+    // number of channels otherwise.
+    unsigned minChannels = std::min(channels, ref.channels);
+    if (channels != ref.channels && minChannels < 3) {
+        return 0.0;
+    }
+
+    const unsigned char *pSrc = start();
+    const unsigned char *pRef = ref.start();
+
+    unsigned long long error = 0;
+    for (unsigned y = 0; y < height; ++y) {
+        for (unsigned  x = 0; x < width; ++x) {
+            // FIXME: Ignore alpha channel until we are able to pick a visual
+            // that matches the traces
+            for (unsigned  c = 0; c < minChannels; ++c) {
+                int delta = pSrc[x*channels + c] - pRef[x*ref.channels + c];
+                error += delta*delta;
+            }
+        }
+
+        pSrc += stride();
+        pRef += ref.stride();
+    }
+
+    double numerator = error*2 + 1;
+    double denominator = height*width*minChannels*255ULL*255ULL*2;
+    double quotient = numerator/denominator;
+
+    // Precision in bits
+    double precision = -log(quotient)/log(2.0);
+
+    return precision;
+}
+
+
+} /* namespace image */
diff --git a/image/image.hpp b/image/image.hpp
new file mode 100644 (file)
index 0000000..7dd18c1
--- /dev/null
@@ -0,0 +1,123 @@
+/**************************************************************************
+ *
+ * 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.
+ */
+
+#ifndef _IMAGE_HPP_
+#define _IMAGE_HPP_
+
+
+#include <fstream>
+
+
+namespace image {
+
+
+class Image {
+public:
+    unsigned width;
+    unsigned height;
+    unsigned channels;
+
+    // Flipped vertically or not
+    bool flipped;
+
+    // Pixels in RGBA format
+    unsigned char *pixels;
+
+    inline Image(unsigned w, unsigned h, unsigned c = 4, bool f = false) : 
+        width(w),
+        height(h),
+        channels(c),
+        flipped(f),
+        pixels(new unsigned char[h*w*c])
+    {}
+
+    inline ~Image() {
+        delete [] pixels;
+    }
+
+    inline unsigned char *start(void) {
+        return flipped ? pixels + (height - 1)*width*channels : pixels;
+    }
+
+    inline const unsigned char *start(void) const {
+        return flipped ? pixels + (height - 1)*width*channels : pixels;
+    }
+
+    inline unsigned char *end(void) {
+        return flipped ? pixels - width*channels : pixels + height*width*channels;
+    }
+
+    inline const unsigned char *end(void) const {
+        return flipped ? pixels - width*channels : pixels + height*width*channels;
+    }
+
+    inline signed stride(void) const {
+        return flipped ? -(signed)(width*channels) : width*channels;
+    }
+
+    bool writeBMP(const char *filename) const;
+
+    void writePNM(std::ostream &os, const char *comment = NULL) const;
+
+    inline bool writePNM(const char *filename, const char *comment = NULL) const {
+        std::ofstream os(filename, std::ofstream::binary);
+        if (!os) {
+            return false;
+        }
+        writePNM(os, comment);
+        return true;
+    }
+
+    bool
+    writePNG(std::ostream &os) const;
+
+    inline bool
+    writePNG(const char *filename) const {
+        std::ofstream os(filename, std::ofstream::binary);
+        if (!os) {
+            return false;
+        }
+        return writePNG(os);
+    }
+
+    double compare(Image &ref);
+};
+
+
+Image *
+readPNG(const char *filename);
+
+const char *
+readPNMHeader(const char *buffer, size_t size, unsigned *channels, unsigned *width, unsigned *height);
+
+
+} /* namespace image */
+
+
+#endif /* _IMAGE_HPP_ */
diff --git a/image/image_bmp.cpp b/image/image_bmp.cpp
new file mode 100644 (file)
index 0000000..e0c6428
--- /dev/null
@@ -0,0 +1,139 @@
+/**************************************************************************
+ *
+ * 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 "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);
+
+    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/image/image_png.cpp b/image/image_png.cpp
new file mode 100644 (file)
index 0000000..dba07d4
--- /dev/null
@@ -0,0 +1,206 @@
+/**************************************************************************
+ *
+ * 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 <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);
+}
+
+bool
+Image::writePNG(std::ostream &os) const
+{
+    png_structp png_ptr;
+    png_infop info_ptr;
+    int color_type;
+
+    switch (channels) {
+    case 4:
+        color_type = 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 (!flipped) {
+        for (unsigned y = 0; y < height; ++y) {
+            png_bytep row = (png_bytep)(pixels + y*width*channels);
+            png_write_rows(png_ptr, &row, 1);
+        }
+    } else {
+        unsigned y = height;
+        while (y--) {
+            png_bytep row = (png_bytep)(pixels + y*width*channels);
+            png_write_rows(png_ptr, &row, 1);
+        }
+    }
+
+    png_write_end(png_ptr, info_ptr);
+    png_destroy_write_struct(&png_ptr, &info_ptr);
+
+    return true;
+
+no_png:
+    return false;
+}
+
+
+Image *
+readPNG(const char *filename)
+{
+    FILE *fp;
+    png_structp png_ptr;
+    png_infop info_ptr;
+    png_infop end_info;
+    Image *image;
+
+    fp = fopen(filename, "rb");
+    if (!fp)
+        goto no_fp;
+
+    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_init_io(png_ptr, fp);
+
+    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);
+
+    image = new Image(width, height);
+    if (!image)
+        goto no_image;
+
+    /* 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);
+
+    for (unsigned y = 0; y < height; ++y) {
+        png_bytep row = (png_bytep)(image->pixels + y*width*4);
+        png_read_row(png_ptr, row, NULL);
+    }
+
+    png_read_end(png_ptr, info_ptr);
+    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+    fclose(fp);
+    return image;
+
+no_image:
+    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+no_png:
+    fclose(fp);
+no_fp:
+    return NULL;
+}
+
+
+
+} /* namespace image */
diff --git a/image/image_pnm.cpp b/image/image_pnm.cpp
new file mode 100644 (file)
index 0000000..f9cd05d
--- /dev/null
@@ -0,0 +1,163 @@
+/**************************************************************************
+ *
+ * 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 "image.hpp"
+
+
+namespace image {
+
+/**
+ * http://en.wikipedia.org/wiki/Netpbm_format
+ * http://netpbm.sourceforge.net/doc/ppm.html
+ */
+void
+Image::writePNM(std::ostream &os, const char *comment) const {
+    assert(channels == 1 || channels >= 3);
+
+    os << (channels == 1 ? "P5" : "P6") << "\n";
+    if (comment) {
+        os << "#" << comment << "\n";
+    }
+    os << width << " " << height << "\n";
+    os << "255" << "\n";
+
+    const unsigned char *row;
+
+    if (channels == 1 || channels == 3) {
+        for (row = start(); row != end(); row += stride()) {
+            os.write((const char *)row, width*channels);
+        }
+    } 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;
+                }
+                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);
+        }
+        delete [] tmp;
+    }
+}
+
+const char *
+readPNMHeader(const char *buffer, size_t bufferSize, unsigned *channels, unsigned *width, unsigned *height)
+{
+    *channels = 0;
+    *width = 0;
+    *height = 0;
+
+    const char *currentBuffer = buffer;
+    const char *nextBuffer;
+
+    // parse number of channels
+    int scannedChannels = sscanf(currentBuffer, "P%d\n", channels);
+    if (scannedChannels != 1) { // validate scanning of channels
+        // invalid channel line
+        return buffer;
+    }
+    // convert channel token to number of channels
+    *channels = (*channels == 5) ? 1 : 3;
+
+    // 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 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, "%d %d\n", width, height);
+    if (scannedDimensions != 2) { // validate scanning of dimensions
+        // invalid dimension line
+        return buffer;
+    }
+
+    // advance past dimension line
+    nextBuffer = (const char *) memchr((const void *) currentBuffer, '\n', bufferSize) + 1;
+    bufferSize -= nextBuffer - currentBuffer;
+    currentBuffer = nextBuffer;
+
+    // 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;
+}
+
+} /* namespace image */
index 5a2a6088d5da9decd77c81af7182b1c3031c81ed..c6a364f30f42f66a6fdb92f7eda432dff52fef65 100644 (file)
@@ -6,6 +6,7 @@ include_directories (
     ${CMAKE_SOURCE_DIR}/helpers
     ${CMAKE_BINARY_DIR}/dispatch
     ${CMAKE_SOURCE_DIR}/dispatch
+    ${CMAKE_SOURCE_DIR}/image
 )
 
 add_definitions (-DRETRACE)
@@ -39,8 +40,8 @@ add_library (retrace_common STATIC
     json.cpp
 )
 target_link_libraries (retrace_common
+    image
     common
-    ${PNG_LIBRARIES}
     ${ZLIB_LIBRARIES}
     ${SNAPPY_LIBRARIES}
     ${GETOPT_LIBRARIES}