xref: /haiku/src/add-ons/translators/gif/GIFTranslator.cpp (revision 9949213a25979d177b420bc71891c2bff02a331d)
1*9949213aSStephan Aßmus ////////////////////////////////////////////////////////////////////////////////
2*9949213aSStephan Aßmus //
3*9949213aSStephan Aßmus //	File: GIFTranslator.cpp
4*9949213aSStephan Aßmus //
5*9949213aSStephan Aßmus //	Date: December 1999
6*9949213aSStephan Aßmus //
7*9949213aSStephan Aßmus //	Author: Daniel Switkin
8*9949213aSStephan Aßmus //
9*9949213aSStephan Aßmus //	Copyright 2003 (c) by Daniel Switkin. This file is made publically available
10*9949213aSStephan Aßmus //	under the BSD license, with the stipulations that this complete header must
11*9949213aSStephan Aßmus //	remain at the top of the file indefinitely, and credit must be given to the
12*9949213aSStephan Aßmus //	original author in any about box using this software.
13*9949213aSStephan Aßmus //
14*9949213aSStephan Aßmus ////////////////////////////////////////////////////////////////////////////////
15*9949213aSStephan Aßmus 
16*9949213aSStephan Aßmus #include "GIFTranslator.h"
17*9949213aSStephan Aßmus #include "GIFWindow.h"
18*9949213aSStephan Aßmus #include "GIFView.h"
19*9949213aSStephan Aßmus #include "GIFSave.h"
20*9949213aSStephan Aßmus #include "GIFLoad.h"
21*9949213aSStephan Aßmus #include <ByteOrder.h>
22*9949213aSStephan Aßmus #include <TypeConstants.h>
23*9949213aSStephan Aßmus #include <DataIO.h>
24*9949213aSStephan Aßmus #include <TranslatorAddOn.h>
25*9949213aSStephan Aßmus #include <TranslatorFormats.h>
26*9949213aSStephan Aßmus #include <InterfaceDefs.h>
27*9949213aSStephan Aßmus #include <stdio.h>
28*9949213aSStephan Aßmus #include <stdlib.h>
29*9949213aSStephan Aßmus #include <string.h>
30*9949213aSStephan Aßmus 
31*9949213aSStephan Aßmus #ifndef GIF_TYPE
32*9949213aSStephan Aßmus #define GIF_TYPE 'GIF '
33*9949213aSStephan Aßmus #endif
34*9949213aSStephan Aßmus 
35*9949213aSStephan Aßmus // This global will be externed in other files - set once here
36*9949213aSStephan Aßmus // for the entire translator
37*9949213aSStephan Aßmus bool debug = false;
38*9949213aSStephan Aßmus 
39*9949213aSStephan Aßmus bool DetermineType(BPositionIO *source, bool *is_gif);
40*9949213aSStephan Aßmus status_t GetBitmap(BPositionIO *in, BBitmap **out);
41*9949213aSStephan Aßmus 
42*9949213aSStephan Aßmus /* Required data */
43*9949213aSStephan Aßmus char translatorName[] = "GIF Images";
44*9949213aSStephan Aßmus char translatorInfo[] = "GIF image translator v1.4";
45*9949213aSStephan Aßmus int32 translatorVersion = 0x140;
46*9949213aSStephan Aßmus 
47*9949213aSStephan Aßmus translation_format inputFormats[] = {
48*9949213aSStephan Aßmus 	{ GIF_TYPE, B_TRANSLATOR_BITMAP, 0.8, 0.8, "image/gif", "GIF image" },
49*9949213aSStephan Aßmus 	{ B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.3, 0.3, "image/x-be-bitmap", "Be Bitmap image" },
50*9949213aSStephan Aßmus 	{ 0 }
51*9949213aSStephan Aßmus };
52*9949213aSStephan Aßmus 
53*9949213aSStephan Aßmus translation_format outputFormats[] = {
54*9949213aSStephan Aßmus 	{ GIF_TYPE, B_TRANSLATOR_BITMAP, 0.8, 0.8, "image/gif", "GIF image" },
55*9949213aSStephan Aßmus 	{ B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.3, 0.3, "image/x-be-bitmap", "Be Bitmap image" },
56*9949213aSStephan Aßmus 	{ 0 }
57*9949213aSStephan Aßmus };
58*9949213aSStephan Aßmus 
59*9949213aSStephan Aßmus 
60*9949213aSStephan Aßmus /* Build a pretty view for DataTranslations */
61*9949213aSStephan Aßmus status_t
62*9949213aSStephan Aßmus MakeConfig(BMessage *ioExtension, BView **outView, BRect *outExtent)
63*9949213aSStephan Aßmus {
64*9949213aSStephan Aßmus 	outExtent->Set(0, 0, 239, 239);
65*9949213aSStephan Aßmus 	GIFView *gifview = new GIFView(*outExtent, "TranslatorView");
66*9949213aSStephan Aßmus 	*outView = gifview;
67*9949213aSStephan Aßmus 	return B_OK;
68*9949213aSStephan Aßmus }
69*9949213aSStephan Aßmus 
70*9949213aSStephan Aßmus 
71*9949213aSStephan Aßmus /* Look at first few bytes in stream to determine type - throw it back
72*9949213aSStephan Aßmus    if it is not a GIF or a BBitmap that we understand */
73*9949213aSStephan Aßmus bool
74*9949213aSStephan Aßmus DetermineType(BPositionIO *source, bool *is_gif)
75*9949213aSStephan Aßmus {
76*9949213aSStephan Aßmus 	unsigned char header[7];
77*9949213aSStephan Aßmus 	*is_gif = true;
78*9949213aSStephan Aßmus 	if (source->Read(header, 6) != 6) return false;
79*9949213aSStephan Aßmus 	header[6] = 0x00;
80*9949213aSStephan Aßmus 
81*9949213aSStephan Aßmus 	if (strcmp((char *)header, "GIF87a") != 0 && strcmp((char *)header, "GIF89a") != 0) {
82*9949213aSStephan Aßmus 		*is_gif = false;
83*9949213aSStephan Aßmus 		int32 magic = (header[0] << 24) + (header[1] << 16) + (header[2] << 8) + header[3];
84*9949213aSStephan Aßmus 		if (magic != B_TRANSLATOR_BITMAP) return false;
85*9949213aSStephan Aßmus 		source->Seek(5 * 4 - 2, SEEK_CUR);
86*9949213aSStephan Aßmus 		color_space cs;
87*9949213aSStephan Aßmus 		if (source->Read(&cs, 4) != 4) return false;
88*9949213aSStephan Aßmus 		cs = (color_space)B_BENDIAN_TO_HOST_INT32(cs);
89*9949213aSStephan Aßmus 		if (cs != B_RGB32 && cs != B_RGBA32 && cs != B_RGB32_BIG && cs != B_RGBA32_BIG) return false;
90*9949213aSStephan Aßmus 	}
91*9949213aSStephan Aßmus 
92*9949213aSStephan Aßmus 	source->Seek(0, SEEK_SET);
93*9949213aSStephan Aßmus 	return true;
94*9949213aSStephan Aßmus }
95*9949213aSStephan Aßmus 
96*9949213aSStephan Aßmus 
97*9949213aSStephan Aßmus /* Dump data from stream into a BBitmap */
98*9949213aSStephan Aßmus status_t
99*9949213aSStephan Aßmus GetBitmap(BPositionIO *in, BBitmap **out)
100*9949213aSStephan Aßmus {
101*9949213aSStephan Aßmus 	TranslatorBitmap header;
102*9949213aSStephan Aßmus 
103*9949213aSStephan Aßmus 	status_t err = in->Read(&header, sizeof(header));
104*9949213aSStephan Aßmus 	if (err != sizeof(header))
105*9949213aSStephan Aßmus 		return B_IO_ERROR;
106*9949213aSStephan Aßmus 
107*9949213aSStephan Aßmus 	header.magic = B_BENDIAN_TO_HOST_INT32(header.magic);
108*9949213aSStephan Aßmus 	header.bounds.left = B_BENDIAN_TO_HOST_FLOAT(header.bounds.left);
109*9949213aSStephan Aßmus 	header.bounds.top = B_BENDIAN_TO_HOST_FLOAT(header.bounds.top);
110*9949213aSStephan Aßmus 	header.bounds.right = B_BENDIAN_TO_HOST_FLOAT(header.bounds.right);
111*9949213aSStephan Aßmus 	header.bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(header.bounds.bottom);
112*9949213aSStephan Aßmus 	header.rowBytes = B_BENDIAN_TO_HOST_INT32(header.rowBytes);
113*9949213aSStephan Aßmus 	header.colors = (color_space)B_BENDIAN_TO_HOST_INT32(header.colors);
114*9949213aSStephan Aßmus 	header.dataSize = B_BENDIAN_TO_HOST_INT32(header.dataSize);
115*9949213aSStephan Aßmus 
116*9949213aSStephan Aßmus 	BBitmap *bitmap = new BBitmap(header.bounds, header.colors);
117*9949213aSStephan Aßmus 	*out = bitmap;
118*9949213aSStephan Aßmus 	if (bitmap == NULL) return B_NO_MEMORY;
119*9949213aSStephan Aßmus 	unsigned char *bits = (unsigned char *)bitmap->Bits();
120*9949213aSStephan Aßmus 	if (bits == NULL) {
121*9949213aSStephan Aßmus 		delete bitmap;
122*9949213aSStephan Aßmus 		return B_NO_MEMORY;
123*9949213aSStephan Aßmus 	}
124*9949213aSStephan Aßmus 	err = in->Read(bits, header.dataSize);
125*9949213aSStephan Aßmus 	if (err == (status_t)header.dataSize) return B_OK;
126*9949213aSStephan Aßmus 	else return B_IO_ERROR;
127*9949213aSStephan Aßmus }
128*9949213aSStephan Aßmus 
129*9949213aSStephan Aßmus 
130*9949213aSStephan Aßmus /* Required Identify function - may need to read entire header, not sure */
131*9949213aSStephan Aßmus status_t
132*9949213aSStephan Aßmus Identify(BPositionIO *inSource, const translation_format *inFormat,
133*9949213aSStephan Aßmus 	BMessage *ioExtension, translator_info *outInfo, uint32 outType)
134*9949213aSStephan Aßmus {
135*9949213aSStephan Aßmus 
136*9949213aSStephan Aßmus 	const char *debug_text = getenv("GIF_TRANSLATOR_DEBUG");
137*9949213aSStephan Aßmus 	if ((debug_text != NULL) && (atoi(debug_text) != 0)) debug = true;
138*9949213aSStephan Aßmus 
139*9949213aSStephan Aßmus 	if (outType == 0) outType = B_TRANSLATOR_BITMAP;
140*9949213aSStephan Aßmus 	if (outType != GIF_TYPE && outType != B_TRANSLATOR_BITMAP) return B_NO_TRANSLATOR;
141*9949213aSStephan Aßmus 
142*9949213aSStephan Aßmus 	bool is_gif;
143*9949213aSStephan Aßmus 	if (!DetermineType(inSource, &is_gif)) return B_NO_TRANSLATOR;
144*9949213aSStephan Aßmus 	if (!is_gif && inFormat != NULL && inFormat->type != B_TRANSLATOR_BITMAP)
145*9949213aSStephan Aßmus 		return B_NO_TRANSLATOR;
146*9949213aSStephan Aßmus 
147*9949213aSStephan Aßmus 	outInfo->group = B_TRANSLATOR_BITMAP;
148*9949213aSStephan Aßmus 	if (is_gif) {
149*9949213aSStephan Aßmus 		outInfo->type = GIF_TYPE;
150*9949213aSStephan Aßmus 		outInfo->quality = 0.8;
151*9949213aSStephan Aßmus 		outInfo->capability = 0.8;
152*9949213aSStephan Aßmus 		strcpy(outInfo->name, "GIF image");
153*9949213aSStephan Aßmus 		strcpy(outInfo->MIME, "image/gif");
154*9949213aSStephan Aßmus 	}
155*9949213aSStephan Aßmus 	else {
156*9949213aSStephan Aßmus 		outInfo->type = B_TRANSLATOR_BITMAP;
157*9949213aSStephan Aßmus 		outInfo->quality = 0.3;
158*9949213aSStephan Aßmus 		outInfo->capability = 0.3;
159*9949213aSStephan Aßmus 		strcpy(outInfo->name, "Be Bitmap image");
160*9949213aSStephan Aßmus 		strcpy(outInfo->MIME, "image/x-be-bitmap");
161*9949213aSStephan Aßmus 	}
162*9949213aSStephan Aßmus 	return B_OK;
163*9949213aSStephan Aßmus }
164*9949213aSStephan Aßmus 
165*9949213aSStephan Aßmus 
166*9949213aSStephan Aßmus /* Main required function - assumes that an incoming GIF must be translated
167*9949213aSStephan Aßmus    to a BBitmap, and vice versa - this could be improved */
168*9949213aSStephan Aßmus status_t
169*9949213aSStephan Aßmus Translate(BPositionIO *inSource, const translator_info *inInfo,
170*9949213aSStephan Aßmus 	BMessage *ioExtension, uint32 outType, BPositionIO *outDestination)
171*9949213aSStephan Aßmus {
172*9949213aSStephan Aßmus 
173*9949213aSStephan Aßmus 	const char *debug_text = getenv("GIF_TRANSLATOR_DEBUG");
174*9949213aSStephan Aßmus 	if ((debug_text != NULL) && (atoi(debug_text) != 0)) debug = true;
175*9949213aSStephan Aßmus 
176*9949213aSStephan Aßmus 	if (outType == 0) outType = B_TRANSLATOR_BITMAP;
177*9949213aSStephan Aßmus 	if (outType != GIF_TYPE && outType != B_TRANSLATOR_BITMAP) {
178*9949213aSStephan Aßmus 		return B_NO_TRANSLATOR;
179*9949213aSStephan Aßmus 	}
180*9949213aSStephan Aßmus 
181*9949213aSStephan Aßmus 	bool is_gif;
182*9949213aSStephan Aßmus 	if (!DetermineType(inSource, &is_gif)) return B_NO_TRANSLATOR;
183*9949213aSStephan Aßmus 	if (!is_gif && inInfo->type != B_TRANSLATOR_BITMAP) return B_NO_TRANSLATOR;
184*9949213aSStephan Aßmus 
185*9949213aSStephan Aßmus 	status_t err = B_OK;
186*9949213aSStephan Aßmus 	bigtime_t now = system_time();
187*9949213aSStephan Aßmus 	// Going from BBitmap to GIF
188*9949213aSStephan Aßmus 	if (!is_gif) {
189*9949213aSStephan Aßmus 		BBitmap **b = (BBitmap **)malloc(4);
190*9949213aSStephan Aßmus 		*b = NULL;
191*9949213aSStephan Aßmus 		err = GetBitmap(inSource, b);
192*9949213aSStephan Aßmus 		if (err != B_OK) return err;
193*9949213aSStephan Aßmus 		GIFSave *gs = new GIFSave(*b, outDestination);
194*9949213aSStephan Aßmus 		if (gs->fatalerror) {
195*9949213aSStephan Aßmus 			delete gs;
196*9949213aSStephan Aßmus 			if (*b != NULL) delete *b;
197*9949213aSStephan Aßmus 			delete b;
198*9949213aSStephan Aßmus 			return B_NO_MEMORY;
199*9949213aSStephan Aßmus 		}
200*9949213aSStephan Aßmus 		delete gs;
201*9949213aSStephan Aßmus 		delete *b;
202*9949213aSStephan Aßmus 		delete b;
203*9949213aSStephan Aßmus 	} else { // GIF to BBitmap
204*9949213aSStephan Aßmus 		GIFLoad *gl = new GIFLoad(inSource, outDestination);
205*9949213aSStephan Aßmus 		if (gl->fatalerror) {
206*9949213aSStephan Aßmus 			delete gl;
207*9949213aSStephan Aßmus 			return B_NO_MEMORY;
208*9949213aSStephan Aßmus 		}
209*9949213aSStephan Aßmus 		delete gl;
210*9949213aSStephan Aßmus 	}
211*9949213aSStephan Aßmus 
212*9949213aSStephan Aßmus 	if (debug) {
213*9949213aSStephan Aßmus 		now = system_time() - now;
214*9949213aSStephan Aßmus 		printf("Translate() - Translation took %Ld microseconds\n", now);
215*9949213aSStephan Aßmus 	}
216*9949213aSStephan Aßmus 	return B_OK;
217*9949213aSStephan Aßmus }
218*9949213aSStephan Aßmus 
219*9949213aSStephan Aßmus 
220*9949213aSStephan Aßmus GIFTranslator::GIFTranslator()
221*9949213aSStephan Aßmus 	: BApplication("application/x-vnd.Jules-GIFTranslator")
222*9949213aSStephan Aßmus {
223*9949213aSStephan Aßmus 	BRect rect(100, 100, 339, 339);
224*9949213aSStephan Aßmus 	gifwindow = new GIFWindow(rect, "GIF Settings");
225*9949213aSStephan Aßmus 	gifwindow->Show();
226*9949213aSStephan Aßmus }
227*9949213aSStephan Aßmus 
228*9949213aSStephan Aßmus 
229*9949213aSStephan Aßmus int
230*9949213aSStephan Aßmus main()
231*9949213aSStephan Aßmus {
232*9949213aSStephan Aßmus 	GIFTranslator myapp;
233*9949213aSStephan Aßmus 	myapp.Run();
234*9949213aSStephan Aßmus 	return 0;
235*9949213aSStephan Aßmus }
236*9949213aSStephan Aßmus 
237