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:
FreeAllocation(void * buffer)30 FreeAllocation(void* buffer)
31 :
32 fBuffer(buffer)
33 {
34 }
35
~FreeAllocation()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
RAWTranslator()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
~RAWTranslator()118 RAWTranslator::~RAWTranslator()
119 {
120 }
121
122
123 status_t
DerivedIdentify(BPositionIO * stream,const translation_format * format,BMessage * settings,translator_info * info,uint32 outType)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
_ProgressMonitor(const char * message,float percentage,void * _data)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
DerivedTranslate(BPositionIO * stream,const translator_info * info,BMessage * settings,uint32 outType,BPositionIO * target,int32 baseType)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 *
NewConfigView(TranslatorSettings * settings)359 RAWTranslator::NewConfigView(TranslatorSettings *settings)
360 {
361 return new ConfigView();
362 }
363
364
365 // #pragma mark -
366
367
368 BTranslator *
make_nth_translator(int32 n,image_id you,uint32 flags,...)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