Click here to Skip to main content
15,884,099 members
Articles / Desktop Programming / MFC

Drawing transparent bitmaps using CImage

Rate me:
Please Sign up or sign in to vote.
4.92/5 (21 votes)
17 Sep 20017 min read 564.1K   13.1K   160  
Universal implementation of transparent drawing of bitmap files (BMP, JPEG, GIF, PNG). Based on the method described by Chris Becke and Raja Segar.
// imapng.cpp

/*
 * File:	ximatif.cpp
 * Purpose:	Platform Independent TIFF Image Class Loader and Writer
 * 07/Aug/2001 <ing.davide.pizzolato@libero.it>
 */
// Removed fopen/fclose mess - Troels K.

#include "..\include\cimage.h"
#pragma hdrstop
#include "imapng.h"

#include "iterator.h"

///////////////////////////////////////////////////////////////////////////
void CImagePNG::ima_png_error(png_struct *png_ptr, char *message)
{
	strcpy(m_info.szLastError,message);
	longjmp(png_ptr->jmpbuf, 1);
}
///////////////////////////////////////////////////////////////////////////
BOOL CImagePNG::Read(FILE* fp)
{
	int number_passes;
	png_struct *png_ptr;
	png_info *info_ptr;
	BYTE *row_pointers=NULL;
	CImageIterator iter(this);
	/* open the file */

	/* Create and initialize the png_struct with the desired error handler
    * functions.  If you want to use the default stderr and longjump method,
    * you can supply NULL for the last three parameters.  We also supply the
    * the compiler header file version, so that we know if the application
    * was compiled with a compatible version of the library.  REQUIRED
    */
	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,(void *)NULL,NULL,NULL);
	if (png_ptr == NULL){
		return FALSE ;
	}

	/* Allocate/initialize the memory for image information.  REQUIRED. */
	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL) {
		png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
		return FALSE ;
	}

    /* Set error handling if you are using the setjmp/longjmp method (this is
    * the normal method of doing things with libpng).  REQUIRED unless you
    * set up your own error handlers in the png_create_read_struct() earlier.
    */
	if (setjmp(png_ptr->jmpbuf)) {
		/* Free all of the memory associated with the png_ptr and info_ptr */
		if (row_pointers) delete[] row_pointers;
		png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
		return FALSE ;
	}
	/* set up the input control */
	png_init_io(png_ptr, fp);

	/* read the file information */
	png_read_info(png_ptr, info_ptr);

	/* allocate the memory to hold the image using the fields of png_m_info. */
	png_color_16 my_background={ 0, 31, 127, 255, 0 };

	png_set_background(png_ptr, &my_background,
			PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);

	/* tell libpng to strip 16 bit depth files down to 8 bits */
	if (info_ptr->bit_depth == 16)	png_set_strip_16(png_ptr);

	int pixel_depth=(info_ptr->pixel_depth<24) ? info_ptr->pixel_depth: 24;

	Create(info_ptr->width, info_ptr->height, pixel_depth);

	if (info_ptr->num_palette>0)
	  SetPalette((rgb_color_struct*)info_ptr->palette,info_ptr->num_palette);

	int row_stride = info_ptr->width * ((pixel_depth+7)>>3);

	row_pointers = new BYTE[row_stride];

	/* turn on interlace handling */
	if (info_ptr->interlace_type)
		number_passes = png_set_interlace_handling(png_ptr);
	else
		number_passes = 1;

	for (int pass=0; pass< number_passes; pass++) {
		iter.Upset();
		int y=0;
		do	{
			if (info_ptr->interlace_type)  {
				if (pass>0)
					iter.GetRow(row_pointers, row_stride);
				png_read_row(png_ptr, row_pointers, NULL);
			} else
				png_read_row(png_ptr, row_pointers, NULL);
			//HACK BY OP
			if (info_ptr->color_type == COLORTYPE_COLOR)
				RGB2BGR(row_pointers, row_stride);
			iter.SetRow(row_pointers, row_stride);
			y++;
		} while(iter.PrevRow());
	}
	delete[] row_pointers;

	/* read the rest of the file, getting any additional chunks in info_ptr */
	png_read_end(png_ptr, info_ptr);

	/* clean up after the read, and free any memory allocated - REQUIRED */
	png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);

	/* that's it */
	return TRUE;
}

BOOL CImagePNG::Write(FILE* fp)
{
	CImageIterator iter(this);
	png_struct *png_ptr;
	png_info *info_ptr;

   /* Create and initialize the png_struct with the desired error handler
    * functions.  If you want to use the default stderr and longjump method,
    * you can supply NULL for the last three parameters.  We also check that
    * the library version is compatible with the one used at compile time,
    * in case we are using dynamically linked libraries.  REQUIRED.
    */
	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,(void *)NULL,NULL,NULL);

	if (png_ptr == NULL){
		return FALSE;
	}

	/* Allocate/initialize the image information data.  REQUIRED */
	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL){
		png_destroy_write_struct(&png_ptr,  (png_infopp)NULL);
		return FALSE;
	}

   /* Set error handling.  REQUIRED if you aren't supplying your own
    * error hadnling functions in the png_create_write_struct() call.
    */
	if (setjmp(png_ptr->jmpbuf)){
		/* If we get here, we had a problem reading the file */
		if (info_ptr->palette) free(info_ptr->palette);
		png_destroy_write_struct(&png_ptr,  (png_infopp)&info_ptr);
		return FALSE;
	}
            
	int row_stride = GetWidth() * ((GetBPP()+7)>>3);
	/* set up the output control */
	png_init_io(png_ptr, fp);

	/* set the file information here */
	info_ptr->width = GetWidth();
	info_ptr->height = GetHeight();
	info_ptr->pixel_depth = (BYTE)GetBPP();
	info_ptr->channels = (GetBPP()>8) ? 3: 1;
	info_ptr->bit_depth = GetBPP()/info_ptr->channels;
	info_ptr->color_type = GetColorType();
	info_ptr->compression_type = info_ptr->filter_type = info_ptr->interlace_type=0;
	info_ptr->valid = 0;
	info_ptr->interlace_type=PNG_INTERLACE_NONE;
	info_ptr->rowbytes = row_stride;

	//HACK BY OP
	if (info_ptr->pixel_depth > 8 )	info_ptr->color_type = COLORTYPE_COLOR;	

	/* set the palette if there is one */
	if ((GetColorType() & COLORTYPE_PALETTE) && GetPalette()){
		png_set_IHDR(png_ptr, info_ptr, info_ptr->width, info_ptr->height, info_ptr->bit_depth, 
					PNG_COLOR_TYPE_PALETTE, info_ptr->interlace_type, 
					PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
		info_ptr->valid |= PNG_INFO_PLTE;
		info_ptr->palette = new png_color[256];
		info_ptr->num_palette = 256;
		for (int i=0; i<256; i++)
			GetRGB(i, &info_ptr->palette[i].red, &info_ptr->palette[i].green, &info_ptr->palette[i].blue);
	}  

	/* write the file information */
	png_write_info(png_ptr, info_ptr);
	/* If you are only writing one row at a time, this works */
	BYTE *row_pointers = new BYTE[row_stride];
  	iter.Upset();
	do	
   {
		iter.GetRow(row_pointers, min(row_stride, GetEffWidth())); // TRK CRT BUG
		//HACK BY OP
		if (info_ptr->color_type == COLORTYPE_COLOR)
			RGB2BGR(row_pointers, row_stride);
		png_write_row(png_ptr, row_pointers);
	} while(iter.PrevRow());
	
	delete [] row_pointers;

	/* It is REQUIRED to call this to finish writing the rest of the file */
	png_write_end(png_ptr, info_ptr);

	/* if you malloced the palette, free it here */
	if (info_ptr->palette)	delete[] (info_ptr->palette);

	/* clean up after the write, and free any memory allocated */
	png_destroy_write_struct(&png_ptr, (png_infopp)&info_ptr);

	/* that's it */
	return TRUE;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Denmark Denmark
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions