LibPNG for NXP with FatFS

16 views
asked Jan 17 in System Integration by Mike_PPsys

Hi All,

 Posting this incase someone else is looking to read in PNG files off a ChaN_FatFS file system. The LibPNG codebase I sourced from SEGGER and modified to support FatFS is here: http://s000.tinyupload.com/?file_id=49354806145704772533

EwLoadExternBitmap() is as follows. 

Hope this saves someone time.
 


#define PNG_BYTES_TO_CHECK 8

/*******************************************************************************
* FUNCTION:
*   EwLoadExternBitmap
*
* DESCRIPTION: wThis function has the job to create and fill a bitmap with content
*  of an extern image file. aName identified extern file to load. If successful,
*  an initialized bitmap is returned otherwise NULL.
*******************************************************************************/
XBitmap* EwLoadExternBitmap( XString aName )
{
  // LibPNG
  png_structp 					png_ptr;
  png_infop 					info_ptr;
  unsigned char					png_header[PNG_BYTES_TO_CHECK];
  uint8_t						channels, color_type;

  // FILE IO
  static FIL                    fil;
  FRESULT 						fr;

  // EW
  XBitmap*                      bitmap  = 0;
  XBitmapLock*                  lock    = 0;
  int                           nameLen = EwGetStringLength( aName );
  char*                         name    = malloc( nameLen + 1 );
  XPoint                        frameSize;
  XRect                         lockArea;

  /* Out of memory? */
  if ( !name )
    return NULL;

  /* Convert the 16-bit wide char string in an 8-bit ANSI string */
  EwStringToAnsi( aName, name, nameLen + 1, 0 );

  // Try to open the file
  fr = f_open(&fil, name, FA_READ);
  if(fr)
  {
	  PRINTF("EwLoadExternBitmap() f_open() error\n\r");
	  free( name );
	  return NULL;
  }

  // read PNG header
  f_read(&fil, png_header, PNG_BYTES_TO_CHECK, NULL);
  if (png_sig_cmp(png_header, 0, PNG_BYTES_TO_CHECK))
  {
	  PRINTF("File %s is not recognized as a PNG file\n\r", name);
	  free(name);
	  f_close(&fil);
	  return NULL;
  }

  // initialize stuff
  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if (!png_ptr)
  {
	  PRINTF("png_create_read_struct() failed\n\r");
	  free(name);
	  f_close(&fil);
	  return NULL;
  }

  info_ptr = png_create_info_struct(png_ptr);
  if (!info_ptr)
  {
	  PRINTF("png_create_info_struct() failed\n\r");
	  png_destroy_read_struct(&png_ptr, NULL, NULL);
      free(name);
      f_close(&fil);
      return NULL;
  }

  png_init_io(png_ptr, &fil);
  png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);
  png_read_info(png_ptr, info_ptr);
  png_set_scale_16(png_ptr);

  color_type = png_get_color_type(png_ptr, info_ptr);
  if (color_type == PNG_COLOR_TYPE_PALETTE)
     png_set_palette_to_rgb(png_ptr);

  if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) != 0)
       png_set_tRNS_to_alpha(png_ptr);

  // Get PNG file info
  png_read_update_info(png_ptr, info_ptr);
  channels = png_get_channels(png_ptr, info_ptr);
  frameSize.X = png_get_image_width(png_ptr, info_ptr);
  frameSize.Y = png_get_image_height(png_ptr, info_ptr);
  PRINTF("[SYSTEM EVENT] Opened:%s %ix%i Channels:%i ColorType:%i   \n\r", name, frameSize.X, frameSize.Y, channels, color_type);

  /* Create an Embedded Wizard bitmap to store the image pixel data */
  bitmap      = EwCreateBitmap( EW_PIXEL_FORMAT_NATIVE, frameSize, 0, 1 );

  /* Could create the image */
  if ( bitmap )
  {
    lockArea.Point1.X = 0;
    lockArea.Point1.Y = 0;
    lockArea.Point2.X = frameSize.X;
    lockArea.Point2.Y = frameSize.Y;

    lock = EwLockBitmap( bitmap, 0, lockArea, 0, 1 );

    png_bytep row_pointer;
    row_pointer = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr));

    for (uint32_t pass = 0; pass < frameSize.Y; pass++)
    {
    	png_read_rows(png_ptr, &row_pointer, NULL, 1);

        unsigned int*  dest   = (unsigned int*)((char*)lock->Pixel1 + pass * lock->Pitch1Y );

    	for (uint32_t x = 0; x < frameSize.X; x++)
    	{
    		png_byte* ptr = &(row_pointer[x*channels]);

    		// Get the RGBA values from the PNG decoder and arrange the 'red', 'green', 'blue' channels at the right bit offset position
    		unsigned int red   = ptr[0] << EW_COLOR_CHANNEL_BIT_OFFSET_RED;
    		unsigned int green = ptr[1] << EW_COLOR_CHANNEL_BIT_OFFSET_GREEN;
    		unsigned int blue  = ptr[2] << EW_COLOR_CHANNEL_BIT_OFFSET_BLUE;
    		unsigned int alpha;
    		if(channels == 4)
    			alpha = ptr[3] << EW_COLOR_CHANNEL_BIT_OFFSET_ALPHA;
    		else
    			alpha = 0xFF << EW_COLOR_CHANNEL_BIT_OFFSET_ALPHA;

    		// Store the pixel data in the bitmap memory
    		*dest++ = red | green | blue | alpha;
    	}

    }

    png_free(png_ptr, row_pointer);
    row_pointer = NULL;
    png_read_end(png_ptr, info_ptr);
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);

    /* Don't forget to unlock the bitmap */
    EwUnlockBitmap( lock );
  }

  /* After finish_decompress, we can close the input file. */
  f_close(&fil);

  /* Release temporary memory */
  free( name );

  /* all ok */
  return bitmap;
}

 

1 Answer

0 votes
answered Jan 17 by Paul Banach
Hello Mike,

thank you very much!

Best regards

Paul Banach

Ask Embedded Wizard

Welcome to the question and answer site for Embedded Wizard users and UI developers.

Ask your question and receive answers from the Embedded Wizard support team or from other members of the community!

Embedded Wizard Website | Privacy Policy | Imprint

...