xref: /haiku/src/add-ons/translators/gif/GIFTranslator.cpp (revision 70d5966963513ff47a456ba70b7d2eec0f99648d)
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 ////////////////////////////////////////////////////////////////////////////////
159949213aSStephan Aßmus 
169949213aSStephan Aßmus #include "GIFTranslator.h"
179949213aSStephan Aßmus #include "GIFWindow.h"
189949213aSStephan Aßmus #include "GIFView.h"
199949213aSStephan Aßmus #include "GIFSave.h"
209949213aSStephan Aßmus #include "GIFLoad.h"
21*70d59669SSiarzhuk Zharski 
22*70d59669SSiarzhuk Zharski 
239949213aSStephan Aßmus #include <ByteOrder.h>
24*70d59669SSiarzhuk Zharski #include <Catalog.h>
259949213aSStephan Aßmus #include <DataIO.h>
26*70d59669SSiarzhuk Zharski #include <InterfaceDefs.h>
27*70d59669SSiarzhuk Zharski #include <TypeConstants.h>
289949213aSStephan Aßmus #include <TranslatorAddOn.h>
299949213aSStephan Aßmus #include <TranslatorFormats.h>
30*70d59669SSiarzhuk Zharski 
319949213aSStephan Aßmus #include <stdio.h>
329949213aSStephan Aßmus #include <stdlib.h>
339949213aSStephan Aßmus #include <string.h>
34*70d59669SSiarzhuk Zharski #include <syslog.h>
359949213aSStephan Aßmus 
369949213aSStephan Aßmus #ifndef GIF_TYPE
379949213aSStephan Aßmus #define GIF_TYPE 'GIF '
389949213aSStephan Aßmus #endif
399949213aSStephan Aßmus 
40*70d59669SSiarzhuk Zharski #undef B_TRANSLATE_CONTEXT
41*70d59669SSiarzhuk Zharski #define B_TRANSLATE_CONTEXT "GIFTranslator"
42*70d59669SSiarzhuk Zharski 
43*70d59669SSiarzhuk Zharski 
449949213aSStephan Aßmus // This global will be externed in other files - set once here
459949213aSStephan Aßmus // for the entire translator
469949213aSStephan Aßmus bool debug = false;
479949213aSStephan Aßmus 
489949213aSStephan Aßmus bool DetermineType(BPositionIO *source, bool *is_gif);
499949213aSStephan Aßmus status_t GetBitmap(BPositionIO *in, BBitmap **out);
509949213aSStephan Aßmus 
519949213aSStephan Aßmus /* Required data */
52fcc3e627SStephan Aßmus char translatorName[] = "GIF images";
539949213aSStephan Aßmus char translatorInfo[] = "GIF image translator v1.4";
549949213aSStephan Aßmus int32 translatorVersion = 0x140;
559949213aSStephan Aßmus 
569949213aSStephan Aßmus translation_format inputFormats[] = {
57*70d59669SSiarzhuk Zharski 	{ GIF_TYPE, B_TRANSLATOR_BITMAP, 0.8, 0.8, "image/gif",
58*70d59669SSiarzhuk Zharski 		"GIF image" },
59*70d59669SSiarzhuk Zharski 	{ B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.3, 0.3, "image/x-be-bitmap",
60*70d59669SSiarzhuk Zharski 		"Be Bitmap Format (GIFTranslator)" },
619949213aSStephan Aßmus 	{ 0 }
629949213aSStephan Aßmus };
639949213aSStephan Aßmus 
649949213aSStephan Aßmus translation_format outputFormats[] = {
65*70d59669SSiarzhuk Zharski 	{ GIF_TYPE, B_TRANSLATOR_BITMAP, 0.8, 0.8, "image/gif",
66*70d59669SSiarzhuk Zharski 		"GIF image" },
67*70d59669SSiarzhuk Zharski 	{ B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.3, 0.3, "image/x-be-bitmap",
68*70d59669SSiarzhuk Zharski 		"Be Bitmap Format (GIFTranslator)" },
699949213aSStephan Aßmus 	{ 0 }
709949213aSStephan Aßmus };
719949213aSStephan Aßmus 
729949213aSStephan Aßmus 
739949213aSStephan Aßmus /* Build a pretty view for DataTranslations */
749949213aSStephan Aßmus status_t
759949213aSStephan Aßmus MakeConfig(BMessage *ioExtension, BView **outView, BRect *outExtent)
769949213aSStephan Aßmus {
77a76f629eSRyan Leavengood 	GIFView *gifview = new GIFView("TranslatorView");
789949213aSStephan Aßmus 	*outView = gifview;
79a76f629eSRyan Leavengood 	gifview->ResizeTo(gifview->ExplicitPreferredSize());
80a76f629eSRyan Leavengood 	*outExtent = gifview->Bounds();
819949213aSStephan Aßmus 	return B_OK;
829949213aSStephan Aßmus }
839949213aSStephan Aßmus 
849949213aSStephan Aßmus 
859949213aSStephan Aßmus /* Look at first few bytes in stream to determine type - throw it back
869949213aSStephan Aßmus    if it is not a GIF or a BBitmap that we understand */
879949213aSStephan Aßmus bool
889949213aSStephan Aßmus DetermineType(BPositionIO *source, bool *is_gif)
899949213aSStephan Aßmus {
909949213aSStephan Aßmus 	unsigned char header[7];
919949213aSStephan Aßmus 	*is_gif = true;
929949213aSStephan Aßmus 	if (source->Read(header, 6) != 6) return false;
939949213aSStephan Aßmus 	header[6] = 0x00;
949949213aSStephan Aßmus 
95*70d59669SSiarzhuk Zharski 	if (strcmp((char *)header, "GIF87a") != 0 && strcmp((char *)header,
96*70d59669SSiarzhuk Zharski 		"GIF89a") != 0) {
979949213aSStephan Aßmus 		*is_gif = false;
98*70d59669SSiarzhuk Zharski 		int32 magic = (header[0] << 24) + (header[1] << 16) + (header[2] << 8)
99*70d59669SSiarzhuk Zharski 			+ header[3];
1009949213aSStephan Aßmus 		if (magic != B_TRANSLATOR_BITMAP) return false;
1019949213aSStephan Aßmus 		source->Seek(5 * 4 - 2, SEEK_CUR);
1029949213aSStephan Aßmus 		color_space cs;
1039949213aSStephan Aßmus 		if (source->Read(&cs, 4) != 4) return false;
1049949213aSStephan Aßmus 		cs = (color_space)B_BENDIAN_TO_HOST_INT32(cs);
105*70d59669SSiarzhuk Zharski 		if (cs != B_RGB32 && cs != B_RGBA32 && cs != B_RGB32_BIG && cs
106*70d59669SSiarzhuk Zharski 			!= B_RGBA32_BIG) return false;
1079949213aSStephan Aßmus 	}
1089949213aSStephan Aßmus 
1099949213aSStephan Aßmus 	source->Seek(0, SEEK_SET);
1109949213aSStephan Aßmus 	return true;
1119949213aSStephan Aßmus }
1129949213aSStephan Aßmus 
1139949213aSStephan Aßmus 
1149949213aSStephan Aßmus /* Dump data from stream into a BBitmap */
1159949213aSStephan Aßmus status_t
1169949213aSStephan Aßmus GetBitmap(BPositionIO *in, BBitmap **out)
1179949213aSStephan Aßmus {
1189949213aSStephan Aßmus 	TranslatorBitmap header;
1199949213aSStephan Aßmus 
1209949213aSStephan Aßmus 	status_t err = in->Read(&header, sizeof(header));
1219949213aSStephan Aßmus 	if (err != sizeof(header))
1229949213aSStephan Aßmus 		return B_IO_ERROR;
1239949213aSStephan Aßmus 
1249949213aSStephan Aßmus 	header.magic = B_BENDIAN_TO_HOST_INT32(header.magic);
1259949213aSStephan Aßmus 	header.bounds.left = B_BENDIAN_TO_HOST_FLOAT(header.bounds.left);
1269949213aSStephan Aßmus 	header.bounds.top = B_BENDIAN_TO_HOST_FLOAT(header.bounds.top);
1279949213aSStephan Aßmus 	header.bounds.right = B_BENDIAN_TO_HOST_FLOAT(header.bounds.right);
1289949213aSStephan Aßmus 	header.bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(header.bounds.bottom);
1299949213aSStephan Aßmus 	header.rowBytes = B_BENDIAN_TO_HOST_INT32(header.rowBytes);
1309949213aSStephan Aßmus 	header.colors = (color_space)B_BENDIAN_TO_HOST_INT32(header.colors);
1319949213aSStephan Aßmus 	header.dataSize = B_BENDIAN_TO_HOST_INT32(header.dataSize);
1329949213aSStephan Aßmus 
1339949213aSStephan Aßmus 	BBitmap *bitmap = new BBitmap(header.bounds, header.colors);
1349949213aSStephan Aßmus 	*out = bitmap;
1359949213aSStephan Aßmus 	if (bitmap == NULL) return B_NO_MEMORY;
1369949213aSStephan Aßmus 	unsigned char *bits = (unsigned char *)bitmap->Bits();
1379949213aSStephan Aßmus 	if (bits == NULL) {
1389949213aSStephan Aßmus 		delete bitmap;
1399949213aSStephan Aßmus 		return B_NO_MEMORY;
1409949213aSStephan Aßmus 	}
1419949213aSStephan Aßmus 	err = in->Read(bits, header.dataSize);
1429949213aSStephan Aßmus 	if (err == (status_t)header.dataSize) return B_OK;
143de6ba1a0SAdrien Destugues 	else {
144de6ba1a0SAdrien Destugues 		delete bitmap;
145de6ba1a0SAdrien Destugues 		return B_IO_ERROR;
146de6ba1a0SAdrien Destugues 	}
1479949213aSStephan Aßmus }
1489949213aSStephan Aßmus 
1499949213aSStephan Aßmus 
1509949213aSStephan Aßmus /* Required Identify function - may need to read entire header, not sure */
1519949213aSStephan Aßmus status_t
1529949213aSStephan Aßmus Identify(BPositionIO *inSource, const translation_format *inFormat,
1539949213aSStephan Aßmus 	BMessage *ioExtension, translator_info *outInfo, uint32 outType)
1549949213aSStephan Aßmus {
1559949213aSStephan Aßmus 
1569949213aSStephan Aßmus 	const char *debug_text = getenv("GIF_TRANSLATOR_DEBUG");
1579949213aSStephan Aßmus 	if ((debug_text != NULL) && (atoi(debug_text) != 0)) debug = true;
1589949213aSStephan Aßmus 
1599949213aSStephan Aßmus 	if (outType == 0) outType = B_TRANSLATOR_BITMAP;
160*70d59669SSiarzhuk Zharski 	if (outType != GIF_TYPE && outType != B_TRANSLATOR_BITMAP)
161*70d59669SSiarzhuk Zharski 		return B_NO_TRANSLATOR;
1629949213aSStephan Aßmus 
1639949213aSStephan Aßmus 	bool is_gif;
1649949213aSStephan Aßmus 	if (!DetermineType(inSource, &is_gif)) return B_NO_TRANSLATOR;
1659949213aSStephan Aßmus 	if (!is_gif && inFormat != NULL && inFormat->type != B_TRANSLATOR_BITMAP)
1669949213aSStephan Aßmus 		return B_NO_TRANSLATOR;
1679949213aSStephan Aßmus 
1689949213aSStephan Aßmus 	outInfo->group = B_TRANSLATOR_BITMAP;
1699949213aSStephan Aßmus 	if (is_gif) {
1709949213aSStephan Aßmus 		outInfo->type = GIF_TYPE;
1719949213aSStephan Aßmus 		outInfo->quality = 0.8;
1729949213aSStephan Aßmus 		outInfo->capability = 0.8;
173*70d59669SSiarzhuk Zharski 		strcpy(outInfo->name, B_TRANSLATE("GIF image"));
1749949213aSStephan Aßmus 		strcpy(outInfo->MIME, "image/gif");
1759949213aSStephan Aßmus 	}
1769949213aSStephan Aßmus 	else {
1779949213aSStephan Aßmus 		outInfo->type = B_TRANSLATOR_BITMAP;
1789949213aSStephan Aßmus 		outInfo->quality = 0.3;
1799949213aSStephan Aßmus 		outInfo->capability = 0.3;
180*70d59669SSiarzhuk Zharski 		strcpy(outInfo->name, B_TRANSLATE("Be Bitmap Format (GIFTranslator)"));
1819949213aSStephan Aßmus 		strcpy(outInfo->MIME, "image/x-be-bitmap");
1829949213aSStephan Aßmus 	}
1839949213aSStephan Aßmus 	return B_OK;
1849949213aSStephan Aßmus }
1859949213aSStephan Aßmus 
1869949213aSStephan Aßmus 
1879949213aSStephan Aßmus /* Main required function - assumes that an incoming GIF must be translated
1889949213aSStephan Aßmus    to a BBitmap, and vice versa - this could be improved */
1899949213aSStephan Aßmus status_t
1909949213aSStephan Aßmus Translate(BPositionIO *inSource, const translator_info *inInfo,
1919949213aSStephan Aßmus 	BMessage *ioExtension, uint32 outType, BPositionIO *outDestination)
1929949213aSStephan Aßmus {
1939949213aSStephan Aßmus 
1949949213aSStephan Aßmus 	const char *debug_text = getenv("GIF_TRANSLATOR_DEBUG");
1959949213aSStephan Aßmus 	if ((debug_text != NULL) && (atoi(debug_text) != 0)) debug = true;
1969949213aSStephan Aßmus 
1979949213aSStephan Aßmus 	if (outType == 0) outType = B_TRANSLATOR_BITMAP;
1989949213aSStephan Aßmus 	if (outType != GIF_TYPE && outType != B_TRANSLATOR_BITMAP) {
1999949213aSStephan Aßmus 		return B_NO_TRANSLATOR;
2009949213aSStephan Aßmus 	}
2019949213aSStephan Aßmus 
2029949213aSStephan Aßmus 	bool is_gif;
2039949213aSStephan Aßmus 	if (!DetermineType(inSource, &is_gif)) return B_NO_TRANSLATOR;
2049949213aSStephan Aßmus 	if (!is_gif && inInfo->type != B_TRANSLATOR_BITMAP) return B_NO_TRANSLATOR;
2059949213aSStephan Aßmus 
2069949213aSStephan Aßmus 	status_t err = B_OK;
2079949213aSStephan Aßmus 	bigtime_t now = system_time();
2089949213aSStephan Aßmus 	// Going from BBitmap to GIF
2099949213aSStephan Aßmus 	if (!is_gif) {
2107bc02c61SStefano Ceccherini 		BBitmap *bitmap = NULL;
2117bc02c61SStefano Ceccherini 		err = GetBitmap(inSource, &bitmap);
2127bc02c61SStefano Ceccherini 		if (err != B_OK)
2137bc02c61SStefano Ceccherini 			return err;
2147bc02c61SStefano Ceccherini 		GIFSave *gs = new GIFSave(bitmap, outDestination);
2159949213aSStephan Aßmus 		if (gs->fatalerror) {
2169949213aSStephan Aßmus 			delete gs;
2177bc02c61SStefano Ceccherini 			delete bitmap;
2189949213aSStephan Aßmus 			return B_NO_MEMORY;
2199949213aSStephan Aßmus 		}
2209949213aSStephan Aßmus 		delete gs;
2217bc02c61SStefano Ceccherini 		delete bitmap;
2229949213aSStephan Aßmus 	} else { // GIF to BBitmap
2239949213aSStephan Aßmus 		GIFLoad *gl = new GIFLoad(inSource, outDestination);
2249949213aSStephan Aßmus 		if (gl->fatalerror) {
2259949213aSStephan Aßmus 			delete gl;
2269949213aSStephan Aßmus 			return B_NO_MEMORY;
2279949213aSStephan Aßmus 		}
2289949213aSStephan Aßmus 		delete gl;
2299949213aSStephan Aßmus 	}
2309949213aSStephan Aßmus 
2319949213aSStephan Aßmus 	if (debug) {
2329949213aSStephan Aßmus 		now = system_time() - now;
233*70d59669SSiarzhuk Zharski 		syslog(LOG_ERR, "Translate() - Translation took %Ld microseconds\n", now);
2349949213aSStephan Aßmus 	}
2359949213aSStephan Aßmus 	return B_OK;
2369949213aSStephan Aßmus }
2379949213aSStephan Aßmus 
2389949213aSStephan Aßmus 
2399949213aSStephan Aßmus GIFTranslator::GIFTranslator()
24097c99097SRyan Leavengood 	: BApplication("application/x-vnd.Haiku-GIFTranslator")
2419949213aSStephan Aßmus {
2429949213aSStephan Aßmus 	BRect rect(100, 100, 339, 339);
243*70d59669SSiarzhuk Zharski 	gifwindow = new GIFWindow(rect, B_TRANSLATE("GIF Settings"));
2449949213aSStephan Aßmus 	gifwindow->Show();
2459949213aSStephan Aßmus }
2469949213aSStephan Aßmus 
2479949213aSStephan Aßmus 
2489949213aSStephan Aßmus int
2499949213aSStephan Aßmus main()
2509949213aSStephan Aßmus {
2519949213aSStephan Aßmus 	GIFTranslator myapp;
2529949213aSStephan Aßmus 	myapp.Run();
2539949213aSStephan Aßmus 	return 0;
2549949213aSStephan Aßmus }
2559949213aSStephan Aßmus 
256