RADRT_API bool RADRT_CALL Decode(const void *buff, AddrSize buffLength, Image &out) { RAD_ASSERT(buff&&buffLength); RAD_ASSERT(buffLength <= std::numeric_limits<stream::SPos>::max()); out.Free(); stream::MemInputBuffer ib(buff, (stream::SPos)buffLength); stream::InputStream is(ib); { char sig[SigSize]; if (is.Read(sig, SigSize, 0) != SigSize) return false; // NOTE: png_sig_cmp() returns 0 if the sig matches the PNG sig. if (png_sig_cmp((png_bytep)sig, 0, SigSize)) return false; } png_structp png; png_infop info; png = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, 0, PNGErrorHandler, PNGWarningHandler, 0, PNGMalloc, PNGFree); if (!png) return false; info = png_create_info_struct(png); if (!info) { png_destroy_read_struct(&png, 0, 0); return false; } png_set_read_fn(png, &is, PNGRead); png_set_sig_bytes(png, SigSize); try { png_uint_32 w, h; int bd, color, interlace; png_read_info(png, info); png_get_IHDR(png, info, &w, &h, &bd, &color, &interlace, 0, 0); if (!out.AllocateFrames(1)||!out.AllocateMipmaps(0, 1)) { png_destroy_read_struct(&png, &info, 0); return false; } Mipmap &m = out.frames[0].mipmaps[0]; out.format = Format(png, info, bd, color); if (out.format == InvalidFormat) { out.Free(); png_destroy_read_struct(&png, &info, 0); return false; } out.bpp = FormatBPP(out.format); if (!out.AllocateMipmap(0, 0, w, h, w * out.bpp, w * h * out.bpp)) { out.Free(); png_destroy_read_struct(&png, &info, 0); return false; } png_set_strip_16(png); if (color == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png); } if (color == PNG_COLOR_TYPE_GRAY && bd < 8) { png_set_expand_gray_1_2_4_to_8(png); } if (png_get_valid(png, info, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png); } png_set_swap(png); int passes = png_set_interlace_handling(png); png_bytep dstRow = 0; png_bytep imgRow = 0; png_uint_32 stride = (png_uint_32)png_get_rowbytes(png, info); RAD_ASSERT(stride >= m.stride); if (stride != m.stride) { dstRow = (png_bytep)safe_zone_malloc(ZImageCodec, stride, 0); } for (int pass = 0; pass < passes; ++pass) { if (stride == m.stride) { dstRow = (png_bytep)m.data; // reset. } imgRow = (png_bytep)m.data; for (png_uint_32 y = 0; y < h; ++y) { if (pass > 0 && stride != m.stride) { RAD_ASSERT(imgRow != dstRow); // interlaced image, copy the result of the last pass. memcpy(dstRow, imgRow, m.stride); } png_read_rows(png, &dstRow, 0, 1); if (stride != m.stride) { // imgRow/dstRow are correct, we are copying from dstRow to imgRow. memcpy(imgRow, dstRow, m.stride); } else { dstRow += m.stride; } imgRow += m.stride; } } if (stride != m.stride) { RAD_ASSERT(dstRow); zone_free(dstRow); } png_read_end(png, info); } catch (PNGException&) { out.Free(); png_destroy_read_struct(&png, &info, 0); return false; } png_destroy_read_struct(&png, &info, 0); return true; }
RADRT_API bool RADRT_CALL DecodeHeader(const void *buff, AddrSize buffLength, Image &out) { RAD_ASSERT(buff&&buffLength); RAD_ASSERT(buffLength <= std::numeric_limits<stream::SPos>::max()); out.Free(); stream::MemInputBuffer ib(buff, (stream::SPos)buffLength); stream::InputStream is(ib); { char sig[SigSize]; if (is.Read(sig, SigSize, 0) != SigSize) return false; // NOTE: png_sig_cmp() returns 0 if the sig matches the PNG sig. if (png_sig_cmp((png_bytep)sig, 0, SigSize)) return false; } png_structp png; png_infop info; png = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, 0, PNGErrorHandler, PNGWarningHandler, 0, PNGMalloc, PNGFree); if (!png) return false; info = png_create_info_struct(png); if (!info) { png_destroy_read_struct(&png, 0, 0); return false; } png_set_read_fn(png, &is, PNGRead); png_set_sig_bytes(png, SigSize); try { png_uint_32 w, h; int bd, color, interlace; png_read_info(png, info); png_get_IHDR(png, info, &w, &h, &bd, &color, &interlace, 0, 0); if (!out.AllocateFrames(1)||!out.AllocateMipmaps(0, 1)) return false; Mipmap &m = out.frames[0].mipmaps[0]; out.format = Format(png, info, bd, color); if (out.format == InvalidFormat) { out.Free(); png_destroy_read_struct(&png, &info, 0); return false; } out.bpp = FormatBPP(out.format); m.width = w; m.height = h; m.stride = w * out.bpp; } catch (PNGException&) { out.Free(); png_destroy_read_struct(&png, &info, 0); return false; } png_destroy_read_struct(&png, &info, 0); return true; }