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