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