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