xref: /haiku/src/add-ons/translators/gif/GIFTranslator.cpp (revision 820dca4df6c7bf955c46e8f6521b9408f50b2900)
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
46 bool debug = false;
47 
48 bool DetermineType(BPositionIO *source, bool *is_gif);
49 status_t GetBitmap(BPositionIO *in, BBitmap **out);
50 
51 /* Required data */
52 char translatorName[] = "GIF images";
53 char translatorInfo[] = "GIF image translator v1.4";
54 int32 translatorVersion = 0x140;
55 
56 translation_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 
64 translation_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 */
74 status_t
75 MakeConfig(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 */
87 bool
88 DetermineType(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 */
115 status_t
116 GetBitmap(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 */
151 status_t
152 Identify(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 */
190 status_t
191 Translate(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 
240 GIFTranslator::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 
249 int
250 main()
251 {
252 	GIFTranslator myapp;
253 	myapp.Run();
254 	return 0;
255 }
256 
257