* Reads the heightmap and/or size of the heightmap from a PNG file. * If map == nullptr only the size of the PNG is read, otherwise a map * with greyscale pixels is allocated and assigned to *map. */
| 139 | * with greyscale pixels is allocated and assigned to *map. |
| 140 | */ |
| 141 | static bool ReadHeightmapPNG(std::string_view filename, uint *x, uint *y, std::vector<uint8_t> *map) |
| 142 | { |
| 143 | png_structp png_ptr = nullptr; |
| 144 | png_infop info_ptr = nullptr; |
| 145 | |
| 146 | auto fp = FioFOpenFile(filename, "rb", HEIGHTMAP_DIR); |
| 147 | if (!fp.has_value()) { |
| 148 | ShowErrorMessage(GetEncodedString(STR_ERROR_PNGMAP), GetEncodedString(STR_ERROR_PNGMAP_FILE_NOT_FOUND), WL_ERROR); |
| 149 | return false; |
| 150 | } |
| 151 | |
| 152 | png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); |
| 153 | if (png_ptr == nullptr) { |
| 154 | ShowErrorMessage(GetEncodedString(STR_ERROR_PNGMAP), GetEncodedString(STR_ERROR_PNGMAP_MISC), WL_ERROR); |
| 155 | return false; |
| 156 | } |
| 157 | |
| 158 | info_ptr = png_create_info_struct(png_ptr); |
| 159 | if (info_ptr == nullptr || setjmp(png_jmpbuf(png_ptr))) { |
| 160 | ShowErrorMessage(GetEncodedString(STR_ERROR_PNGMAP), GetEncodedString(STR_ERROR_PNGMAP_MISC), WL_ERROR); |
| 161 | png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); |
| 162 | return false; |
| 163 | } |
| 164 | |
| 165 | png_init_io(png_ptr, *fp); |
| 166 | |
| 167 | /* Allocate memory and read image, without alpha or 16-bit samples |
| 168 | * (result is either 8-bit indexed/greyscale or 24-bit RGB) */ |
| 169 | png_set_packing(png_ptr); |
| 170 | png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_PACKING | PNG_TRANSFORM_STRIP_ALPHA | PNG_TRANSFORM_STRIP_16, nullptr); |
| 171 | |
| 172 | /* Maps of wrong colour-depth are not used. |
| 173 | * (this should have been taken care of by stripping alpha and 16-bit samples on load) */ |
| 174 | if ((png_get_channels(png_ptr, info_ptr) != 1) && (png_get_channels(png_ptr, info_ptr) != 3) && (png_get_bit_depth(png_ptr, info_ptr) != 8)) { |
| 175 | ShowErrorMessage(GetEncodedString(STR_ERROR_PNGMAP), GetEncodedString(STR_ERROR_PNGMAP_IMAGE_TYPE), WL_ERROR); |
| 176 | png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); |
| 177 | return false; |
| 178 | } |
| 179 | |
| 180 | uint width = png_get_image_width(png_ptr, info_ptr); |
| 181 | uint height = png_get_image_height(png_ptr, info_ptr); |
| 182 | |
| 183 | if (!IsValidHeightmapDimension(width, height)) { |
| 184 | ShowErrorMessage(GetEncodedString(STR_ERROR_PNGMAP), GetEncodedString(STR_ERROR_HEIGHTMAP_TOO_LARGE), WL_ERROR); |
| 185 | png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); |
| 186 | return false; |
| 187 | } |
| 188 | |
| 189 | if (map != nullptr) { |
| 190 | map->resize(static_cast<size_t>(width) * height); |
| 191 | ReadHeightmapPNGImageData(*map, png_ptr, info_ptr); |
| 192 | } |
| 193 | |
| 194 | *x = width; |
| 195 | *y = height; |
| 196 | |
| 197 | png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); |
| 198 | return true; |
no test coverage detected