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 28static const uint32 kImageBufferCount = 10; 29static 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 43class LibRaw_haiku_datastream : public LibRaw_abstract_datastream 44{ 45public: 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 60private: 61 StreamBuffer *buffer; 62 off_t fSize; 63 status_t iseof; 64}; 65 66 67LibRaw_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 76LibRaw_haiku_datastream::~LibRaw_haiku_datastream() 77{ 78 delete buffer; 79} 80 81 82int 83LibRaw_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 96int 97LibRaw_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 105INT64 106LibRaw_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 115INT64 116LibRaw_haiku_datastream::size() 117{ 118 CALLED(); 119 TRACE("RETURN size %ld\n", fSize); 120 return fSize; 121} 122 123 124int 125LibRaw_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 139char* 140LibRaw_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 165int 166LibRaw_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 189int 190LibRaw_haiku_datastream::eof() 191{ 192 CALLED(); 193 return iseof; 194} 195 196 197int 198LibRaw_haiku_datastream::valid() 199{ 200 CALLED(); 201 return buffer != NULL ? 1 : 0; 202} 203 204 205void * 206LibRaw_haiku_datastream::make_jas_stream() 207{ 208 return NULL; 209} 210 211 212// #pragma mark - 213 214 215LibRAW::LibRAW(BPositionIO& stream) 216 : 217 fProgressMonitor(NULL), 218 fRaw(new LibRaw()), 219 fDatastream(new LibRaw_haiku_datastream(&stream)) 220{ 221 CALLED(); 222} 223 224 225LibRAW::~LibRAW() 226{ 227 delete fRaw; 228 delete fDatastream; 229} 230 231 232 233// #pragma mark - 234 235 236status_t 237LibRAW::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 254status_t 255LibRAW::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 289void 290LibRAW::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 298uint32 299LibRAW::CountImages() const 300{ 301 return fRaw->imgdata.idata.raw_count; 302} 303 304 305status_t 306LibRAW::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 322status_t 323LibRAW::GetEXIFTag(off_t& offset, size_t& length, bool& bigEndian) const 324{ 325 return B_ENTRY_NOT_FOUND; 326} 327 328 329void 330LibRAW::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 338void 339LibRAW::SetHalfSize(bool half) 340{ 341 OUT.half_size = half; 342} 343 344 345int 346LibRAW::ProgressCallback(void *data, enum LibRaw_progress p, int iteration, 347 int expected) 348{ 349 return ((LibRAW*)data)->_ProgressCallback(p, iteration, expected); 350} 351 352 353int 354LibRAW::_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