コード例 #1
0
ファイル: imageutil.cpp プロジェクト: salviati/gens-gs-debug
/**
 * WritePNG(): Write a PNG image.
 * @param fImg File handle to save the image to.
 * @param w Width of the image.
 * @param h Height of the image.
 * @param pitch Pitch of the image. (measured in pixels)
 * @param screen Pointer to screen buffer.
 * @param bpp Bits per pixel.
 * @param alpha Alpha channel specification. (32-bit color only.)
 * @return 0 on success; non-zero on error.
 */
int ImageUtil::WritePNG(FILE *fImg, const int w, const int h, const int pitch,
			const void *screen, const int bpp, const AlphaChannel alpha)
{
	if (!fImg || !screen || (w <= 0 || h <= 0 || pitch <= 0))
		return 1;
	
	int rval = gsft_png_dll_init();
	if (rval)
		return rval;
	
	png_structp png_ptr;
	png_infop info_ptr;
	
	// Initialize libpng.
	png_ptr = ppng_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if (!png_ptr)
	{
		LOG_MSG(gens, LOG_MSG_LEVEL_CRITICAL,
			"Error initializing the PNG pointer.");
		return 2;
	}
	info_ptr = ppng_create_info_struct(png_ptr);
	if (!info_ptr)
	{
		LOG_MSG(gens, LOG_MSG_LEVEL_CRITICAL,
			"Error initializing the PNG info pointer.");
		ppng_destroy_write_struct(&png_ptr, (png_infopp)NULL);
		return 3;
	}
	if (setjmp(png_jmpbuf(png_ptr)))
	{
		// TODO: Is setjmp() really necessary?
		LOG_MSG(gens, LOG_MSG_LEVEL_CRITICAL,
			"Error initializing the PNG setjmp pointer.");
		ppng_destroy_write_struct(&png_ptr, &info_ptr);
		return 4;
	}
	
	// Initialize libpng I/O.
	ppng_init_io(png_ptr, fImg);
	
	// Disable PNG filters.
	ppng_set_filter(png_ptr, 0, PNG_FILTER_NONE);
	
	// Set the compression level to 5. (Levels range from 1 through 9.)
	// TODO: Add a UI option to set compression level.
	ppng_set_compression_level(png_ptr, 5);
	
	// Set up the PNG header.
	if (!(bpp == 32 && alpha != ALPHACHANNEL_NONE))
	{
		ppng_set_IHDR(png_ptr, info_ptr, w, h, 8, PNG_COLOR_TYPE_RGB,
				PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
				PNG_FILTER_TYPE_DEFAULT);
	}
	else
	{
		// 32-bit color, with alpha channel.
		ppng_set_IHDR(png_ptr, info_ptr, w, h, 8, PNG_COLOR_TYPE_RGB_ALPHA,
				PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
				PNG_FILTER_TYPE_DEFAULT);
	}
	
	// Write the PNG information to the file.
	ppng_write_info(png_ptr, info_ptr);
	
#if GSFT_BYTEORDER == GSFT_LIL_ENDIAN
	// PNG stores data in big-endian format.
	// On little-endian systems, byteswapping needs to be enabled.
	// TODO: Check if this really isn't needed on big-endian systems.
	ppng_set_swap(png_ptr);
#endif
	
	// Write the image.
	if (bpp == 15)
	{
		// 15-bit color. (Mode 555)
		rval = T_writePNG_rows_16<uint16_t,
					  MASK_RED_15, MASK_GREEN_15, MASK_BLUE_15,
					  SHIFT_RED_15, SHIFT_GREEN_15, SHIFT_BLUE_15>
					 (static_cast<const uint16_t*>(screen), png_ptr, info_ptr, w, h, pitch);
		
		if (rval != 0)
			return 5;
	}
	else if (bpp == 16)
	{
		// 16-bit color. (Mode 565)
		rval = T_writePNG_rows_16<uint16_t,
					  MASK_RED_16, MASK_GREEN_16, MASK_BLUE_16,
					  SHIFT_RED_16, SHIFT_GREEN_16, SHIFT_BLUE_16>
					 (static_cast<const uint16_t*>(screen), png_ptr, info_ptr, w, h, pitch);
		
		if (rval != 0)
			return 6;
	}
	else // if (bpp == 32)
	{
		// 32-bit color.
		// Depending on the alpha channel settings, libpng expects either
		// 24-bit data (no alpha) or 32-bit data (with alpha); however,
		// libpng offers an option to automatically convert 32-bit data
		// without alpha channel to 24-bit. (png_set_filler())
		
		// TODO: PNG_FILLER_AFTER, BGR mode - needed for little-endian.
		 // Figure out what's needed on big-endian.
		
		png_byte **row_pointers = static_cast<png_byte**>(malloc(sizeof(png_byte*) * h));
		uint32_t *screen32 = (uint32_t*)screen;
		
		for (int y = 0; y < h; y++)
		{
			row_pointers[y] = (uint8_t*)&screen32[y * pitch];
		}
		
		if (!alpha)
		{
			// No alpha channel. Set filler byte.
			ppng_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
		}
		else if (alpha == ALPHACHANNEL_TRANSPARENCY)
		{
			// Alpha channel indicates transparency.
			// 0x00 == opaque; 0xFF == transparent.
			ppng_set_invert_alpha(png_ptr);
		}
		
		ppng_set_bgr(png_ptr);
		ppng_write_rows(png_ptr, row_pointers, h);
		
		free(row_pointers);
	}
	
	// Finished writing.
	ppng_write_end(png_ptr, info_ptr);
	ppng_destroy_write_struct(&png_ptr, &info_ptr);
	
	return 0;
}
コード例 #2
0
static BOOL SaveIconResAsPNG(const BITMAPINFO *pIcon, const char *png_filename, LPCWSTR commentW)
{
    static const char comment_key[] = "Created from";
    FILE *fp;
    png_structp png_ptr;
    png_infop info_ptr;
    png_text comment;
    int nXORWidthBytes, nANDWidthBytes, color_type = 0, i, j;
    BYTE *row, *copy = NULL;
    const BYTE *pXOR, *pAND = NULL;
    int nWidth  = pIcon->bmiHeader.biWidth;
    int nHeight = pIcon->bmiHeader.biHeight;
    int nBpp    = pIcon->bmiHeader.biBitCount;

    switch (nBpp)
    {
    case 32:
        color_type |= PNG_COLOR_MASK_ALPHA;
        /* fall through */
    case 24:
        color_type |= PNG_COLOR_MASK_COLOR;
        break;
    default:
        return FALSE;
    }

    if (!libpng_handle && !load_libpng())
    {
        WINE_WARN("Unable to load libpng\n");
        return FALSE;
    }

    if (!(fp = fopen(png_filename, "w")))
    {
        WINE_ERR("unable to open '%s' for writing: %s\n", png_filename, strerror(errno));
        return FALSE;
    }

    nXORWidthBytes = 4 * ((nWidth * nBpp + 31) / 32);
    nANDWidthBytes = 4 * ((nWidth + 31 ) / 32);
    pXOR = (const BYTE*) pIcon + sizeof(BITMAPINFOHEADER) + pIcon->bmiHeader.biClrUsed * sizeof(RGBQUAD);
    if (nHeight > nWidth)
    {
        nHeight /= 2;
        pAND = pXOR + nHeight * nXORWidthBytes;
    }

    /* Apply mask if present */
    if (pAND)
    {
        RGBQUAD bgColor;

        /* copy bytes before modifying them */
        copy = HeapAlloc( GetProcessHeap(), 0, nHeight * nXORWidthBytes );
        memcpy( copy, pXOR, nHeight * nXORWidthBytes );
        pXOR = copy;

        /* image and mask are upside down reversed */
        row = copy + (nHeight - 1) * nXORWidthBytes;

        /* top left corner */
        bgColor.rgbRed   = row[0];
        bgColor.rgbGreen = row[1];
        bgColor.rgbBlue  = row[2];
        bgColor.rgbReserved = 0;

        for (i = 0; i < nHeight; i++, row -= nXORWidthBytes)
            for (j = 0; j < nWidth; j++, row += nBpp >> 3)
                if (MASK(j, i))
                {
                    RGBQUAD *pixel = (RGBQUAD *)row;
                    pixel->rgbBlue  = bgColor.rgbBlue;
                    pixel->rgbGreen = bgColor.rgbGreen;
                    pixel->rgbRed   = bgColor.rgbRed;
                    if (nBpp == 32)
                        pixel->rgbReserved = bgColor.rgbReserved;
                }
    }

    comment.text = NULL;

    if (!(png_ptr = ppng_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)) ||
        !(info_ptr = ppng_create_info_struct(png_ptr)))
        goto error;

    if (setjmp(png_jmpbuf(png_ptr)))
    {
        /* All future errors jump here */
        WINE_ERR("png error\n");
        goto error;
    }

    ppng_init_io(png_ptr, fp);
    ppng_set_IHDR(png_ptr, info_ptr, nWidth, nHeight, 8,
                  color_type,
                  PNG_INTERLACE_NONE,
                  PNG_COMPRESSION_TYPE_DEFAULT,
                  PNG_FILTER_TYPE_DEFAULT);

    /* Set comment */
    comment.compression = PNG_TEXT_COMPRESSION_NONE;
    comment.key = (png_charp)comment_key;
    i = WideCharToMultiByte(CP_UNIXCP, 0, commentW, -1, NULL, 0, NULL, NULL);
    comment.text = HeapAlloc(GetProcessHeap(), 0, i);
    WideCharToMultiByte(CP_UNIXCP, 0, commentW, -1, comment.text, i, NULL, NULL);
    comment.text_length = i - 1;
    ppng_set_text(png_ptr, info_ptr, &comment, 1);


    ppng_write_info(png_ptr, info_ptr);
    ppng_set_bgr(png_ptr);
    for (i = nHeight - 1; i >= 0 ; i--)
        ppng_write_row(png_ptr, (png_bytep)pXOR + nXORWidthBytes * i);
    ppng_write_end(png_ptr, info_ptr);

    ppng_destroy_write_struct(&png_ptr, &info_ptr);
    if (png_ptr) ppng_destroy_write_struct(&png_ptr, NULL);
    fclose(fp);
    HeapFree(GetProcessHeap(), 0, copy);
    HeapFree(GetProcessHeap(), 0, comment.text);
    return TRUE;

 error:
    if (png_ptr) ppng_destroy_write_struct(&png_ptr, NULL);
    fclose(fp);
    unlink(png_filename);
    HeapFree(GetProcessHeap(), 0, copy);
    HeapFree(GetProcessHeap(), 0, comment.text);
    return FALSE;
}