DVBCore  20.3.0
DVBCore Documentation
image_png.c
Go to the documentation of this file.
1 /*******************************************************************************
2  * Copyright © 2014 The DTVKit Open Software Foundation Ltd (www.dtvkit.org)
3  * Copyright © 2010 Ocean Blue Software Ltd
4  *
5  * This file is part of a DTVKit Software Component
6  * You are permitted to copy, modify or distribute this file subject to the terms
7  * of the DTVKit 1.0 Licence which can be found in licence.txt or at www.dtvkit.org
8  *
9  * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
10  * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
11  * OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
12  *
13  * If you or your organisation is not a member of DTVKit then you have access
14  * to this source code outside of the terms of the licence agreement
15  * and you are expected to delete this and any associated files immediately.
16  * Further information on DTVKit, membership and terms can be found at www.dtvkit.org
17  *******************************************************************************/
25 /*#define ENABLE_DEBUG*/
26 
27 /*---includes for this file--------------------------------------------------*/
28 
29 /* compiler library header files */
30 #include <string.h>
31 
32 /* third party header files */
33 #include <png.h>
34 
35 /* DVBCore header files */
36 #include "techtype.h"
37 #include "dbgfuncs.h"
38 
39 #include "stbheap.h"
40 
41 
42 /*---constant definitions for this file--------------------------------------*/
43 #ifdef ENABLE_DEBUG
44 #define DBG(x) STB_SPDebugWrite x
45 #else
46 #define DBG(x)
47 #endif
48 
49 #define PNG_HEADER_SIZE 8
50 
51 #define ST_ALPHA(x) (((x) * 128 + 127) / 255)
52 
53 
54 /*---local typedef structs for this file-------------------------------------*/
55 typedef struct
56 {
57  U8BIT *data;
58  U32BIT length;
59  U32BIT offset;
60 } S_PNG_BUFFER;
61 
62 typedef struct
63 {
64  png_struct *png_ptr;
65  png_info *info_ptr;
66  png_info *end_info;
67  S_PNG_BUFFER buffer;
68 } S_PNG_READER;
69 
70 
71 /*---local (static) variable declarations for this file----------------------*/
72 /* (internal variables declared static to make them local) */
73 
74 
75 /*---local function prototypes for this file---------------------------------*/
76 /* (internal functions declared static to make them local) */
77 static BOOLEAN ReadPNGHeader(U8BIT *image_data, U32BIT num_bytes, U16BIT *pixel_width,
78  U16BIT *pixel_height, U32BIT *bytes_per_row, BOOLEAN keep_open, S_PNG_READER *reader);
79 
80 static png_voidp PNG_Malloc(png_structp png_ptr, png_size_t size);
81 static void PNG_Free(png_structp png_ptr, png_voidp addr);
82 static void PNG_ReadData(png_structp png_ptr, png_bytep data, png_size_t length);
83 
84 
85 /*---global function definitions---------------------------------------------*/
86 
87 /*!**************************************************************************
88  * @brief Converts the given PNG image data to a bitmap image that can be displayed on-screen
89  * with the given bit depth.
90  * @param image_data - PNG image data
91  * @param image_data_size - number of PNG image data bytes
92  * @param output_data - address of pointer to buffer allocated for output data
93  * @param output_data_size - pointer to number of bytes in output bitmap
94  * @param pixel_width - pointer to returned width in pixels
95  * @param pixel_height - pointer to returned height in pixels
96  * @return TRUE if image data is a valid PNG and conversion succeeds, FALSE otherwise
97  ****************************************************************************/
98 BOOLEAN STB_IMGConvertPNG(U8BIT *image_data, U32BIT image_data_size, U8BIT **output_data,
99  U32BIT *output_data_size, U16BIT *pixel_width, U16BIT *pixel_height)
100 {
101  BOOLEAN retval;
102  U32BIT rowbytes;
103  S_PNG_READER reader;
104  U8BIT **row_pointers;
105  U8BIT *source_data;
106  U8BIT *src;
107  U32BIT row, pixel;
108  U32BIT bytes_per_line;
109 #ifdef OSD_16_BIT
110  U16BIT *dest_line;
111  U16BIT *dest;
112 #else
113  U32BIT *dest_line;
114  U32BIT *dest;
115 #endif
116  U32BIT channels;
117  U8BIT alpha, red, green, blue;
118 
119  FUNCTION_START(STB_IMGConvertPNG);
120 
121  retval = FALSE;
122  *output_data = NULL;
123  *output_data_size = 0;
124 
125  if ((image_data != NULL) && (image_data_size >= PNG_HEADER_SIZE))
126  {
127  if (ReadPNGHeader(image_data, image_data_size, pixel_width, pixel_height, &rowbytes, TRUE, &reader))
128  {
129  /* Allocate memory for the output image */
130 #ifdef OSD_16_BIT
131  bytes_per_line = *pixel_width * 2;
132 #else /* OSD_32_BIT */
133  bytes_per_line = *pixel_width * 4;
134 #endif
135  *output_data_size = *pixel_height * bytes_per_line;
136 
137  *output_data = (U8BIT *)STB_GetMemory(*output_data_size);
138  if (*output_data != NULL)
139  {
140  memset(*output_data, 0, *output_data_size);
141 
142  /* Allocate memory to read the entire image */
143  source_data = (U8BIT *)STB_GetMemory(rowbytes * *pixel_height);
144  if (source_data != NULL)
145  {
146  /* Need pointers to start of each row for reading */
147  row_pointers = (U8BIT **)STB_GetMemory(*pixel_height * sizeof(U8BIT *));
148  if (row_pointers != NULL)
149  {
150  for (row = 0; row < *pixel_height; row++)
151  {
152  row_pointers[row] = source_data + (row * rowbytes);
153  }
154 
155  png_read_image(reader.png_ptr, row_pointers);
156 
157  channels = png_get_channels(reader.png_ptr, reader.info_ptr);
158 
159  /* Now process the image to convert it into an image compatible with the OSD */
160 #ifdef OSD_16_BIT
161  dest_line = (U16BIT *)*output_data;
162 #else /* OSD_32_BIT */
163  dest_line = (U32BIT *)*output_data;
164 #endif
165 
166  for (row = 0; row < *pixel_height; dest_line += *pixel_width, row++)
167  {
168  src = row_pointers[row];
169 
170  if (channels == 3)
171  {
172  /* RGB image */
173  for (pixel = *pixel_width, dest = dest_line; pixel > 0;
174  dest++, src += 3, pixel--)
175  {
176  red = *src;
177  green = *(src + 1);
178  blue = *(src + 2);
179 #ifdef OSD_16_BIT
180  *dest = 0x0f;
181  *dest = (*dest << 4) | (red >> 4);
182  *dest = (*dest << 4) | (green >> 4);
183  *dest = (*dest << 4) | (blue >> 4);
184 #else /* OSD_32_BIT */
185 #ifdef OSD_ST_MODE
186  alpha = ST_ALPHA(0xff);
187 #else
188  alpha = 0xff;
189 #endif
190  *dest = (alpha << 24) | (red << 16) | (green << 8) | blue;
191 #endif
192  }
193  }
194  else
195  {
196  /* ARGB image */
197  for (pixel = *pixel_width, dest = dest_line; pixel > 0;
198  dest++, src += 4, pixel--)
199  {
200  alpha = *src;
201  red = *(src + 1);
202  green = *(src + 2);
203  blue = *(src + 3);
204 #ifdef OSD_16_BIT
205  *dest = (alpha >> 4);
206  *dest = (*dest << 4) | (red >> 4);
207  *dest = (*dest << 4) | (green >> 4);
208  *dest = (*dest << 4) | (blue >> 4);
209 #else /* OSD_32_BIT */
210 #ifdef OSD_ST_MODE
211  alpha = ST_ALPHA(alpha);
212 #endif
213  *dest = (alpha << 24) | (red << 16) | (green << 8) | blue;
214 #endif
215  }
216  }
217  }
218 
219  STB_FreeMemory(row_pointers);
220 
221  retval = TRUE;
222  }
223 
224  STB_FreeMemory(source_data);
225  }
226  else
227  {
228  STB_FreeMemory(*output_data);
229  *output_data = NULL;
230  }
231  }
232 
233  png_destroy_read_struct(&reader.png_ptr, &reader.info_ptr, &reader.end_info);
234  }
235  }
236 
237  FUNCTION_FINISH(STB_IMGConvertPNG);
238 
239  return(retval);
240 }
241 
242 /*!**************************************************************************
243  * @brief Common function to read PNG header and return image info
244  * @param image_data - image data containing header
245  * @param num_bytes - number of header bytes supplied
246  * @param pixel_width - pointer to return image width in pixels
247  * @param pixel_height - pointer to return image height in pixels
248  * @param bytes_per_row - pointer to return num bytes per row
249  * @param keep_open - TRUE to keep the PNG open
250  * @param reader - used to return reading related info if PNG is kept open
251  * @return TRUE if reading succeeds, FALSE otherwise
252  ****************************************************************************/
253 static BOOLEAN ReadPNGHeader(U8BIT *image_data, U32BIT num_bytes, U16BIT *pixel_width,
254  U16BIT *pixel_height, U32BIT *bytes_per_row, BOOLEAN keep_open, S_PNG_READER *reader)
255 {
256  BOOLEAN retval;
257  U32BIT num_header_bytes;
258  png_struct *png_ptr;
259  png_infop info_ptr;
260  png_infop end_info;
261  S_PNG_BUFFER buffer;
262 #if (PNG_LIBPNG_VER != 10202) || defined (ENABLE_DEBUG)
263  U32BIT bitdepth;
264 #endif
265 #ifdef ENABLE_DEBUG
266  U32BIT resx, resy, res_unit;
267 #endif
268 
269  FUNCTION_START(ReadPNGHeader);
270 
271  retval = FALSE;
272 
273  if ((image_data != NULL) && (num_bytes > 0))
274  {
275  if (num_bytes < PNG_HEADER_SIZE)
276  {
277  num_header_bytes = num_bytes;
278  }
279  else
280  {
281  num_header_bytes = PNG_HEADER_SIZE;
282  }
283 
284  /* Check that the PNG header indicates a valid PNG image */
285  if (png_sig_cmp(image_data, 0, num_header_bytes) == 0)
286  {
287  png_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL, NULL,
288  PNG_Malloc, PNG_Free);
289  if (png_ptr != NULL)
290  {
291  info_ptr = png_create_info_struct(png_ptr);
292  if (info_ptr != NULL)
293  {
294  end_info = png_create_info_struct(png_ptr);
295  if (end_info != NULL)
296  {
297  /* Initialise the structure used for reading data */
298  if (reader != NULL)
299  {
300  reader->buffer.data = image_data;
301  reader->buffer.length = num_bytes;
302  reader->buffer.offset = 0;
303 
304  /* Set the function that the PNG lib should use to read data */
305  png_set_read_fn(png_ptr, &reader->buffer, PNG_ReadData);
306  }
307  else
308  {
309  buffer.data = image_data;
310  buffer.length = num_bytes;
311  buffer.offset = 0;
312 
313  /* Set the function that the PNG lib should use to read data */
314  png_set_read_fn(png_ptr, &buffer, PNG_ReadData);
315  }
316 
317  /* Read the PNG header info to get details on the image */
318  png_read_info(png_ptr, info_ptr);
319 
320 #ifdef ENABLE_DEBUG
321  DBG(("Original PNG image:"));
322  DBG((" width=%d", png_get_image_width(png_ptr, info_ptr)));
323  DBG((" height=%d", png_get_image_height(png_ptr, info_ptr)));
324  DBG((" bitdepth=%d", png_get_bit_depth(png_ptr, info_ptr)));
325  DBG((" colortype=%d", png_get_color_type(png_ptr, info_ptr)));
326  DBG((" rowbytes=%d", png_get_rowbytes(png_ptr, info_ptr)));
327  DBG((" channels=%d", png_get_channels(png_ptr, info_ptr)));
328  DBG((" compression=%d", png_get_compression_type(png_ptr, info_ptr)));
329  if (png_get_pHYs(png_ptr, info_ptr, &resx, &resy, &res_unit) != 0)
330  {
331  DBG((" resx=%lu, resy=%lu, unit=%lu", resx, resy, res_unit));
332  }
333 #endif
334 
335  /* Set option to read 16-bit data as RGB RGB rather than RRGGBB */
336  png_set_strip_16(png_ptr);
337 
338  /* Set the input transformations that are to be applied depending on the type
339  * of the image. The data is transformed so that it always reads as ARGB on input. */
340 #if (PNG_LIBPNG_VER != 10202) || defined (ENABLE_DEBUG)
341  bitdepth = png_get_bit_depth(png_ptr, info_ptr);
342 #endif
343 
344  switch (png_get_color_type(png_ptr, info_ptr))
345  {
346  case PNG_COLOR_TYPE_GRAY:
347 #if (PNG_LIBPNG_VER != 10202)
348  if (bitdepth < 8)
349  {
350  png_set_expand_gray_1_2_4_to_8(png_ptr);
351  }
352 #endif
353  png_set_gray_to_rgb(png_ptr);
354  break;
355 
356  case PNG_COLOR_TYPE_PALETTE:
357  png_set_palette_to_rgb(png_ptr);
358  if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
359  {
360  png_set_tRNS_to_alpha(png_ptr);
361  }
362  break;
363 
364  case PNG_COLOR_TYPE_RGB:
365  break;
366 
367  case PNG_COLOR_TYPE_RGB_ALPHA:
368  png_set_swap_alpha(png_ptr);
369  break;
370 
371  default:
372  DBG(("PNG: unhandled PNG colour type %lu", png_get_color_type(png_ptr, info_ptr)));
373  break;
374  }
375 
376  /* Now re-read the image info to take into account the input transforms */
377  png_read_update_info(png_ptr, info_ptr);
378 
379 #ifdef ENABLE_DEBUG
380  DBG(("Output PNG image:"));
381  DBG((" width=%d", png_get_image_width(png_ptr, info_ptr)));
382  DBG((" height=%d", png_get_image_height(png_ptr, info_ptr)));
383  DBG((" bitdepth=%d", png_get_bit_depth(png_ptr, info_ptr)));
384  DBG((" colortype=%d", png_get_color_type(png_ptr, info_ptr)));
385  DBG((" rowbytes=%d", png_get_rowbytes(png_ptr, info_ptr)));
386  DBG((" channels=%d", png_get_channels(png_ptr, info_ptr)));
387  DBG((" compression=%d", png_get_compression_type(png_ptr, info_ptr)));
388  if (png_get_pHYs(png_ptr, info_ptr, &resx, &resy, &res_unit) != 0)
389  {
390  DBG((" resx=%lu, resy=%lu, unit=%lu", resx, resy, res_unit));
391  }
392 #endif
393 
394  *pixel_width = (U16BIT)png_get_image_width(png_ptr, info_ptr);
395  *pixel_height = (U16BIT)png_get_image_height(png_ptr, info_ptr);
396  *bytes_per_row = png_get_rowbytes(png_ptr, info_ptr);
397 
398  if (keep_open && (reader != NULL))
399  {
400  /* Pass the PNG reader info back to the calling function so it can be reused */
401  reader->png_ptr = png_ptr;
402  reader->info_ptr = info_ptr;
403  reader->end_info = end_info;
404  }
405  else
406  {
407  png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
408  }
409 
410  retval = TRUE;
411  }
412  else
413  {
414  png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
415  }
416  }
417  else
418  {
419  png_destroy_read_struct(&png_ptr, NULL, NULL);
420  }
421  }
422  }
423  }
424 
425  FUNCTION_FINISH(ReadPNGHeader);
426 
427  return(retval);
428 }
429 
430 /*!**************************************************************************
431  * @brief Function used by PNG library to allocate memory
432  * @param png_ptr - PNG structure
433  * @param size - number of bytes to be allocated
434  * @return address of allocated memory
435  ****************************************************************************/
436 static png_voidp PNG_Malloc(png_structp png_ptr, png_size_t size)
437 {
438  png_voidp addr;
439 
440  FUNCTION_START(PNG_Malloc);
441  USE_UNWANTED_PARAM(png_ptr);
442 
443  addr = STB_GetMemory(size);
444 
445  FUNCTION_FINISH(PNG_Malloc);
446 
447  return(addr);
448 }
449 
450 /*!**************************************************************************
451  * @brief Function used by PNG library to free memory
452  * @param png_ptr - PNG structure
453  * @param addr - address of memory to be freed
454  ****************************************************************************/
455 static void PNG_Free(png_structp png_ptr, png_voidp addr)
456 {
457  FUNCTION_START(PNG_Free);
458  USE_UNWANTED_PARAM(png_ptr);
459 
460  STB_FreeMemory(addr);
461 
462  FUNCTION_FINISH(PNG_Free);
463 }
464 
465 /*!**************************************************************************
466  * @brief Function used by PNG library to read data
467  * @param png_ptr - PNG structure
468  * @param data - address to which data is to be read
469  * @param length - number of bytes to read
470  ****************************************************************************/
471 static void PNG_ReadData(png_structp png_ptr, png_bytep data, png_size_t length)
472 {
473  S_PNG_BUFFER *buffer = (S_PNG_BUFFER *)png_get_io_ptr(png_ptr);
474 
475  FUNCTION_START(PNG_ReadData);
476 
477  if (length > buffer->length - buffer->offset)
478  {
479  length = buffer->length - buffer->offset;
480  }
481 
482  if (length > 0)
483  {
484  memcpy(data, buffer->data + buffer->offset, length);
485  buffer->offset += length;
486  }
487 
488  FUNCTION_FINISH(PNG_ReadData);
489 }
490 
void * STB_GetMemory(U32BIT bytes)
Attempts to allocate memory from the heap.
Definition: stbheap.c:221
BOOLEAN STB_IMGConvertPNG(U8BIT *image_data, U32BIT image_data_size, U8BIT **output_data, U32BIT *output_data_size, U16BIT *pixel_width, U16BIT *pixel_height)
Converts the given PNG image data to a bitmap image that can be displayed on-screen with the given bi...
Definition: image_png.c:98
void STB_FreeMemory(void *addr)
Releases previously allocated heap memory.
Definition: stbheap.c:336
Debug functions header file.
System Wide Global Technical Data Type Definitions.
Header file - Function prototypes for heap memory.