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