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 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 76 LibRaw_haiku_datastream::~LibRaw_haiku_datastream() 77 { 78 delete buffer; 79 } 80 81 82 int 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 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 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 116 LibRaw_haiku_datastream::size() 117 { 118 CALLED(); 119 TRACE("RETURN size %ld\n", fSize); 120 return fSize; 121 } 122 123 124 int 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* 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 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 190 LibRaw_haiku_datastream::eof() 191 { 192 CALLED(); 193 return iseof; 194 } 195 196 197 int 198 LibRaw_haiku_datastream::valid() 199 { 200 CALLED(); 201 return buffer != NULL ? 1 : 0; 202 } 203 204 205 void * 206 LibRaw_haiku_datastream::make_jas_stream() 207 { 208 return NULL; 209 } 210 211 212 // #pragma mark - 213 214 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 225 LibRAW::~LibRAW() 226 { 227 delete fRaw; 228 delete fDatastream; 229 } 230 231 232 233 // #pragma mark - 234 235 236 status_t 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 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 290 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 299 LibRAW::CountImages() const 300 { 301 return fRaw->imgdata.idata.raw_count; 302 } 303 304 305 status_t 306 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 323 LibRAW::GetEXIFTag(off_t& offset, size_t& length, bool& bigEndian) const 324 { 325 return B_ENTRY_NOT_FOUND; 326 } 327 328 329 void 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 339 LibRAW::SetHalfSize(bool half) 340 { 341 OUT.half_size = half; 342 } 343 344 345 int 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 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