File: png_utils.cpp

package info (click to toggle)
webkit2gtk 2.51.2-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 457,708 kB
  • sloc: cpp: 3,884,629; javascript: 198,661; ansic: 165,298; python: 49,171; asm: 21,849; ruby: 18,095; perl: 16,914; xml: 4,623; sh: 2,397; yacc: 2,356; java: 2,019; lex: 1,330; pascal: 372; makefile: 197
file content (120 lines) | stat: -rw-r--r-- 2,955 bytes parent folder | download | duplicates (10)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
//
// 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.
//

#ifdef UNSAFE_BUFFERS_BUILD
#    pragma allow_unsafe_libc_calls
#endif

#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