1//////////////////////////////////////////////////////////////////////////////// 2// 3// File: GIFTranslator.cpp 4// 5// Date: December 1999 6// 7// Author: Daniel Switkin 8// 9// Copyright 2003 (c) by Daniel Switkin. This file is made publically available 10// under the BSD license, with the stipulations that this complete header must 11// remain at the top of the file indefinitely, and credit must be given to the 12// original author in any about box using this software. 13// 14//////////////////////////////////////////////////////////////////////////////// 15 16// Additional authors: Stephan A��mus, <superstippi@gmx.de> 17// John Scipione, <jscipione@gmail.com> 18 19#include "GIFTranslator.h" 20 21#include <stdio.h> 22#include <stdlib.h> 23#include <string.h> 24#include <syslog.h> 25 26#include <Application.h> 27#include <ByteOrder.h> 28#include <Catalog.h> 29#include <DataIO.h> 30#include <InterfaceDefs.h> 31#include <TranslatorAddOn.h> 32#include <TranslatorFormats.h> 33#include <TypeConstants.h> 34 35#include "GIFLoad.h" 36#include "GIFSave.h" 37#include "GIFView.h" 38#include "TranslatorWindow.h" 39 40 41#ifndef GIF_TYPE 42#define GIF_TYPE 'GIF ' 43#endif 44 45#undef B_TRANSLATION_CONTEXT 46#define B_TRANSLATION_CONTEXT "GIFTranslator" 47 48 49bool debug = false; 50 // this global will be externed in other files - set once here 51 // for the entire translator 52 53bool DetermineType(BPositionIO* source, bool* isGif); 54status_t GetBitmap(BPositionIO* in, BBitmap** out); 55 56static const translation_format sInputFormats[] = { 57 { 58 GIF_TYPE, 59 B_TRANSLATOR_BITMAP, 60 GIF_IN_QUALITY, 61 GIF_IN_CAPABILITY, 62 "image/gif", 63 "GIF image" 64 }, 65 { 66 B_TRANSLATOR_BITMAP, 67 B_TRANSLATOR_BITMAP, 68 BBM_IN_QUALITY, 69 BBM_IN_CAPABILITY, 70 "image/x-be-bitmap", 71 "Be Bitmap Format (GIFTranslator)" 72 } 73}; 74 75static const translation_format sOutputFormats[] = { 76 { 77 GIF_TYPE, 78 B_TRANSLATOR_BITMAP, 79 GIF_OUT_QUALITY, 80 GIF_OUT_CAPABILITY, 81 "image/gif", 82 "GIF image" 83 }, 84 { 85 B_TRANSLATOR_BITMAP, 86 B_TRANSLATOR_BITMAP, 87 BBM_OUT_QUALITY, 88 BBM_OUT_CAPABILITY, 89 "image/x-be-bitmap", 90 "Be Bitmap Format (GIFTranslator)" 91 } 92}; 93 94// Default settings for the Translator 95static const TranSetting sDefaultSettings[] = { 96 { B_TRANSLATOR_EXT_HEADER_ONLY, TRAN_SETTING_BOOL, false }, 97 { B_TRANSLATOR_EXT_DATA_ONLY, TRAN_SETTING_BOOL, false }, 98 { GIF_SETTING_INTERLACED, TRAN_SETTING_BOOL, false }, 99 { GIF_SETTING_USE_TRANSPARENT, TRAN_SETTING_BOOL, true }, 100 { GIF_SETTING_USE_TRANSPARENT_AUTO, TRAN_SETTING_BOOL, true }, 101 { GIF_SETTING_USE_DITHERING, TRAN_SETTING_BOOL, false }, 102 { GIF_SETTING_PALETTE_MODE, TRAN_SETTING_INT32, 3 }, 103 { GIF_SETTING_PALETTE_SIZE, TRAN_SETTING_INT32, 8 }, 104 { GIF_SETTING_TRANSPARENT_RED, TRAN_SETTING_INT32, 255 }, 105 { GIF_SETTING_TRANSPARENT_GREEN, TRAN_SETTING_INT32, 255 }, 106 { GIF_SETTING_TRANSPARENT_BLUE, TRAN_SETTING_INT32, 255 } 107}; 108 109const uint32 kNumInputFormats = sizeof(sInputFormats) 110 / sizeof(translation_format); 111const uint32 kNumOutputFormats = sizeof(sOutputFormats) 112 / sizeof(translation_format); 113const uint32 kNumDefaultSettings = sizeof(sDefaultSettings) 114 / sizeof(TranSetting); 115 116 117/*! Look at first few bytes in stream to determine type - throw it back 118 if it is not a GIF or a BBitmap that we understand. 119*/ 120bool 121DetermineType(BPositionIO* source, bool* isGif) 122{ 123 unsigned char header[7]; 124 *isGif = true; 125 if (source->Read(header, 6) != 6) 126 return false; 127 128 header[6] = 0x00; 129 130 if (strcmp((char*)header, "GIF87a") != 0 131 && strcmp((char*)header, "GIF89a") != 0) { 132 *isGif = false; 133 int32 magic = (header[0] << 24) + (header[1] << 16) + (header[2] << 8) 134 + header[3]; 135 if (magic != B_TRANSLATOR_BITMAP) 136 return false; 137 138 source->Seek(5 * 4 - 2, SEEK_CUR); 139 color_space cs; 140 if (source->Read(&cs, 4) != 4) 141 return false; 142 143 cs = (color_space)B_BENDIAN_TO_HOST_INT32(cs); 144 if (cs != B_RGB32 && cs != B_RGBA32 && cs != B_RGB32_BIG 145 && cs != B_RGBA32_BIG) { 146 return false; 147 } 148 } 149 150 source->Seek(0, SEEK_SET); 151 return true; 152} 153 154 155status_t 156GetBitmap(BPositionIO* in, BBitmap** out) 157{ 158 TranslatorBitmap header; 159 status_t result = in->Read(&header, sizeof(header)); 160 if (result != sizeof(header)) 161 return B_IO_ERROR; 162 163 header.magic = B_BENDIAN_TO_HOST_INT32(header.magic); 164 header.bounds.left = B_BENDIAN_TO_HOST_FLOAT(header.bounds.left); 165 header.bounds.top = B_BENDIAN_TO_HOST_FLOAT(header.bounds.top); 166 header.bounds.right = B_BENDIAN_TO_HOST_FLOAT(header.bounds.right); 167 header.bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(header.bounds.bottom); 168 header.rowBytes = B_BENDIAN_TO_HOST_INT32(header.rowBytes); 169 header.colors = (color_space)B_BENDIAN_TO_HOST_INT32(header.colors); 170 header.dataSize = B_BENDIAN_TO_HOST_INT32(header.dataSize); 171 172 // dump data from stream into a BBitmap 173 *out = new(std::nothrow) BBitmap(header.bounds, header.colors); 174 if (*out == NULL) 175 return B_NO_MEMORY; 176 177 if (!(*out)->IsValid()) { 178 delete *out; 179 return B_NO_MEMORY; 180 } 181 182 result = in->Read((*out)->Bits(), header.dataSize); 183 if (result != (status_t)header.dataSize) { 184 delete *out; 185 return B_IO_ERROR; 186 } 187 188 return B_OK; 189} 190 191 192/*! Required identify function - may need to read entire header, not sure 193*/ 194status_t 195GIFTranslator::DerivedIdentify(BPositionIO* inSource, 196 const translation_format* inFormat, BMessage* ioExtension, 197 translator_info* outInfo, uint32 outType) 198{ 199 const char* debug_text = getenv("GIF_TRANSLATOR_DEBUG"); 200 if (debug_text != NULL && atoi(debug_text) != 0) 201 debug = true; 202 203 if (outType == 0) 204 outType = B_TRANSLATOR_BITMAP; 205 206 if (outType != GIF_TYPE && outType != B_TRANSLATOR_BITMAP) 207 return B_NO_TRANSLATOR; 208 209 bool isGif; 210 if (!DetermineType(inSource, &isGif)) 211 return B_NO_TRANSLATOR; 212 213 if (!isGif && inFormat != NULL && inFormat->type != B_TRANSLATOR_BITMAP) 214 return B_NO_TRANSLATOR; 215 216 outInfo->group = B_TRANSLATOR_BITMAP; 217 if (isGif) { 218 outInfo->type = GIF_TYPE; 219 outInfo->quality = GIF_IN_QUALITY; 220 outInfo->capability = GIF_IN_CAPABILITY; 221 strlcpy(outInfo->name, B_TRANSLATE("GIF image"), sizeof(outInfo->name)); 222 strcpy(outInfo->MIME, "image/gif"); 223 } else { 224 outInfo->type = B_TRANSLATOR_BITMAP; 225 outInfo->quality = BBM_IN_QUALITY; 226 outInfo->capability = BBM_IN_CAPABILITY; 227 strlcpy(outInfo->name, B_TRANSLATE("Be Bitmap Format (GIFTranslator)"), 228 sizeof(outInfo->name)); 229 strcpy(outInfo->MIME, "image/x-be-bitmap"); 230 } 231 232 return B_OK; 233} 234 235 236/*! Main required function - assumes that an incoming GIF must be translated 237 to a BBitmap, and vice versa - this could be improved 238*/ 239status_t 240GIFTranslator::DerivedTranslate(BPositionIO* inSource, 241 const translator_info* inInfo, BMessage* ioExtension, uint32 outType, 242 BPositionIO* outDestination, int32 baseType) 243{ 244 const char* debug_text = getenv("GIF_TRANSLATOR_DEBUG"); 245 if (debug_text != NULL && atoi(debug_text) != 0) 246 debug = true; 247 248 if (outType == 0) 249 outType = B_TRANSLATOR_BITMAP; 250 251 if (outType != GIF_TYPE && outType != B_TRANSLATOR_BITMAP) 252 return B_NO_TRANSLATOR; 253 254 bool isGif; 255 if (!DetermineType(inSource, &isGif)) 256 return B_NO_TRANSLATOR; 257 258 if (!isGif && inInfo->type != B_TRANSLATOR_BITMAP) 259 return B_NO_TRANSLATOR; 260 261 status_t result = B_OK; 262 bigtime_t now = system_time(); 263 264 if (!isGif) { 265 // BBitmap to GIF 266 BBitmap* bitmap; 267 result = GetBitmap(inSource, &bitmap); 268 if (result != B_OK) 269 return result; 270 271 GIFSave* gifSave = new(std::nothrow) GIFSave(bitmap, outDestination, 272 fSettings); 273 if (gifSave == NULL) { 274 delete bitmap; 275 return B_NO_MEMORY; 276 } 277 278 if (gifSave->fatalerror) { 279 delete gifSave; 280 delete bitmap; 281 return B_NO_MEMORY; 282 } 283 delete gifSave; 284 delete bitmap; 285 } else { 286 // GIF to BBitmap 287 GIFLoad* gifLoad = new(std::nothrow) GIFLoad(inSource, outDestination); 288 if (gifLoad == NULL) 289 return B_NO_MEMORY; 290 291 if (gifLoad->fatalerror) { 292 delete gifLoad; 293 return B_NO_MEMORY; 294 } 295 delete gifLoad; 296 } 297 298 if (debug) { 299 now = system_time() - now; 300 syslog(LOG_INFO, "Translate() - Translation took %lld microseconds\n", 301 now); 302 } 303 return B_OK; 304} 305 306 307BTranslator* 308make_nth_translator(int32 n, image_id you, uint32 flags, ...) 309{ 310 if (n == 0) 311 return new(std::nothrow) GIFTranslator(); 312 313 return NULL; 314} 315 316 317GIFTranslator::GIFTranslator() 318 : 319 BaseTranslator(B_TRANSLATE("GIF images"), 320 B_TRANSLATE("GIF image translator"), 321 GIF_TRANSLATOR_VERSION, 322 sInputFormats, kNumInputFormats, 323 sOutputFormats, kNumOutputFormats, 324 "GIFTranslator_Settings", 325 sDefaultSettings, kNumDefaultSettings, 326 B_TRANSLATOR_BITMAP, B_GIF_FORMAT) 327{ 328} 329 330 331GIFTranslator::~GIFTranslator() 332{ 333} 334 335 336BView* 337GIFTranslator::NewConfigView(TranslatorSettings* settings) 338{ 339 return new(std::nothrow) GIFView(settings); 340} 341 342 343int 344main() 345{ 346 BApplication app("application/x-vnd.Haiku-GIFTranslator"); 347 status_t result = LaunchTranslatorWindow(new(std::nothrow) GIFTranslator, 348 B_TRANSLATE("GIF Settings"), kRectView); 349 if (result == B_OK) { 350 app.Run(); 351 return 0; 352 } 353 354 return 1; 355} 356