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