1 //
2 // Copyright 2020 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // png_utils: Wrapper around libpng.
7 //
8 
9 #include "util/png_utils.h"
10 
11 #include <array>
12 #include <cstring>
13 
14 #include <png.h>
15 
16 namespace angle
17 {
18 namespace
19 {
20 class ScopedFILE
21 {
22   public:
ScopedFILE(FILE * fp)23     ScopedFILE(FILE *fp) : mFP(fp) {}
~ScopedFILE()24     ~ScopedFILE() { close(); }
25 
get() const26     FILE *get() const { return mFP; }
27 
close()28     void close()
29     {
30         if (mFP)
31         {
32             fclose(mFP);
33             mFP = nullptr;
34         }
35     }
36 
37   private:
38     FILE *mFP;
39 };
40 }  // namespace
41 
SavePNGRGB(const char * fileName,const char * title,uint32_t width,uint32_t height,const std::vector<uint8_t> & data)42 bool SavePNGRGB(const char *fileName,
43                 const char *title,
44                 uint32_t width,
45                 uint32_t height,
46                 const std::vector<uint8_t> &data)
47 {
48     ScopedFILE fp(fopen(fileName, "wb"));
49     if (!fp.get())
50     {
51         fprintf(stderr, "Error opening '%s'.\n", fileName);
52         return false;
53     }
54 
55     png_struct *writeStruct =
56         png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
57     if (!writeStruct)
58     {
59         fprintf(stderr, "Error on png_create_write_struct.\n");
60         return false;
61     }
62 
63     png_info *infoStruct = png_create_info_struct(writeStruct);
64     if (!infoStruct)
65     {
66         fprintf(stderr, "Error on png_create_info_struct.\n");
67         return false;
68     }
69 
70     if (setjmp(png_jmpbuf(writeStruct)))
71     {
72         fp.close();
73         png_free_data(writeStruct, infoStruct, PNG_FREE_ALL, -1);
74         png_destroy_write_struct(&writeStruct, &infoStruct);
75         return false;
76     }
77 
78     png_init_io(writeStruct, fp.get());
79 
80     // Write header (8 bit colour depth)
81     png_set_IHDR(writeStruct, infoStruct, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
82                  PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
83 
84     // Set title
85     if (title != nullptr && strlen(title) > 0)
86     {
87         std::array<char, 50> mutableKey = {};
88         strcpy(mutableKey.data(), "Title");
89         std::array<char, 200> mutableText = {};
90         strncpy(mutableText.data(), title, 199);
91 
92         png_text titleText;
93         titleText.compression = PNG_TEXT_COMPRESSION_NONE;
94         titleText.key         = mutableKey.data();
95         titleText.text        = mutableText.data();
96         png_set_text(writeStruct, infoStruct, &titleText, 1);
97     }
98 
99     png_write_info(writeStruct, infoStruct);
100 
101     // RGB 3-byte stride.
102     const uint32_t rowStride = width * 3;
103     for (uint32_t row = 0; row < height; ++row)
104     {
105         uint32_t rowOffset = row * rowStride;
106         png_write_row(writeStruct, &data[rowOffset]);
107     }
108 
109     png_write_end(writeStruct, infoStruct);
110 
111     fp.close();
112     png_free_data(writeStruct, infoStruct, PNG_FREE_ALL, -1);
113     png_destroy_write_struct(&writeStruct, &infoStruct);
114     return true;
115 }
116 }  // namespace angle
117