"docs/source/en/training/instructpix2pix.md" did not exist on "9dc84448aca9718f9e1175cf83a6a9c10467882a"
decode_png.cpp 4.98 KB
Newer Older
1
2
3
4
5
#include "decode_png.h"
#include "common_png.h"

namespace vision {
namespace image {
6
7

#if !PNG_FOUND
8
9
10
torch::Tensor decode_png(const torch::Tensor& data, ImageReadMode mode) {
  TORCH_CHECK(
      false, "decode_png: torchvision not compiled with libPNG support");
11
12
13
}
#else

14
torch::Tensor decode_png(const torch::Tensor& data, ImageReadMode mode) {
Francisco Massa's avatar
Francisco Massa committed
15
16
17
18
19
20
21
  // Check that the input tensor dtype is uint8
  TORCH_CHECK(data.dtype() == torch::kU8, "Expected a torch.uint8 tensor");
  // Check that the input tensor is 1-dimensional
  TORCH_CHECK(
      data.dim() == 1 && data.numel() > 0,
      "Expected a non empty 1-dimensional tensor");

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
  auto png_ptr =
      png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
  TORCH_CHECK(png_ptr, "libpng read structure allocation failed!")
  auto info_ptr = png_create_info_struct(png_ptr);
  if (!info_ptr) {
    png_destroy_read_struct(&png_ptr, nullptr, nullptr);
    // Seems redundant with the if statement. done here to avoid leaking memory.
    TORCH_CHECK(info_ptr, "libpng info structure allocation failed!")
  }

  auto datap = data.accessor<unsigned char, 1>().data();

  if (setjmp(png_jmpbuf(png_ptr)) != 0) {
    png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
    TORCH_CHECK(false, "Internal error.");
  }
  auto is_png = !png_sig_cmp(datap, 0, 8);
  TORCH_CHECK(is_png, "Content is not png!")

  struct Reader {
    png_const_bytep ptr;
  } reader;
  reader.ptr = png_const_bytep(datap) + 8;

  auto read_callback =
      [](png_structp png_ptr, png_bytep output, png_size_t bytes) {
        auto reader = static_cast<Reader*>(png_get_io_ptr(png_ptr));
        std::copy(reader->ptr, reader->ptr + bytes, output);
        reader->ptr += bytes;
      };
  png_set_sig_bytes(png_ptr, 8);
  png_set_read_fn(png_ptr, &reader, read_callback);
  png_read_info(png_ptr, info_ptr);

  png_uint_32 width, height;
  int bit_depth, color_type;
  auto retval = png_get_IHDR(
      png_ptr,
      info_ptr,
      &width,
      &height,
      &bit_depth,
      &color_type,
      nullptr,
      nullptr,
      nullptr);

  if (retval != 1) {
    png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
    TORCH_CHECK(retval == 1, "Could read image metadata from content.")
  }
73

74
  int channels = png_get_channels(png_ptr, info_ptr);
75

Prabhat Roy's avatar
Prabhat Roy committed
76
77
78
  if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
    png_set_expand_gray_1_2_4_to_8(png_ptr);

79
  if (mode != IMAGE_READ_MODE_UNCHANGED) {
80
81
82
83
84
    // TODO: consider supporting PNG_INFO_tRNS
    bool is_palette = (color_type & PNG_COLOR_MASK_PALETTE) != 0;
    bool has_color = (color_type & PNG_COLOR_MASK_COLOR) != 0;
    bool has_alpha = (color_type & PNG_COLOR_MASK_ALPHA) != 0;

85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
    switch (mode) {
      case IMAGE_READ_MODE_GRAY:
        if (color_type != PNG_COLOR_TYPE_GRAY) {
          if (is_palette) {
            png_set_palette_to_rgb(png_ptr);
            has_alpha = true;
          }

          if (has_alpha) {
            png_set_strip_alpha(png_ptr);
          }

          if (has_color) {
            png_set_rgb_to_gray(png_ptr, 1, 0.2989, 0.587);
          }
          channels = 1;
101
102
        }
        break;
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
      case IMAGE_READ_MODE_GRAY_ALPHA:
        if (color_type != PNG_COLOR_TYPE_GRAY_ALPHA) {
          if (is_palette) {
            png_set_palette_to_rgb(png_ptr);
            has_alpha = true;
          }

          if (!has_alpha) {
            png_set_add_alpha(png_ptr, (1 << bit_depth) - 1, PNG_FILLER_AFTER);
          }

          if (has_color) {
            png_set_rgb_to_gray(png_ptr, 1, 0.2989, 0.587);
          }
          channels = 2;
118
119
        }
        break;
120
121
122
123
124
125
126
127
128
129
130
131
132
      case IMAGE_READ_MODE_RGB:
        if (color_type != PNG_COLOR_TYPE_RGB) {
          if (is_palette) {
            png_set_palette_to_rgb(png_ptr);
            has_alpha = true;
          } else if (!has_color) {
            png_set_gray_to_rgb(png_ptr);
          }

          if (has_alpha) {
            png_set_strip_alpha(png_ptr);
          }
          channels = 3;
133
134
        }
        break;
135
136
137
138
139
140
141
142
143
144
145
146
147
      case IMAGE_READ_MODE_RGB_ALPHA:
        if (color_type != PNG_COLOR_TYPE_RGB_ALPHA) {
          if (is_palette) {
            png_set_palette_to_rgb(png_ptr);
            has_alpha = true;
          } else if (!has_color) {
            png_set_gray_to_rgb(png_ptr);
          }

          if (!has_alpha) {
            png_set_add_alpha(png_ptr, (1 << bit_depth) - 1, PNG_FILLER_AFTER);
          }
          channels = 4;
148
149
150
151
        }
        break;
      default:
        png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
152
        TORCH_CHECK(false, "The provided mode is not supported for PNG files");
153
154
155
    }

    png_read_update_info(png_ptr, info_ptr);
156
157
  }

158
159
  auto tensor =
      torch::empty({int64_t(height), int64_t(width), channels}, torch::kU8);
160
  auto ptr = tensor.accessor<uint8_t, 3>().data();
161
  for (png_uint_32 i = 0; i < height; ++i) {
162
    png_read_row(png_ptr, ptr, nullptr);
Prabhat Roy's avatar
Prabhat Roy committed
163
    ptr += width * channels;
164
165
  }
  png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
166
  return tensor.permute({2, 0, 1});
167
}
168
169
170
171
#endif

} // namespace image
} // namespace vision