1//
2//  PXGifExporter.m
3//  Pixen-XCode
4//
5//  Created by Andy Matuschak on Fri Jul 16 2004.
6//  Copyright (c) 2004 Open Sword Group. All rights reserved.
7//
8
9#import "PXGifExporter.h"
10#import "gif_lib.h"
11
12@implementation PXGifExporter
13
14+ gifDataForImage:anImage
15{
16	id image = [[[NSImage alloc] initWithData:[anImage TIFFRepresentation]] autorelease];
17	NSSize size = [image size];
18	[image lockFocus];
19
20	// first we find a valid transparent color
21	id transparentColor = [NSColor colorWithCalibratedRed:0 green:0 blue:0 alpha:1];
22	BOOL found = YES;
23	while (found) // I know this is ugly. It works.
24	{
25		found = NO;
26		int i, j;
27		for (i = 0; i < size.width; i++)
28		{
29			for (j = 0; j < size.height; j++)
30			{
31				id converted = [NSReadPixel(NSMakePoint(i, j)) colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
32				if ((unsigned char)([converted redComponent] * 255) == (unsigned char)([transparentColor redComponent] * 255) && (unsigned char)([converted greenComponent] * 255) == (unsigned char)([transparentColor greenComponent] * 255) && (unsigned char)([converted blueComponent] * 255) == (unsigned char)([transparentColor blueComponent] * 255))
33				{
34					if ([transparentColor redComponent] < 1)
35					{
36						transparentColor = [NSColor colorWithCalibratedRed:[transparentColor redComponent]+0.1 green:[transparentColor greenComponent] blue:[transparentColor blueComponent] alpha:1];
37					}
38					else if ([transparentColor greenComponent] < 1)
39					{
40						transparentColor = [NSColor colorWithCalibratedRed:[transparentColor redComponent] green:[transparentColor greenComponent]+0.1 blue:[transparentColor blueComponent] alpha:1];
41					}
42					else if ([transparentColor blueComponent] < 1)
43					{
44						transparentColor = [NSColor colorWithCalibratedRed:[transparentColor redComponent] green:[transparentColor greenComponent] blue:[transparentColor blueComponent]+0.1 alpha:1];
45					}
46					found = YES;
47				}
48			}
49		}
50	}
51
52	int colorMapSize = 256;
53	GifByteType *redBuffer = malloc(size.width * size.height);
54	GifByteType *greenBuffer = malloc(size.width * size.height);
55	GifByteType *blueBuffer = malloc(size.width * size.height);
56	EGifSetGifVersion("89a");
57
58	int i, j, count = 0;
59	for (j = size.height - 1; j >= 0; j--)
60	{
61		for (i = 0; i < size.width; i++, count++)
62		{
63			NSColor * color = [NSReadPixel(NSMakePoint(i, j)) colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
64			if ([color alphaComponent] < 0.5) { color = transparentColor; }
65
66			redBuffer[count] = (GifByteType)([color redComponent] * 255);
67			greenBuffer[count] = (GifByteType)([color greenComponent] * 255);
68			blueBuffer[count] = (GifByteType)([color blueComponent] * 255);
69		}
70	}
71
72	ColorMapObject *colorMap = MakeMapObject(colorMapSize, NULL);
73	GifByteType *outputBuffer = malloc(size.width * size.height * sizeof(GifByteType));
74	QuantizeBuffer(size.width, size.height, &colorMapSize, redBuffer, greenBuffer, blueBuffer, outputBuffer, colorMap->Colors);
75
76	GifFileType *gifFile = EGifOpenFileName("/tmp/dummy.gif", NO);
77
78	//find the index of the transparent color in the color map
79	unsigned transparentIndex = 0, bestDelta = 1000;
80	for (i = 0; i < colorMapSize; i++)
81	{
82		unsigned char transRed = (unsigned char)([transparentColor redComponent] * 255);
83		unsigned char transGreen = (unsigned char)([transparentColor greenComponent] * 255);
84		unsigned char transBlue = (unsigned char)([transparentColor blueComponent] * 255);
85		GifColorType color = colorMap->Colors[i];
86		if (color.Red == transRed && color.Green == transGreen && color.Blue == transBlue)
87		{
88			transparentIndex = i;
89		}
90		else
91		{
92			unsigned int tempDelta = (color.Red < transRed ? transRed - color.Red : color.Red - transRed) +
93			(color.Green < transGreen ? transGreen - color.Green : color.Green - transGreen) +
94			(color.Blue < transBlue ? transBlue - color.Blue : color.Blue - transBlue);
95			if (tempDelta < bestDelta)
96			{
97				transparentIndex = i;
98				bestDelta = tempDelta;
99			}
100		}
101	}
102
103	EGifPutScreenDesc(gifFile, size.width, size.height, colorMapSize, 0, colorMap);
104	unsigned char extension[4] = { 0 };
105	extension[0] = 0x01; // byte 1 is a flag; 00000001 turns transparency on.
106	extension[1] = 0x00; // byte 2 is delay time, presumably for animation.
107	extension[2] = 0x00; // byte 3 is continued delay time.
108	extension[3] = transparentIndex; // byte 4 is the index of the transparent color in the palette.
109	EGifPutExtension(gifFile, 0xF9, sizeof(extension), extension); // 0xf9 is the transparency extension magic code
110	EGifPutImageDesc(gifFile, 0, 0, size.width, size.height, 0, NULL);
111
112	GifByteType * position = outputBuffer;
113	for (i = 0; i < size.height; i++)
114	{
115		EGifPutLine(gifFile, position, size.width);
116		position += (int)size.width;
117	}
118	EGifCloseFile(gifFile);
119
120	[image unlockFocus];
121	id finalData = [NSData dataWithContentsOfFile:@"/tmp/dummy.gif"];
122	remove("/tmp/dummy.gif");
123	return finalData;
124}
125
126@end
127