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