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 49 bool debug = false; 50 // this global will be externed in other files - set once here 51 // for the entire translator 52 53 bool DetermineType(BPositionIO* source, bool* isGif); 54 status_t GetBitmap(BPositionIO* in, BBitmap** out); 55 56 static 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 75 static 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 95 static 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 109 const uint32 kNumInputFormats = sizeof(sInputFormats) 110 / sizeof(translation_format); 111 const uint32 kNumOutputFormats = sizeof(sOutputFormats) 112 / sizeof(translation_format); 113 const 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 */ 120 bool 121 DetermineType(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 155 status_t 156 GetBitmap(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 */ 194 status_t 195 GIFTranslator::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 */ 239 status_t 240 GIFTranslator::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 307 BTranslator* 308 make_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 317 GIFTranslator::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 331 GIFTranslator::~GIFTranslator() 332 { 333 } 334 335 336 BView* 337 GIFTranslator::NewConfigView(TranslatorSettings* settings) 338 { 339 return new(std::nothrow) GIFView(settings); 340 } 341 342 343 int 344 main() 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