// // Copyright 2020 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // png_utils: Wrapper around libpng. // #include "util/png_utils.h" #include #include #include namespace angle { namespace { class ScopedFILE { public: ScopedFILE(FILE *fp) : mFP(fp) {} ~ScopedFILE() { close(); } FILE *get() const { return mFP; } void close() { if (mFP) { fclose(mFP); mFP = nullptr; } } private: FILE *mFP; }; } // namespace bool SavePNGRGB(const char *fileName, const char *title, uint32_t width, uint32_t height, const std::vector &data) { ScopedFILE fp(fopen(fileName, "wb")); if (!fp.get()) { fprintf(stderr, "Error opening '%s'.\n", fileName); return false; } png_struct *writeStruct = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); if (!writeStruct) { fprintf(stderr, "Error on png_create_write_struct.\n"); return false; } png_info *infoStruct = png_create_info_struct(writeStruct); if (!infoStruct) { fprintf(stderr, "Error on png_create_info_struct.\n"); return false; } if (setjmp(png_jmpbuf(writeStruct))) { fp.close(); png_free_data(writeStruct, infoStruct, PNG_FREE_ALL, -1); png_destroy_write_struct(&writeStruct, &infoStruct); return false; } png_init_io(writeStruct, fp.get()); // Write header (8 bit colour depth) png_set_IHDR(writeStruct, infoStruct, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); // Set title if (title != nullptr && strlen(title) > 0) { std::array mutableKey = {}; strcpy(mutableKey.data(), "Title"); std::array mutableText = {}; strncpy(mutableText.data(), title, 199); png_text titleText; titleText.compression = PNG_TEXT_COMPRESSION_NONE; titleText.key = mutableKey.data(); titleText.text = mutableText.data(); png_set_text(writeStruct, infoStruct, &titleText, 1); } png_write_info(writeStruct, infoStruct); // RGB 3-byte stride. const uint32_t rowStride = width * 3; for (uint32_t row = 0; row < height; ++row) { uint32_t rowOffset = row * rowStride; png_write_row(writeStruct, &data[rowOffset]); } png_write_end(writeStruct, infoStruct); fp.close(); png_free_data(writeStruct, infoStruct, PNG_FREE_ALL, -1); png_destroy_write_struct(&writeStruct, &infoStruct); return true; } } // namespace angle