1cc1dc7a3Sopenharmony_ci// SPDX-License-Identifier: Apache-2.0 2cc1dc7a3Sopenharmony_ci// ---------------------------------------------------------------------------- 3cc1dc7a3Sopenharmony_ci// Copyright 2021 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// This is a minimal example of using the astcenc library. 19cc1dc7a3Sopenharmony_ci// 20cc1dc7a3Sopenharmony_ci// This sample shows how to include the astcenc library in your CMake project 21cc1dc7a3Sopenharmony_ci// as an external dependency, and how to compress and decompress images using 22cc1dc7a3Sopenharmony_ci// the C library API. 23cc1dc7a3Sopenharmony_ci// 24cc1dc7a3Sopenharmony_ci// For sake of clarity the command line exposed by the sample is minimalistic, 25cc1dc7a3Sopenharmony_ci// and the compression uses a fixed set of options, but the code is commented 26cc1dc7a3Sopenharmony_ci// to indicate where extension would be possible. Errors handling points are 27cc1dc7a3Sopenharmony_ci// detected and logged, but resources are not cleaned up on error paths to keep 28cc1dc7a3Sopenharmony_ci// the sample control path simple, so resources will leak on error. 29cc1dc7a3Sopenharmony_ci 30cc1dc7a3Sopenharmony_ci#include <stdio.h> 31cc1dc7a3Sopenharmony_ci 32cc1dc7a3Sopenharmony_ci#include "astcenc.h" 33cc1dc7a3Sopenharmony_ci 34cc1dc7a3Sopenharmony_ci#define STB_IMAGE_IMPLEMENTATION 35cc1dc7a3Sopenharmony_ci#include "stb_image.h" 36cc1dc7a3Sopenharmony_ci 37cc1dc7a3Sopenharmony_ci#define STB_IMAGE_WRITE_IMPLEMENTATION 38cc1dc7a3Sopenharmony_ci#include "stb_image_write.h" 39cc1dc7a3Sopenharmony_ci 40cc1dc7a3Sopenharmony_ciint main(int argc, char **argv) 41cc1dc7a3Sopenharmony_ci{ 42cc1dc7a3Sopenharmony_ci // Parse command line 43cc1dc7a3Sopenharmony_ci if (argc != 3) 44cc1dc7a3Sopenharmony_ci { 45cc1dc7a3Sopenharmony_ci printf("Usage:\n" 46cc1dc7a3Sopenharmony_ci " %s <source> <dest>\n\n" 47cc1dc7a3Sopenharmony_ci " <source> : Uncompressed LDR source image.\n" 48cc1dc7a3Sopenharmony_ci " <dest> : Uncompressed LDR destination image (png).\n" 49cc1dc7a3Sopenharmony_ci , argv[0]); 50cc1dc7a3Sopenharmony_ci return 1; 51cc1dc7a3Sopenharmony_ci } 52cc1dc7a3Sopenharmony_ci 53cc1dc7a3Sopenharmony_ci // ------------------------------------------------------------------------ 54cc1dc7a3Sopenharmony_ci // For the purposes of this sample we hard-code the compressor settings 55cc1dc7a3Sopenharmony_ci static const unsigned int thread_count = 1; 56cc1dc7a3Sopenharmony_ci static const unsigned int block_x = 6; 57cc1dc7a3Sopenharmony_ci static const unsigned int block_y = 6; 58cc1dc7a3Sopenharmony_ci static const unsigned int block_z = 1; 59cc1dc7a3Sopenharmony_ci static const astcenc_profile profile = ASTCENC_PRF_LDR; 60cc1dc7a3Sopenharmony_ci static const float quality = ASTCENC_PRE_MEDIUM; 61cc1dc7a3Sopenharmony_ci static const astcenc_swizzle swizzle { 62cc1dc7a3Sopenharmony_ci ASTCENC_SWZ_R, ASTCENC_SWZ_G, ASTCENC_SWZ_B, ASTCENC_SWZ_A 63cc1dc7a3Sopenharmony_ci }; 64cc1dc7a3Sopenharmony_ci 65cc1dc7a3Sopenharmony_ci // ------------------------------------------------------------------------ 66cc1dc7a3Sopenharmony_ci // Load input image, forcing 4 components 67cc1dc7a3Sopenharmony_ci int image_x, image_y, image_c; 68cc1dc7a3Sopenharmony_ci uint8_t *image_data = (uint8_t*)stbi_load(argv[1], &image_x, &image_y, &image_c, 4); 69cc1dc7a3Sopenharmony_ci if (!image_data) 70cc1dc7a3Sopenharmony_ci { 71cc1dc7a3Sopenharmony_ci printf("Failed to load image \"%s\"\n", argv[1]); 72cc1dc7a3Sopenharmony_ci return 1; 73cc1dc7a3Sopenharmony_ci } 74cc1dc7a3Sopenharmony_ci 75cc1dc7a3Sopenharmony_ci // Compute the number of ASTC blocks in each dimension 76cc1dc7a3Sopenharmony_ci unsigned int block_count_x = (image_x + block_x - 1) / block_x; 77cc1dc7a3Sopenharmony_ci unsigned int block_count_y = (image_y + block_y - 1) / block_y; 78cc1dc7a3Sopenharmony_ci 79cc1dc7a3Sopenharmony_ci // ------------------------------------------------------------------------ 80cc1dc7a3Sopenharmony_ci // Initialize the default configuration for the block size and quality 81cc1dc7a3Sopenharmony_ci astcenc_config config; 82cc1dc7a3Sopenharmony_ci config.block_x = block_x; 83cc1dc7a3Sopenharmony_ci config.block_y = block_y; 84cc1dc7a3Sopenharmony_ci config.profile = profile; 85cc1dc7a3Sopenharmony_ci 86cc1dc7a3Sopenharmony_ci astcenc_error status; 87cc1dc7a3Sopenharmony_ci status = astcenc_config_init(profile, block_x, block_y, block_z, quality, 0, &config); 88cc1dc7a3Sopenharmony_ci if (status != ASTCENC_SUCCESS) 89cc1dc7a3Sopenharmony_ci { 90cc1dc7a3Sopenharmony_ci printf("ERROR: Codec config init failed: %s\n", astcenc_get_error_string(status)); 91cc1dc7a3Sopenharmony_ci return 1; 92cc1dc7a3Sopenharmony_ci } 93cc1dc7a3Sopenharmony_ci 94cc1dc7a3Sopenharmony_ci // ... power users can customize any config settings after calling 95cc1dc7a3Sopenharmony_ci // config_init() and before calling context alloc(). 96cc1dc7a3Sopenharmony_ci 97cc1dc7a3Sopenharmony_ci // ------------------------------------------------------------------------ 98cc1dc7a3Sopenharmony_ci // Create a context based on the configuration 99cc1dc7a3Sopenharmony_ci astcenc_context* context; 100cc1dc7a3Sopenharmony_ci status = astcenc_context_alloc(&config, thread_count, &context); 101cc1dc7a3Sopenharmony_ci if (status != ASTCENC_SUCCESS) 102cc1dc7a3Sopenharmony_ci { 103cc1dc7a3Sopenharmony_ci printf("ERROR: Codec context alloc failed: %s\n", astcenc_get_error_string(status)); 104cc1dc7a3Sopenharmony_ci return 1; 105cc1dc7a3Sopenharmony_ci } 106cc1dc7a3Sopenharmony_ci 107cc1dc7a3Sopenharmony_ci // ------------------------------------------------------------------------ 108cc1dc7a3Sopenharmony_ci // Compress the image 109cc1dc7a3Sopenharmony_ci astcenc_image image; 110cc1dc7a3Sopenharmony_ci image.dim_x = image_x; 111cc1dc7a3Sopenharmony_ci image.dim_y = image_y; 112cc1dc7a3Sopenharmony_ci image.dim_z = 1; 113cc1dc7a3Sopenharmony_ci image.data_type = ASTCENC_TYPE_U8; 114cc1dc7a3Sopenharmony_ci uint8_t* slices = image_data; 115cc1dc7a3Sopenharmony_ci image.data = reinterpret_cast<void**>(&slices); 116cc1dc7a3Sopenharmony_ci 117cc1dc7a3Sopenharmony_ci // Space needed for 16 bytes of output per compressed block 118cc1dc7a3Sopenharmony_ci size_t comp_len = block_count_x * block_count_y * 16; 119cc1dc7a3Sopenharmony_ci uint8_t* comp_data = new uint8_t[comp_len]; 120cc1dc7a3Sopenharmony_ci 121cc1dc7a3Sopenharmony_ci status = astcenc_compress_image(context, &image, &swizzle, comp_data, comp_len, 0); 122cc1dc7a3Sopenharmony_ci if (status != ASTCENC_SUCCESS) 123cc1dc7a3Sopenharmony_ci { 124cc1dc7a3Sopenharmony_ci printf("ERROR: Codec compress failed: %s\n", astcenc_get_error_string(status)); 125cc1dc7a3Sopenharmony_ci return 1; 126cc1dc7a3Sopenharmony_ci } 127cc1dc7a3Sopenharmony_ci 128cc1dc7a3Sopenharmony_ci // ... the comp_data array contains the raw compressed data you would pass 129cc1dc7a3Sopenharmony_ci // to the graphics API, or pack into a wrapper format such as a KTX file. 130cc1dc7a3Sopenharmony_ci 131cc1dc7a3Sopenharmony_ci // If using multithreaded compression to sequentially compress multiple 132cc1dc7a3Sopenharmony_ci // images you should reuse the same context, calling the function 133cc1dc7a3Sopenharmony_ci // astcenc_compress_reset() between each image in the series. 134cc1dc7a3Sopenharmony_ci 135cc1dc7a3Sopenharmony_ci // ------------------------------------------------------------------------ 136cc1dc7a3Sopenharmony_ci // Decompress the image 137cc1dc7a3Sopenharmony_ci // Note we just reuse the image structure to store the output here ... 138cc1dc7a3Sopenharmony_ci status = astcenc_decompress_image(context, comp_data, comp_len, &image, &swizzle, 0); 139cc1dc7a3Sopenharmony_ci if (status != ASTCENC_SUCCESS) 140cc1dc7a3Sopenharmony_ci { 141cc1dc7a3Sopenharmony_ci printf("ERROR: Codec decompress failed: %s\n", astcenc_get_error_string(status)); 142cc1dc7a3Sopenharmony_ci return 1; 143cc1dc7a3Sopenharmony_ci } 144cc1dc7a3Sopenharmony_ci 145cc1dc7a3Sopenharmony_ci // If using multithreaded decompression to sequentially decompress multiple 146cc1dc7a3Sopenharmony_ci // images you should reuse the same context, calling the function 147cc1dc7a3Sopenharmony_ci // astcenc_decompress_reset() between each image in the series. 148cc1dc7a3Sopenharmony_ci 149cc1dc7a3Sopenharmony_ci // ------------------------------------------------------------------------ 150cc1dc7a3Sopenharmony_ci // Store the result back to disk 151cc1dc7a3Sopenharmony_ci stbi_write_png(argv[2], image_x, image_y, 4, image_data, 4 * image_x); 152cc1dc7a3Sopenharmony_ci 153cc1dc7a3Sopenharmony_ci // ------------------------------------------------------------------------ 154cc1dc7a3Sopenharmony_ci // Cleanup library resources 155cc1dc7a3Sopenharmony_ci stbi_image_free(image_data); 156cc1dc7a3Sopenharmony_ci astcenc_context_free(context); 157cc1dc7a3Sopenharmony_ci delete[] comp_data; 158cc1dc7a3Sopenharmony_ci 159cc1dc7a3Sopenharmony_ci return 0; 160cc1dc7a3Sopenharmony_ci} 161