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 //////////////////////////////////////////////////////////////////////////////// 155e4c29a6SJohn Scipione 16abfe23dcSPhilippe Saint-Pierre // Additional authors: Stephan Aßmus, <superstippi@gmx.de> 175e4c29a6SJohn Scipione // John Scipione, <jscipione@gmail.com> 189949213aSStephan Aßmus 199949213aSStephan Aßmus #include "GIFTranslator.h" 205e4c29a6SJohn Scipione 215e4c29a6SJohn Scipione #include <stdio.h> 225e4c29a6SJohn Scipione #include <stdlib.h> 235e4c29a6SJohn Scipione #include <string.h> 245e4c29a6SJohn Scipione #include <syslog.h> 2570d59669SSiarzhuk Zharski 26abfe23dcSPhilippe Saint-Pierre #include <Application.h> 279949213aSStephan Aßmus #include <ByteOrder.h> 2870d59669SSiarzhuk Zharski #include <Catalog.h> 299949213aSStephan Aßmus #include <DataIO.h> 3070d59669SSiarzhuk Zharski #include <InterfaceDefs.h> 319949213aSStephan Aßmus #include <TranslatorAddOn.h> 329949213aSStephan Aßmus #include <TranslatorFormats.h> 33c030befbSJohn Scipione #include <TypeConstants.h> 3470d59669SSiarzhuk Zharski 355e4c29a6SJohn Scipione #include "GIFLoad.h" 36c030befbSJohn Scipione #include "GIFSave.h" 37c030befbSJohn Scipione #include "GIFView.h" 38abfe23dcSPhilippe Saint-Pierre #include "TranslatorWindow.h" 39abfe23dcSPhilippe Saint-Pierre 405e4c29a6SJohn Scipione 419949213aSStephan Aßmus #ifndef GIF_TYPE 429949213aSStephan Aßmus #define GIF_TYPE 'GIF ' 439949213aSStephan Aßmus #endif 449949213aSStephan Aßmus 45546208a5SOliver Tappe #undef B_TRANSLATION_CONTEXT 46546208a5SOliver Tappe #define B_TRANSLATION_CONTEXT "GIFTranslator" 4770d59669SSiarzhuk Zharski 4870d59669SSiarzhuk Zharski 499949213aSStephan Aßmus bool debug = false; 505e4c29a6SJohn Scipione // this global will be externed in other files - set once here 515e4c29a6SJohn Scipione // for the entire translator 529949213aSStephan Aßmus 535e4c29a6SJohn Scipione bool DetermineType(BPositionIO* source, bool* isGif); 549949213aSStephan Aßmus status_t GetBitmap(BPositionIO* in, BBitmap** out); 559949213aSStephan Aßmus 56abfe23dcSPhilippe Saint-Pierre static const translation_format sInputFormats[] = { 575e4c29a6SJohn Scipione { 585e4c29a6SJohn Scipione GIF_TYPE, 595e4c29a6SJohn Scipione B_TRANSLATOR_BITMAP, 605e4c29a6SJohn Scipione GIF_IN_QUALITY, 615e4c29a6SJohn Scipione GIF_IN_CAPABILITY, 625e4c29a6SJohn Scipione "image/gif", 635e4c29a6SJohn Scipione "GIF image" 645e4c29a6SJohn Scipione }, 655e4c29a6SJohn Scipione { 665e4c29a6SJohn Scipione B_TRANSLATOR_BITMAP, 675e4c29a6SJohn Scipione B_TRANSLATOR_BITMAP, 685e4c29a6SJohn Scipione BBM_IN_QUALITY, 695e4c29a6SJohn Scipione BBM_IN_CAPABILITY, 705e4c29a6SJohn Scipione "image/x-be-bitmap", 715e4c29a6SJohn Scipione "Be Bitmap Format (GIFTranslator)" 725e4c29a6SJohn Scipione } 739949213aSStephan Aßmus }; 749949213aSStephan Aßmus 75abfe23dcSPhilippe Saint-Pierre static const translation_format sOutputFormats[] = { 765e4c29a6SJohn Scipione { 775e4c29a6SJohn Scipione GIF_TYPE, 785e4c29a6SJohn Scipione B_TRANSLATOR_BITMAP, 795e4c29a6SJohn Scipione GIF_OUT_QUALITY, 805e4c29a6SJohn Scipione GIF_OUT_CAPABILITY, 815e4c29a6SJohn Scipione "image/gif", 825e4c29a6SJohn Scipione "GIF image" 835e4c29a6SJohn Scipione }, 845e4c29a6SJohn Scipione { 855e4c29a6SJohn Scipione B_TRANSLATOR_BITMAP, 865e4c29a6SJohn Scipione B_TRANSLATOR_BITMAP, 875e4c29a6SJohn Scipione BBM_OUT_QUALITY, 885e4c29a6SJohn Scipione BBM_OUT_CAPABILITY, 895e4c29a6SJohn Scipione "image/x-be-bitmap", 905e4c29a6SJohn Scipione "Be Bitmap Format (GIFTranslator)" 915e4c29a6SJohn Scipione } 929949213aSStephan Aßmus }; 939949213aSStephan Aßmus 94abfe23dcSPhilippe Saint-Pierre // Default settings for the Translator 95abfe23dcSPhilippe Saint-Pierre static const TranSetting sDefaultSettings[] = { 96abfe23dcSPhilippe Saint-Pierre { B_TRANSLATOR_EXT_HEADER_ONLY, TRAN_SETTING_BOOL, false }, 97abfe23dcSPhilippe Saint-Pierre { B_TRANSLATOR_EXT_DATA_ONLY, TRAN_SETTING_BOOL, false }, 98abfe23dcSPhilippe Saint-Pierre { GIF_SETTING_INTERLACED, TRAN_SETTING_BOOL, false }, 99abfe23dcSPhilippe Saint-Pierre { GIF_SETTING_USE_TRANSPARENT, TRAN_SETTING_BOOL, false }, 100abfe23dcSPhilippe Saint-Pierre { GIF_SETTING_USE_TRANSPARENT_AUTO, TRAN_SETTING_BOOL, false }, 101abfe23dcSPhilippe Saint-Pierre { GIF_SETTING_USE_DITHERING, TRAN_SETTING_BOOL, false }, 102abfe23dcSPhilippe Saint-Pierre { GIF_SETTING_PALETTE_MODE, TRAN_SETTING_INT32, 0 }, 103abfe23dcSPhilippe Saint-Pierre { GIF_SETTING_PALETTE_SIZE, TRAN_SETTING_INT32, 8 }, 104abfe23dcSPhilippe Saint-Pierre { GIF_SETTING_TRANSPARENT_RED, TRAN_SETTING_INT32, 0 }, 105abfe23dcSPhilippe Saint-Pierre { GIF_SETTING_TRANSPARENT_GREEN, TRAN_SETTING_INT32, 0 }, 106abfe23dcSPhilippe Saint-Pierre { GIF_SETTING_TRANSPARENT_BLUE, TRAN_SETTING_INT32, 0 } 107abfe23dcSPhilippe Saint-Pierre }; 1089949213aSStephan Aßmus 109abfe23dcSPhilippe Saint-Pierre const uint32 kNumInputFormats = sizeof(sInputFormats) / sizeof(translation_format); 110abfe23dcSPhilippe Saint-Pierre const uint32 kNumOutputFormats = sizeof(sOutputFormats) / sizeof(translation_format); 111abfe23dcSPhilippe Saint-Pierre const uint32 kNumDefaultSettings = sizeof(sDefaultSettings) / sizeof(TranSetting); 1129949213aSStephan Aßmus 1139949213aSStephan Aßmus 1145adf9d6eSJohn Scipione /*! Look at first few bytes in stream to determine type - throw it back 1155adf9d6eSJohn Scipione if it is not a GIF or a BBitmap that we understand. 1165e4c29a6SJohn Scipione */ 1179949213aSStephan Aßmus bool 1185e4c29a6SJohn Scipione DetermineType(BPositionIO* source, bool* isGif) 1199949213aSStephan Aßmus { 1209949213aSStephan Aßmus unsigned char header[7]; 1215e4c29a6SJohn Scipione *isGif = true; 122abfe23dcSPhilippe Saint-Pierre if (source->Read(header, 6) != 6) 123abfe23dcSPhilippe Saint-Pierre return false; 124*01be25aeSJohn Scipione 1259949213aSStephan Aßmus header[6] = 0x00; 1269949213aSStephan Aßmus 1275e4c29a6SJohn Scipione if (strcmp((char*)header, "GIF87a") != 0 1285e4c29a6SJohn Scipione && strcmp((char*)header, "GIF89a") != 0) { 1295e4c29a6SJohn Scipione *isGif = false; 13070d59669SSiarzhuk Zharski int32 magic = (header[0] << 24) + (header[1] << 16) + (header[2] << 8) 13170d59669SSiarzhuk Zharski + header[3]; 132abfe23dcSPhilippe Saint-Pierre if (magic != B_TRANSLATOR_BITMAP) 133abfe23dcSPhilippe Saint-Pierre return false; 1345e4c29a6SJohn Scipione 1359949213aSStephan Aßmus source->Seek(5 * 4 - 2, SEEK_CUR); 1369949213aSStephan Aßmus color_space cs; 137abfe23dcSPhilippe Saint-Pierre if (source->Read(&cs, 4) != 4) 138abfe23dcSPhilippe Saint-Pierre return false; 1395e4c29a6SJohn Scipione 1409949213aSStephan Aßmus cs = (color_space)B_BENDIAN_TO_HOST_INT32(cs); 141abfe23dcSPhilippe Saint-Pierre if (cs != B_RGB32 && cs != B_RGBA32 && cs != B_RGB32_BIG 1425e4c29a6SJohn Scipione && cs != B_RGBA32_BIG) { 143abfe23dcSPhilippe Saint-Pierre return false; 1449949213aSStephan Aßmus } 1455e4c29a6SJohn Scipione } 1469949213aSStephan Aßmus 1479949213aSStephan Aßmus source->Seek(0, SEEK_SET); 1489949213aSStephan Aßmus return true; 1499949213aSStephan Aßmus } 1509949213aSStephan Aßmus 1519949213aSStephan Aßmus 1529949213aSStephan Aßmus status_t 1539949213aSStephan Aßmus GetBitmap(BPositionIO* in, BBitmap** out) 1549949213aSStephan Aßmus { 1559949213aSStephan Aßmus TranslatorBitmap header; 156*01be25aeSJohn Scipione status_t result = in->Read(&header, sizeof(header)); 157*01be25aeSJohn Scipione if (result != sizeof(header)) 1589949213aSStephan Aßmus return B_IO_ERROR; 1599949213aSStephan Aßmus 1609949213aSStephan Aßmus header.magic = B_BENDIAN_TO_HOST_INT32(header.magic); 1619949213aSStephan Aßmus header.bounds.left = B_BENDIAN_TO_HOST_FLOAT(header.bounds.left); 1629949213aSStephan Aßmus header.bounds.top = B_BENDIAN_TO_HOST_FLOAT(header.bounds.top); 1639949213aSStephan Aßmus header.bounds.right = B_BENDIAN_TO_HOST_FLOAT(header.bounds.right); 1649949213aSStephan Aßmus header.bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(header.bounds.bottom); 1659949213aSStephan Aßmus header.rowBytes = B_BENDIAN_TO_HOST_INT32(header.rowBytes); 1669949213aSStephan Aßmus header.colors = (color_space)B_BENDIAN_TO_HOST_INT32(header.colors); 1679949213aSStephan Aßmus header.dataSize = B_BENDIAN_TO_HOST_INT32(header.dataSize); 1689949213aSStephan Aßmus 1695e4c29a6SJohn Scipione // dump data from stream into a BBitmap 170*01be25aeSJohn Scipione *out = new BBitmap(header.bounds, header.colors); 171*01be25aeSJohn Scipione if (!(*out)->IsValid()) { 172*01be25aeSJohn Scipione delete *out; 1739949213aSStephan Aßmus return B_NO_MEMORY; 1749949213aSStephan Aßmus } 1755e4c29a6SJohn Scipione 176*01be25aeSJohn Scipione result = in->Read((*out)->Bits(), header.dataSize); 177*01be25aeSJohn Scipione if (result != (status_t)header.dataSize) { 178*01be25aeSJohn Scipione delete *out; 179de6ba1a0SAdrien Destugues return B_IO_ERROR; 180de6ba1a0SAdrien Destugues } 181*01be25aeSJohn Scipione 182*01be25aeSJohn Scipione return B_OK; 1839949213aSStephan Aßmus } 1849949213aSStephan Aßmus 1859949213aSStephan Aßmus 1865adf9d6eSJohn Scipione /*! Required identify function - may need to read entire header, not sure 18781abd9edSJohn Scipione */ 1889949213aSStephan Aßmus status_t 189abfe23dcSPhilippe Saint-Pierre GIFTranslator::DerivedIdentify(BPositionIO* inSource, 190abfe23dcSPhilippe Saint-Pierre const translation_format* inFormat, BMessage* ioExtension, 191abfe23dcSPhilippe Saint-Pierre translator_info* outInfo, uint32 outType) 1929949213aSStephan Aßmus { 1939949213aSStephan Aßmus const char* debug_text = getenv("GIF_TRANSLATOR_DEBUG"); 194abfe23dcSPhilippe Saint-Pierre if (debug_text != NULL && atoi(debug_text) != 0) 195abfe23dcSPhilippe Saint-Pierre debug = true; 1969949213aSStephan Aßmus 197abfe23dcSPhilippe Saint-Pierre if (outType == 0) 198abfe23dcSPhilippe Saint-Pierre outType = B_TRANSLATOR_BITMAP; 1995e4c29a6SJohn Scipione 20070d59669SSiarzhuk Zharski if (outType != GIF_TYPE && outType != B_TRANSLATOR_BITMAP) 20170d59669SSiarzhuk Zharski return B_NO_TRANSLATOR; 2029949213aSStephan Aßmus 2035e4c29a6SJohn Scipione bool isGif; 2045e4c29a6SJohn Scipione if (!DetermineType(inSource, &isGif)) 205abfe23dcSPhilippe Saint-Pierre return B_NO_TRANSLATOR; 2065e4c29a6SJohn Scipione 2075e4c29a6SJohn Scipione if (!isGif && inFormat != NULL && inFormat->type != B_TRANSLATOR_BITMAP) 2089949213aSStephan Aßmus return B_NO_TRANSLATOR; 2099949213aSStephan Aßmus 2109949213aSStephan Aßmus outInfo->group = B_TRANSLATOR_BITMAP; 2115e4c29a6SJohn Scipione if (isGif) { 2129949213aSStephan Aßmus outInfo->type = GIF_TYPE; 213abfe23dcSPhilippe Saint-Pierre outInfo->quality = GIF_IN_QUALITY; 214abfe23dcSPhilippe Saint-Pierre outInfo->capability = GIF_IN_CAPABILITY; 215aec33db1SPhilippe Saint-Pierre strlcpy(outInfo->name, B_TRANSLATE("GIF image"), sizeof(outInfo->name)); 2169949213aSStephan Aßmus strcpy(outInfo->MIME, "image/gif"); 217abfe23dcSPhilippe Saint-Pierre } else { 2189949213aSStephan Aßmus outInfo->type = B_TRANSLATOR_BITMAP; 219abfe23dcSPhilippe Saint-Pierre outInfo->quality = BBM_IN_QUALITY; 220abfe23dcSPhilippe Saint-Pierre outInfo->capability = BBM_IN_CAPABILITY; 221aec33db1SPhilippe Saint-Pierre strlcpy(outInfo->name, B_TRANSLATE("Be Bitmap Format (GIFTranslator)"), 2223927bd3cSPhilippe Saint-Pierre sizeof(outInfo->name)); 2239949213aSStephan Aßmus strcpy(outInfo->MIME, "image/x-be-bitmap"); 2249949213aSStephan Aßmus } 2255e4c29a6SJohn Scipione 2269949213aSStephan Aßmus return B_OK; 2279949213aSStephan Aßmus } 2289949213aSStephan Aßmus 2299949213aSStephan Aßmus 2305adf9d6eSJohn Scipione /*! Main required function - assumes that an incoming GIF must be translated 2315adf9d6eSJohn Scipione to a BBitmap, and vice versa - this could be improved 2325e4c29a6SJohn Scipione */ 2339949213aSStephan Aßmus status_t 234abfe23dcSPhilippe Saint-Pierre GIFTranslator::DerivedTranslate(BPositionIO* inSource, 235abfe23dcSPhilippe Saint-Pierre const translator_info* inInfo, BMessage* ioExtension, uint32 outType, 236abfe23dcSPhilippe Saint-Pierre BPositionIO* outDestination, int32 baseType) 2379949213aSStephan Aßmus { 2389949213aSStephan Aßmus const char* debug_text = getenv("GIF_TRANSLATOR_DEBUG"); 2395e4c29a6SJohn Scipione if (debug_text != NULL && atoi(debug_text) != 0) 2405e4c29a6SJohn Scipione debug = true; 2419949213aSStephan Aßmus 2425e4c29a6SJohn Scipione if (outType == 0) 2435e4c29a6SJohn Scipione outType = B_TRANSLATOR_BITMAP; 2445e4c29a6SJohn Scipione 2455e4c29a6SJohn Scipione if (outType != GIF_TYPE && outType != B_TRANSLATOR_BITMAP) 2469949213aSStephan Aßmus return B_NO_TRANSLATOR; 2479949213aSStephan Aßmus 2485e4c29a6SJohn Scipione bool isGif; 2495e4c29a6SJohn Scipione if (!DetermineType(inSource, &isGif)) 2505e4c29a6SJohn Scipione return B_NO_TRANSLATOR; 2515e4c29a6SJohn Scipione 2525e4c29a6SJohn Scipione if (!isGif && inInfo->type != B_TRANSLATOR_BITMAP) 2535e4c29a6SJohn Scipione return B_NO_TRANSLATOR; 2549949213aSStephan Aßmus 255*01be25aeSJohn Scipione status_t result = B_OK; 2569949213aSStephan Aßmus bigtime_t now = system_time(); 2575e4c29a6SJohn Scipione 2585e4c29a6SJohn Scipione if (!isGif) { 2595e4c29a6SJohn Scipione // BBitmap to GIF 260116e78d4SJohn Scipione BBitmap* bitmap; 261*01be25aeSJohn Scipione result = GetBitmap(inSource, &bitmap); 262*01be25aeSJohn Scipione if (result != B_OK) 263*01be25aeSJohn Scipione return result; 2645e4c29a6SJohn Scipione 26581abd9edSJohn Scipione GIFSave* gifSave = new GIFSave(bitmap, outDestination, fSettings); 26681abd9edSJohn Scipione if (gifSave->fatalerror) { 26781abd9edSJohn Scipione delete gifSave; 2687bc02c61SStefano Ceccherini delete bitmap; 2699949213aSStephan Aßmus return B_NO_MEMORY; 2709949213aSStephan Aßmus } 27181abd9edSJohn Scipione delete gifSave; 2727bc02c61SStefano Ceccherini delete bitmap; 2735e4c29a6SJohn Scipione } else { 2745e4c29a6SJohn Scipione // GIF to BBitmap 2755e4c29a6SJohn Scipione GIFLoad* gifLoad = new GIFLoad(inSource, outDestination); 2765e4c29a6SJohn Scipione if (gifLoad->fatalerror) { 2775e4c29a6SJohn Scipione delete gifLoad; 2789949213aSStephan Aßmus return B_NO_MEMORY; 2799949213aSStephan Aßmus } 2805e4c29a6SJohn Scipione delete gifLoad; 2819949213aSStephan Aßmus } 2829949213aSStephan Aßmus 2839949213aSStephan Aßmus if (debug) { 2849949213aSStephan Aßmus now = system_time() - now; 28584bff752SJohn Scipione syslog(LOG_INFO, "Translate() - Translation took %Ld microseconds\n", 2865e4c29a6SJohn Scipione now); 2879949213aSStephan Aßmus } 2889949213aSStephan Aßmus return B_OK; 2899949213aSStephan Aßmus } 2909949213aSStephan Aßmus 2919949213aSStephan Aßmus 292abfe23dcSPhilippe Saint-Pierre BTranslator* 293abfe23dcSPhilippe Saint-Pierre make_nth_translator(int32 n, image_id you, uint32 flags, ...) 2949949213aSStephan Aßmus { 295abfe23dcSPhilippe Saint-Pierre if (n == 0) 296abfe23dcSPhilippe Saint-Pierre return new GIFTranslator(); 297abfe23dcSPhilippe Saint-Pierre 298abfe23dcSPhilippe Saint-Pierre return NULL; 299abfe23dcSPhilippe Saint-Pierre } 300abfe23dcSPhilippe Saint-Pierre 301abfe23dcSPhilippe Saint-Pierre 302abfe23dcSPhilippe Saint-Pierre GIFTranslator::GIFTranslator() 3035e4c29a6SJohn Scipione : 3045e4c29a6SJohn Scipione BaseTranslator(B_TRANSLATE("GIF images"), 305abfe23dcSPhilippe Saint-Pierre B_TRANSLATE("GIF image translator"), 306abfe23dcSPhilippe Saint-Pierre GIF_TRANSLATOR_VERSION, 307abfe23dcSPhilippe Saint-Pierre sInputFormats, kNumInputFormats, 308abfe23dcSPhilippe Saint-Pierre sOutputFormats, kNumOutputFormats, 309abfe23dcSPhilippe Saint-Pierre "GIFTranslator_Settings", 310abfe23dcSPhilippe Saint-Pierre sDefaultSettings, kNumDefaultSettings, 311abfe23dcSPhilippe Saint-Pierre B_TRANSLATOR_BITMAP, B_GIF_FORMAT) 312abfe23dcSPhilippe Saint-Pierre { 313abfe23dcSPhilippe Saint-Pierre } 314abfe23dcSPhilippe Saint-Pierre 315abfe23dcSPhilippe Saint-Pierre 316abfe23dcSPhilippe Saint-Pierre GIFTranslator::~GIFTranslator() 317abfe23dcSPhilippe Saint-Pierre { 318abfe23dcSPhilippe Saint-Pierre } 319abfe23dcSPhilippe Saint-Pierre 320abfe23dcSPhilippe Saint-Pierre 321abfe23dcSPhilippe Saint-Pierre BView* 322abfe23dcSPhilippe Saint-Pierre GIFTranslator::NewConfigView(TranslatorSettings* settings) 323abfe23dcSPhilippe Saint-Pierre { 324abfe23dcSPhilippe Saint-Pierre return new GIFView(settings); 3259949213aSStephan Aßmus } 3269949213aSStephan Aßmus 3279949213aSStephan Aßmus 3289949213aSStephan Aßmus int 3299949213aSStephan Aßmus main() 3309949213aSStephan Aßmus { 331abfe23dcSPhilippe Saint-Pierre BApplication app("application/x-vnd.Haiku-GIFTranslator"); 3325e4c29a6SJohn Scipione status_t result = LaunchTranslatorWindow(new GIFTranslator, 333abfe23dcSPhilippe Saint-Pierre B_TRANSLATE("GIF Settings"), kRectView); 334abfe23dcSPhilippe Saint-Pierre if (result == B_OK) { 335abfe23dcSPhilippe Saint-Pierre app.Run(); 3369949213aSStephan Aßmus return 0; 3375e4c29a6SJohn Scipione } 3385e4c29a6SJohn Scipione 339abfe23dcSPhilippe Saint-Pierre return 1; 3409949213aSStephan Aßmus } 341