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