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