Dali 3D User Interface Engine
loader-astc.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 
18 // CLASS HEADER
19 #include "loader-astc.h"
20 
21 // EXTERNAL INCLUDES
22 #include <cstdio>
23 #include <cstdlib>
24 #include <cstring>
25 #include <stdint.h>
30 
31 namespace Dali
32 {
33 using Integration::Bitmap;
35 
36 namespace TizenPlatform
37 {
38 
39 namespace
40 {
41 
42 // Max width or height of an image.
43 const unsigned MAX_TEXTURE_DIMENSION = 4096;
44 // Max bytes of image data allowed. Not a precise number, just a sanity check.
45 const unsigned MAX_IMAGE_DATA_SIZE = MAX_TEXTURE_DIMENSION * MAX_TEXTURE_DIMENSION;
46 
47 // Minimum and maximum possible sizes for ASTC blocks.
48 const unsigned int MINIMUM_ASTC_BLOCK_SIZE = 4;
49 const unsigned int MAXIMUM_ASTC_BLOCK_SIZE = 12;
50 
51 typedef uint8_t Byte;
52 
53 // This bytes identify an ASTC native file.
54 const Byte FileIdentifier[] = {
55  0x13, 0xAB, 0xA1, 0x5C
56 };
57 
58 
66 {
67  unsigned char magic[ 4 ];
68  unsigned char blockdim_x;
69  unsigned char blockdim_y;
70  unsigned char blockdim_z;
71  unsigned char xsize[ 3 ];
72  unsigned char ysize[ 3 ];
73  unsigned char zsize[ 3 ];
74 } __attribute__ ( (__packed__));
75 
76 using namespace Pixel;
77 
95 };
96 
104 {
105  // Check the block size is valid. This will also prevent an invalid read from the conversion table.
106  if( ( header.blockdim_x < MINIMUM_ASTC_BLOCK_SIZE ) || ( header.blockdim_x > MAXIMUM_ASTC_BLOCK_SIZE ) ||
107  ( header.blockdim_y < MINIMUM_ASTC_BLOCK_SIZE ) || ( header.blockdim_y > MAXIMUM_ASTC_BLOCK_SIZE ) )
108  {
109  return Pixel::INVALID;
110  }
111 
112  // Read the equivalent pixel format from the conversion table.
114 }
115 
125 bool LoadAstcHeader( FILE * const filePointer, unsigned int &width, unsigned int &height, AstcFileHeader &fileHeader )
126 {
127  // Pull the bytes of the file header in as a block:
128  unsigned int readLength = sizeof( AstcFileHeader );
129  if( fread( (void*)&fileHeader, 1, readLength, filePointer ) != readLength )
130  {
131  return false;
132  }
133 
134  // Check the header contains the ASTC native file identifier.
135  bool headerIsValid = memcmp( fileHeader.magic, FileIdentifier, sizeof( fileHeader.magic ) ) == 0;
136  if( !headerIsValid )
137  {
138  DALI_LOG_ERROR( "File is not a valid ASTC native file\n" );
139  // Return here as otherwise, if not a valid ASTC file, we are likely to pick up other header errors spuriously.
140  return false;
141  }
142 
143  // Convert the 3-byte values for width and height to a single resultant value.
144  width = fileHeader.xsize[0] | ( fileHeader.xsize[1] << 8 ) | ( fileHeader.xsize[2] << 16 );
145  height = fileHeader.ysize[0] | ( fileHeader.ysize[1] << 8 ) | ( fileHeader.ysize[2] << 16 );
146 
147  const unsigned int zDepth = fileHeader.zsize[0] + ( fileHeader.zsize[1] << 8 ) + ( fileHeader.zsize[2] << 16 );
148 
149  // Check image dimensions are within limits.
150  if( ( width > MAX_TEXTURE_DIMENSION ) || ( height > MAX_TEXTURE_DIMENSION ) )
151  {
152  DALI_LOG_ERROR( "ASTC file has larger than supported dimensions: %d,%d\n", width, height );
153  headerIsValid = false;
154  }
155 
156  // Confirm the ASTC block does not have any Z depth.
157  if( zDepth != 1 )
158  {
159  DALI_LOG_ERROR( "ASTC files with z size other than 1 are not supported. Z size is: %d\n", zDepth );
160  headerIsValid = false;
161  }
162 
163  return headerIsValid;
164 }
165 
166 } // Unnamed namespace.
167 
168 
169 // File loading API entry-point:
170 bool LoadAstcHeader( const ImageLoader::Input& input, unsigned int& width, unsigned int& height )
171 {
172  AstcFileHeader fileHeader;
173  return LoadAstcHeader( input.file, width, height, fileHeader );
174 }
175 
176 // File loading API entry-point:
178 {
179  FILE* const filePointer = input.file;
180  if( !filePointer )
181  {
182  DALI_LOG_ERROR( "Null file handle passed to ASTC compressed bitmap file loader.\n" );
183  return false;
184  }
185 
186  // Load the header info.
187  AstcFileHeader fileHeader;
188  unsigned int width, height;
189 
190  if( !LoadAstcHeader( filePointer, width, height, fileHeader ) )
191  {
192  DALI_LOG_ERROR( "Could not load ASTC Header from file.\n" );
193  return false;
194  }
195 
196  // Retrieve the pixel format from the ASTC block size.
197  Pixel::Format pixelFormat = GetAstcPixelFormat( fileHeader );
198  if( pixelFormat == Pixel::INVALID )
199  {
200  DALI_LOG_ERROR( "No internal pixel format supported for ASTC file pixel format.\n" );
201  return false;
202  }
203 
204  // Retrieve the file size.
205  fseek( filePointer, 0L, SEEK_END );
206  off_t fileSize = ftell( filePointer );
207  if( fileSize == -1L )
208  {
209  DALI_LOG_ERROR( "Could not determine ASTC file size.\n" );
210  return false;
211  }
212  fseek( filePointer, sizeof( AstcFileHeader ), SEEK_SET );
213 
214  // Data size is file size - header size.
215  size_t imageByteCount = fileSize - sizeof( AstcFileHeader );
216 
217  // Sanity-check the image data is not too large and that it is at less than 2 bytes per texel:
218  if( ( imageByteCount > MAX_IMAGE_DATA_SIZE ) || ( imageByteCount > ( ( width * height ) << 1 ) ) )
219  {
220  DALI_LOG_ERROR( "ASTC file has too large image-data field.\n" );
221  return false;
222  }
223 
224  // Allocate space to load the image data in to.
225  PixelBuffer* const pixels = bitmap.GetCompressedProfile()->ReserveBufferOfSize( pixelFormat, width, height, imageByteCount );
226  if( !pixels )
227  {
228  DALI_LOG_ERROR( "Unable to reserve a pixel buffer to load the requested bitmap into.\n" );
229  return false;
230  }
231 
232  // Load the image data.
233  const size_t bytesRead = fread( pixels, 1, imageByteCount, filePointer );
234  // Check the size of loaded data is what we expected.
235  if( bytesRead != imageByteCount )
236  {
237  DALI_LOG_ERROR( "Read of image pixel data failed.\n" );
238  return false;
239  }
240 
241  return true;
242 }
243 
244 } // namespace TizenPlatform
245 
246 } // namespace Dali
Dali Docs Home
Read more about Dali