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