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