| // | |
| // 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 <array> | |
| #include <cstring> | |
| #include <png.h> | |
| 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<uint8_t> &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<char, 50> mutableKey = {}; | |
| strcpy(mutableKey.data(), "Title"); | |
| std::array<char, 200> 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 |