1cc1dc7a3Sopenharmony_ci// SPDX-License-Identifier: Apache-2.0 2cc1dc7a3Sopenharmony_ci// ---------------------------------------------------------------------------- 3cc1dc7a3Sopenharmony_ci// Copyright 2011-2023 Arm Limited 4cc1dc7a3Sopenharmony_ci// 5cc1dc7a3Sopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License"); you may not 6cc1dc7a3Sopenharmony_ci// use this file except in compliance with the License. You may obtain a copy 7cc1dc7a3Sopenharmony_ci// of the License at: 8cc1dc7a3Sopenharmony_ci// 9cc1dc7a3Sopenharmony_ci// http://www.apache.org/licenses/LICENSE-2.0 10cc1dc7a3Sopenharmony_ci// 11cc1dc7a3Sopenharmony_ci// Unless required by applicable law or agreed to in writing, software 12cc1dc7a3Sopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13cc1dc7a3Sopenharmony_ci// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14cc1dc7a3Sopenharmony_ci// License for the specific language governing permissions and limitations 15cc1dc7a3Sopenharmony_ci// under the License. 16cc1dc7a3Sopenharmony_ci// ---------------------------------------------------------------------------- 17cc1dc7a3Sopenharmony_ci 18cc1dc7a3Sopenharmony_ci/** 19cc1dc7a3Sopenharmony_ci * @brief Functions for building the implementation of stb_image and tinyexr. 20cc1dc7a3Sopenharmony_ci */ 21cc1dc7a3Sopenharmony_ci 22cc1dc7a3Sopenharmony_ci#include <cstdlib> 23cc1dc7a3Sopenharmony_ci#include <cstdio> 24cc1dc7a3Sopenharmony_ci#include <fstream> 25cc1dc7a3Sopenharmony_ci#include <vector> 26cc1dc7a3Sopenharmony_ci 27cc1dc7a3Sopenharmony_ci#include "astcenccli_internal.h" 28cc1dc7a3Sopenharmony_ci 29cc1dc7a3Sopenharmony_ci// Configure the STB image write library build. 30cc1dc7a3Sopenharmony_ci#define STB_IMAGE_IMPLEMENTATION 31cc1dc7a3Sopenharmony_ci#define STB_IMAGE_WRITE_IMPLEMENTATION 32cc1dc7a3Sopenharmony_ci#define STBI_NO_GIF 33cc1dc7a3Sopenharmony_ci#define STBI_NO_PIC 34cc1dc7a3Sopenharmony_ci#define STBI_NO_PNM 35cc1dc7a3Sopenharmony_ci#define STBI_NO_PNG 36cc1dc7a3Sopenharmony_ci#define STBI_NO_PSD 37cc1dc7a3Sopenharmony_ci 38cc1dc7a3Sopenharmony_ci// Configure the TinyEXR library build. 39cc1dc7a3Sopenharmony_ci#define TINYEXR_IMPLEMENTATION 40cc1dc7a3Sopenharmony_ci 41cc1dc7a3Sopenharmony_ci// Configure the Wuffs library build. 42cc1dc7a3Sopenharmony_ci#define WUFFS_IMPLEMENTATION 43cc1dc7a3Sopenharmony_ci#define WUFFS_CONFIG__MODULES 44cc1dc7a3Sopenharmony_ci#define WUFFS_CONFIG__MODULE__ADLER32 45cc1dc7a3Sopenharmony_ci#define WUFFS_CONFIG__MODULE__BASE 46cc1dc7a3Sopenharmony_ci#define WUFFS_CONFIG__MODULE__CRC32 47cc1dc7a3Sopenharmony_ci#define WUFFS_CONFIG__MODULE__DEFLATE 48cc1dc7a3Sopenharmony_ci#define WUFFS_CONFIG__MODULE__PNG 49cc1dc7a3Sopenharmony_ci#define WUFFS_CONFIG__MODULE__ZLIB 50cc1dc7a3Sopenharmony_ci#include "wuffs-v0.3.c" 51cc1dc7a3Sopenharmony_ci 52cc1dc7a3Sopenharmony_ci// For both libraries force asserts (which can be triggered by corrupt input 53cc1dc7a3Sopenharmony_ci// images) to be handled at runtime in release builds to avoid security issues. 54cc1dc7a3Sopenharmony_ci#define STBI_ASSERT(x) astcenc_runtime_assert(x) 55cc1dc7a3Sopenharmony_ci#define TEXR_ASSERT(x) astcenc_runtime_assert(x) 56cc1dc7a3Sopenharmony_ci 57cc1dc7a3Sopenharmony_ci/** 58cc1dc7a3Sopenharmony_ci * @brief Trap image load failures and convert into a runtime error. 59cc1dc7a3Sopenharmony_ci */ 60cc1dc7a3Sopenharmony_cistatic void astcenc_runtime_assert(bool condition) 61cc1dc7a3Sopenharmony_ci{ 62cc1dc7a3Sopenharmony_ci if (!condition) 63cc1dc7a3Sopenharmony_ci { 64cc1dc7a3Sopenharmony_ci print_error("ERROR: Corrupt input image\n"); 65cc1dc7a3Sopenharmony_ci exit(1); 66cc1dc7a3Sopenharmony_ci } 67cc1dc7a3Sopenharmony_ci} 68cc1dc7a3Sopenharmony_ci 69cc1dc7a3Sopenharmony_ci#include "stb_image.h" 70cc1dc7a3Sopenharmony_ci#include "stb_image_write.h" 71cc1dc7a3Sopenharmony_ci#include "tinyexr.h" 72cc1dc7a3Sopenharmony_ci 73cc1dc7a3Sopenharmony_ci/** 74cc1dc7a3Sopenharmony_ci * @brief Load an image using Wuffs to provide the loader. 75cc1dc7a3Sopenharmony_ci * 76cc1dc7a3Sopenharmony_ci * @param filename The name of the file to load. 77cc1dc7a3Sopenharmony_ci * @param y_flip Should the image be vertically flipped? 78cc1dc7a3Sopenharmony_ci * @param[out] is_hdr Is this an HDR image load? 79cc1dc7a3Sopenharmony_ci * @param[out] component_count The number of components in the data. 80cc1dc7a3Sopenharmony_ci * 81cc1dc7a3Sopenharmony_ci * @return The loaded image data in a canonical 4 channel format, or @c nullptr on error. 82cc1dc7a3Sopenharmony_ci */ 83cc1dc7a3Sopenharmony_ciastcenc_image* load_png_with_wuffs( 84cc1dc7a3Sopenharmony_ci const char* filename, 85cc1dc7a3Sopenharmony_ci bool y_flip, 86cc1dc7a3Sopenharmony_ci bool& is_hdr, 87cc1dc7a3Sopenharmony_ci unsigned int& component_count 88cc1dc7a3Sopenharmony_ci) { 89cc1dc7a3Sopenharmony_ci is_hdr = false; 90cc1dc7a3Sopenharmony_ci component_count = 4; 91cc1dc7a3Sopenharmony_ci 92cc1dc7a3Sopenharmony_ci std::ifstream file(filename, std::ios::binary | std::ios::ate); 93cc1dc7a3Sopenharmony_ci if (!file) 94cc1dc7a3Sopenharmony_ci { 95cc1dc7a3Sopenharmony_ci print_error("ERROR: Failed to load image %s (can't fopen)\n", filename); 96cc1dc7a3Sopenharmony_ci return nullptr; 97cc1dc7a3Sopenharmony_ci } 98cc1dc7a3Sopenharmony_ci 99cc1dc7a3Sopenharmony_ci std::streamsize size = file.tellg(); 100cc1dc7a3Sopenharmony_ci file.seekg(0, std::ios::beg); 101cc1dc7a3Sopenharmony_ci 102cc1dc7a3Sopenharmony_ci std::vector<uint8_t> buffer(size); 103cc1dc7a3Sopenharmony_ci file.read((char*)buffer.data(), size); 104cc1dc7a3Sopenharmony_ci 105cc1dc7a3Sopenharmony_ci wuffs_png__decoder *dec = wuffs_png__decoder__alloc(); 106cc1dc7a3Sopenharmony_ci if (!dec) 107cc1dc7a3Sopenharmony_ci { 108cc1dc7a3Sopenharmony_ci return nullptr; 109cc1dc7a3Sopenharmony_ci } 110cc1dc7a3Sopenharmony_ci 111cc1dc7a3Sopenharmony_ci wuffs_base__image_config ic; 112cc1dc7a3Sopenharmony_ci wuffs_base__io_buffer src = wuffs_base__ptr_u8__reader(buffer.data(), size, true); 113cc1dc7a3Sopenharmony_ci wuffs_base__status status = wuffs_png__decoder__decode_image_config(dec, &ic, &src); 114cc1dc7a3Sopenharmony_ci if (status.repr) 115cc1dc7a3Sopenharmony_ci { 116cc1dc7a3Sopenharmony_ci return nullptr; 117cc1dc7a3Sopenharmony_ci } 118cc1dc7a3Sopenharmony_ci 119cc1dc7a3Sopenharmony_ci uint32_t dim_x = wuffs_base__pixel_config__width(&ic.pixcfg); 120cc1dc7a3Sopenharmony_ci uint32_t dim_y = wuffs_base__pixel_config__height(&ic.pixcfg); 121cc1dc7a3Sopenharmony_ci size_t num_pixels = dim_x * dim_y; 122cc1dc7a3Sopenharmony_ci if (num_pixels > (SIZE_MAX / 4)) 123cc1dc7a3Sopenharmony_ci { 124cc1dc7a3Sopenharmony_ci return nullptr; 125cc1dc7a3Sopenharmony_ci } 126cc1dc7a3Sopenharmony_ci 127cc1dc7a3Sopenharmony_ci // Override the image's native pixel format to be RGBA_NONPREMUL 128cc1dc7a3Sopenharmony_ci wuffs_base__pixel_config__set( 129cc1dc7a3Sopenharmony_ci &ic.pixcfg, 130cc1dc7a3Sopenharmony_ci WUFFS_BASE__PIXEL_FORMAT__RGBA_NONPREMUL, 131cc1dc7a3Sopenharmony_ci WUFFS_BASE__PIXEL_SUBSAMPLING__NONE, 132cc1dc7a3Sopenharmony_ci dim_x, dim_y); 133cc1dc7a3Sopenharmony_ci 134cc1dc7a3Sopenharmony_ci // Configure the work buffer 135cc1dc7a3Sopenharmony_ci size_t workbuf_len = wuffs_png__decoder__workbuf_len(dec).max_incl; 136cc1dc7a3Sopenharmony_ci if (workbuf_len > SIZE_MAX) 137cc1dc7a3Sopenharmony_ci { 138cc1dc7a3Sopenharmony_ci return nullptr; 139cc1dc7a3Sopenharmony_ci } 140cc1dc7a3Sopenharmony_ci 141cc1dc7a3Sopenharmony_ci wuffs_base__slice_u8 workbuf_slice = wuffs_base__make_slice_u8((uint8_t*)malloc(workbuf_len), workbuf_len); 142cc1dc7a3Sopenharmony_ci if (!workbuf_slice.ptr) 143cc1dc7a3Sopenharmony_ci { 144cc1dc7a3Sopenharmony_ci return nullptr; 145cc1dc7a3Sopenharmony_ci } 146cc1dc7a3Sopenharmony_ci 147cc1dc7a3Sopenharmony_ci wuffs_base__slice_u8 pixbuf_slice = wuffs_base__make_slice_u8((uint8_t*)malloc(num_pixels * 4), num_pixels * 4); 148cc1dc7a3Sopenharmony_ci if (!pixbuf_slice.ptr) 149cc1dc7a3Sopenharmony_ci { 150cc1dc7a3Sopenharmony_ci return nullptr; 151cc1dc7a3Sopenharmony_ci } 152cc1dc7a3Sopenharmony_ci 153cc1dc7a3Sopenharmony_ci wuffs_base__pixel_buffer pb; 154cc1dc7a3Sopenharmony_ci status = wuffs_base__pixel_buffer__set_from_slice(&pb, &ic.pixcfg, pixbuf_slice); 155cc1dc7a3Sopenharmony_ci if (status.repr) 156cc1dc7a3Sopenharmony_ci { 157cc1dc7a3Sopenharmony_ci return nullptr; 158cc1dc7a3Sopenharmony_ci } 159cc1dc7a3Sopenharmony_ci 160cc1dc7a3Sopenharmony_ci // Decode the pixels 161cc1dc7a3Sopenharmony_ci status = wuffs_png__decoder__decode_frame(dec, &pb, &src, WUFFS_BASE__PIXEL_BLEND__SRC, workbuf_slice, NULL); 162cc1dc7a3Sopenharmony_ci if (status.repr) 163cc1dc7a3Sopenharmony_ci { 164cc1dc7a3Sopenharmony_ci return nullptr; 165cc1dc7a3Sopenharmony_ci } 166cc1dc7a3Sopenharmony_ci 167cc1dc7a3Sopenharmony_ci astcenc_image* img = astc_img_from_unorm8x4_array(pixbuf_slice.ptr, dim_x, dim_y, y_flip); 168cc1dc7a3Sopenharmony_ci 169cc1dc7a3Sopenharmony_ci free(pixbuf_slice.ptr); 170cc1dc7a3Sopenharmony_ci free(workbuf_slice.ptr); 171cc1dc7a3Sopenharmony_ci free(dec); 172cc1dc7a3Sopenharmony_ci 173cc1dc7a3Sopenharmony_ci return img; 174cc1dc7a3Sopenharmony_ci} 175