/** * Reads the heightmap and/or size of the heightmap from a PNG file. * If map == NULL only the size of the PNG is read, otherwise a map * with grayscale pixels is allocated and assigned to *map. */ static bool ReadHeightmapPNG(char *filename, uint *x, uint *y, byte **map) { FILE *fp; png_structp png_ptr = NULL; png_infop info_ptr = NULL; fp = FioFOpenFile(filename, "rb"); if (fp == NULL) { ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_FILE_NOT_FOUND, WL_ERROR); return false; } png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_MISC, WL_ERROR); fclose(fp); return false; } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL || setjmp(png_jmpbuf(png_ptr))) { ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_MISC, WL_ERROR); fclose(fp); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return false; } png_init_io(png_ptr, fp); /* Allocate memory and read image, without alpha or 16-bit samples * (result is either 8-bit indexed/grayscale or 24-bit RGB) */ png_set_packing(png_ptr); png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_PACKING | PNG_TRANSFORM_STRIP_ALPHA | PNG_TRANSFORM_STRIP_16, NULL); /* Maps of wrong colour-depth are not used. * (this should have been taken care of by stripping alpha and 16-bit samples on load) */ 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)) { ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_IMAGE_TYPE, WL_ERROR); fclose(fp); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return false; } if (map != NULL) { *map = MallocT<byte>(png_get_image_width(png_ptr, info_ptr) * png_get_image_height(png_ptr, info_ptr)); ReadHeightmapPNGImageData(*map, png_ptr, info_ptr); } *x = png_get_image_width(png_ptr, info_ptr); *y = png_get_image_height(png_ptr, info_ptr); fclose(fp); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return true; }
/** * 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 grayscale pixels is allocated and assigned to *map. */ static bool ReadHeightmapPNG(const char *filename, uint *x, uint *y, byte **map) { FILE *fp; png_structp png_ptr = nullptr; png_infop info_ptr = nullptr; fp = FioFOpenFile(filename, "rb", HEIGHTMAP_DIR); if (fp == nullptr) { ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_FILE_NOT_FOUND, WL_ERROR); return false; } png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); if (png_ptr == nullptr) { ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_MISC, WL_ERROR); fclose(fp); return false; } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == nullptr || setjmp(png_jmpbuf(png_ptr))) { ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_MISC, WL_ERROR); fclose(fp); png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); return false; } png_init_io(png_ptr, fp); /* Allocate memory and read image, without alpha or 16-bit samples * (result is either 8-bit indexed/grayscale or 24-bit RGB) */ png_set_packing(png_ptr); png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_PACKING | PNG_TRANSFORM_STRIP_ALPHA | PNG_TRANSFORM_STRIP_16, nullptr); /* Maps of wrong colour-depth are not used. * (this should have been taken care of by stripping alpha and 16-bit samples on load) */ 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)) { ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_IMAGE_TYPE, WL_ERROR); fclose(fp); png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); return false; } uint width = png_get_image_width(png_ptr, info_ptr); uint height = png_get_image_height(png_ptr, info_ptr); /* Check if image dimensions don't overflow a size_t to avoid memory corruption. */ if ((uint64)width * height >= (size_t)-1) { ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_HEIGHTMAP_TOO_LARGE, WL_ERROR); fclose(fp); png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); return false; } if (map != nullptr) { *map = MallocT<byte>(width * height); ReadHeightmapPNGImageData(*map, png_ptr, info_ptr); } *x = width; *y = height; fclose(fp); png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); return true; }