/* SPDX-FileCopyrightText: 2023 Blender Authors * * SPDX-License-Identifier: GPL-2.0-or-later */ /** \file * \ingroup imbuf */ #include "oiio/openimageio_support.hh" #include "IMB_colormanagement.h" #include "IMB_filetype.h" #include "IMB_imbuf_types.h" OIIO_NAMESPACE_USING using namespace blender::imbuf; extern "C" { bool imb_is_a_png(const uchar *mem, size_t size) { const char signature[] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A}; if (size < sizeof(signature)) { return false; } return memcmp(signature, mem, sizeof(signature)) == 0; } ImBuf *imb_load_png(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE]) { ImageSpec config, spec; config.attribute("oiio:UnassociatedAlpha", 1); ReadContext ctx{mem, size, "png", IMB_FTYPE_PNG, flags}; /* Both 8 and 16 bit PNGs should be in default byte colorspace. */ ctx.use_colorspace_role = COLOR_ROLE_DEFAULT_BYTE; ImBuf *ibuf = imb_oiio_read(ctx, config, colorspace, spec); if (ibuf) { if (spec.format == TypeDesc::UINT16) { ibuf->flags |= PNG_16BIT; } } return ibuf; } bool imb_save_png(ImBuf *ibuf, const char *filepath, int flags) { const bool is_16bit = (ibuf->foptions.flag & PNG_16BIT); const int file_channels = ibuf->planes >> 3; const TypeDesc data_format = is_16bit ? TypeDesc::UINT16 : TypeDesc::UINT8; WriteContext ctx = imb_create_write_context("png", ibuf, flags, is_16bit); ImageSpec file_spec = imb_create_write_spec(ctx, file_channels, data_format); /* Skip if the float buffer was managed already. */ if (is_16bit && (ibuf->float_buffer.colorspace || (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA))) { file_spec.attribute("oiio:UnassociatedAlpha", 0); } else { file_spec.attribute("oiio:UnassociatedAlpha", 1); } int compression = int(float(ibuf->foptions.quality) / 11.1111f); compression = compression < 0 ? 0 : (compression > 9 ? 9 : compression); file_spec.attribute("png:compressionLevel", compression); return imb_oiio_write(ctx, filepath, file_spec); } }