Renamed PngImage to PngFile and put it in a Utils namespace to match the other file utilities.

Signed-off-by: santorac <55155825+santorac@users.noreply.github.com>
This commit is contained in:
santorac
2021-09-08 13:20:54 -07:00
parent 7a8eb8eda5
commit a9c6909a29
3 changed files with 311 additions and 305 deletions
@@ -87,9 +87,9 @@ namespace AZ
jobCompletion.StartAndWaitForCompletion();
}
PngImage image = PngImage::Create(readbackResult.m_imageDescriptor.m_size, readbackResult.m_imageDescriptor.m_format, *buffer);
Utils::PngFile image = Utils::PngFile::Create(readbackResult.m_imageDescriptor.m_size, readbackResult.m_imageDescriptor.m_format, *buffer);
PngImage::SaveSettings saveSettings;
Utils::PngFile::SaveSettings saveSettings;
saveSettings.m_compressionLevel = r_pngCompressionLevel;
// We should probably strip alpha to save space, especially for automated test screenshots. Alpha is left in to maintain
// prior behavior, changing this is out of scope for the current task. Note, it would have bit of a cascade effect where
@@ -18,77 +18,80 @@
namespace AZ
{
//! This is a light wrapper class for libpng, to load and save .png files.
//! Functionality is limited, feel free to add more features as needed.
class PngImage
namespace Utils
{
public:
using ErrorHandler = AZStd::function<void(const char*)>;
struct LoadSettings
//! This is a light wrapper class for libpng, to load and save .png files.
//! Functionality is limited, feel free to add more features as needed.
class PngFile
{
ErrorHandler m_errorHandler = {}; //!< optional callback function describing any errors that are encountered
bool m_stripAlpha = false; //!< the alpha channel will be skipped, loading an RGBA image as RGB
public:
using ErrorHandler = AZStd::function<void(const char*)>;
struct LoadSettings
{
ErrorHandler m_errorHandler = {}; //!< optional callback function describing any errors that are encountered
bool m_stripAlpha = false; //!< the alpha channel will be skipped, loading an RGBA image as RGB
};
struct SaveSettings
{
ErrorHandler m_errorHandler = {}; //!< optional callback function describing any errors that are encountered
bool m_stripAlpha = false; //!< the alpha channel will be skipped, saving an RGBA buffer as RGB
int m_compressionLevel = 6; //!< this is the zlib compression level. See png_set_compression_level in png.h
};
// To keep things simple for now we limit all images to RGB and RGBA, 8 bits per channel.
enum class Format
{
Unknown,
RGB,
RGBA
};
//! @return the loaded PngFile or an invalid PngFile if there was an error.
static PngFile Load(const char* path, LoadSettings loadSettings = {});
//! Create a PngFile from an RHI data buffer.
//! @param size the dimensions of the image (m_depth is not used, assumed to be 1)
//! @param format indicates the pixel format represented by @data. Only a limited set of formats are supported, see implementation.
//! @param data the buffer of image data. The size of the buffer must match the @size and @format parameters.
//! @return the created PngFile or an invalid PngFile if there was an error.
static PngFile Create(const RHI::Size& size, RHI::Format format, AZStd::array_view<uint8_t> data);
static PngFile Create(const RHI::Size& size, RHI::Format format, AZStd::vector<uint8_t>&& data);
PngFile() = default;
AZ_DEFAULT_MOVE(PngFile)
//! @return true if the save operation was successful
bool Save(const char* path, SaveSettings saveSettings = {});
bool IsValid() const;
operator bool() const { return IsValid(); }
uint32_t GetWidth() const { return m_width; }
uint32_t GetHeight() const { return m_height; }
Format GetBufferFormat() const { return m_bufferFormat; }
const AZStd::vector<uint8_t>& GetBuffer() const { return m_buffer; }
//! Returns a r-value reference that can be moved. This will invalidate the PngFile.
AZStd::vector<uint8_t>&& TakeBuffer();
private:
AZ_DEFAULT_COPY(PngFile)
static const int HeaderSize = 8;
static void DefaultErrorHandler(const char* message);
// See png_get_IHDR in http://www.libpng.org/pub/png/libpng-1.4.0-manual.pdf...
uint32_t m_width = 0;
uint32_t m_height = 0;
int32_t m_bitDepth = 0;
int32_t m_colorType = 0;
Format m_bufferFormat = Format::Unknown;
AZStd::vector<uint8_t> m_buffer;
};
struct SaveSettings
{
ErrorHandler m_errorHandler = {}; //!< optional callback function describing any errors that are encountered
bool m_stripAlpha = false; //!< the alpha channel will be skipped, saving an RGBA buffer as RGB
int m_compressionLevel = 6; //!< this is the zlib compression level. See png_set_compression_level in png.h
};
// To keep things simple for now we limit all images to RGB and RGBA, 8 bits per channel.
enum class Format
{
Unknown,
RGB,
RGBA
};
//! @return the loaded PngImage or an invalid PngImage if there was an error.
static PngImage Load(const char* path, LoadSettings loadSettings = {});
//! Create a PngImage from an RHI data buffer.
//! @param size the dimensions of the image (m_depth is not used, assumed to be 1)
//! @param format indicates the pixel format represented by @data. Only a limited set of formats are supported, see implementation.
//! @param data the buffer of image data. The size of the buffer must match the @size and @format parameters.
//! @return the created PngImage or an invalid PngImage if there was an error.
static PngImage Create(const RHI::Size& size, RHI::Format format, AZStd::array_view<uint8_t> data);
static PngImage Create(const RHI::Size& size, RHI::Format format, AZStd::vector<uint8_t>&& data);
PngImage() = default;
AZ_DEFAULT_MOVE(PngImage)
//! @return true if the save operation was successful
bool Save(const char* path, SaveSettings saveSettings = {});
bool IsValid() const;
operator bool() const { return IsValid(); }
uint32_t GetWidth() const { return m_width; }
uint32_t GetHeight() const { return m_height; }
Format GetBufferFormat() const { return m_bufferFormat; }
const AZStd::vector<uint8_t>& GetBuffer() const { return m_buffer; }
//! Returns a r-value reference that can be moved. This will invalidate the PngImage.
AZStd::vector<uint8_t>&& TakeBuffer();
private:
AZ_DEFAULT_COPY(PngImage)
static const int HeaderSize = 8;
static void DefaultErrorHandler(const char* message);
// See png_get_IHDR in http://www.libpng.org/pub/png/libpng-1.4.0-manual.pdf...
uint32_t m_width = 0;
uint32_t m_height = 0;
int32_t m_bitDepth = 0;
int32_t m_colorType = 0;
Format m_bufferFormat = Format::Unknown;
AZStd::vector<uint8_t> m_buffer;
};
}
} // namespace AZ
+236 -233
View File
@@ -11,285 +11,288 @@
namespace AZ
{
namespace
namespace Utils
{
void PngImage_user_error_fn(png_structp png_ptr, png_const_charp error_msg)
namespace
{
PngImage::ErrorHandler* errorHandler = reinterpret_cast<PngImage::ErrorHandler*>(png_get_error_ptr(png_ptr));
(*errorHandler)(error_msg);
}
void PngImage_user_warning_fn(png_structp /*png_ptr*/, png_const_charp warning_msg)
{
AZ_Warning("PngImage", false, "%s", warning_msg);
}
}
PngImage PngImage::Create(const RHI::Size& size, RHI::Format format, AZStd::array_view<uint8_t> data)
{
return Create(size, format, AZStd::vector<uint8_t>{data.begin(), data.end()});
}
PngImage PngImage::Create(const RHI::Size& size, RHI::Format format, AZStd::vector<uint8_t>&& data)
{
PngImage image;
if (RHI::Format::R8G8B8A8_UNORM == format)
{
if (size.m_width * size.m_height * 4 == data.size())
void PngImage_user_error_fn(png_structp png_ptr, png_const_charp error_msg)
{
image.m_width = size.m_width;
image.m_height = size.m_height;
image.m_bitDepth = 8;
image.m_colorType = PNG_COLOR_TYPE_RGB_ALPHA;
image.m_bufferFormat = PngImage::Format::RGBA;
image.m_buffer = data;
PngFile::ErrorHandler* errorHandler = reinterpret_cast<PngFile::ErrorHandler*>(png_get_error_ptr(png_ptr));
(*errorHandler)(error_msg);
}
else
void PngImage_user_warning_fn(png_structp /*png_ptr*/, png_const_charp warning_msg)
{
AZ_Assert(false, "Invalid arguments. Buffer size does not match the image dimensions.");
AZ_Warning("PngFile", false, "%s", warning_msg);
}
}
return image;
}
PngImage PngImage::Load(const char* path, LoadSettings loadSettings)
{
if (!loadSettings.m_errorHandler)
PngFile PngFile::Create(const RHI::Size& size, RHI::Format format, AZStd::array_view<uint8_t> data)
{
loadSettings.m_errorHandler = [path](const char* message) { DefaultErrorHandler(AZStd::string::format("Could not load file '%s'. %s", path, message).c_str()); };
}
// For documentation of this code, see http://www.libpng.org/pub/png/libpng-1.4.0-manual.pdf chapter 3
FILE* fp = NULL;
if (fopen_s(&fp, path, "rb") || !fp)
{
loadSettings.m_errorHandler("Failed to open file.");
return {};
return Create(size, format, AZStd::vector<uint8_t>{data.begin(), data.end()});
}
png_byte header[HeaderSize] = {};
if (fread(header, 1, HeaderSize, fp) != HeaderSize)
PngFile PngFile::Create(const RHI::Size& size, RHI::Format format, AZStd::vector<uint8_t>&& data)
{
fclose(fp);
loadSettings.m_errorHandler("Invalid header.");
return {};
PngFile image;
if (RHI::Format::R8G8B8A8_UNORM == format)
{
if (size.m_width * size.m_height * 4 == data.size())
{
image.m_width = size.m_width;
image.m_height = size.m_height;
image.m_bitDepth = 8;
image.m_colorType = PNG_COLOR_TYPE_RGB_ALPHA;
image.m_bufferFormat = PngFile::Format::RGBA;
image.m_buffer = data;
}
else
{
AZ_Assert(false, "Invalid arguments. Buffer size does not match the image dimensions.");
}
}
return image;
}
bool isPng = !png_sig_cmp(header, 0, HeaderSize);
if (!isPng)
PngFile PngFile::Load(const char* path, LoadSettings loadSettings)
{
fclose(fp);
loadSettings.m_errorHandler("Invalid header.");
return {};
}
if (!loadSettings.m_errorHandler)
{
loadSettings.m_errorHandler = [path](const char* message) { DefaultErrorHandler(AZStd::string::format("Could not load file '%s'. %s", path, message).c_str()); };
}
png_voidp user_error_ptr = &loadSettings.m_errorHandler;
png_error_ptr user_error_fn = PngImage_user_error_fn;
png_error_ptr user_warning_fn = PngImage_user_warning_fn;
// For documentation of this code, see http://www.libpng.org/pub/png/libpng-1.4.0-manual.pdf chapter 3
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, user_error_ptr, user_error_fn, user_warning_fn);
if (!png_ptr)
{
fclose(fp);
loadSettings.m_errorHandler("png_create_read_struct failed.");
return {};
}
FILE* fp = NULL;
if (fopen_s(&fp, path, "rb") || !fp)
{
loadSettings.m_errorHandler("Failed to open file.");
return {};
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr)
{
png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
fclose(fp);
loadSettings.m_errorHandler("png_create_info_struct failed.");
return {};
}
png_byte header[HeaderSize] = {};
png_infop end_info = png_create_info_struct(png_ptr);
if (!end_info)
{
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
fclose(fp);
loadSettings.m_errorHandler("png_create_info_struct failed.");
return {};
}
if (fread(header, 1, HeaderSize, fp) != HeaderSize)
{
fclose(fp);
loadSettings.m_errorHandler("Invalid header.");
return {};
}
bool isPng = !png_sig_cmp(header, 0, HeaderSize);
if (!isPng)
{
fclose(fp);
loadSettings.m_errorHandler("Invalid header.");
return {};
}
png_voidp user_error_ptr = &loadSettings.m_errorHandler;
png_error_ptr user_error_fn = PngImage_user_error_fn;
png_error_ptr user_warning_fn = PngImage_user_warning_fn;
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, user_error_ptr, user_error_fn, user_warning_fn);
if (!png_ptr)
{
fclose(fp);
loadSettings.m_errorHandler("png_create_read_struct failed.");
return {};
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr)
{
png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
fclose(fp);
loadSettings.m_errorHandler("png_create_info_struct failed.");
return {};
}
png_infop end_info = png_create_info_struct(png_ptr);
if (!end_info)
{
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
fclose(fp);
loadSettings.m_errorHandler("png_create_info_struct failed.");
return {};
}
#pragma warning(push)
#pragma warning(disable: 4611) // Disables "interaction between '_setjmp' and C++ object destruction is non-portable". See https://docs.microsoft.com/en-us/cpp/preprocessor/warning?view=msvc-160
if (setjmp(png_jmpbuf(png_ptr)))
{
if (setjmp(png_jmpbuf(png_ptr)))
{
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
fclose(fp);
// We don't report an error message here because the user_error_fn should have done that already.
return {};
}
#pragma warning(pop)
png_init_io(png_ptr, fp);
png_set_sig_bytes(png_ptr, HeaderSize);
png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_NEVER, NULL, 0);
// To keep things simple for now we limit all images to RGB and RGBA, 8 bits per channel
int png_transforms = PNG_TRANSFORM_PACKING | // Expand 1, 2 and 4-bit samples to bytes
PNG_TRANSFORM_STRIP_16 | // Reduce 16 bit samples to 8 bits
PNG_TRANSFORM_GRAY_TO_RGB;
if (loadSettings.m_stripAlpha)
{
png_transforms |= PNG_TRANSFORM_STRIP_ALPHA;
}
png_read_png(png_ptr, info_ptr, png_transforms, NULL);
// Note that libpng will allocate row_pointers for us. If we want to manage the memory ourselves, we need to call png_set_rows.
// In that case we would have to use the low level interface: png_read_info, png_read_image, and png_read_end.
png_bytep* row_pointers = png_get_rows(png_ptr, info_ptr);
PngFile pngFile;
png_get_IHDR(png_ptr, info_ptr, &pngFile.m_width, &pngFile.m_height, &pngFile.m_bitDepth, &pngFile.m_colorType, NULL, NULL, NULL);
uint32_t bytesPerPixel = 0;
switch (pngFile.m_colorType)
{
case PNG_COLOR_TYPE_RGB:
pngFile.m_bufferFormat = PngFile::Format::RGB;
bytesPerPixel = 3;
break;
case PNG_COLOR_TYPE_RGBA:
pngFile.m_bufferFormat = PngFile::Format::RGBA;
bytesPerPixel = 4;
break;
default:
AZ_Assert(false, "The png transforms should have ensured a pixel format of RGB or RGBA, 8 bits per channel");
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
fclose(fp);
loadSettings.m_errorHandler("Unsupported pixel format.");
return {};
}
// In the future we could use the low-level interface to avoid copying the image (and provide progress callbacks)
pngFile.m_buffer.set_capacity(pngFile.m_width * pngFile.m_height * bytesPerPixel);
for (uint32_t rowIndex = 0; rowIndex < pngFile.m_height; ++rowIndex)
{
png_bytep row = row_pointers[rowIndex];
pngFile.m_buffer.insert(pngFile.m_buffer.end(), row, row + (pngFile.m_width * bytesPerPixel));
}
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
fclose(fp);
// We don't report an error message here because the user_error_fn should have done that already.
return {};
return pngFile;
}
#pragma warning(pop)
png_init_io(png_ptr, fp);
png_set_sig_bytes(png_ptr, HeaderSize);
png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_NEVER, NULL, 0);
// To keep things simple for now we limit all images to RGB and RGBA, 8 bits per channel
int png_transforms = PNG_TRANSFORM_PACKING | // Expand 1, 2 and 4-bit samples to bytes
PNG_TRANSFORM_STRIP_16 | // Reduce 16 bit samples to 8 bits
PNG_TRANSFORM_GRAY_TO_RGB;
if (loadSettings.m_stripAlpha)
bool PngFile::Save(const char* path, SaveSettings saveSettings)
{
png_transforms |= PNG_TRANSFORM_STRIP_ALPHA;
}
if (!saveSettings.m_errorHandler)
{
saveSettings.m_errorHandler = [path](const char* message) { DefaultErrorHandler(AZStd::string::format("Could not save file '%s'. %s", path, message).c_str()); };
}
png_read_png(png_ptr, info_ptr, png_transforms, NULL);
// Note that libpng will allocate row_pointers for us. If we want to manage the memory ourselves, we need to call png_set_rows.
// In that case we would have to use the low level interface: png_read_info, png_read_image, and png_read_end.
png_bytep* row_pointers = png_get_rows(png_ptr, info_ptr);
if (!IsValid())
{
saveSettings.m_errorHandler("This PngFile is invalid.");
return false;
}
PngImage pngImage;
// For documentation of this code, see http://www.libpng.org/pub/png/libpng-1.4.0-manual.pdf chapter 4
png_get_IHDR(png_ptr, info_ptr, &pngImage.m_width, &pngImage.m_height, &pngImage.m_bitDepth, &pngImage.m_colorType, NULL, NULL, NULL);
uint32_t bytesPerPixel = 0;
FILE* fp = NULL;
if (fopen_s(&fp, path, "wb") || !fp)
{
saveSettings.m_errorHandler("Failed to open file.");
return false;
}
switch (pngImage.m_colorType)
{
case PNG_COLOR_TYPE_RGB:
pngImage.m_bufferFormat = PngImage::Format::RGB;
bytesPerPixel = 3;
break;
case PNG_COLOR_TYPE_RGBA:
pngImage.m_bufferFormat = PngImage::Format::RGBA;
bytesPerPixel = 4;
break;
default:
AZ_Assert(false, "The png transforms should have ensured a pixel format of RGB or RGBA, 8 bits per channel");
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
fclose(fp);
loadSettings.m_errorHandler("Unsupported pixel format.");
return {};
}
png_voidp user_error_ptr = &saveSettings.m_errorHandler;
png_error_ptr user_error_fn = PngImage_user_error_fn;
png_error_ptr user_warning_fn = PngImage_user_warning_fn;
// In the future we could use the low-level interface to avoid copying the image (and provide progress callbacks)
pngImage.m_buffer.set_capacity(pngImage.m_width * pngImage.m_height * bytesPerPixel);
for (uint32_t rowIndex = 0; rowIndex < pngImage.m_height; ++rowIndex)
{
png_bytep row = row_pointers[rowIndex];
pngImage.m_buffer.insert(pngImage.m_buffer.end(), row, row + (pngImage.m_width * bytesPerPixel));
}
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
fclose(fp);
return pngImage;
}
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, user_error_ptr, user_error_fn, user_warning_fn);
if (!png_ptr)
{
fclose(fp);
saveSettings.m_errorHandler("png_create_write_struct failed.");
return false;
}
bool PngImage::Save(const char* path, SaveSettings saveSettings)
{
if (!saveSettings.m_errorHandler)
{
saveSettings.m_errorHandler = [path](const char* message) { DefaultErrorHandler(AZStd::string::format("Could not save file '%s'. %s", path, message).c_str()); };
}
if (!IsValid())
{
saveSettings.m_errorHandler("This PngImage is invalid.");
return false;
}
// For documentation of this code, see http://www.libpng.org/pub/png/libpng-1.4.0-manual.pdf chapter 4
FILE* fp = NULL;
if (fopen_s(&fp, path, "wb") || !fp)
{
saveSettings.m_errorHandler("Failed to open file.");
return false;
}
png_voidp user_error_ptr = &saveSettings.m_errorHandler;
png_error_ptr user_error_fn = PngImage_user_error_fn;
png_error_ptr user_warning_fn = PngImage_user_warning_fn;
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, user_error_ptr, user_error_fn, user_warning_fn);
if (!png_ptr)
{
fclose(fp);
saveSettings.m_errorHandler("png_create_write_struct failed.");
return false;
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr)
{
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
fclose(fp);
saveSettings.m_errorHandler("png_destroy_write_struct failed.");
return false;
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr)
{
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
fclose(fp);
saveSettings.m_errorHandler("png_destroy_write_struct failed.");
return false;
}
#pragma warning(push)
#pragma warning(disable: 4611) // Disables "interaction between '_setjmp' and C++ object destruction is non-portable". See https://docs.microsoft.com/en-us/cpp/preprocessor/warning?view=msvc-160
if (setjmp(png_jmpbuf(png_ptr)))
{
png_destroy_write_struct(&png_ptr, &info_ptr);
fclose(fp);
// We don't report an error message here because the user_error_fn should have done that already.
return false;
}
if (setjmp(png_jmpbuf(png_ptr)))
{
png_destroy_write_struct(&png_ptr, &info_ptr);
fclose(fp);
// We don't report an error message here because the user_error_fn should have done that already.
return false;
}
#pragma warning(pop)
png_init_io(png_ptr, fp);
png_init_io(png_ptr, fp);
png_set_IHDR(png_ptr, info_ptr, m_width, m_height, m_bitDepth, m_colorType, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
png_set_compression_level(png_ptr, saveSettings.m_compressionLevel);
png_set_IHDR(png_ptr, info_ptr, m_width, m_height, m_bitDepth, m_colorType, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
const uint32_t bytesPerPixel = (m_bufferFormat == PngImage::Format::RGB) ? 3 : 4;
png_set_compression_level(png_ptr, saveSettings.m_compressionLevel);
AZStd::vector<uint8_t*> rows;
rows.reserve(m_height);
for (uint32_t i = 0; i < m_height; ++i)
{
rows.push_back(m_buffer.begin() + m_width * bytesPerPixel * i);
const uint32_t bytesPerPixel = (m_bufferFormat == PngFile::Format::RGB) ? 3 : 4;
AZStd::vector<uint8_t*> rows;
rows.reserve(m_height);
for (uint32_t i = 0; i < m_height; ++i)
{
rows.push_back(m_buffer.begin() + m_width * bytesPerPixel * i);
}
png_set_rows(png_ptr, info_ptr, rows.begin());
int transforms = PNG_TRANSFORM_IDENTITY;
if (saveSettings.m_stripAlpha && m_bufferFormat == PngFile::Format::RGBA)
{
transforms |= PNG_TRANSFORM_STRIP_FILLER_AFTER;
}
png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
png_destroy_write_struct(&png_ptr, &info_ptr);
fclose(fp);
return true;
}
png_set_rows(png_ptr, info_ptr, rows.begin());
int transforms = PNG_TRANSFORM_IDENTITY;
if (saveSettings.m_stripAlpha && m_bufferFormat == PngImage::Format::RGBA)
void PngFile::DefaultErrorHandler(const char* message)
{
transforms |= PNG_TRANSFORM_STRIP_FILLER_AFTER;
AZ_Error("PngFile", false, "%s", message);
}
png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
bool PngFile::IsValid() const
{
return
!m_buffer.empty() &&
m_width > 0 &&
m_height > 0 &&
m_bitDepth > 0;
}
png_destroy_write_struct(&png_ptr, &info_ptr);
fclose(fp);
AZStd::vector<uint8_t>&& PngFile::TakeBuffer()
{
return AZStd::move(m_buffer);
}
return true;
}
void PngImage::DefaultErrorHandler(const char* message)
{
AZ_Error("PngImage", false, "%s", message);
}
bool PngImage::IsValid() const
{
return
!m_buffer.empty() &&
m_width > 0 &&
m_height > 0 &&
m_bitDepth > 0;
}
AZStd::vector<uint8_t>&& PngImage::TakeBuffer()
{
return AZStd::move(m_buffer);
}
} // namespace Utils
}// namespace AZ