Exemplo n.º 1
0
bool MCImageEncodePNG(MCImageIndexedBitmap *p_indexed, IO_handle p_stream, uindex_t &r_bytes_written)
{
	bool t_success = true;

	MCPNGWriteContext t_context;
	t_context.stream = p_stream;
	t_context.byte_count = 0;

	png_structp t_png_ptr = nil;
	png_infop t_info_ptr = nil;
	png_color *t_png_palette = nil;
	png_byte *t_png_transparency = nil;

	png_bytep t_data_ptr = nil;
	uindex_t t_stride = 0;

	/*init png stuff*/
	if (t_success)
	{
		t_success = nil != (t_png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
			(png_voidp)NULL, (png_error_ptr)NULL,
			(png_error_ptr)NULL));
	}

	if (t_success)
		t_success = nil != (t_info_ptr = png_create_info_struct(t_png_ptr));

	/*in case of png error*/
	if (setjmp(png_jmpbuf(t_png_ptr)))
		t_success = false;

	if (t_success)
		png_set_write_fn(t_png_ptr,(png_voidp)&t_context,fakewrite,fakeflush);

	if (t_success)
	{
		png_set_IHDR(t_png_ptr, t_info_ptr, p_indexed->width, p_indexed->height, 8,
					 PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,
					 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
		png_set_gAMA(t_png_ptr, t_info_ptr, 1/MCgamma);
	}

	if (t_success)
		t_success = MCMemoryNewArray(p_indexed->palette_size, t_png_palette);

	/*create palette for 8 bit*/
	if (t_success)
	{
		for (uindex_t i = 0; i < p_indexed->palette_size ; i++)
		{
			t_png_palette[i].red   = p_indexed->palette[i].red >> 8;
			t_png_palette[i].green = p_indexed->palette[i].green >> 8;
			t_png_palette[i].blue  = p_indexed->palette[i].blue >> 8;
		}

		png_set_PLTE(t_png_ptr, t_info_ptr, t_png_palette, p_indexed->palette_size);
	}

	if (MCImageIndexedBitmapHasTransparency(p_indexed))
	{
		if (t_success)
			t_success = MCMemoryAllocate(p_indexed->palette_size, t_png_transparency);
		if (t_success)
		{
			memset(t_png_transparency, 0xFF, p_indexed->palette_size);
			t_png_transparency[p_indexed->transparent_index] = 0x00;
			png_set_tRNS(t_png_ptr, t_info_ptr, t_png_transparency, p_indexed->palette_size, NULL);
		}
	}
	if (t_success)
		png_write_info(t_png_ptr, t_info_ptr);

	if (t_success)
	{
		t_data_ptr = (png_bytep)p_indexed->data;
		t_stride = p_indexed->stride;
	}

	if (t_success)
	{
		for (uindex_t i = 0; i < p_indexed->height; i++)
		{
			png_write_row(t_png_ptr, t_data_ptr);
			t_data_ptr += t_stride;
		}
	}

	if (t_success)
		png_write_end(t_png_ptr, t_info_ptr);

	if (t_png_ptr != nil)
		png_destroy_write_struct(&t_png_ptr, &t_info_ptr);
	if (t_png_palette != nil)
		MCMemoryDeleteArray(t_png_palette);
	if (t_png_transparency != nil)
		MCMemoryDeallocate(t_png_transparency);

	if (t_success)
		r_bytes_written = t_context.byte_count;

	return t_success;
}
Exemplo n.º 2
0
bool MCImageEncodeGIF(MCImageIndexedBitmap *p_indexed, IO_handle p_stream, uindex_t &r_bytes_written)
{
	bool t_success = true;

	int32_t t_transparent = -1;
	uindex_t t_palette_size;
	uindex_t t_depth;


	t_depth = GifBitSize(p_indexed->palette_size);
	// GIF requires palette size to be 2^depth
	t_palette_size = 1 << t_depth;

	int t_err = 0;
	GifFileType *t_gif = nil;
	ColorMapObject *t_colormap = nil;
	
	MCGIFWriteContext t_context;
	t_context.stream = p_stream;
	t_context.byte_count = 0;

	t_success = nil != (t_gif = EGifOpen(&t_context, gif_writeFunc, &t_err));

	if (t_success)
		t_success = nil != (t_colormap = GifMakeMapObject(t_palette_size, nil));

	if (t_success)
	{
		for (uindex_t i = 0; i < p_indexed->palette_size; i++)
		{
			t_colormap->Colors[i].Red = p_indexed->palette[i].red;
			t_colormap->Colors[i].Green = p_indexed->palette[i].green;
			t_colormap->Colors[i].Blue = p_indexed->palette[i].blue;
		}
		for (uindex_t i = p_indexed->palette_size; i < t_palette_size; i++)
		{
			t_colormap->Colors[i].Red =
				t_colormap->Colors[i].Green =
				t_colormap->Colors[i].Blue = 0;
		}

		if (MCImageIndexedBitmapHasTransparency(p_indexed))
		{
			t_transparent = p_indexed->transparent_index;
			t_colormap->Colors[t_transparent].Red =
				t_colormap->Colors[t_transparent].Green = 
				t_colormap->Colors[t_transparent].Blue = 0xFF;
		}

		t_success = GIF_OK == EGifPutScreenDesc(t_gif, p_indexed->width, p_indexed->height, t_depth, 0, t_colormap);
	}

	if (t_success)
	{
		if (t_transparent != -1)
		{
			GraphicsControlBlock t_gcb;
			MCMemoryClear(&t_gcb, sizeof(t_gcb));
			t_gcb.TransparentColor = t_transparent;

			GifByteType t_extension[4];

			uindex_t t_extension_size;
			t_extension_size = EGifGCBToExtension(&t_gcb, t_extension);

			// Should always be 4 bytes
			MCAssert(t_extension_size == sizeof(t_extension));

			t_success = GIF_OK == EGifPutExtension(t_gif, GRAPHICS_EXT_FUNC_CODE, sizeof(t_extension), t_extension);
		}
	}

	if (t_success)
		t_success = GIF_OK == EGifPutImageDesc(t_gif, 0, 0, p_indexed->width, p_indexed->height, false, nil);

	for (uindex_t y = 0; t_success && y < p_indexed->height; y++)
		t_success = GIF_OK == EGifPutLine(t_gif, (uint8_t*)p_indexed->data + y * p_indexed->stride, p_indexed->width);

	int t_error_code;
	if (GIF_ERROR == EGifCloseFile(t_gif, &t_error_code))
		t_success = false;

	GifFreeMapObject(t_colormap);

	if (t_success)
		r_bytes_written = t_context.byte_count;

	return t_success;
}