From ac3233b81915e65d9c5e8fa876c4582d3a12f213 Mon Sep 17 00:00:00 2001 From: Ted John Date: Tue, 8 May 2018 21:41:41 +0100 Subject: [PATCH] Change consumers to use new imaging API --- src/openrct2/CmdlineSprite.cpp | 45 +++++++---- src/openrct2/core/Imaging.cpp | 2 +- src/openrct2/core/Imaging.h | 5 +- src/openrct2/interface/Screenshot.cpp | 52 +++++++++++-- src/openrct2/world/MapGen.cpp | 106 ++++++++++++-------------- 5 files changed, 128 insertions(+), 82 deletions(-) diff --git a/src/openrct2/CmdlineSprite.cpp b/src/openrct2/CmdlineSprite.cpp index bed9975a7e..ae1416712a 100644 --- a/src/openrct2/CmdlineSprite.cpp +++ b/src/openrct2/CmdlineSprite.cpp @@ -233,10 +233,23 @@ static bool sprite_file_export(sint32 spriteIndex, const char *outPath) gfx_bmp_sprite_to_buffer((uint8*)spriteFilePalette, spriteHeader->offset, pixels, spriteHeader, &dpi, spriteHeader->height, spriteHeader->width, IMAGE_TYPE_DEFAULT); } - if (Imaging::PngWrite(&dpi, (rct_palette*)spriteFilePalette, outPath)) { + auto const pixels8 = dpi.bits; + auto const pixelsLen = (dpi.width + dpi.pitch) * dpi.height; + try + { + Image image; + image.Width = dpi.width; + image.Height = dpi.height; + image.Depth = 8; + image.Stride = dpi.width + dpi.pitch; + image.Palette = std::make_unique(*((rct_palette *)&spriteFilePalette)); + image.Pixels = std::vector(pixels8, pixels8 + pixelsLen); + Imaging::WriteToFile(outPath, image, IMAGE_FORMAT::PNG); return true; - } else { - fprintf(stderr, "Error writing PNG"); + } + catch (const std::exception& e) + { + fprintf(stderr, "Unable to write png: %s", e.what()); return false; } } @@ -300,29 +313,34 @@ static sint32 get_palette_index(sint16 *colour) static bool sprite_file_import(const char *path, sint16 x_offset, sint16 y_offset, bool keep_palette, rct_g1_element *outElement, uint8 **outBuffer, int *outBufferLength, sint32 mode) { - uint8 *pixels; - uint32 width, height; - sint32 bitDepth; - if (!Imaging::PngRead(&pixels, &width, &height, !keep_palette, path, &bitDepth)) + Image image; + auto format = keep_palette ? IMAGE_FORMAT::PNG : IMAGE_FORMAT::PNG_32; + try { - fprintf(stderr, "Error reading PNG\n"); + image = std::move(Imaging::ReadFromFile(path, format)); + } + catch (const std::exception &e) + { + fprintf(stderr, "Error reading PNG: %s\n", e.what()); return false; } - if (width > 256 || height > 256) + if (image.Width > 256 || image.Height > 256) { fprintf(stderr, "Only images 256x256 or less are supported.\n"); - free(pixels); return false; } - if (keep_palette && (bitDepth != 8)) + if (keep_palette && (image.Depth != 8)) { - fprintf(stderr, "Image is not palletted, it has bit depth of %d\n", bitDepth); - free(pixels); + fprintf(stderr, "Image is not palletted, it has bit depth of %d\n", image.Depth); return false; } + const auto width = image.Width; + const auto height = image.Height; + const auto pixels = image.Pixels.data(); + memcpy(spriteFilePalette, CmdlineSprite::_standardPalette, 256 * 4); uint8 *buffer = (uint8 *)malloc((height * 2) + (width * height * 16)); @@ -497,7 +515,6 @@ static bool sprite_file_import(const char *path, sint16 x_offset, sint16 y_offse } } } - free(pixels); free(rgbaSrc_orig); sint32 bufferLength = (sint32)(dst - buffer); diff --git a/src/openrct2/core/Imaging.cpp b/src/openrct2/core/Imaging.cpp index 9f76aa46c5..099a652427 100644 --- a/src/openrct2/core/Imaging.cpp +++ b/src/openrct2/core/Imaging.cpp @@ -277,7 +277,7 @@ namespace Imaging } } - static IMAGE_FORMAT GetImageFormatFromPath(const std::string_view& path) + IMAGE_FORMAT GetImageFormatFromPath(const std::string_view& path) { if (String::EndsWith(path, ".png", true)) { diff --git a/src/openrct2/core/Imaging.h b/src/openrct2/core/Imaging.h index 104ad25ca5..10b9c74051 100644 --- a/src/openrct2/core/Imaging.h +++ b/src/openrct2/core/Imaging.h @@ -49,11 +49,8 @@ struct Image namespace Imaging { + IMAGE_FORMAT GetImageFormatFromPath(const std::string_view& path); Image ReadFromFile(const std::string_view& path, IMAGE_FORMAT format = IMAGE_FORMAT::AUTOMATIC); Image ReadFromBuffer(const std::vector& buffer, IMAGE_FORMAT format = IMAGE_FORMAT::AUTOMATIC); void WriteToFile(const std::string_view& path, const Image& image, IMAGE_FORMAT format = IMAGE_FORMAT::AUTOMATIC); - - bool PngRead(uint8 * * pixels, uint32 * width, uint32 * height, bool expand, const utf8 * path, sint32 * bitDepth); - bool PngWrite(const rct_drawpixelinfo * dpi, const rct_palette * palette, const utf8 * path); - bool PngWrite32bpp(sint32 width, sint32 height, const void * pixels, const utf8 * path); } diff --git a/src/openrct2/interface/Screenshot.cpp b/src/openrct2/interface/Screenshot.cpp index f31aaa0434..3f0fde6d41 100644 --- a/src/openrct2/interface/Screenshot.cpp +++ b/src/openrct2/interface/Screenshot.cpp @@ -41,6 +41,29 @@ using namespace OpenRCT2; uint8 gScreenshotCountdown = 0; +static bool WriteDpiToFile(const std::string_view& path, const rct_drawpixelinfo * dpi, const rct_palette& palette) +{ + auto const pixels8 = dpi->bits; + auto const pixelsLen = (dpi->width + dpi->pitch) * dpi->height; + try + { + Image image; + image.Width = dpi->width; + image.Height = dpi->height; + image.Depth = 8; + image.Stride = dpi->width + dpi->pitch; + image.Palette = std::make_unique(palette); + image.Pixels = std::vector(pixels8, pixels8 + pixelsLen); + Imaging::WriteToFile(path, image, IMAGE_FORMAT::PNG); + return true; + } + catch (const std::exception& e) + { + log_error("Unable to write png: %s", e.what()); + return false; + } +} + /** * * rct2: 0x006E3AEC @@ -153,9 +176,12 @@ sint32 screenshot_dump_png(rct_drawpixelinfo *dpi) rct_palette renderedPalette; screenshot_get_rendered_palette(&renderedPalette); - if (Imaging::PngWrite(dpi, &renderedPalette, path)) { + if (WriteDpiToFile(path, dpi, renderedPalette)) + { return index; - } else { + } + else + { return -1; } } @@ -169,9 +195,23 @@ sint32 screenshot_dump_png_32bpp(sint32 width, sint32 height, const void *pixels return -1; } - if (Imaging::PngWrite32bpp(width, height, pixels, path)) { + const auto pixels8 = (const uint8 *)pixels; + const auto pixelsLen = width * 4 * height; + + try + { + Image image; + image.Width = width; + image.Height = height; + image.Depth = 32; + image.Stride = width * 4; + image.Pixels = std::vector(pixels8, pixels8 + pixelsLen); + Imaging::WriteToFile(path, image, IMAGE_FORMAT::PNG_32); return index; - } else { + } + catch (const std::exception &e) + { + log_error("Unable to save screenshot: %s", e.what()); return -1; } } @@ -259,7 +299,7 @@ void screenshot_giant() rct_palette renderedPalette; screenshot_get_rendered_palette(&renderedPalette); - Imaging::PngWrite(&dpi, &renderedPalette, path); + WriteDpiToFile(path, &dpi, renderedPalette); free(dpi.bits); @@ -576,7 +616,7 @@ sint32 cmdline_for_screenshot(const char * * argv, sint32 argc, ScreenshotOption rct_palette renderedPalette; screenshot_get_rendered_palette(&renderedPalette); - Imaging::PngWrite(&dpi, &renderedPalette, outputPath); + WriteDpiToFile(outputPath, &dpi, renderedPalette); free(dpi.bits); drawing_engine_dispose(); diff --git a/src/openrct2/world/MapGen.cpp b/src/openrct2/world/MapGen.cpp index a1e054fa14..05e1e24b4e 100644 --- a/src/openrct2/world/MapGen.cpp +++ b/src/openrct2/world/MapGen.cpp @@ -647,75 +647,67 @@ static void mapgen_simplex(mapgen_settings * settings) bool mapgen_load_heightmap(const utf8 * path) { - const char * extension = path_get_extension(path); - uint8 * pixels; - size_t pitch; - uint32 numChannels; - uint32 width, height; - - if (String::Equals(extension, ".png", false)) + auto format = Imaging::GetImageFormatFromPath(path); + if (format == IMAGE_FORMAT::PNG) { - sint32 bitDepth; - if (!Imaging::PngRead(&pixels, &width, &height, true, path, &bitDepth)) + // Promote to 32-bit + format = IMAGE_FORMAT::PNG_32; + } + + try + { + auto image = Imaging::ReadFromFile(path, format); + if (image.Width != image.Height) { - log_warning("Error reading PNG"); - context_show_error(STR_HEIGHT_MAP_ERROR, STR_ERROR_READING_PNG); + context_show_error(STR_HEIGHT_MAP_ERROR, STR_ERROR_WIDTH_AND_HEIGHT_DO_NOT_MATCH); return false; } - numChannels = 4; - pitch = width * numChannels; - } - else if (strcicmp(extension, ".bmp") == 0) - { - if (!context_read_bmp((void **) &pixels, &width, &height, path)) + auto size = image.Width; + if (image.Width > MAXIMUM_MAP_SIZE_PRACTICAL) { - // ReadBMP contains context_show_error calls - return false; + context_show_error(STR_HEIGHT_MAP_ERROR, STR_ERROR_HEIHGT_MAP_TOO_BIG); + size = std::min(image.Height, MAXIMUM_MAP_SIZE_PRACTICAL); } - numChannels = 4; - pitch = width * numChannels; - } - else - { - openrct2_assert(false, "A file with an invalid file extension was selected."); - return false; - } + // Allocate memory for the height map values, one byte pixel + delete[] _heightMapData.mono_bitmap; + _heightMapData.mono_bitmap = new uint8[size * size]; + _heightMapData.width = size; + _heightMapData.height = size; - if (width != height) - { - context_show_error(STR_HEIGHT_MAP_ERROR, STR_ERROR_WIDTH_AND_HEIGHT_DO_NOT_MATCH); - free(pixels); - return false; - } - - if (width > MAXIMUM_MAP_SIZE_PRACTICAL) - { - context_show_error(STR_HEIGHT_MAP_ERROR, STR_ERROR_HEIHGT_MAP_TOO_BIG); - width = height = Math::Min(height, (uint32)MAXIMUM_MAP_SIZE_PRACTICAL); - } - - // Allocate memory for the height map values, one byte pixel - delete[] _heightMapData.mono_bitmap; - _heightMapData.mono_bitmap = new uint8[width * height]; - _heightMapData.width = width; - _heightMapData.height = height; - - // Copy average RGB value to mono bitmap - for (uint32 x = 0; x < _heightMapData.width; x++) - { - for (uint32 y = 0; y < _heightMapData.height; y++) + // Copy average RGB value to mono bitmap + constexpr auto numChannels = 4; + const auto pitch = image.Stride; + const auto pixels = image.Pixels.data(); + for (uint32 x = 0; x < _heightMapData.width; x++) { - const uint8 red = pixels[x * numChannels + y * pitch]; - const uint8 green = pixels[x * numChannels + y * pitch + 1]; - const uint8 blue = pixels[x * numChannels + y * pitch + 2]; - _heightMapData.mono_bitmap[x + y * _heightMapData.width] = (red + green + blue) / 3; + for (uint32 y = 0; y < _heightMapData.height; y++) + { + const auto red = pixels[x * numChannels + y * pitch]; + const auto green = pixels[x * numChannels + y * pitch + 1]; + const auto blue = pixels[x * numChannels + y * pitch + 2]; + _heightMapData.mono_bitmap[x + y * _heightMapData.width] = (red + green + blue) / 3; + } } + return true; + } + catch (const std::exception& e) + { + switch (format) + { + case IMAGE_FORMAT::BITMAP: + context_show_error(STR_HEIGHT_MAP_ERROR, STR_ERROR_READING_BITMAP); + break; + case IMAGE_FORMAT::PNG_32: + context_show_error(STR_HEIGHT_MAP_ERROR, STR_ERROR_READING_PNG); + break; + default: + log_error("Unable to load height map image: %s", e.what()); + break; + } + return false; } - - free(pixels); - return true; } /**