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> 3170d59669SSiarzhuk Zharski #include <TypeConstants.h> 329949213aSStephan Aßmus #include <TranslatorAddOn.h> 339949213aSStephan Aßmus #include <TranslatorFormats.h> 3470d59669SSiarzhuk Zharski 355e4c29a6SJohn Scipione #include "GIFView.h" 365e4c29a6SJohn Scipione #include "GIFSave.h" 375e4c29a6SJohn Scipione #include "GIFLoad.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 1149949213aSStephan Aßmus /* Look at first few bytes in stream to determine type - throw it back 1155e4c29a6SJohn 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; 1249949213aSStephan Aßmus header[6] = 0x00; 1259949213aSStephan Aßmus 1265e4c29a6SJohn Scipione if (strcmp((char*)header, "GIF87a") != 0 1275e4c29a6SJohn Scipione && strcmp((char*)header, "GIF89a") != 0) { 1285e4c29a6SJohn Scipione *isGif = false; 12970d59669SSiarzhuk Zharski int32 magic = (header[0] << 24) + (header[1] << 16) + (header[2] << 8) 13070d59669SSiarzhuk Zharski + header[3]; 131abfe23dcSPhilippe Saint-Pierre if (magic != B_TRANSLATOR_BITMAP) 132abfe23dcSPhilippe Saint-Pierre return false; 1335e4c29a6SJohn Scipione 1349949213aSStephan Aßmus source->Seek(5 * 4 - 2, SEEK_CUR); 1359949213aSStephan Aßmus color_space cs; 136abfe23dcSPhilippe Saint-Pierre if (source->Read(&cs, 4) != 4) 137abfe23dcSPhilippe Saint-Pierre return false; 1385e4c29a6SJohn Scipione 1399949213aSStephan Aßmus cs = (color_space)B_BENDIAN_TO_HOST_INT32(cs); 140abfe23dcSPhilippe Saint-Pierre if (cs != B_RGB32 && cs != B_RGBA32 && cs != B_RGB32_BIG 1415e4c29a6SJohn Scipione && cs != B_RGBA32_BIG) { 142abfe23dcSPhilippe Saint-Pierre return false; 1439949213aSStephan Aßmus } 1445e4c29a6SJohn Scipione } 1459949213aSStephan Aßmus 1469949213aSStephan Aßmus source->Seek(0, SEEK_SET); 1479949213aSStephan Aßmus return true; 1489949213aSStephan Aßmus } 1499949213aSStephan Aßmus 1509949213aSStephan Aßmus 1519949213aSStephan Aßmus status_t 1529949213aSStephan Aßmus GetBitmap(BPositionIO* in, BBitmap** out) 1539949213aSStephan Aßmus { 1549949213aSStephan Aßmus TranslatorBitmap header; 1559949213aSStephan Aßmus status_t err = in->Read(&header, sizeof(header)); 1569949213aSStephan Aßmus if (err != sizeof(header)) 1579949213aSStephan Aßmus return B_IO_ERROR; 1589949213aSStephan Aßmus 1599949213aSStephan Aßmus header.magic = B_BENDIAN_TO_HOST_INT32(header.magic); 1609949213aSStephan Aßmus header.bounds.left = B_BENDIAN_TO_HOST_FLOAT(header.bounds.left); 1619949213aSStephan Aßmus header.bounds.top = B_BENDIAN_TO_HOST_FLOAT(header.bounds.top); 1629949213aSStephan Aßmus header.bounds.right = B_BENDIAN_TO_HOST_FLOAT(header.bounds.right); 1639949213aSStephan Aßmus header.bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(header.bounds.bottom); 1649949213aSStephan Aßmus header.rowBytes = B_BENDIAN_TO_HOST_INT32(header.rowBytes); 1659949213aSStephan Aßmus header.colors = (color_space)B_BENDIAN_TO_HOST_INT32(header.colors); 1669949213aSStephan Aßmus header.dataSize = B_BENDIAN_TO_HOST_INT32(header.dataSize); 1679949213aSStephan Aßmus 1685e4c29a6SJohn Scipione // dump data from stream into a BBitmap 169116e78d4SJohn Scipione BBitmap* bitmap = new BBitmap(header.bounds, header.colors); 1709949213aSStephan Aßmus *out = bitmap; 171abfe23dcSPhilippe Saint-Pierre if (bitmap == NULL) 172abfe23dcSPhilippe Saint-Pierre return B_NO_MEMORY; 1735e4c29a6SJohn Scipione 1749949213aSStephan Aßmus unsigned char* bits = (unsigned char*)bitmap->Bits(); 1759949213aSStephan Aßmus if (bits == NULL) { 1769949213aSStephan Aßmus delete bitmap; 1779949213aSStephan Aßmus return B_NO_MEMORY; 1789949213aSStephan Aßmus } 1795e4c29a6SJohn Scipione 1809949213aSStephan Aßmus err = in->Read(bits, header.dataSize); 181abfe23dcSPhilippe Saint-Pierre if (err == (status_t)header.dataSize) 182abfe23dcSPhilippe Saint-Pierre return B_OK; 183de6ba1a0SAdrien Destugues else { 184de6ba1a0SAdrien Destugues delete bitmap; 185de6ba1a0SAdrien Destugues return B_IO_ERROR; 186de6ba1a0SAdrien Destugues } 1879949213aSStephan Aßmus } 1889949213aSStephan Aßmus 1899949213aSStephan Aßmus 190*81abd9edSJohn Scipione /* Required identify function - may need to read entire header, not sure 191*81abd9edSJohn Scipione */ 1929949213aSStephan Aßmus status_t 193abfe23dcSPhilippe Saint-Pierre GIFTranslator::DerivedIdentify(BPositionIO* inSource, 194abfe23dcSPhilippe Saint-Pierre const translation_format* inFormat, BMessage* ioExtension, 195abfe23dcSPhilippe Saint-Pierre translator_info* outInfo, uint32 outType) 1969949213aSStephan Aßmus { 1979949213aSStephan Aßmus const char* debug_text = getenv("GIF_TRANSLATOR_DEBUG"); 198abfe23dcSPhilippe Saint-Pierre if (debug_text != NULL && atoi(debug_text) != 0) 199abfe23dcSPhilippe Saint-Pierre debug = true; 2009949213aSStephan Aßmus 201abfe23dcSPhilippe Saint-Pierre if (outType == 0) 202abfe23dcSPhilippe Saint-Pierre outType = B_TRANSLATOR_BITMAP; 2035e4c29a6SJohn Scipione 20470d59669SSiarzhuk Zharski if (outType != GIF_TYPE && outType != B_TRANSLATOR_BITMAP) 20570d59669SSiarzhuk Zharski return B_NO_TRANSLATOR; 2069949213aSStephan Aßmus 2075e4c29a6SJohn Scipione bool isGif; 2085e4c29a6SJohn Scipione if (!DetermineType(inSource, &isGif)) 209abfe23dcSPhilippe Saint-Pierre return B_NO_TRANSLATOR; 2105e4c29a6SJohn Scipione 2115e4c29a6SJohn Scipione if (!isGif && inFormat != NULL && inFormat->type != B_TRANSLATOR_BITMAP) 2129949213aSStephan Aßmus return B_NO_TRANSLATOR; 2139949213aSStephan Aßmus 2149949213aSStephan Aßmus outInfo->group = B_TRANSLATOR_BITMAP; 2155e4c29a6SJohn Scipione if (isGif) { 2169949213aSStephan Aßmus outInfo->type = GIF_TYPE; 217abfe23dcSPhilippe Saint-Pierre outInfo->quality = GIF_IN_QUALITY; 218abfe23dcSPhilippe Saint-Pierre outInfo->capability = GIF_IN_CAPABILITY; 219aec33db1SPhilippe Saint-Pierre strlcpy(outInfo->name, B_TRANSLATE("GIF image"), sizeof(outInfo->name)); 2209949213aSStephan Aßmus strcpy(outInfo->MIME, "image/gif"); 221abfe23dcSPhilippe Saint-Pierre } else { 2229949213aSStephan Aßmus outInfo->type = B_TRANSLATOR_BITMAP; 223abfe23dcSPhilippe Saint-Pierre outInfo->quality = BBM_IN_QUALITY; 224abfe23dcSPhilippe Saint-Pierre outInfo->capability = BBM_IN_CAPABILITY; 225aec33db1SPhilippe Saint-Pierre strlcpy(outInfo->name, B_TRANSLATE("Be Bitmap Format (GIFTranslator)"), 2263927bd3cSPhilippe Saint-Pierre sizeof(outInfo->name)); 2279949213aSStephan Aßmus strcpy(outInfo->MIME, "image/x-be-bitmap"); 2289949213aSStephan Aßmus } 2295e4c29a6SJohn Scipione 2309949213aSStephan Aßmus return B_OK; 2319949213aSStephan Aßmus } 2329949213aSStephan Aßmus 2339949213aSStephan Aßmus 2349949213aSStephan Aßmus /* Main required function - assumes that an incoming GIF must be translated 2355e4c29a6SJohn Scipione * to a BBitmap, and vice versa - this could be improved 2365e4c29a6SJohn Scipione */ 2379949213aSStephan Aßmus status_t 238abfe23dcSPhilippe Saint-Pierre GIFTranslator::DerivedTranslate(BPositionIO* inSource, 239abfe23dcSPhilippe Saint-Pierre const translator_info* inInfo, BMessage* ioExtension, uint32 outType, 240abfe23dcSPhilippe Saint-Pierre BPositionIO* outDestination, int32 baseType) 2419949213aSStephan Aßmus { 2429949213aSStephan Aßmus const char* debug_text = getenv("GIF_TRANSLATOR_DEBUG"); 2435e4c29a6SJohn Scipione if (debug_text != NULL && atoi(debug_text) != 0) 2445e4c29a6SJohn Scipione debug = true; 2459949213aSStephan Aßmus 2465e4c29a6SJohn Scipione if (outType == 0) 2475e4c29a6SJohn Scipione outType = B_TRANSLATOR_BITMAP; 2485e4c29a6SJohn Scipione 2495e4c29a6SJohn Scipione if (outType != GIF_TYPE && outType != B_TRANSLATOR_BITMAP) 2509949213aSStephan Aßmus return B_NO_TRANSLATOR; 2519949213aSStephan Aßmus 2525e4c29a6SJohn Scipione bool isGif; 2535e4c29a6SJohn Scipione if (!DetermineType(inSource, &isGif)) 2545e4c29a6SJohn Scipione return B_NO_TRANSLATOR; 2555e4c29a6SJohn Scipione 2565e4c29a6SJohn Scipione if (!isGif && inInfo->type != B_TRANSLATOR_BITMAP) 2575e4c29a6SJohn Scipione return B_NO_TRANSLATOR; 2589949213aSStephan Aßmus 2599949213aSStephan Aßmus status_t err = B_OK; 2609949213aSStephan Aßmus bigtime_t now = system_time(); 2615e4c29a6SJohn Scipione 2625e4c29a6SJohn Scipione if (!isGif) { 2635e4c29a6SJohn Scipione // BBitmap to GIF 264116e78d4SJohn Scipione BBitmap* bitmap; 2657bc02c61SStefano Ceccherini err = GetBitmap(inSource, &bitmap); 2667bc02c61SStefano Ceccherini if (err != B_OK) 2677bc02c61SStefano Ceccherini return err; 2685e4c29a6SJohn Scipione 269*81abd9edSJohn Scipione GIFSave* gifSave = new GIFSave(bitmap, outDestination, fSettings); 270*81abd9edSJohn Scipione if (gifSave->fatalerror) { 271*81abd9edSJohn Scipione delete gifSave; 2727bc02c61SStefano Ceccherini delete bitmap; 2739949213aSStephan Aßmus return B_NO_MEMORY; 2749949213aSStephan Aßmus } 275*81abd9edSJohn Scipione delete gifSave; 2767bc02c61SStefano Ceccherini delete bitmap; 2775e4c29a6SJohn Scipione } else { 2785e4c29a6SJohn Scipione // GIF to BBitmap 2795e4c29a6SJohn Scipione GIFLoad* gifLoad = new GIFLoad(inSource, outDestination); 2805e4c29a6SJohn Scipione if (gifLoad->fatalerror) { 2815e4c29a6SJohn Scipione delete gifLoad; 2829949213aSStephan Aßmus return B_NO_MEMORY; 2839949213aSStephan Aßmus } 2845e4c29a6SJohn Scipione delete gifLoad; 2859949213aSStephan Aßmus } 2869949213aSStephan Aßmus 2879949213aSStephan Aßmus if (debug) { 2889949213aSStephan Aßmus now = system_time() - now; 28984bff752SJohn Scipione syslog(LOG_INFO, "Translate() - Translation took %Ld microseconds\n", 2905e4c29a6SJohn Scipione now); 2919949213aSStephan Aßmus } 2929949213aSStephan Aßmus return B_OK; 2939949213aSStephan Aßmus } 2949949213aSStephan Aßmus 2959949213aSStephan Aßmus 296abfe23dcSPhilippe Saint-Pierre BTranslator* 297abfe23dcSPhilippe Saint-Pierre make_nth_translator(int32 n, image_id you, uint32 flags, ...) 2989949213aSStephan Aßmus { 299abfe23dcSPhilippe Saint-Pierre if (n == 0) 300abfe23dcSPhilippe Saint-Pierre return new GIFTranslator(); 301abfe23dcSPhilippe Saint-Pierre 302abfe23dcSPhilippe Saint-Pierre return NULL; 303abfe23dcSPhilippe Saint-Pierre } 304abfe23dcSPhilippe Saint-Pierre 305abfe23dcSPhilippe Saint-Pierre 306abfe23dcSPhilippe Saint-Pierre GIFTranslator::GIFTranslator() 3075e4c29a6SJohn Scipione : 3085e4c29a6SJohn Scipione BaseTranslator(B_TRANSLATE("GIF images"), 309abfe23dcSPhilippe Saint-Pierre B_TRANSLATE("GIF image translator"), 310abfe23dcSPhilippe Saint-Pierre GIF_TRANSLATOR_VERSION, 311abfe23dcSPhilippe Saint-Pierre sInputFormats, kNumInputFormats, 312abfe23dcSPhilippe Saint-Pierre sOutputFormats, kNumOutputFormats, 313abfe23dcSPhilippe Saint-Pierre "GIFTranslator_Settings", 314abfe23dcSPhilippe Saint-Pierre sDefaultSettings, kNumDefaultSettings, 315abfe23dcSPhilippe Saint-Pierre B_TRANSLATOR_BITMAP, B_GIF_FORMAT) 316abfe23dcSPhilippe Saint-Pierre { 317abfe23dcSPhilippe Saint-Pierre } 318abfe23dcSPhilippe Saint-Pierre 319abfe23dcSPhilippe Saint-Pierre 320abfe23dcSPhilippe Saint-Pierre GIFTranslator::~GIFTranslator() 321abfe23dcSPhilippe Saint-Pierre { 322abfe23dcSPhilippe Saint-Pierre } 323abfe23dcSPhilippe Saint-Pierre 324abfe23dcSPhilippe Saint-Pierre 325abfe23dcSPhilippe Saint-Pierre BView* 326abfe23dcSPhilippe Saint-Pierre GIFTranslator::NewConfigView(TranslatorSettings* settings) 327abfe23dcSPhilippe Saint-Pierre { 328abfe23dcSPhilippe Saint-Pierre return new GIFView(settings); 3299949213aSStephan Aßmus } 3309949213aSStephan Aßmus 3319949213aSStephan Aßmus 3329949213aSStephan Aßmus int 3339949213aSStephan Aßmus main() 3349949213aSStephan Aßmus { 335abfe23dcSPhilippe Saint-Pierre BApplication app("application/x-vnd.Haiku-GIFTranslator"); 3365e4c29a6SJohn Scipione status_t result = LaunchTranslatorWindow(new GIFTranslator, 337abfe23dcSPhilippe Saint-Pierre B_TRANSLATE("GIF Settings"), kRectView); 338abfe23dcSPhilippe Saint-Pierre if (result == B_OK) { 339abfe23dcSPhilippe Saint-Pierre app.Run(); 3409949213aSStephan Aßmus return 0; 3415e4c29a6SJohn Scipione } 3425e4c29a6SJohn Scipione 343abfe23dcSPhilippe Saint-Pierre return 1; 3449949213aSStephan Aßmus } 345