Esempio n. 1
0
static HRESULT WINAPI PngFrameEncode_WritePixels(IWICBitmapFrameEncode *iface,
    UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels)
{
    PngEncoder *This = encoder_from_frame(iface);
    png_byte **row_pointers=NULL;
    UINT i;
    jmp_buf jmpbuf;
    TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels);

    if (!This->frame_initialized || !This->width || !This->height || !This->format)
        return WINCODEC_ERR_WRONGSTATE;

    if (lineCount == 0 || lineCount + This->lines_written > This->height)
        return E_INVALIDARG;

    /* set up setjmp/longjmp error handling */
    if (setjmp(jmpbuf))
    {
        HeapFree(GetProcessHeap(), 0, row_pointers);
        return E_FAIL;
    }
    ppng_set_error_fn(This->png_ptr, &jmpbuf, user_error_fn, user_warning_fn);

    if (!This->info_written)
    {
        ppng_set_IHDR(This->png_ptr, This->info_ptr, This->width, This->height,
            This->format->bit_depth, This->format->color_type, PNG_INTERLACE_NONE,
            PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

        if (This->xres != 0.0 && This->yres != 0.0)
        {
            ppng_set_pHYs(This->png_ptr, This->info_ptr, (This->xres+0.0127) / 0.0254,
                (This->yres+0.0127) / 0.0254, PNG_RESOLUTION_METER);
        }

        ppng_write_info(This->png_ptr, This->info_ptr);

        if (This->format->remove_filler)
            ppng_set_filler(This->png_ptr, 0, PNG_FILLER_AFTER);

        if (This->format->swap_rgb)
            ppng_set_bgr(This->png_ptr);

        This->info_written = TRUE;
    }

    row_pointers = HeapAlloc(GetProcessHeap(), 0, lineCount * sizeof(png_byte*));
    if (!row_pointers)
        return E_OUTOFMEMORY;

    for (i=0; i<lineCount; i++)
        row_pointers[i] = pbPixels + cbStride * i;

    ppng_write_rows(This->png_ptr, row_pointers, lineCount);
    This->lines_written += lineCount;

    HeapFree(GetProcessHeap(), 0, row_pointers);

    return S_OK;
}
Esempio n. 2
0
static HRESULT WINAPI PngFrameEncode_Commit(IWICBitmapFrameEncode *iface)
{
    PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
    png_byte **row_pointers=NULL;
    jmp_buf jmpbuf;
    TRACE("(%p)\n", iface);

    EnterCriticalSection(&This->lock);

    if (!This->info_written || This->lines_written != This->height || This->frame_committed)
    {
        LeaveCriticalSection(&This->lock);
        return WINCODEC_ERR_WRONGSTATE;
    }

    /* set up setjmp/longjmp error handling */
    if (setjmp(jmpbuf))
    {
        LeaveCriticalSection(&This->lock);
        HeapFree(GetProcessHeap(), 0, row_pointers);
        return E_FAIL;
    }
    ppng_set_error_fn(This->png_ptr, jmpbuf, user_error_fn, user_warning_fn);

    if (This->interlace)
    {
        int i;

        row_pointers = HeapAlloc(GetProcessHeap(), 0, This->height * sizeof(png_byte*));
        if (!row_pointers)
        {
            LeaveCriticalSection(&This->lock);
            return E_OUTOFMEMORY;
        }

        for (i=0; i<This->height; i++)
            row_pointers[i] = This->data + This->stride * i;

        for (i=0; i<This->passes; i++)
            ppng_write_rows(This->png_ptr, row_pointers, This->height);
    }

    ppng_write_end(This->png_ptr, This->info_ptr);

    This->frame_committed = TRUE;

    HeapFree(GetProcessHeap(), 0, row_pointers);

    LeaveCriticalSection(&This->lock);

    return S_OK;
}
Esempio n. 3
0
static HRESULT WINAPI PngFrameEncode_WritePixels(IWICBitmapFrameEncode *iface,
    UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels)
{
    PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
    png_byte **row_pointers=NULL;
    UINT i;
    jmp_buf jmpbuf;
    TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels);

    EnterCriticalSection(&This->lock);

    if (!This->frame_initialized || !This->width || !This->height || !This->format)
    {
        LeaveCriticalSection(&This->lock);
        return WINCODEC_ERR_WRONGSTATE;
    }

    if (lineCount == 0 || lineCount + This->lines_written > This->height)
    {
        LeaveCriticalSection(&This->lock);
        return E_INVALIDARG;
    }

    /* set up setjmp/longjmp error handling */
    if (setjmp(jmpbuf))
    {
        LeaveCriticalSection(&This->lock);
        HeapFree(GetProcessHeap(), 0, row_pointers);
        return E_FAIL;
    }
    ppng_set_error_fn(This->png_ptr, jmpbuf, user_error_fn, user_warning_fn);

    if (!This->info_written)
    {
        if (This->interlace)
        {
            /* libpng requires us to write all data multiple times in this case. */
            This->stride = (This->format->bpp * This->width + 7)/8;
            This->data = HeapAlloc(GetProcessHeap(), 0, This->height * This->stride);
            if (!This->data)
            {
                LeaveCriticalSection(&This->lock);
                return E_OUTOFMEMORY;
            }
        }

        ppng_set_IHDR(This->png_ptr, This->info_ptr, This->width, This->height,
            This->format->bit_depth, This->format->color_type,
            This->interlace ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE,
            PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

        if (This->xres != 0.0 && This->yres != 0.0)
        {
            ppng_set_pHYs(This->png_ptr, This->info_ptr, (This->xres+0.0127) / 0.0254,
                (This->yres+0.0127) / 0.0254, PNG_RESOLUTION_METER);
        }

        ppng_write_info(This->png_ptr, This->info_ptr);

        if (This->format->remove_filler)
            ppng_set_filler(This->png_ptr, 0, PNG_FILLER_AFTER);

        if (This->format->swap_rgb)
            ppng_set_bgr(This->png_ptr);

        if (This->interlace)
            This->passes = ppng_set_interlace_handling(This->png_ptr);

        This->info_written = TRUE;
    }

    if (This->interlace)
    {
        /* Just store the data so we can write it in multiple passes in Commit. */
        for (i=0; i<lineCount; i++)
            memcpy(This->data + This->stride * (This->lines_written + i),
                   pbPixels + cbStride * i,
                   This->stride);

        This->lines_written += lineCount;

        LeaveCriticalSection(&This->lock);
        return S_OK;
    }

    row_pointers = HeapAlloc(GetProcessHeap(), 0, lineCount * sizeof(png_byte*));
    if (!row_pointers)
    {
        LeaveCriticalSection(&This->lock);
        return E_OUTOFMEMORY;
    }

    for (i=0; i<lineCount; i++)
        row_pointers[i] = pbPixels + cbStride * i;

    ppng_write_rows(This->png_ptr, row_pointers, lineCount);
    This->lines_written += lineCount;

    LeaveCriticalSection(&This->lock);

    HeapFree(GetProcessHeap(), 0, row_pointers);

    return S_OK;
}
Esempio n. 4
0
/**
 * 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;
}