xref: /haiku/src/add-ons/translators/raw/LibRAW.cpp (revision 268f99dd7dc4bd7474a8bd2742d3f1ec1de6752a)
1 /*
2  * Copyright 2021, Jérôme Duval, jerome.duval@gmail.com.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "LibRAW.h"
8 
9 #include <Message.h>
10 #include <TranslationErrors.h>
11 
12 #include <ctype.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 
17 #include <libraw/libraw.h>
18 
19 #include "StreamBuffer.h"
20 
21 
22 //#define TRACE(x...) printf(x)
23 #define TRACE(x...)
24 #define CALLED() TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
25 #define RETURN(x, y) { TRACE("RETURN %s %s\n", __PRETTY_FUNCTION__, x); \
26 	return y; }
27 
28 static const uint32 kImageBufferCount = 10;
29 static const uint32 kDecodeBufferCount = 2048;
30 
31 
32 #define P1 fRaw->imgdata.idata
33 #define S fRaw->imgdata.sizes
34 #define C fRaw->imgdata.color
35 #define T fRaw->imgdata.thumbnail
36 #define P2 fRaw->imgdata.other
37 #define OUT fRaw->imgdata.params
38 
39 
40 //	#pragma mark -
41 
42 
43 class LibRaw_haiku_datastream : public LibRaw_abstract_datastream
44 {
45 public:
46 	BPositionIO* fStream;
47 	virtual ~LibRaw_haiku_datastream();
48 			LibRaw_haiku_datastream(BPositionIO* stream);
49 	virtual int valid();
50 	virtual int read(void *ptr, size_t size, size_t nmemb);
51 	virtual int eof();
52 	virtual int seek(INT64 o, int whence);
53 	virtual INT64 tell();
54 	virtual INT64 size();
55 	virtual int get_char();
56 	virtual char *gets(char *str, int sz);
57 	virtual int scanf_one(const char *fmt, void *val);
58 	virtual void *make_jas_stream();
59 
60 private:
61 	StreamBuffer *buffer;
62 	off_t	fSize;
63 	status_t iseof;
64 };
65 
66 
LibRaw_haiku_datastream(BPositionIO * stream)67 LibRaw_haiku_datastream::LibRaw_haiku_datastream(BPositionIO* stream)
68 {
69 	CALLED();
70 	iseof = 0;
71 	buffer = new StreamBuffer(stream, 2048);
72 	fStream = stream;
73 	fStream->GetSize(&fSize);
74 }
75 
~LibRaw_haiku_datastream()76 LibRaw_haiku_datastream::~LibRaw_haiku_datastream()
77 {
78 	delete buffer;
79 }
80 
81 
82 int
read(void * ptr,size_t sz,size_t nmemb)83 LibRaw_haiku_datastream::read(void *ptr, size_t sz, size_t nmemb)
84 {
85 	CALLED();
86 	TRACE("read %ld %ld\n", sz, nmemb);
87 	size_t to_read = sz * nmemb;
88 
89 	to_read = buffer->Read(ptr, to_read);
90 	if (to_read < B_OK)
91 		RETURN("ERROR2", to_read);
92 	return int((to_read + sz - 1) / (sz > 0 ? sz : 1));
93 }
94 
95 
96 int
seek(INT64 o,int whence)97 LibRaw_haiku_datastream::seek(INT64 o, int whence)
98 {
99 	CALLED();
100 	TRACE("seek %lld %d\n", o, whence);
101 	return buffer->Seek(o, whence) < 0;
102 }
103 
104 
105 INT64
tell()106 LibRaw_haiku_datastream::tell()
107 {
108 	CALLED();
109 	off_t position = buffer->Position();
110 	TRACE("RETURN LibRaw_haiku_datastream::tell %ld\n", position);
111 	return position;
112 }
113 
114 
115 INT64
size()116 LibRaw_haiku_datastream::size()
117 {
118 	CALLED();
119 	TRACE("RETURN size %ld\n", fSize);
120 	return fSize;
121 }
122 
123 
124 int
get_char()125 LibRaw_haiku_datastream::get_char()
126 {
127 	CALLED();
128 	unsigned char value;
129 	ssize_t error;
130 	iseof = 0;
131 	error = buffer->Read((void*)&value, sizeof(unsigned char));
132 	if (error >= 0)
133 		return value;
134 	iseof = EOF;
135 	return EOF;
136 }
137 
138 
139 char*
gets(char * s,int sz)140 LibRaw_haiku_datastream::gets(char* s, int sz)
141 {
142 	CALLED();
143 	if (sz<1)
144 		return NULL;
145 	int pos = 0;
146 	bool found = false ;
147 	while (!found && pos < (sz - 1)) {
148 		char buffer;
149 		if (this->buffer->Read(&buffer, 1) < 1)
150 			break;
151 		s[pos++] = buffer ;
152 		if (buffer == '\n') {
153 			found = true;
154 			break;
155 		}
156 	}
157 	if (found) {
158 		s[pos] = 0;
159 	} else
160 		s[sz - 1] = 0 ;
161 	return s;
162 }
163 
164 
165 int
scanf_one(const char * fmt,void * val)166 LibRaw_haiku_datastream::scanf_one(const char *fmt, void *val)
167 {
168 	CALLED();
169   int scanf_res = 0;
170 /*  if (streampos > streamsize)
171     return 0;
172   scanf_res = sscanf_s((char *)(buf + streampos), fmt, val);
173   if (scanf_res > 0)
174   {
175     int xcnt = 0;
176     while (streampos < streamsize)
177     {
178       streampos++;
179       xcnt++;
180       if (buf[streampos] == 0 || buf[streampos] == ' ' ||
181           buf[streampos] == '\t' || buf[streampos] == '\n' || xcnt > 24)
182         break;
183     }
184   }*/
185   return scanf_res;
186 }
187 
188 
189 int
eof()190 LibRaw_haiku_datastream::eof()
191 {
192 	CALLED();
193 	return iseof;
194 }
195 
196 
197 int
valid()198 LibRaw_haiku_datastream::valid()
199 {
200 	CALLED();
201 	return buffer != NULL ? 1 : 0;
202 }
203 
204 
205 void *
make_jas_stream()206 LibRaw_haiku_datastream::make_jas_stream()
207 {
208 	return NULL;
209 }
210 
211 
212 //	#pragma mark -
213 
214 
LibRAW(BPositionIO & stream)215 LibRAW::LibRAW(BPositionIO& stream)
216 	:
217 	fProgressMonitor(NULL),
218 	fRaw(new LibRaw()),
219 	fDatastream(new LibRaw_haiku_datastream(&stream))
220 {
221 	CALLED();
222 }
223 
224 
~LibRAW()225 LibRAW::~LibRAW()
226 {
227 	delete fRaw;
228 	delete fDatastream;
229 }
230 
231 
232 
233 //	#pragma mark -
234 
235 
236 status_t
Identify()237 LibRAW::Identify()
238 {
239 	CALLED();
240 	fDatastream->fStream->Seek(0, SEEK_SET);
241 
242 	status_t status = B_NO_TRANSLATOR;
243 	int ret = fRaw->open_datastream(fDatastream);
244 	if (ret != LIBRAW_SUCCESS) {
245 		TRACE("LibRAW::Identify() open_datastream returned %s\n",
246 			libraw_strerror(ret));
247 		return status;
248 	}
249 
250 	return B_OK;
251 }
252 
253 
254 status_t
ReadImageAt(uint32 index,uint8 * & outputBuffer,size_t & bufferSize)255 LibRAW::ReadImageAt(uint32 index, uint8*& outputBuffer, size_t& bufferSize)
256 {
257 	CALLED();
258 	if (index >= P1.raw_count)
259 		return B_BAD_VALUE;
260 	OUT.shot_select = index;
261 	OUT.output_bps = 8;
262 	OUT.output_tiff = 1;
263 	OUT.no_auto_bright = 1;
264 	OUT.use_auto_wb = 1;
265 	OUT.user_qual = 3;
266 
267 	if (fRaw->unpack() != LIBRAW_SUCCESS)
268 		return B_BAD_DATA;
269 	if (fRaw->dcraw_process() != LIBRAW_SUCCESS)
270 		return B_BAD_DATA;
271 
272 	libraw_processed_image_t* img = fRaw->dcraw_make_mem_image();
273 	if (img == NULL)
274 		return B_BAD_DATA;
275 	bufferSize = img->data_size;
276 	outputBuffer = (uint8*)malloc(bufferSize);
277 	if (outputBuffer == NULL) {
278 		fRaw->dcraw_clear_mem(img);
279 		throw (status_t)B_NO_MEMORY;
280 	}
281 
282 	memcpy(outputBuffer, img->data, bufferSize);
283 
284 	fRaw->dcraw_clear_mem(img);
285 	return B_OK;
286 }
287 
288 
289 void
GetMetaInfo(image_meta_info & metaInfo) const290 LibRAW::GetMetaInfo(image_meta_info& metaInfo) const
291 {
292 	strlcpy(metaInfo.manufacturer, fRaw->imgdata.idata.make,
293 		sizeof(metaInfo.manufacturer));
294 	strlcpy(metaInfo.model, fRaw->imgdata.idata.model, sizeof(metaInfo.model));
295 }
296 
297 
298 uint32
CountImages() const299 LibRAW::CountImages() const
300 {
301 	return fRaw->imgdata.idata.raw_count;
302 }
303 
304 
305 status_t
ImageAt(uint32 index,image_data_info & info) const306 LibRAW::ImageAt(uint32 index, image_data_info& info) const
307 {
308 	if (index >= fRaw->imgdata.idata.raw_count)
309 		return B_BAD_VALUE;
310 
311 	info.width = S.width;
312 	info.height = S.height;
313 	info.output_width = S.flip > 4 ? S.iheight : S.iwidth;
314 	info.output_height = S.flip > 4 ? S.iwidth : S.iheight;
315 	info.flip = S.flip;
316 	info.bytes = S.raw_pitch;
317 	info.is_raw = 1;
318 	return B_OK;
319 }
320 
321 
322 status_t
GetEXIFTag(off_t & offset,size_t & length,bool & bigEndian) const323 LibRAW::GetEXIFTag(off_t& offset, size_t& length, bool& bigEndian) const
324 {
325 	return B_ENTRY_NOT_FOUND;
326 }
327 
328 
329 void
SetProgressMonitor(monitor_hook hook,void * data)330 LibRAW::SetProgressMonitor(monitor_hook hook, void* data)
331 {
332 	fProgressMonitor = hook;
333 	fProgressData = data;
334 	fRaw->set_progress_handler(hook != NULL ? ProgressCallback : NULL, this);
335 }
336 
337 
338 void
SetHalfSize(bool half)339 LibRAW::SetHalfSize(bool half)
340 {
341 	OUT.half_size = half;
342 }
343 
344 
345 int
ProgressCallback(void * data,enum LibRaw_progress p,int iteration,int expected)346 LibRAW::ProgressCallback(void *data, enum LibRaw_progress p, int iteration,
347 	int expected)
348 {
349 	return ((LibRAW*)data)->_ProgressCallback(p, iteration, expected);
350 }
351 
352 
353 int
_ProgressCallback(enum LibRaw_progress p,int iteration,int expected)354 LibRAW::_ProgressCallback(enum LibRaw_progress p,int iteration, int expected)
355 {
356 	fProgressMonitor(libraw_strprogress(p), iteration * 100 / expected,
357 		fProgressData);
358 	return 0;
359 }
360