예제 #1
0
/*
// converts a color image to a gray scale image.  If img is a 16 or
// 24-BPP image then it is converted to a 256 color grayscale bitmap.
// If img is a 1, 4, or 8 BPP image, then it will have the same number
// of grayscales as it has palette entries.  If it is a 32-BPP bitmap then
// it will remain a 32-BPP bitmap to preserve the alpha channel.
//
// This function returns BMG_OK if successfull, or an error state
// otherwise.
*/
BMGError ConvertToGrayScale( struct BMGImageStruct *img )
{
    unsigned char *p, *q, *r, *end, gray;

    SetLastBMGError( BMG_OK );

    /* if this is a paletted image then we simply need to convert the
    // palette entries */
    switch ( img->bits_per_pixel )
    {
    default:
        end = img->palette + img->palette_size * img->bytes_per_palette_entry;
        for ( p = img->palette; p < end; p += img->bytes_per_palette_entry )
        {
            gray = CreateGrayScale( p );
            memset( (void *)p, gray, 3 );
        }
        break;
    /* 16 BPP image are converted to 24 BPP images */
    case 16:
    {
        BMGError tmp = Convert16to24( img );
        if ( tmp != BMG_OK )
        {
            SetLastBMGError( tmp );
            return tmp;
        }
    }
    case 24:
    {
        unsigned char *new_bits;
        unsigned char *s, *s_end;
        unsigned short i;

        /* calculate the new scan width */
        unsigned int new_scan_width = img->width;
        if ( new_scan_width % 4 && img->opt_for_bmp )
            new_scan_width += 4 - new_scan_width % 4;

        /* allocate memory for the new pixel values */
        new_bits = (unsigned char *)calloc( new_scan_width * img->height,
                    sizeof(unsigned char) );
        if ( new_bits == NULL )
        {
            SetLastBMGError( errMemoryAllocation );
            return errMemoryAllocation;
        }

        /* allocate memory for a 256 gray scale palette */
        img->bytes_per_palette_entry = img->opt_for_bmp == 1 ? 4 : 3;
        img->palette_size = 256;
        img->palette =
            (unsigned char *)calloc(img->bytes_per_palette_entry *
                                    img->palette_size,
                                    sizeof(unsigned char) );
        if ( img->palette == NULL )
        {
            free( new_bits );
            img->bytes_per_palette_entry = 0;
            img->palette_size = 0;
            SetLastBMGError( errMemoryAllocation );
            return errMemoryAllocation;
        }

        /* assign values to the gray scale palette */
        for ( i = 0; i < 256; i++ )
        {
            p = img->palette + i * img->bytes_per_palette_entry;
            memset( (void *)p, i, 3 );
            if ( img->bytes_per_palette_entry == 4 )
                p[3] = 0;
        }

        /* cycle through the pixels and convert them to gray scale values */
        q = new_bits;
        end = img->bits + img->scan_width * img->height;

        for ( p = img->bits; p < end; p += img->scan_width, q += new_scan_width )
        {
            s_end = p + 3 * img->width;
            r = q;
            for ( s = p; s < s_end; s += 3, r++ )
                *r = CreateGrayScale( s );
        }

        free( img->bits );
        img->bits = new_bits;
        img->scan_width = new_scan_width;
        img->bits_per_pixel = 8;

        break;
    }
    case 32:
        end = img->bits + img->scan_width * img->height;
        for ( p = img->bits; p < end; p += img->scan_width )
        {
            r = p + img->scan_width;
            for ( q = p; q < r; q += 4 )
            {
                gray = CreateGrayScale( q );
                memset( (void *)q, gray, 3 );
            }
        }
        break;
    }

    return BMG_OK;
}
예제 #2
0
/******************************************************************************
//  ConvertPaletteToRGB converts paletted and 16-BPP images that do not have
// transparent pixels to 24-BPP images.  Paletted images with transparent pixels
// are converted to 32-BPP images.  24-BPP and 32-BPP images are simply copied
// to the output structure
//
// INPUTS:
//  img_in
// OUTPUTS:
//  img_out
//
// returns BMG_OK if no errors occur, an error code otherwise
******************************************************************************/
BMGError ConvertPaletteToRGB( struct BMGImageStruct img_in,
                              struct BMGImageStruct *img_out )
{
    jmp_buf err_jmp;
    int error;

    /* error handler */
    error = setjmp( err_jmp );
    if ( error != 0 )
    {
        FreeBMGImage( img_out );
        SetLastBMGError( (BMGError)error );
        return (BMGError)error;
    }

    SetLastBMGError( BMG_OK );

    if ( img_in.height == 0 || img_in.width == 0 )
        longjmp( err_jmp, (int)errInvalidSize );

    InitBMGImage( img_out );

    // copy 16, 24, and 32-BPP images into the output image
    if ( img_in.bits_per_pixel > 8 )
    {
        BMGError out;
        img_out->bits_per_pixel = img_in.bits_per_pixel;
        out = CopyBMGImage( img_in, img_out );
        if ( out != BMG_OK )
            longjmp( err_jmp, (int)out );

        // 16-BPP are converted to 24-BPP images
        if ( img_out->bits_per_pixel == 16 )
        {
            out = Convert16to24( img_out );
            if ( out != BMG_OK )
                longjmp( err_jmp, (int)out );
        }
    }
    else // convert paletted images to 24-BPP BGR or 32-BPP BGRA images
    {
        BMGError out;
        unsigned char *buf;
        unsigned int scan_width;
        int dealloc;
        unsigned char *q0, *q1, *p0, *p1;
        unsigned int bpp;

        // allocate memory for the 24-BPP output image
        img_out->width  = img_in.width;
        img_out->height = img_in.height;
        img_out->opt_for_bmp = img_in.opt_for_bmp;
        img_out->bits_per_pixel = img_in.transparency_index > -1 ? 32 : 24;

        out = AllocateBMGImage( img_out );
        if ( out != BMG_OK )
            longjmp( err_jmp, (int)out );

        // 1-BPP and 4-BPP images are packed, so we need to unpack them
        if ( img_in.bits_per_pixel < 8 )
        {
            dealloc = 1;
            scan_width = img_in.width;
            buf = (unsigned char *)malloc(scan_width * img_in.height);
            if ( buf == NULL )
                longjmp( err_jmp, (int)errMemoryAllocation );

            if ( img_in.bits_per_pixel == 1 )
                Convert1to8( img_in, buf );
            else
                Convert4to8( img_in, buf );
        }
        else // simply point to the bits array if we have a 8-BPP image
        {
            dealloc = 0;
            buf = img_in.bits;
            scan_width = img_in.scan_width;
        }

        // convert palette indices to BGR pixels
        bpp = img_out->bits_per_pixel / 8;
        q0 = img_out->bits;
        for ( p0 = buf; p0 < buf + scan_width * img_in.height;
                    p0 += scan_width, q0 += img_out->scan_width )
        {
            q1 = q0;
            for ( p1 = p0; p1 < p0 + img_in.width; p1++, q1 += bpp )
            {
                memcpy( (void *)q1,
                    (void *)(img_in.palette + *p1 * img_in.bytes_per_palette_entry), 3 );
                if ( bpp == 4 )
                {
                    q1[3] = *p1 == img_in.transparency_index ? 0 : 0xFF;
                }
            }
        }

        if ( dealloc == 1 )
            free( buf );
    }

    return BMG_OK;
}
예제 #3
0
/*
    WritePNG - writes the contents of a BMGImageStruct to a JPEG file.

    Inputs:
        filename    - the name of the file to be opened
        img         - the BMGImageStruct containing the image data

    Returns:
        0 - if the file could not be written or a resource error occurred
        1 - if the file was written

    Comments:
		16-BPP BMG Images are converted to 24-BPP images

    Limitations:
        Color Type is limited to PNG_COLOR_TYPE_GRAY, PNG_COLOR_TYPE_RGB_ALPHA,
        PNG_COLOR_TYPE_RGB, & PNG_COLOR_TYPE_PALETTE;
*/
BMGError WritePNG( const char *filename,
                   struct BMGImageStruct img )
{
    jmp_buf             err_jmp;
    int                 error;

    int                 BitDepth;
    int                 ColorType;
    png_structp         png_ptr = NULL;
    png_infop           info_ptr = NULL;
    png_colorp          PNGPalette = NULL;
    int                 GrayScale;

    unsigned char      *bits, *p, *q;
    unsigned char     **rows = NULL;
    int                 NumColors = 0;

    int                DIBScanWidth;
    int                HasPalette;
    FILE              *outfile = NULL;
    int                i;
	BMGError           tmp;

    /* error handler */
    error = setjmp( err_jmp );
    if ( error != 0 )
    {
        if ( png_ptr != NULL )
            png_destroy_write_struct( &png_ptr, NULL );
        if ( rows )
        {
            if ( rows[0] )
            {
                free( rows[0] );
            }
            free( rows );
        }
        if ( PNGPalette )
            free( PNGPalette );
		if ( outfile)
			fclose( outfile );
        return (BMGError)error;
    }

    /* open the file */
    if ((outfile = fopen(filename, "wb")) == NULL)
        longjmp( err_jmp, (int)errFileOpen );

	/* 16 BPP DIBS do not have palettes.  libPNG expects 16 BPP images to have
	   a palette.  To correct this situation we must convert 16 BPP images to
	   24 BPP images before saving the data to the file */
	if ( img.bits_per_pixel == 16 )
	{
		tmp = Convert16to24( &img ); 
		if (  tmp != BMG_OK )
	        longjmp( err_jmp, (int)tmp );
	}

    HasPalette = img.bits_per_pixel <= 8;
    if ( HasPalette )
    {
        NumColors = img.palette_size;
        /* if this is a grayscale image then set the flag and delete the palette*/
        i = 0;
        bits = img.palette;
        while ( i < NumColors && bits[0] == bits[1] && bits[0] == bits[2] )
        {
            i++;
            bits += img.bytes_per_palette_entry;
        }
        GrayScale = i == NumColors;
    }
    else
        GrayScale = 0;

    /* dimensions */
    DIBScanWidth = ( img.width * img.bits_per_pixel + 7 ) / 8;

    /* create the png pointer */
    png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if ( !png_ptr )
        longjmp( err_jmp, (int)errMemoryAllocation );

    /* create the info pointer */
    info_ptr = png_create_info_struct( png_ptr );
    if ( !info_ptr )
        longjmp( err_jmp, (int)errMemoryAllocation );

    /* bamboozle the png error handler */
	/* error will always == 1 which equals errLib */
//    error = png_setjmp(png_ptr);
    error = setjmp( png_jmpbuf( png_ptr ) );
	if ( error > 0 )
        longjmp( err_jmp, error );

    /* setup the output control */
    png_init_io( png_ptr, outfile );

    /* prepare variables needed to create PNG header */
    BitDepth = img.bits_per_pixel < 8 ? img.bits_per_pixel : 8;

    /* determine color type */
    if ( GrayScale )
        ColorType = PNG_COLOR_TYPE_GRAY;
    else if ( img.bits_per_pixel == 32 )
        ColorType = PNG_COLOR_TYPE_RGB_ALPHA;
    else if ( img.bits_per_pixel == 24 )
        ColorType = PNG_COLOR_TYPE_RGB;
    else
        ColorType = PNG_COLOR_TYPE_PALETTE;

    /* create the PNG header */
    png_set_IHDR( png_ptr, info_ptr, img.width, img.height, BitDepth, ColorType, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE );

    /* store the palette information if there is any */
    if ( img.palette != NULL && !GrayScale )
    {
        PNGPalette = (png_colorp)png_malloc( png_ptr,
                                             NumColors*sizeof(png_color));
        if ( PNGPalette )
        {
            bits = img.palette;
            for ( i = 0; i < NumColors; i++, bits += img.bytes_per_palette_entry )
            {
                PNGPalette[i].red   = bits[2];
                PNGPalette[i].green = bits[1];
                PNGPalette[i].blue  = bits[0];
            }
            png_set_PLTE( png_ptr, info_ptr, PNGPalette, NumColors );
        }
        else
            longjmp( err_jmp, (int)errMemoryAllocation );
    }

    /* write the file header information */
    png_write_info( png_ptr, info_ptr );

    /* create array to store data in */
    rows = (unsigned char **)malloc(sizeof(unsigned char*));
    if ( !rows )
        longjmp( err_jmp, (int)errMemoryAllocation );
    rows[0] = (unsigned char *)malloc( DIBScanWidth * sizeof(unsigned char));
    if ( !rows[0] )
        longjmp( err_jmp, (int)errMemoryAllocation );

    /* point to the bottom row of the DIB data.  DIBs are stored bottom-to-top,
        PNGs are stored top-to-bottom. */
    bits = img.bits + (img.height - 1) * img.scan_width;

    /* store bits */
    for ( i = 0; i < (int)img.height; i++ )
    {
        switch ( img.bits_per_pixel )
        {
            case 1:
            case 4:
            case 8:
                memcpy( (void *)rows[0], (void *)bits, DIBScanWidth );
                break;
            case 24:
                q = bits;
                for ( p = rows[0]; p < rows[0] + DIBScanWidth; p += 3, q += 3 )
                {
                    p[0] = q[2];
                    p[1] = q[1];
                    p[2] = q[0];
                }
                break;
            case 32:
                q = bits;
                for ( p = rows[0]; p < rows[0] + DIBScanWidth; p += 4, q += 4 )
                {
                    p[3] = q[3];
                    p[0] = q[2];
                    p[1] = q[1];
                    p[2] = q[0];
                }
                break;
        }

        png_write_rows( png_ptr, rows, 1 );
        bits -= img.scan_width;
    }

    /* finish writing the rest of the file */
    png_write_end( png_ptr, info_ptr );

    /* clean up and exit */
    if ( PNGPalette )
        free( PNGPalette );
    free( rows[0] );
    free( rows );
    png_destroy_write_struct( &png_ptr, NULL );
    fclose( outfile );

    return BMG_OK;
}