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
24class 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
41struct progress_data {
42	BMessenger	monitor;
43	BMessage	message;
44};
45
46// Extensions that ShowImage supports
47const char* kDocumentCount = "/documentCount";
48const char* kDocumentIndex = "/documentIndex";
49const char* kProgressMonitor = "/progressMonitor";
50const char* kProgressMessage = "/progressMessage";
51
52
53// The input formats that this translator supports.
54static 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.
74static 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
86static 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
91const uint32 kNumInputFormats = sizeof(sInputFormats) / sizeof(translation_format);
92const uint32 kNumOutputFormats = sizeof(sOutputFormats) / sizeof(translation_format);
93const uint32 kNumDefaultSettings = sizeof(sDefaultSettings) / sizeof(TranSetting);
94
95const char* kShortName1 = B_TRANSLATE("RAW images");
96const char* kShortInfo1 = B_TRANSLATE("RAW image translator");
97
98
99//	#pragma mark -
100
101
102RAWTranslator::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
114RAWTranslator::~RAWTranslator()
115{
116}
117
118
119status_t
120RAWTranslator::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
177RAWTranslator::_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
191status_t
192RAWTranslator::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
336BView *
337RAWTranslator::NewConfigView(TranslatorSettings *settings)
338{
339	return new ConfigView();
340}
341
342
343//	#pragma mark -
344
345
346BTranslator *
347make_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