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