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