112230Sgiacomo.travaglini@arm.com/*
212230Sgiacomo.travaglini@arm.com * Copyright (c) 2017 ARM Limited
312230Sgiacomo.travaglini@arm.com * All rights reserved
412230Sgiacomo.travaglini@arm.com *
512230Sgiacomo.travaglini@arm.com * The license below extends only to copyright in the software and shall
612230Sgiacomo.travaglini@arm.com * not be construed as granting a license to any other intellectual
712230Sgiacomo.travaglini@arm.com * property including but not limited to intellectual property relating
812230Sgiacomo.travaglini@arm.com * to a hardware implementation of the functionality of the software
912230Sgiacomo.travaglini@arm.com * licensed hereunder.  You may use the software subject to the license
1012230Sgiacomo.travaglini@arm.com * terms below provided that you ensure that this notice is replicated
1112230Sgiacomo.travaglini@arm.com * unmodified and in its entirety in all distributions of the software,
1212230Sgiacomo.travaglini@arm.com * modified or unmodified, in source code or in binary form.
1312230Sgiacomo.travaglini@arm.com *
1412230Sgiacomo.travaglini@arm.com * Redistribution and use in source and binary forms, with or without
1512230Sgiacomo.travaglini@arm.com * modification, are permitted provided that the following conditions are
1612230Sgiacomo.travaglini@arm.com * met: redistributions of source code must retain the above copyright
1712230Sgiacomo.travaglini@arm.com * notice, this list of conditions and the following disclaimer;
1812230Sgiacomo.travaglini@arm.com * redistributions in binary form must reproduce the above copyright
1912230Sgiacomo.travaglini@arm.com * notice, this list of conditions and the following disclaimer in the
2012230Sgiacomo.travaglini@arm.com * documentation and/or other materials provided with the distribution;
2112230Sgiacomo.travaglini@arm.com * neither the name of the copyright holders nor the names of its
2212230Sgiacomo.travaglini@arm.com * contributors may be used to endorse or promote products derived from
2312230Sgiacomo.travaglini@arm.com * this software without specific prior written permission.
2412230Sgiacomo.travaglini@arm.com *
2512230Sgiacomo.travaglini@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2612230Sgiacomo.travaglini@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2712230Sgiacomo.travaglini@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2812230Sgiacomo.travaglini@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2912230Sgiacomo.travaglini@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3012230Sgiacomo.travaglini@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3112230Sgiacomo.travaglini@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3212230Sgiacomo.travaglini@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3312230Sgiacomo.travaglini@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3412230Sgiacomo.travaglini@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3512230Sgiacomo.travaglini@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3612230Sgiacomo.travaglini@arm.com *
3712230Sgiacomo.travaglini@arm.com * Authors: Giacomo Travaglini
3812230Sgiacomo.travaglini@arm.com */
3912230Sgiacomo.travaglini@arm.com
4012230Sgiacomo.travaglini@arm.com/**
4112230Sgiacomo.travaglini@arm.com * @file Definition of a class that writes a frame buffer to a png
4212230Sgiacomo.travaglini@arm.com */
4312230Sgiacomo.travaglini@arm.com
4412230Sgiacomo.travaglini@arm.com#include "base/pngwriter.hh"
4512230Sgiacomo.travaglini@arm.com
4612230Sgiacomo.travaglini@arm.comextern "C"
4712230Sgiacomo.travaglini@arm.com{
4812230Sgiacomo.travaglini@arm.com#include <png.h>
4912230Sgiacomo.travaglini@arm.com}
5012230Sgiacomo.travaglini@arm.com
5112230Sgiacomo.travaglini@arm.com#include <cstdio>
5212230Sgiacomo.travaglini@arm.com#include <cstdlib>
5312230Sgiacomo.travaglini@arm.com
5412334Sgabeblack@google.com#include "base/logging.hh"
5512230Sgiacomo.travaglini@arm.com
5612230Sgiacomo.travaglini@arm.comconst char* PngWriter::_imgExtension = "png";
5712230Sgiacomo.travaglini@arm.com
5812230Sgiacomo.travaglini@arm.com/**
5912230Sgiacomo.travaglini@arm.com * Write callback to use with libpng APIs
6012230Sgiacomo.travaglini@arm.com *
6112230Sgiacomo.travaglini@arm.com * @param pngPtr  pointer to the png_struct structure
6212230Sgiacomo.travaglini@arm.com * @param data    pointer to the data being written
6312230Sgiacomo.travaglini@arm.com * @param length  number of bytes being written
6412230Sgiacomo.travaglini@arm.com */
6512230Sgiacomo.travaglini@arm.comstatic void
6612230Sgiacomo.travaglini@arm.comwritePng(png_structp pngPtr, png_bytep data, png_size_t length)
6712230Sgiacomo.travaglini@arm.com{
6812230Sgiacomo.travaglini@arm.com    // Here we get our IO pointer back from the write struct
6912230Sgiacomo.travaglini@arm.com    // and we cast it into a ostream* type.
7012230Sgiacomo.travaglini@arm.com    std::ostream* strmPtr = reinterpret_cast<std::ostream*>(
7112230Sgiacomo.travaglini@arm.com        png_get_io_ptr(pngPtr)
7212230Sgiacomo.travaglini@arm.com    );
7312230Sgiacomo.travaglini@arm.com
7412230Sgiacomo.travaglini@arm.com    // Write length bytes to data
7512230Sgiacomo.travaglini@arm.com    strmPtr->write(reinterpret_cast<const char *>(data), length);
7612230Sgiacomo.travaglini@arm.com}
7712230Sgiacomo.travaglini@arm.com
7812230Sgiacomo.travaglini@arm.comstruct PngWriter::PngStructHandle {
7912230Sgiacomo.travaglini@arm.com  private:
8012230Sgiacomo.travaglini@arm.com    // Make PngStructHandle uncopyable
8112230Sgiacomo.travaglini@arm.com    PngStructHandle(const PngStructHandle&) = delete;
8212230Sgiacomo.travaglini@arm.com    PngStructHandle& operator=(const PngStructHandle&) = delete;
8312230Sgiacomo.travaglini@arm.com  public:
8412230Sgiacomo.travaglini@arm.com
8512230Sgiacomo.travaglini@arm.com    PngStructHandle() :
8612230Sgiacomo.travaglini@arm.com        pngWriteP(NULL), pngInfoP(NULL)
8712230Sgiacomo.travaglini@arm.com    {
8812230Sgiacomo.travaglini@arm.com        // Creating write structure
8912230Sgiacomo.travaglini@arm.com        pngWriteP = png_create_write_struct(
9012230Sgiacomo.travaglini@arm.com            PNG_LIBPNG_VER_STRING, NULL, NULL, NULL
9112230Sgiacomo.travaglini@arm.com        );
9212230Sgiacomo.travaglini@arm.com
9312230Sgiacomo.travaglini@arm.com        if (pngWriteP) {
9412230Sgiacomo.travaglini@arm.com            // Creating info structure
9512230Sgiacomo.travaglini@arm.com            pngInfoP = png_create_info_struct(pngWriteP);
9612230Sgiacomo.travaglini@arm.com        }
9712230Sgiacomo.travaglini@arm.com    }
9812230Sgiacomo.travaglini@arm.com
9912230Sgiacomo.travaglini@arm.com    ~PngStructHandle()
10012230Sgiacomo.travaglini@arm.com    {
10112230Sgiacomo.travaglini@arm.com        if (pngWriteP) {
10212230Sgiacomo.travaglini@arm.com            png_destroy_write_struct(&pngWriteP, &pngInfoP);
10312230Sgiacomo.travaglini@arm.com        }
10412230Sgiacomo.travaglini@arm.com    }
10512230Sgiacomo.travaglini@arm.com
10612230Sgiacomo.travaglini@arm.com    /** Pointer to PNG Write struct */
10712230Sgiacomo.travaglini@arm.com    png_structp pngWriteP;
10812230Sgiacomo.travaglini@arm.com
10912230Sgiacomo.travaglini@arm.com    /** Pointer to PNG Info struct */
11012230Sgiacomo.travaglini@arm.com    png_infop pngInfoP;
11112230Sgiacomo.travaglini@arm.com};
11212230Sgiacomo.travaglini@arm.com
11312230Sgiacomo.travaglini@arm.comvoid
11412230Sgiacomo.travaglini@arm.comPngWriter::write(std::ostream &png) const
11512230Sgiacomo.travaglini@arm.com{
11612230Sgiacomo.travaglini@arm.com
11712230Sgiacomo.travaglini@arm.com    // Height of the frame buffer
11812230Sgiacomo.travaglini@arm.com    unsigned height = fb.height();
11912230Sgiacomo.travaglini@arm.com    unsigned width  = fb.width();
12012230Sgiacomo.travaglini@arm.com
12112230Sgiacomo.travaglini@arm.com    // Do not write if frame buffer is empty
12212230Sgiacomo.travaglini@arm.com    if (!fb.area()) {
12312230Sgiacomo.travaglini@arm.com        png.flush();
12412230Sgiacomo.travaglini@arm.com        return;
12512230Sgiacomo.travaglini@arm.com    }
12612230Sgiacomo.travaglini@arm.com
12712230Sgiacomo.travaglini@arm.com    // Initialize Png structures
12812230Sgiacomo.travaglini@arm.com    PngStructHandle handle;
12912230Sgiacomo.travaglini@arm.com
13012230Sgiacomo.travaglini@arm.com    // Png info/write pointers.
13112230Sgiacomo.travaglini@arm.com    png_structp pngPtr  = handle.pngWriteP;
13212230Sgiacomo.travaglini@arm.com    png_infop   infoPtr = handle.pngInfoP;
13312230Sgiacomo.travaglini@arm.com
13412230Sgiacomo.travaglini@arm.com    if (!pngPtr) {
13512230Sgiacomo.travaglini@arm.com        warn("Frame buffer dump aborted: Unable to create"
13612230Sgiacomo.travaglini@arm.com             "Png Write Struct\n");
13712230Sgiacomo.travaglini@arm.com        return;
13812230Sgiacomo.travaglini@arm.com    }
13912230Sgiacomo.travaglini@arm.com
14012230Sgiacomo.travaglini@arm.com    if (!infoPtr) {
14112230Sgiacomo.travaglini@arm.com        warn("Frame buffer dump aborted: Unable to create"
14212230Sgiacomo.travaglini@arm.com             "Png Info Struct\n");
14312230Sgiacomo.travaglini@arm.com        return;
14412230Sgiacomo.travaglini@arm.com    }
14512230Sgiacomo.travaglini@arm.com
14612230Sgiacomo.travaglini@arm.com    // We cannot use default libpng write function since it requires
14712230Sgiacomo.travaglini@arm.com    // a file pointer (FILE*), whereas we want to use the ostream.
14812230Sgiacomo.travaglini@arm.com    // The following function replaces the write function with a custom
14912230Sgiacomo.travaglini@arm.com    // one provided by us (writePng)
15012230Sgiacomo.travaglini@arm.com    png_set_write_fn(pngPtr, (png_voidp)&png, writePng, NULL);
15112230Sgiacomo.travaglini@arm.com
15212230Sgiacomo.travaglini@arm.com    png_set_IHDR(pngPtr, infoPtr, width, height, 8,
15312230Sgiacomo.travaglini@arm.com                 PNG_COLOR_TYPE_RGB,
15412230Sgiacomo.travaglini@arm.com                 PNG_INTERLACE_NONE,
15512230Sgiacomo.travaglini@arm.com                 PNG_COMPRESSION_TYPE_DEFAULT,
15612230Sgiacomo.travaglini@arm.com                 PNG_FILTER_TYPE_DEFAULT);
15712230Sgiacomo.travaglini@arm.com
15812230Sgiacomo.travaglini@arm.com    png_write_info(pngPtr, infoPtr);
15912230Sgiacomo.travaglini@arm.com
16012230Sgiacomo.travaglini@arm.com    // libpng requires an array of pointers to the frame buffer's rows.
16112230Sgiacomo.travaglini@arm.com    std::vector<PixelType> rowPacked(width);
16212230Sgiacomo.travaglini@arm.com    for (unsigned y=0; y < height; ++y) {
16312582Schunchenhsu@google.com        for (unsigned x=0; x < width; ++x) {
16412230Sgiacomo.travaglini@arm.com            rowPacked[x] = fb.pixel(x, y);
16512230Sgiacomo.travaglini@arm.com        }
16612230Sgiacomo.travaglini@arm.com
16712230Sgiacomo.travaglini@arm.com        png_write_row(pngPtr,
16812230Sgiacomo.travaglini@arm.com            reinterpret_cast<png_bytep>(rowPacked.data())
16912230Sgiacomo.travaglini@arm.com        );
17012230Sgiacomo.travaglini@arm.com    }
17112230Sgiacomo.travaglini@arm.com
17212230Sgiacomo.travaglini@arm.com    // End of write
17312230Sgiacomo.travaglini@arm.com    png_write_end(pngPtr, NULL);
17412230Sgiacomo.travaglini@arm.com}
17512230Sgiacomo.travaglini@arm.com
176