1 /* 2 * Copyright 2007-2008, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "RAWTranslator.h" 8 #include "ConfigView.h" 9 #include "RAW.h" 10 11 #include <Catalog.h> 12 #include <BufferIO.h> 13 #include <Messenger.h> 14 #include <TranslatorRoster.h> 15 16 #include <stdlib.h> 17 #include <stdio.h> 18 #include <string.h> 19 20 #undef B_TRANSLATION_CONTEXT 21 #define B_TRANSLATION_CONTEXT "RAWTranslator" 22 23 24 class FreeAllocation { 25 public: 26 FreeAllocation(void* buffer) 27 : 28 fBuffer(buffer) 29 { 30 } 31 32 ~FreeAllocation() 33 { 34 free(fBuffer); 35 } 36 37 private: 38 void* fBuffer; 39 }; 40 41 struct progress_data { 42 BMessenger monitor; 43 BMessage message; 44 }; 45 46 // Extensions that ShowImage supports 47 const char* kDocumentCount = "/documentCount"; 48 const char* kDocumentIndex = "/documentIndex"; 49 const char* kProgressMonitor = "/progressMonitor"; 50 const char* kProgressMessage = "/progressMessage"; 51 52 53 // The input formats that this translator supports. 54 static const translation_format sInputFormats[] = { 55 { 56 RAW_IMAGE_FORMAT, 57 B_TRANSLATOR_BITMAP, 58 RAW_IN_QUALITY, 59 RAW_IN_CAPABILITY, 60 "image/x-vnd.adobe-dng", 61 "Adobe Digital Negative" 62 }, 63 { 64 RAW_IMAGE_FORMAT, 65 B_TRANSLATOR_BITMAP, 66 RAW_IN_QUALITY, 67 RAW_IN_CAPABILITY, 68 "image/x-vnd.photo-raw", 69 "Digital Photo RAW image" 70 } 71 }; 72 73 // The output formats that this translator supports. 74 static const translation_format sOutputFormats[] = { 75 { 76 B_TRANSLATOR_BITMAP, 77 B_TRANSLATOR_BITMAP, 78 BITS_OUT_QUALITY, 79 BITS_OUT_CAPABILITY, 80 "image/x-be-bitmap", 81 "Be Bitmap Format (RAWTranslator)" 82 } 83 }; 84 85 // Default settings for the Translator 86 static const TranSetting sDefaultSettings[] = { 87 {B_TRANSLATOR_EXT_HEADER_ONLY, TRAN_SETTING_BOOL, false}, 88 {B_TRANSLATOR_EXT_DATA_ONLY, TRAN_SETTING_BOOL, false} 89 }; 90 91 const uint32 kNumInputFormats = sizeof(sInputFormats) / sizeof(translation_format); 92 const uint32 kNumOutputFormats = sizeof(sOutputFormats) / sizeof(translation_format); 93 const uint32 kNumDefaultSettings = sizeof(sDefaultSettings) / sizeof(TranSetting); 94 95 const char* kShortName1 = B_TRANSLATE("RAW images"); 96 const char* kShortInfo1 = B_TRANSLATE("RAW image translator"); 97 98 99 // #pragma mark - 100 101 102 RAWTranslator::RAWTranslator() 103 : BaseTranslator(kShortName1, kShortInfo1, 104 RAW_TRANSLATOR_VERSION, 105 sInputFormats, kNumInputFormats, 106 sOutputFormats, kNumOutputFormats, 107 "RAWTranslator_Settings", 108 sDefaultSettings, kNumDefaultSettings, 109 B_TRANSLATOR_BITMAP, RAW_IMAGE_FORMAT) 110 { 111 } 112 113 114 RAWTranslator::~RAWTranslator() 115 { 116 } 117 118 119 status_t 120 RAWTranslator::DerivedIdentify(BPositionIO *stream, 121 const translation_format *format, BMessage *settings, 122 translator_info *info, uint32 outType) 123 { 124 if (!outType) 125 outType = B_TRANSLATOR_BITMAP; 126 if (outType != B_TRANSLATOR_BITMAP) 127 return B_NO_TRANSLATOR; 128 129 BBufferIO io(stream, 128 * 1024, false); 130 DCRaw raw(io); 131 status_t status; 132 133 try { 134 status = raw.Identify(); 135 } catch (status_t error) { 136 status = error; 137 } 138 139 if (status < B_OK) 140 return B_NO_TRANSLATOR; 141 142 image_meta_info meta; 143 raw.GetMetaInfo(meta); 144 145 if (settings) { 146 int32 count = raw.CountImages(); 147 148 // Add page count to ioExtension 149 settings->RemoveName(kDocumentCount); 150 settings->AddInt32(kDocumentCount, count); 151 152 // Check if a document index has been specified 153 int32 index; 154 if (settings->FindInt32(kDocumentIndex, &index) == B_OK) 155 index--; 156 else 157 index = 0; 158 159 if (index < 0 || index >= count) 160 return B_NO_TRANSLATOR; 161 } 162 163 info->type = RAW_IMAGE_FORMAT; 164 info->group = B_TRANSLATOR_BITMAP; 165 info->quality = RAW_IN_QUALITY; 166 info->capability = RAW_IN_CAPABILITY; 167 snprintf(info->name, sizeof(info->name), 168 B_TRANSLATE_COMMENT("%s RAW image", "Parameter (%s) is the name of " 169 "the manufacturer (like 'Canon')"), meta.manufacturer); 170 strcpy(info->MIME, "image/x-vnd.photo-raw"); 171 172 return B_OK; 173 } 174 175 176 /*static*/ void 177 RAWTranslator::_ProgressMonitor(const char* message, float percentage, 178 void* _data) 179 { 180 progress_data& data = *(progress_data*)_data; 181 182 BMessage update(data.message); 183 update.AddString("message", message); 184 update.AddFloat("percent", percentage); 185 update.AddInt64("time", system_time()); 186 187 data.monitor.SendMessage(&update); 188 } 189 190 191 status_t 192 RAWTranslator::DerivedTranslate(BPositionIO* stream, 193 const translator_info* info, BMessage* settings, 194 uint32 outType, BPositionIO* target, int32 baseType) 195 { 196 if (!outType) 197 outType = B_TRANSLATOR_BITMAP; 198 if (outType != B_TRANSLATOR_BITMAP || baseType != 0) 199 return B_NO_TRANSLATOR; 200 201 BBufferIO io(stream, 1024 * 1024, false); 202 DCRaw raw(io); 203 204 bool headerOnly = false; 205 206 progress_data progressData; 207 BMessenger monitor; 208 209 if (settings != NULL) { 210 settings->FindBool(B_TRANSLATOR_EXT_HEADER_ONLY, &headerOnly); 211 212 bool half; 213 if (settings->FindBool("raw:half_size", &half) == B_OK && half) 214 raw.SetHalfSize(true); 215 216 if (settings->FindMessenger(kProgressMonitor, 217 &progressData.monitor) == B_OK 218 && settings->FindMessage(kProgressMessage, 219 &progressData.message) == B_OK) { 220 raw.SetProgressMonitor(&_ProgressMonitor, &progressData); 221 _ProgressMonitor("Reading Image Data", 0, &progressData); 222 } 223 } 224 225 int32 imageIndex = 0; 226 uint8* buffer = NULL; 227 size_t bufferSize; 228 status_t status; 229 230 try { 231 status = raw.Identify(); 232 233 if (status == B_OK && settings) { 234 // Check if a document index has been specified 235 if (settings->FindInt32(kDocumentIndex, &imageIndex) == B_OK) 236 imageIndex--; 237 else 238 imageIndex = 0; 239 240 if (imageIndex < 0 || imageIndex >= (int32)raw.CountImages()) 241 status = B_BAD_VALUE; 242 } 243 if (status == B_OK && !headerOnly) 244 status = raw.ReadImageAt(imageIndex, buffer, bufferSize); 245 } catch (status_t error) { 246 status = error; 247 } 248 249 if (status < B_OK) 250 return B_NO_TRANSLATOR; 251 252 FreeAllocation _(buffer); 253 // frees the buffer on destruction 254 255 image_meta_info meta; 256 raw.GetMetaInfo(meta); 257 258 image_data_info data; 259 raw.ImageAt(imageIndex, data); 260 261 if (!data.is_raw) { 262 // let others handle embedded JPEG data 263 BMemoryIO io(buffer, bufferSize); 264 BMessage buffer; 265 if (meta.flip != 1) { 266 // preserve orientation 267 if (settings == NULL) 268 settings = &buffer; 269 settings->AddInt32("exif:orientation", meta.flip); 270 } 271 272 BTranslatorRoster* roster = BTranslatorRoster::Default(); 273 return roster->Translate(&io, NULL, settings, target, outType); 274 } 275 276 // retrieve EXIF data 277 off_t exifOffset; 278 size_t exifLength; 279 bool bigEndian; 280 if (settings != NULL && raw.GetEXIFTag(exifOffset, exifLength, bigEndian) == B_OK) { 281 uint8* exifBuffer = (uint8*)malloc(exifLength + 16); 282 if (exifBuffer != NULL) { 283 // add fake TIFF header to EXIF data 284 struct { 285 uint16 endian; 286 uint16 tiff_marker; 287 uint32 offset; 288 uint16 null; 289 } _PACKED header; 290 header.endian = bigEndian ? 'MM' : 'II'; 291 header.tiff_marker = 42; 292 header.offset = 16; 293 header.null = 0; 294 memcpy(exifBuffer, &header, sizeof(header)); 295 296 if (io.ReadAt(exifOffset, exifBuffer + 16, exifLength) 297 == (ssize_t)exifLength) 298 settings->AddData("exif", B_RAW_TYPE, exifBuffer, exifLength + 16); 299 300 free(exifBuffer); 301 } 302 } 303 uint32 dataSize = data.output_width * 4 * data.output_height; 304 305 TranslatorBitmap header; 306 header.magic = B_TRANSLATOR_BITMAP; 307 header.bounds.Set(0, 0, data.output_width - 1, data.output_height - 1); 308 header.rowBytes = data.output_width * 4; 309 header.colors = B_RGB32; 310 header.dataSize = dataSize; 311 312 // write out Be's Bitmap header 313 swap_data(B_UINT32_TYPE, &header, sizeof(TranslatorBitmap), 314 B_SWAP_HOST_TO_BENDIAN); 315 ssize_t bytesWritten = target->Write(&header, sizeof(TranslatorBitmap)); 316 if (bytesWritten < B_OK) 317 return bytesWritten; 318 319 if ((size_t)bytesWritten != sizeof(TranslatorBitmap)) 320 return B_IO_ERROR; 321 322 if (headerOnly) 323 return B_OK; 324 325 bytesWritten = target->Write(buffer, dataSize); 326 if (bytesWritten < B_OK) 327 return bytesWritten; 328 329 if ((size_t)bytesWritten != dataSize) 330 return B_IO_ERROR; 331 332 return B_OK; 333 } 334 335 336 BView * 337 RAWTranslator::NewConfigView(TranslatorSettings *settings) 338 { 339 return new ConfigView(); 340 } 341 342 343 // #pragma mark - 344 345 346 BTranslator * 347 make_nth_translator(int32 n, image_id you, uint32 flags, ...) 348 { 349 if (n != 0) 350 return NULL; 351 352 return new RAWTranslator(); 353 } 354 355