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