xref: /haiku/src/add-ons/translators/raw/RAWTranslator.cpp (revision 3be9edf8da228afd9fec0390f408c964766122aa)
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