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 #include "GIFTranslator.h" 17 #include "GIFWindow.h" 18 #include "GIFView.h" 19 #include "GIFSave.h" 20 #include "GIFLoad.h" 21 22 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 #ifndef GIF_TYPE 37 #define GIF_TYPE 'GIF ' 38 #endif 39 40 #undef B_TRANSLATION_CONTEXT 41 #define B_TRANSLATION_CONTEXT "GIFTranslator" 42 43 44 // This global will be externed in other files - set once here 45 // for the entire translator 46 bool debug = false; 47 48 bool DetermineType(BPositionIO *source, bool *is_gif); 49 status_t GetBitmap(BPositionIO *in, BBitmap **out); 50 51 /* Required data */ 52 char translatorName[] = "GIF images"; 53 char translatorInfo[] = "GIF image translator v1.4"; 54 int32 translatorVersion = 0x140; 55 56 translation_format inputFormats[] = { 57 { GIF_TYPE, B_TRANSLATOR_BITMAP, 0.8, 0.8, "image/gif", 58 "GIF image" }, 59 { B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.3, 0.3, "image/x-be-bitmap", 60 "Be Bitmap Format (GIFTranslator)" }, 61 { 0 } 62 }; 63 64 translation_format outputFormats[] = { 65 { GIF_TYPE, B_TRANSLATOR_BITMAP, 0.8, 0.8, "image/gif", 66 "GIF image" }, 67 { B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.3, 0.3, "image/x-be-bitmap", 68 "Be Bitmap Format (GIFTranslator)" }, 69 { 0 } 70 }; 71 72 73 /* Build a pretty view for DataTranslations */ 74 status_t 75 MakeConfig(BMessage *ioExtension, BView **outView, BRect *outExtent) 76 { 77 GIFView *gifview = new GIFView("TranslatorView"); 78 *outView = gifview; 79 gifview->ResizeTo(gifview->ExplicitPreferredSize()); 80 *outExtent = gifview->Bounds(); 81 return B_OK; 82 } 83 84 85 /* Look at first few bytes in stream to determine type - throw it back 86 if it is not a GIF or a BBitmap that we understand */ 87 bool 88 DetermineType(BPositionIO *source, bool *is_gif) 89 { 90 unsigned char header[7]; 91 *is_gif = true; 92 if (source->Read(header, 6) != 6) return false; 93 header[6] = 0x00; 94 95 if (strcmp((char *)header, "GIF87a") != 0 && strcmp((char *)header, 96 "GIF89a") != 0) { 97 *is_gif = false; 98 int32 magic = (header[0] << 24) + (header[1] << 16) + (header[2] << 8) 99 + header[3]; 100 if (magic != B_TRANSLATOR_BITMAP) return false; 101 source->Seek(5 * 4 - 2, SEEK_CUR); 102 color_space cs; 103 if (source->Read(&cs, 4) != 4) return false; 104 cs = (color_space)B_BENDIAN_TO_HOST_INT32(cs); 105 if (cs != B_RGB32 && cs != B_RGBA32 && cs != B_RGB32_BIG && cs 106 != B_RGBA32_BIG) return false; 107 } 108 109 source->Seek(0, SEEK_SET); 110 return true; 111 } 112 113 114 /* Dump data from stream into a BBitmap */ 115 status_t 116 GetBitmap(BPositionIO *in, BBitmap **out) 117 { 118 TranslatorBitmap header; 119 120 status_t err = in->Read(&header, sizeof(header)); 121 if (err != sizeof(header)) 122 return B_IO_ERROR; 123 124 header.magic = B_BENDIAN_TO_HOST_INT32(header.magic); 125 header.bounds.left = B_BENDIAN_TO_HOST_FLOAT(header.bounds.left); 126 header.bounds.top = B_BENDIAN_TO_HOST_FLOAT(header.bounds.top); 127 header.bounds.right = B_BENDIAN_TO_HOST_FLOAT(header.bounds.right); 128 header.bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(header.bounds.bottom); 129 header.rowBytes = B_BENDIAN_TO_HOST_INT32(header.rowBytes); 130 header.colors = (color_space)B_BENDIAN_TO_HOST_INT32(header.colors); 131 header.dataSize = B_BENDIAN_TO_HOST_INT32(header.dataSize); 132 133 BBitmap *bitmap = new BBitmap(header.bounds, header.colors); 134 *out = bitmap; 135 if (bitmap == NULL) return B_NO_MEMORY; 136 unsigned char *bits = (unsigned char *)bitmap->Bits(); 137 if (bits == NULL) { 138 delete bitmap; 139 return B_NO_MEMORY; 140 } 141 err = in->Read(bits, header.dataSize); 142 if (err == (status_t)header.dataSize) return B_OK; 143 else { 144 delete bitmap; 145 return B_IO_ERROR; 146 } 147 } 148 149 150 /* Required Identify function - may need to read entire header, not sure */ 151 status_t 152 Identify(BPositionIO *inSource, const translation_format *inFormat, 153 BMessage *ioExtension, translator_info *outInfo, uint32 outType) 154 { 155 156 const char *debug_text = getenv("GIF_TRANSLATOR_DEBUG"); 157 if ((debug_text != NULL) && (atoi(debug_text) != 0)) debug = true; 158 159 if (outType == 0) outType = B_TRANSLATOR_BITMAP; 160 if (outType != GIF_TYPE && outType != B_TRANSLATOR_BITMAP) 161 return B_NO_TRANSLATOR; 162 163 bool is_gif; 164 if (!DetermineType(inSource, &is_gif)) return B_NO_TRANSLATOR; 165 if (!is_gif && inFormat != NULL && inFormat->type != B_TRANSLATOR_BITMAP) 166 return B_NO_TRANSLATOR; 167 168 outInfo->group = B_TRANSLATOR_BITMAP; 169 if (is_gif) { 170 outInfo->type = GIF_TYPE; 171 outInfo->quality = 0.8; 172 outInfo->capability = 0.8; 173 strlcpy(outInfo->name, B_TRANSLATE("GIF image"), sizeof(outInfo->name)); 174 strcpy(outInfo->MIME, "image/gif"); 175 } 176 else { 177 outInfo->type = B_TRANSLATOR_BITMAP; 178 outInfo->quality = 0.3; 179 outInfo->capability = 0.3; 180 strlcpy(outInfo->name, B_TRANSLATE("Be Bitmap Format (GIFTranslator)"), 181 sizeof(outInfo->name)); 182 strcpy(outInfo->MIME, "image/x-be-bitmap"); 183 } 184 return B_OK; 185 } 186 187 188 /* Main required function - assumes that an incoming GIF must be translated 189 to a BBitmap, and vice versa - this could be improved */ 190 status_t 191 Translate(BPositionIO *inSource, const translator_info *inInfo, 192 BMessage *ioExtension, uint32 outType, BPositionIO *outDestination) 193 { 194 195 const char *debug_text = getenv("GIF_TRANSLATOR_DEBUG"); 196 if ((debug_text != NULL) && (atoi(debug_text) != 0)) debug = true; 197 198 if (outType == 0) outType = B_TRANSLATOR_BITMAP; 199 if (outType != GIF_TYPE && outType != B_TRANSLATOR_BITMAP) { 200 return B_NO_TRANSLATOR; 201 } 202 203 bool is_gif; 204 if (!DetermineType(inSource, &is_gif)) return B_NO_TRANSLATOR; 205 if (!is_gif && inInfo->type != B_TRANSLATOR_BITMAP) return B_NO_TRANSLATOR; 206 207 status_t err = B_OK; 208 bigtime_t now = system_time(); 209 // Going from BBitmap to GIF 210 if (!is_gif) { 211 BBitmap *bitmap = NULL; 212 err = GetBitmap(inSource, &bitmap); 213 if (err != B_OK) 214 return err; 215 GIFSave *gs = new GIFSave(bitmap, outDestination); 216 if (gs->fatalerror) { 217 delete gs; 218 delete bitmap; 219 return B_NO_MEMORY; 220 } 221 delete gs; 222 delete bitmap; 223 } else { // GIF to BBitmap 224 GIFLoad *gl = new GIFLoad(inSource, outDestination); 225 if (gl->fatalerror) { 226 delete gl; 227 return B_NO_MEMORY; 228 } 229 delete gl; 230 } 231 232 if (debug) { 233 now = system_time() - now; 234 syslog(LOG_ERR, "Translate() - Translation took %Ld microseconds\n", now); 235 } 236 return B_OK; 237 } 238 239 240 GIFTranslator::GIFTranslator() 241 : BApplication("application/x-vnd.Haiku-GIFTranslator") 242 { 243 BRect rect(100, 100, 339, 339); 244 gifwindow = new GIFWindow(rect, B_TRANSLATE("GIF Settings")); 245 gifwindow->Show(); 246 } 247 248 249 int 250 main() 251 { 252 GIFTranslator myapp; 253 myapp.Run(); 254 return 0; 255 } 256 257