Ejemplo n.º 1
0
/*
// converts a color image to a pseudo-gray scale image.  This is a implementation
// is based upon the code published by Rich Franzen
// <http://rocq.home.att.net/pseudoGrey.html>. I have "simplified" the 2 functions
// he published into a single function.  This implementation creates 1786 gray
// scales from a 24-bit image. 16-BPP images are converted to 24-BPP images.  24
// and 32-BPP images will keep the same bitdepth. Paletted images and 16-BPP images
// are not supported.
//
// This function returns BMK_OK if successfull,
// errInvalidPixelFormat otherwise
*/
BMGError ConvertToPseudoGrayScale( struct BMGImageStruct *img )
{
    unsigned char *p, *p_end;
    unsigned char *q, *q_end;
    unsigned char gray;
    unsigned int bytes_per_pixel;

    SetLastBMGError( errMemoryAllocation );

    if ( img->bits_per_pixel <= 16 )
    {
        SetLastBMGError( errInvalidPixelFormat );
        return errInvalidPixelFormat;
    }

    bytes_per_pixel = img->bits_per_pixel / 8;
    p_end = img->bits + img->scan_width * img->height;

    for ( p = img->bits; p < p_end; p += img->scan_width )
    {
        q_end = p + bytes_per_pixel * img->width;
        for ( q = p; q < q_end; q += bytes_per_pixel )
        {
        /* Rich's code has 1 function that converts an RGB triplet to a float
        // bounded by 0 and 1.  He has a second function that converts a
        // float to a pseudo gray value.  Pseudo gray values are RGB triplets
        // whose red, green and blue values differ by no more than 1.  I have
        // combined these two functions into a single function that simply
        // looks for pseudo gray RGB triplets.  If an RGB triplet meets this
        // criteria, I leave it unchanged; otherwise, I use the common intensity
        // conversion to create a grayscale value */
            unsigned char cmin, cmax;

            cmin = q[0];
            if ( q[1] < cmin )
                cmin = q[1];
            if ( q[2] < cmin )
                cmin = q[2];

            cmax = q[0];
            if ( q[1] > cmax )
                cmax = q[1];
            if ( q[2] > cmax )
                cmax = q[2];

            if ( cmax - cmin > 2 )
            {
                gray = CreateGrayScale( q );
                memset( (void *)q, gray, 3 );
            }
        }
    }

    return BMG_OK;
}
Ejemplo n.º 2
0
/******************************************************************************
// CopyBMG copies the contents of img_in into img_out.
//
// CopyBMG returns BMG_OK if successful, otherwise, it returns an error code
******************************************************************************/
BMGError CopyBMGImage( struct BMGImageStruct img_in,
                       struct BMGImageStruct *img_out )
{
    BMGError out = BMG_OK;
    SetLastBMGError( out );

    FreeBMGImage( img_out );

    img_out->height = img_in.height;
    img_out->width = img_in.width;
    img_out->bits_per_pixel = img_in.bits_per_pixel;
    img_out->palette_size = img_in.palette_size;
    img_out->opt_for_bmp = img_in.opt_for_bmp;

    if ( img_in.width > 0 && img_in.height > 0 )
    {
        out = AllocateBMGImage( img_out );
        if ( out == BMG_OK )
        {
            memcpy( (void *)img_out->bits, (void *)img_in.bits,
                img_in.scan_width * img_in.height );
            if ( img_in.palette_size > 0 )
                memcpy( (void *)img_out->palette, (void *)img_in.palette,
                    img_in.palette_size * img_in.bytes_per_palette_entry );
        }
    }

    return out;
}
Ejemplo n.º 3
0
/* saves the contents of an HBITMAP to a file.  returns 1 if successfull,
                // 0 otherwise */
                BMGError SaveBitmapToPNGFile( HBITMAP hBitmap,      /* bitmap to be saved */
                const char *filename) /* name of output file */
{
    struct BMGImageStruct img;
    char msg[256], ext[4], *period;
    BMGError out = BMG_OK;

    InitBMGImage( &img );

    /* determine the file type by using the extension */
    strcpy( msg, filename );
    period = strrchr( msg, '.' );
    if ( period != NULL )
    {
        period++;
        strcpy( ext, period );
        ext[0] = toupper( ext[0] );
        ext[1] = toupper( ext[1] );
        ext[2] = toupper( ext[2] );
        ext[3] = 0;
    }
    else
    {
        strcat( msg, ".PNG" );
        strcpy( ext, "PNG" );
    }

    if ( strcmp( ext, "PNG" ) == 0 )
    {
/* extract data from the bitmap.  We assume that 32 bit images have been
// blended with the background (unless this is a DDB - see GetDataFromBitmap
        // for more details) */
        out = GetDataFromBitmap( hBitmap, &img, 1 ); 
        if (  out == BMG_OK )
        {
            out = WritePNG( msg, img );
        }
        FreeBMGImage( &img );
    }
    else
    {
        out = errInvalidFileExtension;
    }

    SetLastBMGError( out );
    return out;
}
Ejemplo n.º 4
0
/* Creates an HBITMAP to an image file.  returns an HBITMAP if successfull,
// NULL otherwise */
HBITMAP CreateBitmapFromPNGFile( const char *filename,
                int blend )
{
    char ext[4], msg[256];
    char *period;
    BMGError out = BMG_OK;
    struct BMGImageStruct img;
    HBITMAP hBitmap = NULL;

    InitBMGImage( &img );
    img.opt_for_bmp = 1;

    strcpy( msg, filename );
    period = strrchr( msg, '.' );
    if ( period != NULL )
    {
        period++;
        strncpy( ext, period, 3 );
        ext[0] = toupper( ext[0] );
        ext[1] = toupper( ext[1] );
        ext[2] = toupper( ext[2] );
        ext[3] = 0;
    }
    else
    {
        strcat( msg, ".PNG" );
        strcpy( ext, "PNG" );
    }

    if ( strcmp( ext, "PNG" ) == 0 )
    {
        out = ReadPNG( msg, &img ); 
        if (  out == BMG_OK )
        {
            hBitmap = CreateBitmapFromData( img, blend );
        }
        FreeBMGImage( &img );
    }
    else
    {
        out = errInvalidFileExtension;
    }

    SetLastBMGError( out );
    return hBitmap;
}
Ejemplo n.º 5
0
/*
    ReadBMP - reads the image data from a BMP files and stores it in a
              BMGImageStruct.

    Inputs:
        filename    - the name of the file to be opened

    Outputs:
        img         - the BMGImageStruct containing the image data

    Returns:
        BMGError - if the file could not be read or a resource error occurred
        BMG_OK   - if the file was read and the data was stored in img

    Limitations:
        will not read BMP files using BI_RLE8, BI_RLE4, or BI_BITFIELDS
*/
BMGError ReadBMP( const char *filename,
              struct BMGImageStruct *img )
{
    FILE *file = NULL;
    int error;
    BMGError tmp;
    unsigned char *p, *q; /*, *q_end; */
/*    unsigned int cnt; */
    int i;
/*    int EOBMP; */

    BITMAPFILEHEADER bmfh;
    BITMAPINFOHEADER bmih;
/*
    unsigned int mask[3];
*/

    unsigned int DIBScanWidth;
    unsigned int bit_size, rawbit_size;
    unsigned char *rawbits = NULL;

    SetLastBMGError( BMG_OK );

    if ( img == NULL )
        { error = (int) errInvalidBMGImage; goto err_jmp; }


    file = fopen( filename, "rb" );
    if  ( file == NULL )
        { error = (int) errFileOpen; goto err_jmp; }

        /* read the file header */
    if ( fread( (void *)&bmfh, sizeof(BITMAPFILEHEADER), 1, file ) != 1 )
        { error = (int) errFileRead; goto err_jmp; }

    /* confirm that this is a BMP file */
    if ( bmfh.bfType != BMP_ID )
        { error = (int) errUnsupportedFileFormat; goto err_jmp; }

    /* read the bitmap info header */
    if ( fread( (void *)&bmih, sizeof(BITMAPINFOHEADER), 1, file ) != 1 )
        { error = (int) errFileRead; goto err_jmp; }

    /* abort if this is an unsupported format */
    if ( bmih.biCompression != BI_RGB )
        { printf("planes: %i  bits: %i  type: %i   ", bmih.biPlanes, bmih.biBitCount, bmih.biCompression); error = (int) errUnsupportedFileFormat; goto err_jmp; }

    img->bits_per_pixel = (unsigned char)bmih.biBitCount;
    img->width  = bmih.biWidth;
    img->height = bmih.biHeight;
    if ( img->bits_per_pixel <= 8 )
    {
        img->palette_size = (unsigned short)bmih.biClrUsed;
        img->bytes_per_palette_entry = 4U;
    }

    tmp = AllocateBMGImage( img );
    if ( tmp != BMG_OK )
        { error = (int) tmp; goto err_jmp; }

    /* read palette if necessary */
    if ( img->bits_per_pixel <= 8 )
    {
        if ( fread( (void *)img->palette, sizeof(RGBQUAD), img->palette_size,
                file ) != (unsigned int)img->palette_size )
        {
          error = (int) errFileRead;
          goto err_jmp;
        }
    }

    /* dimensions */
    DIBScanWidth = ( img->bits_per_pixel * img->width + 7 ) / 8;
    if ( DIBScanWidth %4 )
        DIBScanWidth += 4 - DIBScanWidth % 4;

    bit_size = img->scan_width * img->height;

    /* allocate memory for the raw bits */
    if ( bmih.biCompression != BI_RGB )
        rawbit_size = bmfh.bfSize - bmfh.bfOffBits;
    else
        rawbit_size = DIBScanWidth * img->height;

    rawbits = (unsigned char *)calloc( rawbit_size, 1 );
    if ( rawbits == NULL )
        { error = (int) errMemoryAllocation; goto err_jmp; }

    if ( fread( (void *)rawbits, sizeof(unsigned char), rawbit_size, file )
                   != rawbit_size )
    {
        error = (int) errFileRead;
        goto err_jmp;
    }

    if ( bmih.biCompression == BI_RGB )
    {
        p = rawbits;
        for ( q = img->bits; q < img->bits + bit_size;
                         q += img->scan_width, p += DIBScanWidth )
        {
            memcpy( (void *)q, (void *)p, img->scan_width );
        }
    }

    /* swap rows if necessary */
    if ( bmih.biHeight < 0 )
    {
        for ( i = 0; i < (int)(img->height) / 2; i++ )
        {
            p = img->bits + i * img->scan_width;
            q = img->bits + ((img->height) - i - 1 ) * img->scan_width;
            memcpy( (void *)rawbits, (void *)p, img->scan_width );
            memcpy( (void *)p, (void *)q, img->scan_width );
            memcpy( (void *)q, (void *)rawbits, img->scan_width );
        }
    }

    fclose( file );
    free( rawbits );
    return BMG_OK;

  /* error handler */
err_jmp:
    if ( file != NULL )
        fclose( file );
    if ( rawbits != NULL )
        free( rawbits );
    FreeBMGImage( img );
    SetLastBMGError( (BMGError)error );
    return (BMGError)error;

}
Ejemplo n.º 6
0
/*
    WriteBMP - writes the contents of an BMGImageStruct to a bmp file.

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

    Returns:
        BMGError - if a write error or a resource error occurred
        BMG_OK   - if the data was successfilly stored in filename

    Limitations:
        will not write BMP files using BI_RLE8, BI_RLE4, or BI_BITFIELDS
*/
BMGError WriteBMP( const char *filename,
                   struct BMGImageStruct img )
{
    FILE * volatile file = NULL;
    jmp_buf err_jmp;
    int error;

    unsigned char * volatile bits = NULL;
    unsigned int DIBScanWidth;
    unsigned int BitsPerPixel;
    unsigned int bit_size; /*, new_bit_size; */
/*    unsigned int rawbit_size; */
    unsigned char *p, *q, *r, *t;
/*    unsigned int cnt;  */
    unsigned char * volatile pColor = NULL;

    BITMAPFILEHEADER bmfh;
    BITMAPINFOHEADER bmih;

    SetLastBMGError( BMG_OK );

    /* error handler */
    error = setjmp(err_jmp);
    if (error != 0)
    {
        if (file != NULL)
            fclose(file);
        if (bits != NULL)
            free(bits);
        if (pColor != NULL)
            free(pColor);
        SetLastBMGError((BMGError)error);
        return (BMGError) error;
    }

    if ( img.bits == NULL )
        longjmp( err_jmp, (int)errInvalidBMGImage );

    file = fopen( filename, "wb" );
    if ( file == NULL )
        longjmp( err_jmp, (int)errFileOpen );

    /* abort if we do not support the data */
    if ( img.palette != NULL && img.bytes_per_palette_entry < 3 )
        longjmp( err_jmp, (int)errInvalidBMGImage );

    /* calculate dimensions */
    BitsPerPixel = img.bits_per_pixel < 32 ? img.bits_per_pixel : 24U;
    DIBScanWidth = ( BitsPerPixel * img.width + 7 ) / 8;
    if ( DIBScanWidth % 4 )
        DIBScanWidth += 4 - DIBScanWidth % 4;
    bit_size = DIBScanWidth * img.height;
/*    rawbit_size = BITScanWidth * img.height; */

    /* allocate memory for bit array - assume that compression will
    // actually compress the bitmap */
    bits = (unsigned char *)calloc( bit_size, 1 );
    if ( bits == NULL )
        longjmp( err_jmp, (int)errMemoryAllocation );

    /* some initialization */
    memset( (void *)&bmih, 0, sizeof(BITMAPINFOHEADER) );
    bmih.biSize = sizeof(BITMAPINFOHEADER);
    bmih.biWidth = img.width;
    bmih.biHeight = img.height;
    bmih.biPlanes = 1;
    /* 32-bit images will be stored as 24-bit images to save space.  The BMP
       format does not use the high word and I do not want to store alpha
       components in an image format that does not recognize it */
    bmih.biBitCount = BitsPerPixel;
    bmih.biCompression = BI_RGB; // assumed
    bmih.biSizeImage = bit_size; // assumed
    bmih.biClrUsed = img.palette == NULL ? 0 : img.palette_size;
    bmih.biClrImportant = img.palette == NULL ? 0 : img.palette_size;

    /* if we are not compressed then copy the raw bits to bits */
    if ( bmih.biCompression == BI_RGB )
    {
        p = img.bits;
        /* simple memcpy's for images containing < 32-bits per pixel */
        if ( img.bits_per_pixel < 32 )
        {
            for ( q = bits; q < bits + bit_size; q += DIBScanWidth,
                                                 p += img.scan_width )
            {
                memcpy( (void *)q, (void *)p, img.scan_width );
            }
        }
        /* store 32-bit images as 24-bit images to save space. alpha terms
           are lost */
        else
        {
            DIBScanWidth = 3 * img.width;
            if ( DIBScanWidth % 4 )
                DIBScanWidth += 4 - DIBScanWidth % 4;

            for ( q = bits; q < bits + bit_size; q += DIBScanWidth,
                                                 p += img.scan_width )
            {
                t = p;
                for ( r = q; r < q + DIBScanWidth; r += 3, t += 4 )
                    memcpy( (void *)r, (void *)t, 3 );
            }
        }
    }

    /* create the palette if necessary */
    if ( img.palette != NULL )
    {
        pColor = (unsigned char *)calloc( img.palette_size, sizeof(RGBQUAD) );
        if ( pColor == NULL )
            longjmp( err_jmp, (int)errMemoryAllocation );

        if ( img.bytes_per_palette_entry == 3 )
        {
            p = img.palette;
            for ( q = pColor + 1; q < pColor +img.palette_size*sizeof(RGBQUAD);
                            q += sizeof(RGBQUAD), p += 3 )
            {
                memcpy( (void *)pColor, (void *)p, 3 );
            }
        }
        else /* img.bytes_per_palette_entry == 4 */
        {
            memcpy( (void *)pColor, (void *)img.palette,
                img.palette_size * sizeof(RGBQUAD) );
        }
    }

    /* now that we know how big everything is let's write the file */
    memset( (void *)&bmfh, 0, sizeof(BITMAPFILEHEADER) );
    bmfh.bfType = BMP_ID;
    bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
                     img.palette_size * sizeof(RGBQUAD);
    bmfh.bfSize = bmfh.bfOffBits + bit_size;

    if ( fwrite( (void *)&bmfh, sizeof(BITMAPFILEHEADER), 1, file ) != 1 )
        longjmp( err_jmp, (int)errFileWrite );

    if ( fwrite( (void *)&bmih, sizeof(BITMAPINFOHEADER), 1, file ) != 1 )
        longjmp( err_jmp, (int)errFileWrite );

    if ( pColor != NULL )
    {
        if ( fwrite( (void *)pColor, sizeof(RGBQUAD), img.palette_size, file )
                              != (unsigned int)img.palette_size )
        {
            longjmp( err_jmp, (int)errFileWrite );
        }
    }

    if ( fwrite( (void *)bits, sizeof(unsigned char), bit_size, file )
                    != bit_size )
    {
        longjmp( err_jmp, (int)errFileWrite );
    }

    fclose( file );
    free( bits );
    if ( pColor != NULL )
        free( pColor );
    return BMG_OK;
}
Ejemplo n.º 7
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;
}
Ejemplo n.º 8
0
/* allocates memory for the bits & palette.  Assigned values to scan_line
   & bits_per_palette_entry as well.  Assumes opt_for_bmp has been set before
   this function is called. Assumes that all images with bits_per_pixel <= 8
   require a palette.
 */
BMGError AllocateBMGImage( struct BMGImageStruct *img )
{
    unsigned int mempal;

    SetLastBMGError( BMG_OK );

    /* make sure that all REQUIRED parameters are valid */
    if ( img->width * img->height <= 0 )
    {
        SetLastBMGError(errInvalidSize);
        return errInvalidSize;
    }

    switch( img->bits_per_pixel )
    {
        case  1:
        case  4:
        case  8:
        case 16:
        case 24:
        case 32:
            break;
        default:
            SetLastBMGError( errInvalidPixelFormat );
            return errInvalidPixelFormat;
    }

    /* delete old memory */
    if ( img->bits != NULL )
    {
        free( img->bits );
        img->bits = NULL;
    }
    if ( img->palette != NULL )
    {
        free( img->palette );
        img->palette = NULL;
    }

    /* allocate memory for the palette */
    if ( img->bits_per_pixel <= 8 )
    {
        if ( img->opt_for_bmp > 0 )
            img->bytes_per_palette_entry = 4U;
        else
        {
            /* we only support 3-byte and 4-byte palettes */
            if ( img->bytes_per_palette_entry <= 3U )
                img->bytes_per_palette_entry = 3U;
            else
                img->bytes_per_palette_entry = 4U;
        }
        /*
           use bits_per_pixel to determine palette_size if none was
           specified
        */
        if ( img->palette_size == 0 )
            img->palette_size = (unsigned short)(1 << img->bits_per_pixel);

        mempal = img->bytes_per_palette_entry * img->palette_size;
        img->palette = (unsigned char *)calloc( mempal, sizeof(unsigned char) );
        if ( img->palette == NULL )
        {
            SetLastBMGError(errMemoryAllocation);
            return errMemoryAllocation;
        }
    }
    else
    {
        img->bytes_per_palette_entry = 0;
        img->palette_size = 0;
    }

    /*
       set the scan width.  Bitmaps optimized for windows have scan widths that
       are evenly divisible by 4.
    */
    img->scan_width = ( img->bits_per_pixel * img->width + 7 ) / 8;
    if ( img->opt_for_bmp && img->scan_width % 4 )
        img->scan_width += 4 - img->scan_width % 4;

    /* allocate memory for the bits */
    mempal = img->scan_width * img->height;
    if ( mempal > 0 )
    {
        img->bits = (unsigned char *)calloc( mempal, sizeof( unsigned char) );
        if ( img->bits == NULL )
        {
            if ( img->palette != NULL )
            {
                free( img->palette );
                img->palette = NULL;
            }
            SetLastBMGError(errMemoryAllocation);
            return errMemoryAllocation;
        }
    }
    else
    {
        SetLastBMGError(errInvalidSize);
        return errInvalidSize;
    }

    return BMG_OK;
}
Ejemplo n.º 9
0
/*******************************************************************************
// this function creates a bitmap from raw data. Returns an HBITMAP if it
// succeeds, otherwise NULL */
HBITMAP CreateBitmapFromData( struct BMGImageStruct img,
                              int alpha_blend )
{
    HBITMAP hBitmap = NULL;
    HDC hMemDC = NULL;
    HWND hWnd = GetForegroundWindow();
    HDC hDC = NULL;
    RGBQUAD *pColor = NULL;
    BITMAPINFO bmi;
    unsigned char *rbits;
    unsigned char *bits;
    unsigned char *lpBits;
    unsigned char alpha;
    unsigned int DIBScanWidth;
    int i;

    jmp_buf err_jmp;
    int error;

    /* error handler */
    error = setjmp( err_jmp );
    if ( error != 0 )
    {
        if ( hMemDC != NULL )
            DeleteDC( hMemDC );
        if ( hDC != NULL )
            ReleaseDC( hWnd, hDC );
        if ( pColor != NULL && img.bytes_per_palette_entry == 3U )
            free( pColor );
        SetLastBMGError( (BMGError)error );
        return 0;
    }

    SetLastBMGError( BMG_OK );

    /* create the DIB section that will hold this bitmap */
    bmi = InternalCreateBMI( (unsigned int)img.width, (unsigned int)img.height,
                              (unsigned short)img.bits_per_pixel, BI_RGB );
    bmi.bmiHeader.biClrUsed = bmi.bmiHeader.biClrImportant =
         img.palette_size;
    hDC = GetDC( hWnd );
    hBitmap = CreateDIBSection( hDC, &bmi, DIB_RGB_COLORS,
                                   (void **)&lpBits, NULL, 0 );

    if ( !hBitmap || !lpBits )
        longjmp( err_jmp, (int)errWindowsAPI );

    /* create a palette if needed */
    if ( img.palette != NULL )
    {
        /* copy pixel data to pColor */
        if ( img.bytes_per_palette_entry == 4U )
            pColor = (RGBQUAD *)img.palette;
        else /* bytes_per_palette_entry === 3 */
        {
            pColor = (RGBQUAD *)calloc(img.palette_size, sizeof(RGBQUAD) );
            if ( pColor == NULL )
                longjmp( err_jmp, (int)errMemoryAllocation );

            bits = img.palette;
            for ( i = 0; i < (int)bmi.bmiHeader.biClrUsed; i++, bits += 3 )
            {
                pColor[i].rgbRed   = bits[0];
                pColor[i].rgbGreen = bits[1];
                pColor[i].rgbBlue  = bits[2];
            }
        }

        if ( img.transparency_index > -1 )
        {
            unsigned char *color = GetBackgroundColor();
            rbits = img.palette + img.bytes_per_palette_entry *
                    img.transparency_index;
            rbits[0] = color[2];
            rbits[1] = color[1];
            rbits[2] = color[0];
        }
        /* save color table in bitmap */
        hMemDC = CreateCompatibleDC( hDC );
        SelectObject( hMemDC, hBitmap );
        if ( !SetDIBColorTable( hMemDC, 0, img.palette_size, pColor ) )
            longjmp( err_jmp, (int)errWindowsAPI );

        DeleteDC( hMemDC );
        hMemDC = NULL;
        if ( img.bytes_per_palette_entry == 3U )
            free( pColor );
        pColor = NULL;
    }

    /* calculate the scan line width */
    DIBScanWidth = img.scan_width;
    if ( DIBScanWidth % 4 )
        DIBScanWidth += 4 - DIBScanWidth % 4;

    if ( img.opt_for_bmp == 0 )
    {
        /* store bits into hBitmap */
        rbits = img.bits;
        for ( bits = lpBits;
              bits < lpBits + img.height * DIBScanWidth;
              bits += DIBScanWidth, rbits += img.scan_width )
        {
            memcpy( (void *)bits, (void *)rbits, img.scan_width );
        }
    }
    else
        memcpy( (void *)lpBits, (void *)img.bits, img.scan_width * img.height );

    /* blend the image with the window background if alpha pixels
    // are present */
    if ( img.bits_per_pixel == 32 )
    {
        /* blend with a bland background */
        if ( alpha_blend == 1 )
        {
            unsigned char *color = GetBackgroundColor();
            unsigned char red   = color[2];
            unsigned char green = color[1];
            unsigned char blue  = color[0];

            for ( rbits = lpBits;
                  rbits < lpBits + img.height*DIBScanWidth;
                  rbits += DIBScanWidth )
            {
                for ( bits = rbits; bits < rbits + DIBScanWidth; bits += 4 )
                {
                    alpha = bits[3];
                    bits[2] = AlphaComp( bits[2], alpha, blue );
                    bits[1] = AlphaComp( bits[1], alpha, green );
                    bits[0] = AlphaComp( bits[0], alpha, red );
                }
            }
        }
        /* blend with a background image */
        else if ( alpha_blend == 2 )
        {
            unsigned char *bg_bits;
            unsigned char *bg_bits_2;
            unsigned int bg_bytes_per_pixel;
            struct BMGImageStruct *bg = GetBackgroundImage();

            /* make sure we can blend with a background image
            // I assume that the background image is invalid if it does not
            // have a valid width */
            if ( bg->width <= 0 || bg->height <= 0 )
                longjmp( err_jmp, (int)errUndefinedBGImage );

            /* I cannot blend a foreground image with a background image that
            // is smaller than it */
            if ( bg->width < img.width || bg->height < img.height )
                longjmp( err_jmp, (int)errBGImageTooSmall );

            /* the background image was forced to be a 24 or 32-BPP image;
            // therefore, we can safely divide by 8 to determined the
            // bytes per pixel*/
            bg_bytes_per_pixel = bg->bits_per_pixel / 8;

            /* I will assume that the upper left corner of the input image
            // must be aligned with the upper left corner of the background
            // image.  This allows me to have background images that are bigger
            // than the input image. */
            bg_bits = bg->bits;
            for ( rbits = lpBits;
                  rbits < lpBits + img.height*DIBScanWidth;
                  rbits += DIBScanWidth, bg_bits += bg->scan_width )
            {
                bg_bits_2 = bg_bits;
                for ( bits = rbits; bits < rbits + DIBScanWidth;
                      bits += 4, bg_bits_2 += bg_bytes_per_pixel )
                {
                    alpha = bits[3];
                    bits[2] = AlphaComp( bits[2], alpha, bg_bits_2[2] );
                    bits[1] = AlphaComp( bits[1], alpha, bg_bits_2[1] );
                    bits[0] = AlphaComp( bits[0], alpha, bg_bits_2[0] );
                }
            }

        }
    }

    ReleaseDC( hWnd, hDC );

    return hBitmap;
}
Ejemplo n.º 10
0
/*******************************************************************************
// extracts the dimensional information, pixel array, and color table from an
// HBITMAP.
// hBitmap can be a handle to a DIB or a DDB.  This function assumes that DDBs
// will not have a palette.  If you create a DDB on a 256-color graphics card,
// then the DDB will have a palette and this function will fail.
//
// returns BMK_OK if successfull, and error state otherwise.
********************************************************************************/
BMGError GetDataFromBitmap( HBITMAP hBitmap,
                            struct BMGImageStruct *img,
                            int remove_alpha )
{
    unsigned int        DIBScanWidth;
    DIBSECTION          DS;
    HWND                hWnd = GetForegroundWindow();
    HDC                 hDC = NULL;
    HDC                 hMemDC = NULL;
    unsigned char       red, green, blue;
    int                 FreelpBits = 0;
    unsigned int        numBytes;
    size_t              soDIBSECTION = sizeof(DIBSECTION);
    size_t              soBITMAP = sizeof(BITMAP);

    unsigned char *p, *q, *lpBits, alpha;

    jmp_buf err_jmp;
    int error;
    BMGError bmgerr;

    /* error handler */
    error = setjmp( err_jmp );
    if ( error != 0 )
    {
        if ( hMemDC != NULL )
            DeleteDC( hMemDC );
        if ( hDC != NULL )
            ReleaseDC( hWnd, hDC );
        if ( FreelpBits )
            free( lpBits );
        FreeBMGImage( img );
        SetLastBMGError( (BMGError)error );
        return (BMGError)error;
    }

    SetLastBMGError( BMG_OK );
    /* check for valid bitmap*/
    if ( !hBitmap )
        longjmp( err_jmp, (int)errInvalidBitmapHandle );

    /* Extract DIBSECTION info from the HBITMAP.  numBytes will equal
    // soDIBSECTION (84) if hBitmap is a handle to a DIBSECTION (DIB).
    // numBytes will equal soBITMAP (24) if hBitmap is a handle to a
    // BITMAP (DDB). */
    numBytes = GetObject( hBitmap, sizeof(DIBSECTION), &DS );
    if ( numBytes == 0 )
        longjmp( err_jmp, (int)errWindowsAPI );

    img->opt_for_bmp = 1;
    if ( numBytes == soDIBSECTION )
    {
        img->width = DS.dsBmih.biWidth;
        img->height = DS.dsBmih.biHeight;
        img->bits_per_pixel = (unsigned char)DS.dsBmih.biBitCount;
        if ( img->bits_per_pixel <= 8 && DS.dsBmih.biClrUsed > 0 )
            img->palette_size = (unsigned short)DS.dsBmih.biClrUsed;
        lpBits = (unsigned char *)DS.dsBm.bmBits;
    }
    /* this may be a DDB which must be handled differently */
    else if ( numBytes == soBITMAP )
    {
        BITMAP bm;
        BITMAPINFO bmi;

        if ( GetObject( hBitmap, sizeof(BITMAP), &bm ) == 0 )
            longjmp( err_jmp, (int)errWindowsAPI );

        /* DDB with a palette */
        if ( bm.bmBitsPixel <= 8 )
            longjmp( err_jmp, (int)errInvalidPixelFormat );

        img->width = bm.bmWidth;
        img->height = bm.bmHeight;
        img->bits_per_pixel = (unsigned char)bm.bmBitsPixel;
        bmi = InternalCreateBMI( bm.bmWidth, bm.bmHeight, bm.bmBitsPixel,
                                 BI_RGB );

        lpBits = (unsigned char *)calloc( bm.bmHeight * bm.bmWidthBytes,
                                          sizeof(unsigned char) );
        if ( lpBits == 0 )
            longjmp( err_jmp, (int)errMemoryAllocation );
        FreelpBits = 1;
        hDC = GetDC( hWnd );
        if ( GetDIBits(hDC, hBitmap, 0, bm.bmHeight, (void *)lpBits, &bmi,
                       DIB_RGB_COLORS ) == 0 )
            longjmp( err_jmp, (int)errWindowsAPI );
        ReleaseDC( hWnd, hDC );
        hDC = NULL;
    }
    else /* I have no idea what this is */
        longjmp( err_jmp, (int)errInvalidBitmapHandle );

    /* allocate memory */
    bmgerr = AllocateBMGImage( img );
    if ( bmgerr != BMG_OK )
        longjmp( err_jmp, (int)bmgerr );

    /* dimensions */
    DIBScanWidth = ( img->width * img->bits_per_pixel + 7 )/8;
    if ( DIBScanWidth % 4 )
        DIBScanWidth += 4 - DIBScanWidth % 4;

    p = img->bits;
    for ( q = lpBits; q < lpBits + DIBScanWidth * img->height;
            p += img->scan_width, q += DIBScanWidth )
    {
        memcpy( (void *)p, (void *)q, DIBScanWidth );
    }

    /* "un-blend" the image if requested.  NOTE: unblending only works with
    // bland backgrounds */
    if ( remove_alpha > 0 &&
         img->bits_per_pixel == 32 &&
         numBytes == soDIBSECTION )
    {
        unsigned char *color = GetBackgroundColor();
        red   = color[2];
        green = color[1];
        blue  = color[0];

        for ( p = img->bits; p < img->bits + img->scan_width * img->height;
              p += 4 )
        {
            alpha = p[3];
            p[2] = InverseAlphaComp( p[2], alpha, blue);
            p[1] = InverseAlphaComp( p[1], alpha, green);
            p[0] = InverseAlphaComp( p[0], alpha, red);
        }
    }

    /* 32-bit DDBs must have the alpha channel set to 0xFF before they are
    // saved to a file. This may not be true for all devices that generate
    // 32-bit DDBs.  I have only created 32-bit DDBs using an Intense3D Wildcat
    // 4110 card.  The alpha channel was always 0. */
    if (img->bits_per_pixel == 32 && numBytes == soBITMAP )
    {
        for ( p = img->bits + 3; p < img->bits + img->scan_width * img->height;
                                 p += 4 )
        {
            *p = 0xFF;
        }
    }

    /* create palette if necessary */
    if ( img->bits_per_pixel <= 8 )
    {
        hDC = GetDC( hWnd );
        hMemDC = CreateCompatibleDC( hDC );
        SelectObject( hMemDC, hBitmap );
        if ( !GetDIBColorTable( hMemDC, 0, img->palette_size,
                                (RGBQUAD *)img->palette ) )
        {
            longjmp( err_jmp, (int)errWindowsAPI );
        }
        DeleteDC( hMemDC );
        ReleaseDC( hWnd, hDC );
    }

    if ( FreelpBits )
        free( lpBits );

    return BMG_OK;
}
Ejemplo n.º 11
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;
}
Ejemplo n.º 12
0
/*******************************************************************************
 A utility function for compressing paletted images.  Will automatically
 convert 8-bit paletted images to 1-bit or 4-bit paletted images based
 upon palette_size.  Assumes that indices in img->bits are valid.  That is,
 0 <= img->bits[i] <= 1 for all i if 1-bit compression is desired, and
 0 <= img->bits[i] <= 15 for all i if 4-bit compression is desired  Returns
 BMG_OK if successful, or an error code otherwise.
*******************************************************************************/
BMGError CompressBMGImage( struct BMGImageStruct *img )
{
    unsigned char new_bits_per_pixel;
    unsigned int new_scan_width;
    unsigned char *new_bits = NULL;
    unsigned int new_bit_size;
    unsigned char *new_row, *old_row, *p, *q;
    unsigned char *end;
    unsigned short scale;

    SetLastBMGError( BMG_OK );

    /* if we cannot compress it then do no harm and return "true" */
    if ( img->palette == NULL ||
         img->palette_size > 16 ||
         img->bits_per_pixel != 8 )
    {
        return BMG_OK;
    }

    /* calculate new dimensions */
    new_bits_per_pixel = img->palette_size <= 2 ? 1U : 4U;
    new_scan_width = ( new_bits_per_pixel * img->width + 7 ) / 8;
    if ( img->opt_for_bmp > 0 && new_scan_width % 4 )
        new_scan_width += 4 - new_scan_width % 4;
    new_bit_size = new_scan_width * img->height;

    /* allocate & test memory */
    new_bits = (unsigned char *)calloc( new_bit_size, sizeof(unsigned char) );
    if ( new_bits == NULL )
    {
        SetLastBMGError( errMemoryAllocation );
        return errMemoryAllocation;
    }

    old_row = img->bits;
    for ( new_row = new_bits; new_row < new_bits + new_bit_size;
          new_row += new_scan_width, old_row += img->scan_width )
    {
        scale = 8 / new_bits_per_pixel;
        end = new_row + img->width / scale;
        p = old_row;
        if ( new_bits_per_pixel == 1 )
        {
            for ( q = new_row; q < end; q++, p += scale )
            {
                *q = (unsigned char)( (p[0] << 7) | (p[1] << 6) |
                                      (p[2] << 5) | (p[3] << 4) |
                                      (p[4] << 3) | (p[5] << 2) |
                                      (p[6] << 1) | p[7] );
            }
            scale = img->width % scale;
            if  ( scale-- > 0 )
            {
                *q = (unsigned char)(p[0] << 7);
                if ( scale-- )
                {
                    *q |= (unsigned char)(p[1] << 6);
                    if ( scale-- )
                    {
                        *q |= (unsigned char)(p[2] << 5);
                        if ( scale-- )
                        {
                            *q |= (unsigned char)(p[3] << 4);
                            if ( scale-- )
                            {
                                *q |= (unsigned char)(p[4] << 3);
                                if ( scale-- )
                                {
                                    *q |= (unsigned char)(p[5] << 2);
                                    if ( scale-- )
                                        *q |= (unsigned char)(p[6] << 1);
                                }
                            }
                        }
                    }
                }
            }
        }
        else /* new_bits_per_pixel == 4 */
        {
            for ( q = new_row; q < end; q++, p += scale )
            {
                *q = (unsigned char)( (p[0] << 4) | (p[1] & 0x0F) );
            }
            if  ( img->width % scale )
                *q = (unsigned char)(p[0] << 4);
        }
    }

    /* replace old values with new values */
    free( img->bits );
    img->bits = new_bits;
    img->scan_width = new_scan_width;
    img->bits_per_pixel = new_bits_per_pixel;

    return BMG_OK;
}
Ejemplo n.º 13
0
/*
ReadPNG - Reads the contents of a PNG file and stores the contents into
    BMGImageStruct

Inputs:
    filename    - the name of the file to be opened

Outputs:
    img         - the BMGImageStruct containing the image data

Returns:
    BMGError - if the file could not be read or a resource error occurred
    BMG_OK   - if the file was read and the data was stored in img

Limitations:
    None.

Comments:
    2-bit images are converted to 4-bit images.
    16-bit images are converted to 8-bit images.
    gray scale images with alpha components are converted to 32-bit images
*/
BMGError ReadPNG( const char *filename,
        struct BMGImageStruct * volatile img )
{
    jmp_buf             err_jmp;
    int                 error;

    FILE * volatile     file = NULL;
    int                 BitDepth;
    int                 ColorType;
    int                 InterlaceType;
    unsigned char       signature[8];
    png_structp volatile png_ptr = NULL;
    png_infop   volatile info_ptr = NULL;
    png_infop   volatile end_info = NULL;
    png_color_16       *ImageBackground = NULL;
    png_bytep           trns = NULL;
    int                 NumTrans = 0;
    int                 i, k;
    png_color_16p       TransColors = NULL;
    png_uint_32         Width, Height;

    unsigned char      *bits;
    unsigned char** volatile rows = NULL;

    BMGError tmp;

    /* error handler */
    error = setjmp( err_jmp );
    if (error != 0)
    {
        if (end_info != NULL)
            png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, (png_infop *) &end_info);
        else if (info_ptr != NULL)
            png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, NULL);
        else if (png_ptr != NULL)
            png_destroy_read_struct((png_structp *) &png_ptr, NULL, NULL);
        if (rows)
        {
            if (rows[0])
                free(rows[0]);
            free(rows);
        }
        if (img)
            FreeBMGImage(img);
        if (file)
            fclose(file);
        SetLastBMGError((BMGError) error);
        return (BMGError) error;
    }

    if ( img == NULL )
        longjmp ( err_jmp, (int)errInvalidBMGImage );

    file = fopen( filename, "rb" );
    if ( !file || fread( signature, 1, 8, file ) != 8)
        longjmp ( err_jmp, (int)errFileOpen );

    /* check the signature */
    if ( png_sig_cmp( signature, 0, 8 ) != 0 )
        longjmp( err_jmp, (int)errUnsupportedFileFormat );

    /* create a pointer to the png read structure */
    png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL );
    if ( !png_ptr )
        longjmp( err_jmp, (int)errMemoryAllocation );

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

    /* create a pointer to the png end-info structure */
    end_info = png_create_info_struct(png_ptr);
    if (!end_info)
        longjmp( err_jmp, (int)errMemoryAllocation );

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

    /* set function pointers in the PNG library, for read callbacks */
    png_set_read_fn(png_ptr, (png_voidp) file, user_read_data);

    /*let the read functions know that we have already read the 1st 8 bytes */
    png_set_sig_bytes( png_ptr, 8 );

    /* read all PNG data up to the image data */
    png_read_info( png_ptr, info_ptr );

    /* extract the data we need to form the HBITMAP from the PNG header */
    png_get_IHDR( png_ptr, info_ptr, &Width, &Height, &BitDepth, &ColorType,
        &InterlaceType, NULL, NULL);

    img->width = (unsigned int) Width;
    img->height = (unsigned int) Height;

    img->bits_per_pixel = (unsigned char)32;
    img->scan_width = Width * 4;

    /* convert 16-bit images to 8-bit images */
    if (BitDepth == 16)
        png_set_strip_16(png_ptr);

    /* These are not really required per Rice format spec,
     * but is done just in case someone uses them.
     */
    /* convert palette color to rgb color */
    if (ColorType == PNG_COLOR_TYPE_PALETTE) {
        png_set_palette_to_rgb(png_ptr);
        ColorType = PNG_COLOR_TYPE_RGB;
    }

    /* expand 1,2,4 bit gray scale to 8 bit gray scale */
    if (ColorType == PNG_COLOR_TYPE_GRAY && BitDepth < 8)
        png_set_expand_gray_1_2_4_to_8(png_ptr);

    /* convert gray scale or gray scale + alpha to rgb color */
    if (ColorType == PNG_COLOR_TYPE_GRAY ||
        ColorType == PNG_COLOR_TYPE_GRAY_ALPHA) {
        png_set_gray_to_rgb(png_ptr);
        ColorType = PNG_COLOR_TYPE_RGB;
    }

    /* add alpha channel if any */
    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
        png_set_tRNS_to_alpha(png_ptr);
        ColorType = PNG_COLOR_TYPE_RGB_ALPHA;
    }

    /* convert rgb to rgba */
    if (ColorType == PNG_COLOR_TYPE_RGB) {
        png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
        ColorType = PNG_COLOR_TYPE_RGB_ALPHA;
    }

    png_set_bgr(png_ptr);

    /* set the background color if one is found */
    if ( png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD) )
        png_get_bKGD(png_ptr, info_ptr, &ImageBackground);

    /* get the transparent color if one is there */
    if ( png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS ) )
        png_get_tRNS( png_ptr, info_ptr, &trns, &NumTrans, &TransColors );

    img->palette_size = (unsigned short)0;
    img->bytes_per_palette_entry = 4U;

    tmp = AllocateBMGImage( img );
    if ( tmp != BMG_OK )
        longjmp( err_jmp, (int)tmp );

    png_read_update_info( png_ptr, info_ptr );

    /* create buffer to read data to */
    rows = (unsigned char **)malloc(Height*sizeof(unsigned char *));
    if ( !rows )
        longjmp( err_jmp, (int)errMemoryAllocation );

    k = png_get_rowbytes( png_ptr, info_ptr );
    rows[0] = (unsigned char *)malloc( Height*k*sizeof(char));
    if ( !rows[0] )
        longjmp( err_jmp, (int)errMemoryAllocation );

    for ( i = 1; i < (int)Height; i++ )
        rows[i] = rows[i-1] + k;

    /* read the entire image into rows */
    png_read_image( png_ptr, rows );

    bits = img->bits + (Height - 1) * img->scan_width;
    for ( i = 0; i < (int)Height; i++ )
    {
        memcpy(bits, rows[i], 4*Width);
        bits -= img->scan_width;
    }

    free( rows[0] );
    free( rows );
    png_read_end( png_ptr, info_ptr );
    png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, (png_infop *) &end_info);
    fclose( file );

    return BMG_OK;
}
Ejemplo n.º 14
0
/*
WritePNG - writes the contents of a BMGImageStruct to a PNG 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 = 0;
    int     BitDepth = 0;
    int     ColorType = 0;
    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 );
    fprintf(stderr,"Writing PNG file %s.\n", filename);
    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 );
        }
        SetLastBMGError( (BMGError)error );
        return (BMGError)error;
    }

    SetLastBMGError( BMG_OK );
    /* open the file */
    if ((outfile = fopen(filename, "wb")) == NULL)
    {
        fprintf(stderr, "Error opening %s for reading.\n", filename);
        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 );

    /* set function pointers in the PNG library, for write callbacks */
    png_set_write_fn(png_ptr, (png_voidp) outfile, user_write_data, user_flush_data);

    /* 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;
}
Ejemplo n.º 15
0
BMGError ReadPNGInfo( const char *filename,
        struct BMGImageStruct * volatile img )
{
    jmp_buf             err_jmp;
    int                 error;

    FILE * volatile     file = NULL;
    int                 BitDepth;
    int                 ColorType;
    int                 InterlaceType;
    unsigned char       signature[8];
    png_structp volatile png_ptr = NULL;
    png_infop   volatile info_ptr = NULL;
    png_infop   volatile end_info = NULL;
    png_uint_32         Width, Height;

    /* error handler */
    error = setjmp( err_jmp );
    if (error != 0)
    {
        if (end_info != NULL)
            png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, (png_infop *) &end_info);
        else if (info_ptr != NULL)
            png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, NULL);
        else if (png_ptr != NULL)
            png_destroy_read_struct((png_structp *) &png_ptr, NULL, NULL);
        if (img)
            FreeBMGImage(img);
        if (file)
            fclose(file);
        SetLastBMGError((BMGError) error);
        return (BMGError) error;
    }

    if ( img == NULL )
        longjmp ( err_jmp, (int)errInvalidBMGImage );

    file = fopen( filename, "rb" );
    if ( !file || fread( signature, 1, 8, file ) != 8)
        longjmp ( err_jmp, (int)errFileOpen );

    /* check the signature */
    if ( png_sig_cmp( signature, 0, 8 ) != 0 )
        longjmp( err_jmp, (int)errUnsupportedFileFormat );

    /* create a pointer to the png read structure */
    png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL );
    if ( !png_ptr )
        longjmp( err_jmp, (int)errMemoryAllocation );

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

    /* create a pointer to the png end-info structure */
    end_info = png_create_info_struct(png_ptr);
    if (!end_info)
        longjmp( err_jmp, (int)errMemoryAllocation );

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

    /* set function pointers in the PNG library, for read callbacks */
    png_set_read_fn(png_ptr, (png_voidp) file, user_read_data);

    /*let the read functions know that we have already read the 1st 8 bytes */
    png_set_sig_bytes( png_ptr, 8 );

    /* read all PNG data up to the image data */
    png_read_info( png_ptr, info_ptr );

    /* extract the data we need to form the HBITMAP from the PNG header */
    png_get_IHDR( png_ptr, info_ptr, &Width, &Height, &BitDepth, &ColorType,
        &InterlaceType, NULL, NULL);

    img->width = (unsigned int) Width;
    img->height = (unsigned int) Height;

    img->bits_per_pixel = (unsigned char)32;
    img->scan_width = Width * 4;

    img->palette_size = (unsigned short)0;
    img->bytes_per_palette_entry = 4U;
    img->bits = NULL;

    png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, (png_infop *) &end_info);
    fclose( file );

    return BMG_OK;
}