1e5c31af7Sopenharmony_ci/*-------------------------------------------------------------------------
2e5c31af7Sopenharmony_ci * drawElements Quality Program Tester Core
3e5c31af7Sopenharmony_ci * ----------------------------------------
4e5c31af7Sopenharmony_ci *
5e5c31af7Sopenharmony_ci * Copyright 2014 The Android Open Source Project
6e5c31af7Sopenharmony_ci *
7e5c31af7Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
8e5c31af7Sopenharmony_ci * you may not use this file except in compliance with the License.
9e5c31af7Sopenharmony_ci * You may obtain a copy of the License at
10e5c31af7Sopenharmony_ci *
11e5c31af7Sopenharmony_ci *      http://www.apache.org/licenses/LICENSE-2.0
12e5c31af7Sopenharmony_ci *
13e5c31af7Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
14e5c31af7Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
15e5c31af7Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16e5c31af7Sopenharmony_ci * See the License for the specific language governing permissions and
17e5c31af7Sopenharmony_ci * limitations under the License.
18e5c31af7Sopenharmony_ci *
19e5c31af7Sopenharmony_ci *//*!
20e5c31af7Sopenharmony_ci * \file
21e5c31af7Sopenharmony_ci * \brief Image IO.
22e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/
23e5c31af7Sopenharmony_ci
24e5c31af7Sopenharmony_ci#include "tcuImageIO.hpp"
25e5c31af7Sopenharmony_ci#include "tcuResource.hpp"
26e5c31af7Sopenharmony_ci#include "tcuSurface.hpp"
27e5c31af7Sopenharmony_ci#include "tcuCompressedTexture.hpp"
28e5c31af7Sopenharmony_ci#include "deFilePath.hpp"
29e5c31af7Sopenharmony_ci#include "deUniquePtr.hpp"
30e5c31af7Sopenharmony_ci
31e5c31af7Sopenharmony_ci#include <string>
32e5c31af7Sopenharmony_ci#include <vector>
33e5c31af7Sopenharmony_ci#include <cstdio>
34e5c31af7Sopenharmony_ci
35e5c31af7Sopenharmony_ci#include "png.h"
36e5c31af7Sopenharmony_ci
37e5c31af7Sopenharmony_cinamespace tcu
38e5c31af7Sopenharmony_ci{
39e5c31af7Sopenharmony_cinamespace ImageIO
40e5c31af7Sopenharmony_ci{
41e5c31af7Sopenharmony_ci
42e5c31af7Sopenharmony_ciusing std::string;
43e5c31af7Sopenharmony_ciusing std::vector;
44e5c31af7Sopenharmony_ci
45e5c31af7Sopenharmony_ci/*--------------------------------------------------------------------*//*!
46e5c31af7Sopenharmony_ci * \brief Load image from resource
47e5c31af7Sopenharmony_ci *
48e5c31af7Sopenharmony_ci * TextureLevel storage is set to match image data. Only PNG format is
49e5c31af7Sopenharmony_ci * currently supported.
50e5c31af7Sopenharmony_ci *
51e5c31af7Sopenharmony_ci * \param dst		Destination pixel container
52e5c31af7Sopenharmony_ci * \param archive	Resource archive
53e5c31af7Sopenharmony_ci * \param fileName	Resource file name
54e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/
55e5c31af7Sopenharmony_civoid loadImage (TextureLevel& dst, const tcu::Archive& archive, const char* fileName)
56e5c31af7Sopenharmony_ci{
57e5c31af7Sopenharmony_ci	string ext = de::FilePath(fileName).getFileExtension();
58e5c31af7Sopenharmony_ci
59e5c31af7Sopenharmony_ci	if (ext == "png" || ext == "PNG")
60e5c31af7Sopenharmony_ci		loadPNG(dst, archive, fileName);
61e5c31af7Sopenharmony_ci	else
62e5c31af7Sopenharmony_ci		throw InternalError("Unrecognized image file extension", fileName, __FILE__, __LINE__);
63e5c31af7Sopenharmony_ci}
64e5c31af7Sopenharmony_ci
65e5c31af7Sopenharmony_ciDE_BEGIN_EXTERN_C
66e5c31af7Sopenharmony_cistatic void pngReadResource (png_structp png_ptr, png_bytep data, png_size_t length)
67e5c31af7Sopenharmony_ci{
68e5c31af7Sopenharmony_ci	tcu::Resource* resource = (tcu::Resource*)png_get_io_ptr(png_ptr);
69e5c31af7Sopenharmony_ci	resource->read(data, (int)length);
70e5c31af7Sopenharmony_ci}
71e5c31af7Sopenharmony_ciDE_END_EXTERN_C
72e5c31af7Sopenharmony_ci
73e5c31af7Sopenharmony_ci/*--------------------------------------------------------------------*//*!
74e5c31af7Sopenharmony_ci * \brief Load PNG image from resource
75e5c31af7Sopenharmony_ci *
76e5c31af7Sopenharmony_ci * TextureLevel storage is set to match image data.
77e5c31af7Sopenharmony_ci *
78e5c31af7Sopenharmony_ci * \param dst		Destination pixel container
79e5c31af7Sopenharmony_ci * \param archive	Resource archive
80e5c31af7Sopenharmony_ci * \param fileName	Resource file name
81e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/
82e5c31af7Sopenharmony_civoid loadPNG (TextureLevel& dst, const tcu::Archive& archive, const char* fileName)
83e5c31af7Sopenharmony_ci{
84e5c31af7Sopenharmony_ci	de::UniquePtr<Resource> resource(archive.getResource(fileName));
85e5c31af7Sopenharmony_ci
86e5c31af7Sopenharmony_ci	// Verify header.
87e5c31af7Sopenharmony_ci	deUint8 header[8];
88e5c31af7Sopenharmony_ci	resource->read(header, sizeof(header));
89e5c31af7Sopenharmony_ci	TCU_CHECK(png_sig_cmp((png_bytep)&header[0], 0, DE_LENGTH_OF_ARRAY(header)) == 0);
90e5c31af7Sopenharmony_ci
91e5c31af7Sopenharmony_ci	png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, DE_NULL, DE_NULL, DE_NULL);
92e5c31af7Sopenharmony_ci	TCU_CHECK(png_ptr);
93e5c31af7Sopenharmony_ci
94e5c31af7Sopenharmony_ci	png_infop info_ptr = png_create_info_struct(png_ptr);
95e5c31af7Sopenharmony_ci	TCU_CHECK(info_ptr);
96e5c31af7Sopenharmony_ci
97e5c31af7Sopenharmony_ci	if (setjmp(png_jmpbuf(png_ptr)))
98e5c31af7Sopenharmony_ci		throw InternalError("An error occured when loading PNG", fileName, __FILE__, __LINE__);
99e5c31af7Sopenharmony_ci
100e5c31af7Sopenharmony_ci	png_set_read_fn(png_ptr, resource.get(), pngReadResource);
101e5c31af7Sopenharmony_ci	png_set_sig_bytes(png_ptr, 8);
102e5c31af7Sopenharmony_ci
103e5c31af7Sopenharmony_ci	png_read_info(png_ptr, info_ptr);
104e5c31af7Sopenharmony_ci
105e5c31af7Sopenharmony_ci	const deUint32	width			= (deUint32)png_get_image_width(png_ptr, info_ptr);
106e5c31af7Sopenharmony_ci	const deUint32	height			= (deUint32)png_get_image_height(png_ptr, info_ptr);
107e5c31af7Sopenharmony_ci	TextureFormat	textureFormat;
108e5c31af7Sopenharmony_ci
109e5c31af7Sopenharmony_ci	{
110e5c31af7Sopenharmony_ci		const png_byte	colorType	= png_get_color_type(png_ptr, info_ptr);
111e5c31af7Sopenharmony_ci		const png_byte	bitDepth	= png_get_bit_depth(png_ptr, info_ptr);
112e5c31af7Sopenharmony_ci
113e5c31af7Sopenharmony_ci		if (colorType == PNG_COLOR_TYPE_RGB && bitDepth == 8)
114e5c31af7Sopenharmony_ci			textureFormat = TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8);
115e5c31af7Sopenharmony_ci		else if (colorType == PNG_COLOR_TYPE_RGBA && bitDepth == 8)
116e5c31af7Sopenharmony_ci			textureFormat = TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8);
117e5c31af7Sopenharmony_ci		else
118e5c31af7Sopenharmony_ci			throw InternalError("Unsupported PNG depth or color type", fileName, __FILE__, __LINE__);
119e5c31af7Sopenharmony_ci	}
120e5c31af7Sopenharmony_ci
121e5c31af7Sopenharmony_ci	// Resize destination texture.
122e5c31af7Sopenharmony_ci	dst.setStorage(textureFormat, width, height);
123e5c31af7Sopenharmony_ci
124e5c31af7Sopenharmony_ci	std::vector<png_bytep> row_pointers;
125e5c31af7Sopenharmony_ci	row_pointers.resize(height);
126e5c31af7Sopenharmony_ci	for (deUint32 y = 0; y < height; y++)
127e5c31af7Sopenharmony_ci		row_pointers[y] = (deUint8*)dst.getAccess().getDataPtr() + y*dst.getAccess().getRowPitch();
128e5c31af7Sopenharmony_ci
129e5c31af7Sopenharmony_ci	png_read_image(png_ptr, &row_pointers[0]);
130e5c31af7Sopenharmony_ci
131e5c31af7Sopenharmony_ci	png_destroy_info_struct(png_ptr, &info_ptr);
132e5c31af7Sopenharmony_ci	png_destroy_read_struct(&png_ptr, DE_NULL, DE_NULL);
133e5c31af7Sopenharmony_ci}
134e5c31af7Sopenharmony_ci
135e5c31af7Sopenharmony_cistatic int textureFormatToPNGFormat (const TextureFormat& format)
136e5c31af7Sopenharmony_ci{
137e5c31af7Sopenharmony_ci	if (format == TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8))
138e5c31af7Sopenharmony_ci		return PNG_COLOR_TYPE_RGB;
139e5c31af7Sopenharmony_ci	else if (format == TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
140e5c31af7Sopenharmony_ci		return PNG_COLOR_TYPE_RGBA;
141e5c31af7Sopenharmony_ci	else
142e5c31af7Sopenharmony_ci		throw InternalError("Unsupported texture format", DE_NULL, __FILE__, __LINE__);
143e5c31af7Sopenharmony_ci}
144e5c31af7Sopenharmony_ci
145e5c31af7Sopenharmony_ci/*--------------------------------------------------------------------*//*!
146e5c31af7Sopenharmony_ci * \brief Write image to file in PNG format
147e5c31af7Sopenharmony_ci *
148e5c31af7Sopenharmony_ci * This is provided for debugging and development purposes. Test code must
149e5c31af7Sopenharmony_ci * not write to any files except the test log by default.
150e5c31af7Sopenharmony_ci *
151e5c31af7Sopenharmony_ci * \note Only RGB/RGBA, UNORM_INT8 formats are supported
152e5c31af7Sopenharmony_ci * \param src		Source pixel data
153e5c31af7Sopenharmony_ci * \param fileName	File name
154e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/
155e5c31af7Sopenharmony_civoid savePNG (const ConstPixelBufferAccess& src, const char* fileName)
156e5c31af7Sopenharmony_ci{
157e5c31af7Sopenharmony_ci	FILE*	fp			= fopen(fileName, "wb");
158e5c31af7Sopenharmony_ci	TCU_CHECK(fp);
159e5c31af7Sopenharmony_ci
160e5c31af7Sopenharmony_ci	png_structp pngPtr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
161e5c31af7Sopenharmony_ci
162e5c31af7Sopenharmony_ci	if (!pngPtr)
163e5c31af7Sopenharmony_ci	{
164e5c31af7Sopenharmony_ci		fclose(fp);
165e5c31af7Sopenharmony_ci		TCU_CHECK(pngPtr);
166e5c31af7Sopenharmony_ci	}
167e5c31af7Sopenharmony_ci
168e5c31af7Sopenharmony_ci	png_infop infoPtr = png_create_info_struct(pngPtr);
169e5c31af7Sopenharmony_ci	if (!infoPtr)
170e5c31af7Sopenharmony_ci	{
171e5c31af7Sopenharmony_ci		png_destroy_write_struct(&pngPtr, NULL);
172e5c31af7Sopenharmony_ci		TCU_CHECK(infoPtr);
173e5c31af7Sopenharmony_ci	}
174e5c31af7Sopenharmony_ci
175e5c31af7Sopenharmony_ci	if (setjmp(png_jmpbuf(pngPtr)))
176e5c31af7Sopenharmony_ci	{
177e5c31af7Sopenharmony_ci		png_destroy_write_struct(&pngPtr, &infoPtr);
178e5c31af7Sopenharmony_ci		fclose(fp);
179e5c31af7Sopenharmony_ci		throw tcu::InternalError("PNG compression failed");
180e5c31af7Sopenharmony_ci	}
181e5c31af7Sopenharmony_ci	else
182e5c31af7Sopenharmony_ci	{
183e5c31af7Sopenharmony_ci		int pngFormat = textureFormatToPNGFormat(src.getFormat());
184e5c31af7Sopenharmony_ci
185e5c31af7Sopenharmony_ci		png_init_io(pngPtr, fp);
186e5c31af7Sopenharmony_ci
187e5c31af7Sopenharmony_ci		// Header
188e5c31af7Sopenharmony_ci		png_set_IHDR(pngPtr, infoPtr, src.getWidth(), src.getHeight(), 8,
189e5c31af7Sopenharmony_ci					 pngFormat, PNG_INTERLACE_NONE,
190e5c31af7Sopenharmony_ci					 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
191e5c31af7Sopenharmony_ci		png_write_info(pngPtr, infoPtr);
192e5c31af7Sopenharmony_ci
193e5c31af7Sopenharmony_ci		std::vector<png_bytep> rowPointers(src.getHeight());
194e5c31af7Sopenharmony_ci		for (int y = 0; y < src.getHeight(); y++)
195e5c31af7Sopenharmony_ci			rowPointers[y] = (deUint8*)src.getDataPtr() + y*src.getRowPitch();
196e5c31af7Sopenharmony_ci
197e5c31af7Sopenharmony_ci		png_write_image(pngPtr, &rowPointers[0]);
198e5c31af7Sopenharmony_ci		png_write_end(pngPtr, NULL);
199e5c31af7Sopenharmony_ci
200e5c31af7Sopenharmony_ci		png_destroy_write_struct(&pngPtr, &infoPtr);
201e5c31af7Sopenharmony_ci		fclose(fp);
202e5c31af7Sopenharmony_ci	}
203e5c31af7Sopenharmony_ci}
204e5c31af7Sopenharmony_ci
205e5c31af7Sopenharmony_cienum PkmImageFormat
206e5c31af7Sopenharmony_ci{
207e5c31af7Sopenharmony_ci	ETC1_RGB_NO_MIPMAPS		= 0,
208e5c31af7Sopenharmony_ci	ETC1_RGBA_NO_MIPMAPS	= 1,
209e5c31af7Sopenharmony_ci	ETC1_RGB_MIPMAPS		= 2,
210e5c31af7Sopenharmony_ci	ETC1_RGBA_MIPMAPS		= 3
211e5c31af7Sopenharmony_ci};
212e5c31af7Sopenharmony_ci
213e5c31af7Sopenharmony_cistatic inline deUint16 readBigEndianShort (tcu::Resource* resource)
214e5c31af7Sopenharmony_ci{
215e5c31af7Sopenharmony_ci	deUint16 val;
216e5c31af7Sopenharmony_ci	resource->read((deUint8*)&val, sizeof(val));
217e5c31af7Sopenharmony_ci	return (deUint16)(((val >> 8) & 0xFF) | ((val << 8) & 0xFF00));
218e5c31af7Sopenharmony_ci}
219e5c31af7Sopenharmony_ci
220e5c31af7Sopenharmony_ci/*--------------------------------------------------------------------*//*!
221e5c31af7Sopenharmony_ci * \brief Load compressed image data from PKM file
222e5c31af7Sopenharmony_ci *
223e5c31af7Sopenharmony_ci * \note			Only ETC1_RGB8_NO_MIPMAPS format is supported
224e5c31af7Sopenharmony_ci * \param dst		Destination pixel container
225e5c31af7Sopenharmony_ci * \param archive	Resource archive
226e5c31af7Sopenharmony_ci * \param fileName	Resource file name
227e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/
228e5c31af7Sopenharmony_civoid loadPKM (CompressedTexture& dst, const tcu::Archive& archive, const char* fileName)
229e5c31af7Sopenharmony_ci{
230e5c31af7Sopenharmony_ci	de::UniquePtr<Resource> resource(archive.getResource(fileName));
231e5c31af7Sopenharmony_ci
232e5c31af7Sopenharmony_ci	// Check magic and version.
233e5c31af7Sopenharmony_ci	deUint8 refMagic[] = {'P', 'K', 'M', ' ', '1', '0'};
234e5c31af7Sopenharmony_ci	deUint8 magic[6];
235e5c31af7Sopenharmony_ci	resource->read(magic, DE_LENGTH_OF_ARRAY(magic));
236e5c31af7Sopenharmony_ci
237e5c31af7Sopenharmony_ci	if (memcmp(refMagic, magic, sizeof(magic)) != 0)
238e5c31af7Sopenharmony_ci		throw InternalError("Signature doesn't match PKM signature", resource->getName().c_str(), __FILE__, __LINE__);
239e5c31af7Sopenharmony_ci
240e5c31af7Sopenharmony_ci	deUint16 type = readBigEndianShort(resource.get());
241e5c31af7Sopenharmony_ci	if (type != ETC1_RGB_NO_MIPMAPS)
242e5c31af7Sopenharmony_ci		throw InternalError("Unsupported PKM type", resource->getName().c_str(), __FILE__, __LINE__);
243e5c31af7Sopenharmony_ci
244e5c31af7Sopenharmony_ci	deUint16	width			= readBigEndianShort(resource.get());
245e5c31af7Sopenharmony_ci	deUint16	height			= readBigEndianShort(resource.get());
246e5c31af7Sopenharmony_ci	deUint16	activeWidth		= readBigEndianShort(resource.get());
247e5c31af7Sopenharmony_ci	deUint16	activeHeight	= readBigEndianShort(resource.get());
248e5c31af7Sopenharmony_ci
249e5c31af7Sopenharmony_ci    DE_UNREF(width && height);
250e5c31af7Sopenharmony_ci
251e5c31af7Sopenharmony_ci	dst.setStorage(COMPRESSEDTEXFORMAT_ETC1_RGB8, (int)activeWidth, (int)activeHeight);
252e5c31af7Sopenharmony_ci	resource->read((deUint8*)dst.getData(), dst.getDataSize());
253e5c31af7Sopenharmony_ci}
254e5c31af7Sopenharmony_ci
255e5c31af7Sopenharmony_ci} // ImageIO
256e5c31af7Sopenharmony_ci} // tcu
257