xref: /haiku/src/add-ons/translators/gif/GIFTranslator.cpp (revision abfe23dcf33fc8172f5deb50980ff6c6c8fd8a53)
19949213aSStephan Aßmus ////////////////////////////////////////////////////////////////////////////////
29949213aSStephan Aßmus //
39949213aSStephan Aßmus //	File: GIFTranslator.cpp
49949213aSStephan Aßmus //
59949213aSStephan Aßmus //	Date: December 1999
69949213aSStephan Aßmus //
79949213aSStephan Aßmus //	Author: Daniel Switkin
89949213aSStephan Aßmus //
99949213aSStephan Aßmus //	Copyright 2003 (c) by Daniel Switkin. This file is made publically available
109949213aSStephan Aßmus //	under the BSD license, with the stipulations that this complete header must
119949213aSStephan Aßmus //	remain at the top of the file indefinitely, and credit must be given to the
129949213aSStephan Aßmus //	original author in any about box using this software.
139949213aSStephan Aßmus //
149949213aSStephan Aßmus ////////////////////////////////////////////////////////////////////////////////
15*abfe23dcSPhilippe Saint-Pierre // Additional authors:  Stephan Aßmus, <superstippi@gmx.de>
169949213aSStephan Aßmus 
179949213aSStephan Aßmus #include "GIFTranslator.h"
189949213aSStephan Aßmus #include "GIFView.h"
199949213aSStephan Aßmus #include "GIFSave.h"
209949213aSStephan Aßmus #include "GIFLoad.h"
2170d59669SSiarzhuk Zharski 
22*abfe23dcSPhilippe Saint-Pierre #include <Application.h>
239949213aSStephan Aßmus #include <ByteOrder.h>
2470d59669SSiarzhuk Zharski #include <Catalog.h>
259949213aSStephan Aßmus #include <DataIO.h>
2670d59669SSiarzhuk Zharski #include <InterfaceDefs.h>
2770d59669SSiarzhuk Zharski #include <TypeConstants.h>
289949213aSStephan Aßmus #include <TranslatorAddOn.h>
299949213aSStephan Aßmus #include <TranslatorFormats.h>
3070d59669SSiarzhuk Zharski 
319949213aSStephan Aßmus #include <stdio.h>
329949213aSStephan Aßmus #include <stdlib.h>
339949213aSStephan Aßmus #include <string.h>
3470d59669SSiarzhuk Zharski #include <syslog.h>
359949213aSStephan Aßmus 
36*abfe23dcSPhilippe Saint-Pierre #include "TranslatorWindow.h"
37*abfe23dcSPhilippe Saint-Pierre 
389949213aSStephan Aßmus #ifndef GIF_TYPE
399949213aSStephan Aßmus #define GIF_TYPE 'GIF '
409949213aSStephan Aßmus #endif
419949213aSStephan Aßmus 
42546208a5SOliver Tappe #undef B_TRANSLATION_CONTEXT
43546208a5SOliver Tappe #define B_TRANSLATION_CONTEXT "GIFTranslator"
4470d59669SSiarzhuk Zharski 
4570d59669SSiarzhuk Zharski 
469949213aSStephan Aßmus // This global will be externed in other files - set once here
479949213aSStephan Aßmus // for the entire translator
489949213aSStephan Aßmus bool debug = false;
499949213aSStephan Aßmus 
509949213aSStephan Aßmus bool DetermineType(BPositionIO *source, bool *is_gif);
519949213aSStephan Aßmus status_t GetBitmap(BPositionIO *in, BBitmap **out);
529949213aSStephan Aßmus 
53*abfe23dcSPhilippe Saint-Pierre static const translation_format sInputFormats[] = {
54*abfe23dcSPhilippe Saint-Pierre 	{ GIF_TYPE, B_TRANSLATOR_BITMAP, GIF_IN_QUALITY, GIF_IN_CAPABILITY,
55*abfe23dcSPhilippe Saint-Pierre 		"image/gif", "GIF image" },
56*abfe23dcSPhilippe Saint-Pierre 	{ B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, BBM_IN_QUALITY, BBM_IN_CAPABILITY,
57*abfe23dcSPhilippe Saint-Pierre 		"image/x-be-bitmap", "Be Bitmap Format (GIFTranslator)" }
589949213aSStephan Aßmus };
599949213aSStephan Aßmus 
60*abfe23dcSPhilippe Saint-Pierre static const translation_format sOutputFormats[] = {
61*abfe23dcSPhilippe Saint-Pierre 	{ GIF_TYPE, B_TRANSLATOR_BITMAP, GIF_OUT_QUALITY, GIF_OUT_CAPABILITY, "image/gif",
6270d59669SSiarzhuk Zharski 		"GIF image" },
63*abfe23dcSPhilippe Saint-Pierre 	{ B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, BBM_OUT_QUALITY, BBM_OUT_CAPABILITY,
64*abfe23dcSPhilippe Saint-Pierre 		"image/x-be-bitmap", "Be Bitmap Format (GIFTranslator)" }
659949213aSStephan Aßmus };
669949213aSStephan Aßmus 
67*abfe23dcSPhilippe Saint-Pierre // Default settings for the Translator
68*abfe23dcSPhilippe Saint-Pierre static const TranSetting sDefaultSettings[] = {
69*abfe23dcSPhilippe Saint-Pierre         {B_TRANSLATOR_EXT_HEADER_ONLY, TRAN_SETTING_BOOL, false},
70*abfe23dcSPhilippe Saint-Pierre         {B_TRANSLATOR_EXT_DATA_ONLY, TRAN_SETTING_BOOL, false},
71*abfe23dcSPhilippe Saint-Pierre 	{GIF_SETTING_INTERLACED, TRAN_SETTING_BOOL, false},
72*abfe23dcSPhilippe Saint-Pierre 	{GIF_SETTING_USE_TRANSPARENT, TRAN_SETTING_BOOL, false},
73*abfe23dcSPhilippe Saint-Pierre 	{GIF_SETTING_USE_TRANSPARENT_AUTO, TRAN_SETTING_BOOL, false},
74*abfe23dcSPhilippe Saint-Pierre 	{GIF_SETTING_USE_DITHERING, TRAN_SETTING_BOOL, false},
75*abfe23dcSPhilippe Saint-Pierre 	{GIF_SETTING_PALETTE_MODE, TRAN_SETTING_INT32, 0},
76*abfe23dcSPhilippe Saint-Pierre 	{GIF_SETTING_PALETTE_SIZE, TRAN_SETTING_INT32, 8},
77*abfe23dcSPhilippe Saint-Pierre 	{GIF_SETTING_TRANSPARENT_RED, TRAN_SETTING_INT32, 0},
78*abfe23dcSPhilippe Saint-Pierre 	{GIF_SETTING_TRANSPARENT_GREEN, TRAN_SETTING_INT32, 0},
79*abfe23dcSPhilippe Saint-Pierre 	{GIF_SETTING_TRANSPARENT_BLUE, TRAN_SETTING_INT32, 0}
80*abfe23dcSPhilippe Saint-Pierre };
819949213aSStephan Aßmus 
82*abfe23dcSPhilippe Saint-Pierre const uint32 kNumInputFormats = sizeof(sInputFormats) / sizeof(translation_format);
83*abfe23dcSPhilippe Saint-Pierre const uint32 kNumOutputFormats = sizeof(sOutputFormats) / sizeof(translation_format);
84*abfe23dcSPhilippe Saint-Pierre const uint32 kNumDefaultSettings = sizeof(sDefaultSettings) / sizeof(TranSetting);
859949213aSStephan Aßmus 
869949213aSStephan Aßmus 
879949213aSStephan Aßmus /* Look at first few bytes in stream to determine type - throw it back
889949213aSStephan Aßmus    if it is not a GIF or a BBitmap that we understand */
899949213aSStephan Aßmus bool
909949213aSStephan Aßmus DetermineType(BPositionIO *source, bool *is_gif)
919949213aSStephan Aßmus {
929949213aSStephan Aßmus 	unsigned char header[7];
939949213aSStephan Aßmus 	*is_gif = true;
94*abfe23dcSPhilippe Saint-Pierre 	if (source->Read(header, 6) != 6)
95*abfe23dcSPhilippe Saint-Pierre 		return false;
969949213aSStephan Aßmus 	header[6] = 0x00;
979949213aSStephan Aßmus 
9870d59669SSiarzhuk Zharski 	if (strcmp((char *)header, "GIF87a") != 0 && strcmp((char *)header,
9970d59669SSiarzhuk Zharski 		"GIF89a") != 0) {
1009949213aSStephan Aßmus 		*is_gif = false;
10170d59669SSiarzhuk Zharski 		int32 magic = (header[0] << 24) + (header[1] << 16) + (header[2] << 8)
10270d59669SSiarzhuk Zharski 			+ header[3];
103*abfe23dcSPhilippe Saint-Pierre 		if (magic != B_TRANSLATOR_BITMAP)
104*abfe23dcSPhilippe Saint-Pierre 			return false;
1059949213aSStephan Aßmus 		source->Seek(5 * 4 - 2, SEEK_CUR);
1069949213aSStephan Aßmus 		color_space cs;
107*abfe23dcSPhilippe Saint-Pierre 		if (source->Read(&cs, 4) != 4)
108*abfe23dcSPhilippe Saint-Pierre 			return false;
1099949213aSStephan Aßmus 		cs = (color_space)B_BENDIAN_TO_HOST_INT32(cs);
110*abfe23dcSPhilippe Saint-Pierre 		if (cs != B_RGB32 && cs != B_RGBA32 && cs != B_RGB32_BIG
111*abfe23dcSPhilippe Saint-Pierre 			&& cs != B_RGBA32_BIG)
112*abfe23dcSPhilippe Saint-Pierre 			return false;
1139949213aSStephan Aßmus 	}
1149949213aSStephan Aßmus 
1159949213aSStephan Aßmus 	source->Seek(0, SEEK_SET);
1169949213aSStephan Aßmus 	return true;
1179949213aSStephan Aßmus }
1189949213aSStephan Aßmus 
1199949213aSStephan Aßmus 
1209949213aSStephan Aßmus /* Dump data from stream into a BBitmap */
1219949213aSStephan Aßmus status_t
1229949213aSStephan Aßmus GetBitmap(BPositionIO *in, BBitmap **out)
1239949213aSStephan Aßmus {
1249949213aSStephan Aßmus 	TranslatorBitmap header;
1259949213aSStephan Aßmus 
1269949213aSStephan Aßmus 	status_t err = in->Read(&header, sizeof(header));
1279949213aSStephan Aßmus 	if (err != sizeof(header))
1289949213aSStephan Aßmus 		return B_IO_ERROR;
1299949213aSStephan Aßmus 
1309949213aSStephan Aßmus 	header.magic = B_BENDIAN_TO_HOST_INT32(header.magic);
1319949213aSStephan Aßmus 	header.bounds.left = B_BENDIAN_TO_HOST_FLOAT(header.bounds.left);
1329949213aSStephan Aßmus 	header.bounds.top = B_BENDIAN_TO_HOST_FLOAT(header.bounds.top);
1339949213aSStephan Aßmus 	header.bounds.right = B_BENDIAN_TO_HOST_FLOAT(header.bounds.right);
1349949213aSStephan Aßmus 	header.bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(header.bounds.bottom);
1359949213aSStephan Aßmus 	header.rowBytes = B_BENDIAN_TO_HOST_INT32(header.rowBytes);
1369949213aSStephan Aßmus 	header.colors = (color_space)B_BENDIAN_TO_HOST_INT32(header.colors);
1379949213aSStephan Aßmus 	header.dataSize = B_BENDIAN_TO_HOST_INT32(header.dataSize);
1389949213aSStephan Aßmus 
139*abfe23dcSPhilippe Saint-Pierre 	BBitmap* bitmap = new(std::nothrow) BBitmap(header.bounds, header.colors);
1409949213aSStephan Aßmus 	*out = bitmap;
141*abfe23dcSPhilippe Saint-Pierre 	if (bitmap == NULL)
142*abfe23dcSPhilippe Saint-Pierre 		return B_NO_MEMORY;
1439949213aSStephan Aßmus 	unsigned char *bits = (unsigned char *)bitmap->Bits();
1449949213aSStephan Aßmus 	if (bits == NULL) {
1459949213aSStephan Aßmus 		delete bitmap;
1469949213aSStephan Aßmus 		return B_NO_MEMORY;
1479949213aSStephan Aßmus 	}
1489949213aSStephan Aßmus 	err = in->Read(bits, header.dataSize);
149*abfe23dcSPhilippe Saint-Pierre 	if (err == (status_t)header.dataSize)
150*abfe23dcSPhilippe Saint-Pierre 		return B_OK;
151de6ba1a0SAdrien Destugues 	else {
152de6ba1a0SAdrien Destugues 		delete bitmap;
153de6ba1a0SAdrien Destugues 		return B_IO_ERROR;
154de6ba1a0SAdrien Destugues 	}
1559949213aSStephan Aßmus }
1569949213aSStephan Aßmus 
1579949213aSStephan Aßmus 
1589949213aSStephan Aßmus /* Required Identify function - may need to read entire header, not sure */
1599949213aSStephan Aßmus status_t
160*abfe23dcSPhilippe Saint-Pierre GIFTranslator::DerivedIdentify(BPositionIO* inSource,
161*abfe23dcSPhilippe Saint-Pierre 	const translation_format* inFormat, BMessage* ioExtension,
162*abfe23dcSPhilippe Saint-Pierre 	translator_info* outInfo, uint32 outType)
1639949213aSStephan Aßmus {
1649949213aSStephan Aßmus 	const char *debug_text = getenv("GIF_TRANSLATOR_DEBUG");
165*abfe23dcSPhilippe Saint-Pierre 	if (debug_text != NULL && atoi(debug_text) != 0)
166*abfe23dcSPhilippe Saint-Pierre 		debug = true;
1679949213aSStephan Aßmus 
168*abfe23dcSPhilippe Saint-Pierre 	if (outType == 0)
169*abfe23dcSPhilippe Saint-Pierre 		outType = B_TRANSLATOR_BITMAP;
17070d59669SSiarzhuk Zharski 	if (outType != GIF_TYPE && outType != B_TRANSLATOR_BITMAP)
17170d59669SSiarzhuk Zharski 		return B_NO_TRANSLATOR;
1729949213aSStephan Aßmus 
1739949213aSStephan Aßmus 	bool is_gif;
174*abfe23dcSPhilippe Saint-Pierre 	if (!DetermineType(inSource, &is_gif))
175*abfe23dcSPhilippe Saint-Pierre 		return B_NO_TRANSLATOR;
1769949213aSStephan Aßmus 	if (!is_gif && inFormat != NULL && inFormat->type != B_TRANSLATOR_BITMAP)
1779949213aSStephan Aßmus 		return B_NO_TRANSLATOR;
1789949213aSStephan Aßmus 
1799949213aSStephan Aßmus 	outInfo->group = B_TRANSLATOR_BITMAP;
1809949213aSStephan Aßmus 	if (is_gif) {
1819949213aSStephan Aßmus 		outInfo->type = GIF_TYPE;
182*abfe23dcSPhilippe Saint-Pierre 		outInfo->quality = GIF_IN_QUALITY;
183*abfe23dcSPhilippe Saint-Pierre 		outInfo->capability = GIF_IN_CAPABILITY;
184aec33db1SPhilippe Saint-Pierre 		strlcpy(outInfo->name, B_TRANSLATE("GIF image"), sizeof(outInfo->name));
1859949213aSStephan Aßmus 		strcpy(outInfo->MIME, "image/gif");
186*abfe23dcSPhilippe Saint-Pierre 	} else {
1879949213aSStephan Aßmus 		outInfo->type = B_TRANSLATOR_BITMAP;
188*abfe23dcSPhilippe Saint-Pierre 		outInfo->quality = BBM_IN_QUALITY;
189*abfe23dcSPhilippe Saint-Pierre 		outInfo->capability = BBM_IN_CAPABILITY;
190aec33db1SPhilippe Saint-Pierre 		strlcpy(outInfo->name, B_TRANSLATE("Be Bitmap Format (GIFTranslator)"),
1913927bd3cSPhilippe Saint-Pierre 			sizeof(outInfo->name));
1929949213aSStephan Aßmus 		strcpy(outInfo->MIME, "image/x-be-bitmap");
1939949213aSStephan Aßmus 	}
1949949213aSStephan Aßmus 	return B_OK;
1959949213aSStephan Aßmus }
1969949213aSStephan Aßmus 
1979949213aSStephan Aßmus 
1989949213aSStephan Aßmus /* Main required function - assumes that an incoming GIF must be translated
1999949213aSStephan Aßmus    to a BBitmap, and vice versa - this could be improved */
2009949213aSStephan Aßmus status_t
201*abfe23dcSPhilippe Saint-Pierre GIFTranslator::DerivedTranslate(BPositionIO* inSource,
202*abfe23dcSPhilippe Saint-Pierre 	const translator_info* inInfo, BMessage* ioExtension, uint32 outType,
203*abfe23dcSPhilippe Saint-Pierre 	BPositionIO* outDestination, int32 baseType)
2049949213aSStephan Aßmus {
2059949213aSStephan Aßmus 	const char* debug_text = getenv("GIF_TRANSLATOR_DEBUG");
2069949213aSStephan Aßmus 	if ((debug_text != NULL) && (atoi(debug_text) != 0)) debug = true;
2079949213aSStephan Aßmus 
2089949213aSStephan Aßmus 	if (outType == 0) outType = B_TRANSLATOR_BITMAP;
2099949213aSStephan Aßmus 	if (outType != GIF_TYPE && outType != B_TRANSLATOR_BITMAP) {
2109949213aSStephan Aßmus 		return B_NO_TRANSLATOR;
2119949213aSStephan Aßmus 	}
2129949213aSStephan Aßmus 
2139949213aSStephan Aßmus 	bool is_gif;
2149949213aSStephan Aßmus 	if (!DetermineType(inSource, &is_gif)) return B_NO_TRANSLATOR;
2159949213aSStephan Aßmus 	if (!is_gif && inInfo->type != B_TRANSLATOR_BITMAP) return B_NO_TRANSLATOR;
2169949213aSStephan Aßmus 
2179949213aSStephan Aßmus 	status_t err = B_OK;
2189949213aSStephan Aßmus 	bigtime_t now = system_time();
2199949213aSStephan Aßmus 	// Going from BBitmap to GIF
2209949213aSStephan Aßmus 	if (!is_gif) {
2217bc02c61SStefano Ceccherini 		BBitmap *bitmap = NULL;
2227bc02c61SStefano Ceccherini 		err = GetBitmap(inSource, &bitmap);
2237bc02c61SStefano Ceccherini 		if (err != B_OK)
2247bc02c61SStefano Ceccherini 			return err;
225*abfe23dcSPhilippe Saint-Pierre 		GIFSave* gs = new GIFSave(bitmap, outDestination, fSettings);
2269949213aSStephan Aßmus 		if (gs->fatalerror) {
2279949213aSStephan Aßmus 			delete gs;
2287bc02c61SStefano Ceccherini 			delete bitmap;
2299949213aSStephan Aßmus 			return B_NO_MEMORY;
2309949213aSStephan Aßmus 		}
2319949213aSStephan Aßmus 		delete gs;
2327bc02c61SStefano Ceccherini 		delete bitmap;
2339949213aSStephan Aßmus 	} else { // GIF to BBitmap
2349949213aSStephan Aßmus 		GIFLoad *gl = new GIFLoad(inSource, outDestination);
2359949213aSStephan Aßmus 		if (gl->fatalerror) {
2369949213aSStephan Aßmus 			delete gl;
2379949213aSStephan Aßmus 			return B_NO_MEMORY;
2389949213aSStephan Aßmus 		}
2399949213aSStephan Aßmus 		delete gl;
2409949213aSStephan Aßmus 	}
2419949213aSStephan Aßmus 
2429949213aSStephan Aßmus 	if (debug) {
2439949213aSStephan Aßmus 		now = system_time() - now;
24470d59669SSiarzhuk Zharski 		syslog(LOG_ERR, "Translate() - Translation took %Ld microseconds\n", now);
2459949213aSStephan Aßmus 	}
2469949213aSStephan Aßmus 	return B_OK;
2479949213aSStephan Aßmus }
2489949213aSStephan Aßmus 
2499949213aSStephan Aßmus 
250*abfe23dcSPhilippe Saint-Pierre BTranslator*
251*abfe23dcSPhilippe Saint-Pierre make_nth_translator(int32 n, image_id you, uint32 flags, ...)
2529949213aSStephan Aßmus {
253*abfe23dcSPhilippe Saint-Pierre         if (n == 0)
254*abfe23dcSPhilippe Saint-Pierre                 return new GIFTranslator();
255*abfe23dcSPhilippe Saint-Pierre 
256*abfe23dcSPhilippe Saint-Pierre         return NULL;
257*abfe23dcSPhilippe Saint-Pierre }
258*abfe23dcSPhilippe Saint-Pierre 
259*abfe23dcSPhilippe Saint-Pierre 
260*abfe23dcSPhilippe Saint-Pierre GIFTranslator::GIFTranslator()
261*abfe23dcSPhilippe Saint-Pierre 	: BaseTranslator(B_TRANSLATE("GIF images"),
262*abfe23dcSPhilippe Saint-Pierre 		B_TRANSLATE("GIF image translator"),
263*abfe23dcSPhilippe Saint-Pierre 		GIF_TRANSLATOR_VERSION,
264*abfe23dcSPhilippe Saint-Pierre 		sInputFormats, kNumInputFormats,
265*abfe23dcSPhilippe Saint-Pierre 		sOutputFormats, kNumOutputFormats,
266*abfe23dcSPhilippe Saint-Pierre 		"GIFTranslator_Settings",
267*abfe23dcSPhilippe Saint-Pierre 		sDefaultSettings, kNumDefaultSettings,
268*abfe23dcSPhilippe Saint-Pierre 		B_TRANSLATOR_BITMAP, B_GIF_FORMAT)
269*abfe23dcSPhilippe Saint-Pierre {
270*abfe23dcSPhilippe Saint-Pierre }
271*abfe23dcSPhilippe Saint-Pierre 
272*abfe23dcSPhilippe Saint-Pierre 
273*abfe23dcSPhilippe Saint-Pierre GIFTranslator::~GIFTranslator()
274*abfe23dcSPhilippe Saint-Pierre {
275*abfe23dcSPhilippe Saint-Pierre }
276*abfe23dcSPhilippe Saint-Pierre 
277*abfe23dcSPhilippe Saint-Pierre 
278*abfe23dcSPhilippe Saint-Pierre BView*
279*abfe23dcSPhilippe Saint-Pierre GIFTranslator::NewConfigView(TranslatorSettings *settings)
280*abfe23dcSPhilippe Saint-Pierre {
281*abfe23dcSPhilippe Saint-Pierre 	return new GIFView(settings);
2829949213aSStephan Aßmus }
2839949213aSStephan Aßmus 
2849949213aSStephan Aßmus 
2859949213aSStephan Aßmus int
2869949213aSStephan Aßmus main()
2879949213aSStephan Aßmus {
288*abfe23dcSPhilippe Saint-Pierre         BApplication app("application/x-vnd.Haiku-GIFTranslator");
289*abfe23dcSPhilippe Saint-Pierre         status_t result;
290*abfe23dcSPhilippe Saint-Pierre         result = LaunchTranslatorWindow(new GIFTranslator,
291*abfe23dcSPhilippe Saint-Pierre                 B_TRANSLATE("GIF Settings"), kRectView);
292*abfe23dcSPhilippe Saint-Pierre         if (result == B_OK) {
293*abfe23dcSPhilippe Saint-Pierre                 app.Run();
2949949213aSStephan Aßmus                 return 0;
295*abfe23dcSPhilippe Saint-Pierre         } else
296*abfe23dcSPhilippe Saint-Pierre                 return 1;
2979949213aSStephan Aßmus }
298