diff --git a/build/jam/BuildFeatures b/build/jam/BuildFeatures index 3162433dfc..a36dda79c7 100644 --- a/build/jam/BuildFeatures +++ b/build/jam/BuildFeatures @@ -622,6 +622,23 @@ if [ IsPackageAvailable libdvdnav_devel ] { } +# libraw +if [ IsPackageAvailable libraw_devel ] { + ExtractBuildFeatureArchives libraw : + file: base libraw + runtime: lib + file: devel libraw_devel + depends: base + libraries: $(developLibDir)/libraw.so.19 + headers: $(developHeadersDir) + ; + + EnableBuildFeatures libraw ; +} else { + unavailableBuildFeatures += libraw ; +} + + # libwebp if [ IsPackageAvailable libwebp_devel ] { if $(HAIKU_PACKAGING_ARCH) = x86 && $(TARGET_PACKAGING_ARCH) = x86_gcc2 { diff --git a/src/add-ons/translators/raw/ConfigView.cpp b/src/add-ons/translators/raw/ConfigView.cpp index a58678019f..347fc8372a 100644 --- a/src/add-ons/translators/raw/ConfigView.cpp +++ b/src/add-ons/translators/raw/ConfigView.cpp @@ -16,6 +16,10 @@ #include #include +#ifdef USES_LIBRAW +#include +#endif + #undef B_TRANSLATION_CONTEXT #define B_TRANSLATION_CONTEXT "ConfigView" @@ -39,13 +43,23 @@ ConfigView::ConfigView(uint32 flags) BStringView *fVersion = new BStringView("version", version); BStringView *fCopyright = new BStringView("copyright", - B_UTF8_COPYRIGHT "2007-2009 Haiku Inc."); + B_UTF8_COPYRIGHT "2007-2021 Haiku Inc."); +#ifdef USES_LIBRAW + BString librawInfo = B_TRANSLATE( + "Based on libraw %version%"); + librawInfo.ReplaceAll("%version%", LibRaw::version()); + BStringView *fCopyright2 = new BStringView("Copyright2", + librawInfo.String()); + BStringView *fCopyright3 = new BStringView("Copyright3", + B_TRANSLATE(B_UTF8_COPYRIGHT "Copyright (C) 2008-2021 LibRaw LLC")); +#else BStringView *fCopyright2 = new BStringView("copyright2", B_TRANSLATE("Based on Dave Coffin's dcraw 8.63")); BStringView *fCopyright3 = new BStringView("copyright3", B_UTF8_COPYRIGHT "1997-2007 Dave Coffin"); +#endif // Build the layout BLayoutBuilder::Group<>(this, B_VERTICAL, 0) diff --git a/src/add-ons/translators/raw/Jamfile b/src/add-ons/translators/raw/Jamfile index 1aaee7a3e5..7120c53f2b 100644 --- a/src/add-ons/translators/raw/Jamfile +++ b/src/add-ons/translators/raw/Jamfile @@ -7,16 +7,32 @@ AddResources RAWTranslator : RAWTranslator.rdef ; local architectureObject ; for architectureObject in [ MultiArchSubDirSetup ] { on $(architectureObject) { + + local backend = RAW.cpp ; + local libs = ; + local defines = ; + + if [ FIsBuildFeatureEnabled libraw ] { + UseBuildFeatureHeaders libraw ; + backend = LibRAW.cpp ; + libs = [ BuildFeatureAttribute libraw : libraries ] ; + defines = [ FDefines USES_LIBRAW ] ; + Includes [ FGristFiles ConfigView.cpp LibRAW.cpp + RAWTranslator.cpp ] + : [ BuildFeatureAttribute libraw : headers ] ; + } + SubDirC++Flags $(defines) ; + Translator [ MultiArchDefaultGristFiles RAWTranslator ] : # RawTranslator classes main.cpp RAWTranslator.cpp ConfigView.cpp - RAW.cpp + $(backend) : be translation [ MultiArchDefaultGristFiles libtranslatorsutils.a ] - [ TargetLibsupc++ ] localestub + [ TargetLibsupc++ ] $(libs) localestub : true ; diff --git a/src/add-ons/translators/raw/LibRAW.cpp b/src/add-ons/translators/raw/LibRAW.cpp new file mode 100644 index 0000000000..4dbaa5c255 --- /dev/null +++ b/src/add-ons/translators/raw/LibRAW.cpp @@ -0,0 +1,359 @@ +/* + * Copyright 2021, Jérôme Duval, jerome.duval@gmail.com. + * Distributed under the terms of the MIT License. + */ + + +#include "LibRAW.h" + +#include +#include + +#include +#include +#include +#include + +#include + +#include "StreamBuffer.h" + + +//#define TRACE(x...) printf(x) +#define TRACE(x...) +#define CALLED() TRACE("CALLED %s\n", __PRETTY_FUNCTION__) +#define RETURN(x, y) { TRACE("RETURN %s %s\n", __PRETTY_FUNCTION__, x); \ + return y; } + +static const uint32 kImageBufferCount = 10; +static const uint32 kDecodeBufferCount = 2048; + + +#define P1 fRaw->imgdata.idata +#define S fRaw->imgdata.sizes +#define C fRaw->imgdata.color +#define T fRaw->imgdata.thumbnail +#define P2 fRaw->imgdata.other +#define OUT fRaw->imgdata.params + + +// #pragma mark - + + +class LibRaw_haiku_datastream : public LibRaw_abstract_datastream +{ +public: + BPositionIO* fStream; + virtual ~LibRaw_haiku_datastream(); + LibRaw_haiku_datastream(BPositionIO* stream); + virtual int valid(); + virtual int read(void *ptr, size_t size, size_t nmemb); + virtual int eof(); + virtual int seek(INT64 o, int whence); + virtual INT64 tell(); + virtual INT64 size(); + virtual int get_char(); + virtual char *gets(char *str, int sz); + virtual int scanf_one(const char *fmt, void *val); + virtual void *make_jas_stream(); + +private: + StreamBuffer *buffer; + off_t fSize; + status_t iseof; +}; + + +LibRaw_haiku_datastream::LibRaw_haiku_datastream(BPositionIO* stream) +{ + CALLED(); + iseof = 0; + buffer = new StreamBuffer(stream, 2048); + fStream = stream; + fStream->GetSize(&fSize); +} + +LibRaw_haiku_datastream::~LibRaw_haiku_datastream() +{ + delete buffer; +} + + +int +LibRaw_haiku_datastream::read(void *ptr, size_t sz, size_t nmemb) +{ + CALLED(); + TRACE("read %ld %ld\n", sz, nmemb); + size_t to_read = sz * nmemb; + + to_read = buffer->Read(ptr, to_read); + if (to_read < B_OK) + RETURN("ERROR2", to_read); + return int((to_read + sz - 1) / (sz > 0 ? sz : 1)); +} + + +int +LibRaw_haiku_datastream::seek(INT64 o, int whence) +{ + CALLED(); + TRACE("seek %lld %d\n", o, whence); + return buffer->Seek(o, whence) < 0; +} + + +INT64 +LibRaw_haiku_datastream::tell() +{ + CALLED(); + off_t position = buffer->Position(); + TRACE("RETURN LibRaw_haiku_datastream::tell %ld\n", position); + return position; +} + + +INT64 +LibRaw_haiku_datastream::size() +{ + CALLED(); + TRACE("RETURN size %ld\n", fSize); + return fSize; +} + + +int +LibRaw_haiku_datastream::get_char() +{ + CALLED(); + unsigned char value; + ssize_t error; + iseof = 0; + error = buffer->Read((void*)&value, sizeof(unsigned char)); + if (error >= 0) + return value; + iseof = EOF; + return EOF; +} + + +char* +LibRaw_haiku_datastream::gets(char* s, int sz) +{ + CALLED(); + if (sz<1) + return NULL; + int pos = 0; + bool found = false ; + while (!found && pos < (sz - 1)) { + char buffer; + if (this->buffer->Read(&buffer, 1) < 1) + break; + s[pos++] = buffer ; + if (buffer == '\n') { + found = true; + break; + } + } + if (found) { + s[pos] = 0; + } else + s[sz - 1] = 0 ; + return s; +} + + +int +LibRaw_haiku_datastream::scanf_one(const char *fmt, void *val) +{ + CALLED(); + int scanf_res = 0; +/* if (streampos > streamsize) + return 0; + scanf_res = sscanf_s((char *)(buf + streampos), fmt, val); + if (scanf_res > 0) + { + int xcnt = 0; + while (streampos < streamsize) + { + streampos++; + xcnt++; + if (buf[streampos] == 0 || buf[streampos] == ' ' || + buf[streampos] == '\t' || buf[streampos] == '\n' || xcnt > 24) + break; + } + }*/ + return scanf_res; +} + + +int +LibRaw_haiku_datastream::eof() +{ + CALLED(); + return iseof; +} + + +int +LibRaw_haiku_datastream::valid() +{ + CALLED(); + return buffer != NULL ? 1 : 0; +} + + +void * +LibRaw_haiku_datastream::make_jas_stream() +{ + return NULL; +} + + +// #pragma mark - + + +LibRAW::LibRAW(BPositionIO& stream) + : + fProgressMonitor(NULL), + fRaw(new LibRaw()), + fDatastream(new LibRaw_haiku_datastream(&stream)) +{ + CALLED(); +} + + +LibRAW::~LibRAW() +{ + delete fRaw; + delete fDatastream; +} + + + +// #pragma mark - + + +status_t +LibRAW::Identify() +{ + CALLED(); + fDatastream->fStream->Seek(0, SEEK_SET); + + status_t status = B_NO_TRANSLATOR; + int ret = fRaw->open_datastream(fDatastream); + if (ret != LIBRAW_SUCCESS) { + TRACE("LibRAW::Identify() open_datastream returned %s\n", + libraw_strerror(ret)); + return status; + } + + return B_OK; +} + + +status_t +LibRAW::ReadImageAt(uint32 index, uint8*& outputBuffer, size_t& bufferSize) +{ + CALLED(); + if (index >= P1.raw_count) + return B_BAD_VALUE; + OUT.shot_select = index; + OUT.output_bps = 8; + OUT.output_tiff = 1; + OUT.no_auto_bright = 1; + OUT.use_auto_wb = 1; + OUT.user_qual = 3; + + if (fRaw->unpack() != LIBRAW_SUCCESS) + return B_BAD_DATA; + if (fRaw->dcraw_process() != LIBRAW_SUCCESS) + return B_BAD_DATA; + + libraw_processed_image_t* img = fRaw->dcraw_make_mem_image(); + if (img == NULL) + return B_BAD_DATA; + bufferSize = img->data_size; + outputBuffer = (uint8*)malloc(bufferSize); + if (outputBuffer == NULL) { + fRaw->dcraw_clear_mem(img); + throw (status_t)B_NO_MEMORY; + } + + memcpy(outputBuffer, img->data, bufferSize); + + fRaw->dcraw_clear_mem(img); + return B_OK; +} + + +void +LibRAW::GetMetaInfo(image_meta_info& metaInfo) const +{ + strlcpy(metaInfo.manufacturer, fRaw->imgdata.idata.make, + sizeof(metaInfo.manufacturer)); + strlcpy(metaInfo.model, fRaw->imgdata.idata.model, sizeof(metaInfo.model)); +} + + +uint32 +LibRAW::CountImages() const +{ + return fRaw->imgdata.idata.raw_count; +} + + +status_t +LibRAW::ImageAt(uint32 index, image_data_info& info) const +{ + if (index >= fRaw->imgdata.idata.raw_count) + return B_BAD_VALUE; + + info.width = S.width; + info.height = S.height; + info.output_width = S.flip > 4 ? S.iheight : S.iwidth; + info.output_height = S.flip > 4 ? S.iwidth : S.iheight; + info.flip = S.flip; + info.bytes = S.raw_pitch; + info.is_raw = 1; + return B_OK; +} + + +status_t +LibRAW::GetEXIFTag(off_t& offset, size_t& length, bool& bigEndian) const +{ + return B_ENTRY_NOT_FOUND; +} + + +void +LibRAW::SetProgressMonitor(monitor_hook hook, void* data) +{ + fProgressMonitor = hook; + fProgressData = data; + fRaw->set_progress_handler(hook != NULL ? ProgressCallback : NULL, this); +} + + +void +LibRAW::SetHalfSize(bool half) +{ + OUT.half_size = half; +} + + +int +LibRAW::ProgressCallback(void *data, enum LibRaw_progress p, int iteration, + int expected) +{ + return ((LibRAW*)data)->_ProgressCallback(p, iteration, expected); +} + + +int +LibRAW::_ProgressCallback(enum LibRaw_progress p,int iteration, int expected) +{ + fProgressMonitor(libraw_strprogress(p), iteration * 100 / expected, + fProgressData); + return 0; +} diff --git a/src/add-ons/translators/raw/LibRAW.h b/src/add-ons/translators/raw/LibRAW.h new file mode 100644 index 0000000000..a55dbd6c94 --- /dev/null +++ b/src/add-ons/translators/raw/LibRAW.h @@ -0,0 +1,100 @@ +/* + * Copyright 2021, Jérôme Duval, jerome.duval@gmail.com. + * Distributed under the terms of the MIT License. + */ +#ifndef LIBRAW_H +#define LIBRAW_H + + +#include +#include + +#include + + +class LibRaw; +class LibRaw_haiku_datastream; + + +struct image_meta_info { + char manufacturer[64]; + char model[64]; + char software[64]; + float flash_used; + float iso_speed; + float shutter; + float aperture; + float focal_length; + double pixel_aspect; + uint32 raw_width; + uint32 raw_height; + int flip; + uint32 dng_version; + uint32 shot_order; + int32 black; + int32 maximum; + float camera_multipliers[4]; + float pre_multipliers[4]; + float rgb_camera[3][4]; /* RGB from camera color */ + time_t timestamp; +}; + +struct image_data_info { + uint32 width; + uint32 height; + uint32 output_width; + uint32 output_height; + uint32 bits_per_sample; + uint32 compression; + uint32 photometric_interpretation; + uint32 flip; + uint32 samples; + uint32 bytes; + off_t data_offset; + bool is_raw; +}; + +#define COMPRESSION_NONE 1 +#define COMPRESSION_OLD_JPEG 6 // Old JPEG (before 6.0) +#define COMPRESSION_PACKBITS 32773 // Macintosh RLE + + +typedef void (*monitor_hook)(const char* message, float percentage, void* data); + +class LibRAW { +public: + LibRAW(BPositionIO& stream); + ~LibRAW(); + + status_t Identify(); + status_t ReadImageAt(uint32 index, uint8*& outputBuffer, + size_t& bufferSize); + + void GetMetaInfo(image_meta_info& metaInfo) const; + uint32 CountImages() const; + status_t ImageAt(uint32 index, image_data_info& info) + const; + + status_t GetEXIFTag(off_t& offset, size_t& length, + bool& bigEndian) const; + void SetProgressMonitor(monitor_hook hook, + void* data); + + void SetHalfSize(bool half); + +private: + static int ProgressCallback(void *data, + enum LibRaw_progress p, + int iteration, int expected); + int _ProgressCallback(enum LibRaw_progress p, + int iteration, int expected); + + monitor_hook fProgressMonitor; + void* fProgressData; + + LibRaw* fRaw; + LibRaw_haiku_datastream* fDatastream; +}; + + +#endif // LIBRAW_H diff --git a/src/add-ons/translators/raw/RAWTranslator.cpp b/src/add-ons/translators/raw/RAWTranslator.cpp index 031a0a6b2d..8b9b789514 100644 --- a/src/add-ons/translators/raw/RAWTranslator.cpp +++ b/src/add-ons/translators/raw/RAWTranslator.cpp @@ -6,7 +6,11 @@ #include "RAWTranslator.h" #include "ConfigView.h" +#ifdef USES_LIBRAW +#include "LibRAW.h" +#else #include "RAW.h" +#endif #include #include @@ -127,7 +131,11 @@ RAWTranslator::DerivedIdentify(BPositionIO *stream, return B_NO_TRANSLATOR; BBufferIO io(stream, 128 * 1024, false); +#ifdef USES_LIBRAW + LibRAW raw(io); +#else DCRaw raw(io); +#endif status_t status; try { @@ -199,7 +207,11 @@ RAWTranslator::DerivedTranslate(BPositionIO* stream, return B_NO_TRANSLATOR; BBufferIO io(stream, 1024 * 1024, false); +#ifdef USES_LIBRAW + LibRAW raw(io); +#else DCRaw raw(io); +#endif bool headerOnly = false; @@ -300,13 +312,23 @@ RAWTranslator::DerivedTranslate(BPositionIO* stream, free(exifBuffer); } } + +#ifdef USES_LIBRAW + uint32 dataSize = data.output_width * 3 * data.output_height; +#else uint32 dataSize = data.output_width * 4 * data.output_height; +#endif TranslatorBitmap header; header.magic = B_TRANSLATOR_BITMAP; header.bounds.Set(0, 0, data.output_width - 1, data.output_height - 1); +#ifdef USES_LIBRAW + header.rowBytes = data.output_width * 3; + header.colors = B_RGB24_BIG; +#else header.rowBytes = data.output_width * 4; header.colors = B_RGB32; +#endif header.dataSize = dataSize; // write out Be's Bitmap header diff --git a/src/data/package_infos/generic/haiku b/src/data/package_infos/generic/haiku index dbea0cada7..878f1cb1c1 100644 --- a/src/data/package_infos/generic/haiku +++ b/src/data/package_infos/generic/haiku @@ -143,5 +143,8 @@ requires { #ifdef HAIKU_BUILD_FEATURE_%HAIKU_PACKAGING_ARCH%_libwebp_ENABLED lib:libwebp #endif +#ifdef HAIKU_BUILD_FEATURE_%HAIKU_PACKAGING_ARCH%_libraw_ENABLED + lib:libraw >= 19 +#endif #endif }