xref: /haiku/src/add-ons/translators/gif/GIFTranslator.cpp (revision e1c4049fed1047bdb957b0529e1921e97ef94770)
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 // Additional authors:	Stephan Aßmus, <superstippi@gmx.de>
17 //						John Scipione, <jscipione@gmail.com>
18 
19 #include "GIFTranslator.h"
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <syslog.h>
25 
26 #include <Application.h>
27 #include <ByteOrder.h>
28 #include <Catalog.h>
29 #include <DataIO.h>
30 #include <InterfaceDefs.h>
31 #include <TranslatorAddOn.h>
32 #include <TranslatorFormats.h>
33 #include <TypeConstants.h>
34 
35 #include "GIFLoad.h"
36 #include "GIFSave.h"
37 #include "GIFView.h"
38 #include "TranslatorWindow.h"
39 
40 
41 #ifndef GIF_TYPE
42 #define GIF_TYPE 'GIF '
43 #endif
44 
45 #undef B_TRANSLATION_CONTEXT
46 #define B_TRANSLATION_CONTEXT "GIFTranslator"
47 
48 
49 bool debug = false;
50 	// this global will be externed in other files - set once here
51 	// for the entire translator
52 
53 bool DetermineType(BPositionIO* source, bool* isGif);
54 status_t GetBitmap(BPositionIO* in, BBitmap** out);
55 
56 static const translation_format sInputFormats[] = {
57 	{
58 		GIF_TYPE,
59 		B_TRANSLATOR_BITMAP,
60 		GIF_IN_QUALITY,
61 		GIF_IN_CAPABILITY,
62 		"image/gif",
63 		"GIF image"
64 	},
65 	{
66 		B_TRANSLATOR_BITMAP,
67 		B_TRANSLATOR_BITMAP,
68 		BBM_IN_QUALITY,
69 		BBM_IN_CAPABILITY,
70 		"image/x-be-bitmap",
71 		"Be Bitmap Format (GIFTranslator)"
72 	}
73 };
74 
75 static const translation_format sOutputFormats[] = {
76 	{
77 		GIF_TYPE,
78 		B_TRANSLATOR_BITMAP,
79 		GIF_OUT_QUALITY,
80 		GIF_OUT_CAPABILITY,
81 		"image/gif",
82 		"GIF image"
83 	},
84 	{
85 		B_TRANSLATOR_BITMAP,
86 		B_TRANSLATOR_BITMAP,
87 		BBM_OUT_QUALITY,
88 		BBM_OUT_CAPABILITY,
89 		"image/x-be-bitmap",
90 		"Be Bitmap Format (GIFTranslator)"
91 	}
92 };
93 
94 // Default settings for the Translator
95 static const TranSetting sDefaultSettings[] = {
96 	{ B_TRANSLATOR_EXT_HEADER_ONLY, TRAN_SETTING_BOOL, false },
97 	{ B_TRANSLATOR_EXT_DATA_ONLY, TRAN_SETTING_BOOL, false },
98 	{ GIF_SETTING_INTERLACED, TRAN_SETTING_BOOL, false },
99 	{ GIF_SETTING_USE_TRANSPARENT, TRAN_SETTING_BOOL, true },
100 	{ GIF_SETTING_USE_TRANSPARENT_AUTO, TRAN_SETTING_BOOL, true },
101 	{ GIF_SETTING_USE_DITHERING, TRAN_SETTING_BOOL, false },
102 	{ GIF_SETTING_PALETTE_MODE, TRAN_SETTING_INT32, 3 },
103 	{ GIF_SETTING_PALETTE_SIZE, TRAN_SETTING_INT32, 8 },
104 	{ GIF_SETTING_TRANSPARENT_RED, TRAN_SETTING_INT32, 255 },
105 	{ GIF_SETTING_TRANSPARENT_GREEN, TRAN_SETTING_INT32, 255 },
106 	{ GIF_SETTING_TRANSPARENT_BLUE, TRAN_SETTING_INT32, 255 }
107 };
108 
109 const uint32 kNumInputFormats = sizeof(sInputFormats)
110 	/ sizeof(translation_format);
111 const uint32 kNumOutputFormats = sizeof(sOutputFormats)
112 	/ sizeof(translation_format);
113 const uint32 kNumDefaultSettings = sizeof(sDefaultSettings)
114 	/ sizeof(TranSetting);
115 
116 
117 /*!	Look at first few bytes in stream to determine type - throw it back
118 	if it is not a GIF or a BBitmap that we understand.
119 */
120 bool
121 DetermineType(BPositionIO* source, bool* isGif)
122 {
123 	unsigned char header[7];
124 	*isGif = true;
125 	if (source->Read(header, 6) != 6)
126 		return false;
127 
128 	header[6] = 0x00;
129 
130 	if (strcmp((char*)header, "GIF87a") != 0
131 		&& strcmp((char*)header, "GIF89a") != 0) {
132 		*isGif = false;
133 		int32 magic = (header[0] << 24) + (header[1] << 16) + (header[2] << 8)
134 			+ header[3];
135 		if (magic != B_TRANSLATOR_BITMAP)
136 			return false;
137 
138 		source->Seek(5 * 4 - 2, SEEK_CUR);
139 		color_space cs;
140 		if (source->Read(&cs, 4) != 4)
141 			return false;
142 
143 		cs = (color_space)B_BENDIAN_TO_HOST_INT32(cs);
144 		if (cs != B_RGB32 && cs != B_RGBA32 && cs != B_RGB32_BIG
145 			&& cs != B_RGBA32_BIG) {
146 			return false;
147 		}
148 	}
149 
150 	source->Seek(0, SEEK_SET);
151 	return true;
152 }
153 
154 
155 status_t
156 GetBitmap(BPositionIO* in, BBitmap** out)
157 {
158 	TranslatorBitmap header;
159 	status_t result = in->Read(&header, sizeof(header));
160 	if (result != sizeof(header))
161 		return B_IO_ERROR;
162 
163 	header.magic = B_BENDIAN_TO_HOST_INT32(header.magic);
164 	header.bounds.left = B_BENDIAN_TO_HOST_FLOAT(header.bounds.left);
165 	header.bounds.top = B_BENDIAN_TO_HOST_FLOAT(header.bounds.top);
166 	header.bounds.right = B_BENDIAN_TO_HOST_FLOAT(header.bounds.right);
167 	header.bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(header.bounds.bottom);
168 	header.rowBytes = B_BENDIAN_TO_HOST_INT32(header.rowBytes);
169 	header.colors = (color_space)B_BENDIAN_TO_HOST_INT32(header.colors);
170 	header.dataSize = B_BENDIAN_TO_HOST_INT32(header.dataSize);
171 
172 	// dump data from stream into a BBitmap
173 	*out = new(std::nothrow) BBitmap(header.bounds, header.colors);
174 	if (*out == NULL)
175 		return B_NO_MEMORY;
176 
177 	if (!(*out)->IsValid()) {
178 		delete *out;
179 		return B_NO_MEMORY;
180 	}
181 
182 	result = in->Read((*out)->Bits(), header.dataSize);
183 	if (result != (status_t)header.dataSize) {
184 		delete *out;
185 		return B_IO_ERROR;
186 	}
187 
188 	return B_OK;
189 }
190 
191 
192 /*!	Required identify function - may need to read entire header, not sure
193 */
194 status_t
195 GIFTranslator::DerivedIdentify(BPositionIO* inSource,
196 	const translation_format* inFormat, BMessage* ioExtension,
197 	translator_info* outInfo, uint32 outType)
198 {
199 	const char* debug_text = getenv("GIF_TRANSLATOR_DEBUG");
200 	if (debug_text != NULL && atoi(debug_text) != 0)
201 		debug = true;
202 
203 	if (outType == 0)
204 		outType = B_TRANSLATOR_BITMAP;
205 
206 	if (outType != GIF_TYPE && outType != B_TRANSLATOR_BITMAP)
207 		return B_NO_TRANSLATOR;
208 
209 	bool isGif;
210 	if (!DetermineType(inSource, &isGif))
211 		return B_NO_TRANSLATOR;
212 
213 	if (!isGif && inFormat != NULL && inFormat->type != B_TRANSLATOR_BITMAP)
214 		return B_NO_TRANSLATOR;
215 
216 	outInfo->group = B_TRANSLATOR_BITMAP;
217 	if (isGif) {
218 		outInfo->type = GIF_TYPE;
219 		outInfo->quality = GIF_IN_QUALITY;
220 		outInfo->capability = GIF_IN_CAPABILITY;
221 		strlcpy(outInfo->name, B_TRANSLATE("GIF image"), sizeof(outInfo->name));
222 		strcpy(outInfo->MIME, "image/gif");
223 	} else {
224 		outInfo->type = B_TRANSLATOR_BITMAP;
225 		outInfo->quality = BBM_IN_QUALITY;
226 		outInfo->capability = BBM_IN_CAPABILITY;
227 		strlcpy(outInfo->name, B_TRANSLATE("Be Bitmap Format (GIFTranslator)"),
228 			sizeof(outInfo->name));
229 		strcpy(outInfo->MIME, "image/x-be-bitmap");
230 	}
231 
232 	return B_OK;
233 }
234 
235 
236 /*!	Main required function - assumes that an incoming GIF must be translated
237 	to a BBitmap, and vice versa - this could be improved
238 */
239 status_t
240 GIFTranslator::DerivedTranslate(BPositionIO* inSource,
241 	const translator_info* inInfo, BMessage* ioExtension, uint32 outType,
242 	BPositionIO* outDestination, int32 baseType)
243 {
244 	const char* debug_text = getenv("GIF_TRANSLATOR_DEBUG");
245 	if (debug_text != NULL && atoi(debug_text) != 0)
246 		debug = true;
247 
248 	if (outType == 0)
249 		outType = B_TRANSLATOR_BITMAP;
250 
251 	if (outType != GIF_TYPE && outType != B_TRANSLATOR_BITMAP)
252 		return B_NO_TRANSLATOR;
253 
254 	bool isGif;
255 	if (!DetermineType(inSource, &isGif))
256 		return B_NO_TRANSLATOR;
257 
258 	if (!isGif && inInfo->type != B_TRANSLATOR_BITMAP)
259 		return B_NO_TRANSLATOR;
260 
261 	status_t result = B_OK;
262 	bigtime_t now = system_time();
263 
264 	if (!isGif) {
265 		// BBitmap to GIF
266 		BBitmap* bitmap;
267 		result = GetBitmap(inSource, &bitmap);
268 		if (result != B_OK)
269 			return result;
270 
271 		GIFSave* gifSave = new(std::nothrow) GIFSave(bitmap, outDestination,
272 			fSettings);
273 		if (gifSave == NULL) {
274 			delete bitmap;
275 			return B_NO_MEMORY;
276 		}
277 
278 		if (gifSave->fatalerror) {
279 			delete gifSave;
280 			delete bitmap;
281 			return B_NO_MEMORY;
282 		}
283 		delete gifSave;
284 		delete bitmap;
285 	} else {
286 		// GIF to BBitmap
287 		GIFLoad* gifLoad = new(std::nothrow) GIFLoad(inSource, outDestination);
288 		if (gifLoad == NULL)
289 			return B_NO_MEMORY;
290 
291 		if (gifLoad->fatalerror) {
292 			delete gifLoad;
293 			return B_NO_MEMORY;
294 		}
295 		delete gifLoad;
296 	}
297 
298 	if (debug) {
299 		now = system_time() - now;
300 		syslog(LOG_INFO, "Translate() - Translation took %lld microseconds\n",
301 			now);
302 	}
303 	return B_OK;
304 }
305 
306 
307 BTranslator*
308 make_nth_translator(int32 n, image_id you, uint32 flags, ...)
309 {
310 	if (n == 0)
311 		return new(std::nothrow) GIFTranslator();
312 
313 	return NULL;
314 }
315 
316 
317 GIFTranslator::GIFTranslator()
318 	:
319 	BaseTranslator(B_TRANSLATE("GIF images"),
320 	B_TRANSLATE("GIF image translator"),
321 	GIF_TRANSLATOR_VERSION,
322 	sInputFormats, kNumInputFormats,
323 	sOutputFormats, kNumOutputFormats,
324 	"GIFTranslator_Settings",
325 	sDefaultSettings, kNumDefaultSettings,
326 	B_TRANSLATOR_BITMAP, B_GIF_FORMAT)
327 {
328 }
329 
330 
331 GIFTranslator::~GIFTranslator()
332 {
333 }
334 
335 
336 BView*
337 GIFTranslator::NewConfigView(TranslatorSettings* settings)
338 {
339 	return new(std::nothrow) GIFView(settings);
340 }
341 
342 
343 int
344 main()
345 {
346 	BApplication app("application/x-vnd.Haiku-GIFTranslator");
347 	status_t result = LaunchTranslatorWindow(new(std::nothrow) GIFTranslator,
348 		B_TRANSLATE("GIF Settings"), kRectView);
349 	if (result == B_OK) {
350 		app.Run();
351 		return 0;
352 	}
353 
354 	return 1;
355 }
356