pax_global_header00006660000000000000000000000064132442322770014520gustar00rootroot0000000000000052 comment=9f26ce37f5be86ea11bfc6831366558650b1f6ff LibRaw-0.18.8/000077500000000000000000000000001324423227700127765ustar00rootroot00000000000000LibRaw-0.18.8/.gitignore000066400000000000000000000000321324423227700147610ustar00rootroot00000000000000samples/lens-identify.cpp LibRaw-0.18.8/COPYRIGHT000077500000000000000000000021211324423227700142700ustar00rootroot00000000000000 ** LibRaw: Raw images processing library ** Copyright (C) 2008-2017 LibRaw LLC (http://www.libraw.org, info@libraw.org) LibRaw is free software; you can redistribute it and/or modify it under the terms of the one of two licenses as you choose: 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 (See file LICENSE.LGPL provided in LibRaw distribution archive for details). 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 (See file LICENSE.CDDL provided in LibRaw distribution archive for details). LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, dcraw.c is copyright 1997-2012 by Dave Coffin, dcoffin a cybercom o net. LibRaw uses DCB demosaic and FBDD denoise licensed under BSD-like 3-clause license DCB and FBDD are Copyright (C) 2010, Jacek Gozdz (cuniek@kft.umcs.lublin.pl) LibRaw uses X3F library to unpack Foveon Files, licensed BSD-style license Copyright (c) 2010, Roland Karlsson (roland@proxel.se) All rights reserved. LibRaw uses pieces of code from Adobe DNG SDK 1.4, Copyright (c) 2005 Adobe Systems Incorporated licensed under MIT license LibRaw-0.18.8/Changelog.txt000077500000000000000000002213541324423227700154400ustar00rootroot000000000000002018-02-23 Alex Tutubalin Secunia #81000: Credit: Laurent Delosieres, Secunia Research at Flexera * leaf_hdr_load_raw: check for image pointer for demosaiced raw * NOKIARAW parser: check image dimensions readed from file * quicktake_100_load_raw: check width/height limits * LibRaw 0.18.8 2018-01-29 Alex Tutubalin * Checks for width+left_margin/height+top_margin not larger than 64k * LIBRAW_MAX_ALLOC_MB define limits maximum image/raw_image allocation (default is 2048 so 2Gb per array) * LibRaw::read_shorts item count is now unsigned 2018-01-19 Alex Tutubalin Secunia #79000: Credit: Laurent Delosieres, Secunia Research at Flexera * All legacy (RGB raw) image loaders checks for imgdata.image is not NULL * kodak_radc_load_raw: check image size before processing * legacy memory allocator: allocate max(widh,raw_width)*max(height,raw_height) * LibRaw 0.18.7 2017-12-06 Alex Tutubalin Secunia #76000: * Fixed fuji_width handling if file is neither fuji nor DNG * Fixed xtrans interpolate for broken xtrans pattern * Fixed panasonic decoder * LibRaw 0.18.6 2017-09-22 Alex Tutubalin * Fixed possible out of bound access in Kodak 6500 loader * LibRaw 0.18.5 2017-09-12 Alex Tutubalin * CVE-2017-14348: Fix for possible heap overrun in Canon makernotes parser Credit: Henri Salo from Nixu Corporation * LibRaw 0.18.4 2017-09-09 Alex Tutubalin * Fix for CVE-2017-13735 * CVE-2017-14265: Additional check for X-Trans CFA pattern data * LibRaw 0.18.3 2017-03-08 Alex Tutubalin * Fixed several errors (Secunia advisory SA75000) * ACES colorspace output option included in dcraw_emu help page * Avoided possible 32-bit overflows in Sony metadata parser * Phase One flat field code called even for half-s * LibRaw 0.18.2 2017-02-12 Alex Tutubalin * Camera Support: Sigma Quatto H * Fixed bug in FujiExpoMidPointShift parser * Fixed wrong black level in Sony A350 * Added standard integer types for VisualStudio 2008 and earlier * LibRaw 0.18.1 2016-12-27 Alex Tutubalin * Licensing changes: - there is no 'LibRaw Software License 27032010' licensing anymore (and all signed agreements have expired) - LibRaw is now dual-licensed: LGPL 2.1 or CDDL 1.0 * Camera support (+87): Apple: iPad Pro, iPhone SE, iPhone 6s, iPhone 6 plus, iPhone 7, iPhone 7 plus BlackMagic Micro Cinema Camera, URSA, URSA Mini Canon PowerShot G5 X, PowerShot G7 X Mark II, PowerShot G9 X, IXUS 160 (CHDK hack), EOS 5D Mark IV, EOS 80D, EOS 1300D, EOS M10, EOS M5, EOS-1D X Mark II Casio EX-ZR4000/5000 DXO One, FujiFilm X-Pro2, X70, X-E2S, X-T2 Gione E7 GITUP GIT2 Google Pixel,Pixel XL Hasselblad X1D, True Zoom HTC MyTouch 4G, One (A9), One (M9), 10 Huawei P9 Leica M (Typ 262), M-D (Typ 262), S (Typ 007), SL (Typ 601), X-U (Typ 113), TL LG G3, G4 Meizy MX4 Nikon D5, D500, D3400 Olympus E-PL8, E-M10 Mark II, Pen F, SH-3, E-M1-II Panasonic DMC-G8/80/81/85, DMC-GX80/85, DMC-TZ80/81/85/ZS60, DMC-TZ100/101/ZS100,DMC-LX9/10/15, FZ2000/FZ2500 Pentax K-1, K-3 II, K-70 PhaseOne IQ3 100MP RaspberryPi Camera, Camera V2 Ricoh GR II Samsung Galaxy S7, S7 Edge Sigma sd Quattro Sony A7S II, ILCA-68 (A68),ILCE-6300,DSC-RX1R II,DSC-RX10III, DSC-RX100V,ILCA-99M2 (A99-II), a6500 IMX214, IMX219, IMX230, IMX298-mipi 16mp, IMX219-mipi 8mp, Xperia L PtGrey GRAS-50S5C YUNEEC CGO4 Xiaomi MI3, RedMi Note3 Pro * Floating point DNG support: - new data fields: imgdata.rawdata.float_image - bayer float data imgdata.rawdata.float3_image - 3-component float data imgdata.rawdata.float4_image - 4-component float data imgdata.color.fmaximum - float data maximum (calculated from real data, rounded to 1.0 if below 1.0) - new raw processing flag LIBRAW_PROCESSING_CONVERTFLOAT_TO_INT - converts float data to 16-bit integer immediately after decoding with default parameters - new API Calls: int LibRaw::is_floating_point() returns non-zero if RAW file contains floating point data int LibRaw::have_fpdata() returns non-zero if rawdata.float*_image is not null (so FP data has been unpacked but not converted to integrer, see below). LibRaw::convertFloatToInt(float dmin=4096.f, float dmax=32767.f, float dtarget = 16383.f) converts float/float3/float4_image to raw_image/color3/color4_image with or without scaling: - if both real data maximum and metadata maximum are within the range ( >= dmin && <=dmax), float data is just converted to integer - if data is out of the range given above, values are scaled so real data maximum becomes dtarget - if data was rescaled (normalized), scale multiplier is stored in imgdata.color.fnorm * LibRaw can be built with Adobe DNG SDK support to decode exotic DNG formats (e.g. 8 bit). See README.DNGSDK.txt for details * New API calls unsigned LibRaw::capabilities and C-API libraw_capabilities() allows developers to determine LibRaw compile flags at runtime. Returns ORed bit fields: LIBRAW_CAPS_RAWSPEED - LibRaw was compiled with RawSpeed Support LIBRAW_CAPS_DNGSDK - LibRaw was compiled with Adobe DNG SDK LIBRAW_CAPS_DEMOSAICSGPL2, LIBRAW_CAPS_DEMOSAICSGPL3 - LibRaw was compiled with demosaic packs (GPL2/GPL3) * More metadata parsed: - White balance coefficients stored in the raw file are extracted into: int imgdata.color.WBCoeffs[256][4] - array indexed by EXIF lightsource type for example, WBCoeffs[21][..] contains coefficients for D65 lightsource float imgdata.color.WBCT_Coeffs[64][5] contains white balance data specified for given color temperature: WBCT_Coeffs[i][0] contains temperature value, and [1]..[4] are WB coefficients. - DNG analog balance, per-channel black/white level, and forward matrix - vendor specific metadata stored in vendor-specific data structures * new C-API calls: void libraw_set_user_mul(libraw_data_t *lr,int index, float val); void libraw_set_ca_correction(libraw_data_t *lr,int ca_correc, float ca_red, float ca_blue); void libraw_set_cfalinenoise(libraw_data_t *lr,int cfaline, float linenoise); void libraw_set_wf_debanding(libraw_data_t *lr, int wf_debanding, float wfd0, float wfd1, float wfd2, float wfd3); void libraw_set_interpolation_passes(libraw_data_t *lr,int passes); * Existing API changes: imgdata.params fields (all very specific purpose): sony_arw2_options, sraw_ycc, and params.x3f_flags replaced with single bit-field raw_processing_options See LIBRAW_PROCESSING_* bits in documentation. * zlib library is optional Use -DUSE_ZLIB to compile with zlib (to provide deflate DNG support) * libjpeg version: jpeg_mem_src() is mandatory, so use libjpeg-turbo or libjpeg 8+ * Fixes in vng_intepolate to make modern compilers happy * Fixed bug in Sony SR2 files black level * DNG files with BlackLevel both in vendor makernotes and BlackLevel: BlackLevel tag always takes precedence * strlen replaced with strnlen in most cases, added local version of strnlen * ChannelBlackLevel added to canon makernotes * unpack_thumb() data size/offset check against file size 2015-08-15 Alex Tutubalin * LibRaw 0.17 * Fixed dcraw.c ljpeg_start possibly buffer overrun * fixed several bugs detected by using American Fuzzy Lop * C-API extension to support 3DLut Creator * More metadata parsing/extraction: - XMP packet extracted (if exists) - DNG Color information parsed - GPS data (partially) parsed - EXIF/Makernotes parsed for used optics (for both RAW files and DNG converted by Adobe convertor). * Exif/Makernotes parser callback (called for each processed tag) * Sony ARW2.3 decoder: - params.sony_arw2_hack removed, decoded data are always in 0...17k range (note the difference with dcraw!) - Additional processing options for Sony lossy compression techincal analysis. * Dcraw 9.26 imported (but some changes not approved because Libraw do it better) with some exceptions: - no Pentax K3-II frame selection code - no built-in JPEG decompressor * Many improvements in data decoding/processing: - Correct decoding of black level values from metadata for many formats, LibRaw do not rely on hardcoded black levels. * 224 camera models added to supported camera list. Some of them are new (released since LibRaw 0.16 come out), some was supported before, but missed from the list. Added cameras are: Alcatel 5035D BlackMagic Pocket Cinema Camera, Production Camera 4k Canon PowerShot A550, A3300 IS, G1 X Mark II, G7 X, SD950, SX60 HS, EOS 7D Mark II, EOS 20Da, EOS 60Da, EOS 1200D, EOS-1D C, 5DS, 5DS R, 750D, 760D, M2, M3, G3 X Casio EX-FC300S, EX-FC400S, EX-Z1080, EX-ZR700, EX-ZR710, EX-ZR750, EX-ZR800, EX-ZR850, EX-ZR1000, EX-ZR1100, ZR1200, ZR1300, EX-ZR1500, EX-100, EX-10 Digital Bolex D16,D16M DJI 4384x3288, Epson R-D1s, R-D1x FujiFilm E505,S1,S205EXR,HS10,HS11,HS22EXR,HS33EXR,HS35EXR,F505EXR,F605EXR,F775EXR,F900EXR,X100T,X30,X-T1,X-T1 Graphite Silver, XQ2, X-A2, X-T10 Hasselblad H5D-60, H5D-50,H5D-50c,H5D-40,H4D-60,H4D-50,H4D-40,H4D-31,H3DII-22,H3DII-31,H3DII-39,H3DII-50,H3D-22,H3D-31,H3D-39,H2D-22,H2D-39,CF-22,CF-31,CF-39,Stellar II,HV HTC UltraPixel Imacon Ixpress 96, 96C, 384, 384C (single shot only),132C, 528C (single shot only) ISG 2020x1520 Ikonoskop A-Cam dII Panchromatic, A-Cam dII Kinefinity KineMINI, KineRAW Mini, KineRAW S35 Kodak DCS460D, S-1 Leaf Credo 50 Lenovo a820 Leica Digital-Modul-R, D-Lux (Typ 109), M (Typ 240), Monochrom (Typ 240), M-E, M-P, R8, S, T (Typ 701), X (Typ 113), X2, X-E (Typ 102), V-Lux (Typ 114), Monochrom (Typ 246), Q Matrix 4608x3288 Nikon D4s, D600, D610, D750, D800, D800E, D810, D3300, D5500, Df, 1 J4, 1 S2, 1 V3, Coolpix P340, Coolscan NEF, D7200, 1 J5,D810A Nokia 1200x1600 Olympus E-450, E-600, E-PL6, E-PL7, E-M1, E-M10, E-M5 Mark II, SP565UZ, STYLUS1s, SH-2, TG-4, AIR-A01 Panasonic DMC-CM1, DMC-FZ7, DMC-FZ70, DMC-FZ1000, DMC-GF7, DMC-GH4, AG-GH4, DMC-GM1s, DMC-GM5, DMC-LX100, DMC-TZ60/61/SZ40, DMC-TZ70, FZ300/330, GX8 Pentax GR, K110D, K-01, K-S1, Q, QS-1, 645Z, K-S2, K3 II PhaseOne IQ250, IQ260, IQ260 Achromatic, IQ280, Achromatic+, P 20+, P 21, P 25+, P 30+, P 40+ Ricoh GXR MOUNT A12, GXR MOUNT A16 24-85mm F3.5-5.5, GXR, S10 24-72mm F2.5-4.4 VC, GXR, GR A12 50mm F2.5 MACRO, GXR, GR LENS A12 28mm F2.5, GXR, GXR P10 Samsung GX-1L, NX1, NX5, NX1000, NX1100, NX30, NX300, NX300M, NX3000, NX mini, Galaxy S3, Galaxy Nexus, NX500 Sigma dp1 Quattro, dp2 Quattro, dp3 Quattro, dp0 Quattro Sinar eMotion 22, eMotion 54, eSpirit 65, eMotion 75, eVolution 75, Sinarback 54 Sony A7 II, A7S, ILCA-77M2 (A77-II), ILCE-3000, ILCE-5000, ILCE-5100, ILCE-6000, ILCE-QX1, DSC-RX100III, DSLR-A560, NEX-VG20, NEX-VG30, NEX-VG900, IMX135-mipi 13mp, IMX135-QCOM, IMX072-mipi, RX100-IV, A7R-II, RX10-II * Fujifilm F700/S20Pro second frame support 2014-02-01 Alex Tutubalin * Updated Oly E-M10 & Panasonic TZ60/61 color data * Updated foveon SD9-14 white level * Support for 1x1 BlackLevelRepeatDim 2014-01-31 Alex Tutubalin * imported dcraw 1.461: fixed error in BlackLevelDim handling * Accurate work with pattern black-level (cblack[6+]) * Support for Olympus E-M10 and Fujifilm X-T1 * Adjusted possbile maximum value for Sigma SD9 small raws 2014-01-27 Alex Tutubalin * dcraw 1.460: Nikon D3300, Panasonic DMC-TZ61, Sony ILCE-5000 2014-01-25 Alex Tutubalin * PhaseOne IQ250 support (both compressed and uncompressed) 2014-01-21 Alex Tutubalin * imgdata.params.sony_arw2_hack removed. It always on for ARW2-files. * New imgdata.params.sony_arw2_options processing flags Values: LIBRAW_SONYARW2_NONE - normal processing LIBRAW_SONYARW2_BASEONLY - BASE pixels outputeed, delta pixels set to 0 LIBRAW_SONYARW2_DELTAONLY - Delta pixels written to raw data, base pixels zeroed LIBRAW_SONYARW2_DELTAZEROBASE - Only deltas written without base offset 2014-01-20 Alex Tutubalin * Imported dcraw 9.20: - Support for DNG BlackLevelRepeatDim tags - imgdata.color.cblack[] holds variable BlackLevel for DNG files (up to ~4k values) - imgdata.params.use_camera_matrix is now ON by default. Set it to 3 if you want to force use of DNG embedded matrix. - Tone curve for Canon RMF format supported - Color data for Canon C500 * Additional camera support: Alcatel 5035D DJI 4384x3288 Fujifilm F900EXR Kodak 12MP Matrix 4608x3288 Nokia 1200x1600 Olympus E-PL6 Panasonic DMC-FZ7 2014-01-17 Alex Tutubalin * Camera support: Added: Fujifilm XE2, XQ1 Color data updated: Nikon D4 1 AW1/J3, Fuji X-M2 Fixes: Nikon D610 visible image area, Canon A3300 bayer pattern * RawSpeed support: enabled processing for cameras, unknown to RawSpeed * Fixed error in LibRaw::unpack_thumb() * little improve performance in my_strcasestr * Fix compiler errors for VS2012/OpenMP * Fixed typo which prevents to use Demosaic Pack GPL2 * LibRaw 0.16.0-Release 2013-11-15 Alex Tutubalin * New cameras supported Leica C, X VARIO Nikon D5300, D610, Df, 1 AW1 Nokia Lumia 1020, 1520 Olympus STYLUS1 Pentax K-3 Sony RX10, A3000 (ILCE-3000), * Color data updated: Canon S120 Nikon P7800, 1 J3 Olympus E-M1 * Corrected image visible area sizes Canon G16 Sigma pre-Merrill cameras: small and medium-sized RAWs * Better EXIF parsing: - ISO values for new Nikon cameras (D4, D800) - black level extraction for Nikon D5300 - correct Olympus color data conversion * Better Visual Studio compatibility (esp. old versions) * Cmake build: added ws2_32 library for MinGW builds * LibRaw 0.16.0-Beta1 2013-10-22 Alex Tutubalin * Support for new cameras: Sony A7, A7R Panasonic GM1 * Sony RX1R and RX100M2 color data updated. * Sony cameras model name is set by SonyModelID EXIF tag * Sony ARW2: black level and color matrix extracted from EXIF data * Samsung: black level and color matrix extracted from EXIF; Camera multipliers are now extracted correctly even if black is not 0 * Better source compatibility with Mac OS X compilation * Better source compatibility with Win32 compilation * DNG without Compression tag assumed uncompressed * Better X3F-tools based Foveon support: - new Foveon metadata parser based on X3F-tools. So, if LibRaw compiled without demosaic-pack-GPL2, then no dcraw Foveon code used. - Support for Medium resolution RAWs from DPx Merrill and SD1 cameras. RAW data extracted as is (4800x1600 pixels), aspect ratio is set to 0.5, so these RAWs are processed to full-size 4800x3200 RGB. - Support for Foveon thumbnail extraction. Only JPEG and bitmap thumbnails extracted, but 'foveon' (RAW) thumbnails are really not used in production cameras. - New imgdata.params.force_foveon_x3f flag Forces use of x3f-tools based code for Foveon processing if LibRaw compiled with demosaic-pack-GPL2 (and does nothing if LibRaw compiled without this pack). New flag -disadcf added to dcraw_emu sample to use this flag. - LibRaw do not calls exit() on broken Foveon files. * API/ABI changed, so all code using LibRaw should be recompiled. * LibRaw 0.16.0-Alpha3 2013-10-16 Alex Tutubalin * Support for new cameras: Canon S120 (preliminary color data), G16 Fujifilm X-A1 (preliminary color data) Hasselblad Lunar, Stellar Nikon P7800 (preliminary color data) Pentax K50, K500, Q7 Samsung Galaxy NX (EK-GN120) Sony NEX-5T * Updated color data for: Samsung NX300 Sony RX1R Sigma SD1, SD1 Merrill, DPxx (only if non-GPL2 foveon decoder used) * Image dimensions table for Foveon cameras (only if non-GPL2 foveon decoder used) * Fixed memory leak in x3f-tools code (new Foveon decoder) * Fixed DHT-demosaic incompatibility with MS VisualStudio in OpenMP directives * Additional image size checks. * LibRaw 0.16-Alpha2 2013-09-22 Alex Tutubalin * Support for new cameras: Baumer TXG14 Blackmagic Cinema Canon EOS 70D, C500 Fujifilm X-M1 Nikon D5200 Olympus E-P5,E-M1 OmniVision OV5647 (Raspberry Pi) Panasonic LF1, GX7, GF6 Richon GR Samsung NX300, NX1100, NX2000 Sony RX100II, RX1R, NEX-3N * Support for Foveon sensor based on X3F code by Roland Karlsson BSD-like license, so included in main LibRaw code. No 'foveon intepolation', so no way to get good colors from old Sigma cameras (SD9, SD14, Polaroid x530). For modern Foveon cameras one may try to create ICC profile (not supplied). TODO: thumbnail extraction, fast cancelation Old foveon_*_load_raw (from dcraw) code is used if compiled with LIBRAW_DEMOSAIC_PACK_GPL2 * API Changes: + New parameters in imgdata.params: - imgdata.params.no_interpolation - disables interpolation step in LibRaw::dcraw_process() call. - imgdata.params.no_auto_scale - disables call to scale_colors() in LibRaw::dcraw_process() call. - imgdata.params.sraw_ycc - disables Canon sRAW YCbCr to RGB conversion in LibRaw::unpack() call (use for RAW analyzers + New Fuji X-Trans handling: - imgdata.iparams.filters value is now 9 for Fuji X-Trans (instead of 2) - imgdata.iparams.xtrans[6][6] matrix contains row/col to color mapping for Fuji X-Trans sensor. + LibRaw::setCancelFlag() - use for fast decoder termination + LibRaw_abstract_datastream::make_byte_buffer() call is not needed more. + New demosaic code: DHT Demosaic by Anton Petrusevich Set params.user_qual=11 to use. + New demosaic code: Modified AHD Demosaic by Anton Petrusevich Set params.user_qual=12 to use. + New C-API call libraw_COLOR(libraw_data_t *t, int row,int col) (so LibRaw::COLOR(row,col) exposed to C-API users) * Removed faster lossless jpeg decoder ported from RawSpeed library some years ago. Build LibRaw with RawSpeed to get fast decoding. * Fixed decoding error for some Canon sRAW files. * Disabled RawSpeed's bad pixel processing if RawSpeed used. * EOS M and EOS 70D added to unique Canon ID table * Canon EOS model name normalized by unique ID table * Backported 0.15.4 input data checks * Support for CMake builds * Updated RawSpeed supported camera list * Internals changed, so all code using LibRaw should be recompiled. * LibRaw 0.16.0-Alpha1 2013-05-23 Alex Tutubalin LibRaw 0.15-Release New camera/format support: * Adobe DNG: fast Load DNG (LightRoom 4.x), support for lossy-compressed DNG (LR 4.x, requires libjpeg 6+) * Canon: G1 X, SX220 HS, EOS 5D Mark III, EOS 650D, EOS 1D-X, 100D (Rebel SL1), 700D (Rebel T5i), 6D, EOS M, G15, S110, SX50 * Casio: EX-ZR100,EX-Z8 * Fujifilm: X-S1, HS30EXR, X1-Pro,X-E1, X20, X100S, SL1000, HS50EXR, F800EXR, XF1 * Leica: D-LUX6 and V-LUX4 * Nikon: D4, D3200, D800, D800E, 1 J2, 1 V2, D600, 1 J3, 1 S1, Coolpix A, Coolpix P330, Coolpix P7700, D7100 * Olympus: E-M5, XZ-2, XZ-10, E-PL5, E-PM2 * Panasonic: G5, G6, DMC-GF5, FZ200, GH3, LX7 * Pentax: MX-1, K-5 II, K-5 IIs, K-30, Q10 * Samsung: EX2F, NX20, NX210, support for the new firmware for NX100 * Sigma: SD15, SD1, SD1 Merill, DP1, DP1S, DP1X, DP2, DP2S, DP2X (only with Demosaic-pack-GPL2) * Sony: SLT-A58, RX-1, SLT-A99, NEX-5R, NEX-6, NEX-F3, SLT-A37, SLT-A57 * Multishot files: Imacon Ixpress 39Mpix API changes: 1. dcraw_process() can now be called several times with different parameters without re-opening and unpacking the file for second and consecutive calls to dcraw_process 2. deleted (nobody uses those) - LibRaw::dcraw_document_mode_processing (and respective C-API) - imgdata.color.color_flags data field 3. LibRaw::unpack() now decodes data into different buffers, the buffer depends on the raw data type - imgdata.rawdata.raw_image - 1 color component per pixel, for b/w and Bayer type sensors - imgdata.rawdata.color3_image - 3 color components per pixel, sRAW/mRAW files, RawSpeed decoding - imgdata.rawdata.color4_image - 4 components per pixel, the 4th component can be void 4. Support for compiling with RawSpeed library, http://rawstudio.org/blog/?p=800 details are in README.RawSpeed 5. Suppression of banding 6. New API calls - recycle_datastream(), - open_file(wchar_t*) (Win32) 2012-04-05 Alex Tutubalin * Casio EX-Z500 support * (possible) I/O exceptions on file open catched in open_datastream * Fixed possible read-after-buffer in Sony ARW2 decoder * Fixed mingw32 errors when compiling LibRaw_windows_datastream * Makefile.msvc: support of OpenMP and LCMS (uncomment to use) * Fixed decoding of some Leaf Aptus II files * LibRaw 0.14.6-Release 2011-12-24 Alex Tutubalin * Fixed bug (uninitialized variable) in SMAL format decoding. * Imported new dcraw 9.12 (1.446): support for Leica V-LUX 3, updated color data for Canon S100, Fujifilm X10, Nikon 1 J1/V1, Panasonic GX1, Samsung NX200, Sony NEX-7 * LibRaw 0.14.5-Release 2011-12-12 Alex Tutubalin * Fixes to Panasonic/Leica file parser to prevent crash on broken jpegs. * Fixes to include order in src/libraw_datastream.cpp to better compile with KDEWIN * Floating-point DNGs are rejected on early processing stage. * Support for new cameras: Canon S100, Fuji X10, Panasonic GX1, Samsung NX200, Sony NEX-7. * LibRaw 0.14.4-Release 2011-10-26 Alex Tutubalin * Bug fixes in black level subtraction code for PhaseOne files * New API call LibRaw::get_internal_data_pointer() for developers who need access to libraw_internal_data fields (i.e. Fuji SuperCCD layout). * doc/API-overview fixes to reflect 0.14 changes * LibRaw 0.14.3-Release 2011-10-19 Alex Tutubalin * Fixed bug in Canon 1D and 1Ds files decoding. * New decoder information bit DECODER_HASRAWCURVE * LibRaw 0.14.2-Release 2011-10-11 Alex Tutubalin * Imported dcraw 9.11/1.445: + Support for new cameras added: Fujifilm F600EXR, Nikon P7100, Olympus E-PL3 and E-PM1, Panasonic DMC-FZ150, Sony NEX-5N, A65 and A77. + Changed color data for: Olympus E-P3, Panasonic G3 and GF3, PhaseOne H25, P40 and P65, Sony NEX-C3, NEX-5, NEX-3, A35 and A55. + Support for dark frame extraction on Sony cameras. * DCB demosaicing: reserving 6 pixels instead of 3 to suppress colored image frame. * LibRaw 0.14.1-Release 2011-09-21 Alex Tutubalin * Cosmetic changes to make Visual C++/OpenMP more happy * Fix megapixel calculation for postprocessing_benchmark in half mode * Shlib version number increment * LibRaw 0.14.0-Release 2011-09-04 Alex Tutubalin * Fixed bug with Kodak thumbnail extraction * raw2image_ex() always return value * LibRaw 0.14.0-Beta2 2011-09-02 Alex Tutubalin * Cosmetic changes to LibRaw_file_datastream interface * OpenMP speedup of postprocessing steps (up to 50% for half mode and 4-core machine) * LibRaw 0.14.0-Beta1 2011-08-20 Alex Tutubalin * Patch to dcraw_emu for SunStudio compiler compatibility * Fixed crash in unprocessed_raw sample due to uninitialized timestamp variable. * Fixed crash in raw decoding if raw_width/raw_height is less than resulting image width/height. * imgdata.sizes.flip is set from user_flip only on postprocessing and/or adjust_sizes_info_only() * Fixed buffer overrun for some LJPEG-compressed files * Most of LibRaw_datastream function bodies are moved to separate source file * LibRaw_windows_datastream is merged to main sourcetree * LibRaw 0.14.0-Alpha5 2011-08-11 Alex Tutubalin * Imported dcraw 9.10 (1.444), support for new cameras added: ARRIRAW format, Canon SX30 IS, Leica D-LUX 5 and V-LUX2, Olympus E-P3, Panasonic G3 and GF3, Sony NEX-C3 and SLT-A35 * Support for RedOne digital movie cameras (R3D format). To enable this support you should: + install libjasper JPEG2000 support library + compile LibRaw with -DUSE_JASPER compiler switch (./configure will do it for you) + If you use own LibRaw_datastream implementation, you should implement make_jas_stream() call for your datastream. See bottom of src/libraw_cxx.cpp for implementations in datafile and mem-buffer LibRaw streams. * Bugfix: green matching is turned off if output image is shrinked due to wavelet filtering or aberration correction. * fixed open_file()/adjust_sizes_info_only() code path * Removed imgdata.sizes.bottom_margin and right_margin data fields use imgdata.sizes.raw_width - width - left_margin to get right one, the same with bottom_margin. * minor ./configure cleanup * Qmake files and Visual Studio Project files are updated. * New version check macros: For use at runtime checks: LIBRAW_RUNTIME_CHECK_VERSION_EXACT() - checks that runtime major/minor version numbers are same with compile-time values. LIBRAW_RUNTIME_CHECK_VERSION_NOTLESS() - checks that runtime version is not less that compile-time one. For use at compile-time in preprocessor directives: LIBRAW_COMPILE_CHECK_VERSION_EXACT(major,minor) - Compile-time check that LibRaw version is exact major.minor. LIBRAW_COMPILE_CHECK_VERSION_NOTLESS(major,minor) - Compile-time check that version is not less than major.minor. * all client code should be recompiled due to internals change. * LibRaw 0.14.0-Alpha4 2011-07-19 Alex Tutubalin * New sample samples/postprocessing_benchmark.cpp This sample measures postprocessing speed. All demosaic methods, averaged white balance, median filtering, wavelet filtration, highlight recovery, and cropping are supported. * Removed LibRaw::rotate_fuji_raw() call and corresponding C-API call. * The LibRaw::adjust_sizes_info_only() call may be called repeated and mixed with dcraw_process() call. * Postprocessing speedup and optimization, especially if cropping set. * Cropping works for FujiCCD raws. For the technical reasons, the position of top-left corner of crop area will be rounded to the nearest multiple of 4 (the corner is shifted top-left). * LibRaw 0.14.0-Alpha3 2011-07-15 Alex Tutubalin * imported cropping code from 0.13 branch 2011-07-12 Alex Tutubalin * samples/multirender_test - check for different clip settings 2011-07-11 Alex Tutubalin * New call LibRaw::free_image(), deallocates imgdata.image buffer. Use this call if current postprocessing results are not needed, but it is to early to call recycle() because dcraw_process() may be called later. * New C-API calls libraw_raw2image() - C API for LibRaw::raw2image() libraw_free_image() - C API for LibRaw::free_image() libraw_get_decoder_info() - C API for LibRaw::get_decoder_info() * Bugfix: change of params.user_flip aftee open()/unpack() calls should work. * LibRaw 0.14.0-Alpha2 2011-07-10 Alex Tutubalin * Multiple rendering (LibRaw::dcraw_process() calls) allowed without re-opening RAW file thrfough the sequence of open()/unpack() calls. You should be able to change any processing parameters (except shot_select parameter) between dcraw_process() calls. + New sample in samples/multirender_test.cpp: renders data 4 times: in half and full modes with different white balance settings. + Unprocessed RAW data is stored in separate data buffer: (2 bytes per pixel for all Bayer-pattern images, 8 bytes per pixel for Foveon, sRAW, and other full-color raw formats), so now LibRaw uses 25% more memory for full processing of most common Bayer images; while for just unpack memory is reduced 4 times. + New call LibRaw::raw2image() fills imgdata.image array with fresh copy of data. There is no need to call raw2image() separately if you use dcraw_process() or dcraw_document_mode_processing() calls. + New call LibRaw::get_decoder_info() to determine raw data storage layout. See samples/unprocessed_raw.cpp for an example of how to use it. If your code uses usual open()/unpack()/dcraw_process() call sequence, then NOTHING CHANGED: your program should produce same results. For interactive programs you may skip open()/unpack() calls after adjusting processing parameters, so user should see image refreshed much faster. If your code uses raw data (open+unpack calls), you need to call LibRaw::raw2image(), and imgdata.image will contain same bitmap as in LibRaw 0.13.x If you code uses access to masked borders data, you need to rewrite it. See samples/unprocessed_raw.cpp as a sample. Unfortunately, documentation is untouched yet. This problem will be fixed in next Alpha release. Other changes: * No separate imgdata.masked_pixels buffers, Bayer raw formats are read to buffer with borders. So, no ugly add_masked_border_to_bitmap() call. * No filtering_mode parameter. Raw tone curve is applied at unpack() stage; zero pixels removed on postprocesing stage. * unprocessed_raw and 4colors samples are adjusted to use new RAW data storage layout. * all client code should be recompiled due to internals change. * LibRaw 0.14.0-Alpha1 2011-07-03 Alex Tutubalin * Cosmetic cleanup in Libraw_memmgr code * Permit OpenMP support on MS VS2008 * More general mem_image interface: + New call get_mem_image_format returns bitmap size and bit depth + New call copy_mem_image can copy bitmap into buffer with different color order (RGB/BGR) and line stride + dcraw_make_mem_image() uses calls mentioned above + see documentation for info on these function parameters. * libraw/librawwindows.h implements LibRaw_datastream class based on Windows memory mapped files.Win32/64-only Thanks to Linc Brookes. * Fixed parallel make errors in configure/Makefile.am * LibRaw 0.13.6-Release 2011-05-18 Alex Tutubalin * Imported new dcraw 9.08/1.443: + New color data for Canon 600D and 1100D, Fuji S200EXR + New camera supported: Fuji HS20EXR and F550EXR, Kodak Z990, Nikon D5100, Olympus E-PL1s and XZ-1, Samsung NX11, Sony A230 and 290. * LibRaw 0.13.5-Release 2011-04-02 Alex Tutubalin * Imported new dcraw 9.07/1.442: + Support for Canon 600D and 1100D, Hasselblad H4D-60, Olympus E-PL2 * Color data for Leaf Aptus II and Canon Powershot S2 IS * LibRaw 0.13.4-Release 2011-03-30 Alex Tutubalin * Preliminary support for Leaf Aptus II cameras (no color data yet): Leaf Aptus II 6,7,8,10 and 12 are tested, Aptus II 5 should work. * Preliminary support for Fujifilm X100 camera (again, no color data). * Fixed possible after the end of buffer read when working with in-memory data. * Fixed possible loss of JPEG stream sync marks in LJPEG decoder (this bug was found only for Leaf Aptus II RAWs). * LibRaw 0.13.3-Release 2011-03-08 Alex Tutubalin * Fixed broken camera white balance reading for some Sony cameras * LibRaw 0.13.2-Release 2011-02-25 Alex Tutubalin * Sony A390 support (colordata from A380) * Leica D-LUX 4: fixed typo in camera name in colordata 2011-02-15 Alex Tutubalin * New -mem option for dcraw_emu: I/O via allocated buffer * Removed debug printf from LibRaw_memory_buffer code * Preliminary shared library support 2011-02-12 Alex Tutubalin * Added qmake .pro and Visual Studio 2008 sln/vcproj project files 2011-02-07 Alex Tutubalin * dcraw_emu documentation updated * ./configure stuff changed for correct linking on some systems * FBDD denoising is disabled for full-color images and 4-color bayer data (including forced 4-color via four_color_rgb option) * LibRaw 0.13.1-Release 2011-02-05 Alex Tutubalin * ./configure fixes for PACKAGE_REQUIRES * Makefile.msvc: correct compiler flags for demosaic packs * dcraw.c 9.06/1.440 imported: + New camera support: Canon S95, Casio EX-Z1080, Panasonic GF2 and GH2, Samsung NX100, Sony A-580 + New color data for: Canon G12, Nikon D3100, D7000 and P7000, Olympus E-5, Pentax K-r and K-5, Samsung NX10 and WB2000 * green_matching() code is disabled for half-size processing * LibRaw 0.13.0-Release 2011-01-15 Alex Tutubalin * Fallback to old huffman decoder for Sony files with unspecified data length (Sony A100) * Fixed incomplete data fields reset in LibRaw::recycle() * LibRaw 0.13.0-Beta3 2011-01-13 Alex Tutubalin * Better parsing of unknown command-line params in dcraw_emu sample * Brigtness table in ahd_demosaic is calculated in reversed order to prevent possible (very unlikely) multithreaded app problem. * New exposure correction code based on linear-cubic root combination. New working correction range is from 0.25 (-2 stops) to 8 (+3 stops) * LibRaw 0.13.0-Beta2 2011-01-10 Alex Tutubalin * Fixed file extension in half_mt.c sample 2011-01-10 Alex Tutubalin * Three patches provided by Jacques Desmis: - Exposure correction before demosaic (demosaic pack GPL3) - OpenMP speed-up in median filters (demosaic pack GPL2) - OpenMP speed-up in green equilibration (demosaic pack GPL3) * Merged 0.12.2-0.12.3 changes: - Patches for ./configure system for better LCMS2 support - Patches for ./configure system - math.h included before any other includes to make KDE compile with Visual C++ happy - Fuji FinePix S5500 size adjusted to ignore (rare?) garbage at top of frame. * all client code should be recompiled due to internals change. * LibRaw 0.13.0-Beta1 2010-12-22 Alex Tutubalin * Zero copy huffman buffer for LibRaw_buffer_datastream * Fixed memory leak in compressed NEFs handling * LibRaw 0.13.0-Alpha2 2010-12-20 Alex Tutubalin * Demosaic-pack-GPL3 changes: + New noise reduction methods before demosaic - Banding suppression - High-frequency noise suppression - Green channel equalization + New chromatic abberration correction. All three methods are written by Emil Martinec for Raw Therapee. Adapted to LibRaw by Jacques Desmis * Merged Foveon code fix from LibRaw 0.12.1 * LJPEG decompressor speed-up (about 1.5 times for Canon cameras and slightly less for others). Some ideas are from RawSpeed library. * all client code should be recompiled due to internals change. * LibRaw 0.13.0-Alpha1 2010-12-12 Alex Tutubalin * Thread-safe and demosaic packs support for MinGW build * Demosaic packs support for MS VC build * LibRaw 0.12.0-Release 2010-12-09 Alex Tutubalin * Fixed bug in add_masked_borders_to_bitmap() call for cameras with odd pixels border. * New command line options for unprocessed_raw sample: -B - subtract black level, -M - add masked pixels to bitmap. * Foveon-sensor cameras added to supported camera list if compiled with demosaic pack GPL2 * LibRaw 0.12.0-Beta4 2010-12-05 Alex Tutubalin * Demosaic packs support in Makefile.dist * Foveon support in LibRaw demosaic pack GPL2 * all client code should be recompiled due to internals change. * LibRaw 0.12.0-Beta3 2010-11-27 Alex Tutubalin * Fixed allocation bug in lmmse_interpolation (demosaic-pack-GPL2) * In LMMSE and AMaZE interpolators allocation changed to calloc to make valgrind happy with uninitialized values * Changes in distribution-making scripts * LibRaw 0.12.0-Beta2 2010-11-21 Alex Tutubalin * Fixes to green_matching code by Sergey Pavlov 2010-11-20 Alex Tutubalin * Update for new demosaic-pack-GPL3 * LibRaw 0.12.0-Beta1 2010-11-19 Alex Tutubalin * Demosaic pack(s) supported via ./configure 2010-11-17 Alex Tutubalin * LCMS2 support * afd_interpolate(2,1) instead of (5,0) * dcraw_emu sample command line keys added and reordered to reflect changes in LibRaw 0.12. * Nikon P7000: color matrix data and black level patch for ISO >=400 Thanks to Gunnar Thorburn * Support for several industrial cameras based on Sony ICX 625/655 sensor: JAI BB500CL/GE, SVS625CL, ptGrey GRAS-50S5C Thanks to kaare 2010-11-15 Alex Tutubalin * Several demosaic algorithms, found in other open-source RAW processing packages are implemented in LibRaw. 1) DCB demosaic and FBDD denoise by Jacek Gozdz are included in main LibRaw source. 2) GPL2 demosaic pack with these demosaic methods: * AFD and LMMSE implementations from PerfectRaw by Manuel Llorens * VCD, Modified AHD, post-demosaic refinemend and median filters by Paul Lee 3) GPL3 demosaic pack with AMaZe interpolation by Emil Martinec See more details in README.demosaic-packs * Current implementation of dcraw_emu sample allows only selection of demosaic method (via -q) options. All other parameters change will be implemented later. * LibRaw 0.12-alpha1 2010-11-11 Alex Tutubalin * Imported 0.11(2) version changes: + Fixed dcraw_emu command line processing code + OpenMP is completely disabled on MacOS X if compiled with -pthread due to well-known MacOS problem. + dcraw 9.05 (1.439) imported, many new cameras supported: Canon: G12, SX120, 60D, Hasselblad H4D, Nokia X2, Olympus E-5, Nikon: D3100, D7000, P7000, Panasonic: FZ40, FZ100, LX5, Pentax: K-r, K-5, 645D, Samsung GX20, WB2000 * LibRaw 0.12-alpha0 2010-11-08 Alex Tutubalin * Fixes for Sun Studio compiler compatibility * Fixes for Visual Studio 2010 compatibility * All russian-language files are converted to UTF-8 * LibRaw 0.11.0-Release 2010-10-18 Alex Tutubalin * Disabled OpenMP for wavelet_denoise under Mac OS X * More Visual C++ 2003 warnings cleaned in libraw/*h files * LibRaw 0.11-Beta7 2010-10-16 Alex Tutubalin * internal/dcraw_fileio.c can be compiled with -DDCRAW_VERBOSE again * fixed comment style in libraw_datastream.h * LibRaw 0.11-Beta6 2010-10-15 Alex Tutubalin * New changes to I/O layer. Three LibRaw_*datastream clasees are exists: + LibRaw_buffer_datastream - buffer reaging + LibRaw_file_datastream - file reading using iostreams (large files are no supported on some systems) + LibRaw_bigfile_datastream - FILE*-based file I/O * file/bigfile_datastream is selected automatically by LibRaw::open_file based on input file size. By default, files larger than 250Mb are opened using bigfile interface, you may change this behaviour by using second optional parameter of open_file() * There is no way to use default parameter values in C API, so new call libraw_open_file_ex added with two parameters (file name and minimal file size for bigfile_datastream use). * all client code should be recompiled due to internals change. * All LibRaw_abstract_datastream functions are virtual again. You may (again) use your own I/O layer. * new -d key for dcraw_emu sample: print timings of processing stages * simple_dcraw sample simplified: no mmap code * LibRaw 0.11-Beta5 2010-10-08 Alex Tutubalin * Fixed bug in exception handling in OpenMP sections in AHD interpolation code. * LibRaw_datastreams are now C++ iostreams based instead of old plain FILE* calls. LibRaw::open_file() in multithreaded programs are WAY faster on many OSes (Linux, Windows, MacOSX) because of no extra locks. * all client code should be recompiled due to internals change. * LibRaw 0.11-Beta4 2010-10-01 Alex Tutubalin * Fixed bug in LibRaw::dcraw_process() code: for half_size processing, params.four_color_rgb was set to 1 internally and not returned back after postprocessing. * Several Visual Studio 2003 compatibility fixes * AHD interpolation refactored. Now it is about 10% faster than dcraw in single-process mode and up to 1.5 times faster on 4-core and OpenMP (total execution time counted, not AHD itself) Thanks to Adam Hooper * AHD interpolation refactored. Now it is about 10% faster than dcraw in single-process mode and up to 1.5 times faster on 4-core and OpenMP (total execution time counted, not AHD itself) Thanks to Adam Hooper * LibRaw 0.11-Beta3 2010-09-07 Alex Tutubalin * Phase One files: LibRaw::unpack() sets colordata.black to approximately correct value. * Fixed minor error in setting colordata.maximum value for Phase One files. * LibRaw::subtract_black() sets colordata.black and colordata.cblack[] to zero to preserve data integrity. * LibRaw 0.11-Beta2 2010-09-04 Alex Tutubalin * It is now possible to crop output image on postprocessing stage (dcraw_process). Coordinates and size of the output box are set via imgdata.params.cropbox[4] parameter. Look into LibRaw documentation for more details. + New fatal error code LIBRAW_BAD_CROP + New dcraw_emu sample command line switch: -B x y w h (sets cropbox) Thanks to Patrick and Jan. * Processing pipeline has changed: the black level is subtracted from data on postprocessing stage either automatically (on dcraw_process() stage) or by special LibRaw API call: + New API calls: LibRaw::subtract_black() (C++ API) and libraw_subtract_black (C API). If you use dcraw_process() or dcraw_document_mode_processing() calls YOU DON'T NEED to call subtract_black() directly. + The raw preprocessing mode LIBRAW_FILTERING_NOBLACKS is deprecated and removed from LibRaw. * New ./configure script. Use ./configure -h for usage details. Thanks to Siddhesh Poyarekar * New API cals static LibRaw::dcraw_clear_mem() (C++ API) and libraw_dcraw_clear_mem(..) (C API). This calls are used to free memory, allocated by dcraw_make_mem_image() and dcraw_make_mem_thumb() instead of free() call. In some cases LibRaw and calling process have different memory managers, so free() of make_mem_image() data results to program crash (especially in Win32/VisualStudio enviroment). * LibRaw::free() is now private instead of public (again). * Minor changes and bugfixes: + Memory allocation exceptions (std::bad_alloc) are caught, so LibRaw API calls will return reasonable error codes instead of C++ exception (possibly unhandled). This problem is very unlikely to see in wild: if application cannot allocate small data for internal structure, it will always fail on allocation for RAW image data. + WIN32/VisualStudio 2008/2010: fopen,fscanf and sscanf calls in Libraw_datastream code are changed to *_s (secure) ones. + Debug print removed from fatal error handler. + Mmaped I/O for dcraw_emu sample is turned on via -E switch now (because old -B switch is used for settng cropbox). * all client code should be recompiled due to structures size change * LibRaw 0.11-Beta1 2010-07-31 Alex Tutubalin * dcraw 9.04 (1.438) imported: changes in tiff metadata parser, fixed a typo in Canon A720 model name * small patch in Sony ARW2 unpacking code to make valgrind happy * LibRaw 0.10.0-Beta3. 2010-07-05 Alex Tutubalin * dcraw 9.03 (1.437) imported: + New cameras: Canon SX20, Nikon D3s, Olympus E-P2, Panasoni DMC-GF1, Samsung EX1, Sony A450 + Color data changed for some cameras * LibRaw 0.10.0-Beta2. 2010-06-06 Alex Tutubalin * dcraw 9.01 (1.434) imported: + Separate black levels for each color channel. + New cameras: Canon 550D, Casio EX-Z1050, Fuji HS10/HS11, Kodak Z981, Panasonic G2 and G10, Phase One P65, Samsung NX-10 and WB550, Sony NEX-3 and NEX-5. + Fixed file descriptor leak in dark frame subtraction processing * Fixed dcraw 9.01's bug in DNG black level processing * Preliminary support for Sony A450 camera. * New command-line switch -h in mem_image sample (half_size support) * Some patches by Johannes Hanika (darktable author): + OpenMP speedup for PPG-interpolation + green_matching - suppress of 'color maze' on cameras with different green channel sensitivity. This option is turns on by filed with same name in imgdata.params * all client code should be recompiled due to structures size change * LibRaw::free() is now public instead of private. * LibRaw 0.10.0-Beta1. 2010-05-15 Alex Tutubalin * Fixed bug in 8-bit RAW processing code * LibRaw 0.9.1-Release 2010-04-26 Alex Tutubalin * OpenMP support: OpenMP is possible under MinGW (untested) * LibRaw 0.9.0-Release 2010-04-21 Alex Tutubalin * Finally fixed inconsistency in Fuji files processing * New COLOR(row,col) call to get bayer color index in image[] array * Old FC() call is deprecated and will be removed in future releases * unprocessed_raw sample switched to COLOR() call * LibRaw 0.9.0-Beta5 2010-04-10 Alex Tutubalin * Fixed bug in unpacking DNG files made from Fuji RAFs. * LibRaw 0.9.0-Beta4 2010-04-09 Alex Tutubalin * Fixed typecast error (problem reported only on gcc 4.2.1/32bit) in CRW files processing. * C++ API call LibRaw::adjust_maximum() is now deprecated and de-documented, use params.adjust_maximum_thr instead (on by default) * C-API call libraw_adjust_maximum() removed. * New postprocessing parameter params.adjust_maximum_thr This parameter replaces LibRaw::adjust_maximum(), but more flexible Defaults are reasonable (0.75, same as in old adjust_maximum), look into documentation for more details. * Removed last OpenMP warning * dcraw_emu's -c parameter now wants numeric (float) argument. This value is assigned to params.adjust_maximum_thr. Use -c 0.0 for dcraw compatibility. * all client code should be recompiled due to structures size change * LibRaw 0.9.0-Beta3 2010-03-29 Alex Tutubalin * Fixed a bug in channel_maximum[] calculation for Panasonic cameras. * channel_maximum[] data now calculated for ALL cameras. * OpenMP warnings suppressed. * Documented the -c command-line switch for dcraw_emu sample. * Removed extra messages from dcraw_emu sample. * LibRaw 0.9.0-Beta2 2010-03-28 Alex Tutubalin New licensing: * Triple licensing (selected by LibRaw user): + LGPL 2.1 (http://www.gnu.org/licenses/lgpl-2.1.html) + CDDL 1.0 (http://www.opensource.org/licenses/cddl1.txt) + LibRaw Software License (27 March 2010 version) (http://www.libraw.org/data/LICENSE.LibRaw.pdf) * There is no separate LibRaw-Lite and LibRaw-Commercial versions, only single LibRaw. Current LibRaw-Lite and LibRaw-Commercial users should switch to LibRaw without loss of functionality. It is possible to change licensig too (e.g. from LGPL to CDDL for LibRaw-Lite users and from LibRaw License to LGPL or CDDL for LibRaw-Commercial users). * No Foveon support :( It is not possible to get good color from Foveon sensors with *any* converter. So, there is no need to support these cameras. Dcraw's Foveon-processing code is too strict licensed (GPL), so we choose to drop it. New Features: * New data field colordata.channel_maximum[4] - per channel data maximum (calculated for most cameras, 0 for others). * New call LibRaw::adjust_maximum() (and libraw_adjust_maximum() in C API). This call changes hardcoded colordata.maximum value to calculated at unpack stage. This helps suppress false color in highlights (magenta clouds and so). * New command line parameter -c for dcraw_emu sample. Calls adjust_maximum() for each processed file. * all client code should be recompiled due to structures size change * LibRaw 0.9.0-Beta1 2010-02-06 Alex Tutubalin * Fixed ambiguity in pow/sqrt calls (to make Sun C++ compiler happy) * OpenMP is not supported under MS Visual Studio * Masked a bug in RIFF format parser * LibRaw 0.8.6 2009-12-30 Alex Tutubalin * Fixed bug in simple_dcraw sample parameters processing * Imported dcraw 8.99 (1.432): + New cameras: Canon: 1D mk IV, Canon S90; Casio Z750, Nikon D3S, Pentax K-x, Sony A-500/550, Fuji S200EXR + New color data for Canon G11 and Sony A850 + Changes in Canon sRAW processing + Changes in Kodak metadata processing + Changes in uncompressed Fuji files processing (FinePix S5xxx) * LibRaw 0.8.5 2009-11-21 Alex Tutubalin + Fixed a bug in processing of uncompressed Phase One files * LibRaw 0.8.4 2009-10-24 Alex Tutubalin + Imported dcraw 8.98/1.431: * New Cameras: Canon 7D, Panasonic GF1, Sony A850 and A380, Casio Z850, Nikon D300s + changes in libraw_datastream.h to make compilers more happy * LibRaw 0.8.3 2009-09-02 Alex Tutubalin + Fixed bug in Hasselblad .3FR unpacking code * Imported dcraw 8.97/1.428: Nikon D3000 image width fix * LibRaw 0.8.2 2009-08-31 Alex Tutubalin + Enum LibRaw_thumbnail_formats (LIBRAW_IMAGE_*) values changed to match values in enum LibRaw_image_formats (LIBRAW_THUMBNAIL_*). You need to recompile all sources using these constants. 2009-08-30 Alex Tutubalin * Imported dcraw 8.97/1.427: + new cameras: Canon A470, Canon G11 (without color data), Nikon D3000, Olympus E-P1, Panasonic DMC-FZ35/FZ38 + some changes in decoding code. * Fixes for Microsoft Visual C++ 6.0 compatibility * C-API dcraw_make_mem_thumb() call finally exported in API * LibRaw 0.8.1 2009-08-24 Alex Tutubalin * Imported dcraw 8.96/1.426 + New cameras: Casio EX-Z60 and EX-Z75, Kodak Z980, Nikon D5000, Olympus X200, D560Z,C350Z,E620, Pentax K7, Sony A330. + New color data for many cameras + Generalized unpacker code for Canon and Casio P&S cameras * LibRaw 0.8.0-Release 2009-08-13 Alex Tutubalin * RAW files larger than 2Gb are supported on: - Unix (all supported: FreeBSD, MacOS X, Linux) - Windows (with C runtime version >= 8.0) * bzero replaced with memset to make Solaris users happy * All applications on 32-bit systems should be recompiled due to data structures size changes. * Minor fixes in windows makefile * LibRaw 0.8.0-Beta5 2009-07-21 Alex Tutubalin * Imported dcraw 8.95 (1.425): + new huffman tree code + New cameras supported: AGFAPHOTO DC-833m, Casio EX-S20, Phase One P65, Samsung S850 + Removed hardcoded white-balance data for many P&S cameras. It is recommended to set params.use_camera_wb to 1 for safe WB. * Fixes for Nikon D5000 files: no pink stripe at right side of frame * C-wrapper: added missed calls libraw_dcraw_make_mem_image libraw_dcraw_ make_mem_thumb * Minor fixes to make non-gcc compilers more happy * Internal structures changed, full recompilation of all client code is needed. * LibRaw 0.8.0-Beta4 2009-06-08 Alex Tutubalin * Fixes: gamma curve processing was not performed in dcraw_write_mem_image() * Fixes: gamma curve processing was not performed for Kodak thumbnails * LibRaw 0.8.0-Beta3 2009-06-05 Alex Tutubalin * Fixes in documentation: params.gamm[] described more precisely * Fixes in version number, 0.8-beta1 was mistakenly 0.0.0-beta1 * LibRaw 0.8.0-Beta2 2009-06-04 Alex Tutubalin * Imported dcraw 8.94 (1.423): + New camera support: Canon: SX1, 500D/Rebel T1i, A570, A590, SX110 Kodak Z1015, Motorola PIXL, Olympus E30, Panasonic DMC-GH1 + Improved color data for Nikon D3X + New gamma curve model + Many changes in RAW unpacking code + Canon cameras: black level is not subtracted if set params.document_mode > 1 * API changed: params.gamma_16bit field removed. Gamma curve is set via params.gamm[0]/gamm[1] values (see documentation and samples for details) * LibRaw::identify() splitted to avoid MS VS2008 bug (too many nested blocks) * Samples: dcraw_emu and mem_image samples supports new dcraw 16bit/gamma semantics: -6: set 16 bit output -4: set 16 bit output and linear gamma curve and no auto brighness * LibRaw 0.8.0-Beta1 2009-04-28 Alex Tutubalin * Identify sample renamed to raw-identify (name conflict with ImageMagic) * Copyright notice changes * Many compiler warnings removed 2009-04-07 Alex Tutubalin * More accurate types conversion in libraw_datastream.h * New postprocessing parameter auto_bright_thr: set portion of clipped pixels for auto brightening code (instead of dcraw-derived hardcoded 1%) * -U option for dcraw_emu sample sets auto_bright_thr parameter * all client code should be recompiled due to structures size change * LibRaw 0.7.2-Release 2009-03-22 Alex Tutubalin * Fixed typo in OpenMP support code * MinGW support * dcraw source is included in distribution * LibRaw 0.7.1-Release 2009-03-15 Alex Tutubalin * Fuji SuperCCD RAWs: color channels unshuffled on RAW read stage (moved from postprocessing stage) * LibRaw 0.7.0-Release 2009-03-13 Alex Tutubalin * dcraw 8.93/1.421 imported: + more accurate pentax dSLR support + fixes in Kodak 620x/720x identification + faster identification procedure for some formats. * LibRaw 0.7.0-Beta5 2009-03-08 Alex Tutubalin * dcraw 8.92/1.420 imported: + user-specified gamma curve + Pentax K2000/Km support + Changes in Canon sRAW processing (support for 5D2 fw 1.07) * all client code should be recompiled * LibRaw 0.7.0-Beta4 2009-02-13 Alex Tutubalin * bugfix: 4channels sample finally subtracts black by default * dcraw 8.91/1.419 imported: + fixes in RIFF files parsing * LibRaw 0.7.0-Beta3 2009-02-12 Alex Tutubalin * Black level was not calculated for Canon RAWs in some filtering modes * 4channels sample prints calculated black level (scaled if autoscaling used). Also output file names for this sample now includes color channel name (R/G/B/G2 or C/M/Y/G) * LibRaw 0.7.0-Beta2 2009-02-09 Alex Tutubalin * New sample 4channels: splits RAW color channels into four separate TIFFs * LibRaw 0.7.0-Beta1 2009-02-07 Alex Tutubalin * Fixed bug in external jpeg metadata reading code. * Cleaned some C++ warnings * dcraw 8.91/1.418 imported + Hasselblad V96C support * You need to clean and recompile client code which uses LibRaw_*_datastream classes. * LibRaw 0.7.0-Alpha6 2009-01-30 Alex Tutubalin * New data input framework is created. It is possible now to easyly implement your own data input interface for LibRaw (e.g. for reading RAW data from network data stream) * All older programs using previous LibRaw versions are compatible at source code level. * LibRaw can read RAW data from memory buffer via new LibRaw::open_buffer() API call (implemented on top of new input framework). This call used in sample application dcraw_emu and simple_dcraw (with -B command-line switch) to test new API. * Error handling callback functions now can be called with NULL filename passed (if underlying data stream object does not know file name). So, client error handling callbacks should work with NULL filename. * All client code should be recompiled * Imported dcraw 8.90/1.417: + Support for loading White Balance data from Sony ARW files edited with Sony IDC software. * LibRaw 0.7.0-Alpha5 2009-01-17 Alex Tutubalin * Raw filtering mode LIBRAW_FILTERING_NOPOSTPROCESS has renamed to LIBRAW_FILTERING_NORAWCURVE for better reflect its purpose. This filtering_mode bit turns off tone curve applying on RAW data on bayer-pattern cameras with raw tone curve: + Adobe DNG (only RAW with bayer pattern) + Nikon compressed NEF + Some Kodak cameras + Sony A700/A900 (tone curve applied to 8-bit raws) * unprocessed_raw sample: added command-line key -N, this key turns on LIBRAW_FILTERING_NORAWCURVE filtering mode. * New scheme of Fuji RAW processing (introduced in 0.7-Alpha3) supports DNG files generated from Fuji RAF. * Imported dcraw 8.90/1.416: + better support for Samsung S85 + fixed possible integer overflow in wavelet denoising code * LibRaw 0.7.0-Alpha4 2009-01-14 Alex Tutubalin * Black mask extraction supported for all files with bayer data (one component per pixel). Black mask data not avaliable for multi-component data (Foveon, Canon sRAW, Sinar 4-shot, Kodak YCC/YRGB). * Black level subtraction can be turned off for all bayer cameras (added support for PhaseOne backs). * Fujifilm camera processing model changed: + RAW data is extracted without 45-degree rotation + dcraw-compatible rotation is performed on postptocessing stage + it is possible to rotate RAW data without postprocessing by LibRaw::rotate_fuji_raw() call. * New filtering mode setting: LIBRAW_FILTERING_NOPOSTPROCESS This bits turns off RAW tone curve processing based on tone curve readed from RAW metadata. This mode supported only for PhaseOne backs now (to be supported on all relevant cameras in nearest future releases) * Black level data (got from RAW data) are stored for PhaseOne backs. * Black level subtraction bug (derived from dcraw) fixed for PhaseOne files. * Fixed processing of -s parameter for dcraw_emu sample * Parameter -s N (select shot number) added to unprocessed_raw sample. * Imported dcraw 8.90/1.414: + changes in QuickTake 100 metadata processing + changes in external jpeg processing code + Samsung S85 support * All client code should be recompiled * LibRaw 0.7.0-Alpha3 released 2009-01-10 Alex Tutubalin * Fixed bug in add_masked_borders: crash if output dimensions is already larger than raw dimensions * Fixed out of bounds in samples/unprocessed_raw.cpp for files with non-square pixels * LibRaw 0.7.0-Alpha2 released 2009-01-08 Alex Tutubalin * Fixed bug in 0.7.0-a0: black frame size has not reset, so in batch processing there is an error in black frame size for files without black frame. * Implemented reading of black/masked pixels data for near all cameras with masked pixels, exclding: + Canon sRAW, Leaf (MOS), Sinar 4-shot - more than one color component in black frame (redesign of black frame data structures required). + Fuji SuperCCD: need to design right methods of extraction (should we rotate and resize black pixels as active ones??) * Tested for most dSLR data formats with masked pixels: 7 of 9 untested formats are from old P&S cameras. * New call LibRaw::unpack_function_name() returns unpack function name (useful for testers only) * New identify sample parameters (useful for test-suite builders to check test coverage): -u - print unpack function name -f - print masked frame size These parameters works only for identify run without -v parameter * Imported dcraw 8.89/1.411 + changes in Panasonic FZ50 files parsing * LibRaw 0.7.0-Alpha1 released 2009-01-05 Alex Tutubalin * It is possible to turn off RAW data filtration (black level subtraction, zero pixels averaging): + supported on all cameras except Foveon and Phase One + filtraction controlled by new parameter "filtering_mode" + it is possible to expand API by filtering procedures built for specific camera model. * Black border (masked pixels) extraction: + API (data structures) for storing black mask. + Black mask extraction supported only for limited list of data formats: - Canon .CRW, .CR2 (with exception of sRAW),A600, A5 - Adobe DNG (both converted RAW and native DNG) - Nikon NEF (compressed only) this list to be expanded in future LibRaw versions * New call add_masked_borders_to_bitmap makes full bitmap 'masked border' + image * Usage sample for functionality listed above: samples/unprocessed_raw * Imported dcraw 8.89/1.410: + fixed bugs in Hasselblad .fff decoding + fixes in Imacon metadata decoding * Documentation changes * All client code should be recompiled * LibRaw 0.7.0-Alpha0 2009-01-01 Alex Tutubalin * Fixed a bug (filedescriptor and buffer memory leak) in thumbnail extraction when called before metadata analysis. Thanks to Albert Astalis Cid. * LibRaw 0.6.4 Release 2008-12-11 Alex Tutubalin * Imported new edition of dcraw 8.89 (version 1.409) * Nikon NEF decoding changed * LibRaw 0.6.3 Release 2008-12-03 Alex Tutubalin * fixed bug in Panasonic .RW2 processing (only for thread-safe version, single-threaded version was not affected) * All client code should be recompiled * LibRaw 0.6.2 Release 2008-12-03 Alex Tutubalin * Imported dcraw 8.89 (version 1.407) * New cameras: Canon G10 & 5D Mk2, Leaf AFi 7, Leica D-LUX4, Panasonic FX150 & G1, Fujifilm IS Pro, * Changed camera support (color conversion tables): Canon 50D, Nikon D90 & P6000, Panasonic LX3 & FZ28, Sony A900 * LibRaw 0.6.2 beta 2008-09-25 Alex Tutubalin * Added new data field float LibRaw::imgdata.color.cam_xyz[4][3]. This field contains constant table (different for each camera) for Camera RGB->XYZ conversion. * All client code should be recompiled * LibRaw 0.6.1 Release 2008-09-18 Alex Tutubalin * dcraw 8.88 imported: - new cameras (Canon 50D, Sony A900, Nikon D90 & P6000, Panasonic LX3 FZ28) - new method of black point subtraction for Canon cameras, preliminary banding supression. * Stack memory usage lowered (some thread data moved to dynamic memory) * some patches for MSVC compatibility * LibRaw 0.6.0 Release 2008-09-16 Alex Tutubalin * Enum definitions changed to make gcc -pedantic happy * Compiler/preprocessor flags does not affects LibRaw class field set (i.e. structure for thread local storage is always allocated) * Default library compilation mode (i.e. sources imported in another project) is thread-safe 2008-09-14 Alex Tutubalin * OpenMP support for most CPU consuming steps of processing: ahd_interpolation. wavelet_denoise 10-30% speed-up of full processing pipe on 2-core CPU OpenMP supported only on gcc (Linux/FreeBSD and Mac OS X) * LibRaw 0.6.0-Beta-1 2008-09-10 Alex Tutubalin * All set_**handler accepts additional void* pointer, which should point to callback private data. This pointer passed to user callback when it called. * LibRaw 0.6.0-alpha5 * All client code should be recompiled 2008-09-10 Alex Tutubalin * New processing stages in enum LibRaw_progress: LIBRAW_PROGRESS_BAD_PIXELS LIBRAW_PROGRESS_DARK_FRAME (reserved stages LIBRAW_PROGRESS_RESERVED_PRE1-PRE2 has removed) * libraw_strprogress() - convert progress code into string * Added progress/cancellation user callbacks + new fatal error code: CANCELLED_BY_CALLBACK + sample usage in samples/dcraw_emu.cpp (try run it with -v -v -v opts) * LibRaw 0.6.0-alpha4 * All client code should be recompiled 2008-09-08 Alex Tutubalin * ICC-profiles support (same as in dcraw) + input/output profiles (specified as path to 'icc' file or 'embed' for embedded input profile) + additional warnings + LCMS library used * support of bad pixel map (caller should specify path to bad pixel file in dcraw-compatible format) * dark frame subtraction support (caller should supply path to 16-bit PGM map). samples/simple_dcraw.cpp - -4 option added for dark frame file generation * support of bad pixeld map (dcraw-compatible format) * the dcraw_emu sample supports all new features (ICC, dark frame, bad pixels) * libraw/libraw_version.h, defines, calls and macros for version checks: + LibRaw::version(), LibRaw::versionNumber(), LIBRAW_CHECK_VERSION() * List of supported cameras: + LibRaw::cameraCount() + LibRaw::cameraList() * fixed error in adjust_sizes_info_only * documentation changes * LibRaw 0.6.0-alpha3 2008-09-07 Alex Tutubalin * samples/mem_image.c - bitwise equal output with dcraw -4 (PPMs outputted with network byte order) * LibRaw 0.6.0-alpha2 2008-09-06 Alex Tutubalin * Added calls dcraw_make_mem_image and dcraw_make_mem_image: + functions (and supporting code) + documentation changed + new sample code samples/mem_image.cpp * Added processing parameter LibRaw::imgdata.params.gamma_16bit (set to 1 to make gamma correction for 16-bit output) * LibRaw 0.6.0-alpha1 2008-08-28 Alex Tutubalin * dcraw 1.404 (8.87) imported: - 6 new cameras supported (Canon 1000D, A720, SD300; Nikon D700, Oly E-520,Kodak C603) * Licensing changed to GPL v2 2008-05-02 Alex Tutubalin * mmap/malloc+read IO-layer removed due to no performance gain. FILE I/O returned 2008-05-02 Alex Tutubalin * dcraw 1.403 imported - changes in ljpeg decompression (index values cut to 12 bit) - changes in parse_foveon() jpeg thumbnail extraction * LibRaw 0.5.3 released 2008-04-24 Alex Tutubalin * Linux build of samples/identify fixed * documentation editorial * LibRaw 0.5.2 released 2008-04-21 Alex Tutubalin * All documentation translated to English * English changelog started :) * minor bug (include path) fixed in samples/half_mt * LibRaw 0.5.1 released LibRaw-0.18.8/DEVELOPER-NOTES000066400000000000000000000030431324423227700151340ustar00rootroot00000000000000 === Notes for LibRaw contributor === 0. Repository LibRaw public repository is located on GitHub URL: http://github.com/LibRaw/LibRaw - main page git://github.com/LibRaw/LibRaw.git - git URL If you wish to participate in LibRaw development please use GitHub fork. 1. Some files in internal/ folder are generated from dcraw/dcraw.c file by simple preprocessor internal/preprocess.pl (you need perl to run it) dcraw/dcraw.c is a *patched* dcraw (and foveon processng code is removed due to copyright). 'Official' dcraw.c changes are tracked by LibRaw team and merged to head revision at regular basis. So, if you want to change code in internal/*.cpp files you need to change dcraw/dcraw.c (and run make) 2. For developer's work use Makefile from GitHub It contains rules to re-generate internal/*cpp from dcraw/dcraw.c 3. LibRaw distribution files are prepared by ./mkdist.sh script This script - regenerates internal/*cpp without #line directives - generates ./configure script from autotools stuff - removes developer Makefile - fetches 'Official' dcraw.c from Dave Coffin's site - removes .PSD files from doc/ - removes itself 3. Please do not use ./configure script in development enviroment. This script generates Makefile from ./Makefile.in for use in production. The generated Makefile does not contain section to build internal/* from dcraw/dcraw.c Feel free to contact us (info@libraw.org or Contact form on www.libraw.org) if you have any questions or suggestions. LibRaw-0.18.8/INSTALL000066400000000000000000000041531324423227700140320ustar00rootroot00000000000000 ========= Installing LibRaw ======== I. Installation steps 1. Unpack the distribution file: $ tar xzvf LibRaw-0.xx.yy.tar.gz 2. If you wish to use LibRaw demosaic pack(s), unpack them in the same folder: $ tar xzvf LibRaw-demosaic-pack-GPL2-0.xx.yy.tar.gz $ tar xzvf LibRaw-demosaic-pack-GPL3-0.xx.yy.tar.gz 3. Go to LibRaw folder and run ./configure and make: $ cd LibRaw-0.xx.yy $ ./configure [...optional args...] $ make 4. install by run make install as root: $ sudo make install II. ./configure options --enable-openmp --disable-openmp Enable/disable OpenMP support if compiler supports it. OpenMP is enabled by default. --enable-lcms --disable-lcms Enable/disable LCMS color engine support. If enabled, ./configure will try to find lcms library. Both LCMS-1.x and LCMS-2.x are supported LCMS support is enabled by default --enable-examples --disable-examples Enables/disables examples compilation and installation. Enabled by default --enable-demosaic-pack-gpl2 --enable-demosaic-pack-gpl2=FOLDERNAME --enable-demosaic-pack-gpl2=no --disable-demosaic-pack-gpl2 Enables/disables support of additional demosaic methods licensed under GPL2 You need to download and unpack LibRaw-demosaic-pack-GPL2 archive to use this feature. ./configure will try to find demosaic pack in: a) If folder is specified via --enable-demosaic-pack-gpl2=FOLDERNAME command-line option, then only this folder will be checked. b) If no folder is specified in --enable-demosaic-pack-gpl2 switch: ./LibRaw-demosaic-pack-GPL2 (in LibRaw folder) ../LibRaw-demosaic-pack*GPL2* - upper level folder If several ../LibRaw-demosaic-pack*GPL2* folders exists in upper level catalog, then ./configure will NOT use any of them due of ambiguity. Specify exact folder name in this case using --enable-demosaic-pack-gpl2=FOLDERNAME --enable-demosaic-pack-gpl3 --enable-demosaic-pack-gpl3=FOLDERNAME --enable-demosaic-pack-gpl3=no --disable-demosaic-pack-gpl3 Same as above, but for GPL3-licensed demosaic pack. LibRaw-0.18.8/LICENSE.CDDL000077500000000000000000000410121324423227700145110ustar00rootroot00000000000000COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 1. Definitions. 1.1. Contributor means each individual or entity that creates or contributes to the creation of Modifications. 1.2. Contributor Version means the combination of the Original Software, prior Modifications used by a Contributor (if any), and the Modifications made by that particular Contributor. 1.3. Covered Software means (a) the Original Software, or (b) Modifications, or (c) the combination of files containing Original Software with files containing Modifications, in each case including portions thereof. 1.4. Executable means the Covered Software in any form other than Source Code. 1.5. Initial Developer means the individual or entity that first makes Original Software available under this License. 1.6. Larger Workmeans a work which combines Covered Software or portions thereof with code not governed by the terms of this License. 1.7. License means this document. 1.8. Licensable means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently acquired, any and all of the rights conveyed herein. 1.9. Modifications means the Source Code and Executable form of any of the following: A. Any file that results from an addition to, deletion from or modification of the contents of a file containing Original Software or previous Modifications; B. Any new file that contains any part of the Original Software or previous Modification; or C. Any new file that is contributed or otherwise made available under the terms of this License. 1.10. Original Software means the Source Code and Executable form of computer software code that is originally released under this License. 1.11. Patent Claims means any patent claim(s), now owned or hereafter acquired, including without limitation, method, process, and apparatus claims, in any patent Licensable by grantor. 1.12. Source Code means (a) the common form of computer software code in which modifications are made and (b) associated documentation included in or with such code. 1.13. You (or Your) means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, You includes any entity which controls, is controlled by, or is under common control with You. For purposes of this definition, control means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. License Grants. 2.1. The Initial Developer Grant. Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, the Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license: (a) under intellectual property rights (other than patent or trademark) Licensable by Initial Developer, to use, reproduce, modify, display, perform, sublicense and distribute the Original Software (or portions thereof), with or without Modifications, and/or as part of a Larger Work; and (b) under Patent Claims infringed by the making, using or selling of Original Software, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Software (or portions thereof); (c) The licenses granted in Sections 2.1(a) and (b) are effective on the date Initial Developer first distributes or otherwise makes the Original Software available to a third party under the terms of this License; (d) Notwithstanding Section 2.1(b) above, no patent license is granted: (1) for code that You delete from the Original Software, or (2) for infringements caused by: (i) the modification of the Original Software, or (ii) the combination of the Original Software with other software or devices. 2.2. Contributor Grant. Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: (a) under intellectual property rights (other than patent or trademark) Licensable by Contributor to use, reproduce, modify, display, perform, sublicense and distribute the Modifications created by such Contributor (or portions thereof), either on an unmodified basis, with other Modifications, as Covered Software and/or as part of a Larger Work; and (b) under Patent Claims infringed by the making, using, or selling of Modifications made by that Contributor either alone and/or in combination with its Contributor Version (or portions of such combination), to make, use, sell, offer for sale, have made, and/or otherwise dispose of: (1) Modifications made by that Contributor (or portions thereof); and (2) the combination of Modifications made by that Contributor with its Contributor Version (or portions of such combination). (c) The licenses granted in Sections 2.2(a) and 2.2(b) areeffective on the date Contributor first distributes or otherwise makes the Modifications available to a third party. (d) Notwithstanding Section 2.2(b) above, no patent license is granted: (1) for any code that Contributor has deleted from the Contributor Version; (2) for infringements caused by: (i) third party modifications of Contributor Version, or (ii) the combination of Modifications made by that Contributor with other software (except as part of the Contributor Version) or other devices; or (3) under Patent Claims infringed by Covered Software in the absence of Modifications made by that Contributor. 3. Distribution Obligations. 3.1. Availability of Source Code. Any Covered Software that You distribute or otherwise make available in Executable form must also be made available in Source Code form and that Source Code form must be distributed only under the terms of this License. You must include a copy of this License with every copy of the Source Code form of the Covered Software You distribute or otherwise make available. You must inform recipients of any such Covered Software in Executable form as to how they can obtain such Covered Software in Source Code form in a reasonable manner on or through a medium customarily used for software exchange. 3.2. Modifications. The Modifications that You create or to which You contribute are governed by the terms of this License. You represent that You believe Your Modifications are Your original creation(s) and/or You have sufficient rights to grant the rights conveyed by this License. 3.3. Required Notices. You must include a notice in each of Your Modifications that identifies You as the Contributor of the Modification. You may not remove or alter any copyright, patent or trademark notices contained within the Covered Software, or any notices of licensing or any descriptive text giving attribution to any Contributor or the Initial Developer. 3.4. Application of Additional Terms. You may not offer or impose any terms on any Covered Software in Source Code form that alters or restricts the applicable version of this License or the recipients rights hereunder. You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, you may do so only on Your own behalf, and not on behalf of the Initial Developer or any Contributor. You must make it absolutely clear that any such warranty, support, indemnity or liability obligation is offered by You alone, and You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of warranty, support, indemnity or liability terms You offer. 3.5. Distribution of Executable Versions. You may distribute the Executable form of the Covered Software under the terms of this License or under the terms of a license of Your choice, which may contain terms different from this License, provided that You are in compliance with the terms of this License and that the license for the Executable form does not attempt to limit or alter the recipients rights in the Source Code form from the rights set forth in this License. If You distribute the Covered Software in Executable form under a different license, You must make it absolutely clear that any terms which differ from this License are offered by You alone, not by the Initial Developer or Contributor. You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of any such terms You offer. 3.6. Larger Works. You may create a Larger Work by combining Covered Software with other code not governed by the terms of this License and distribute the Larger Work as a single product. In such a case, You must make sure the requirements of this License are fulfilled for the Covered Software. 4. Versions of the License. 4.1. New Versions. Sun Microsystems, Inc. is the initial license steward and may publish revised and/or new versions of this License from time to time. Each version will be given a distinguishing version number. Except as provided in Section 4.3, no one other than the license steward has the right to modify this License. 4.2. Effect of New Versions. You may always continue to use, distribute or otherwise make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. If the Initial Developer includes a notice in the Original Software prohibiting it from being distributed or otherwise made available under any subsequent version of the License, You must distribute and make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. Otherwise, You may also choose to use, distribute or otherwise make the Covered Software available under the terms of any subsequent version of the License published by the license steward. 4.3. Modified Versions. When You are an Initial Developer and You want to create a new license for Your Original Software, You may create and use a modified version of this License if You: (a) rename the license and remove any references to the name of the license steward (except to note that the license differs from this License); and (b) otherwise make it clear that the license contains terms which differ from this License. 5. DISCLAIMER OF WARRANTY. COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN AS IS BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. 6. TERMINATION. 6.1. This License and the rights granted hereunder will terminate automatically if You fail to comply with terms herein and fail to cure such breach within 30 days of becoming aware of the breach. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive. 6.2. If You assert a patent infringement claim (excluding declaratory judgment actions) against Initial Developer or a Contributor (the Initial Developer or Contributor against whom You assert such claim is referred to as Participant) alleging that the Participant Software (meaning the Contributor Version where the Participant is a Contributor or the Original Software where the Participant is the Initial Developer) directly or indirectly infringes any patent, then any and all rights granted directly or indirectly to You by such Participant, the Initial Developer (if the Initial Developer is not the Participant) and all Contributors under Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice from Participant terminate prospectively and automatically at the expiration of such 60 day notice period, unless if within such 60 day period You withdraw Your claim with respect to the Participant Software against such Participant either unilaterally or pursuant to a written agreement with Participant. 6.3. In the event of termination under Sections 6.1 or 6.2 above, all end user licenses that have been validly granted by You or any distributor hereunder prior to termination (excluding licenses granted to You by any distributor) shall survive termination. 7. LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOST PROFITS, LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH PARTYS NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. 8. U.S. GOVERNMENT END USERS. The Covered Software is a commercial item, as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of commercial computer software (as that term is defined at 48 C.F.R. 252.227-7014(a)(1)) and commercial computer software documentation as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government End Users acquire Covered Software with only those rights set forth herein. This U.S. Government Rights clause is in lieu of, and supersedes, any other FAR, DFAR, or other clause or provision that addresses Government rights in computer software under this License. 9. MISCELLANEOUS. This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. This License shall be governed by the law of the jurisdiction specified in a notice contained within the Original Software (except to the extent applicable law, if any, provides otherwise), excluding such jurisdictions conflict-of-law provisions. Any litigation relating to this License shall be subject to the jurisdiction of the courts located in the jurisdiction and venue specified in a notice contained within the Original Software, with the losing party responsible for costs, including, without limitation, court costs and reasonable attorneys fees and expenses. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not apply to this License. You agree that You alone are responsible for compliance with the United States export administration regulations (and the export control laws and regulation of any other countries) when You use, distribute or otherwise make available any Covered Software. 10. RESPONSIBILITY FOR CLAIMS. As between Initial Developer and the Contributors, each party is responsible for claims and damages arising, directly or indirectly, out of its utilization of rights under this License and You agree to work with Initial Developer and Contributors to distribute such responsibility on an equitable basis. Nothing herein is intended or shall be deemed to constitute any admission of liability. ---------------------------------------------------------------- NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL): This code is released under the CDDL and shall be governed by the laws of the State of California (excluding conflict-of-law provisions). Any litigation relating to this License shall be subject to the jurisdiction of the Federal Courts of the Northern District of California and the state courts of the State of California, with venue lying in Santa Clara County, California. ---------------------------------------------------------------- LibRaw-0.18.8/LICENSE.LGPL000077500000000000000000000575051324423227700145570ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS LibRaw-0.18.8/LibRaw.pro000066400000000000000000000006001324423227700146740ustar00rootroot00000000000000TEMPLATE=subdirs SUBDIRS= \ buildfiles/postprocessing_benchmark.pro \ buildfiles/libraw.pro \ buildfiles/dcraw_emu.pro \ buildfiles/dcraw_half.pro \ buildfiles/half_mt.pro \ buildfiles/mem_image.pro \ buildfiles/raw-identify.pro \ buildfiles/simple_dcraw.pro \ buildfiles/multirender_test.pro \ buildfiles/unprocessed_raw.pro \ buildfiles/4channels.pro \ LibRaw-0.18.8/LibRaw.sln000066400000000000000000000131121324423227700146720ustar00rootroot00000000000000Microsoft Visual Studio Solution File, Format Version 10.00 # Visual Studio 2008 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libraw", "buildfiles\libraw.vcproj", "{2FBFAA81-822F-33B9-8371-3AB3C515F19C}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dcraw_emu", "buildfiles\dcraw_emu.vcproj", "{C82D4C5B-2870-3178-A0CF-784324C61739}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dcraw_half", "buildfiles\dcraw_half.vcproj", "{F7B693FE-0B0B-3479-9975-3C8D22C46EC5}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "half_mt", "buildfiles\half_mt.vcproj", "{34B83B81-817D-30CB-9490-C9DF7C92C002}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mem_image", "buildfiles\mem_image.vcproj", "{EEC2A34F-EC49-36EC-AEB9-668ED8D9D774}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "raw-identify", "buildfiles\raw-identify.vcproj", "{2C04DB64-E5A7-33FC-B2FB-796909A8CA70}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simple_dcraw", "buildfiles\simple_dcraw.vcproj", "{229D76B0-5D05-37DD-ABCD-111E6815AF22}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "multirender_test", "buildfiles\multirender_test.vcproj", "{333626F0-EC45-3771-92C8-5E276A8799C7}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "postprocessing_benchmark", "buildfiles\postprocessing_benchmark.vcproj", "{7101B5EF-6757-30FF-840F-8A022ECE3065}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unprocessed_raw", "buildfiles\unprocessed_raw.vcproj", "{2433FF3D-BAC0-3744-9185-555CC2EF0CD0}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "4channels", "buildfiles\4channels.vcproj", "{4CC3EBFB-7831-3671-B550-F42B151855E5}" EndProject Global GlobalSection(SolutionConfiguration) = preSolution ConfigName.0 = Debug|Win32 ConfigName.1 = Release|Win32 EndGlobalSection GlobalSection(ProjectDependencies) = postSolution EndGlobalSection GlobalSection(ProjectConfiguration) = postSolution {2FBFAA81-822F-33B9-8371-3AB3C515F19C}.Debug|Win32.ActiveCfg = Debug|Win32 {2FBFAA81-822F-33B9-8371-3AB3C515F19C}.Debug|Win32.Build.0 = Debug|Win32 {2FBFAA81-822F-33B9-8371-3AB3C515F19C}.Release|Win32.ActiveCfg = Release|Win32 {2FBFAA81-822F-33B9-8371-3AB3C515F19C}.Release|Win32.Build.0 = Release|Win32 {C82D4C5B-2870-3178-A0CF-784324C61739}.Debug|Win32.ActiveCfg = Debug|Win32 {C82D4C5B-2870-3178-A0CF-784324C61739}.Debug|Win32.Build.0 = Debug|Win32 {C82D4C5B-2870-3178-A0CF-784324C61739}.Release|Win32.ActiveCfg = Release|Win32 {C82D4C5B-2870-3178-A0CF-784324C61739}.Release|Win32.Build.0 = Release|Win32 {F7B693FE-0B0B-3479-9975-3C8D22C46EC5}.Debug|Win32.ActiveCfg = Debug|Win32 {F7B693FE-0B0B-3479-9975-3C8D22C46EC5}.Debug|Win32.Build.0 = Debug|Win32 {F7B693FE-0B0B-3479-9975-3C8D22C46EC5}.Release|Win32.ActiveCfg = Release|Win32 {F7B693FE-0B0B-3479-9975-3C8D22C46EC5}.Release|Win32.Build.0 = Release|Win32 {34B83B81-817D-30CB-9490-C9DF7C92C002}.Debug|Win32.ActiveCfg = Debug|Win32 {34B83B81-817D-30CB-9490-C9DF7C92C002}.Debug|Win32.Build.0 = Debug|Win32 {34B83B81-817D-30CB-9490-C9DF7C92C002}.Release|Win32.ActiveCfg = Release|Win32 {34B83B81-817D-30CB-9490-C9DF7C92C002}.Release|Win32.Build.0 = Release|Win32 {EEC2A34F-EC49-36EC-AEB9-668ED8D9D774}.Debug|Win32.ActiveCfg = Debug|Win32 {EEC2A34F-EC49-36EC-AEB9-668ED8D9D774}.Debug|Win32.Build.0 = Debug|Win32 {EEC2A34F-EC49-36EC-AEB9-668ED8D9D774}.Release|Win32.ActiveCfg = Release|Win32 {EEC2A34F-EC49-36EC-AEB9-668ED8D9D774}.Release|Win32.Build.0 = Release|Win32 {2C04DB64-E5A7-33FC-B2FB-796909A8CA70}.Debug|Win32.ActiveCfg = Debug|Win32 {2C04DB64-E5A7-33FC-B2FB-796909A8CA70}.Debug|Win32.Build.0 = Debug|Win32 {2C04DB64-E5A7-33FC-B2FB-796909A8CA70}.Release|Win32.ActiveCfg = Release|Win32 {2C04DB64-E5A7-33FC-B2FB-796909A8CA70}.Release|Win32.Build.0 = Release|Win32 {229D76B0-5D05-37DD-ABCD-111E6815AF22}.Debug|Win32.ActiveCfg = Debug|Win32 {229D76B0-5D05-37DD-ABCD-111E6815AF22}.Debug|Win32.Build.0 = Debug|Win32 {229D76B0-5D05-37DD-ABCD-111E6815AF22}.Release|Win32.ActiveCfg = Release|Win32 {229D76B0-5D05-37DD-ABCD-111E6815AF22}.Release|Win32.Build.0 = Release|Win32 {333626F0-EC45-3771-92C8-5E276A8799C7}.Debug|Win32.ActiveCfg = Debug|Win32 {333626F0-EC45-3771-92C8-5E276A8799C7}.Debug|Win32.Build.0 = Debug|Win32 {333626F0-EC45-3771-92C8-5E276A8799C7}.Release|Win32.ActiveCfg = Release|Win32 {333626F0-EC45-3771-92C8-5E276A8799C7}.Release|Win32.Build.0 = Release|Win32 {7101B5EF-6757-30FF-840F-8A022ECE3065}.Debug|Win32.ActiveCfg = Debug|Win32 {7101B5EF-6757-30FF-840F-8A022ECE3065}.Debug|Win32.Build.0 = Debug|Win32 {7101B5EF-6757-30FF-840F-8A022ECE3065}.Release|Win32.ActiveCfg = Release|Win32 {7101B5EF-6757-30FF-840F-8A022ECE3065}.Release|Win32.Build.0 = Release|Win32 {2433FF3D-BAC0-3744-9185-555CC2EF0CD0}.Debug|Win32.ActiveCfg = Debug|Win32 {2433FF3D-BAC0-3744-9185-555CC2EF0CD0}.Debug|Win32.Build.0 = Debug|Win32 {2433FF3D-BAC0-3744-9185-555CC2EF0CD0}.Release|Win32.ActiveCfg = Release|Win32 {2433FF3D-BAC0-3744-9185-555CC2EF0CD0}.Release|Win32.Build.0 = Release|Win32 {4CC3EBFB-7831-3671-B550-F42B151855E5}.Debug|Win32.ActiveCfg = Debug|Win32 {4CC3EBFB-7831-3671-B550-F42B151855E5}.Debug|Win32.Build.0 = Debug|Win32 {4CC3EBFB-7831-3671-B550-F42B151855E5}.Release|Win32.ActiveCfg = Release|Win32 {4CC3EBFB-7831-3671-B550-F42B151855E5}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection GlobalSection(ExtensibilityAddIns) = postSolution EndGlobalSection EndGlobalLibRaw-0.18.8/Makefile-preprocess.msvc000066400000000000000000000007231324423227700175720ustar00rootroot00000000000000 all: internal/dcraw_common.cpp internal/dcraw_fileio.cpp internal/defines.h internal/dcraw_common.cpp: dcraw/dcraw.c internal/defines.h perl internal/preprocess.pl -DCOMMON dcraw/dcraw.c >internal/dcraw_common.cpp internal/defines.h: dcraw/dcraw.c perl internal/preprocess.pl -DDEFINES dcraw/dcraw.c >internal/defines.h internal/dcraw_fileio.cpp: dcraw/dcraw.c internal/defines.h perl internal/preprocess.pl -DFILEIO dcraw/dcraw.c >internal/dcraw_fileio.cpp LibRaw-0.18.8/Makefile.am000066400000000000000000000055631324423227700150430ustar00rootroot00000000000000# autoconf macros ACLOCAL_AMFLAGS = -I m4 AUTOMAKE_OPTIONS=subdir-objects LIBRAW_SHLIB_VER = @LIBRAW_SHLIB_VERSION@ LIBRAW_RELEASE_VER = @LIBRAW_RELEASE_VERSION@ # Headers nobase_include_HEADERS = libraw/libraw.h \ libraw/libraw_alloc.h \ libraw/libraw_const.h \ libraw/libraw_datastream.h \ libraw/libraw_internal.h \ libraw/libraw_types.h \ libraw/libraw_version.h # Docs doc_DATA = COPYRIGHT \ LICENSE.CDDL \ LICENSE.LGPL \ Changelog.txt # pkg-config .pc files pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libraw.pc libraw_r.pc # Libraries lib_LTLIBRARIES = lib/libraw.la lib/libraw_r.la lib_libraw_a_CPPFLAGS = -DLIBRAW_NOTHREADS -w lib_libraw_a_SOURCES = internal/dcraw_common.cpp \ internal/dcraw_fileio.cpp \ internal/demosaic_packs.cpp \ src/libraw_cxx.cpp \ src/libraw_datastream.cpp \ src/libraw_c_api.cpp lib_libraw_r_a_CXXFLAGS = -pthread -w lib_libraw_r_a_CFLAGS = -pthread -w lib_libraw_la_SOURCES = $(lib_libraw_a_SOURCES) lib_libraw_r_la_SOURCES = $(lib_libraw_a_SOURCES) lib_libraw_la_LDFLAGS = -no-undefined -version-info $(LIBRAW_SHLIB_VER) lib_libraw_r_la_LDFLAGS = -no-undefined -version-info $(LIBRAW_SHLIB_VER) # Sample binaries if EXAMPLES bin_PROGRAMS = bin/raw-identify \ bin/unprocessed_raw \ bin/4channels \ bin/simple_dcraw \ bin/mem_image \ bin/dcraw_half \ bin/half_mt \ bin/multirender_test \ bin/postprocessing_benchmark \ bin/dcraw_emu endif bin_raw_identify_SOURCES = samples/raw-identify.cpp bin_raw_identify_CPPFLAGS = $(lib_libraw_a_CPPFLAGS) bin_raw_identify_LDADD = lib/libraw.la bin_unprocessed_raw_SOURCES = samples/unprocessed_raw.cpp bin_unprocessed_raw_CPPFLAGS = $(lib_libraw_a_CPPFLAGS) bin_unprocessed_raw_LDADD = lib/libraw.la bin_4channels_SOURCES = samples/4channels.cpp bin_4channels_CPPFLAGS = $(lib_libraw_a_CPPFLAGS) bin_4channels_LDADD = lib/libraw.la bin_simple_dcraw_SOURCES = samples/simple_dcraw.cpp bin_simple_dcraw_CPPFLAGS = $(lib_libraw_a_CPPFLAGS) bin_simple_dcraw_LDADD = lib/libraw.la bin_multirender_test_SOURCES = samples/multirender_test.cpp bin_multirender_test_CPPFLAGS = $(lib_libraw_a_CPPFLAGS) bin_multirender_test_LDADD = lib/libraw.la bin_postprocessing_benchmark_SOURCES = samples/postprocessing_benchmark.cpp bin_postprocessing_benchmark_CPPFLAGS = $(lib_libraw_a_CPPFLAGS) bin_postprocessing_benchmark_LDADD = lib/libraw.la bin_mem_image_SOURCES = samples/mem_image.cpp bin_mem_image_CPPFLAGS = $(lib_libraw_a_CPPFLAGS) bin_mem_image_LDADD = lib/libraw.la bin_dcraw_half_SOURCES = samples/dcraw_half.c bin_dcraw_half_CPPFLAGS = $(lib_libraw_a_CPPFLAGS) bin_dcraw_half_LDADD = lib/libraw.la bin_half_mt_SOURCES = samples/half_mt.c bin_half_mt_CFLAGS = $(lib_libraw_r_a_CXXFLAGS) bin_half_mt_LDADD = lib/libraw_r.la bin_dcraw_emu_SOURCES = samples/dcraw_emu.cpp bin_dcraw_emu_CPPFLAGS = $(lib_libraw_a_CPPFLAGS) bin_dcraw_emu_LDADD = lib/libraw.la LibRaw-0.18.8/Makefile.devel000066400000000000000000000160531324423227700155410ustar00rootroot00000000000000all: sources library all_samples dcraw_binaries PP=./internal/preprocess.pl CC=gcc CXX=g++ LDADD+=-lz #CFLAGS= # RawSpeed Support # CFLAGS+=-DUSE_RAWSPEED -I../RawSpeed -I/opt/local/include/libxml2 # LDADD+=-L../RawSpeed/RawSpeed/release -lrawspeed -L/opt/local/include -ljpeg -lxml2 # RAWSPEED_DATA=../RawSpeed/data/cameras.xml # DNG SDK Support # CFLAGS+=-DUSE_DNGSDK -I../dng_sdk/source # LDADDD+=-L../dng_sdk/release -ldng -ljpeg -lz CC=gcc CXX=g++ # CFLAGS+= -g -I. -pedantic -Wno-long-long -Wno-overflow -O4 -fopenmp CFLAGS+= -g -I. -pedantic -Wno-long-long -Wno-overflow -O3 #CC=gcc #CXX=g++ CFLAGS+= -g -I. -pedantic -Wno-long-long -Wno-overflow -O2 # Haswell: #CFLAGS+=-march=core-avx2 -mtune=core-avx2 -mavx2 # LCMS support # For lcms2 set -DUSE_LCMS2 CFLAGS+=-DUSE_LCMS2 -I/opt/local/include LDADD+=-L/opt/local/lib -llcms # Jasper support for RedCine CFLAGS+=-DUSE_JASPER -I/opt/local/include LDADD+=-L/opt/local/lib -ljasper # JPEG support for DNG CFLAGS+=-DUSE_JPEG -I/opt/local/include LDADD+=-L/opt/local/lib -ljpeg # LIBJPEG8: CFLAGS+=-DUSE_JPEG8 # Demosaic Pack GPL2: # DPCFLAGS+=-I../LibRaw-demosaic-pack-GPL2 # CFLAGS+=-DLIBRAW_DEMOSAIC_PACK_GPL2 # Demosaic Pack GPL3: #DPCFLAGS+=-I../LibRaw-demosaic-pack-GPL3 #CFLAGS+=-DLIBRAW_DEMOSAIC_PACK_GPL3 DCRAW_GEN= internal/dcraw_common.cpp internal/dcraw_fileio.cpp DCRAW_LIB_OBJECTS=object/dcraw_common.o object/libraw_cxx.o object/libraw_datastream.o object/libraw_c_api.o object/dcraw_fileio.o object/demosaic_packs.o DCRAW_LIB_MT_OBJECTS=object/dcraw_common_mt.o object/libraw_cxx_mt.o object/libraw_datastream_mt.o object/libraw_c_api_mt.o object/dcraw_fileio_mt.o object/demosaic_packs_mt.o LR_INCLUDES=libraw/libraw.h libraw/libraw_alloc.h libraw/libraw_const.h libraw/libraw_datastream.h libraw/libraw_internal.h libraw/libraw_types.h libraw/libraw_version.h sources: ${DCRAW_GEN} Makefile.devel ${PP} library: lib/libraw.a lib/libraw_r.a all_samples: bin/raw-identify bin/simple_dcraw bin/dcraw_emu bin/dcraw_half bin/half_mt bin/mem_image \ bin/unprocessed_raw bin/4channels bin/multirender_test bin/postprocessing_benchmark ## RawSpeed xml file RawSpeed/rawspeed_xmldata.cpp: ${RAWSPEED_DATA} ./rsxml2c.sh ${RAWSPEED_DATA} > RawSpeed/rawspeed_xmldata.cpp ## Demosaic Pack(s) object/demosaic_packs.o: internal/demosaic_packs.cpp ${LR_INCLUDES} $(CXX) -w -c -DLIBRAW_NOTHREADS ${CFLAGS} ${DPCFLAGS} -o object/demosaic_packs.o internal/demosaic_packs.cpp object/demosaic_packs_mt.o: internal/demosaic_packs.cpp ${LR_INCLUDES} $(CXX) -w -c -pthread ${CFLAGS} ${DPCFLAGS} -o object/demosaic_packs_mt.o internal/demosaic_packs.cpp ## Samples ## bin/raw-identify: lib/libraw.a samples/raw-identify.cpp $(CXX) ${CFLAGS} -o bin/raw-identify samples/raw-identify.cpp -L./lib -lraw -lm ${LDADD} bin/simple_dcraw: lib/libraw.a samples/simple_dcraw.cpp $(CXX) -DLIBRAW_NOTHREADS ${CFLAGS} -o bin/simple_dcraw samples/simple_dcraw.cpp -L./lib -lraw -lm ${LDADD} bin/multirender_test: lib/libraw.a samples/multirender_test.cpp $(CXX) -DLIBRAW_NOTHREADS ${CFLAGS} -o bin/multirender_test samples/multirender_test.cpp -L./lib -lraw -lm ${LDADD} bin/postprocessing_benchmark: lib/libraw.a samples/postprocessing_benchmark.cpp $(CXX) -DLIBRAW_NOTHREADS ${CFLAGS} -o bin/postprocessing_benchmark samples/postprocessing_benchmark.cpp -L./lib -lraw -lm ${LDADD} bin/unprocessed_raw: lib/libraw.a samples/unprocessed_raw.cpp $(CXX) -DLIBRAW_NOTHREADS ${CFLAGS} -o bin/unprocessed_raw samples/unprocessed_raw.cpp -L./lib -lraw -lm ${LDADD} bin/4channels: lib/libraw.a samples/4channels.cpp $(CXX) -DLIBRAW_NOTHREADS ${CFLAGS} -o bin/4channels samples/4channels.cpp -L./lib -lraw -lm ${LDADD} bin/mem_image: lib/libraw.a samples/mem_image.cpp $(CXX) ${CFLAGS} -o bin/mem_image samples/mem_image.cpp -L./lib -lraw -lm ${LDADD} bin/dcraw_half: lib/libraw.a samples/dcraw_half.c $(CC) ${CFLAGS} -o bin/dcraw_half samples/dcraw_half.c -L./lib -lraw -lm -lstdc++ ${LDADD} bin/half_mt: lib/libraw_r.a samples/half_mt.c $(CC) -pthread ${CFLAGS} -o bin/half_mt samples/half_mt.c -L./lib -lraw_r -lm -lstdc++ ${LDADD} bin/dcraw_emu: lib/libraw.a samples/dcraw_emu.cpp $(CXX) ${CFLAGS} -o bin/dcraw_emu samples/dcraw_emu.cpp -L./lib -lraw_r -lm ${LDADD} dcraw_binaries: bin/dcraw_dist bin/dcraw_dist: dcraw/dcraw.c Makefile.devel $(CXX) -w -O3 -DLIBRAW_NOTHREADS -DNO_LCMS -DNO_JASPER -I/opt/local/include -o bin/dcraw_dist dcraw/dcraw.c -lm -L/opt/local/lib -ljpeg regenerate: ${PP} -N -DDEFINES dcraw/dcraw.c >internal/defines.h ${PP} -N -DCOMMON dcraw/dcraw.c >internal/dcraw_common.cpp ${PP} -N -DFILEIO dcraw/dcraw.c >internal/dcraw_fileio.cpp internal/defines.h: dcraw/dcraw.c ${PP} ${PP} -N -DDEFINES dcraw/dcraw.c >internal/defines.h internal/dcraw_common.cpp: dcraw/dcraw.c internal/defines.h ${PP} Makefile.devel ${PP} -N -DCOMMON dcraw/dcraw.c >internal/dcraw_common.cpp internal/dcraw_fileio.cpp: dcraw/dcraw.c internal/defines.h ${PP} Makefile.devel ${PP} -N -DFILEIO dcraw/dcraw.c >internal/dcraw_fileio.cpp object/dcraw_common.o: internal/dcraw_common.cpp ${LR_INCLUDES} $(CXX) -c -DLIBRAW_NOTHREADS ${CFLAGS} ${LCMS_DEF} -o object/dcraw_common.o internal/dcraw_common.cpp object/dcraw_fileio.o: internal/dcraw_fileio.cpp ${LR_INCLUDES} $(CXX) -c -DLIBRAW_NOTHREADS ${CFLAGS} ${LCMS_DEF} -o object/dcraw_fileio.o internal/dcraw_fileio.cpp object/libraw_cxx.o: src/libraw_cxx.cpp ${LR_INCLUDES} RawSpeed/rawspeed_xmldata.cpp src/libraw_xtrans_compressed.cpp $(CXX) -c -DLIBRAW_NOTHREADS ${LCMS_DEF} ${CFLAGS} -o object/libraw_cxx.o src/libraw_cxx.cpp object/libraw_datastream.o: src/libraw_datastream.cpp ${LR_INCLUDES} $(CXX) -c -DLIBRAW_NOTHREADS ${LCMS_DEF} ${CFLAGS} -o object/libraw_datastream.o src/libraw_datastream.cpp object/libraw_c_api.o: src/libraw_c_api.cpp ${LR_INCLUDES} $(CXX) -c -DLIBRAW_NOTHREADS ${LCMS_DEF} ${CFLAGS} -o object/libraw_c_api.o src/libraw_c_api.cpp lib/libraw.a: ${DCRAW_LIB_OBJECTS} rm -f lib/libraw.a ar crv lib/libraw.a ${DCRAW_LIB_OBJECTS} ranlib lib/libraw.a lib/libraw_r.a: ${DCRAW_LIB_MT_OBJECTS} rm -f lib/libraw_r.a ar crv lib/libraw_r.a ${DCRAW_LIB_MT_OBJECTS} ranlib lib/libraw_r.a object/dcraw_common_mt.o: internal/dcraw_common.cpp ${LR_INCLUDES} $(CXX) -c -pthread ${LCMS_DEF} ${CFLAGS} -o object/dcraw_common_mt.o internal/dcraw_common.cpp object/dcraw_fileio_mt.o: internal/dcraw_fileio.cpp ${LR_INCLUDES} $(CXX) -c -pthread ${LCMS_DEF} ${CFLAGS} -o object/dcraw_fileio_mt.o internal/dcraw_fileio.cpp object/libraw_cxx_mt.o: src/libraw_cxx.cpp ${LR_INCLUDES} src/libraw_xtrans_compressed.cpp $(CXX) -c ${LCMS_DEF} -pthread ${CFLAGS} -o object/libraw_cxx_mt.o src/libraw_cxx.cpp object/libraw_datastream_mt.o: src/libraw_datastream.cpp ${LR_INCLUDES} $(CXX) -c ${LCMS_DEF} -pthread ${CFLAGS} -o object/libraw_datastream_mt.o src/libraw_datastream.cpp object/libraw_c_api_mt.o: src/libraw_c_api.cpp ${LR_INCLUDES} $(CXX) -c ${LCMS_DEF} -pthread ${CFLAGS} -o object/libraw_c_api_mt.o src/libraw_c_api.cpp clean: rm -fr bin/*.dSYM rm -f *.o *~ src/*~ samples/*~ internal/*~ libraw/*~ lib/lib*.a bin/[4a-z]* object/*o dcraw/*~ doc/*~ bin/*~ fullclean: clean rm -f ${DCRAW_GEN} LibRaw-0.18.8/Makefile.dist000066400000000000000000000143011324423227700153770ustar00rootroot00000000000000all: library all_samples CFLAGS=-arch i386 -arch x86_64 -O3 -I. -w CC=gcc CXX=g++ # OpenMP support #CFLAGS+=-fopenmp # RawSpeed Support #CFLAGS+=-pthread -DUSE_RAWSPEED -I../RawSpeed -I/usr/local/include/libxml2 #LDADD+=-L../RawSpeed/RawSpeed -lrawspeed -L/usr/local/lib -ljpeg -lxml2 #RAWSPEED_DATA=../RawSpeed/data/cameras.xml # DNG SDK Support # CFLAGS+=-DUSE_DNGSDK -I../dng_sdk/source # LDADDD+=-L../dng_sdk/release -ldng -lXMPCore -ljpeg -lz # Jasper support for RedCine #CFLAGS+=-DUSE_JASPER -I/usr/local/include #LDADD+=-L/usr/local/lib -ljasper # JPEG support for lossy DNG #CFLAGS+=-DUSE_JPEG -I/usr/local/include #LDADD+=-L/usr/local/lib -ljpeg # LIBJPEG8: #CFLAGS+=-DUSE_JPEG8 # LCMS support #CFLAGS+=-DUSE_LCMS -I/usr/local/include #LDADD+=-L/usr/local/lib -llcms # LCMS2.x support #CFLAGS+=-DUSE_LCMS2 -I/usr/local/include #LDADD+=-L/usr/local/lib -llcms2 # Demosaic Pack GPL2: #DPCFLAGS+=-I../LibRaw-demosaic-pack-GPL2 #CFLAGS+=-DLIBRAW_DEMOSAIC_PACK_GPL2 # Demosaic Pack GPL3: #DPCFLAGS+=-I../LibRaw-demosaic-pack-GPL3 #CFLAGS+=-DLIBRAW_DEMOSAIC_PACK_GPL3 DCRAW_LIB_OBJECTS=object/dcraw_common.o object/libraw_cxx.o object/libraw_datastream.o object/libraw_c_api.o object/dcraw_fileio.o object/demosaic_packs.o DCRAW_LIB_MT_OBJECTS=object/dcraw_common_mt.o object/libraw_cxx_mt.o object/libraw_datastream_mt.o object/libraw_c_api_mt.o object/dcraw_fileio_mt.o object/demosaic_packs_mt.o library: lib/libraw.a lib/libraw_r.a all_samples: bin/raw-identify bin/simple_dcraw bin/dcraw_emu bin/dcraw_half bin/half_mt bin/mem_image \ bin/unprocessed_raw bin/4channels bin/multirender_test bin/postprocessing_benchmark install: library @if [ -d /usr/local/include ] ; then cp -R libraw /usr/local/include/ ; else echo 'no /usr/local/include' ; fi @if [ -d /usr/local/lib ] ; then cp lib/libraw.a lib/libraw_r.a /usr/local/lib/ ; else echo 'no /usr/local/lib' ; fi install-binaries: all_samples @if [ -d /usr/local/bin ] ; then cp bin/[a-z]* /usr/local/bin/ ; else echo 'no /usr/local/bin' ; fi ## RawSpeed xml file RawSpeed/rawspeed_xmldata.cpp: ${RAWSPEED_DATA} ./rsxml2c.sh ${RAWSPEED_DATA} > RawSpeed/rawspeed_xmldata.cpp #binaries bin/raw-identify: lib/libraw.a samples/raw-identify.cpp ${CXX} -DLIBRAW_NOTHREADS ${CFLAGS} -o bin/raw-identify samples/raw-identify.cpp -L./lib -lraw -lm ${LDADD} bin/unprocessed_raw: lib/libraw.a samples/unprocessed_raw.cpp ${CXX} -DLIBRAW_NOTHREADS ${CFLAGS} -o bin/unprocessed_raw samples/unprocessed_raw.cpp -L./lib -lraw -lm ${LDADD} bin/4channels: lib/libraw.a samples/4channels.cpp ${CXX} -DLIBRAW_NOTHREADS ${CFLAGS} -o bin/4channels samples/4channels.cpp -L./lib -lraw -lm ${LDADD} bin/simple_dcraw: lib/libraw.a samples/simple_dcraw.cpp ${CXX} -DLIBRAW_NOTHREADS ${CFLAGS} -o bin/simple_dcraw samples/simple_dcraw.cpp -L./lib -lraw -lm ${LDADD} bin/multirender_test: lib/libraw.a samples/multirender_test.cpp ${CXX} -DLIBRAW_NOTHREADS ${CFLAGS} -o bin/multirender_test samples/multirender_test.cpp -L./lib -lraw -lm ${LDADD} bin/postprocessing_benchmark: lib/libraw.a samples/postprocessing_benchmark.cpp ${CXX} -DLIBRAW_NOTHREADS ${CFLAGS} -o bin/postprocessing_benchmark samples/postprocessing_benchmark.cpp -L./lib -lraw -lm ${LDADD} bin/mem_image: lib/libraw.a samples/mem_image.cpp ${CXX} -DLIBRAW_NOTHREADS ${CFLAGS} -o bin/mem_image samples/mem_image.cpp -L./lib -lraw -lm ${LDADD} bin/dcraw_half: lib/libraw.a object/dcraw_half.o ${CC} -DLIBRAW_NOTHREADS ${CFLAGS} -o bin/dcraw_half object/dcraw_half.o -L./lib -lraw -lm -lstdc++ ${LDADD} bin/half_mt: lib/libraw_r.a object/half_mt.o ${CC} -pthread ${CFLAGS} -o bin/half_mt object/half_mt.o -L./lib -lraw_r -lm -lstdc++ ${LDADD} bin/dcraw_emu: lib/libraw.a samples/dcraw_emu.cpp ${CXX} -DLIBRAW_NOTHREADS ${CFLAGS} -o bin/dcraw_emu samples/dcraw_emu.cpp -L./lib -lraw -lm ${LDADD} #objects object/demosaic_packs.o: internal/demosaic_packs.cpp ${CXX} -c -DLIBRAW_NOTHREADS ${CFLAGS} ${DPCFLAGS} -o object/demosaic_packs.o internal/demosaic_packs.cpp object/dcraw_common.o: internal/dcraw_common.cpp ${CXX} -c -DLIBRAW_NOTHREADS ${CFLAGS} -o object/dcraw_common.o internal/dcraw_common.cpp object/dcraw_fileio.o: internal/dcraw_fileio.cpp ${CXX} -c -DLIBRAW_NOTHREADS ${CFLAGS} -o object/dcraw_fileio.o internal/dcraw_fileio.cpp object/libraw_cxx.o: src/libraw_cxx.cpp RawSpeed/rawspeed_xmldata.cpp src/libraw_xtrans_compressed.cpp ${CXX} -c -DLIBRAW_NOTHREADS ${CFLAGS} -o object/libraw_cxx.o src/libraw_cxx.cpp object/libraw_datastream.o: src/libraw_datastream.cpp ${CXX} -c -DLIBRAW_NOTHREADS ${CFLAGS} -o object/libraw_datastream.o src/libraw_datastream.cpp object/libraw_c_api.o: src/libraw_c_api.cpp ${CXX} -c -DLIBRAW_NOTHREADS ${CFLAGS} -o object/libraw_c_api.o src/libraw_c_api.cpp object/dcraw_half.o: samples/dcraw_half.c ${CC} -c -DLIBRAW_NOTHREADS ${CFLAGS} -o object/dcraw_half.o samples/dcraw_half.c object/half_mt.o: samples/half_mt.c ${CC} -c -pthread ${CFLAGS} -o object/half_mt.o samples/half_mt.c lib/libraw.a: ${DCRAW_LIB_OBJECTS} rm -f lib/libraw.a ar crv lib/libraw.a ${DCRAW_LIB_OBJECTS} ranlib lib/libraw.a lib/libraw_r.a: ${DCRAW_LIB_MT_OBJECTS} rm -f lib/libraw_r.a ar crv lib/libraw_r.a ${DCRAW_LIB_MT_OBJECTS} ranlib lib/libraw_r.a object/demosaic_packs_mt.o: internal/demosaic_packs.cpp ${CXX} -c -pthread ${CFLAGS} ${DPCFLAGS} -o object/demosaic_packs_mt.o internal/demosaic_packs.cpp object/dcraw_common_mt.o: internal/dcraw_common.cpp ${CXX} -c -pthread ${CFLAGS} -o object/dcraw_common_mt.o internal/dcraw_common.cpp object/dcraw_fileio_mt.o: internal/dcraw_fileio.cpp ${CXX} -c -pthread ${CFLAGS} -o object/dcraw_fileio_mt.o internal/dcraw_fileio.cpp object/libraw_cxx_mt.o: src/libraw_cxx.cpp RawSpeed/rawspeed_xmldata.cpp src/libraw_xtrans_compressed.cpp ${CXX} -c -pthread ${CFLAGS} -o object/libraw_cxx_mt.o src/libraw_cxx.cpp object/libraw_datastream_mt.o: src/libraw_datastream.cpp ${CXX} -c -pthread ${CFLAGS} -o object/libraw_datastream_mt.o src/libraw_datastream.cpp object/libraw_c_api_mt.o: src/libraw_c_api.cpp ${CXX} -c -pthread ${CFLAGS} -o object/libraw_c_api_mt.o src/libraw_c_api.cpp clean: rm -fr bin/*.dSYM rm -f *.o *~ src/*~ samples/*~ internal/*~ libraw/*~ lib/lib*.a bin/[4a-z]* object/*o dcraw/*~ doc/*~ bin/*~ LibRaw-0.18.8/Makefile.mingw000077500000000000000000000101621324423227700155610ustar00rootroot00000000000000all: library samples # OpenMP support #OPENMP_CFLAGS=-fopenmp # Demosaic Pack GPL2: #CFLAGS_DP2=-I../LibRaw-demosaic-pack-GPL2 #CFLAGS2=-DLIBRAW_DEMOSAIC_PACK_GPL2 # Demosaic Pack GPL3: #CFLAGS_DP3=-I../LibRaw-demosaic-pack-GPL3 #CFLAGS3=-DLIBRAW_DEMOSAIC_PACK_GPL3 # Jasper support for RedCine #CFLAGS+=-DUSE_JASPER -I/usr/local/include #LDADD+=-L/usr/local/lib -ljasper # JPEG support for DNG #CFLAGS+=-DUSE_JPEG -I/usr/local/include #LDADD+=-L/usr/local/lib -ljpeg # LCMS support #LCMS_DEF=-DUSE_LCMS -I/usr/local/include #LCMS_LIB=-L/usr/local/lib -llcms # LCMS2.x support #LCMS_DEF=-DUSE_LCMS2 -I/usr/local/include #LCMS_LIB=-L/usr/local/lib -llcms2 # Non thread-safe: CFLAGS_THREADS=-DLIBRAW_NOTHREADS # Thread Safe: #CFLAGS_THREADS= # Common flags # WARNING: library order matters COMMON_LIBS=-lws2_32 -lm ${LCMS_LIB} CLIBS=-L./lib -lraw ${COMMON_LIBS} CFLAGS=-O4 -I. -w -DLIBRAW_NODLL ${OPENMP_CFLAGS} ${CFLAGS_THREADS} ${CFLAGS2} ${CFLAGS3} DCRAW_LIB_OBJECTS=object/libraw_cxx.o object/libraw_datastream.o object/libraw_c_api.o object/dcraw_common.o object/dcraw_fileio.o object/demosaic_packs.o library: lib/libraw.a samples: bin/raw-identify bin/simple_dcraw bin/dcraw_emu bin/dcraw_half bin/mem_image bin/mem_image \ bin/unprocessed_raw bin/4channels bin/multirender_test bin/postprocessing_benchmark install: library @if [ -d /usr/local/include ] ; then cp -R libraw /usr/local/include/ ; else echo 'no /usr/local/include' ; fi @if [ -d /usr/local/lib ] ; then cp lib/libraw.a /usr/local/lib/ ; else echo 'no /usr/local/lib' ; fi install-samples: samples @if [ -d /usr/local/bin ] ; then cp bin/[a-z]* /usr/local/bin/ ; else echo 'no /usr/local/bin' ; fi # Samples bin/raw-identify: lib/libraw.a samples/raw-identify.cpp g++ ${LCMS_DEF} ${CFLAGS} -o bin/raw-identify samples/raw-identify.cpp ${CLIBS} bin/unprocessed_raw: lib/libraw.a samples/unprocessed_raw.cpp g++ ${LCMS_DEF} ${CFLAGS} -o bin/unprocessed_raw samples/unprocessed_raw.cpp ${CLIBS} bin/4channels: lib/libraw.a samples/4channels.cpp g++ ${LCMS_DEF} ${CFLAGS} -o bin/4channels samples/4channels.cpp ${CLIBS} bin/simple_dcraw: lib/libraw.a samples/simple_dcraw.cpp g++ ${LCMS_DEF} ${CFLAGS} -o bin/simple_dcraw samples/simple_dcraw.cpp ${CLIBS} bin/multirender_test: lib/libraw.a samples/multirender_test.cpp g++ ${LCMS_DEF} ${CFLAGS} -o bin/multirender_test samples/multirender_test.cpp ${CLIBS} bin/postprocessing_benchmark: lib/libraw.a samples/postprocessing_benchmark.cpp g++ ${LCMS_DEF} ${CFLAGS} -o bin/postprocessing_benchmark samples/postprocessing_benchmark.cpp ${CLIBS} bin/mem_image: lib/libraw.a samples/mem_image.cpp g++ ${LCMS_DEF} ${CFLAGS} -o bin/mem_image samples/mem_image.cpp ${CLIBS} bin/dcraw_half: lib/libraw.a object/dcraw_half.o gcc ${LCMS_DEF} ${CFLAGS} -o bin/dcraw_half object/dcraw_half.o ${CLIBS} -lstdc++ bin/dcraw_emu: lib/libraw.a samples/dcraw_emu.cpp g++ ${LCMS_DEF} ${CFLAGS} -o bin/dcraw_emu samples/dcraw_emu.cpp ${CLIBS} #Libraries object/dcraw_common.o: internal/dcraw_common.cpp g++ -c ${LCMS_DEF} ${CFLAGS} -o object/dcraw_common.o internal/dcraw_common.cpp object/demosaic_packs.o: internal/demosaic_packs.cpp g++ -c ${LCMS_DEF} ${CFLAGS} ${CFLAGS_DP2} ${CFLAGS_DP3} -o object/demosaic_packs.o internal/demosaic_packs.cpp object/dcraw_fileio.o: internal/dcraw_fileio.cpp g++ -c ${LCMS_DEF} ${CFLAGS} -o object/dcraw_fileio.o internal/dcraw_fileio.cpp object/libraw_cxx.o: src/libraw_cxx.cpp src/libraw_xtrans_compressed.cpp g++ -c ${LCMS_DEF} ${CFLAGS} -o object/libraw_cxx.o src/libraw_cxx.cpp object/libraw_datastream.o: src/libraw_datastream.cpp g++ -c ${LCMS_DEF} ${CFLAGS} -o object/libraw_datastream.o src/libraw_datastream.cpp object/libraw_c_api.o: src/libraw_c_api.cpp g++ -c ${LCMS_DEF} ${CFLAGS} -o object/libraw_c_api.o src/libraw_c_api.cpp object/dcraw_half.o: samples/dcraw_half.c gcc -c ${LCMS_DEF} ${CFLAGS} -o object/dcraw_half.o samples/dcraw_half.c lib/libraw.a: ${DCRAW_LIB_OBJECTS} -del lib\\libraw.a -rm -f lib/libraw.a ar crv lib/libraw.a ${DCRAW_LIB_OBJECTS} ranlib lib/libraw.a # Clean clean: -del bin\\*.dSYM -del lib\\lib*.a bin\\*.exe object\\*o -rm -f lib/lib*.a bin/*.exe object/*o LibRaw-0.18.8/Makefile.msvc000077500000000000000000000137331324423227700154170ustar00rootroot00000000000000# Additional compiler flags (OpenMP, SSEx, AVX, ...) #COPT_OPT=/arch:SSE2 /arch:AVX # Compile with RawSpeed support #CFLAGS_RAWSPEED=/DUSE_RAWSPEED /I"..\\RawSpeed" /I"..\\RawSpeed\include" /I"..\\RawSpeed\include\libjpeg" #LDFLAGS_RAWSPEED=..\RawSpeed\lib\rawspeed.lib ..\RawSpeed\lib\libxml2.lib ..\RawSpeed\lib\iconv.lib ..\RawSpeed\lib\charset.lib ..\RawSpeed\lib\turbojpeg-static.lib # Compile with DNG SDK support #CFLAGS_DNG=/DUSE_DNGSDK /I"..\\dng_sdk\\source" #LDFLAGS_DNG=..\\dng_sdk\\release\\libdng.lib ..\\dng_sdk\\release\\XMPCore.lib # you may also need to specify zlib.lib and jpeg.lib in the line above # Demosaic Pack GPL2: #CFLAGS_DP2=/I"..\\LibRaw-demosaic-pack-GPL2" #CFLAGSG2=/DLIBRAW_DEMOSAIC_PACK_GPL2 # Demosaic Pack GPL3: #CFLAGS_DP3=/I"..\\LibRaw-demosaic-pack-GPL3" #CFLAGSG3=/DLIBRAW_DEMOSAIC_PACK_GPL3 # LCMS 1.x support #LCMS_DEF=/DUSE_LCMS /DCMS_DLL /I..\lcms-1.19\include #LCMS_LIB=..\lcms-1.19\bin\lcms.lib # LCMS 2.x support #LCMS_DEF=/DUSE_LCMS2 /DCMS_DLL /I..\lcms2-2.3\include #LCMS_LIB=..\lcms2-2.3\bin\lcms2_dll.lib # JPEG support for DNG #JPEG_DEF=/DUSE_JPEG /I..\jpeg-8d #JPEG_LIB=..\jpeg-8d\Release\jpeg.lib SAMPLES=bin\raw-identify.exe bin\simple_dcraw.exe bin\dcraw_emu.exe bin\dcraw_half.exe bin\half_mt.exe bin\mem_image.exe bin\unprocessed_raw.exe bin\4channels.exe bin\multirender_test.exe bin\postprocessing_benchmark.exe LIBSTATIC=lib\libraw_static.lib DLL=bin\libraw.dll LIBDLL=lib\libraw.lib all: $(DLL) $(SAMPLES) $(LIBSTATIC) # Guess LIBPATH from $INCLUDE LIB_OBJECTS=object\dcraw_common_st.obj object\dcraw_fileio_st.obj object\libraw_cxx_st.obj object\libraw_datastream_st.obj object\libraw_c_api_st.obj object\demosaic_packs_st.obj DLL_OBJECTS=object\dcraw_common.obj object\dcraw_fileio.obj object\libraw_cxx.obj object\libraw_datastream.obj object\libraw_c_api.obj object\demosaic_packs.obj CC=cl.exe COPT=/EHsc /MP /MD /I. /DWIN32 /O2 /W0 /nologo $(COPT_OPT) $(CFLAGSG2) $(CFLAGSG3) $(LCMS_DEF) $(JPEG_DEF) $(CFLAGS_RAWSPEED) $(CFLAGS_DNG) LINKLIB=$(LIBDLL) $(LDFLAGS_RAWSPEED) $(LDFLAGS_DNG) # Samples - default to dynamic (DLL) link, uncomment next lines #CFLAGS2=/DLIBRAW_NODLL #LINKLIB=$(LIBSTATIC) bin\raw-identify.exe: $(LINKLIB) samples\raw-identify.cpp $(CC) $(COPT) $(CFLAGS2) /Fe"bin\\raw-identify.exe" /Fo"object\\" samples\raw-identify.cpp $(LINKLIB) bin\unprocessed_raw.exe: $(LINKLIB) samples\unprocessed_raw.cpp $(CC) $(COPT) $(CFLAGS2) /Fe"bin\\unprocessed_raw.exe" /Fo"object\\" samples\unprocessed_raw.cpp $(LINKLIB) ws2_32.lib bin\4channels.exe: $(LINKLIB) samples\4channels.cpp $(CC) $(COPT) $(CFLAGS2) /Fe"bin\\4channels.exe" /Fo"object\\" samples\4channels.cpp $(LINKLIB) bin\simple_dcraw.exe: $(LINKLIB) samples\simple_dcraw.cpp $(CC) $(COPT) $(CFLAGS2) /Fe"bin\\simple_dcraw.exe" /Fo"object\\" samples\simple_dcraw.cpp $(LINKLIB) bin\postprocessing_benchmark.exe: $(LINKLIB) samples\postprocessing_benchmark.cpp $(CC) $(COPT) $(CFLAGS2) /Fe"bin\\postprocessing_benchmark.exe" /Fo"object\\" samples\postprocessing_benchmark.cpp $(LINKLIB) bin\multirender_test.exe: $(LINKLIB) samples\multirender_test.cpp $(CC) $(COPT) $(CFLAGS2) /Fe"bin\\multirender_test.exe" /Fo"object\\" samples\multirender_test.cpp $(LINKLIB) bin\mem_image.exe: $(LINKLIB) samples\mem_image.cpp $(CC) $(COPT) $(CFLAGS2) /Fe"bin\\mem_image.exe" /Fo"object\\" samples\mem_image.cpp $(LINKLIB) bin\dcraw_emu.exe: $(LINKLIB) samples\dcraw_emu.cpp $(CC) $(COPT) $(CFLAGS2) /Fe"bin\\dcraw_emu.exe" /Fo"object\\" samples\dcraw_emu.cpp $(LINKLIB) bin\dcraw_half.exe: $(LINKLIB) samples\dcraw_half.c $(CC) $(COPT) $(CFLAGS2) /Fe"bin\\dcraw_half.exe" /Fo"object\\" samples\dcraw_half.c $(LINKLIB) bin\half_mt.exe: $(LINKLIB) samples\half_mt_win32.c $(CC) $(COPT) $(CFLAGS2) /Fe"bin\\half_mt.exe" /Fo"object\\" samples\half_mt_win32.c $(LINKLIB) # DLL build $(DLL): $(DLL_OBJECTS) -del /f $(DLL) $(LIBDLL) cl $(COPT) /LD $(DLL_OBJECTS) $(LDFLAGS_RAWSPEED) $(LDFLAGS_DNG) $(LCMS_LIB) $(JPEG_LIB) /link /out:"$(DLL)" /implib:"$(LIBDLL)" object\dcraw_common.obj: internal\dcraw_common.cpp $(CC) $(COPT) /DLIBRAW_BUILDLIB /Fo"object\\dcraw_common.obj" /c internal\dcraw_common.cpp object\dcraw_fileio.obj: internal\dcraw_fileio.cpp $(CC) $(COPT) /DLIBRAW_BUILDLIB /Fo"object\\dcraw_fileio.obj" /c internal\dcraw_fileio.cpp object\demosaic_packs.obj: internal\demosaic_packs.cpp $(CC) $(COPT) $(CFLAGS_DP2) $(CFLAGS_DP3) /DLIBRAW_BUILDLIB /Fo"object\\demosaic_packs.obj" /c internal\demosaic_packs.cpp object\libraw_cxx.obj: src\libraw_cxx.cpp src\libraw_xtrans_compressed.cpp $(CC) $(COPT) /DLIBRAW_BUILDLIB /Fo"object\\libraw_cxx.obj" /c src\libraw_cxx.cpp object\libraw_datastream.obj: src\libraw_datastream.cpp $(CC) $(COPT) /DLIBRAW_BUILDLIB /Fo"object\\libraw_datastream.obj" /c src\libraw_datastream.cpp object\libraw_c_api.obj: src\libraw_c_api.cpp $(CC) $(COPT) /DLIBRAW_BUILDLIB /Fo"object\\libraw_c_api.obj" /c src\libraw_c_api.cpp # LIBRARY BUILD $(LIBSTATIC): $(LIB_OBJECTS) -del /f $(LIBSTATIC) lib /OUT:$(LIBSTATIC) /LTCG $(LIB_OBJECTS) object\dcraw_common_st.obj: internal\dcraw_common.cpp $(CC) $(COPT) /DLIBRAW_NODLL /Fo"object\\dcraw_common_st.obj" /c internal\dcraw_common.cpp object\dcraw_fileio_st.obj: internal\dcraw_fileio.cpp $(CC) $(COPT) /DLIBRAW_NODLL /Fo"object\\dcraw_fileio_st.obj" /c internal\dcraw_fileio.cpp object\demosaic_packs_st.obj: internal\demosaic_packs.cpp $(CC) $(COPT) $(CFLAGS_DP2) $(CFLAGS_DP3) /DLIBRAW_NODLL /Fo"object\\demosaic_packs_st.obj" /c internal\demosaic_packs.cpp object\libraw_cxx_st.obj: src\libraw_cxx.cpp src\libraw_xtrans_compressed.cpp $(CC) $(COPT) /DLIBRAW_NODLL /Fo"object\\libraw_cxx_st.obj" /c src\libraw_cxx.cpp object\libraw_datastream_st.obj: src\libraw_datastream.cpp $(CC) $(COPT) /DLIBRAW_NODLL /Fo"object\\libraw_datastream_st.obj" /c src\libraw_datastream.cpp object\libraw_c_api_st.obj: src\libraw_c_api.cpp $(CC) $(COPT) /DLIBRAW_NODLL /Fo"object\\libraw_c_api_st.obj" /c src\libraw_c_api.cpp clean: -del $(LIBSTATIC) $(LIBDLL) lib\*.exp -del $(LIB_OBJECTS) $(DLL_OBJECTS) -del $(DLL) $(SAMPLES) LibRaw-0.18.8/README000066400000000000000000000021541324423227700136600ustar00rootroot00000000000000====================== LibRaw ============================== == Library for reading and processing of RAW digicam images == LibRaw is a library for reading RAW files from digital photo cameras (CRW/CR2, NEF, RAF, DNG, MOS, KDC, DCR, etc, virtually all RAW formats are supported). It pays special attention to correct retrieval of data required for subsequent RAW conversion. The library is intended for embedding in RAW converters, data analyzers, and other programs using RAW files as the initial data. LibRaw library, Copyright (C) 2008-2017 LibRaw LLC (info@libraw.org) The library includes source code from dcraw.c, Dave Coffin's raw photo decoder Copyright 1997-2016 by Dave Coffin, dcoffin a cybercom o net LibRaw is distributed for free under two different licenses: * GNU Lesser General Public License, version 2.1 * COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 You may use one of these licensing modes and switch between them. If you modify LibRaw source and made your changes public, you should accept both two licensing modes for your changes/additions. LibRaw-0.18.8/README.DNGSDK.txt000066400000000000000000000034331324423227700154500ustar00rootroot00000000000000LibRaw can decode most common DNG formats (Bayer/Linear, 16-bit integer and floating point) by itself (you need to use zlib for deflate decompression support and libjpeg for lossy compressed DNGs). Some rare flavours of DNG files (e.g. for 8-bit files) are not implemented in LibRaw. These files never come from camera or DNG files created by Adobe DNG Converter, but created by some processing software that uses DNG as intermediate format. To decode such files you need to compile LibRaw with Adobe DNG SDK. This SDK to be used internally, standard LibRaw API remains untouched (you may specify what kinds of DNG files you want to decode via Adobe code, see below). To build LibRaw with DNG SDK specify USE_DNGSDK in defines and adjust include/linker path settings to point to DNG SDK's include and library folders. In your application * create dng_host object (or derived object, e.g. with multithreaded) entity in your program; * pass it to LibRaw via LibRaw::set_dng_host(dng_host *) call to enable DNG SDK use on runtime * adjust imgdata.params.use_dngsdk parameter with one of this values (ORed bitwise): LIBRAW_DNG_NONE - do not use DNG SDK for DNG processing LIBRAW_DNG_FLOAT - process floating point DNGs via Adobe DNG SDK LIBRAW_DNG_LINEAR - process 'linear DNG' (i.e. demosaiced) LIBRAW_DNG_DEFLATE - process DNGs compressed with deflate (gzip) LIBRAW_DNG_XTRANS - process Fuji X-Trans DNGs (6x6 CFA) LIBRAW_DNG_OTHER - process other files (so usual 2x2 bayer) Default value for this field: LIBRAW_DNG_DEFAULT=LIBRAW_DNG_FLOAT|LIBRAW_DNG_LINEAR|LIBRAW_DNG_DEFLATE You also may use this macro to pass all supported DNGs to Adobe SDK: LIBRAW_DNG_ALL = LIBRAW_DNG_FLOAT|LIBRAW_DNG_LINEAR|LIBRAW_DNG_XTRANS|LIBRAW_DNG_OTHER LibRaw-0.18.8/README.RawSpeed.txt000066400000000000000000000037141324423227700162120ustar00rootroot00000000000000================= Compile LibRaw with RawSpeed support ======================== 1) Prerequisites To build RawSpeed you need libxml2, iconv, and JPEG library installed on your system. 2) Build RawSpeed: -- consult http://rawstudio.org/blog/?p=800 for details -- Win32: you need POSIX Threads for Win32 installed on your system (http://sources.redhat.com/pthreads-win32/) -- you may use qmake .pro files supplied in LibRaw distribution (RawSpeed/rawspeed.qmake-pro-files.patch) Adjust path to libraries/includes according to your setup. -- Win32: you need to add __declspec(..) to external C++ classes. Use patch provided with LibRaw (RawSpeed/rawspeed.win32-dll.patch) -- Unix: you need to define rawspeed_get_number_of_processor_cores() call For most unix systems (Linux, MacOS X 10.4+, FreeBSD) patch provided with LibRaw (RawSpeed/rawspeed.cpucount-unix.patch) should work. 3) Build LibRaw with RawSpeed support: Win32: --Uncomment CFLAGS_RAWSPEED and LDFLAGS_RAWSPEED lines in Makefile.msvc. Adjust paths to libraries/includes if needed. -- run nmake -f Makefile.msvc Unix/MacOS: -- Uncomment CFLAGS/LDADD lines in RawSpeed section in Makefile.dist -- Uncomment RAWSPEED_DATA line if you wish to rebuild internal copy of RawSpeed's cameras.xml -- run make -f Makefile.dist Compile options: -- You may specify -DNOSONY_RAWSPEED define if you do not want to use RawSpeed's Sony formats decoder (because result of this decoder is different from LibRaw's built-in decoder) 4) Build/run your Apps with LibRaw+RawSpeed -- Build as usual, no changes required in your apps unless you access LibRaw::imgdata.rawdata.raw_image[] directly -- you may turn off RawSpeed support on runtime by setting imgdata.params.use_rawspeed to 0. -- You'll need all shared libraries you linked to at runtime (libxml2, iconv, LibJPEG, and posix threads on Win32). LibRaw-0.18.8/README.cmake000066400000000000000000000004561324423227700147420ustar00rootroot00000000000000Due to inability to support (user contributed) Cmake scripts, the cmake builds are not officially supported by LibRaw team since October 23, 2014 The scripts are moved to separate github repository github.com:LibRaw/LibRaw-cmake.git Checkout from this repo if you want to use Cmake to build LibRaw. LibRaw-0.18.8/README.demosaic-packs000066400000000000000000000035041324423227700165420ustar00rootroot00000000000000======================= LibRaw demosaic pack(s) =============================== There are many good interpolation (demosaic) methods implemented in open-source world. Unfortunately, some of these methods are distributed under the terms of different versions of GNU General Public License (GPL). So it is not possible to include implementation of these demosaics into the LibRaw distribution because LibRaw is distributed under more liberal licenses (LGPL and CDDL). Of course, it is possible to distribute these demosaic methods in separate packages and use within LibRaw under following conditions: * LibRaw is used under the terms of LGPL license which is GPL-compatible * Resulting product (which uses LibRaw AND LibRaw-demosaic-pack) is licensed under GPL2+ (for GPL2 demosaic-pack) or GPL3+ (if demosaic-pack-GPL3 is used). For now demosaic packs are available via GitHub only: 1) LibRaw demosaic pack GPL2+ GitHub URL: git://github.com/LibRaw/LibRaw-demosaic-pack-GPL2.git This pack includes these demosaic implementations: * AFD and LMMSE implementations from PerfectRaw by Manuel Llorens * VCD, Modified AHD, post-demosaic refinemend and median filters by Paul Lee 2) LibRaw demosaic pack GPL3+ GitHub URL: git://github.com/LibRaw/LibRaw-demosaic-pack-GPL3.git This pack includes AMaZe interpolation by Emil Martinec. == How To Use (developer only!) === 1. Get LibRaw-0.12... and unpack it in some folder. 2. Checkout one or both demosaic pack(s) in the same folder (NOT within LibRaw folder). 3. Check Makefile settings: CFLAGS_DP1 and CFLAGS_DP2 should point to demosaic pack(s) folder(s) CFLAGS should have -DLIBRAW_DEMOSAIC_PACK_GPL2/-DLIBRAW_DEMOSAIC_PACK_GPL3 setting 4. Just run make. ./configure stuff is not supported with demosaic-pack(s) for now. LibRaw-0.18.8/RawSpeed/000077500000000000000000000000001324423227700145105ustar00rootroot00000000000000LibRaw-0.18.8/RawSpeed/rawspeed.cpucount-unix.patch000066400000000000000000000005571324423227700221720ustar00rootroot00000000000000diff --git a/RawSpeed/Common.cpp b/RawSpeed/Common.cpp index abec232..6990c04 100644 --- a/RawSpeed/Common.cpp +++ b/RawSpeed/Common.cpp @@ -31,5 +31,10 @@ void* _aligned_malloc(size_t bytes, size_t alignment) { else return NULL; } +#include +int rawspeed_get_number_of_processor_cores() +{ + return sysconf( _SC_NPROCESSORS_ONLN ); +} #endif LibRaw-0.18.8/RawSpeed/rawspeed.qmake-pro-files.patch000066400000000000000000000063671324423227700223520ustar00rootroot00000000000000diff --git a/RawSpeed/rawspeed-lib.pro b/RawSpeed/rawspeed-lib.pro new file mode 100644 index 0000000..1599ddf --- /dev/null +++ b/RawSpeed/rawspeed-lib.pro @@ -0,0 +1,42 @@ +TEMPLATE=lib +TARGET=rawspeed + +win32:INCLUDEPATH+=d:/Qt/iconv/include d:/Qt/libxml2/include/libxml2 d:/Qt/pthreads/include d:/Qt/libjpeg-turbo/include +win32:LIBS+=-Ld:/Qt/iconv/lib/x86 -liconv -Ld:/Qt/libxml2/lib/x86 -llibxml2 -Ld:/Qt/pthreads/lib/x86 -lpthreadVC2 -Ld:/Qt/libjpeg-turbo/lib/x86 -ljpeg8 + +unix:INCLUDEPATH+=/usr/local/include /usr/local/include/libxml2 +unix:CONFIG+=staticlib + +INCLUDEPATH+=. + +HEADERS = ArwDecoder.h BitPumpJPEG.h BitPumpMSB.h BitPumpMSB32.h \ + BitPumpPlain.h BlackArea.h ByteStream.h ByteStreamSwap.h \ + Camera.h CameraMetaData.h CameraMetadataException.h \ + CameraSensorInfo.h ColorFilterArray.h Common.h Cr2Decoder.h \ + DngDecoder.h DngDecoderSlices.h DngOpcodes.h FileIOException.h \ + FileMap.h FileReader.h IOException.h LJpegDecompressor.h \ + LJpegPlain.h NefDecoder.h NikonDecompressor.h OrfDecoder.h \ + PefDecoder.h PentaxDecompressor.h Point.h RawDecoder.h \ + RawDecoderException.h RawImage.h RawParser.h Rw2Decoder.h SrwDecoder.h \ + StdAfx.h TiffEntry.h TiffEntryBE.h TiffIFD.h TiffIFDBE.h TiffParser.h \ + TiffParserException.h TiffParserHeaderless.h TiffParserOlympus.h \ + TiffTag.h dlldef.h + +SOURCES = \ + ArwDecoder.cpp BitPumpJPEG.cpp BitPumpMSB.cpp BitPumpMSB32.cpp \ + BitPumpPlain.cpp BlackArea.cpp ByteStream.cpp ByteStreamSwap.cpp \ + Camera.cpp CameraMetaData.cpp CameraMetadataException.cpp \ + CameraSensorInfo.cpp ColorFilterArray.cpp Common.cpp Cr2Decoder.cpp \ + DngDecoder.cpp DngDecoderSlices.cpp DngOpcodes.cpp \ + FileIOException.cpp FileMap.cpp FileReader.cpp IOException.cpp \ + LJpegDecompressor.cpp LJpegPlain.cpp NefDecoder.cpp \ + NikonDecompressor.cpp OrfDecoder.cpp PefDecoder.cpp \ + PentaxDecompressor.cpp RawDecoder.cpp RawDecoderException.cpp \ + RawImage.cpp RawImageDataFloat.cpp RawImageDataU16.cpp RawParser.cpp \ + Rw2Decoder.cpp SrwDecoder.cpp TiffEntry.cpp TiffEntryBE.cpp\ + TiffIFD.cpp TiffIFDBE.cpp TiffParser.cpp TiffParserException.cpp \ + TiffParserHeaderless.cpp TiffParserOlympus.cpp + +DEFINES+=RAWSPEED_BUILDLIB +CONFIG-=qt +win32:QMAKE_CXXFLAGS+=/O2 /arch:SSE2 /fp:fast /MP diff --git a/RawSpeed/rawspeed-test.pro b/RawSpeed/rawspeed-test.pro new file mode 100644 index 0000000..518aa98 --- /dev/null +++ b/RawSpeed/rawspeed-test.pro @@ -0,0 +1,21 @@ +TEMPLATE=app +TARGET=rawspeed-test + +SOURCES=RawSpeed.cpp + +win32:CONFIG(debug,debug|release) { + LIBDIR = debug +} else { + LIBDIR = release +} + + +INCLUDEPATH+=../ + +unix:INCLUDEPATH+=/usr/local/include /usr/local/include/libxml2 +unix:LIBS+=-L. -lrawspeed -L/usr/local/lib -lxml2 -ljpeg +win32:LIBS+=-L$$LIBDIR -llibrawspeed +win32:LIBS+=-Ld:/Qt/iconv/lib/x86 -liconv -Ld:/Qt/libxml2/lib/x86 -llibxml2a -Ld:/Qt/pthreads/lib/x86 -lpthreadVC2 -Ld:/Qt/libjpeg-turbo/lib/x86 -ljpeg8 +win32:INCLUDEPATH+=d:/Qt/iconv/include d:/Qt/libxml2/include/libxml2 d:/Qt/pthreads/include d:/Qt/libjpeg-turbo/include +CONFIG-=qt +CONFIG+=console diff --git a/RawSpeed/rawspeed.pro b/RawSpeed/rawspeed.pro new file mode 100644 index 0000000..df2a0b9 --- /dev/null +++ b/RawSpeed/rawspeed.pro @@ -0,0 +1,3 @@ +TEMPLATE=subdirs +SUBDIRS=rawspeed-lib.pro rawspeed-test.pro + LibRaw-0.18.8/RawSpeed/rawspeed.uncompressed-color-dng.patch000066400000000000000000000012121324423227700237270ustar00rootroot00000000000000diff --git a/RawSpeed/DngDecoder.cpp b/RawSpeed/DngDecoder.cpp index 56c701b..98f2474 100644 --- a/RawSpeed/DngDecoder.cpp +++ b/RawSpeed/DngDecoder.cpp @@ -216,7 +216,7 @@ RawImage DngDecoder::decodeRawInternal() { if (bps != 8 && bps != 16) big_endian = true; try { - readUncompressedRaw(in, size, pos, width*bps / 8, bps, big_endian ? BitOrder_Jpeg : BitOrder_Plain); + readUncompressedRaw(in, size, pos, mRaw->getCpp()*width*bps / 8, bps, big_endian ? BitOrder_Jpeg : BitOrder_Plain); } catch(IOException &ex) { if (i > 0) mRaw->setError(ex.what()); LibRaw-0.18.8/RawSpeed/rawspeed.win32-dll.patch000066400000000000000000000102431324423227700210550ustar00rootroot00000000000000diff --git a/RawSpeed/Camera.h b/RawSpeed/Camera.h index 7b3045d..4363c1b 100644 --- a/RawSpeed/Camera.h +++ b/RawSpeed/Camera.h @@ -6,6 +6,7 @@ #include #include "BlackArea.h" #include "CameraMetadataException.h" +#include "dlldef.h" /* RawSpeed - RAW file decoder. @@ -30,7 +31,7 @@ namespace RawSpeed { -class Camera +class DllDef Camera { public: Camera(xmlDocPtr doc, xmlNodePtr cur); diff --git a/RawSpeed/CameraMetaData.h b/RawSpeed/CameraMetaData.h index 616b2bb..c6b8031 100644 --- a/RawSpeed/CameraMetaData.h +++ b/RawSpeed/CameraMetaData.h @@ -27,9 +27,10 @@ http://www.klauspost.com */ +#include "dlldef.h" namespace RawSpeed { -class CameraMetaData +class DllDef CameraMetaData { public: CameraMetaData(); diff --git a/RawSpeed/CameraMetadataException.h b/RawSpeed/CameraMetadataException.h index 55a2814..52d5ea1 100644 --- a/RawSpeed/CameraMetadataException.h +++ b/RawSpeed/CameraMetadataException.h @@ -22,10 +22,11 @@ #ifndef CAMERA_METADATA_EXCEPTION_H #define CAMERA_METADATA_EXCEPTION_H +#include "dlldef.h" namespace RawSpeed { -void ThrowCME(const char* fmt, ...); +void DllDef ThrowCME(const char* fmt, ...); class CameraMetadataException : public std::runtime_error diff --git a/RawSpeed/FileMap.h b/RawSpeed/FileMap.h index 5c15918..bcd2a79 100644 --- a/RawSpeed/FileMap.h +++ b/RawSpeed/FileMap.h @@ -25,6 +25,7 @@ */ #include "IOException.h" +#include "dlldef.h" namespace RawSpeed { @@ -36,7 +37,7 @@ namespace RawSpeed { * This can also be done as a MemMap * *****************************/ -class FileMap +class DllDef FileMap { public: FileMap(uint32 _size); // Allocates the data array itself diff --git a/RawSpeed/FileReader.h b/RawSpeed/FileReader.h index 7448ec2..fb42ac0 100644 --- a/RawSpeed/FileReader.h +++ b/RawSpeed/FileReader.h @@ -24,10 +24,11 @@ #include "FileIOException.h" #include "FileMap.h" +#include "dlldef.h" namespace RawSpeed { -class FileReader +class DllDef FileReader { public: FileReader(LPCWSTR filename); diff --git a/RawSpeed/RawDecoder.h b/RawSpeed/RawDecoder.h index a6c4708..b35cae5 100644 --- a/RawSpeed/RawDecoder.h +++ b/RawSpeed/RawDecoder.h @@ -9,6 +9,7 @@ #include "BitPumpPlain.h" #include "CameraMetaData.h" #include "TiffIFD.h" +#include "dlldef.h" /* RawSpeed - RAW file decoder. @@ -48,7 +49,7 @@ class RawDecoderThread RawDecoder* parent; }; -class RawDecoder +class DllDef RawDecoder { public: /* Construct decoder instance - FileMap is a filemap of the file to be decoded */ diff --git a/RawSpeed/RawImage.h b/RawSpeed/RawImage.h index 5741760..74cea96 100644 --- a/RawSpeed/RawImage.h +++ b/RawSpeed/RawImage.h @@ -26,13 +26,15 @@ http://www.klauspost.com */ +#include "dlldef.h" + namespace RawSpeed { class RawImage; class RawImageWorker; typedef enum {TYPE_USHORT16, TYPE_FLOAT32} RawImageType; -class RawImageData +class DllDef RawImageData { friend class RawImageWorker; public: @@ -125,7 +127,7 @@ protected: int end_y; }; - class RawImage { + class DllDef RawImage { public: static RawImage create(RawImageType type = TYPE_USHORT16); static RawImage create(iPoint2D dim, RawImageType type = TYPE_USHORT16, uint32 componentsPerPixel = 1); diff --git a/RawSpeed/RawParser.h b/RawSpeed/RawParser.h index 9ef86e3..1b3cb83 100644 --- a/RawSpeed/RawParser.h +++ b/RawSpeed/RawParser.h @@ -25,10 +25,11 @@ #include "FileMap.h" #include "RawDecoder.h" +#include "dlldef.h" namespace RawSpeed { -class RawParser +class DllDef RawParser { public: RawParser(FileMap* input); diff --git a/RawSpeed/dlldef.h b/RawSpeed/dlldef.h new file mode 100644 index 0000000..c806451 --- /dev/null +++ b/RawSpeed/dlldef.h @@ -0,0 +1,20 @@ +#ifndef DLLDEF_H +#define DLLDEF_H + +#ifdef WIN32 +#ifdef _MSC_VER +#pragma warning( disable: 4251 ) +#endif +#ifdef RAWSPEED_NODLL +# define DllDef +#else +# ifdef RAWSPEED_BUILDLIB +# define DllDef __declspec( dllexport ) +# else +# define DllDef __declspec( dllimport ) +# endif +#endif +#else +# define DllDef +#endif +#endif LibRaw-0.18.8/RawSpeed/rawspeed_xmldata.cpp000066400000000000000000004757671324423227700205720ustar00rootroot00000000000000const char *_rawspeed_data_xml[]={ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "]>\n", "\n", "\n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " Canon EOS REBEL SL1\n", " Canon EOS Kiss X7\n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " Canon EOS DIGITAL REBEL XT\n", " Canon EOS Kiss Digital N\n", " Canon EOS 350D\n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " Canon EOS DIGITAL REBEL XSi\n", " Canon EOS Kiss Digital X2\n", " Canon EOS Kiss X2\n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " Canon EOS REBEL T5i\n", " Canon EOS Kiss X7i\n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " Canon EOS REBEL T1i\n", " Canon EOS Kiss X3\n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " Canon EOS REBEL T2i\n", " Canon EOS Kiss X4\n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " Canon EOS REBEL T3i\n", " Canon EOS Kiss X5\n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " Canon EOS REBEL T4i\n", " Canon EOS Kiss X6i\n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " Canon EOS DIGITAL REBEL XS\n", " Canon EOS Kiss Digital F\n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " Canon EOS REBEL T3\n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " Canon EOS REBEL T5\n", " Canon EOS Kiss X70\n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " Canon EOS DIGITAL REBEL XTi\n", " Canon EOS Kiss Digital X\n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " RED\n", " BLUE\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " RED\n", " BLUE\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " NIKON D800E\n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", "\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " RED\n", " BLUE\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " RED\n", " BLUE\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\t\t\t\t\n", "\t\t\t\t\t\t\t\t\n", "\t\t\t\t\t\t\t\t\t\t\t\tRED\n", "\t\t\t\t\t\t\t\t\t\t\t\tGREEN\n", "\t\t\t\t\t\t\t\t\t\t\t\tGREEN\n", "\t\t\t\t\t\t\t\t\t\t\t\tBLUE\n", "\t\t\t\t\t\t\t\t\n", "\t\t\t\t\t\t\t\t\n", "\t\t\t\t\t\t\t\t\n", "\t\t\t\t\n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " RED\n", " BLUE\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " RED\n", " BLUE\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " RED\n", " BLUE\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " RED\n", " BLUE\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " DMC-FZ38\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " DMC-FZ38\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " DMC-FZ40\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " DMC-FZ40\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " DMC-FZ72\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " DMC-FZ72\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " RED\n", " BLUE\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " RED\n", " BLUE\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " RED\n", " BLUE\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " RED\n", " BLUE\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " RED\n", " BLUE\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " GREEN\n", " RED\n", " BLUE\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " RED\n", " BLUE\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " RED\n", " BLUE\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " RED\n", " BLUE\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " RED\n", " BLUE\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " RED\n", " BLUE\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " RED\n", " BLUE\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " RED\n", " BLUE\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " RED\n", " BLUE\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " RED\n", " BLUE\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " RED\n", " BLUE\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " RED\n", " BLUE\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " RED\n", " BLUE\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " RED\n", " BLUE\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " RED\n", " BLUE\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " RED\n", " BLUE\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " RED\n", " BLUE\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " RED\n", " BLUE\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " BLUE\n", " RED\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " GREEN\n", " RED\n", " BLUE\n", " GREEN\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " BLUE\n", " GREEN\n", " GREEN\n", " RED\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " RED\n", " GREEN\n", " GREEN\n", " BLUE\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", 0 }; LibRaw-0.18.8/bin/000077500000000000000000000000001324423227700135465ustar00rootroot00000000000000LibRaw-0.18.8/bin/.keep_me000066400000000000000000000000021324423227700151440ustar00rootroot00000000000000 LibRaw-0.18.8/buildIncr.pl000077500000000000000000000002671324423227700152560ustar00rootroot00000000000000#!/usr/bin/perl open F,"libraw_build.h"; $l1 = ; $l2 = ; $l3 = ; @a = split(/\s+/,$l2); $a[2]++; $l2 = "$a[0] $a[1] $a[2]\n"; open F,">libraw_build.h"; print F "$l1$l2$l3";LibRaw-0.18.8/buildfiles/000077500000000000000000000000001324423227700151205ustar00rootroot00000000000000LibRaw-0.18.8/buildfiles/4channels.pro000066400000000000000000000001511324423227700175160ustar00rootroot00000000000000include (libraw-common.pro) win32:LIBS+=libraw.lib unix:LIBS+=-lraw SOURCES=../samples/4channels.cpp LibRaw-0.18.8/buildfiles/4channels.vcproj000066400000000000000000000074041324423227700202310ustar00rootroot00000000000000 LibRaw-0.18.8/buildfiles/dcraw_emu.pro000066400000000000000000000001511324423227700176050ustar00rootroot00000000000000include (libraw-common.pro) win32:LIBS+=libraw.lib unix:LIBS+=-lraw SOURCES=../samples/dcraw_emu.cpp LibRaw-0.18.8/buildfiles/dcraw_emu.vcproj000066400000000000000000000074041324423227700203200ustar00rootroot00000000000000 LibRaw-0.18.8/buildfiles/dcraw_half.pro000066400000000000000000000001501324423227700177300ustar00rootroot00000000000000include (libraw-common.pro) win32:LIBS+=libraw.lib unix:LIBS+=-lraw SOURCES=../samples/dcraw_half.c LibRaw-0.18.8/buildfiles/dcraw_half.vcproj000066400000000000000000000074061324423227700204460ustar00rootroot00000000000000 LibRaw-0.18.8/buildfiles/half_mt.pro000066400000000000000000000002411324423227700172510ustar00rootroot00000000000000include (libraw-common.pro) win32:LIBS+=libraw.lib unix:LIBS+=-lraw win32 { SOURCES=../samples/half_mt_win32.c } else { SOURCES=../samples/half_mt.c } LibRaw-0.18.8/buildfiles/half_mt.vcproj000066400000000000000000000074001324423227700177600ustar00rootroot00000000000000 LibRaw-0.18.8/buildfiles/libraw-all.pro000066400000000000000000000003271324423227700176720ustar00rootroot00000000000000TEMPLATE=subdirs SUBDIRS=libraw.pro \ 4channels.pro dcraw_emu.pro dcraw_half.pro half_mt.pro mem_image.pro \ multirender_test.pro postprocessing_benchmark.pro raw-identify.pro simple_dcraw.pro unprocessed_raw.pro LibRaw-0.18.8/buildfiles/libraw-common-lib.pro000066400000000000000000000006561324423227700211630ustar00rootroot00000000000000win32 { !contains(QMAKE_HOST.arch, x86_64) { SUFF="x86" } else { ## Windows x64 (64bit) specific build here SUFF="x86_64" } } CONFIG(debug,debug|release) { win32:OUTD=debug-$$SUFF macx:OUTD=debug } else { win32:OUTD=release-$$SUFF macx:OUTD=release } INCLUDEPATH+=../../LibRaw OBJECTS_DIR = $$OUTD/ MOC_DIR = $$OUTD/ RCC_DIR = $$OUTD/ UI_DIR = $$OUTD/ DESTDIR = $$OUTD/ LIBS+=-L$$OUTD CONFIG+=warn_off LibRaw-0.18.8/buildfiles/libraw-common.pro000066400000000000000000000002011324423227700204010ustar00rootroot00000000000000win32:CONFIG+=console win32:LIBS+=libraw.lib unix:LIBS+=-lraw win32-g++: { LIBS += -lws2_32 } include (libraw-common-lib.pro)LibRaw-0.18.8/buildfiles/libraw.pro000066400000000000000000000026071324423227700171270ustar00rootroot00000000000000TEMPLATE=lib TARGET=libraw INCLUDEPATH+=../ include (libraw-common-lib.pro) # JPEG section (libjpeg is linked later) DEFINES+=USE_JPEG ## RawSpeed section DEFINES+=USE_RAWSPEED INCLUDEPATH+=../../RawSpeed/ win32:INCLUDEPATH+= $$TJDIR/include win32:INCLUDEPATH+=d:/Qt/local/include d:/Qt/local/include/libxml2 win32:LIBS+=-L$$TJDIR/lib$$TJSUFF/$$SUFF -ljpeg win32:LIBS+=-lrawspeed -Ld:/Qt/local/lib/$$SUFF -llibxml2 HEADERS=../libraw/libraw.h \ ../libraw/libraw_alloc.h \ ../libraw/libraw_const.h \ ../libraw/libraw_datastream.h \ ../libraw/libraw_types.h \ ../libraw/libraw_internal.h \ ../libraw/libraw_version.h \ ../internal/defines.h \ ../internal/var_defines.h \ ../internal/libraw_internal_funcs.h win32: { PREPROCESS_FILES=../dcraw/dcraw.c preprocess.name=dcraw.c preprocess preprocess.input=PREPROCESS_FILES preprocess.output+=../internal/dcraw_common_fake.cpp preprocess.commands=..\\win32pre.cmd preprocess.CONFIG+= no_link preprocess.clean= preprocess.variable_out=SOURCES QMAKE_EXTRA_COMPILERS+=preprocess } CONFIG-=qt CONFIG+=warn_off macx: CONFIG+= static x86 x86_64 macx: QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.5 DEFINES+=LIBRAW_BUILDLIB SOURCES+= \ ../internal/dcraw_common.cpp \ ../internal/dcraw_fileio.cpp \ ../internal/demosaic_packs.cpp \ ../src/libraw_cxx.cpp \ ../src/libraw_datastream.cpp \ ../src/libraw_c_api.cpp LibRaw-0.18.8/buildfiles/libraw.vcproj000066400000000000000000000107611324423227700176320ustar00rootroot00000000000000 LibRaw-0.18.8/buildfiles/mem_image.pro000066400000000000000000000001511324423227700175570ustar00rootroot00000000000000include (libraw-common.pro) win32:LIBS+=libraw.lib unix:LIBS+=-lraw SOURCES=../samples/mem_image.cpp LibRaw-0.18.8/buildfiles/mem_image.vcproj000066400000000000000000000074041324423227700202720ustar00rootroot00000000000000 LibRaw-0.18.8/buildfiles/multirender_test.pro000066400000000000000000000001601324423227700212300ustar00rootroot00000000000000include (libraw-common.pro) win32:LIBS+=libraw.lib unix:LIBS+=-lraw SOURCES=../samples/multirender_test.cpp LibRaw-0.18.8/buildfiles/multirender_test.vcproj000066400000000000000000000074361324423227700217500ustar00rootroot00000000000000 LibRaw-0.18.8/buildfiles/postprocessing_benchmark.pro000066400000000000000000000001161324423227700227340ustar00rootroot00000000000000include (libraw-common.pro) SOURCES=../samples/postprocessing_benchmark.cpp LibRaw-0.18.8/buildfiles/postprocessing_benchmark.vcproj000066400000000000000000000075001324423227700234430ustar00rootroot00000000000000 LibRaw-0.18.8/buildfiles/raw-identify.pro000066400000000000000000000001541324423227700202440ustar00rootroot00000000000000include (libraw-common.pro) win32:LIBS+=libraw.lib unix:LIBS+=-lraw SOURCES=../samples/raw-identify.cpp LibRaw-0.18.8/buildfiles/raw-identify.vcproj000066400000000000000000000074201324423227700207520ustar00rootroot00000000000000 LibRaw-0.18.8/buildfiles/simple_dcraw.pro000066400000000000000000000001541324423227700203130ustar00rootroot00000000000000include (libraw-common.pro) win32:LIBS+=libraw.lib unix:LIBS+=-lraw SOURCES=../samples/simple_dcraw.cpp LibRaw-0.18.8/buildfiles/simple_dcraw.vcproj000066400000000000000000000074201324423227700210210ustar00rootroot00000000000000 LibRaw-0.18.8/buildfiles/unprocessed_raw.pro000066400000000000000000000001571324423227700210500ustar00rootroot00000000000000include (libraw-common.pro) win32:LIBS+=libraw.lib unix:LIBS+=-lraw SOURCES=../samples/unprocessed_raw.cpp LibRaw-0.18.8/buildfiles/unprocessed_raw.vcproj000066400000000000000000000074621324423227700215610ustar00rootroot00000000000000 LibRaw-0.18.8/clist2c.pl000077500000000000000000000002241324423227700146770ustar00rootroot00000000000000#!/usr/bin/perl while (<>) { chomp; s/^\s+//; s/^\s+\*\s+//; s/^\s+//; s/\"/\\\"/g; s/\s+$//; print "\"$_\",\n"; } LibRaw-0.18.8/clist2html.pl000077500000000000000000000021651324423227700154270ustar00rootroot00000000000000#!/usr/bin/perl use Data::Dumper; @makes=( "AgfaPhoto", "Canon", "Casio", "Digital Bolex", "Epson", "Fujifilm", "Imacon", "Mamiya", "Minolta", "Motorola", "Kodak", "Konica", "Leica", "Hasselblad", "Nikon", "Nokia", "Olympus", "Pentax", "Phase One", "Ricoh", "Samsung", "Sigma", "Sinar", "Sony" ); MAINLOOP: while(<>) { chomp; $cname = $_; $cname=~s/^\s+//g; $cname=~s/\s+$//g; for my $camera (@makes) { if ($cname=~/\Q$camera\E\s+(.*)/) { $model = $1; push @{$cameralist->{$camera}},$model; next MAINLOOP; } } if($cname=~/(\S+)\s+(.*)/) { ($make,$model) = ($1,$2); push @{$cameralist->{$make}},$model; next MAINLOOP; } push @{$cameralist->{$make}},"NO MODEL"; } my $havenx1=0; print "
    \n"; for my $make (sort keys %$cameralist) { if( $#{$cameralist->{$make}} < 1) { print "
  • $make $cameralist->{$make}->[0]
  • \n"; } else { print "
  • $make\n
      \n"; for my $model (@{$cameralist->{$make}}) { print "
    • $model
    • \n"; } print "
    \n
  • \n"; } } print "
\n"; LibRaw-0.18.8/configure.ac000066400000000000000000000156021324423227700152700ustar00rootroot00000000000000# Initialization AC_INIT([LibRaw], m4_esyscmd([./version.sh]), [info@libraw.org], [], [http://www.libraw.org]) AM_INIT_AUTOMAKE([foreign no-define]) #AM_SILENT_RULES([yes]) AC_CONFIG_MACRO_DIR([m4]) # Tools to use AC_PROG_CXX AC_PROG_CC AC_PROG_LIBTOOL AC_ENABLE_SHARED AC_ENABLE_STATIC AC_LIBTOOL_WIN32_DLL AC_LIBTOOL_SETUP AC_SUBST(LIBTOOL_DEPS) # Config files to generate AC_CONFIG_FILES([ Makefile libraw.pc libraw_r.pc ]) # check if we want OpenMP support AC_ARG_ENABLE([openmp], [ --enable-openmp Enable OpenMP support], [case "${enableval}" in yes) openmp=true ;; no) openmp=false ;; *) AC_MSG_ERROR([bad value ${enableval} for --enable-openmp]) ;; esac],[openmp=true]) if test x$openmp = xtrue ; then AX_OPENMP([ CXXFLAGS="$CXXFLAGS $OPENMP_CFLAGS" CFLAGS="$CFLAGS $OPENMP_CFLAGS" AC_SUBST([PC_OPENMP],[" $OPENMP_CFLAGS"]) ],[ AC_MSG_WARN([OpenMP support cannot be enabled because your system doesn't support it.]) ]) fi # check for libjpeg v8 AC_ARG_ENABLE([jpeg], [ --enable-jpeg Enable JPEG support for Lossy compressed DNG files], [case "${enableval}" in yes) jpeg=true ;; no) jpeg=false ;; *) AC_MSG_ERROR([bad value ${enableval} for --enable-jpeg]) ;; esac],[jpeg=true]) if test x$jpeg = xtrue; then AC_CHECK_LIB([jpeg], [jpeg_mem_src], [ AC_CHECK_HEADERS([jpeglib.h], [ CPPFLAGS="$CPPFLAGS -DUSE_JPEG -DUSE_JPEG8" LIBS="$LIBS -ljpeg" ], AC_MSG_WARN([no jpeg headers found])) ], AC_MSG_WARN([libjpeg not found]) ) fi # check for Jasper (JPEG2000) support AC_ARG_ENABLE([jasper], [ --enable-jasper Enable Jasper (JPEG2000) support for RedCine files], [case "${enableval}" in yes) jasper=true ;; no) jasper=false ;; *) AC_MSG_ERROR([bad value ${enableval} for --enable-jasper]) ;; esac],[jasper=true]) if test x$jasper = xtrue; then AC_CHECK_LIB([jasper], [jas_init], [ AC_CHECK_HEADERS([jasper/jasper.h], [ CPPFLAGS="$CPPFLAGS -DUSE_JASPER" LIBS="$LIBS -ljasper" ], AC_MSG_WARN([no jasper headers found])) ], AC_MSG_WARN([libjasper not found]) ) fi # check if we want LCMS support AC_ARG_ENABLE([lcms], [ --enable-lcms Enable LCMS support], [case "${enableval}" in yes) lcms=true ;; no) lcms=false ;; *) AC_MSG_ERROR([bad value ${enableval} for --enable-lcms]) ;; esac],[lcms=true]) if test x$lcms = xtrue; then PKG_CHECK_MODULES([LCMS2],[lcms2],[ CPPFLAGS="$CPPFLAGS $LCMS2_CFLAGS -DUSE_LCMS2" LIBS="$LIBS $LCMS2_LIBS" AC_SUBST([PACKAGE_REQUIRES],[lcms2]) ],[ PKG_CHECK_MODULES([LCMS],[lcms],[ CPPFLAGS="$CPPFLAGS $LCMS_CFLAGS -DUSE_LCMS" LIBS="$LIBS $LCMS_LIBS" AC_SUBST([PACKAGE_REQUIRES],[lcms]) ],[ AC_MSG_WARN([LCMS support cannot be enabled]) ]) ]) fi # check if we want build examples AC_ARG_ENABLE([examples], [ --enable-examples Enable building of examples], [case "${enableval}" in yes) examples=true ;; no) examples=false ;; *) AC_MSG_ERROR([bad value ${enableval} for --enable-examples]) ;; esac],[examples=true]) AM_CONDITIONAL([EXAMPLES], [test x$examples = xtrue]) # LibRaw-demosaic-pack-gpl2 AC_ARG_ENABLE([demosaic-pack-gpl2], [ --enable-demosaic-pack-gpl2 Enable LibRaw demosaic pack/GPL2 ], [case "${enableval}" in yes) dp2=true ;; no) dp2=false ;; *) dp2=true; dp2dir=${enableval} ;; esac],[dp2=true]) if test x$dp2 = xtrue ; then if test x$dp2dir = x ; then if test -f ./LibRaw-demosaic-pack-GPL2/afd_interpolate_pl.c ; then # Directory within LibRaw source tree. echo "Activated LibRaw demosaic pack/GPL2 in current dir" CPPFLAGS="$CPPFLAGS -I./LibRaw-demosaic-pack-GPL2 -DLIBRAW_DEMOSAIC_PACK_GPL2" else lcount=`find .. -type d -name 'LibRaw-demosaic*GPL2*' | wc -l` if test $lcount -eq 1 ; then pdir=`find .. -type d -name 'LibRaw-demosaic*GPL2*' | head -1` if test -f ${pdir}/afd_interpolate_pl.c ; then echo "Activated LibRaw demosaic pack/GPL2 in $pdir" CPPFLAGS="$CPPFLAGS -I${pdir} -DLIBRAW_DEMOSAIC_PACK_GPL2" else AC_MSG_WARN([Unable to find working LibRaw-demosaic-pack-GPL2 in ${pdir}, disabling the feature.\n Use --enable-demosaic-pack-gpl2=directory to override]); fi else AC_MSG_WARN([Unable to find working LibRaw-demosaic-pack-GPL2 in ${pdir}, disabling the feature. Use --enable-demosaic-pack-gpl2=directory to override]); fi fi else # directory set manually if test -f ${dp2dir}/afd_interpolate_pl.c ; then echo "Activated LibRaw demosaic pack/GPL2 in $dp2dir" CPPFLAGS="$CPPFLAGS -I${dp2dir} -DLIBRAW_DEMOSAIC_PACK_GPL2" else AC_MSG_ERROR([${dp2dir} does not contain LibRaw-demosaic-pack-GPL2]); fi fi fi # LibRaw-demosaic-pack-gpl3 AC_ARG_ENABLE([demosaic-pack-gpl3], [ --enable-demosaic-pack-gpl3 Enable LibRaw demosaic pack/GPL3 ], [case "${enableval}" in yes) dp3=true ;; no) dp3=false ;; *) dp3=true; dp3dir=${enableval} ;; esac],[dp3=true]) if test x$dp3 = xtrue ; then if test x$dp3dir = x ; then if test -f ./LibRaw-demosaic-pack-GPL3/CA_correct_RT.cc ; then # Directory within LibRaw source tree. echo "Activated LibRaw demosaic pack/GPL3 in current dir" CPPFLAGS="$CPPFLAGS -I./LibRaw-demosaic-pack-GPL3 -DLIBRAW_DEMOSAIC_PACK_GPL3" else lcount=`find .. -type d -name 'LibRaw-demosaic*GPL3*' | wc -l` if test $lcount -eq 1 ; then pdir=`find .. -type d -name 'LibRaw-demosaic*GPL3*'|head -1` if test -f ${pdir}/CA_correct_RT.cc ; then echo "Activated LibRaw demosaic pack/GPL3 in $pdir" CPPFLAGS="$CPPFLAGS -I${pdir} -DLIBRAW_DEMOSAIC_PACK_GPL3" else AC_MSG_WARN([Unable to find working LibRaw-demosaic-pack-GPL3 in ${pdir}, disabling the feature.\n Use --enable-demosaic-pack-gpl3=directory to override]); fi else AC_MSG_WARN([Unable to find working LibRaw-demosaic-pack-GPL3 in ${pdir}, disabling the feature. Use --enable-demosaic-pack-gpl3=directory to override]); fi fi else # directory set manually if test -f ${dp3dir}/CA_correct_RT.cc ; then echo "Activated LibRaw demosaic pack/GPL3 in $dp3dir" CPPFLAGS="$CPPFLAGS -I${dp3dir} -DLIBRAW_DEMOSAIC_PACK_GPL3" else AC_MSG_ERROR([${dp3dir} does not contain LibRaw-demosaic-pack-GPL3]); fi fi fi LIBS="$LIBS -lm" AC_SUBST([LIBRAW_SHLIB_VERSION],m4_esyscmd([./shlib-version.sh])) AC_SUBST([LIBRAW_RELEASE_VERSION],m4_esyscmd([./version.sh])) AC_OUTPUT LibRaw-0.18.8/dcraw/000077500000000000000000000000001324423227700140765ustar00rootroot00000000000000LibRaw-0.18.8/dcraw/.gdbinit000066400000000000000000000000421324423227700155130ustar00rootroot00000000000000set args -s 5 -v test.cine b main LibRaw-0.18.8/dcraw/dcraw.1.html000066400000000000000000000221721324423227700162270ustar00rootroot00000000000000 Manpage of dcraw

dcraw

Section: User Commands (1)
Updated: March 3, 2015
Index Return to Main Contents
 

NAME

dcraw - command-line decoder for raw digital photos  

SYNOPSIS

dcraw [OPTION]... [FILE]...  

DESCRIPTION

dcraw decodes raw photos, displays metadata, and extracts thumbnails.  

GENERAL OPTIONS

-v
Print verbose messages, not just warnings and errors.
-c
Write decoded images or thumbnails to standard output.
-e
Extract the camera-generated thumbnail, not the raw image. You'll get either a JPEG or a PPM file, depending on the camera.
-z
Change the access and modification times of an AVI, JPEG, TIFF or raw file to when the photo was taken, assuming that the camera clock was set to Universal Time.
-i
Identify files but don't decode them. Exit status is 0 if dcraw can decode the last file, 1 if it can't. -i -v shows metadata.
dcraw cannot decode JPEG files!!
 

REPAIR OPTIONS

-I
Read the raw pixels from standard input in CPU byte order with no header. Use dcraw -E -4 to get the raw pixel values.
-P deadpixels.txt
Read the dead pixel list from this file instead of ".badpixels". See FILES for a description of the format.
-K darkframe.pgm
Subtract a dark frame from the raw data. To generate a dark frame, shoot a raw photo with no light and do dcraw -D -4 -j -t 0.
-k darkness
When shadows appear foggy, you need to raise the darkness level. To measure this, apply pamsumm -mean to the dark frame generated above.
-S saturation
When highlights appear pink, you need to lower the saturation level. To measure this, take a picture of something shiny and do dcraw -D -4 -j -c photo.raw | pamsumm -max
The default darkness and saturation are usually correct.
-n noise_threshold
Use wavelets to erase noise while preserving real detail. The best threshold should be somewhere between 100 and 1000.
-C red_mag blue_mag
Enlarge the raw red and blue layers by the given factors, typically 0.999 to 1.001, to correct chromatic aberration.
-H 0
Clip all highlights to solid white (default).
-H 1
Leave highlights unclipped in various shades of pink.
-H 2
Blend clipped and unclipped values together for a gradual fade to white.
-H 3+
Reconstruct highlights. Low numbers favor whites; high numbers favor colors. Try -H 5 as a compromise. If that's not good enough, do -H 9, cut out the non-white highlights, and paste them into an image generated with -H 3.
 

COLOR OPTIONS

By default, dcraw uses a fixed white balance based on a color chart illuminated with a standard D65 lamp.
-w
Use the white balance specified by the camera. If this is not found, print a warning and use another method.
-a
Calculate the white balance by averaging the entire image.
-A left top width height
Calculate the white balance by averaging a rectangular area. First do dcraw -j -t 0 and select an area of neutral grey color.
-r mul0 mul1 mul2 mul3
Specify your own raw white balance. These multipliers can be cut and pasted from the output of dcraw -v.
+M or -M
Use (or don't use) any color matrix from the camera metadata. The default is +M if -w is set or the photo is in DNG format, -M otherwise. Besides DNG, this option only affects Olympus, Leaf, and Phase One cameras.
-o [0-5]
Select the output colorspace when the -p option is not used:

0   Raw color (unique to each camera)
1   sRGB D65 (default)
2   Adobe RGB (1998) D65
3   Wide Gamut RGB D65
4   Kodak ProPhoto RGB D65
5   XYZ

-p camera.icm [ -o output.icm ]
Use ICC profiles to define the camera's raw colorspace and the desired output colorspace (sRGB by default).
-p embed
Use the ICC profile embedded in the raw photo.
 

INTERPOLATION OPTIONS

-d
Show the raw data as a grayscale image with no interpolation. Good for photographing black-and-white documents.
-D
Same as -d, but with the original unscaled pixel values.
-E
Same as -D, but masked pixels are not cropped.
-h
Output a half-size color image. Twice as fast as -q 0.
-q 0
Use high-speed, low-quality bilinear interpolation.
-q 1
Use Variable Number of Gradients (VNG) interpolation.
-q 2
Use Patterned Pixel Grouping (PPG) interpolation.
-q 3
Use Adaptive Homogeneity-Directed (AHD) interpolation.
-f
Interpolate RGB as four colors. Use this if the output shows false 2x2 meshes with VNG or mazes with AHD.
-m number_of_passes
After interpolation, clean up color artifacts by repeatedly applying a 3x3 median filter to the R-G and B-G channels.
 

OUTPUT OPTIONS

By default, dcraw writes PGM/PPM/PAM with 8-bit samples, a BT.709 gamma curve, a histogram-based white level, and no metadata.
-W
Use a fixed white level, ignoring the image histogram.
-b brightness
Divide the white level by this number, 1.0 by default.
-g power toe_slope
Set the gamma curve, by default BT.709 (-g 2.222 4.5). If you prefer sRGB gamma, use -g 2.4 12.92. For a simple power curve, set the toe slope to zero.
-6
Write sixteen bits per sample instead of eight.
-4
Linear 16-bit, same as -6 -W -g 1 1.
-T
Write TIFF with metadata instead of PGM/PPM/PAM.
-t [0-7,90,180,270]
Flip the output image. By default, dcraw applies the flip specified by the camera. -t 0 disables all flipping.
-j
For Fuji Super CCD cameras, show the image tilted 45 degrees. For cameras with non-square pixels, do not stretch the image to its correct aspect ratio. In any case, this option guarantees that each output pixel corresponds to one raw pixel.
-s [0..N-1] or -s all
If a file contains N raw images, choose one or "all" to decode. For example, Fuji Super CCD SR cameras generate a second image underexposed four stops to show detail in the highlights.
 

FILES

:./.badpixels, ../.badpixels, ../../.badpixels, ...
List of your camera's dead pixels, so that dcraw can interpolate around them. Each line specifies the column, row, and UNIX time of death for one pixel. For example:

 962   91 1028350000  # died between August 1 and 4, 2002
1285 1067 0           # don't know when this pixel died

These coordinates are before any stretching or rotation, so use dcraw -j -t 0 to locate dead pixels.

 

SEE ALSO

pgm(5), ppm(5), pam(5), pamsumm(1), pnmgamma(1), pnmtotiff(1), pnmtopng(1), gphoto2(1), cjpeg(1), djpeg(1)  

AUTHOR

Written by David Coffin, dcoffin a cybercom o net


 

Index

NAME
SYNOPSIS
DESCRIPTION
GENERAL OPTIONS
REPAIR OPTIONS
COLOR OPTIONS
INTERPOLATION OPTIONS
OUTPUT OPTIONS
FILES
SEE ALSO
AUTHOR

This document was created by man2html, using the manual pages.
Time: 02:31:53 GMT, May 25, 2015 LibRaw-0.18.8/dcraw/dcraw.c000066400000000000000000021734711324423227700153610ustar00rootroot00000000000000#ifndef IGNOREALL /* dcraw.c -- Dave Coffin's raw photo decoder Copyright 1997-2015 by Dave Coffin, dcoffin a cybercom o net This is a command-line ANSI C program to convert raw photos from any digital camera on any computer running any operating system. No license is required to download and use dcraw.c. However, to lawfully redistribute dcraw, you must either (a) offer, at no extra charge, full source code* for all executable files containing RESTRICTED functions, (b) distribute this code under the GPL Version 2 or later, (c) remove all RESTRICTED functions, re-implement them, or copy them from an earlier, unrestricted Revision of dcraw.c, or (d) purchase a license from the author. The functions that process Foveon images have been RESTRICTED since Revision 1.237. All other code remains free for all uses. *If you have not modified dcraw.c in any way, a link to my homepage qualifies as "full source code". $Revision: 1.476 $ $Date: 2015/05/25 02:29:14 $ */ /*@out DEFINES #ifndef USE_JPEG #define NO_JPEG #endif #ifndef USE_JASPER #define NO_JASPER #endif @end DEFINES */ #define NO_LCMS #define DCRAW_VERBOSE //@out DEFINES #define DCRAW_VERSION "9.26" #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #define _USE_MATH_DEFINES #include #include #include #include #include #include #include #include #include #include #include #include //@end DEFINES #if defined(DJGPP) || defined(__MINGW32__) #define fseeko fseek #define ftello ftell #else #define fgetc getc_unlocked #endif //@out DEFINES #ifdef __CYGWIN__ #include #endif #if defined WIN32 || defined (__MINGW32__) #include #include #pragma comment(lib, "ws2_32.lib") #define snprintf _snprintf #define strcasecmp stricmp #define strncasecmp strnicmp //@end DEFINES typedef __int64 INT64; typedef unsigned __int64 UINT64; //@out DEFINES #else #include #include #include typedef long long INT64; typedef unsigned long long UINT64; #endif #ifdef NODEPS #define NO_JASPER #define NO_JPEG #define NO_LCMS #endif #ifndef NO_JASPER #include /* Decode Red camera movies */ #endif #ifndef NO_JPEG #include /* Decode compressed Kodak DC120 photos */ #endif /* and Adobe Lossy DNGs */ #ifndef NO_LCMS #ifdef USE_LCMS #include /* Support color profiles */ #else #include /* Support color profiles */ #endif #endif #ifdef LOCALEDIR #include #define _(String) gettext(String) #else #define _(String) (String) #endif #ifdef LJPEG_DECODE #error Please compile dcraw.c by itself. #error Do not link it with ljpeg_decode. #endif #ifndef LONG_BIT #define LONG_BIT (8 * sizeof (long)) #endif //@end DEFINES #if !defined(uchar) #define uchar unsigned char #endif #if !defined(ushort) #define ushort unsigned short #endif /* All global variables are defined here, and all functions that access them are prefixed with "CLASS". Note that a thread-safe C++ class cannot have non-const static local variables. */ FILE *ifp, *ofp; short order; const char *ifname; char *meta_data, xtrans[6][6], xtrans_abs[6][6]; char cdesc[5], desc[512], make[64], model[64], model2[64], artist[64],software[64]; float flash_used, canon_ev, iso_speed, shutter, aperture, focal_len; time_t timestamp; off_t strip_offset, data_offset; off_t thumb_offset, meta_offset, profile_offset; unsigned shot_order, kodak_cbpp, exif_cfa, unique_id; unsigned thumb_length, meta_length, profile_length; unsigned thumb_misc, *oprof, fuji_layout, shot_select=0, multi_out=0; unsigned tiff_nifds, tiff_samples, tiff_bps, tiff_compress; unsigned black, maximum, mix_green, raw_color, zero_is_bad; unsigned zero_after_ff, is_raw, dng_version, is_foveon, data_error; unsigned tile_width, tile_length, gpsdata[32], load_flags; unsigned flip, tiff_flip, filters, colors; ushort raw_height, raw_width, height, width, top_margin, left_margin; ushort shrink, iheight, iwidth, fuji_width, thumb_width, thumb_height; ushort *raw_image, (*image)[4], cblack[4102]; ushort white[8][8], curve[0x10000], cr2_slice[3], sraw_mul[4]; double pixel_aspect, aber[4]={1,1,1,1}, gamm[6]={ 0.45,4.5,0,0,0,0 }; float bright=1, user_mul[4]={0,0,0,0}, threshold=0; int mask[8][4]; int half_size=0, four_color_rgb=0, document_mode=0, highlight=0; int verbose=0, use_auto_wb=0, use_camera_wb=0, use_camera_matrix=1; int output_color=1, output_bps=8, output_tiff=0, med_passes=0; int no_auto_bright=0; unsigned greybox[4] = { 0, 0, UINT_MAX, UINT_MAX }; float cam_mul[4], pre_mul[4], cmatrix[3][4], rgb_cam[3][4]; const double xyz_rgb[3][3] = { /* XYZ from RGB */ { 0.412453, 0.357580, 0.180423 }, { 0.212671, 0.715160, 0.072169 }, { 0.019334, 0.119193, 0.950227 } }; const float d65_white[3] = { 0.950456, 1, 1.088754 }; int histogram[4][0x2000]; void (*write_thumb)(), (*write_fun)(); void (*load_raw)(), (*thumb_load_raw)(); jmp_buf failure; struct decode { struct decode *branch[2]; int leaf; } first_decode[2048], *second_decode, *free_decode; struct tiff_ifd { int t_width, t_height, bps, comp, phint, offset, t_flip, samples, bytes; int t_tile_width, t_tile_length,sample_format,predictor; float t_shutter; } tiff_ifd[10]; struct ph1 { int format, key_off, tag_21a; int t_black, split_col, black_col, split_row, black_row; float tag_210; } ph1; #define CLASS //@out DEFINES #define FORC(cnt) for (c=0; c < cnt; c++) #define FORC3 FORC(3) #define FORC4 FORC(4) #define FORCC for (c=0; c < colors && c < 4; c++) #define SQR(x) ((x)*(x)) #define ABS(x) (((int)(x) ^ ((int)(x) >> 31)) - ((int)(x) >> 31)) #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define LIM(x,min,max) MAX(min,MIN(x,max)) #define ULIM(x,y,z) ((y) < (z) ? LIM(x,y,z) : LIM(x,z,y)) #define CLIP(x) LIM((int)(x),0,65535) #define SWAP(a,b) { a=a+b; b=a-b; a=a-b; } #define my_swap(type, i, j) {type t = i; i = j; j = t;} static float fMAX(float a, float b) { return MAX(a,b); } /* In order to inline this calculation, I make the risky assumption that all filter patterns can be described by a repeating pattern of eight rows and two columns Do not use the FC or BAYER macros with the Leaf CatchLight, because its pattern is 16x16, not 2x8. Return values are either 0/1/2/3 = G/M/C/Y or 0/1/2/3 = R/G1/B/G2 PowerShot 600 PowerShot A50 PowerShot Pro70 Pro90 & G1 0xe1e4e1e4: 0x1b4e4b1e: 0x1e4b4e1b: 0xb4b4b4b4: 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 G M G M G M 0 C Y C Y C Y 0 Y C Y C Y C 0 G M G M G M 1 C Y C Y C Y 1 M G M G M G 1 M G M G M G 1 Y C Y C Y C 2 M G M G M G 2 Y C Y C Y C 2 C Y C Y C Y 3 C Y C Y C Y 3 G M G M G M 3 G M G M G M 4 C Y C Y C Y 4 Y C Y C Y C PowerShot A5 5 G M G M G M 5 G M G M G M 0x1e4e1e4e: 6 Y C Y C Y C 6 C Y C Y C Y 7 M G M G M G 7 M G M G M G 0 1 2 3 4 5 0 C Y C Y C Y 1 G M G M G M 2 C Y C Y C Y 3 M G M G M G All RGB cameras use one of these Bayer grids: 0x16161616: 0x61616161: 0x49494949: 0x94949494: 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 B G B G B G 0 G R G R G R 0 G B G B G B 0 R G R G R G 1 G R G R G R 1 B G B G B G 1 R G R G R G 1 G B G B G B 2 B G B G B G 2 G R G R G R 2 G B G B G B 2 R G R G R G 3 G R G R G R 3 B G B G B G 3 R G R G R G 3 G B G B G B */ #define RAW(row,col) \ raw_image[(row)*raw_width+(col)] //@end DEFINES #define FC(row,col) \ (filters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3) //@out DEFINES #define BAYER(row,col) \ image[((row) >> shrink)*iwidth + ((col) >> shrink)][FC(row,col)] #define BAYER2(row,col) \ image[((row) >> shrink)*iwidth + ((col) >> shrink)][fcol(row,col)] //@end DEFINES /* @out COMMON #include #define CLASS LibRaw:: #include "libraw/libraw_types.h" #define LIBRAW_LIBRARY_BUILD #define LIBRAW_IO_REDEFINED #include "libraw/libraw.h" #include "internal/defines.h" #include "internal/var_defines.h" @end COMMON */ //@out COMMON int CLASS fcol (int row, int col) { static const char filter[16][16] = { { 2,1,1,3,2,3,2,0,3,2,3,0,1,2,1,0 }, { 0,3,0,2,0,1,3,1,0,1,1,2,0,3,3,2 }, { 2,3,3,2,3,1,1,3,3,1,2,1,2,0,0,3 }, { 0,1,0,1,0,2,0,2,2,0,3,0,1,3,2,1 }, { 3,1,1,2,0,1,0,2,1,3,1,3,0,1,3,0 }, { 2,0,0,3,3,2,3,1,2,0,2,0,3,2,2,1 }, { 2,3,3,1,2,1,2,1,2,1,1,2,3,0,0,1 }, { 1,0,0,2,3,0,0,3,0,3,0,3,2,1,2,3 }, { 2,3,3,1,1,2,1,0,3,2,3,0,2,3,1,3 }, { 1,0,2,0,3,0,3,2,0,1,1,2,0,1,0,2 }, { 0,1,1,3,3,2,2,1,1,3,3,0,2,1,3,2 }, { 2,3,2,0,0,1,3,0,2,0,1,2,3,0,1,0 }, { 1,3,1,2,3,2,3,2,0,2,0,1,1,0,3,0 }, { 0,2,0,3,1,0,0,1,1,3,3,2,3,2,2,1 }, { 2,1,3,2,3,1,2,1,0,3,0,2,0,2,0,2 }, { 0,3,1,0,0,2,0,3,2,1,3,1,1,3,1,3 } }; if (filters == 1) return filter[(row+top_margin)&15][(col+left_margin)&15]; if (filters == 9) return xtrans[(row+6) % 6][(col+6) % 6]; return FC(row,col); } static size_t local_strnlen(const char *s, size_t n) { const char *p = (const char *)memchr(s, 0, n); return(p ? p-s : n); } /* add OS X version check here ?? */ #define strnlen(a,b) local_strnlen(a,b) #ifdef LIBRAW_LIBRARY_BUILD static int stread(char *buf, size_t len, LibRaw_abstract_datastream *fp) { int r = fp->read(buf,len,1); buf[len-1] = 0; return r; } #define stmread(buf,maxlen,fp) stread(buf,MIN(maxlen,sizeof(buf)),fp) #endif #ifndef __GLIBC__ char *my_memmem (char *haystack, size_t haystacklen, char *needle, size_t needlelen) { char *c; for (c = haystack; c <= haystack + haystacklen - needlelen; c++) if (!memcmp (c, needle, needlelen)) return c; return 0; } #define memmem my_memmem char *my_strcasestr (char *haystack, const char *needle) { char *c; for (c = haystack; *c; c++) if (!strncasecmp(c, needle, strlen(needle))) return c; return 0; } #define strcasestr my_strcasestr #endif #define strbuflen(buf) strnlen(buf,sizeof(buf)-1) //@end COMMON void CLASS merror (void *ptr, const char *where) { if (ptr) return; fprintf (stderr,_("%s: Out of memory in %s\n"), ifname, where); longjmp (failure, 1); } void CLASS derror() { if (!data_error) { fprintf (stderr, "%s: ", ifname); if (feof(ifp)) fprintf (stderr,_("Unexpected end of file\n")); else fprintf (stderr,_("Corrupt data near 0x%llx\n"), (INT64) ftello(ifp)); } data_error++; } //@out COMMON ushort CLASS sget2 (uchar *s) { if (order == 0x4949) /* "II" means little-endian */ return s[0] | s[1] << 8; else /* "MM" means big-endian */ return s[0] << 8 | s[1]; } // DNG was written by: #define CameraDNG 1 #define AdobeDNG 2 #ifdef LIBRAW_LIBRARY_BUILD static int getwords(char *line, char *words[], int maxwords,int maxlen) { line[maxlen-1] = 0; char *p = line; int nwords = 0; while(1) { while(isspace(*p)) p++; if(*p == '\0') return nwords; words[nwords++] = p; while(!isspace(*p) && *p != '\0') p++; if(*p == '\0') return nwords; *p++ = '\0'; if(nwords >= maxwords) return nwords; } } static ushort saneSonyCameraInfo(uchar a, uchar b, uchar c, uchar d, uchar e, uchar f){ if ((a >> 4) > 9) return 0; else if ((a & 0x0f) > 9) return 0; else if ((b >> 4) > 9) return 0; else if ((b & 0x0f) > 9) return 0; else if ((c >> 4) > 9) return 0; else if ((c & 0x0f) > 9) return 0; else if ((d >> 4) > 9) return 0; else if ((d & 0x0f) > 9) return 0; else if ((e >> 4) > 9) return 0; else if ((e & 0x0f) > 9) return 0; else if ((f >> 4) > 9) return 0; else if ((f & 0x0f) > 9) return 0; return 1; } static ushort bcd2dec(uchar data){ if ((data >> 4) > 9) return 0; else if ((data & 0x0f) > 9) return 0; else return (data >> 4) * 10 + (data & 0x0f); } static uchar SonySubstitution[257] = "\x00\x01\x32\xb1\x0a\x0e\x87\x28\x02\xcc\xca\xad\x1b\xdc\x08\xed\x64\x86\xf0\x4f\x8c\x6c\xb8\xcb\x69\xc4\x2c\x03\x97\xb6\x93\x7c\x14\xf3\xe2\x3e\x30\x8e\xd7\x60\x1c\xa1\xab\x37\xec\x75\xbe\x23\x15\x6a\x59\x3f\xd0\xb9\x96\xb5\x50\x27\x88\xe3\x81\x94\xe0\xc0\x04\x5c\xc6\xe8\x5f\x4b\x70\x38\x9f\x82\x80\x51\x2b\xc5\x45\x49\x9b\x21\x52\x53\x54\x85\x0b\x5d\x61\xda\x7b\x55\x26\x24\x07\x6e\x36\x5b\x47\xb7\xd9\x4a\xa2\xdf\xbf\x12\x25\xbc\x1e\x7f\x56\xea\x10\xe6\xcf\x67\x4d\x3c\x91\x83\xe1\x31\xb3\x6f\xf4\x05\x8a\x46\xc8\x18\x76\x68\xbd\xac\x92\x2a\x13\xe9\x0f\xa3\x7a\xdb\x3d\xd4\xe7\x3a\x1a\x57\xaf\x20\x42\xb2\x9e\xc3\x8b\xf2\xd5\xd3\xa4\x7e\x1f\x98\x9c\xee\x74\xa5\xa6\xa7\xd8\x5e\xb0\xb4\x34\xce\xa8\x79\x77\x5a\xc1\x89\xae\x9a\x11\x33\x9d\xf5\x39\x19\x65\x78\x16\x71\xd2\xa9\x44\x63\x40\x29\xba\xa0\x8f\xe4\xd6\x3b\x84\x0d\xc2\x4e\x58\xdd\x99\x22\x6b\xc9\xbb\x17\x06\xe5\x7d\x66\x43\x62\xf6\xcd\x35\x90\x2e\x41\x8d\x6d\xaa\x09\x73\x95\x0c\xf1\x1d\xde\x4c\x2f\x2d\xf7\xd1\x72\xeb\xef\x48\xc7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"; ushort CLASS sget2Rev(uchar *s) // specific to some Canon Makernotes fields, where they have endian in reverse { if (order == 0x4d4d) /* "II" means little-endian, and we reverse to "MM" - big endian */ return s[0] | s[1] << 8; else /* "MM" means big-endian... */ return s[0] << 8 | s[1]; } #endif ushort CLASS get2() { uchar str[2] = { 0xff,0xff }; fread (str, 1, 2, ifp); return sget2(str); } unsigned CLASS sget4 (uchar *s) { if (order == 0x4949) return s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24; else return s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]; } #define sget4(s) sget4((uchar *)s) unsigned CLASS get4() { uchar str[4] = { 0xff,0xff,0xff,0xff }; fread (str, 1, 4, ifp); return sget4(str); } unsigned CLASS getint (int type) { return type == 3 ? get2() : get4(); } float CLASS int_to_float (int i) { union { int i; float f; } u; u.i = i; return u.f; } double CLASS getreal (int type) { union { char c[8]; double d; } u,v; int i, rev; switch (type) { case 3: return (unsigned short) get2(); case 4: return (unsigned int) get4(); case 5: u.d = (unsigned int) get4(); v.d = (unsigned int)get4(); return u.d / (v.d ? v.d : 1); case 8: return (signed short) get2(); case 9: return (signed int) get4(); case 10: u.d = (signed int) get4(); v.d = (signed int)get4(); return u.d / (v.d?v.d:1); case 11: return int_to_float (get4()); case 12: rev = 7 * ((order == 0x4949) == (ntohs(0x1234) == 0x1234)); for (i=0; i < 8; i++) u.c[i ^ rev] = fgetc(ifp); return u.d; default: return fgetc(ifp); } } void CLASS read_shorts (ushort *pixel, unsigned count) { if (fread (pixel, 2, count, ifp) < count) derror(); if ((order == 0x4949) == (ntohs(0x1234) == 0x1234)) swab ((char*)pixel, (char*)pixel, count*2); } void CLASS cubic_spline (const int *x_, const int *y_, const int len) { float **A, *b, *c, *d, *x, *y; int i, j; A = (float **) calloc (((2*len + 4)*sizeof **A + sizeof *A), 2*len); if (!A) return; A[0] = (float *) (A + 2*len); for (i = 1; i < 2*len; i++) A[i] = A[0] + 2*len*i; y = len + (x = i + (d = i + (c = i + (b = A[0] + i*i)))); for (i = 0; i < len; i++) { x[i] = x_[i] / 65535.0; y[i] = y_[i] / 65535.0; } for (i = len-1; i > 0; i--) { b[i] = (y[i] - y[i-1]) / (x[i] - x[i-1]); d[i-1] = x[i] - x[i-1]; } for (i = 1; i < len-1; i++) { A[i][i] = 2 * (d[i-1] + d[i]); if (i > 1) { A[i][i-1] = d[i-1]; A[i-1][i] = d[i-1]; } A[i][len-1] = 6 * (b[i+1] - b[i]); } for(i = 1; i < len-2; i++) { float v = A[i+1][i] / A[i][i]; for(j = 1; j <= len-1; j++) A[i+1][j] -= v * A[i][j]; } for(i = len-2; i > 0; i--) { float acc = 0; for(j = i; j <= len-2; j++) acc += A[i][j]*c[j]; c[i] = (A[i][len-1] - acc) / A[i][i]; } for (i = 0; i < 0x10000; i++) { float x_out = (float)(i / 65535.0); float y_out = 0; for (j = 0; j < len-1; j++) { if (x[j] <= x_out && x_out <= x[j+1]) { float v = x_out - x[j]; y_out = y[j] + ((y[j+1] - y[j]) / d[j] - (2 * d[j] * c[j] + c[j+1] * d[j])/6) * v + (c[j] * 0.5) * v*v + ((c[j+1] - c[j]) / (6 * d[j])) * v*v*v; } } curve[i] = y_out < 0.0 ? 0 : (y_out >= 1.0 ? 65535 : (ushort)(y_out * 65535.0 + 0.5)); } free (A); } void CLASS canon_600_fixed_wb (int temp) { static const short mul[4][5] = { { 667, 358,397,565,452 }, { 731, 390,367,499,517 }, { 1119, 396,348,448,537 }, { 1399, 485,431,508,688 } }; int lo, hi, i; float frac=0; for (lo=4; --lo; ) if (*mul[lo] <= temp) break; for (hi=0; hi < 3; hi++) if (*mul[hi] >= temp) break; if (lo != hi) frac = (float) (temp - *mul[lo]) / (*mul[hi] - *mul[lo]); for (i=1; i < 5; i++) pre_mul[i-1] = 1 / (frac * mul[hi][i] + (1-frac) * mul[lo][i]); } /* Return values: 0 = white 1 = near white 2 = not white */ int CLASS canon_600_color (int ratio[2], int mar) { int clipped=0, target, miss; if (flash_used) { if (ratio[1] < -104) { ratio[1] = -104; clipped = 1; } if (ratio[1] > 12) { ratio[1] = 12; clipped = 1; } } else { if (ratio[1] < -264 || ratio[1] > 461) return 2; if (ratio[1] < -50) { ratio[1] = -50; clipped = 1; } if (ratio[1] > 307) { ratio[1] = 307; clipped = 1; } } target = flash_used || ratio[1] < 197 ? -38 - (398 * ratio[1] >> 10) : -123 + (48 * ratio[1] >> 10); if (target - mar <= ratio[0] && target + 20 >= ratio[0] && !clipped) return 0; miss = target - ratio[0]; if (abs(miss) >= mar*4) return 2; if (miss < -20) miss = -20; if (miss > mar) miss = mar; ratio[0] = target - miss; return 1; } void CLASS canon_600_auto_wb() { int mar, row, col, i, j, st, count[] = { 0,0 }; int test[8], total[2][8], ratio[2][2], stat[2]; memset (&total, 0, sizeof total); i = canon_ev + 0.5; if (i < 10) mar = 150; else if (i > 12) mar = 20; else mar = 280 - 20 * i; if (flash_used) mar = 80; for (row=14; row < height-14; row+=4) for (col=10; col < width; col+=2) { for (i=0; i < 8; i++) test[(i & 4) + FC(row+(i >> 1),col+(i & 1))] = BAYER(row+(i >> 1),col+(i & 1)); for (i=0; i < 8; i++) if (test[i] < 150 || test[i] > 1500) goto next; for (i=0; i < 4; i++) if (abs(test[i] - test[i+4]) > 50) goto next; for (i=0; i < 2; i++) { for (j=0; j < 4; j+=2) ratio[i][j >> 1] = ((test[i*4+j+1]-test[i*4+j]) << 10) / test[i*4+j]; stat[i] = canon_600_color (ratio[i], mar); } if ((st = stat[0] | stat[1]) > 1) goto next; for (i=0; i < 2; i++) if (stat[i]) for (j=0; j < 2; j++) test[i*4+j*2+1] = test[i*4+j*2] * (0x400 + ratio[i][j]) >> 10; for (i=0; i < 8; i++) total[st][i] += test[i]; count[st]++; next: ; } if (count[0] | count[1]) { st = count[0]*200 < count[1]; for (i=0; i < 4; i++) pre_mul[i] = 1.0 / (total[st][i] + total[st][i+4]); } } void CLASS canon_600_coeff() { static const short table[6][12] = { { -190,702,-1878,2390, 1861,-1349,905,-393, -432,944,2617,-2105 }, { -1203,1715,-1136,1648, 1388,-876,267,245, -1641,2153,3921,-3409 }, { -615,1127,-1563,2075, 1437,-925,509,3, -756,1268,2519,-2007 }, { -190,702,-1886,2398, 2153,-1641,763,-251, -452,964,3040,-2528 }, { -190,702,-1878,2390, 1861,-1349,905,-393, -432,944,2617,-2105 }, { -807,1319,-1785,2297, 1388,-876,769,-257, -230,742,2067,-1555 } }; int t=0, i, c; float mc, yc; mc = pre_mul[1] / pre_mul[2]; yc = pre_mul[3] / pre_mul[2]; if (mc > 1 && mc <= 1.28 && yc < 0.8789) t=1; if (mc > 1.28 && mc <= 2) { if (yc < 0.8789) t=3; else if (yc <= 2) t=4; } if (flash_used) t=5; for (raw_color = i=0; i < 3; i++) FORCC rgb_cam[i][c] = table[t][i*4 + c] / 1024.0; } void CLASS canon_600_load_raw() { uchar data[1120], *dp; ushort *pix; int irow, row; for (irow=row=0; irow < height; irow++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif if (fread (data, 1, 1120, ifp) < 1120) derror(); pix = raw_image + row*raw_width; for (dp=data; dp < data+1120; dp+=10, pix+=8) { pix[0] = (dp[0] << 2) + (dp[1] >> 6 ); pix[1] = (dp[2] << 2) + (dp[1] >> 4 & 3); pix[2] = (dp[3] << 2) + (dp[1] >> 2 & 3); pix[3] = (dp[4] << 2) + (dp[1] & 3); pix[4] = (dp[5] << 2) + (dp[9] & 3); pix[5] = (dp[6] << 2) + (dp[9] >> 2 & 3); pix[6] = (dp[7] << 2) + (dp[9] >> 4 & 3); pix[7] = (dp[8] << 2) + (dp[9] >> 6 ); } if ((row+=2) > height) row = 1; } } void CLASS canon_600_correct() { int row, col, val; static const short mul[4][2] = { { 1141,1145 }, { 1128,1109 }, { 1178,1149 }, { 1128,1109 } }; for (row=0; row < height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col=0; col < width; col++) { if ((val = BAYER(row,col) - black) < 0) val = 0; val = val * mul[row & 3][col & 1] >> 9; BAYER(row,col) = val; } } canon_600_fixed_wb(1311); canon_600_auto_wb(); canon_600_coeff(); maximum = (0x3ff - black) * 1109 >> 9; black = 0; } int CLASS canon_s2is() { unsigned row; for (row=0; row < 100; row++) { fseek (ifp, row*3340 + 3284, SEEK_SET); if (getc(ifp) > 15) return 1; } return 0; } unsigned CLASS getbithuff (int nbits, ushort *huff) { #ifdef LIBRAW_NOTHREADS static unsigned bitbuf=0; static int vbits=0, reset=0; #else #define bitbuf tls->getbits.bitbuf #define vbits tls->getbits.vbits #define reset tls->getbits.reset #endif unsigned c; if (nbits > 25) return 0; if (nbits < 0) return bitbuf = vbits = reset = 0; if (nbits == 0 || vbits < 0) return 0; while (!reset && vbits < nbits && (c = fgetc(ifp)) != EOF && !(reset = zero_after_ff && c == 0xff && fgetc(ifp))) { bitbuf = (bitbuf << 8) + (uchar) c; vbits += 8; } c = bitbuf << (32-vbits) >> (32-nbits); if (huff) { vbits -= huff[c] >> 8; c = (uchar) huff[c]; } else vbits -= nbits; if (vbits < 0) derror(); return c; #ifndef LIBRAW_NOTHREADS #undef bitbuf #undef vbits #undef reset #endif } #define getbits(n) getbithuff(n,0) #define gethuff(h) getbithuff(*h,h+1) /* Construct a decode tree according the specification in *source. The first 16 bytes specify how many codes should be 1-bit, 2-bit 3-bit, etc. Bytes after that are the leaf values. For example, if the source is { 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0, 0x04,0x03,0x05,0x06,0x02,0x07,0x01,0x08,0x09,0x00,0x0a,0x0b,0xff }, then the code is 00 0x04 010 0x03 011 0x05 100 0x06 101 0x02 1100 0x07 1101 0x01 11100 0x08 11101 0x09 11110 0x00 111110 0x0a 1111110 0x0b 1111111 0xff */ ushort * CLASS make_decoder_ref (const uchar **source) { int max, len, h, i, j; const uchar *count; ushort *huff; count = (*source += 16) - 17; for (max=16; max && !count[max]; max--); huff = (ushort *) calloc (1 + (1 << max), sizeof *huff); merror (huff, "make_decoder()"); huff[0] = max; for (h=len=1; len <= max; len++) for (i=0; i < count[len]; i++, ++*source) for (j=0; j < 1 << (max-len); j++) if (h <= 1 << max) huff[h++] = len << 8 | **source; return huff; } ushort * CLASS make_decoder (const uchar *source) { return make_decoder_ref (&source); } void CLASS crw_init_tables (unsigned table, ushort *huff[2]) { static const uchar first_tree[3][29] = { { 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0, 0x04,0x03,0x05,0x06,0x02,0x07,0x01,0x08,0x09,0x00,0x0a,0x0b,0xff }, { 0,2,2,3,1,1,1,1,2,0,0,0,0,0,0,0, 0x03,0x02,0x04,0x01,0x05,0x00,0x06,0x07,0x09,0x08,0x0a,0x0b,0xff }, { 0,0,6,3,1,1,2,0,0,0,0,0,0,0,0,0, 0x06,0x05,0x07,0x04,0x08,0x03,0x09,0x02,0x00,0x0a,0x01,0x0b,0xff }, }; static const uchar second_tree[3][180] = { { 0,2,2,2,1,4,2,1,2,5,1,1,0,0,0,139, 0x03,0x04,0x02,0x05,0x01,0x06,0x07,0x08, 0x12,0x13,0x11,0x14,0x09,0x15,0x22,0x00,0x21,0x16,0x0a,0xf0, 0x23,0x17,0x24,0x31,0x32,0x18,0x19,0x33,0x25,0x41,0x34,0x42, 0x35,0x51,0x36,0x37,0x38,0x29,0x79,0x26,0x1a,0x39,0x56,0x57, 0x28,0x27,0x52,0x55,0x58,0x43,0x76,0x59,0x77,0x54,0x61,0xf9, 0x71,0x78,0x75,0x96,0x97,0x49,0xb7,0x53,0xd7,0x74,0xb6,0x98, 0x47,0x48,0x95,0x69,0x99,0x91,0xfa,0xb8,0x68,0xb5,0xb9,0xd6, 0xf7,0xd8,0x67,0x46,0x45,0x94,0x89,0xf8,0x81,0xd5,0xf6,0xb4, 0x88,0xb1,0x2a,0x44,0x72,0xd9,0x87,0x66,0xd4,0xf5,0x3a,0xa7, 0x73,0xa9,0xa8,0x86,0x62,0xc7,0x65,0xc8,0xc9,0xa1,0xf4,0xd1, 0xe9,0x5a,0x92,0x85,0xa6,0xe7,0x93,0xe8,0xc1,0xc6,0x7a,0x64, 0xe1,0x4a,0x6a,0xe6,0xb3,0xf1,0xd3,0xa5,0x8a,0xb2,0x9a,0xba, 0x84,0xa4,0x63,0xe5,0xc5,0xf3,0xd2,0xc4,0x82,0xaa,0xda,0xe4, 0xf2,0xca,0x83,0xa3,0xa2,0xc3,0xea,0xc2,0xe2,0xe3,0xff,0xff }, { 0,2,2,1,4,1,4,1,3,3,1,0,0,0,0,140, 0x02,0x03,0x01,0x04,0x05,0x12,0x11,0x06, 0x13,0x07,0x08,0x14,0x22,0x09,0x21,0x00,0x23,0x15,0x31,0x32, 0x0a,0x16,0xf0,0x24,0x33,0x41,0x42,0x19,0x17,0x25,0x18,0x51, 0x34,0x43,0x52,0x29,0x35,0x61,0x39,0x71,0x62,0x36,0x53,0x26, 0x38,0x1a,0x37,0x81,0x27,0x91,0x79,0x55,0x45,0x28,0x72,0x59, 0xa1,0xb1,0x44,0x69,0x54,0x58,0xd1,0xfa,0x57,0xe1,0xf1,0xb9, 0x49,0x47,0x63,0x6a,0xf9,0x56,0x46,0xa8,0x2a,0x4a,0x78,0x99, 0x3a,0x75,0x74,0x86,0x65,0xc1,0x76,0xb6,0x96,0xd6,0x89,0x85, 0xc9,0xf5,0x95,0xb4,0xc7,0xf7,0x8a,0x97,0xb8,0x73,0xb7,0xd8, 0xd9,0x87,0xa7,0x7a,0x48,0x82,0x84,0xea,0xf4,0xa6,0xc5,0x5a, 0x94,0xa4,0xc6,0x92,0xc3,0x68,0xb5,0xc8,0xe4,0xe5,0xe6,0xe9, 0xa2,0xa3,0xe3,0xc2,0x66,0x67,0x93,0xaa,0xd4,0xd5,0xe7,0xf8, 0x88,0x9a,0xd7,0x77,0xc4,0x64,0xe2,0x98,0xa5,0xca,0xda,0xe8, 0xf3,0xf6,0xa9,0xb2,0xb3,0xf2,0xd2,0x83,0xba,0xd3,0xff,0xff }, { 0,0,6,2,1,3,3,2,5,1,2,2,8,10,0,117, 0x04,0x05,0x03,0x06,0x02,0x07,0x01,0x08, 0x09,0x12,0x13,0x14,0x11,0x15,0x0a,0x16,0x17,0xf0,0x00,0x22, 0x21,0x18,0x23,0x19,0x24,0x32,0x31,0x25,0x33,0x38,0x37,0x34, 0x35,0x36,0x39,0x79,0x57,0x58,0x59,0x28,0x56,0x78,0x27,0x41, 0x29,0x77,0x26,0x42,0x76,0x99,0x1a,0x55,0x98,0x97,0xf9,0x48, 0x54,0x96,0x89,0x47,0xb7,0x49,0xfa,0x75,0x68,0xb6,0x67,0x69, 0xb9,0xb8,0xd8,0x52,0xd7,0x88,0xb5,0x74,0x51,0x46,0xd9,0xf8, 0x3a,0xd6,0x87,0x45,0x7a,0x95,0xd5,0xf6,0x86,0xb4,0xa9,0x94, 0x53,0x2a,0xa8,0x43,0xf5,0xf7,0xd4,0x66,0xa7,0x5a,0x44,0x8a, 0xc9,0xe8,0xc8,0xe7,0x9a,0x6a,0x73,0x4a,0x61,0xc7,0xf4,0xc6, 0x65,0xe9,0x72,0xe6,0x71,0x91,0x93,0xa6,0xda,0x92,0x85,0x62, 0xf3,0xc5,0xb2,0xa4,0x84,0xba,0x64,0xa5,0xb3,0xd2,0x81,0xe5, 0xd3,0xaa,0xc4,0xca,0xf2,0xb1,0xe4,0xd1,0x83,0x63,0xea,0xc3, 0xe2,0x82,0xf1,0xa3,0xc2,0xa1,0xc1,0xe3,0xa2,0xe1,0xff,0xff } }; if (table > 2) table = 2; huff[0] = make_decoder ( first_tree[table]); huff[1] = make_decoder (second_tree[table]); } /* Return 0 if the image starts with compressed data, 1 if it starts with uncompressed low-order bits. In Canon compressed data, 0xff is always followed by 0x00. */ int CLASS canon_has_lowbits() { uchar test[0x4000]; int ret=1, i; fseek (ifp, 0, SEEK_SET); fread (test, 1, sizeof test, ifp); for (i=540; i < sizeof test - 1; i++) if (test[i] == 0xff) { if (test[i+1]) return 1; ret=0; } return ret; } void CLASS canon_load_raw() { ushort *pixel, *prow, *huff[2]; int nblocks, lowbits, i, c, row, r, save, val; int block, diffbuf[64], leaf, len, diff, carry=0, pnum=0, base[2]; crw_init_tables (tiff_compress, huff); lowbits = canon_has_lowbits(); if (!lowbits) maximum = 0x3ff; fseek (ifp, 540 + lowbits*raw_height*raw_width/4, SEEK_SET); zero_after_ff = 1; getbits(-1); #ifdef LIBRAW_LIBRARY_BUILD try { #endif for (row=0; row < raw_height; row+=8) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif pixel = raw_image + row*raw_width; nblocks = MIN (8, raw_height-row) * raw_width >> 6; for (block=0; block < nblocks; block++) { memset (diffbuf, 0, sizeof diffbuf); for (i=0; i < 64; i++ ) { leaf = gethuff(huff[i > 0]); if (leaf == 0 && i) break; if (leaf == 0xff) continue; i += leaf >> 4; len = leaf & 15; if (len == 0) continue; diff = getbits(len); if ((diff & (1 << (len-1))) == 0) diff -= (1 << len) - 1; if (i < 64) diffbuf[i] = diff; } diffbuf[0] += carry; carry = diffbuf[0]; for (i=0; i < 64; i++ ) { if (pnum++ % raw_width == 0) base[0] = base[1] = 512; if ((pixel[(block << 6) + i] = base[i & 1] += diffbuf[i]) >> 10) derror(); } } if (lowbits) { save = ftell(ifp); fseek (ifp, 26 + row*raw_width/4, SEEK_SET); for (prow=pixel, i=0; i < raw_width*2; i++) { c = fgetc(ifp); for (r=0; r < 8; r+=2, prow++) { val = (*prow << 2) + ((c >> r) & 3); if (raw_width == 2672 && val < 512) val += 2; *prow = val; } } fseek (ifp, save, SEEK_SET); } } #ifdef LIBRAW_LIBRARY_BUILD } catch (...) { FORC(2) free (huff[c]); throw; } #endif FORC(2) free (huff[c]); } //@end COMMON struct jhead { int algo, bits, high, wide, clrs, sraw, psv, restart, vpred[6]; ushort quant[64], idct[64], *huff[20], *free[20], *row; }; //@out COMMON int CLASS ljpeg_start (struct jhead *jh, int info_only) { ushort c, tag, len; int cnt = 0; uchar data[0x10000]; const uchar *dp; memset (jh, 0, sizeof *jh); jh->restart = INT_MAX; if ((fgetc(ifp),fgetc(ifp)) != 0xd8) return 0; do { if(feof(ifp)) return 0; if(cnt++ > 1024) return 0; // 1024 tags limit if (!fread (data, 2, 2, ifp)) return 0; tag = data[0] << 8 | data[1]; len = (data[2] << 8 | data[3]) - 2; if (tag <= 0xff00) return 0; fread (data, 1, len, ifp); switch (tag) { case 0xffc3: // start of frame; lossless, Huffman jh->sraw = ((data[7] >> 4) * (data[7] & 15) - 1) & 3; case 0xffc1: case 0xffc0: jh->algo = tag & 0xff; jh->bits = data[0]; jh->high = data[1] << 8 | data[2]; jh->wide = data[3] << 8 | data[4]; jh->clrs = data[5] + jh->sraw; if (len == 9 && !dng_version) getc(ifp); break; case 0xffc4: // define Huffman tables if (info_only) break; for (dp = data; dp < data+len && !((c = *dp++) & -20); ) jh->free[c] = jh->huff[c] = make_decoder_ref (&dp); break; case 0xffda: // start of scan jh->psv = data[1+data[0]*2]; jh->bits -= data[3+data[0]*2] & 15; break; case 0xffdb: FORC(64) jh->quant[c] = data[c*2+1] << 8 | data[c*2+2]; break; case 0xffdd: jh->restart = data[0] << 8 | data[1]; } } while (tag != 0xffda); if (jh->bits > 16 || jh->clrs > 6 || !jh->bits || !jh->high || !jh->wide || !jh->clrs) return 0; if (info_only) return 1; if (!jh->huff[0]) return 0; FORC(19) if (!jh->huff[c+1]) jh->huff[c+1] = jh->huff[c]; if (jh->sraw) { FORC(4) jh->huff[2+c] = jh->huff[1]; FORC(jh->sraw) jh->huff[1+c] = jh->huff[0]; } jh->row = (ushort *) calloc (jh->wide*jh->clrs, 4); merror (jh->row, "ljpeg_start()"); return zero_after_ff = 1; } void CLASS ljpeg_end (struct jhead *jh) { int c; FORC4 if (jh->free[c]) free (jh->free[c]); free (jh->row); } int CLASS ljpeg_diff (ushort *huff) { int len, diff; if(!huff) #ifdef LIBRAW_LIBRARY_BUILD throw LIBRAW_EXCEPTION_IO_CORRUPT; #else longjmp (failure, 2); #endif len = gethuff(huff); if (len == 16 && (!dng_version || dng_version >= 0x1010000)) return -32768; diff = getbits(len); if ((diff & (1 << (len-1))) == 0) diff -= (1 << len) - 1; return diff; } ushort * CLASS ljpeg_row (int jrow, struct jhead *jh) { int col, c, diff, pred, spred=0; ushort mark=0, *row[3]; if (jrow * jh->wide % jh->restart == 0) { FORC(6) jh->vpred[c] = 1 << (jh->bits-1); if (jrow) { fseek (ifp, -2, SEEK_CUR); do mark = (mark << 8) + (c = fgetc(ifp)); while (c != EOF && mark >> 4 != 0xffd); } getbits(-1); } FORC3 row[c] = jh->row + jh->wide*jh->clrs*((jrow+c) & 1); for (col=0; col < jh->wide; col++) FORC(jh->clrs) { diff = ljpeg_diff (jh->huff[c]); if (jh->sraw && c <= jh->sraw && (col | c)) pred = spred; else if (col) pred = row[0][-jh->clrs]; else pred = (jh->vpred[c] += diff) - diff; if (jrow && col) switch (jh->psv) { case 1: break; case 2: pred = row[1][0]; break; case 3: pred = row[1][-jh->clrs]; break; case 4: pred = pred + row[1][0] - row[1][-jh->clrs]; break; case 5: pred = pred + ((row[1][0] - row[1][-jh->clrs]) >> 1); break; case 6: pred = row[1][0] + ((pred - row[1][-jh->clrs]) >> 1); break; case 7: pred = (pred + row[1][0]) >> 1; break; default: pred = 0; } if ((**row = pred + diff) >> jh->bits) derror(); if (c <= jh->sraw) spred = **row; row[0]++; row[1]++; } return row[2]; } void CLASS lossless_jpeg_load_raw() { int jwide, jhigh, jrow, jcol, val, jidx, i, j, row=0, col=0; struct jhead jh; ushort *rp; if (!ljpeg_start (&jh, 0)) return; if(jh.wide<1 || jh.high<1 || jh.clrs<1 || jh.bits <1) #ifdef LIBRAW_LIBRARY_BUILD throw LIBRAW_EXCEPTION_IO_CORRUPT; #else longjmp (failure, 2); #endif jwide = jh.wide * jh.clrs; jhigh = jh.high; if(jh.clrs == 4 && jwide >= raw_width*2) jhigh *= 2; #ifdef LIBRAW_LIBRARY_BUILD try { #endif for (jrow=0; jrow < jh.high; jrow++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif rp = ljpeg_row (jrow, &jh); if (load_flags & 1) row = jrow & 1 ? height-1-jrow/2 : jrow/2; for (jcol=0; jcol < jwide; jcol++) { val = curve[*rp++]; if (cr2_slice[0]) { jidx = jrow*jwide + jcol; i = jidx / (cr2_slice[1]*raw_height); if ((j = i >= cr2_slice[0])) i = cr2_slice[0]; jidx -= i * (cr2_slice[1]*raw_height); row = jidx / cr2_slice[1+j]; col = jidx % cr2_slice[1+j] + i*cr2_slice[1]; } if (raw_width == 3984 && (col -= 2) < 0) col += (row--,raw_width); if(row>raw_height) #ifdef LIBRAW_LIBRARY_BUILD throw LIBRAW_EXCEPTION_IO_CORRUPT; #else longjmp (failure, 3); #endif if ((unsigned) row < raw_height) RAW(row,col) = val; if (++col >= raw_width) col = (row++,0); } } #ifdef LIBRAW_LIBRARY_BUILD } catch (...) { ljpeg_end (&jh); throw; } #endif ljpeg_end (&jh); } void CLASS canon_sraw_load_raw() { struct jhead jh; short *rp=0, (*ip)[4]; int jwide, slice, scol, ecol, row, col, jrow=0, jcol=0, pix[3], c; int v[3]={0,0,0}, ver, hue; #ifdef LIBRAW_LIBRARY_BUILD int saved_w = width, saved_h = height; #endif char *cp; if (!ljpeg_start (&jh, 0) || jh.clrs < 4) return; jwide = (jh.wide >>= 1) * jh.clrs; #ifdef LIBRAW_LIBRARY_BUILD if(load_flags & 256) { width = raw_width; height = raw_height; } try { #endif for (ecol=slice=0; slice <= cr2_slice[0]; slice++) { scol = ecol; ecol += cr2_slice[1] * 2 / jh.clrs; if (!cr2_slice[0] || ecol > raw_width-1) ecol = raw_width & -2; for (row=0; row < height; row += (jh.clrs >> 1) - 1) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif ip = (short (*)[4]) image + row*width; for (col=scol; col < ecol; col+=2, jcol+=jh.clrs) { if ((jcol %= jwide) == 0) rp = (short *) ljpeg_row (jrow++, &jh); if (col >= width) continue; #ifdef LIBRAW_LIBRARY_BUILD if(imgdata.params.raw_processing_options & LIBRAW_PROCESSING_SRAW_NO_INTERPOLATE) { FORC (jh.clrs-2) { ip[col + (c >> 1)*width + (c & 1)][0] = rp[jcol+c]; ip[col + (c >> 1)*width + (c & 1)][1] = ip[col + (c >> 1)*width + (c & 1)][2] = 8192; } ip[col][1] = rp[jcol+jh.clrs-2] - 8192; ip[col][2] = rp[jcol+jh.clrs-1] - 8192; } else if(imgdata.params.raw_processing_options & LIBRAW_PROCESSING_SRAW_NO_RGB) { FORC (jh.clrs-2) ip[col + (c >> 1)*width + (c & 1)][0] = rp[jcol+c]; ip[col][1] = rp[jcol+jh.clrs-2] - 8192; ip[col][2] = rp[jcol+jh.clrs-1] - 8192; } else #endif { FORC (jh.clrs-2) ip[col + (c >> 1)*width + (c & 1)][0] = rp[jcol+c]; ip[col][1] = rp[jcol+jh.clrs-2] - 16384; ip[col][2] = rp[jcol+jh.clrs-1] - 16384; } } } } #ifdef LIBRAW_LIBRARY_BUILD } catch (...) { ljpeg_end (&jh); throw ; } #endif #ifdef LIBRAW_LIBRARY_BUILD if(imgdata.params.raw_processing_options & LIBRAW_PROCESSING_SRAW_NO_INTERPOLATE) { ljpeg_end (&jh); maximum = 0x3fff; height = saved_h; width = saved_w; return; } #endif #ifdef LIBRAW_LIBRARY_BUILD try { #endif for (cp=model2; *cp && !isdigit(*cp); cp++); sscanf (cp, "%d.%d.%d", v, v+1, v+2); ver = (v[0]*1000 + v[1])*1000 + v[2]; hue = (jh.sraw+1) << 2; if (unique_id >= 0x80000281 || (unique_id == 0x80000218 && ver > 1000006)) hue = jh.sraw << 1; ip = (short (*)[4]) image; rp = ip[0]; for (row=0; row < height; row++, ip+=width) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif if (row & (jh.sraw >> 1)) { for (col=0; col < width; col+=2) for (c=1; c < 3; c++) if (row == height-1) { ip[col][c] = ip[col-width][c]; } else { ip[col][c] = (ip[col-width][c] + ip[col+width][c] + 1) >> 1; } } for (col=1; col < width; col+=2) for (c=1; c < 3; c++) if (col == width-1) ip[col][c] = ip[col-1][c]; else ip[col][c] = (ip[col-1][c] + ip[col+1][c] + 1) >> 1; } #ifdef LIBRAW_LIBRARY_BUILD if(!(imgdata.params.raw_processing_options & LIBRAW_PROCESSING_SRAW_NO_RGB) ) #endif for ( ; rp < ip[0]; rp+=4) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif if (unique_id == 0x80000218 || unique_id == 0x80000250 || unique_id == 0x80000261 || unique_id == 0x80000281 || unique_id == 0x80000287) { rp[1] = (rp[1] << 2) + hue; rp[2] = (rp[2] << 2) + hue; pix[0] = rp[0] + (( 50*rp[1] + 22929*rp[2]) >> 14); pix[1] = rp[0] + ((-5640*rp[1] - 11751*rp[2]) >> 14); pix[2] = rp[0] + ((29040*rp[1] - 101*rp[2]) >> 14); } else { if (unique_id < 0x80000218) rp[0] -= 512; pix[0] = rp[0] + rp[2]; pix[2] = rp[0] + rp[1]; pix[1] = rp[0] + ((-778*rp[1] - (rp[2] << 11)) >> 12); } FORC3 rp[c] = CLIP(pix[c] * sraw_mul[c] >> 10); } #ifdef LIBRAW_LIBRARY_BUILD } catch (...) { ljpeg_end (&jh); throw ; } height = saved_h; width = saved_w; #endif ljpeg_end (&jh); maximum = 0x3fff; } void CLASS adobe_copy_pixel (unsigned row, unsigned col, ushort **rp) { int c; if (tiff_samples == 2 && shot_select) (*rp)++; if (raw_image) { if (row < raw_height && col < raw_width) RAW(row,col) = curve[**rp]; *rp += tiff_samples; } else { if (row < height && col < width) FORC(tiff_samples) image[row*width+col][c] = curve[(*rp)[c]]; *rp += tiff_samples; } if (tiff_samples == 2 && shot_select) (*rp)--; } void CLASS ljpeg_idct (struct jhead *jh) { int c, i, j, len, skip, coef; float work[3][8][8]; static float cs[106] = { 0 }; static const uchar zigzag[80] = { 0, 1, 8,16, 9, 2, 3,10,17,24,32,25,18,11, 4, 5,12,19,26,33, 40,48,41,34,27,20,13, 6, 7,14,21,28,35,42,49,56,57,50,43,36, 29,22,15,23,30,37,44,51,58,59,52,45,38,31,39,46,53,60,61,54, 47,55,62,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63 }; if (!cs[0]) FORC(106) cs[c] = cos((c & 31)*M_PI/16)/2; memset (work, 0, sizeof work); work[0][0][0] = jh->vpred[0] += ljpeg_diff (jh->huff[0]) * jh->quant[0]; for (i=1; i < 64; i++ ) { len = gethuff (jh->huff[16]); i += skip = len >> 4; if (!(len &= 15) && skip < 15) break; coef = getbits(len); if ((coef & (1 << (len-1))) == 0) coef -= (1 << len) - 1; ((float *)work)[zigzag[i]] = coef * jh->quant[i]; } FORC(8) work[0][0][c] *= M_SQRT1_2; FORC(8) work[0][c][0] *= M_SQRT1_2; for (i=0; i < 8; i++) for (j=0; j < 8; j++) FORC(8) work[1][i][j] += work[0][i][c] * cs[(j*2+1)*c]; for (i=0; i < 8; i++) for (j=0; j < 8; j++) FORC(8) work[2][i][j] += work[1][c][j] * cs[(i*2+1)*c]; FORC(64) jh->idct[c] = CLIP(((float *)work[2])[c]+0.5); } void CLASS lossless_dng_load_raw() { unsigned save, trow=0, tcol=0, jwide, jrow, jcol, row, col, i, j; struct jhead jh; ushort *rp; while (trow < raw_height) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif save = ftell(ifp); if (tile_length < INT_MAX) fseek (ifp, get4(), SEEK_SET); if (!ljpeg_start (&jh, 0)) break; jwide = jh.wide; if (filters) jwide *= jh.clrs; jwide /= MIN (is_raw, tiff_samples); #ifdef LIBRAW_LIBRARY_BUILD try { #endif switch (jh.algo) { case 0xc1: jh.vpred[0] = 16384; getbits(-1); for (jrow=0; jrow+7 < jh.high; jrow += 8) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (jcol=0; jcol+7 < jh.wide; jcol += 8) { ljpeg_idct (&jh); rp = jh.idct; row = trow + jcol/tile_width + jrow*2; col = tcol + jcol%tile_width; for (i=0; i < 16; i+=2) for (j=0; j < 8; j++) adobe_copy_pixel (row+i, col+j, &rp); } } break; case 0xc3: for (row=col=jrow=0; jrow < jh.high; jrow++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif rp = ljpeg_row (jrow, &jh); for (jcol=0; jcol < jwide; jcol++) { adobe_copy_pixel (trow+row, tcol+col, &rp); if (++col >= tile_width || col >= raw_width) row += 1 + (col = 0); } } } #ifdef LIBRAW_LIBRARY_BUILD } catch (...) { ljpeg_end (&jh); throw ; } #endif fseek (ifp, save+4, SEEK_SET); if ((tcol += tile_width) >= raw_width) trow += tile_length + (tcol = 0); ljpeg_end (&jh); } } void CLASS packed_dng_load_raw() { ushort *pixel, *rp; int row, col; pixel = (ushort *) calloc (raw_width, tiff_samples*sizeof *pixel); merror (pixel, "packed_dng_load_raw()"); #ifdef LIBRAW_LIBRARY_BUILD try { #endif for (row=0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif if (tiff_bps == 16) read_shorts (pixel, raw_width * tiff_samples); else { getbits(-1); for (col=0; col < raw_width * tiff_samples; col++) pixel[col] = getbits(tiff_bps); } for (rp=pixel, col=0; col < raw_width; col++) adobe_copy_pixel (row, col, &rp); } #ifdef LIBRAW_LIBRARY_BUILD } catch (...) { free (pixel); throw ; } #endif free (pixel); } void CLASS pentax_load_raw() { ushort bit[2][15], huff[4097]; int dep, row, col, diff, c, i; ushort vpred[2][2] = {{0,0},{0,0}}, hpred[2]; fseek (ifp, meta_offset, SEEK_SET); dep = (get2() + 12) & 15; fseek (ifp, 12, SEEK_CUR); FORC(dep) bit[0][c] = get2(); FORC(dep) bit[1][c] = fgetc(ifp); FORC(dep) for (i=bit[0][c]; i <= ((bit[0][c]+(4096 >> bit[1][c])-1) & 4095); ) huff[++i] = bit[1][c] << 8 | c; huff[0] = 12; fseek (ifp, data_offset, SEEK_SET); getbits(-1); for (row=0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col=0; col < raw_width; col++) { diff = ljpeg_diff (huff); if (col < 2) hpred[col] = vpred[row & 1][col] += diff; else hpred[col & 1] += diff; RAW(row,col) = hpred[col & 1]; if (hpred[col & 1] >> tiff_bps) derror(); } } } #ifdef LIBRAW_LIBRARY_BUILD void CLASS nikon_coolscan_load_raw() { int bufsize = width*3*tiff_bps/8; if(tiff_bps <= 8) gamma_curve(1.0/imgdata.params.coolscan_nef_gamma,0.,1,255); else gamma_curve(1.0/imgdata.params.coolscan_nef_gamma,0.,1,65535); fseek (ifp, data_offset, SEEK_SET); unsigned char *buf = (unsigned char*)malloc(bufsize); unsigned short *ubuf = (unsigned short *)buf; for(int row = 0; row < raw_height; row++) { int red = fread (buf, 1, bufsize, ifp); unsigned short (*ip)[4] = (unsigned short (*)[4]) image + row*width; if(tiff_bps <= 8) for(int col=0; col 1) step = max / (csize-1); if (ver0 == 0x44 && ver1 == 0x20 && step > 0) { for (i=0; i < csize; i++) curve[i*step] = get2(); for (i=0; i < max; i++) curve[i] = ( curve[i-i%step]*(step-i%step) + curve[i-i%step+step]*(i%step) ) / step; fseek (ifp, meta_offset+562, SEEK_SET); split = get2(); } else if (ver0 != 0x46 && csize <= 0x4001) read_shorts (curve, max=csize); while (curve[max-2] == curve[max-1]) max--; huff = make_decoder (nikon_tree[tree]); fseek (ifp, data_offset, SEEK_SET); getbits(-1); #ifdef LIBRAW_LIBRARY_BUILD try { #endif for (min=row=0; row < height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif if (split && row == split) { free (huff); huff = make_decoder (nikon_tree[tree+1]); max += (min = 16) << 1; } for (col=0; col < raw_width; col++) { i = gethuff(huff); len = i & 15; shl = i >> 4; diff = ((getbits(len-shl) << 1) + 1) << shl >> 1; if ((diff & (1 << (len-1))) == 0) diff -= (1 << len) - !shl; if (col < 2) hpred[col] = vpred[row & 1][col] += diff; else hpred[col & 1] += diff; if ((ushort)(hpred[col & 1] + min) >= max) derror(); RAW(row,col) = curve[LIM((short)hpred[col & 1],0,0x3fff)]; } } #ifdef LIBRAW_LIBRARY_BUILD } catch (...) { free (huff); throw; } #endif free (huff); } void CLASS nikon_yuv_load_raw() { #ifdef LIBRAW_LIBRARY_BUILD if(!image) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif int row, col, yuv[4], rgb[3], b, c; UINT64 bitbuf=0; float cmul[4]; FORC4 { cmul[c] = cam_mul[c]>0.001f?cam_mul[c]:1.f; } for (row=0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col=0; col < raw_width; col++) { if (!(b = col & 1)) { bitbuf = 0; FORC(6) bitbuf |= (UINT64) fgetc(ifp) << c*8; FORC(4) yuv[c] = (bitbuf >> c*12 & 0xfff) - (c >> 1 << 11); } rgb[0] = yuv[b] + 1.370705*yuv[3]; rgb[1] = yuv[b] - 0.337633*yuv[2] - 0.698001*yuv[3]; rgb[2] = yuv[b] + 1.732446*yuv[2]; FORC3 image[row*width+col][c] = curve[LIM(rgb[c],0,0xfff)] / cmul[c]; } } } /* Returns 1 for a Coolpix 995, 0 for anything else. */ int CLASS nikon_e995() { int i, histo[256]; const uchar often[] = { 0x00, 0x55, 0xaa, 0xff }; memset (histo, 0, sizeof histo); fseek (ifp, -2000, SEEK_END); for (i=0; i < 2000; i++) histo[fgetc(ifp)]++; for (i=0; i < 4; i++) if (histo[often[i]] < 200) return 0; return 1; } /* Returns 1 for a Coolpix 2100, 0 for anything else. */ int CLASS nikon_e2100() { uchar t[12]; int i; fseek (ifp, 0, SEEK_SET); for (i=0; i < 1024; i++) { fread (t, 1, 12, ifp); if (((t[2] & t[4] & t[7] & t[9]) >> 4 & t[1] & t[6] & t[8] & t[11] & 3) != 3) return 0; } return 1; } void CLASS nikon_3700() { int bits, i; uchar dp[24]; static const struct { int bits; char t_make[12], t_model[15]; } table[] = { { 0x00, "Pentax", "Optio 33WR" }, { 0x03, "Nikon", "E3200" }, { 0x32, "Nikon", "E3700" }, { 0x33, "Olympus", "C740UZ" } }; fseek (ifp, 3072, SEEK_SET); fread (dp, 1, 24, ifp); bits = (dp[8] & 3) << 4 | (dp[20] & 3); for (i=0; i < sizeof table / sizeof *table; i++) if (bits == table[i].bits) { strcpy (make, table[i].t_make ); strcpy (model, table[i].t_model); } } /* Separates a Minolta DiMAGE Z2 from a Nikon E4300. */ int CLASS minolta_z2() { int i, nz; char tail[424]; fseek (ifp, -sizeof tail, SEEK_END); fread (tail, 1, sizeof tail, ifp); for (nz=i=0; i < sizeof tail; i++) if (tail[i]) nz++; return nz > 20; } //@end COMMON void CLASS jpeg_thumb(); //@out COMMON void CLASS ppm_thumb() { char *thumb; thumb_length = thumb_width*thumb_height*3; thumb = (char *) malloc (thumb_length); merror (thumb, "ppm_thumb()"); fprintf (ofp, "P6\n%d %d\n255\n", thumb_width, thumb_height); fread (thumb, 1, thumb_length, ifp); fwrite (thumb, 1, thumb_length, ofp); free (thumb); } void CLASS ppm16_thumb() { int i; char *thumb; thumb_length = thumb_width*thumb_height*3; thumb = (char *) calloc (thumb_length, 2); merror (thumb, "ppm16_thumb()"); read_shorts ((ushort *) thumb, thumb_length); for (i=0; i < thumb_length; i++) thumb[i] = ((ushort *) thumb)[i] >> 8; fprintf (ofp, "P6\n%d %d\n255\n", thumb_width, thumb_height); fwrite (thumb, 1, thumb_length, ofp); free (thumb); } void CLASS layer_thumb() { int i, c; char *thumb, map[][4] = { "012","102" }; colors = thumb_misc >> 5 & 7; thumb_length = thumb_width*thumb_height; thumb = (char *) calloc (colors, thumb_length); merror (thumb, "layer_thumb()"); fprintf (ofp, "P%d\n%d %d\n255\n", 5 + (colors >> 1), thumb_width, thumb_height); fread (thumb, thumb_length, colors, ifp); for (i=0; i < thumb_length; i++) FORCC putc (thumb[i+thumb_length*(map[thumb_misc >> 8][c]-'0')], ofp); free (thumb); } void CLASS rollei_thumb() { unsigned i; ushort *thumb; thumb_length = thumb_width * thumb_height; thumb = (ushort *) calloc (thumb_length, 2); merror (thumb, "rollei_thumb()"); fprintf (ofp, "P6\n%d %d\n255\n", thumb_width, thumb_height); read_shorts (thumb, thumb_length); for (i=0; i < thumb_length; i++) { putc (thumb[i] << 3, ofp); putc (thumb[i] >> 5 << 2, ofp); putc (thumb[i] >> 11 << 3, ofp); } free (thumb); } void CLASS rollei_load_raw() { uchar pixel[10]; unsigned iten=0, isix, i, buffer=0, todo[16]; isix = raw_width * raw_height * 5 / 8; while (fread (pixel, 1, 10, ifp) == 10) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (i=0; i < 10; i+=2) { todo[i] = iten++; todo[i+1] = pixel[i] << 8 | pixel[i+1]; buffer = pixel[i] >> 2 | buffer << 6; } for ( ; i < 16; i+=2) { todo[i] = isix++; todo[i+1] = buffer >> (14-i)*5; } for (i=0; i < 16; i+=2) raw_image[todo[i]] = (todo[i+1] & 0x3ff); } maximum = 0x3ff; } int CLASS raw (unsigned row, unsigned col) { return (row < raw_height && col < raw_width) ? RAW(row,col) : 0; } void CLASS phase_one_flat_field (int is_float, int nc) { ushort head[8]; unsigned wide, high, y, x, c, rend, cend, row, col; float *mrow, num, mult[4]; read_shorts (head, 8); if (head[2] * head[3] * head[4] * head[5] == 0) return; wide = head[2] / head[4] + (head[2] % head[4] != 0); high = head[3] / head[5] + (head[3] % head[5] != 0); mrow = (float *) calloc (nc*wide, sizeof *mrow); merror (mrow, "phase_one_flat_field()"); for (y=0; y < high; y++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (x=0; x < wide; x++) for (c=0; c < nc; c+=2) { num = is_float ? getreal(11) : get2()/32768.0; if (y==0) mrow[c*wide+x] = num; else mrow[(c+1)*wide+x] = (num - mrow[c*wide+x]) / head[5]; } if (y==0) continue; rend = head[1] + y*head[5]; for (row = rend-head[5]; row < raw_height && row < rend && row < head[1]+head[3]-head[5]; row++) { for (x=1; x < wide; x++) { for (c=0; c < nc; c+=2) { mult[c] = mrow[c*wide+x-1]; mult[c+1] = (mrow[c*wide+x] - mult[c]) / head[4]; } cend = head[0] + x*head[4]; for (col = cend-head[4]; col < raw_width && col < cend && col < head[0]+head[2]-head[4]; col++) { c = nc > 2 ? FC(row-top_margin,col-left_margin) : 0; if (!(c & 1)) { c = RAW(row,col) * mult[c]; RAW(row,col) = LIM(c,0,65535); } for (c=0; c < nc; c+=2) mult[c] += mult[c+1]; } } for (x=0; x < wide; x++) for (c=0; c < nc; c+=2) mrow[c*wide+x] += mrow[(c+1)*wide+x]; } } free (mrow); } int CLASS phase_one_correct() { unsigned entries, tag, data, save, col, row, type; int len, i, j, k, cip, val[4], dev[4], sum, max; int head[9], diff, mindiff=INT_MAX, off_412=0; /* static */ const signed char dir[12][2] = { {-1,-1}, {-1,1}, {1,-1}, {1,1}, {-2,0}, {0,-2}, {0,2}, {2,0}, {-2,-2}, {-2,2}, {2,-2}, {2,2} }; float poly[8], num, cfrac, frac, mult[2], *yval[2]={NULL,NULL}; ushort *xval[2]; int qmult_applied = 0, qlin_applied = 0; #ifdef LIBRAW_LIBRARY_BUILD if (!meta_length) #else if (half_size || !meta_length) #endif return 0; #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("Phase One correction...\n")); #endif fseek (ifp, meta_offset, SEEK_SET); order = get2(); fseek (ifp, 6, SEEK_CUR); fseek (ifp, meta_offset+get4(), SEEK_SET); entries = get4(); get4(); #ifdef LIBRAW_LIBRARY_BUILD try { #endif while (entries--) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif tag = get4(); len = get4(); data = get4(); save = ftell(ifp); fseek (ifp, meta_offset+data, SEEK_SET); if (tag == 0x419) { /* Polynomial curve */ for (get4(), i=0; i < 8; i++) poly[i] = getreal(11); poly[3] += (ph1.tag_210 - poly[7]) * poly[6] + 1; for (i=0; i < 0x10000; i++) { num = (poly[5]*i + poly[3])*i + poly[1]; curve[i] = LIM(num,0,65535); } goto apply; /* apply to right half */ } else if (tag == 0x41a) { /* Polynomial curve */ for (i=0; i < 4; i++) poly[i] = getreal(11); for (i=0; i < 0x10000; i++) { for (num=0, j=4; j--; ) num = num * i + poly[j]; curve[i] = LIM(num+i,0,65535); } apply: /* apply to whole image */ for (row=0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col = (tag & 1)*ph1.split_col; col < raw_width; col++) RAW(row,col) = curve[RAW(row,col)]; } } else if (tag == 0x400) { /* Sensor defects */ while ((len -= 8) >= 0) { col = get2(); row = get2(); type = get2(); get2(); if (col >= raw_width) continue; if (type == 131 || type == 137) /* Bad column */ for (row=0; row < raw_height; row++) if (FC(row-top_margin,col-left_margin) == 1) { for (sum=i=0; i < 4; i++) sum += val[i] = raw (row+dir[i][0], col+dir[i][1]); for (max=i=0; i < 4; i++) { dev[i] = abs((val[i] << 2) - sum); if (dev[max] < dev[i]) max = i; } RAW(row,col) = (sum - val[max])/3.0 + 0.5; } else { for (sum=0, i=8; i < 12; i++) sum += raw (row+dir[i][0], col+dir[i][1]); RAW(row,col) = 0.5 + sum * 0.0732233 + (raw(row,col-2) + raw(row,col+2)) * 0.3535534; } else if (type == 129) { /* Bad pixel */ if (row >= raw_height) continue; j = (FC(row-top_margin,col-left_margin) != 1) * 4; for (sum=0, i=j; i < j+8; i++) sum += raw (row+dir[i][0], col+dir[i][1]); RAW(row,col) = (sum + 4) >> 3; } } } else if (tag == 0x401) { /* All-color flat fields */ phase_one_flat_field (1, 2); } else if (tag == 0x416 || tag == 0x410) { phase_one_flat_field (0, 2); } else if (tag == 0x40b) { /* Red+blue flat field */ phase_one_flat_field (0, 4); } else if (tag == 0x412) { fseek (ifp, 36, SEEK_CUR); diff = abs (get2() - ph1.tag_21a); if (mindiff > diff) { mindiff = diff; off_412 = ftell(ifp) - 38; } } else if (tag == 0x41f && !qlin_applied) { /* Quadrant linearization */ ushort lc[2][2][16], ref[16]; int qr, qc; for (qr = 0; qr < 2; qr++) for (qc = 0; qc < 2; qc++) for (i = 0; i < 16; i++) lc[qr][qc][i] = get4(); for (i = 0; i < 16; i++) { int v = 0; for (qr = 0; qr < 2; qr++) for (qc = 0; qc < 2; qc++) v += lc[qr][qc][i]; ref[i] = (v + 2) >> 2; } for (qr = 0; qr < 2; qr++) { for (qc = 0; qc < 2; qc++) { int cx[19], cf[19]; for (i = 0; i < 16; i++) { cx[1+i] = lc[qr][qc][i]; cf[1+i] = ref[i]; } cx[0] = cf[0] = 0; cx[17] = cf[17] = ((unsigned int)ref[15] * 65535) / lc[qr][qc][15]; cf[18] = cx[18] = 65535; cubic_spline(cx, cf, 19); for (row = (qr ? ph1.split_row : 0); row < (qr ? raw_height : ph1.split_row); row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col = (qc ? ph1.split_col : 0); col < (qc ? raw_width : ph1.split_col); col++) RAW(row,col) = curve[RAW(row,col)]; } } } qlin_applied = 1; } else if (tag == 0x41e && !qmult_applied) { /* Quadrant multipliers */ float qmult[2][2] = { { 1, 1 }, { 1, 1 } }; get4(); get4(); get4(); get4(); qmult[0][0] = 1.0 + getreal(11); get4(); get4(); get4(); get4(); get4(); qmult[0][1] = 1.0 + getreal(11); get4(); get4(); get4(); qmult[1][0] = 1.0 + getreal(11); get4(); get4(); get4(); qmult[1][1] = 1.0 + getreal(11); for (row=0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col=0; col < raw_width; col++) { i = qmult[row >= ph1.split_row][col >= ph1.split_col] * RAW(row,col); RAW(row,col) = LIM(i,0,65535); } } qmult_applied = 1; } else if (tag == 0x431 && !qmult_applied) { /* Quadrant combined */ ushort lc[2][2][7], ref[7]; int qr, qc; for (i = 0; i < 7; i++) ref[i] = get4(); for (qr = 0; qr < 2; qr++) for (qc = 0; qc < 2; qc++) for (i = 0; i < 7; i++) lc[qr][qc][i] = get4(); for (qr = 0; qr < 2; qr++) { for (qc = 0; qc < 2; qc++) { int cx[9], cf[9]; for (i = 0; i < 7; i++) { cx[1+i] = ref[i]; cf[1+i] = ((unsigned) ref[i] * lc[qr][qc][i]) / 10000; } cx[0] = cf[0] = 0; cx[8] = cf[8] = 65535; cubic_spline(cx, cf, 9); for (row = (qr ? ph1.split_row : 0); row < (qr ? raw_height : ph1.split_row); row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col = (qc ? ph1.split_col : 0); col < (qc ? raw_width : ph1.split_col); col++) RAW(row,col) = curve[RAW(row,col)]; } } } qmult_applied = 1; qlin_applied = 1; } fseek (ifp, save, SEEK_SET); } if (off_412) { fseek (ifp, off_412, SEEK_SET); for (i=0; i < 9; i++) head[i] = get4() & 0x7fff; yval[0] = (float *) calloc (head[1]*head[3] + head[2]*head[4], 6); merror (yval[0], "phase_one_correct()"); yval[1] = (float *) (yval[0] + head[1]*head[3]); xval[0] = (ushort *) (yval[1] + head[2]*head[4]); xval[1] = (ushort *) (xval[0] + head[1]*head[3]); get2(); for (i=0; i < 2; i++) for (j=0; j < head[i+1]*head[i+3]; j++) yval[i][j] = getreal(11); for (i=0; i < 2; i++) for (j=0; j < head[i+1]*head[i+3]; j++) xval[i][j] = get2(); for (row=0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col=0; col < raw_width; col++) { cfrac = (float) col * head[3] / raw_width; cfrac -= cip = cfrac; num = RAW(row,col) * 0.5; for (i=cip; i < cip+2; i++) { for (k=j=0; j < head[1]; j++) if (num < xval[0][k = head[1]*i+j]) break; frac = (j == 0 || j == head[1]) ? 0 : (xval[0][k] - num) / (xval[0][k] - xval[0][k-1]); mult[i-cip] = yval[0][k-1] * frac + yval[0][k] * (1-frac); } i = ((mult[0] * (1-cfrac) + mult[1] * cfrac) * row + num) * 2; RAW(row,col) = LIM(i,0,65535); } } free (yval[0]); } #ifdef LIBRAW_LIBRARY_BUILD } catch (...) { if(yval[0]) free(yval[0]); return LIBRAW_CANCELLED_BY_CALLBACK; } #endif return 0; } void CLASS phase_one_load_raw() { int a, b, i; ushort akey, bkey, t_mask; fseek (ifp, ph1.key_off, SEEK_SET); akey = get2(); bkey = get2(); t_mask = ph1.format == 1 ? 0x5555:0x1354; #ifdef LIBRAW_LIBRARY_BUILD if (ph1.black_col || ph1.black_row ) { imgdata.rawdata.ph1_cblack = (short(*)[2])calloc(raw_height*2,sizeof(ushort)); merror(imgdata.rawdata.ph1_cblack,"phase_one_load_raw()"); imgdata.rawdata.ph1_rblack = (short(*)[2])calloc(raw_width*2,sizeof(ushort)); merror(imgdata.rawdata.ph1_rblack,"phase_one_load_raw()"); if (ph1.black_col) { fseek (ifp, ph1.black_col, SEEK_SET); read_shorts ((ushort *)imgdata.rawdata.ph1_cblack[0], raw_height*2); } if (ph1.black_row) { fseek (ifp, ph1.black_row, SEEK_SET); read_shorts ((ushort *) imgdata.rawdata.ph1_rblack[0], raw_width*2); } } #endif fseek (ifp, data_offset, SEEK_SET); read_shorts (raw_image, raw_width*raw_height); if (ph1.format) for (i=0; i < raw_width*raw_height; i+=2) { a = raw_image[i+0] ^ akey; b = raw_image[i+1] ^ bkey; raw_image[i+0] = (a & t_mask) | (b & ~t_mask); raw_image[i+1] = (b & t_mask) | (a & ~t_mask); } } unsigned CLASS ph1_bithuff (int nbits, ushort *huff) { #ifndef LIBRAW_NOTHREADS #define bitbuf tls->ph1_bits.bitbuf #define vbits tls->ph1_bits.vbits #else static UINT64 bitbuf=0; static int vbits=0; #endif unsigned c; if (nbits == -1) return bitbuf = vbits = 0; if (nbits == 0) return 0; if (vbits < nbits) { bitbuf = bitbuf << 32 | get4(); vbits += 32; } c = bitbuf << (64-vbits) >> (64-nbits); if (huff) { vbits -= huff[c] >> 8; return (uchar) huff[c]; } vbits -= nbits; return c; #ifndef LIBRAW_NOTHREADS #undef bitbuf #undef vbits #endif } #define ph1_bits(n) ph1_bithuff(n,0) #define ph1_huff(h) ph1_bithuff(*h,h+1) void CLASS phase_one_load_raw_c() { static const int length[] = { 8,7,6,9,11,10,5,12,14,13 }; int *offset, len[2], pred[2], row, col, i, j; ushort *pixel; short (*c_black)[2], (*r_black)[2]; #ifdef LIBRAW_LIBRARY_BUILD if(ph1.format == 6) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif pixel = (ushort *) calloc (raw_width*3 + raw_height*4, 2); merror (pixel, "phase_one_load_raw_c()"); offset = (int *) (pixel + raw_width); fseek (ifp, strip_offset, SEEK_SET); for (row=0; row < raw_height; row++) offset[row] = get4(); c_black = (short (*)[2]) (offset + raw_height); fseek (ifp, ph1.black_col, SEEK_SET); if (ph1.black_col) read_shorts ((ushort *) c_black[0], raw_height*2); r_black = c_black + raw_height; fseek (ifp, ph1.black_row, SEEK_SET); if (ph1.black_row) read_shorts ((ushort *) r_black[0], raw_width*2); #ifdef LIBRAW_LIBRARY_BUILD // Copy data to internal copy (ever if not read) if (ph1.black_col || ph1.black_row ) { imgdata.rawdata.ph1_cblack = (short(*)[2])calloc(raw_height*2,sizeof(ushort)); merror(imgdata.rawdata.ph1_cblack,"phase_one_load_raw_c()"); memmove(imgdata.rawdata.ph1_cblack,(ushort*)c_black[0],raw_height*2*sizeof(ushort)); imgdata.rawdata.ph1_rblack = (short(*)[2])calloc(raw_width*2,sizeof(ushort)); merror(imgdata.rawdata.ph1_rblack,"phase_one_load_raw_c()"); memmove(imgdata.rawdata.ph1_rblack,(ushort*)r_black[0],raw_width*2*sizeof(ushort)); } #endif for (i=0; i < 256; i++) curve[i] = i*i / 3.969 + 0.5; #ifdef LIBRAW_LIBRARY_BUILD try { #endif for (row=0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif fseek (ifp, data_offset + offset[row], SEEK_SET); ph1_bits(-1); pred[0] = pred[1] = 0; for (col=0; col < raw_width; col++) { if (col >= (raw_width & -8)) len[0] = len[1] = 14; else if ((col & 7) == 0) for (i=0; i < 2; i++) { for (j=0; j < 5 && !ph1_bits(1); j++); if (j--) len[i] = length[j*2 + ph1_bits(1)]; } if ((i = len[col & 1]) == 14) pixel[col] = pred[col & 1] = ph1_bits(16); else pixel[col] = pred[col & 1] += ph1_bits(i) + 1 - (1 << (i - 1)); if (pred[col & 1] >> 16) derror(); if (ph1.format == 5 && pixel[col] < 256) pixel[col] = curve[pixel[col]]; } #ifndef LIBRAW_LIBRARY_BUILD for (col=0; col < raw_width; col++) { int shift = ph1.format == 8? 0: 2; i = (pixel[col] << shift) - ph1.t_black + c_black[row][col >= ph1.split_col] + r_black[col][row >= ph1.split_row]; if (i > 0) RAW(row,col) = i; } #else if(ph1.format == 8) memmove(&RAW(row,0),&pixel[0],raw_width*2); else for (col=0; col < raw_width; col++) RAW(row,col) = pixel[col] << 2; #endif } #ifdef LIBRAW_LIBRARY_BUILD } catch(...) { free (pixel); throw; } #endif free (pixel); maximum = 0xfffc - ph1.t_black; } void CLASS hasselblad_load_raw() { struct jhead jh; int shot, row, col, *back[5], len[2], diff[12], pred, sh, f, s, c; unsigned upix, urow, ucol; ushort *ip; if (!ljpeg_start (&jh, 0)) return; order = 0x4949; ph1_bits(-1); #ifdef LIBRAW_LIBRARY_BUILD try { #endif back[4] = (int *) calloc (raw_width, 3*sizeof **back); merror (back[4], "hasselblad_load_raw()"); FORC3 back[c] = back[4] + c*raw_width; cblack[6] >>= sh = tiff_samples > 1; shot = LIM(shot_select, 1, tiff_samples) - 1; for (row=0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif FORC4 back[(c+3) & 3] = back[c]; for (col=0; col < raw_width; col+=2) { for (s=0; s < tiff_samples*2; s+=2) { FORC(2) len[c] = ph1_huff(jh.huff[0]); FORC(2) { diff[s+c] = ph1_bits(len[c]); if ((diff[s+c] & (1 << (len[c]-1))) == 0) diff[s+c] -= (1 << len[c]) - 1; if (diff[s+c] == 65535) diff[s+c] = -32768; } } for (s=col; s < col+2; s++) { pred = 0x8000 + load_flags; if (col) pred = back[2][s-2]; if (col && row > 1) switch (jh.psv) { case 11: pred += back[0][s]/2 - back[0][s-2]/2; break; } f = (row & 1)*3 ^ ((col+s) & 1); FORC (tiff_samples) { pred += diff[(s & 1)*tiff_samples+c]; upix = pred >> sh & 0xffff; if (raw_image && c == shot) RAW(row,s) = upix; if (image) { urow = row-top_margin + (c & 1); ucol = col-left_margin - ((c >> 1) & 1); ip = &image[urow*width+ucol][f]; if (urow < height && ucol < width) *ip = c < 4 ? upix : (*ip + upix) >> 1; } } back[2][s] = pred; } } } #ifdef LIBRAW_LIBRARY_BUILD } catch (...){ free (back[4]); ljpeg_end (&jh); throw; } #endif free (back[4]); ljpeg_end (&jh); if (image) mix_green = 1; } void CLASS leaf_hdr_load_raw() { ushort *pixel=0; unsigned tile=0, r, c, row, col; if (!filters) { #ifdef LIBRAW_LIBRARY_BUILD if(!image) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif pixel = (ushort *) calloc (raw_width, sizeof *pixel); merror (pixel, "leaf_hdr_load_raw()"); } #ifdef LIBRAW_LIBRARY_BUILD try { #endif FORC(tiff_samples) for (r=0; r < raw_height; r++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif if (r % tile_length == 0) { fseek (ifp, data_offset + 4*tile++, SEEK_SET); fseek (ifp, get4(), SEEK_SET); } if (filters && c != shot_select) continue; if (filters) pixel = raw_image + r*raw_width; read_shorts (pixel, raw_width); if (!filters && (row = r - top_margin) < height) for (col=0; col < width; col++) image[row*width+col][c] = pixel[col+left_margin]; } #ifdef LIBRAW_LIBRARY_BUILD } catch (...) { if(!filters) free(pixel); throw; } #endif if (!filters) { maximum = 0xffff; raw_color = 1; free (pixel); } } void CLASS unpacked_load_raw() { int row, col, bits=0; while (1 << ++bits < maximum); read_shorts (raw_image, raw_width*raw_height); for (row=0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col=0; col < raw_width; col++) if ((RAW(row,col) >>= load_flags) >> bits && (unsigned) (row-top_margin) < height && (unsigned) (col-left_margin) < width) derror(); } } void CLASS unpacked_load_raw_reversed() { int row, col, bits=0; while (1 << ++bits < maximum); for (row=raw_height-1; row >= 0; row--) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif read_shorts (&raw_image[row*raw_width], raw_width); for (col=0; col < raw_width; col++) if ((RAW(row,col) >>= load_flags) >> bits && (unsigned) (row-top_margin) < height && (unsigned) (col-left_margin) < width) derror(); } } void CLASS sinar_4shot_load_raw() { ushort *pixel; unsigned shot, row, col, r, c; if (raw_image) { shot = LIM (shot_select, 1, 4) - 1; fseek (ifp, data_offset + shot*4, SEEK_SET); fseek (ifp, get4(), SEEK_SET); unpacked_load_raw(); return; } #ifdef LIBRAW_LIBRARY_BUILD else if(!image) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif pixel = (ushort *) calloc (raw_width, sizeof *pixel); merror (pixel, "sinar_4shot_load_raw()"); #ifdef LIBRAW_LIBRARY_BUILD try { #endif for (shot=0; shot < 4; shot++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif fseek (ifp, data_offset + shot*4, SEEK_SET); fseek (ifp, get4(), SEEK_SET); for (row=0; row < raw_height; row++) { read_shorts (pixel, raw_width); if ((r = row-top_margin - (shot >> 1 & 1)) >= height) continue; for (col=0; col < raw_width; col++) { if ((c = col-left_margin - (shot & 1)) >= width) continue; image[r*width+c][(row & 1)*3 ^ (~col & 1)] = pixel[col]; } } } #ifdef LIBRAW_LIBRARY_BUILD } catch (...) { free(pixel); throw; } #endif free (pixel); mix_green = 1; } void CLASS imacon_full_load_raw() { int row, col; if (!image) return; #ifdef LIBRAW_LIBRARY_BUILD unsigned short *buf = (unsigned short *)malloc(width*3*sizeof(unsigned short)); merror(buf,"imacon_full_load_raw"); #endif for (row=0; row < height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); read_shorts(buf,width*3); unsigned short (*rowp)[4] = &image[row*width]; for (col=0; col < width; col++) { rowp[col][0]=buf[col*3]; rowp[col][1]=buf[col*3+1]; rowp[col][2]=buf[col*3+2]; rowp[col][3]=0; } #else for (col=0; col < width; col++) read_shorts (image[row*width+col], 3); #endif } #ifdef LIBRAW_LIBRARY_BUILD free(buf); #endif } void CLASS packed_load_raw() { int vbits=0, bwide, rbits, bite, half, irow, row, col, val, i; UINT64 bitbuf=0; bwide = raw_width * tiff_bps / 8; bwide += bwide & load_flags >> 7; rbits = bwide * 8 - raw_width * tiff_bps; if (load_flags & 1) bwide = bwide * 16 / 15; bite = 8 + (load_flags & 24); half = (raw_height+1) >> 1; for (irow=0; irow < raw_height; irow++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif row = irow; if (load_flags & 2 && (row = irow % half * 2 + irow / half) == 1 && load_flags & 4) { if (vbits=0, tiff_compress) fseek (ifp, data_offset - (-half*bwide & -2048), SEEK_SET); else { fseek (ifp, 0, SEEK_END); fseek (ifp, ftell(ifp) >> 3 << 2, SEEK_SET); } } for (col=0; col < raw_width; col++) { for (vbits -= tiff_bps; vbits < 0; vbits += bite) { bitbuf <<= bite; for (i=0; i < bite; i+=8) bitbuf |= (unsigned) (fgetc(ifp) << i); } val = bitbuf << (64-tiff_bps-vbits) >> (64-tiff_bps); RAW(row,col ^ (load_flags >> 6 & 1)) = val; if (load_flags & 1 && (col % 10) == 9 && fgetc(ifp) && row < height+top_margin && col < width+left_margin) derror(); } vbits -= rbits; } } #ifdef LIBRAW_LIBRARY_BUILD ushort raw_stride; void CLASS parse_broadcom () { /* This structure is at offset 0xb0 from the 'BRCM' ident. */ struct { uint8_t umode[32]; uint16_t uwidth; uint16_t uheight; uint16_t padding_right; uint16_t padding_down; uint32_t unknown_block[6]; uint16_t transform; uint16_t format; uint8_t bayer_order; uint8_t bayer_format; } header; header.bayer_order = 0; fseek (ifp, 0xb0 - 0x20, SEEK_CUR); fread (&header, 1, sizeof(header), ifp); raw_stride = ((((((header.uwidth + header.padding_right)*5)+3)>>2) + 0x1f)&(~0x1f)); raw_width = width = header.uwidth; raw_height = height = header.uheight; filters = 0x16161616; /* default Bayer order is 2, BGGR */ switch (header.bayer_order) { case 0: /* RGGB */ filters = 0x94949494; break; case 1: /* GBRG */ filters = 0x49494949; break; case 3: /* GRBG */ filters = 0x61616161; break; } } void CLASS broadcom_load_raw() { uchar *data, *dp; int rev, row, col, c; rev = 3 * (order == 0x4949); data = (uchar *) malloc (raw_stride*2); merror (data, "broadcom_load_raw()"); for (row=0; row < raw_height; row++) { if (fread (data+raw_stride, 1, raw_stride, ifp) < raw_stride) derror(); FORC(raw_stride) data[c] = data[raw_stride+(c ^ rev)]; for (dp=data, col=0; col < raw_width; dp+=5, col+=4) FORC4 RAW(row,col+c) = (dp[c] << 2) | (dp[4] >> (c << 1) & 3); } free (data); } #endif void CLASS nokia_load_raw() { uchar *data, *dp; int rev, dwide, row, col, c; double sum[]={0,0}; rev = 3 * (order == 0x4949); dwide = (raw_width * 5 + 1) / 4; data = (uchar *) malloc (dwide*2); merror (data, "nokia_load_raw()"); #ifdef LIBRAW_LIBRARY_BUILD try { #endif for (row=0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif if (fread (data+dwide, 1, dwide, ifp) < dwide) derror(); FORC(dwide) data[c] = data[dwide+(c ^ rev)]; for (dp=data, col=0; col < raw_width; dp+=5, col+=4) FORC4 RAW(row,col+c) = (dp[c] << 2) | (dp[4] >> (c << 1) & 3); } #ifdef LIBRAW_LIBRARY_BUILD } catch (...){ free (data); throw; } #endif free (data); maximum = 0x3ff; if (strncmp(make,"OmniVision",10)) return; row = raw_height/2; FORC(width-1) { sum[ c & 1] += SQR(RAW(row,c)-RAW(row+1,c+1)); sum[~c & 1] += SQR(RAW(row+1,c)-RAW(row,c+1)); } if (sum[1] > sum[0]) filters = 0x4b4b4b4b; } void CLASS android_tight_load_raw() { uchar *data, *dp; int bwide, row, col, c; bwide = -(-5*raw_width >> 5) << 3; data = (uchar *) malloc (bwide); merror (data, "android_tight_load_raw()"); for (row=0; row < raw_height; row++) { if (fread (data, 1, bwide, ifp) < bwide) derror(); for (dp=data, col=0; col < raw_width; dp+=5, col+=4) FORC4 RAW(row,col+c) = (dp[c] << 2) | (dp[4] >> (c << 1) & 3); } free (data); } void CLASS android_loose_load_raw() { uchar *data, *dp; int bwide, row, col, c; UINT64 bitbuf=0; bwide = (raw_width+5)/6 << 3; data = (uchar *) malloc (bwide); merror (data, "android_loose_load_raw()"); for (row=0; row < raw_height; row++) { if (fread (data, 1, bwide, ifp) < bwide) derror(); for (dp=data, col=0; col < raw_width; dp+=8, col+=6) { FORC(8) bitbuf = (bitbuf << 8) | dp[c^7]; FORC(6) RAW(row,col+c) = (bitbuf >> c*10) & 0x3ff; } } free (data); } void CLASS canon_rmf_load_raw() { int row, col, bits, orow, ocol, c; #ifdef LIBRAW_LIBRARY_BUILD int *words = (int*)malloc(sizeof(int)*(raw_width/3+1)); merror(words,"canon_rmf_load_raw"); #endif for (row=0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); fread(words,sizeof(int),raw_width/3,ifp); for (col=0; col < raw_width-2; col+=3) { bits = words[col/3]; FORC3 { orow = row; if ((ocol = col+c-4) < 0) { ocol += raw_width; if ((orow -= 2) < 0) orow += raw_height; } RAW(orow,ocol) = curve[bits >> (10*c+2) & 0x3ff]; } } #else for (col=0; col < raw_width-2; col+=3) { bits = get4(); FORC3 { orow = row; if ((ocol = col+c-4) < 0) { ocol += raw_width; if ((orow -= 2) < 0) orow += raw_height; } RAW(orow,ocol) = curve[bits >> (10*c+2) & 0x3ff]; } } #endif } #ifdef LIBRAW_LIBRARY_BUILD free(words); #endif maximum = curve[0x3ff]; } unsigned CLASS pana_bits (int nbits) { #ifndef LIBRAW_NOTHREADS #define buf tls->pana_bits.buf #define vbits tls->pana_bits.vbits #else static uchar buf[0x4000]; static int vbits; #endif int byte; if (!nbits) return vbits=0; if (!vbits) { fread (buf+load_flags, 1, 0x4000-load_flags, ifp); fread (buf, 1, load_flags, ifp); } vbits = (vbits - nbits) & 0x1ffff; byte = vbits >> 3 ^ 0x3ff0; return (buf[byte] | buf[byte+1] << 8) >> (vbits & 7) & ~((~0u) << nbits); #ifndef LIBRAW_NOTHREADS #undef buf #undef vbits #endif } void CLASS panasonic_load_raw() { int row, col, i, j, sh=0, pred[2], nonz[2]; pana_bits(0); for (row = 0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col=0; col < raw_width; col++) { if ((i = col % 14) == 0) pred[0] = pred[1] = nonz[0] = nonz[1] = 0; if (i % 3 == 2) sh = 4 >> (3 - pana_bits(2)); if (nonz[i & 1]) { if ((j = pana_bits(8))) { if ((pred[i & 1] -= 0x80 << sh) < 0 || sh == 4) pred[i & 1] &= ~((~0u) << sh); pred[i & 1] += j << sh; } } else if ((nonz[i & 1] = pana_bits(8)) || i > 11) pred[i & 1] = nonz[i & 1] << 4 | pana_bits(4); if ((RAW(row, col) = pred[col & 1]) > 4098 && col < width && row < height) derror(); } } } void CLASS olympus_load_raw() { ushort huff[4096]; int row, col, nbits, sign, low, high, i, c, w, n, nw; int acarry[2][3], *carry, pred, diff; huff[n=0] = 0xc0c; for (i=12; i--; ) FORC(2048 >> i) huff[++n] = (i+1) << 8 | i; fseek (ifp, 7, SEEK_CUR); getbits(-1); for (row=0; row < height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif memset (acarry, 0, sizeof acarry); for (col=0; col < raw_width; col++) { carry = acarry[col & 1]; i = 2 * (carry[2] < 3); for (nbits=2+i; (ushort) carry[0] >> (nbits+i); nbits++); low = (sign = getbits(3)) & 3; sign = sign << 29 >> 31; if ((high = getbithuff(12,huff)) == 12) high = getbits(16-nbits) >> 1; carry[0] = (high << nbits) | getbits(nbits); diff = (carry[0] ^ sign) + carry[1]; carry[1] = (diff*3 + carry[1]) >> 5; carry[2] = carry[0] > 16 ? 0 : carry[2]+1; if (col >= width) continue; if (row < 2 && col < 2) pred = 0; else if (row < 2) pred = RAW(row,col-2); else if (col < 2) pred = RAW(row-2,col); else { w = RAW(row,col-2); n = RAW(row-2,col); nw = RAW(row-2,col-2); if ((w < nw && nw < n) || (n < nw && nw < w)) { if (ABS(w-nw) > 32 || ABS(n-nw) > 32) pred = w + n - nw; else pred = (w + n) >> 1; } else pred = ABS(w-nw) > ABS(n-nw) ? w : n; } if ((RAW(row,col) = pred + ((diff << 2) | low)) >> 12) derror(); } } } void CLASS minolta_rd175_load_raw() { uchar pixel[768]; unsigned irow, box, row, col; for (irow=0; irow < 1481; irow++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif if (fread (pixel, 1, 768, ifp) < 768) derror(); box = irow / 82; row = irow % 82 * 12 + ((box < 12) ? box | 1 : (box-12)*2); switch (irow) { case 1477: case 1479: continue; case 1476: row = 984; break; case 1480: row = 985; break; case 1478: row = 985; box = 1; } if ((box < 12) && (box & 1)) { for (col=0; col < 1533; col++, row ^= 1) if (col != 1) RAW(row,col) = (col+1) & 2 ? pixel[col/2-1] + pixel[col/2+1] : pixel[col/2] << 1; RAW(row,1) = pixel[1] << 1; RAW(row,1533) = pixel[765] << 1; } else for (col=row & 1; col < 1534; col+=2) RAW(row,col) = pixel[col/2] << 1; } maximum = 0xff << 1; } void CLASS quicktake_100_load_raw() { uchar pixel[484][644]; static const short gstep[16] = { -89,-60,-44,-32,-22,-15,-8,-2,2,8,15,22,32,44,60,89 }; static const short rstep[6][4] = { { -3,-1,1,3 }, { -5,-1,1,5 }, { -8,-2,2,8 }, { -13,-3,3,13 }, { -19,-4,4,19 }, { -28,-6,6,28 } }; static const short t_curve[256] = { 0,1,2,3,4,5,6,7,8,9,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27, 28,29,30,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,53, 54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,74,75,76,77,78, 79,80,81,82,83,84,86,88,90,92,94,97,99,101,103,105,107,110,112,114,116, 118,120,123,125,127,129,131,134,136,138,140,142,144,147,149,151,153,155, 158,160,162,164,166,168,171,173,175,177,179,181,184,186,188,190,192,195, 197,199,201,203,205,208,210,212,214,216,218,221,223,226,230,235,239,244, 248,252,257,261,265,270,274,278,283,287,291,296,300,305,309,313,318,322, 326,331,335,339,344,348,352,357,361,365,370,374,379,383,387,392,396,400, 405,409,413,418,422,426,431,435,440,444,448,453,457,461,466,470,474,479, 483,487,492,496,500,508,519,531,542,553,564,575,587,598,609,620,631,643, 654,665,676,687,698,710,721,732,743,754,766,777,788,799,810,822,833,844, 855,866,878,889,900,911,922,933,945,956,967,978,989,1001,1012,1023 }; int rb, row, col, sharp, val=0; #ifdef LIBRAW_LIBRARY_BUILD if(width>640 || height > 480) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif getbits(-1); memset (pixel, 0x80, sizeof pixel); for (row=2; row < height+2; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col=2+(row & 1); col < width+2; col+=2) { val = ((pixel[row-1][col-1] + 2*pixel[row-1][col+1] + pixel[row][col-2]) >> 2) + gstep[getbits(4)]; pixel[row][col] = val = LIM(val,0,255); if (col < 4) pixel[row][col-2] = pixel[row+1][~row & 1] = val; if (row == 2) pixel[row-1][col+1] = pixel[row-1][col+3] = val; } pixel[row][col] = val; } for (rb=0; rb < 2; rb++) for (row=2+rb; row < height+2; row+=2) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col=3-(row & 1); col < width+2; col+=2) { if (row < 4 || col < 4) sharp = 2; else { val = ABS(pixel[row-2][col] - pixel[row][col-2]) + ABS(pixel[row-2][col] - pixel[row-2][col-2]) + ABS(pixel[row][col-2] - pixel[row-2][col-2]); sharp = val < 4 ? 0 : val < 8 ? 1 : val < 16 ? 2 : val < 32 ? 3 : val < 48 ? 4 : 5; } val = ((pixel[row-2][col] + pixel[row][col-2]) >> 1) + rstep[sharp][getbits(2)]; pixel[row][col] = val = LIM(val,0,255); if (row < 4) pixel[row-2][col+2] = val; if (col < 4) pixel[row+2][col-2] = val; } } for (row=2; row < height+2; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col=3-(row & 1); col < width+2; col+=2) { val = ((pixel[row][col-1] + (pixel[row][col] << 2) + pixel[row][col+1]) >> 1) - 0x100; pixel[row][col] = LIM(val,0,255); } } for (row=0; row < height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col=0; col < width; col++) RAW(row,col) = t_curve[pixel[row+2][col+2]]; } maximum = 0x3ff; } #define radc_token(tree) ((signed char) getbithuff(8,huff[tree])) #define FORYX for (y=1; y < 3; y++) for (x=col+1; x >= col; x--) #define PREDICTOR (c ? (buf[c][y-1][x] + buf[c][y][x+1]) / 2 \ : (buf[c][y-1][x+1] + 2*buf[c][y-1][x] + buf[c][y][x+1]) / 4) #ifdef __GNUC__ # if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) # pragma GCC optimize("no-aggressive-loop-optimizations") # endif #endif void CLASS kodak_radc_load_raw() { #ifdef LIBRAW_LIBRARY_BUILD // All kodak radc images are 768x512 if(width>768 || raw_width>768 || height > 512 || raw_height>512 ) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif static const signed char src[] = { 1,1, 2,3, 3,4, 4,2, 5,7, 6,5, 7,6, 7,8, 1,0, 2,1, 3,3, 4,4, 5,2, 6,7, 7,6, 8,5, 8,8, 2,1, 2,3, 3,0, 3,2, 3,4, 4,6, 5,5, 6,7, 6,8, 2,0, 2,1, 2,3, 3,2, 4,4, 5,6, 6,7, 7,5, 7,8, 2,1, 2,4, 3,0, 3,2, 3,3, 4,7, 5,5, 6,6, 6,8, 2,3, 3,1, 3,2, 3,4, 3,5, 3,6, 4,7, 5,0, 5,8, 2,3, 2,6, 3,0, 3,1, 4,4, 4,5, 4,7, 5,2, 5,8, 2,4, 2,7, 3,3, 3,6, 4,1, 4,2, 4,5, 5,0, 5,8, 2,6, 3,1, 3,3, 3,5, 3,7, 3,8, 4,0, 5,2, 5,4, 2,0, 2,1, 3,2, 3,3, 4,4, 4,5, 5,6, 5,7, 4,8, 1,0, 2,2, 2,-2, 1,-3, 1,3, 2,-17, 2,-5, 2,5, 2,17, 2,-7, 2,2, 2,9, 2,18, 2,-18, 2,-9, 2,-2, 2,7, 2,-28, 2,28, 3,-49, 3,-9, 3,9, 4,49, 5,-79, 5,79, 2,-1, 2,13, 2,26, 3,39, 4,-16, 5,55, 6,-37, 6,76, 2,-26, 2,-13, 2,1, 3,-39, 4,16, 5,-55, 6,-76, 6,37 }; ushort huff[19][256]; int row, col, tree, nreps, rep, step, i, c, s, r, x, y, val; short last[3] = { 16,16,16 }, mul[3], buf[3][3][386]; static const ushort pt[] = { 0,0, 1280,1344, 2320,3616, 3328,8000, 4095,16383, 65535,16383 }; for (i=2; i < 12; i+=2) for (c=pt[i-2]; c <= pt[i]; c++) curve[c] = (float) (c-pt[i-2]) / (pt[i]-pt[i-2]) * (pt[i+1]-pt[i-1]) + pt[i-1] + 0.5; for (s=i=0; i < sizeof src; i+=2) FORC(256 >> src[i]) ((ushort *)huff)[s++] = src[i] << 8 | (uchar) src[i+1]; s = kodak_cbpp == 243 ? 2 : 3; FORC(256) huff[18][c] = (8-s) << 8 | c >> s << s | 1 << (s-1); getbits(-1); for (i=0; i < sizeof(buf)/sizeof(short); i++) ((short *)buf)[i] = 2048; for (row=0; row < height; row+=4) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif FORC3 mul[c] = getbits(6); #ifdef LIBRAW_LIBRARY_BUILD if(!mul[0] || !mul[1] || !mul[2]) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif FORC3 { val = ((0x1000000/last[c] + 0x7ff) >> 12) * mul[c]; s = val > 65564 ? 10:12; x = ~((~0u) << (s-1)); val <<= 12-s; for (i=0; i < sizeof(buf[0])/sizeof(short); i++) ((short *)buf[c])[i] = (((short *)buf[c])[i] * val + x) >> s; last[c] = mul[c]; for (r=0; r <= !c; r++) { buf[c][1][width/2] = buf[c][2][width/2] = mul[c] << 7; for (tree=1, col=width/2; col > 0; ) { if ((tree = radc_token(tree))) { col -= 2; if (tree == 8) FORYX buf[c][y][x] = (uchar) radc_token(18) * mul[c]; else FORYX buf[c][y][x] = radc_token(tree+10) * 16 + PREDICTOR; } else do { nreps = (col > 2) ? radc_token(9) + 1 : 1; for (rep=0; rep < 8 && rep < nreps && col > 0; rep++) { col -= 2; FORYX buf[c][y][x] = PREDICTOR; if (rep & 1) { step = radc_token(10) << 4; FORYX buf[c][y][x] += step; } } } while (nreps == 9); } for (y=0; y < 2; y++) for (x=0; x < width/2; x++) { val = (buf[c][y+1][x] << 4) / mul[c]; if (val < 0) val = 0; if (c) RAW(row+y*2+c-1,x*2+2-c) = val; else RAW(row+r*2+y,x*2+y) = val; } memcpy (buf[c][0]+!c, buf[c][2], sizeof buf[c][0]-2*!c); } } for (y=row; y < row+4; y++) for (x=0; x < width; x++) if ((x+y) & 1) { r = x ? x-1 : x+1; s = x+1 < width ? x+1 : x-1; val = (RAW(y,x)-2048)*2 + (RAW(y,r)+RAW(y,s))/2; if (val < 0) val = 0; RAW(y,x) = val; } } for (i=0; i < height*width; i++) raw_image[i] = curve[raw_image[i]]; maximum = 0x3fff; } #undef FORYX #undef PREDICTOR #ifdef NO_JPEG void CLASS kodak_jpeg_load_raw() {} void CLASS lossy_dng_load_raw() {} #else #ifndef LIBRAW_LIBRARY_BUILD METHODDEF(boolean) fill_input_buffer (j_decompress_ptr cinfo) { static uchar jpeg_buffer[4096]; size_t nbytes; nbytes = fread (jpeg_buffer, 1, 4096, ifp); swab (jpeg_buffer, jpeg_buffer, nbytes); cinfo->src->next_input_byte = jpeg_buffer; cinfo->src->bytes_in_buffer = nbytes; return TRUE; } void CLASS kodak_jpeg_load_raw() { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPARRAY buf; JSAMPLE (*pixel)[3]; int row, col; cinfo.err = jpeg_std_error (&jerr); jpeg_create_decompress (&cinfo); jpeg_stdio_src (&cinfo, ifp); cinfo.src->fill_input_buffer = fill_input_buffer; jpeg_read_header (&cinfo, TRUE); jpeg_start_decompress (&cinfo); if ((cinfo.output_width != width ) || (cinfo.output_height*2 != height ) || (cinfo.output_components != 3 )) { fprintf (stderr,_("%s: incorrect JPEG dimensions\n"), ifname); jpeg_destroy_decompress (&cinfo); longjmp (failure, 3); } buf = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, width*3, 1); while (cinfo.output_scanline < cinfo.output_height) { row = cinfo.output_scanline * 2; jpeg_read_scanlines (&cinfo, buf, 1); pixel = (JSAMPLE (*)[3]) buf[0]; for (col=0; col < width; col+=2) { RAW(row+0,col+0) = pixel[col+0][1] << 1; RAW(row+1,col+1) = pixel[col+1][1] << 1; RAW(row+0,col+1) = pixel[col][0] + pixel[col+1][0]; RAW(row+1,col+0) = pixel[col][2] + pixel[col+1][2]; } } jpeg_finish_decompress (&cinfo); jpeg_destroy_decompress (&cinfo); maximum = 0xff << 1; } #else struct jpegErrorManager { struct jpeg_error_mgr pub; }; static void jpegErrorExit (j_common_ptr cinfo) { jpegErrorManager* myerr = (jpegErrorManager*) cinfo->err; throw LIBRAW_EXCEPTION_DECODE_JPEG; } // LibRaw's Kodak_jpeg_load_raw void CLASS kodak_jpeg_load_raw() { if(data_size < 1) throw LIBRAW_EXCEPTION_DECODE_JPEG; int row, col; jpegErrorManager jerr; struct jpeg_decompress_struct cinfo; cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = jpegErrorExit; unsigned char *jpg_buf = (unsigned char *)malloc(data_size); merror(jpg_buf,"kodak_jpeg_load_raw"); unsigned char *pixel_buf = (unsigned char*) malloc(width*3); jpeg_create_decompress (&cinfo); merror(pixel_buf,"kodak_jpeg_load_raw"); fread(jpg_buf,data_size,1,ifp); swab ((char*)jpg_buf, (char*)jpg_buf, data_size); try { jpeg_mem_src(&cinfo, jpg_buf, data_size); int rc = jpeg_read_header(&cinfo, TRUE); if(rc!=1) throw LIBRAW_EXCEPTION_DECODE_JPEG; jpeg_start_decompress (&cinfo); if ((cinfo.output_width != width ) || (cinfo.output_height*2 != height ) || (cinfo.output_components != 3 )) { throw LIBRAW_EXCEPTION_DECODE_JPEG; } unsigned char *buf[1]; buf[0] = pixel_buf; while (cinfo.output_scanline < cinfo.output_height) { checkCancel(); row = cinfo.output_scanline * 2; jpeg_read_scanlines (&cinfo, buf, 1); unsigned char (*pixel)[3] = (unsigned char (*)[3]) buf[0]; for (col=0; col < width; col+=2) { RAW(row+0,col+0) = pixel[col+0][1] << 1; RAW(row+1,col+1) = pixel[col+1][1] << 1; RAW(row+0,col+1) = pixel[col][0] + pixel[col+1][0]; RAW(row+1,col+0) = pixel[col][2] + pixel[col+1][2]; } } } catch (...) { jpeg_finish_decompress (&cinfo); jpeg_destroy_decompress (&cinfo); free(jpg_buf); free(pixel_buf); throw; } jpeg_finish_decompress (&cinfo); jpeg_destroy_decompress (&cinfo); free(jpg_buf); free(pixel_buf); maximum = 0xff << 1; } #endif #ifndef LIBRAW_LIBRARY_BUILD void CLASS gamma_curve (double pwr, double ts, int mode, int imax); #endif void CLASS lossy_dng_load_raw() { #ifdef LIBRAW_LIBRARY_BUILD if(!image) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPARRAY buf; JSAMPLE (*pixel)[3]; unsigned sorder=order, ntags, opcode, deg, i, j, c; unsigned save=data_offset-4, trow=0, tcol=0, row, col; ushort cur[3][256]; double coeff[9], tot; if (meta_offset) { fseek (ifp, meta_offset, SEEK_SET); order = 0x4d4d; ntags = get4(); while (ntags--) { opcode = get4(); get4(); get4(); if (opcode != 8) { fseek (ifp, get4(), SEEK_CUR); continue; } fseek (ifp, 20, SEEK_CUR); if ((c = get4()) > 2) break; fseek (ifp, 12, SEEK_CUR); if ((deg = get4()) > 8) break; for (i=0; i <= deg && i < 9; i++) coeff[i] = getreal(12); for (i=0; i < 256; i++) { for (tot=j=0; j <= deg; j++) tot += coeff[j] * pow(i/255.0, (int)j); cur[c][i] = tot*0xffff; } } order = sorder; } else { gamma_curve (1/2.4, 12.92, 1, 255); FORC3 memcpy (cur[c], curve, sizeof cur[0]); } cinfo.err = jpeg_std_error (&jerr); jpeg_create_decompress (&cinfo); while (trow < raw_height) { fseek (ifp, save+=4, SEEK_SET); if (tile_length < INT_MAX) fseek (ifp, get4(), SEEK_SET); #ifdef LIBRAW_LIBRARY_BUILD if(libraw_internal_data.internal_data.input->jpeg_src(&cinfo) == -1) { jpeg_destroy_decompress(&cinfo); throw LIBRAW_EXCEPTION_DECODE_JPEG; } #else jpeg_stdio_src (&cinfo, ifp); #endif jpeg_read_header (&cinfo, TRUE); jpeg_start_decompress (&cinfo); buf = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, cinfo.output_width*3, 1); #ifdef LIBRAW_LIBRARY_BUILD try { #endif while (cinfo.output_scanline < cinfo.output_height && (row = trow + cinfo.output_scanline) < height) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif jpeg_read_scanlines (&cinfo, buf, 1); pixel = (JSAMPLE (*)[3]) buf[0]; for (col=0; col < cinfo.output_width && tcol+col < width; col++) { FORC3 image[row*width+tcol+col][c] = cur[c][pixel[col][c]]; } } #ifdef LIBRAW_LIBRARY_BUILD } catch(...) { jpeg_destroy_decompress (&cinfo); throw; } #endif jpeg_abort_decompress (&cinfo); if ((tcol += tile_width) >= raw_width) trow += tile_length + (tcol = 0); } jpeg_destroy_decompress (&cinfo); maximum = 0xffff; } #endif void CLASS kodak_dc120_load_raw() { static const int mul[4] = { 162, 192, 187, 92 }; static const int add[4] = { 0, 636, 424, 212 }; uchar pixel[848]; int row, shift, col; for (row=0; row < height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif if (fread (pixel, 1, 848, ifp) < 848) derror(); shift = row * mul[row & 3] + add[row & 3]; for (col=0; col < width; col++) RAW(row,col) = (ushort) pixel[(col + shift) % 848]; } maximum = 0xff; } void CLASS eight_bit_load_raw() { uchar *pixel; unsigned row, col; pixel = (uchar *) calloc (raw_width, sizeof *pixel); merror (pixel, "eight_bit_load_raw()"); #ifdef LIBRAW_LIBRARY_BUILD try { #endif for (row=0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif if (fread (pixel, 1, raw_width, ifp) < raw_width) derror(); for (col=0; col < raw_width; col++) RAW(row,col) = curve[pixel[col]]; } #ifdef LIBRAW_LIBRARY_BUILD } catch(...) { free (pixel); throw; } #endif free (pixel); maximum = curve[0xff]; } void CLASS kodak_c330_load_raw() { #ifdef LIBRAW_LIBRARY_BUILD if(!image) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif uchar *pixel; int row, col, y, cb, cr, rgb[3], c; pixel = (uchar *) calloc (raw_width, 2*sizeof *pixel); merror (pixel, "kodak_c330_load_raw()"); #ifdef LIBRAW_LIBRARY_BUILD try { #endif for (row=0; row < height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif if (fread (pixel, raw_width, 2, ifp) < 2) derror(); if (load_flags && (row & 31) == 31) fseek (ifp, raw_width*32, SEEK_CUR); for (col=0; col < width; col++) { y = pixel[col*2]; cb = pixel[(col*2 & -4) | 1] - 128; cr = pixel[(col*2 & -4) | 3] - 128; rgb[1] = y - ((cb + cr + 2) >> 2); rgb[2] = rgb[1] + cb; rgb[0] = rgb[1] + cr; FORC3 image[row*width+col][c] = curve[LIM(rgb[c],0,255)]; } } #ifdef LIBRAW_LIBRARY_BUILD } catch(...) { free (pixel); throw; } #endif free (pixel); maximum = curve[0xff]; } void CLASS kodak_c603_load_raw() { #ifdef LIBRAW_LIBRARY_BUILD if(!image) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif uchar *pixel; int row, col, y, cb, cr, rgb[3], c; pixel = (uchar *) calloc (raw_width, 3*sizeof *pixel); merror (pixel, "kodak_c603_load_raw()"); #ifdef LIBRAW_LIBRARY_BUILD try { #endif for (row=0; row < height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif if (~row & 1) if (fread (pixel, raw_width, 3, ifp) < 3) derror(); for (col=0; col < width; col++) { y = pixel[width*2*(row & 1) + col]; cb = pixel[width + (col & -2)] - 128; cr = pixel[width + (col & -2)+1] - 128; rgb[1] = y - ((cb + cr + 2) >> 2); rgb[2] = rgb[1] + cb; rgb[0] = rgb[1] + cr; FORC3 image[row*width+col][c] = curve[LIM(rgb[c],0,255)]; } } #ifdef LIBRAW_LIBRARY_BUILD } catch(...) { free (pixel); throw; } #endif free (pixel); maximum = curve[0xff]; } void CLASS kodak_262_load_raw() { static const uchar kodak_tree[2][26] = { { 0,1,5,1,1,2,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9 }, { 0,3,1,1,1,1,1,2,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9 } }; ushort *huff[2]; uchar *pixel; int *strip, ns, c, row, col, chess, pi=0, pi1, pi2, pred, val; FORC(2) huff[c] = make_decoder (kodak_tree[c]); ns = (raw_height+63) >> 5; pixel = (uchar *) malloc (raw_width*32 + ns*4); merror (pixel, "kodak_262_load_raw()"); strip = (int *) (pixel + raw_width*32); order = 0x4d4d; FORC(ns) strip[c] = get4(); #ifdef LIBRAW_LIBRARY_BUILD try { #endif for (row=0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif if ((row & 31) == 0) { fseek (ifp, strip[row >> 5], SEEK_SET); getbits(-1); pi = 0; } for (col=0; col < raw_width; col++) { chess = (row + col) & 1; pi1 = chess ? pi-2 : pi-raw_width-1; pi2 = chess ? pi-2*raw_width : pi-raw_width+1; if (col <= chess) pi1 = -1; if (pi1 < 0) pi1 = pi2; if (pi2 < 0) pi2 = pi1; if (pi1 < 0 && col > 1) pi1 = pi2 = pi-2; pred = (pi1 < 0) ? 0 : (pixel[pi1] + pixel[pi2]) >> 1; pixel[pi] = val = pred + ljpeg_diff (huff[chess]); if (val >> 8) derror(); val = curve[pixel[pi++]]; RAW(row,col) = val; } } #ifdef LIBRAW_LIBRARY_BUILD } catch(...) { free (pixel); throw; } #endif free (pixel); FORC(2) free (huff[c]); } int CLASS kodak_65000_decode (short *out, int bsize) { uchar c, blen[768]; ushort raw[6]; INT64 bitbuf=0; int save, bits=0, i, j, len, diff; save = ftell(ifp); bsize = (bsize + 3) & -4; for (i=0; i < bsize; i+=2) { c = fgetc(ifp); if ((blen[i ] = c & 15) > 12 || (blen[i+1] = c >> 4) > 12 ) { fseek (ifp, save, SEEK_SET); for (i=0; i < bsize; i+=8) { read_shorts (raw, 6); out[i ] = raw[0] >> 12 << 8 | raw[2] >> 12 << 4 | raw[4] >> 12; out[i+1] = raw[1] >> 12 << 8 | raw[3] >> 12 << 4 | raw[5] >> 12; for (j=0; j < 6; j++) out[i+2+j] = raw[j] & 0xfff; } return 1; } } if ((bsize & 7) == 4) { bitbuf = fgetc(ifp) << 8; bitbuf += fgetc(ifp); bits = 16; } for (i=0; i < bsize; i++) { len = blen[i]; if (bits < len) { for (j=0; j < 32; j+=8) bitbuf += (INT64) fgetc(ifp) << (bits+(j^8)); bits += 32; } diff = bitbuf & (0xffff >> (16-len)); bitbuf >>= len; bits -= len; if ((diff & (1 << (len-1))) == 0) diff -= (1 << len) - 1; out[i] = diff; } return 0; } void CLASS kodak_65000_load_raw() { short buf[272]; /* extra room for data stored w/o predictor */ int row, col, len, pred[2], ret, i; for (row=0; row < height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col=0; col < width; col+=256) { pred[0] = pred[1] = 0; len = MIN (256, width-col); ret = kodak_65000_decode (buf, len); for (i=0; i < len; i++) { int idx = ret ? buf[i] : (pred[i & 1] += buf[i]); if(idx >=0 && idx <= 0xffff) { if ((RAW(row,col+i) = curve[idx]) >> 12) derror(); } else derror(); } } } } void CLASS kodak_ycbcr_load_raw() { #ifdef LIBRAW_LIBRARY_BUILD if(!image) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif short buf[384], *bp; int row, col, len, c, i, j, k, y[2][2], cb, cr, rgb[3]; ushort *ip; if (!image) return; unsigned int bits = (load_flags && load_flags > 9 && load_flags < 17)?load_flags:10; for (row=0; row < height; row+=2) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col=0; col < width; col+=128) { len = MIN (128, width-col); kodak_65000_decode (buf, len*3); y[0][1] = y[1][1] = cb = cr = 0; for (bp=buf, i=0; i < len; i+=2, bp+=2) { cb += bp[4]; cr += bp[5]; rgb[1] = -((cb + cr + 2) >> 2); rgb[2] = rgb[1] + cb; rgb[0] = rgb[1] + cr; for (j=0; j < 2; j++) for (k=0; k < 2; k++) { if ((y[j][k] = y[j][k^1] + *bp++) >> bits) derror(); ip = image[(row+j)*width + col+i+k]; FORC3 ip[c] = curve[LIM(y[j][k]+rgb[c], 0, 0xfff)]; } } } } } void CLASS kodak_rgb_load_raw() { #ifdef LIBRAW_LIBRARY_BUILD if(!image) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif short buf[768], *bp; int row, col, len, c, i, rgb[3],ret; ushort *ip=image[0]; for (row=0; row < height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col=0; col < width; col+=256) { len = MIN (256, width-col); ret = kodak_65000_decode (buf, len*3); memset (rgb, 0, sizeof rgb); for (bp=buf, i=0; i < len; i++, ip+=4) #ifdef LIBRAW_LIBRARY_BUILD if(load_flags == 12) { FORC3 ip[c] = ret ? (*bp++) : (rgb[c] += *bp++); } else #endif FORC3 if ((ip[c] = ret ? (*bp++) : (rgb[c] += *bp++)) >> 12) derror(); } } } void CLASS kodak_thumb_load_raw() { #ifdef LIBRAW_LIBRARY_BUILD if(!image) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif int row, col; colors = thumb_misc >> 5; for (row=0; row < height; row++) for (col=0; col < width; col++) read_shorts (image[row*width+col], colors); maximum = (1 << (thumb_misc & 31)) - 1; } void CLASS sony_decrypt (unsigned *data, int len, int start, int key) { #ifndef LIBRAW_NOTHREADS #define pad tls->sony_decrypt.pad #define p tls->sony_decrypt.p #else static unsigned pad[128], p; #endif if (start) { for (p=0; p < 4; p++) pad[p] = key = key * 48828125 + 1; pad[3] = pad[3] << 1 | (pad[0]^pad[2]) >> 31; for (p=4; p < 127; p++) pad[p] = (pad[p-4]^pad[p-2]) << 1 | (pad[p-3]^pad[p-1]) >> 31; for (p=0; p < 127; p++) pad[p] = htonl(pad[p]); } while (len--) { *data++ ^= pad[p & 127] = pad[(p+1) & 127] ^ pad[(p+65) & 127]; p++; } #ifndef LIBRAW_NOTHREADS #undef pad #undef p #endif } void CLASS sony_load_raw() { uchar head[40]; ushort *pixel; unsigned i, key, row, col; fseek (ifp, 200896, SEEK_SET); fseek (ifp, (unsigned) fgetc(ifp)*4 - 1, SEEK_CUR); order = 0x4d4d; key = get4(); fseek (ifp, 164600, SEEK_SET); fread (head, 1, 40, ifp); sony_decrypt ((unsigned *) head, 10, 1, key); for (i=26; i-- > 22; ) key = key << 8 | head[i]; fseek (ifp, data_offset, SEEK_SET); for (row=0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif pixel = raw_image + row*raw_width; if (fread (pixel, 2, raw_width, ifp) < raw_width) derror(); sony_decrypt ((unsigned *) pixel, raw_width/2, !row, key); for (col=0; col < raw_width; col++) if ((pixel[col] = ntohs(pixel[col])) >> 14) derror(); } maximum = 0x3ff0; } void CLASS sony_arw_load_raw() { ushort huff[32770]; static const ushort tab[18] = { 0xf11,0xf10,0xe0f,0xd0e,0xc0d,0xb0c,0xa0b,0x90a,0x809, 0x708,0x607,0x506,0x405,0x304,0x303,0x300,0x202,0x201 }; int i, c, n, col, row, sum=0; huff[0] = 15; for (n=i=0; i < 18; i++) FORC(32768 >> (tab[i] >> 8)) huff[++n] = tab[i]; getbits(-1); for (col = raw_width; col--; ) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (row=0; row < raw_height+1; row+=2) { if (row == raw_height) row = 1; if ((sum += ljpeg_diff(huff)) >> 12) derror(); if (row < height) RAW(row,col) = sum; } } } void CLASS sony_arw2_load_raw() { uchar *data, *dp; ushort pix[16]; int row, col, val, max, min, imax, imin, sh, bit, i; data = (uchar *) malloc (raw_width+1); merror (data, "sony_arw2_load_raw()"); #ifdef LIBRAW_LIBRARY_BUILD try { #endif for (row=0; row < height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif fread (data, 1, raw_width, ifp); for (dp=data, col=0; col < raw_width-30; dp+=16) { max = 0x7ff & (val = sget4(dp)); min = 0x7ff & val >> 11; imax = 0x0f & val >> 22; imin = 0x0f & val >> 26; for (sh=0; sh < 4 && 0x80 << sh <= max-min; sh++); #ifdef LIBRAW_LIBRARY_BUILD /* flag checks if outside of loop */ if(! (imgdata.params.raw_processing_options & LIBRAW_PROCESSING_SONYARW2_ALLFLAGS) // no flag set || (imgdata.params.raw_processing_options & LIBRAW_PROCESSING_SONYARW2_DELTATOVALUE) ) { for (bit=30, i=0; i < 16; i++) if (i == imax) pix[i] = max; else if (i == imin) pix[i] = min; else { pix[i] = ((sget2(dp+(bit >> 3)) >> (bit & 7) & 0x7f) << sh) + min; if (pix[i] > 0x7ff) pix[i] = 0x7ff; bit += 7; } } else if(imgdata.params.raw_processing_options & LIBRAW_PROCESSING_SONYARW2_BASEONLY) { for (bit=30, i=0; i < 16; i++) if (i == imax) pix[i] = max; else if (i == imin) pix[i] = min; else pix[i]=0; } else if(imgdata.params.raw_processing_options & LIBRAW_PROCESSING_SONYARW2_DELTAONLY) { for (bit=30, i=0; i < 16; i++) if (i == imax) pix[i] = 0; else if (i == imin) pix[i] = 0; else { pix[i] = ((sget2(dp+(bit >> 3)) >> (bit & 7) & 0x7f) << sh) + min; if (pix[i] > 0x7ff) pix[i] = 0x7ff; bit += 7; } } else if(imgdata.params.raw_processing_options & LIBRAW_PROCESSING_SONYARW2_DELTAZEROBASE) { for (bit=30, i=0; i < 16; i++) if (i == imax) pix[i] = 0; else if (i == imin) pix[i] = 0; else { pix[i] = ((sget2(dp+(bit >> 3)) >> (bit & 7) & 0x7f) << sh); if (pix[i] > 0x7ff) pix[i] = 0x7ff; bit += 7; } } #else /* unaltered dcraw processing */ for (bit=30, i=0; i < 16; i++) if (i == imax) pix[i] = max; else if (i == imin) pix[i] = min; else { pix[i] = ((sget2(dp+(bit >> 3)) >> (bit & 7) & 0x7f) << sh) + min; if (pix[i] > 0x7ff) pix[i] = 0x7ff; bit += 7; } #endif #ifdef LIBRAW_LIBRARY_BUILD if(imgdata.params.raw_processing_options & LIBRAW_PROCESSING_SONYARW2_DELTATOVALUE) { for (i=0; i < 16; i++, col+=2) { unsigned slope = pix[i] < 1001? 2 : curve[pix[i]<<1]-curve[(pix[i]<<1)-2]; unsigned step = 1 << sh; RAW(row,col)=curve[pix[i]<<1]>black+imgdata.params.sony_arw2_posterization_thr? LIM(((slope*step*1000)/(curve[pix[i]<<1]-black)),0,10000):0; } } else { for (i=0; i < 16; i++, col+=2) RAW(row,col) = curve[pix[i] << 1]; } #else for (i=0; i < 16; i++, col+=2) RAW(row,col) = curve[pix[i] << 1] >> 2; #endif col -= col & 1 ? 1:31; } } #ifdef LIBRAW_LIBRARY_BUILD } catch(...) { free (data); throw; } if(imgdata.params.raw_processing_options & LIBRAW_PROCESSING_SONYARW2_DELTATOVALUE) maximum=10000; #endif free (data); } void CLASS samsung_load_raw() { int row, col, c, i, dir, op[4], len[4]; order = 0x4949; for (row=0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif fseek (ifp, strip_offset+row*4, SEEK_SET); fseek (ifp, data_offset+get4(), SEEK_SET); ph1_bits(-1); FORC4 len[c] = row < 2 ? 7:4; for (col=0; col < raw_width; col+=16) { dir = ph1_bits(1); FORC4 op[c] = ph1_bits(2); FORC4 switch (op[c]) { case 3: len[c] = ph1_bits(4); break; case 2: len[c]--; break; case 1: len[c]++; } for (c=0; c < 16; c+=2) { i = len[((c & 1) << 1) | (c >> 3)]; RAW(row,col+c) = ((signed) ph1_bits(i) << (32-i) >> (32-i)) + (dir ? RAW(row+(~c | -2),col+c) : col ? RAW(row,col+(c | -2)) : 128); if (c == 14) c = -1; } } } for (row=0; row < raw_height-1; row+=2) for (col=0; col < raw_width-1; col+=2) SWAP (RAW(row,col+1), RAW(row+1,col)); } void CLASS samsung2_load_raw() { static const ushort tab[14] = { 0x304,0x307,0x206,0x205,0x403,0x600,0x709, 0x80a,0x90b,0xa0c,0xa0d,0x501,0x408,0x402 }; ushort huff[1026], vpred[2][2] = {{0,0},{0,0}}, hpred[2]; int i, c, n, row, col, diff; huff[0] = 10; for (n=i=0; i < 14; i++) FORC(1024 >> (tab[i] >> 8)) huff[++n] = tab[i]; getbits(-1); for (row=0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col=0; col < raw_width; col++) { diff = ljpeg_diff (huff); if (col < 2) hpred[col] = vpred[row & 1][col] += diff; else hpred[col & 1] += diff; RAW(row,col) = hpred[col & 1]; if (hpred[col & 1] >> tiff_bps) derror(); } } } void CLASS samsung3_load_raw() { int opt, init, mag, pmode, row, tab, col, pred, diff, i, c; ushort lent[3][2], len[4], *prow[2]; order = 0x4949; fseek (ifp, 9, SEEK_CUR); opt = fgetc(ifp); init = (get2(),get2()); for (row=0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif fseek (ifp, (data_offset-ftell(ifp)) & 15, SEEK_CUR); ph1_bits(-1); mag = 0; pmode = 7; FORC(6) ((ushort *)lent)[c] = row < 2 ? 7:4; prow[ row & 1] = &RAW(row-1,1-((row & 1) << 1)); // green prow[~row & 1] = &RAW(row-2,0); // red and blue for (tab=0; tab+15 < raw_width; tab+=16) { if (~opt & 4 && !(tab & 63)) { i = ph1_bits(2); mag = i < 3 ? mag-'2'+"204"[i] : ph1_bits(12); } if (opt & 2) pmode = 7 - 4*ph1_bits(1); else if (!ph1_bits(1)) pmode = ph1_bits(3); if (opt & 1 || !ph1_bits(1)) { FORC4 len[c] = ph1_bits(2); FORC4 { i = ((row & 1) << 1 | (c & 1)) % 3; len[c] = len[c] < 3 ? lent[i][0]-'1'+"120"[len[c]] : ph1_bits(4); lent[i][0] = lent[i][1]; lent[i][1] = len[c]; } } FORC(16) { col = tab + (((c & 7) << 1)^(c >> 3)^(row & 1)); pred = (pmode == 7 || row < 2) ? (tab ? RAW(row,tab-2+(col & 1)) : init) : (prow[col & 1][col-'4'+"0224468"[pmode]] + prow[col & 1][col-'4'+"0244668"[pmode]] + 1) >> 1; diff = ph1_bits (i = len[c >> 2]); if (diff >> (i-1)) diff -= 1 << i; diff = diff * (mag*2+1) + mag; RAW(row,col) = pred + diff; } } } } #define HOLE(row) ((holes >> (((row) - raw_height) & 7)) & 1) /* Kudos to Rich Taylor for figuring out SMaL's compression algorithm. */ void CLASS smal_decode_segment (unsigned seg[2][2], int holes) { uchar hist[3][13] = { { 7, 7, 0, 0, 63, 55, 47, 39, 31, 23, 15, 7, 0 }, { 7, 7, 0, 0, 63, 55, 47, 39, 31, 23, 15, 7, 0 }, { 3, 3, 0, 0, 63, 47, 31, 15, 0 } }; int low, high=0xff, carry=0, nbits=8; int pix, s, count, bin, next, i, sym[3]; uchar diff, pred[]={0,0}; ushort data=0, range=0; fseek (ifp, seg[0][1]+1, SEEK_SET); getbits(-1); if (seg[1][0] > raw_width*raw_height) seg[1][0] = raw_width*raw_height; for (pix=seg[0][0]; pix < seg[1][0]; pix++) { for (s=0; s < 3; s++) { data = data << nbits | getbits(nbits); if (carry < 0) carry = (nbits += carry+1) < 1 ? nbits-1 : 0; while (--nbits >= 0) if ((data >> nbits & 0xff) == 0xff) break; if (nbits > 0) data = ((data & ((1 << (nbits-1)) - 1)) << 1) | ((data + (((data & (1 << (nbits-1)))) << 1)) & ((~0u) << nbits)); if (nbits >= 0) { data += getbits(1); carry = nbits - 8; } count = ((((data-range+1) & 0xffff) << 2) - 1) / (high >> 4); for (bin=0; hist[s][bin+5] > count; bin++); low = hist[s][bin+5] * (high >> 4) >> 2; if (bin) high = hist[s][bin+4] * (high >> 4) >> 2; high -= low; for (nbits=0; high << nbits < 128; nbits++); range = (range+low) << nbits; high <<= nbits; next = hist[s][1]; if (++hist[s][2] > hist[s][3]) { next = (next+1) & hist[s][0]; hist[s][3] = (hist[s][next+4] - hist[s][next+5]) >> 2; hist[s][2] = 1; } if (hist[s][hist[s][1]+4] - hist[s][hist[s][1]+5] > 1) { if (bin < hist[s][1]) for (i=bin; i < hist[s][1]; i++) hist[s][i+5]--; else if (next <= bin) for (i=hist[s][1]; i < bin; i++) hist[s][i+5]++; } hist[s][1] = next; sym[s] = bin; } diff = sym[2] << 5 | sym[1] << 2 | (sym[0] & 3); if (sym[0] & 4) diff = diff ? -diff : 0x80; if (ftell(ifp) + 12 >= seg[1][1]) diff = 0; #ifdef LIBRAW_LIBRARY_BUILD if(pix>=raw_width*raw_height) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif raw_image[pix] = pred[pix & 1] += diff; if (!(pix & 1) && HOLE(pix / raw_width)) pix += 2; } maximum = 0xff; } void CLASS smal_v6_load_raw() { unsigned seg[2][2]; fseek (ifp, 16, SEEK_SET); seg[0][0] = 0; seg[0][1] = get2(); seg[1][0] = raw_width * raw_height; seg[1][1] = INT_MAX; smal_decode_segment (seg, 0); } int CLASS median4 (int *p) { int min, max, sum, i; min = max = sum = p[0]; for (i=1; i < 4; i++) { sum += p[i]; if (min > p[i]) min = p[i]; if (max < p[i]) max = p[i]; } return (sum - min - max) >> 1; } void CLASS fill_holes (int holes) { int row, col, val[4]; for (row=2; row < height-2; row++) { if (!HOLE(row)) continue; for (col=1; col < width-1; col+=4) { val[0] = RAW(row-1,col-1); val[1] = RAW(row-1,col+1); val[2] = RAW(row+1,col-1); val[3] = RAW(row+1,col+1); RAW(row,col) = median4(val); } for (col=2; col < width-2; col+=4) if (HOLE(row-2) || HOLE(row+2)) RAW(row,col) = (RAW(row,col-2) + RAW(row,col+2)) >> 1; else { val[0] = RAW(row,col-2); val[1] = RAW(row,col+2); val[2] = RAW(row-2,col); val[3] = RAW(row+2,col); RAW(row,col) = median4(val); } } } void CLASS smal_v9_load_raw() { unsigned seg[256][2], offset, nseg, holes, i; fseek (ifp, 67, SEEK_SET); offset = get4(); nseg = (uchar) fgetc(ifp); fseek (ifp, offset, SEEK_SET); for (i=0; i < nseg*2; i++) ((unsigned *)seg)[i] = get4() + data_offset*(i & 1); fseek (ifp, 78, SEEK_SET); holes = fgetc(ifp); fseek (ifp, 88, SEEK_SET); seg[nseg][0] = raw_height * raw_width; seg[nseg][1] = get4() + data_offset; for (i=0; i < nseg; i++) smal_decode_segment (seg+i, holes); if (holes) fill_holes (holes); } void CLASS redcine_load_raw() { #ifndef NO_JASPER int c, row, col; jas_stream_t *in; jas_image_t *jimg; jas_matrix_t *jmat; jas_seqent_t *data; ushort *img, *pix; jas_init(); #ifndef LIBRAW_LIBRARY_BUILD in = jas_stream_fopen (ifname, "rb"); #else in = (jas_stream_t*)ifp->make_jas_stream(); if(!in) throw LIBRAW_EXCEPTION_DECODE_JPEG2000; #endif jas_stream_seek (in, data_offset+20, SEEK_SET); jimg = jas_image_decode (in, -1, 0); #ifndef LIBRAW_LIBRARY_BUILD if (!jimg) longjmp (failure, 3); #else if(!jimg) { jas_stream_close (in); throw LIBRAW_EXCEPTION_DECODE_JPEG2000; } #endif jmat = jas_matrix_create (height/2, width/2); merror (jmat, "redcine_load_raw()"); img = (ushort *) calloc ((height+2), (width+2)*2); merror (img, "redcine_load_raw()"); #ifdef LIBRAW_LIBRARY_BUILD bool fastexitflag = false; try { #endif FORC4 { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif jas_image_readcmpt (jimg, c, 0, 0, width/2, height/2, jmat); data = jas_matrix_getref (jmat, 0, 0); for (row = c >> 1; row < height; row+=2) for (col = c & 1; col < width; col+=2) img[(row+1)*(width+2)+col+1] = data[(row/2)*(width/2)+col/2]; } for (col=1; col <= width; col++) { img[col] = img[2*(width+2)+col]; img[(height+1)*(width+2)+col] = img[(height-1)*(width+2)+col]; } for (row=0; row < height+2; row++) { img[row*(width+2)] = img[row*(width+2)+2]; img[(row+1)*(width+2)-1] = img[(row+1)*(width+2)-3]; } for (row=1; row <= height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif pix = img + row*(width+2) + (col = 1 + (FC(row,1) & 1)); for ( ; col <= width; col+=2, pix+=2) { c = (((pix[0] - 0x800) << 3) + pix[-(width+2)] + pix[width+2] + pix[-1] + pix[1]) >> 2; pix[0] = LIM(c,0,4095); } } for (row=0; row < height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col=0; col < width; col++) RAW(row,col) = curve[img[(row+1)*(width+2)+col+1]]; } #ifdef LIBRAW_LIBRARY_BUILD } catch (...) { fastexitflag=true; } #endif free (img); jas_matrix_destroy (jmat); jas_image_destroy (jimg); jas_stream_close (in); #ifdef LIBRAW_LIBRARY_BUILD if(fastexitflag) throw LIBRAW_EXCEPTION_CANCELLED_BY_CALLBACK; #endif #endif } //@end COMMON /* RESTRICTED code starts here */ void CLASS foveon_decoder (unsigned size, unsigned code) { static unsigned huff[1024]; struct decode *cur; int i, len; if (!code) { for (i=0; i < size; i++) huff[i] = get4(); memset (first_decode, 0, sizeof first_decode); free_decode = first_decode; } cur = free_decode++; if (free_decode > first_decode+2048) { fprintf (stderr,_("%s: decoder table overflow\n"), ifname); longjmp (failure, 2); } if (code) for (i=0; i < size; i++) if (huff[i] == code) { cur->leaf = i; return; } if ((len = code >> 27) > 26) return; code = (len+1) << 27 | (code & 0x3ffffff) << 1; cur->branch[0] = free_decode; foveon_decoder (size, code); cur->branch[1] = free_decode; foveon_decoder (size, code+1); } void CLASS foveon_thumb() { unsigned bwide, row, col, bitbuf=0, bit=1, c, i; char *buf; struct decode *dindex; short pred[3]; bwide = get4(); fprintf (ofp, "P6\n%d %d\n255\n", thumb_width, thumb_height); if (bwide > 0) { if (bwide < thumb_width*3) return; buf = (char *) malloc (bwide); merror (buf, "foveon_thumb()"); for (row=0; row < thumb_height; row++) { fread (buf, 1, bwide, ifp); fwrite (buf, 3, thumb_width, ofp); } free (buf); return; } foveon_decoder (256, 0); for (row=0; row < thumb_height; row++) { memset (pred, 0, sizeof pred); if (!bit) get4(); for (bit=col=0; col < thumb_width; col++) FORC3 { for (dindex=first_decode; dindex->branch[0]; ) { if ((bit = (bit-1) & 31) == 31) for (i=0; i < 4; i++) bitbuf = (bitbuf << 8) + fgetc(ifp); dindex = dindex->branch[bitbuf >> bit & 1]; } pred[c] += dindex->leaf; fputc (pred[c], ofp); } } } void CLASS foveon_sd_load_raw() { #ifdef LIBRAW_LIBRARY_BUILD if(!image) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif struct decode *dindex; short diff[1024]; unsigned bitbuf=0; int pred[3], row, col, bit=-1, c, i; read_shorts ((ushort *) diff, 1024); if (!load_flags) foveon_decoder (1024, 0); for (row=0; row < height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif memset (pred, 0, sizeof pred); if (!bit && !load_flags && atoi(model+2) < 14) get4(); for (col=bit=0; col < width; col++) { if (load_flags) { bitbuf = get4(); FORC3 pred[2-c] += diff[bitbuf >> c*10 & 0x3ff]; } else FORC3 { for (dindex=first_decode; dindex->branch[0]; ) { if ((bit = (bit-1) & 31) == 31) for (i=0; i < 4; i++) bitbuf = (bitbuf << 8) + fgetc(ifp); dindex = dindex->branch[bitbuf >> bit & 1]; } pred[c] += diff[dindex->leaf]; if (pred[c] >> 16 && ~pred[c] >> 16) derror(); } FORC3 image[row*width+col][c] = pred[c]; } } } void CLASS foveon_huff (ushort *huff) { int i, j, clen, code; huff[0] = 8; for (i=0; i < 13; i++) { clen = getc(ifp); code = getc(ifp); for (j=0; j < 256 >> clen; ) huff[code+ ++j] = clen << 8 | i; } get2(); } void CLASS foveon_dp_load_raw() { #ifdef LIBRAW_LIBRARY_BUILD if(!image) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif unsigned c, roff[4], row, col, diff; ushort huff[512], vpred[2][2], hpred[2]; fseek (ifp, 8, SEEK_CUR); foveon_huff (huff); roff[0] = 48; FORC3 roff[c+1] = -(-(roff[c] + get4()) & -16); FORC3 { fseek (ifp, data_offset+roff[c], SEEK_SET); getbits(-1); vpred[0][0] = vpred[0][1] = vpred[1][0] = vpred[1][1] = 512; for (row=0; row < height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col=0; col < width; col++) { diff = ljpeg_diff(huff); if (col < 2) hpred[col] = vpred[row & 1][col] += diff; else hpred[col & 1] += diff; image[row*width+col][c] = hpred[col & 1]; } } } } void CLASS foveon_load_camf() { unsigned type, wide, high, i, j, row, col, diff; ushort huff[258], vpred[2][2] = {{512,512},{512,512}}, hpred[2]; fseek (ifp, meta_offset, SEEK_SET); type = get4(); get4(); get4(); wide = get4(); high = get4(); if (type == 2) { fread (meta_data, 1, meta_length, ifp); for (i=0; i < meta_length; i++) { high = (high * 1597 + 51749) % 244944; wide = high * (INT64) 301593171 >> 24; meta_data[i] ^= ((((high << 8) - wide) >> 1) + wide) >> 17; } } else if (type == 4) { free (meta_data); meta_data = (char *) malloc (meta_length = wide*high*3/2); merror (meta_data, "foveon_load_camf()"); foveon_huff (huff); get4(); getbits(-1); for (j=row=0; row < high; row++) { for (col=0; col < wide; col++) { diff = ljpeg_diff(huff); if (col < 2) hpred[col] = vpred[row & 1][col] += diff; else hpred[col & 1] += diff; if (col & 1) { meta_data[j++] = hpred[0] >> 4; meta_data[j++] = hpred[0] << 4 | hpred[1] >> 8; meta_data[j++] = hpred[1]; } } } } #ifdef DCRAW_VERBOSE else fprintf (stderr,_("%s has unknown CAMF type %d.\n"), ifname, type); #endif } const char * CLASS foveon_camf_param (const char *block, const char *param) { unsigned idx, num; char *pos, *cp, *dp; for (idx=0; idx < meta_length; idx += sget4(pos+8)) { pos = meta_data + idx; if (strncmp (pos, "CMb", 3)) break; if (pos[3] != 'P') continue; if (strcmp (block, pos+sget4(pos+12))) continue; cp = pos + sget4(pos+16); num = sget4(cp); dp = pos + sget4(cp+4); while (num--) { cp += 8; if (!strcmp (param, dp+sget4(cp))) return dp+sget4(cp+4); } } return 0; } void * CLASS foveon_camf_matrix (unsigned dim[3], const char *name) { unsigned i, idx, type, ndim, size, *mat; char *pos, *cp, *dp; double dsize; for (idx=0; idx < meta_length; idx += sget4(pos+8)) { pos = meta_data + idx; if (strncmp (pos, "CMb", 3)) break; if (pos[3] != 'M') continue; if (strcmp (name, pos+sget4(pos+12))) continue; dim[0] = dim[1] = dim[2] = 1; cp = pos + sget4(pos+16); type = sget4(cp); if ((ndim = sget4(cp+4)) > 3) break; dp = pos + sget4(cp+8); for (i=ndim; i--; ) { cp += 12; dim[i] = sget4(cp); } if ((dsize = (double) dim[0]*dim[1]*dim[2]) > meta_length/4) break; mat = (unsigned *) malloc ((size = dsize) * 4); merror (mat, "foveon_camf_matrix()"); for (i=0; i < size; i++) if (type && type != 6) mat[i] = sget4(dp + i*4); else mat[i] = sget4(dp + i*2) & 0xffff; return mat; } #ifdef DCRAW_VERBOSE fprintf (stderr,_("%s: \"%s\" matrix not found!\n"), ifname, name); #endif return 0; } int CLASS foveon_fixed (void *ptr, int size, const char *name) { void *dp; unsigned dim[3]; if (!name) return 0; dp = foveon_camf_matrix (dim, name); if (!dp) return 0; memcpy (ptr, dp, size*4); free (dp); return 1; } float CLASS foveon_avg (short *pix, int range[2], float cfilt) { int i; float val, min=FLT_MAX, max=-FLT_MAX, sum=0; for (i=range[0]; i <= range[1]; i++) { sum += val = pix[i*4] + (pix[i*4]-pix[(i-1)*4]) * cfilt; if (min > val) min = val; if (max < val) max = val; } if (range[1] - range[0] == 1) return sum/2; return (sum - min - max) / (range[1] - range[0] - 1); } short * CLASS foveon_make_curve (double max, double mul, double filt) { short *curve; unsigned i, size; double x; if (!filt) filt = 0.8; size = 4*M_PI*max / filt; if (size == UINT_MAX) size--; curve = (short *) calloc (size+1, sizeof *curve); merror (curve, "foveon_make_curve()"); curve[0] = size; for (i=0; i < size; i++) { x = i*filt/max/4; curve[i+1] = (cos(x)+1)/2 * tanh(i*filt/mul) * mul + 0.5; } return curve; } void CLASS foveon_make_curves (short **curvep, float dq[3], float div[3], float filt) { double mul[3], max=0; int c; FORC3 mul[c] = dq[c]/div[c]; FORC3 if (max < mul[c]) max = mul[c]; FORC3 curvep[c] = foveon_make_curve (max, mul[c], filt); } int CLASS foveon_apply_curve (short *curve, int i) { if (abs(i) >= curve[0]) return 0; return i < 0 ? -curve[1-i] : curve[1+i]; } #define image ((short (*)[4]) image) void CLASS foveon_interpolate() { static const short hood[] = { -1,-1, -1,0, -1,1, 0,-1, 0,1, 1,-1, 1,0, 1,1 }; short *pix, prev[3], *curve[8], (*shrink)[3]; float cfilt=0, ddft[3][3][2], ppm[3][3][3]; float cam_xyz[3][3], correct[3][3], last[3][3], trans[3][3]; float chroma_dq[3], color_dq[3], diag[3][3], div[3]; float (*black)[3], (*sgain)[3], (*sgrow)[3]; float fsum[3], val, frow, num; int row, col, c, i, j, diff, sgx, irow, sum, min, max, limit; int dscr[2][2], dstb[4], (*smrow[7])[3], total[4], ipix[3]; int work[3][3], smlast, smred, smred_p=0, dev[3]; int satlev[3], keep[4], active[4]; unsigned dim[3], *badpix; double dsum=0, trsum[3]; char str[128]; const char* cp; #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("Foveon interpolation...\n")); #endif foveon_load_camf(); foveon_fixed (dscr, 4, "DarkShieldColRange"); foveon_fixed (ppm[0][0], 27, "PostPolyMatrix"); foveon_fixed (satlev, 3, "SaturationLevel"); foveon_fixed (keep, 4, "KeepImageArea"); foveon_fixed (active, 4, "ActiveImageArea"); foveon_fixed (chroma_dq, 3, "ChromaDQ"); foveon_fixed (color_dq, 3, foveon_camf_param ("IncludeBlocks", "ColorDQ") ? "ColorDQ" : "ColorDQCamRGB"); if (foveon_camf_param ("IncludeBlocks", "ColumnFilter")) foveon_fixed (&cfilt, 1, "ColumnFilter"); memset (ddft, 0, sizeof ddft); if (!foveon_camf_param ("IncludeBlocks", "DarkDrift") || !foveon_fixed (ddft[1][0], 12, "DarkDrift")) for (i=0; i < 2; i++) { foveon_fixed (dstb, 4, i ? "DarkShieldBottom":"DarkShieldTop"); for (row = dstb[1]; row <= dstb[3]; row++) for (col = dstb[0]; col <= dstb[2]; col++) FORC3 ddft[i+1][c][1] += (short) image[row*width+col][c]; FORC3 ddft[i+1][c][1] /= (dstb[3]-dstb[1]+1) * (dstb[2]-dstb[0]+1); } if (!(cp = foveon_camf_param ("WhiteBalanceIlluminants", model2))) { #ifdef DCRAW_VERBOSE fprintf (stderr,_("%s: Invalid white balance \"%s\"\n"), ifname, model2); #endif return; } foveon_fixed (cam_xyz, 9, cp); foveon_fixed (correct, 9, foveon_camf_param ("WhiteBalanceCorrections", model2)); memset (last, 0, sizeof last); for (i=0; i < 3; i++) for (j=0; j < 3; j++) FORC3 last[i][j] += correct[i][c] * cam_xyz[c][j]; #define LAST(x,y) last[(i+x)%3][(c+y)%3] for (i=0; i < 3; i++) FORC3 diag[c][i] = LAST(1,1)*LAST(2,2) - LAST(1,2)*LAST(2,1); #undef LAST FORC3 div[c] = diag[c][0]*0.3127 + diag[c][1]*0.329 + diag[c][2]*0.3583; sprintf (str, "%sRGBNeutral", model2); if (foveon_camf_param ("IncludeBlocks", str)) foveon_fixed (div, 3, str); num = 0; FORC3 if (num < div[c]) num = div[c]; FORC3 div[c] /= num; memset (trans, 0, sizeof trans); for (i=0; i < 3; i++) for (j=0; j < 3; j++) FORC3 trans[i][j] += rgb_cam[i][c] * last[c][j] * div[j]; FORC3 trsum[c] = trans[c][0] + trans[c][1] + trans[c][2]; dsum = (6*trsum[0] + 11*trsum[1] + 3*trsum[2]) / 20; for (i=0; i < 3; i++) FORC3 last[i][c] = trans[i][c] * dsum / trsum[i]; memset (trans, 0, sizeof trans); for (i=0; i < 3; i++) for (j=0; j < 3; j++) FORC3 trans[i][j] += (i==c ? 32 : -1) * last[c][j] / 30; foveon_make_curves (curve, color_dq, div, cfilt); FORC3 chroma_dq[c] /= 3; foveon_make_curves (curve+3, chroma_dq, div, cfilt); FORC3 dsum += chroma_dq[c] / div[c]; curve[6] = foveon_make_curve (dsum, dsum, cfilt); curve[7] = foveon_make_curve (dsum*2, dsum*2, cfilt); sgain = (float (*)[3]) foveon_camf_matrix (dim, "SpatialGain"); if (!sgain) return; sgrow = (float (*)[3]) calloc (dim[1], sizeof *sgrow); sgx = (width + dim[1]-2) / (dim[1]-1); black = (float (*)[3]) calloc (height, sizeof *black); for (row=0; row < height; row++) { for (i=0; i < 6; i++) ((float *)ddft[0])[i] = ((float *)ddft[1])[i] + row / (height-1.0) * (((float *)ddft[2])[i] - ((float *)ddft[1])[i]); FORC3 black[row][c] = ( foveon_avg (image[row*width]+c, dscr[0], cfilt) + foveon_avg (image[row*width]+c, dscr[1], cfilt) * 3 - ddft[0][c][0] ) / 4 - ddft[0][c][1]; } memcpy (black, black+8, sizeof *black*8); memcpy (black+height-11, black+height-22, 11*sizeof *black); memcpy (last, black, sizeof last); for (row=1; row < height-1; row++) { FORC3 if (last[1][c] > last[0][c]) { if (last[1][c] > last[2][c]) black[row][c] = (last[0][c] > last[2][c]) ? last[0][c]:last[2][c]; } else if (last[1][c] < last[2][c]) black[row][c] = (last[0][c] < last[2][c]) ? last[0][c]:last[2][c]; memmove (last, last+1, 2*sizeof last[0]); memcpy (last[2], black[row+1], sizeof last[2]); } FORC3 black[row][c] = (last[0][c] + last[1][c])/2; FORC3 black[0][c] = (black[1][c] + black[3][c])/2; val = 1 - exp(-1/24.0); memcpy (fsum, black, sizeof fsum); for (row=1; row < height; row++) FORC3 fsum[c] += black[row][c] = (black[row][c] - black[row-1][c])*val + black[row-1][c]; memcpy (last[0], black[height-1], sizeof last[0]); FORC3 fsum[c] /= height; for (row = height; row--; ) FORC3 last[0][c] = black[row][c] = (black[row][c] - fsum[c] - last[0][c])*val + last[0][c]; memset (total, 0, sizeof total); for (row=2; row < height; row+=4) for (col=2; col < width; col+=4) { FORC3 total[c] += (short) image[row*width+col][c]; total[3]++; } for (row=0; row < height; row++) FORC3 black[row][c] += fsum[c]/2 + total[c]/(total[3]*100.0); for (row=0; row < height; row++) { for (i=0; i < 6; i++) ((float *)ddft[0])[i] = ((float *)ddft[1])[i] + row / (height-1.0) * (((float *)ddft[2])[i] - ((float *)ddft[1])[i]); pix = image[row*width]; memcpy (prev, pix, sizeof prev); frow = row / (height-1.0) * (dim[2]-1); if ((irow = frow) == dim[2]-1) irow--; frow -= irow; for (i=0; i < dim[1]; i++) FORC3 sgrow[i][c] = sgain[ irow *dim[1]+i][c] * (1-frow) + sgain[(irow+1)*dim[1]+i][c] * frow; for (col=0; col < width; col++) { FORC3 { diff = pix[c] - prev[c]; prev[c] = pix[c]; ipix[c] = pix[c] + floor ((diff + (diff*diff >> 14)) * cfilt - ddft[0][c][1] - ddft[0][c][0] * ((float) col/width - 0.5) - black[row][c] ); } FORC3 { work[0][c] = ipix[c] * ipix[c] >> 14; work[2][c] = ipix[c] * work[0][c] >> 14; work[1][2-c] = ipix[(c+1) % 3] * ipix[(c+2) % 3] >> 14; } FORC3 { for (val=i=0; i < 3; i++) for ( j=0; j < 3; j++) val += ppm[c][i][j] * work[i][j]; ipix[c] = floor ((ipix[c] + floor(val)) * ( sgrow[col/sgx ][c] * (sgx - col%sgx) + sgrow[col/sgx+1][c] * (col%sgx) ) / sgx / div[c]); if (ipix[c] > 32000) ipix[c] = 32000; pix[c] = ipix[c]; } pix += 4; } } free (black); free (sgrow); free (sgain); if ((badpix = (unsigned *) foveon_camf_matrix (dim, "BadPixels"))) { for (i=0; i < dim[0]; i++) { col = (badpix[i] >> 8 & 0xfff) - keep[0]; row = (badpix[i] >> 20 ) - keep[1]; if ((unsigned)(row-1) > height-3 || (unsigned)(col-1) > width-3) continue; memset (fsum, 0, sizeof fsum); for (sum=j=0; j < 8; j++) if (badpix[i] & (1 << j)) { FORC3 fsum[c] += (short) image[(row+hood[j*2])*width+col+hood[j*2+1]][c]; sum++; } if (sum) FORC3 image[row*width+col][c] = fsum[c]/sum; } free (badpix); } /* Array for 5x5 Gaussian averaging of red values */ smrow[6] = (int (*)[3]) calloc (width*5, sizeof **smrow); merror (smrow[6], "foveon_interpolate()"); for (i=0; i < 5; i++) smrow[i] = smrow[6] + i*width; /* Sharpen the reds against these Gaussian averages */ for (smlast=-1, row=2; row < height-2; row++) { while (smlast < row+2) { for (i=0; i < 6; i++) smrow[(i+5) % 6] = smrow[i]; pix = image[++smlast*width+2]; for (col=2; col < width-2; col++) { smrow[4][col][0] = (pix[0]*6 + (pix[-4]+pix[4])*4 + pix[-8]+pix[8] + 8) >> 4; pix += 4; } } pix = image[row*width+2]; for (col=2; col < width-2; col++) { smred = ( 6 * smrow[2][col][0] + 4 * (smrow[1][col][0] + smrow[3][col][0]) + smrow[0][col][0] + smrow[4][col][0] + 8 ) >> 4; if (col == 2) smred_p = smred; i = pix[0] + ((pix[0] - ((smred*7 + smred_p) >> 3)) >> 3); if (i > 32000) i = 32000; pix[0] = i; smred_p = smred; pix += 4; } } /* Adjust the brighter pixels for better linearity */ min = 0xffff; FORC3 { i = satlev[c] / div[c]; if (min > i) min = i; } limit = min * 9 >> 4; for (pix=image[0]; pix < image[height*width]; pix+=4) { if (pix[0] <= limit || pix[1] <= limit || pix[2] <= limit) continue; min = max = pix[0]; for (c=1; c < 3; c++) { if (min > pix[c]) min = pix[c]; if (max < pix[c]) max = pix[c]; } if (min >= limit*2) { pix[0] = pix[1] = pix[2] = max; } else { i = 0x4000 - ((min - limit) << 14) / limit; i = 0x4000 - (i*i >> 14); i = i*i >> 14; FORC3 pix[c] += (max - pix[c]) * i >> 14; } } /* Because photons that miss one detector often hit another, the sum R+G+B is much less noisy than the individual colors. So smooth the hues without smoothing the total. */ for (smlast=-1, row=2; row < height-2; row++) { while (smlast < row+2) { for (i=0; i < 6; i++) smrow[(i+5) % 6] = smrow[i]; pix = image[++smlast*width+2]; for (col=2; col < width-2; col++) { FORC3 smrow[4][col][c] = (pix[c-4]+2*pix[c]+pix[c+4]+2) >> 2; pix += 4; } } pix = image[row*width+2]; for (col=2; col < width-2; col++) { FORC3 dev[c] = -foveon_apply_curve (curve[7], pix[c] - ((smrow[1][col][c] + 2*smrow[2][col][c] + smrow[3][col][c]) >> 2)); sum = (dev[0] + dev[1] + dev[2]) >> 3; FORC3 pix[c] += dev[c] - sum; pix += 4; } } for (smlast=-1, row=2; row < height-2; row++) { while (smlast < row+2) { for (i=0; i < 6; i++) smrow[(i+5) % 6] = smrow[i]; pix = image[++smlast*width+2]; for (col=2; col < width-2; col++) { FORC3 smrow[4][col][c] = (pix[c-8]+pix[c-4]+pix[c]+pix[c+4]+pix[c+8]+2) >> 2; pix += 4; } } pix = image[row*width+2]; for (col=2; col < width-2; col++) { for (total[3]=375, sum=60, c=0; c < 3; c++) { for (total[c]=i=0; i < 5; i++) total[c] += smrow[i][col][c]; total[3] += total[c]; sum += pix[c]; } if (sum < 0) sum = 0; j = total[3] > 375 ? (sum << 16) / total[3] : sum * 174; FORC3 pix[c] += foveon_apply_curve (curve[6], ((j*total[c] + 0x8000) >> 16) - pix[c]); pix += 4; } } /* Transform the image to a different colorspace */ for (pix=image[0]; pix < image[height*width]; pix+=4) { FORC3 pix[c] -= foveon_apply_curve (curve[c], pix[c]); sum = (pix[0]+pix[1]+pix[1]+pix[2]) >> 2; FORC3 pix[c] -= foveon_apply_curve (curve[c], pix[c]-sum); FORC3 { for (dsum=i=0; i < 3; i++) dsum += trans[c][i] * pix[i]; if (dsum < 0) dsum = 0; if (dsum > 24000) dsum = 24000; ipix[c] = dsum + 0.5; } FORC3 pix[c] = ipix[c]; } /* Smooth the image bottom-to-top and save at 1/4 scale */ shrink = (short (*)[3]) calloc ((height/4), (width/4)*sizeof *shrink); merror (shrink, "foveon_interpolate()"); for (row = height/4; row--; ) for (col=0; col < width/4; col++) { ipix[0] = ipix[1] = ipix[2] = 0; for (i=0; i < 4; i++) for (j=0; j < 4; j++) FORC3 ipix[c] += image[(row*4+i)*width+col*4+j][c]; FORC3 if (row+2 > height/4) shrink[row*(width/4)+col][c] = ipix[c] >> 4; else shrink[row*(width/4)+col][c] = (shrink[(row+1)*(width/4)+col][c]*1840 + ipix[c]*141 + 2048) >> 12; } /* From the 1/4-scale image, smooth right-to-left */ for (row=0; row < (height & ~3); row++) { ipix[0] = ipix[1] = ipix[2] = 0; if ((row & 3) == 0) for (col = width & ~3 ; col--; ) FORC3 smrow[0][col][c] = ipix[c] = (shrink[(row/4)*(width/4)+col/4][c]*1485 + ipix[c]*6707 + 4096) >> 13; /* Then smooth left-to-right */ ipix[0] = ipix[1] = ipix[2] = 0; for (col=0; col < (width & ~3); col++) FORC3 smrow[1][col][c] = ipix[c] = (smrow[0][col][c]*1485 + ipix[c]*6707 + 4096) >> 13; /* Smooth top-to-bottom */ if (row == 0) memcpy (smrow[2], smrow[1], sizeof **smrow * width); else for (col=0; col < (width & ~3); col++) FORC3 smrow[2][col][c] = (smrow[2][col][c]*6707 + smrow[1][col][c]*1485 + 4096) >> 13; /* Adjust the chroma toward the smooth values */ for (col=0; col < (width & ~3); col++) { for (i=j=30, c=0; c < 3; c++) { i += smrow[2][col][c]; j += image[row*width+col][c]; } j = (j << 16) / i; for (sum=c=0; c < 3; c++) { ipix[c] = foveon_apply_curve (curve[c+3], ((smrow[2][col][c] * j + 0x8000) >> 16) - image[row*width+col][c]); sum += ipix[c]; } sum >>= 3; FORC3 { i = image[row*width+col][c] + ipix[c] - sum; if (i < 0) i = 0; image[row*width+col][c] = i; } } } free (shrink); free (smrow[6]); for (i=0; i < 8; i++) free (curve[i]); /* Trim off the black border */ active[1] -= keep[1]; active[3] -= 2; i = active[2] - active[0]; for (row=0; row < active[3]-active[1]; row++) memcpy (image[row*i], image[(row+active[1])*width+active[0]], i * sizeof *image); width = i; height = row; } #undef image /* RESTRICTED code ends here */ //@out COMMON void CLASS crop_masked_pixels() { int row, col; unsigned #ifndef LIBRAW_LIBRARY_BUILD r, raw_pitch = raw_width*2, c, m, mblack[8], zero, val; #else c, m, zero, val; #define mblack imgdata.color.black_stat #endif #ifndef LIBRAW_LIBRARY_BUILD if (load_raw == &CLASS phase_one_load_raw || load_raw == &CLASS phase_one_load_raw_c) phase_one_correct(); if (fuji_width) { for (row=0; row < raw_height-top_margin*2; row++) { for (col=0; col < fuji_width << !fuji_layout; col++) { if (fuji_layout) { r = fuji_width - 1 - col + (row >> 1); c = col + ((row+1) >> 1); } else { r = fuji_width - 1 + row - (col >> 1); c = row + ((col+1) >> 1); } if (r < height && c < width) BAYER(r,c) = RAW(row+top_margin,col+left_margin); } } } else { for (row=0; row < height; row++) for (col=0; col < width; col++) BAYER2(row,col) = RAW(row+top_margin,col+left_margin); } #endif if (mask[0][3] > 0) goto mask_set; if (load_raw == &CLASS canon_load_raw || load_raw == &CLASS lossless_jpeg_load_raw) { mask[0][1] = mask[1][1] += 2; mask[0][3] -= 2; goto sides; } if (load_raw == &CLASS canon_600_load_raw || load_raw == &CLASS sony_load_raw || (load_raw == &CLASS eight_bit_load_raw && strncmp(model,"DC2",3)) || load_raw == &CLASS kodak_262_load_raw || (load_raw == &CLASS packed_load_raw && (load_flags & 32))) { sides: mask[0][0] = mask[1][0] = top_margin; mask[0][2] = mask[1][2] = top_margin+height; mask[0][3] += left_margin; mask[1][1] += left_margin+width; mask[1][3] += raw_width; } if (load_raw == &CLASS nokia_load_raw) { mask[0][2] = top_margin; mask[0][3] = width; } #ifdef LIBRAW_LIBRARY_BUILD if (load_raw == &CLASS broadcom_load_raw) { mask[0][2] = top_margin; mask[0][3] = width; } #endif mask_set: memset (mblack, 0, sizeof mblack); for (zero=m=0; m < 8; m++) for (row=MAX(mask[m][0],0); row < MIN(mask[m][2],raw_height); row++) for (col=MAX(mask[m][1],0); col < MIN(mask[m][3],raw_width); col++) { c = FC(row-top_margin,col-left_margin); mblack[c] += val = raw_image[(row)*raw_pitch/2+(col)]; mblack[4+c]++; zero += !val; } if (load_raw == &CLASS canon_600_load_raw && width < raw_width) { black = (mblack[0]+mblack[1]+mblack[2]+mblack[3]) / (mblack[4]+mblack[5]+mblack[6]+mblack[7]) - 4; #ifndef LIBRAW_LIBRARY_BUILD canon_600_correct(); #endif } else if (zero < mblack[4] && mblack[5] && mblack[6] && mblack[7]) { FORC4 cblack[c] = mblack[c] / mblack[4+c]; black = cblack[4] = cblack[5] = cblack[6] = 0; } } #ifdef LIBRAW_LIBRARY_BUILD #undef mblack #endif void CLASS remove_zeroes() { unsigned row, col, tot, n, r, c; #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_REMOVE_ZEROES,0,2); #endif for (row=0; row < height; row++) for (col=0; col < width; col++) if (BAYER(row,col) == 0) { tot = n = 0; for (r = row-2; r <= row+2; r++) for (c = col-2; c <= col+2; c++) if (r < height && c < width && FC(r,c) == FC(row,col) && BAYER(r,c)) tot += (n++,BAYER(r,c)); if (n) BAYER(row,col) = tot/n; } #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_REMOVE_ZEROES,1,2); #endif } //@end COMMON /* @out FILEIO #include #define CLASS LibRaw:: #include "libraw/libraw_types.h" #define LIBRAW_LIBRARY_BUILD #include "libraw/libraw.h" #include "internal/defines.h" #include "internal/var_defines.h" @end FILEIO */ // @out FILEIO /* Seach from the current directory up to the root looking for a ".badpixels" file, and fix those pixels now. */ void CLASS bad_pixels (const char *cfname) { FILE *fp=NULL; #ifndef LIBRAW_LIBRARY_BUILD char *fname, *cp, line[128]; int len, time, row, col, r, c, rad, tot, n, fixed=0; #else char *cp, line[128]; int time, row, col, r, c, rad, tot, n; #ifdef DCRAW_VERBOSE int fixed = 0; #endif #endif if (!filters) return; #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_BAD_PIXELS,0,2); #endif if (cfname) fp = fopen (cfname, "r"); // @end FILEIO else { for (len=32 ; ; len *= 2) { fname = (char *) malloc (len); if (!fname) return; if (getcwd (fname, len-16)) break; free (fname); if (errno != ERANGE) return; } #if defined(WIN32) || defined(DJGPP) if (fname[1] == ':') memmove (fname, fname+2, len-2); for (cp=fname; *cp; cp++) if (*cp == '\\') *cp = '/'; #endif cp = fname + strlen(fname); if (cp[-1] == '/') cp--; while (*fname == '/') { strcpy (cp, "/.badpixels"); if ((fp = fopen (fname, "r"))) break; if (cp == fname) break; while (*--cp != '/'); } free (fname); } // @out FILEIO if (!fp) { #ifdef LIBRAW_LIBRARY_BUILD imgdata.process_warnings |= LIBRAW_WARN_NO_BADPIXELMAP; #endif return; } while (fgets (line, 128, fp)) { cp = strchr (line, '#'); if (cp) *cp = 0; if (sscanf (line, "%d %d %d", &col, &row, &time) != 3) continue; if ((unsigned) col >= width || (unsigned) row >= height) continue; if (time > timestamp) continue; for (tot=n=0, rad=1; rad < 3 && n==0; rad++) for (r = row-rad; r <= row+rad; r++) for (c = col-rad; c <= col+rad; c++) if ((unsigned) r < height && (unsigned) c < width && (r != row || c != col) && fcol(r,c) == fcol(row,col)) { tot += BAYER2(r,c); n++; } BAYER2(row,col) = tot/n; #ifdef DCRAW_VERBOSE if (verbose) { if (!fixed++) fprintf (stderr,_("Fixed dead pixels at:")); fprintf (stderr, " %d,%d", col, row); } #endif } #ifdef DCRAW_VERBOSE if (fixed) fputc ('\n', stderr); #endif fclose (fp); #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_BAD_PIXELS,1,2); #endif } void CLASS subtract (const char *fname) { FILE *fp; int dim[3]={0,0,0}, comment=0, number=0, error=0, nd=0, c, row, col; ushort *pixel; #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_DARK_FRAME,0,2); #endif if (!(fp = fopen (fname, "rb"))) { #ifdef DCRAW_VERBOSE perror (fname); #endif #ifdef LIBRAW_LIBRARY_BUILD imgdata.process_warnings |= LIBRAW_WARN_BAD_DARKFRAME_FILE; #endif return; } if (fgetc(fp) != 'P' || fgetc(fp) != '5') error = 1; while (!error && nd < 3 && (c = fgetc(fp)) != EOF) { if (c == '#') comment = 1; if (c == '\n') comment = 0; if (comment) continue; if (isdigit(c)) number = 1; if (number) { if (isdigit(c)) dim[nd] = dim[nd]*10 + c -'0'; else if (isspace(c)) { number = 0; nd++; } else error = 1; } } if (error || nd < 3) { #ifdef DCRAW_VERBOSE fprintf (stderr,_("%s is not a valid PGM file!\n"), fname); #endif fclose (fp); return; } else if (dim[0] != width || dim[1] != height || dim[2] != 65535) { #ifdef DCRAW_VERBOSE fprintf (stderr,_("%s has the wrong dimensions!\n"), fname); #endif #ifdef LIBRAW_LIBRARY_BUILD imgdata.process_warnings |= LIBRAW_WARN_BAD_DARKFRAME_DIM; #endif fclose (fp); return; } pixel = (ushort *) calloc (width, sizeof *pixel); merror (pixel, "subtract()"); for (row=0; row < height; row++) { fread (pixel, 2, width, fp); for (col=0; col < width; col++) BAYER(row,col) = MAX (BAYER(row,col) - ntohs(pixel[col]), 0); } free (pixel); fclose (fp); memset (cblack, 0, sizeof cblack); black = 0; #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_DARK_FRAME,1,2); #endif } //@end FILEIO //@out COMMON static const uchar xlat[2][256] = { { 0xc1,0xbf,0x6d,0x0d,0x59,0xc5,0x13,0x9d,0x83,0x61,0x6b,0x4f,0xc7,0x7f,0x3d,0x3d, 0x53,0x59,0xe3,0xc7,0xe9,0x2f,0x95,0xa7,0x95,0x1f,0xdf,0x7f,0x2b,0x29,0xc7,0x0d, 0xdf,0x07,0xef,0x71,0x89,0x3d,0x13,0x3d,0x3b,0x13,0xfb,0x0d,0x89,0xc1,0x65,0x1f, 0xb3,0x0d,0x6b,0x29,0xe3,0xfb,0xef,0xa3,0x6b,0x47,0x7f,0x95,0x35,0xa7,0x47,0x4f, 0xc7,0xf1,0x59,0x95,0x35,0x11,0x29,0x61,0xf1,0x3d,0xb3,0x2b,0x0d,0x43,0x89,0xc1, 0x9d,0x9d,0x89,0x65,0xf1,0xe9,0xdf,0xbf,0x3d,0x7f,0x53,0x97,0xe5,0xe9,0x95,0x17, 0x1d,0x3d,0x8b,0xfb,0xc7,0xe3,0x67,0xa7,0x07,0xf1,0x71,0xa7,0x53,0xb5,0x29,0x89, 0xe5,0x2b,0xa7,0x17,0x29,0xe9,0x4f,0xc5,0x65,0x6d,0x6b,0xef,0x0d,0x89,0x49,0x2f, 0xb3,0x43,0x53,0x65,0x1d,0x49,0xa3,0x13,0x89,0x59,0xef,0x6b,0xef,0x65,0x1d,0x0b, 0x59,0x13,0xe3,0x4f,0x9d,0xb3,0x29,0x43,0x2b,0x07,0x1d,0x95,0x59,0x59,0x47,0xfb, 0xe5,0xe9,0x61,0x47,0x2f,0x35,0x7f,0x17,0x7f,0xef,0x7f,0x95,0x95,0x71,0xd3,0xa3, 0x0b,0x71,0xa3,0xad,0x0b,0x3b,0xb5,0xfb,0xa3,0xbf,0x4f,0x83,0x1d,0xad,0xe9,0x2f, 0x71,0x65,0xa3,0xe5,0x07,0x35,0x3d,0x0d,0xb5,0xe9,0xe5,0x47,0x3b,0x9d,0xef,0x35, 0xa3,0xbf,0xb3,0xdf,0x53,0xd3,0x97,0x53,0x49,0x71,0x07,0x35,0x61,0x71,0x2f,0x43, 0x2f,0x11,0xdf,0x17,0x97,0xfb,0x95,0x3b,0x7f,0x6b,0xd3,0x25,0xbf,0xad,0xc7,0xc5, 0xc5,0xb5,0x8b,0xef,0x2f,0xd3,0x07,0x6b,0x25,0x49,0x95,0x25,0x49,0x6d,0x71,0xc7 }, { 0xa7,0xbc,0xc9,0xad,0x91,0xdf,0x85,0xe5,0xd4,0x78,0xd5,0x17,0x46,0x7c,0x29,0x4c, 0x4d,0x03,0xe9,0x25,0x68,0x11,0x86,0xb3,0xbd,0xf7,0x6f,0x61,0x22,0xa2,0x26,0x34, 0x2a,0xbe,0x1e,0x46,0x14,0x68,0x9d,0x44,0x18,0xc2,0x40,0xf4,0x7e,0x5f,0x1b,0xad, 0x0b,0x94,0xb6,0x67,0xb4,0x0b,0xe1,0xea,0x95,0x9c,0x66,0xdc,0xe7,0x5d,0x6c,0x05, 0xda,0xd5,0xdf,0x7a,0xef,0xf6,0xdb,0x1f,0x82,0x4c,0xc0,0x68,0x47,0xa1,0xbd,0xee, 0x39,0x50,0x56,0x4a,0xdd,0xdf,0xa5,0xf8,0xc6,0xda,0xca,0x90,0xca,0x01,0x42,0x9d, 0x8b,0x0c,0x73,0x43,0x75,0x05,0x94,0xde,0x24,0xb3,0x80,0x34,0xe5,0x2c,0xdc,0x9b, 0x3f,0xca,0x33,0x45,0xd0,0xdb,0x5f,0xf5,0x52,0xc3,0x21,0xda,0xe2,0x22,0x72,0x6b, 0x3e,0xd0,0x5b,0xa8,0x87,0x8c,0x06,0x5d,0x0f,0xdd,0x09,0x19,0x93,0xd0,0xb9,0xfc, 0x8b,0x0f,0x84,0x60,0x33,0x1c,0x9b,0x45,0xf1,0xf0,0xa3,0x94,0x3a,0x12,0x77,0x33, 0x4d,0x44,0x78,0x28,0x3c,0x9e,0xfd,0x65,0x57,0x16,0x94,0x6b,0xfb,0x59,0xd0,0xc8, 0x22,0x36,0xdb,0xd2,0x63,0x98,0x43,0xa1,0x04,0x87,0x86,0xf7,0xa6,0x26,0xbb,0xd6, 0x59,0x4d,0xbf,0x6a,0x2e,0xaa,0x2b,0xef,0xe6,0x78,0xb6,0x4e,0xe0,0x2f,0xdc,0x7c, 0xbe,0x57,0x19,0x32,0x7e,0x2a,0xd0,0xb8,0xba,0x29,0x00,0x3c,0x52,0x7d,0xa8,0x49, 0x3b,0x2d,0xeb,0x25,0x49,0xfa,0xa3,0xaa,0x39,0xa7,0xc5,0xa7,0x50,0x11,0x36,0xfb, 0xc6,0x67,0x4a,0xf5,0xa5,0x12,0x65,0x7e,0xb0,0xdf,0xaf,0x4e,0xb3,0x61,0x7f,0x2f } }; void CLASS gamma_curve (double pwr, double ts, int mode, int imax) { int i; double g[6], bnd[2]={0,0}, r; g[0] = pwr; g[1] = ts; g[2] = g[3] = g[4] = 0; bnd[g[1] >= 1] = 1; if (g[1] && (g[1]-1)*(g[0]-1) <= 0) { for (i=0; i < 48; i++) { g[2] = (bnd[0] + bnd[1])/2; if (g[0]) bnd[(pow(g[2]/g[1],-g[0]) - 1)/g[0] - 1/g[2] > -1] = g[2]; else bnd[g[2]/exp(1-1/g[2]) < g[1]] = g[2]; } g[3] = g[2] / g[1]; if (g[0]) g[4] = g[2] * (1/g[0] - 1); } if (g[0]) g[5] = 1 / (g[1]*SQR(g[3])/2 - g[4]*(1 - g[3]) + (1 - pow(g[3],1+g[0]))*(1 + g[4])/(1 + g[0])) - 1; else g[5] = 1 / (g[1]*SQR(g[3])/2 + 1 - g[2] - g[3] - g[2]*g[3]*(log(g[3]) - 1)) - 1; if (!mode--) { memcpy (gamm, g, sizeof gamm); return; } for (i=0; i < 0x10000; i++) { curve[i] = 0xffff; if ((r = (double) i / imax) < 1) curve[i] = 0x10000 * ( mode ? (r < g[3] ? r*g[1] : (g[0] ? pow( r,g[0])*(1+g[4])-g[4] : log(r)*g[2]+1)) : (r < g[2] ? r/g[1] : (g[0] ? pow((r+g[4])/(1+g[4]),1/g[0]) : exp((r-1)/g[2])))); } } void CLASS pseudoinverse (double (*in)[3], double (*out)[3], int size) { double work[3][6], num; int i, j, k; for (i=0; i < 3; i++) { for (j=0; j < 6; j++) work[i][j] = j == i+3; for (j=0; j < 3; j++) for (k=0; k < size; k++) work[i][j] += in[k][i] * in[k][j]; } for (i=0; i < 3; i++) { num = work[i][i]; for (j=0; j < 6; j++) work[i][j] /= num; for (k=0; k < 3; k++) { if (k==i) continue; num = work[k][i]; for (j=0; j < 6; j++) work[k][j] -= work[i][j] * num; } } for (i=0; i < size; i++) for (j=0; j < 3; j++) for (out[i][j]=k=0; k < 3; k++) out[i][j] += work[j][k+3] * in[i][k]; } void CLASS cam_xyz_coeff (float _rgb_cam[3][4], double cam_xyz[4][3]) { double cam_rgb[4][3], inverse[4][3], num; int i, j, k; for (i=0; i < colors; i++) /* Multiply out XYZ colorspace */ for (j=0; j < 3; j++) for (cam_rgb[i][j] = k=0; k < 3; k++) cam_rgb[i][j] += cam_xyz[i][k] * xyz_rgb[k][j]; for (i=0; i < colors; i++) { /* Normalize cam_rgb so that */ for (num=j=0; j < 3; j++) /* cam_rgb * (1,1,1) is (1,1,1,1) */ num += cam_rgb[i][j]; if(num > 0.00001) { for (j=0; j < 3; j++) cam_rgb[i][j] /= num; pre_mul[i] = 1 / num; } else { for (j=0; j < 3; j++) cam_rgb[i][j] = 0.0; pre_mul[i] = 1.0; } } pseudoinverse (cam_rgb, inverse, colors); for (i=0; i < 3; i++) for (j=0; j < colors; j++) _rgb_cam[i][j] = inverse[j][i]; } #ifdef COLORCHECK void CLASS colorcheck() { #define NSQ 24 // Coordinates of the GretagMacbeth ColorChecker squares // width, height, 1st_column, 1st_row int cut[NSQ][4]; // you must set these // ColorChecker Chart under 6500-kelvin illumination static const double gmb_xyY[NSQ][3] = { { 0.400, 0.350, 10.1 }, // Dark Skin { 0.377, 0.345, 35.8 }, // Light Skin { 0.247, 0.251, 19.3 }, // Blue Sky { 0.337, 0.422, 13.3 }, // Foliage { 0.265, 0.240, 24.3 }, // Blue Flower { 0.261, 0.343, 43.1 }, // Bluish Green { 0.506, 0.407, 30.1 }, // Orange { 0.211, 0.175, 12.0 }, // Purplish Blue { 0.453, 0.306, 19.8 }, // Moderate Red { 0.285, 0.202, 6.6 }, // Purple { 0.380, 0.489, 44.3 }, // Yellow Green { 0.473, 0.438, 43.1 }, // Orange Yellow { 0.187, 0.129, 6.1 }, // Blue { 0.305, 0.478, 23.4 }, // Green { 0.539, 0.313, 12.0 }, // Red { 0.448, 0.470, 59.1 }, // Yellow { 0.364, 0.233, 19.8 }, // Magenta { 0.196, 0.252, 19.8 }, // Cyan { 0.310, 0.316, 90.0 }, // White { 0.310, 0.316, 59.1 }, // Neutral 8 { 0.310, 0.316, 36.2 }, // Neutral 6.5 { 0.310, 0.316, 19.8 }, // Neutral 5 { 0.310, 0.316, 9.0 }, // Neutral 3.5 { 0.310, 0.316, 3.1 } }; // Black double gmb_cam[NSQ][4], gmb_xyz[NSQ][3]; double inverse[NSQ][3], cam_xyz[4][3], balance[4], num; int c, i, j, k, sq, row, col, pass, count[4]; memset (gmb_cam, 0, sizeof gmb_cam); for (sq=0; sq < NSQ; sq++) { FORCC count[c] = 0; for (row=cut[sq][3]; row < cut[sq][3]+cut[sq][1]; row++) for (col=cut[sq][2]; col < cut[sq][2]+cut[sq][0]; col++) { c = FC(row,col); if (c >= colors) c -= 2; gmb_cam[sq][c] += BAYER2(row,col); BAYER2(row,col) = black + (BAYER2(row,col)-black)/2; count[c]++; } FORCC gmb_cam[sq][c] = gmb_cam[sq][c]/count[c] - black; gmb_xyz[sq][0] = gmb_xyY[sq][2] * gmb_xyY[sq][0] / gmb_xyY[sq][1]; gmb_xyz[sq][1] = gmb_xyY[sq][2]; gmb_xyz[sq][2] = gmb_xyY[sq][2] * (1 - gmb_xyY[sq][0] - gmb_xyY[sq][1]) / gmb_xyY[sq][1]; } pseudoinverse (gmb_xyz, inverse, NSQ); for (pass=0; pass < 2; pass++) { for (raw_color = i=0; i < colors; i++) for (j=0; j < 3; j++) for (cam_xyz[i][j] = k=0; k < NSQ; k++) cam_xyz[i][j] += gmb_cam[k][i] * inverse[k][j]; cam_xyz_coeff (rgb_cam, cam_xyz); FORCC balance[c] = pre_mul[c] * gmb_cam[20][c]; for (sq=0; sq < NSQ; sq++) FORCC gmb_cam[sq][c] *= balance[c]; } if (verbose) { printf (" { \"%s %s\", %d,\n\t{", make, model, black); num = 10000 / (cam_xyz[1][0] + cam_xyz[1][1] + cam_xyz[1][2]); FORCC for (j=0; j < 3; j++) printf ("%c%d", (c | j) ? ',':' ', (int) (cam_xyz[c][j] * num + 0.5)); puts (" } },"); } #undef NSQ } #endif void CLASS hat_transform (float *temp, float *base, int st, int size, int sc) { int i; for (i=0; i < sc; i++) temp[i] = 2*base[st*i] + base[st*(sc-i)] + base[st*(i+sc)]; for (; i+sc < size; i++) temp[i] = 2*base[st*i] + base[st*(i-sc)] + base[st*(i+sc)]; for (; i < size; i++) temp[i] = 2*base[st*i] + base[st*(i-sc)] + base[st*(2*size-2-(i+sc))]; } #if !defined(LIBRAW_USE_OPENMP) void CLASS wavelet_denoise() { float *fimg=0, *temp, thold, mul[2], avg, diff; int scale=1, size, lev, hpass, lpass, row, col, nc, c, i, wlast, blk[2]; ushort *window[4]; static const float noise[] = { 0.8002,0.2735,0.1202,0.0585,0.0291,0.0152,0.0080,0.0044 }; #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("Wavelet denoising...\n")); #endif while (maximum << scale < 0x10000) scale++; maximum <<= --scale; black <<= scale; FORC4 cblack[c] <<= scale; if ((size = iheight*iwidth) < 0x15550000) fimg = (float *) malloc ((size*3 + iheight + iwidth) * sizeof *fimg); merror (fimg, "wavelet_denoise()"); temp = fimg + size*3; if ((nc = colors) == 3 && filters) nc++; FORC(nc) { /* denoise R,G1,B,G3 individually */ for (i=0; i < size; i++) fimg[i] = 256 * sqrt((double)(image[i][c] << scale)); for (hpass=lev=0; lev < 5; lev++) { lpass = size*((lev & 1)+1); for (row=0; row < iheight; row++) { hat_transform (temp, fimg+hpass+row*iwidth, 1, iwidth, 1 << lev); for (col=0; col < iwidth; col++) fimg[lpass + row*iwidth + col] = temp[col] * 0.25; } for (col=0; col < iwidth; col++) { hat_transform (temp, fimg+lpass+col, iwidth, iheight, 1 << lev); for (row=0; row < iheight; row++) fimg[lpass + row*iwidth + col] = temp[row] * 0.25; } thold = threshold * noise[lev]; for (i=0; i < size; i++) { fimg[hpass+i] -= fimg[lpass+i]; if (fimg[hpass+i] < -thold) fimg[hpass+i] += thold; else if (fimg[hpass+i] > thold) fimg[hpass+i] -= thold; else fimg[hpass+i] = 0; if (hpass) fimg[i] += fimg[hpass+i]; } hpass = lpass; } for (i=0; i < size; i++) image[i][c] = CLIP(SQR(fimg[i]+fimg[lpass+i])/0x10000); } if (filters && colors == 3) { /* pull G1 and G3 closer together */ for (row=0; row < 2; row++) { mul[row] = 0.125 * pre_mul[FC(row+1,0) | 1] / pre_mul[FC(row,0) | 1]; blk[row] = cblack[FC(row,0) | 1]; } for (i=0; i < 4; i++) window[i] = (ushort *) fimg + width*i; for (wlast=-1, row=1; row < height-1; row++) { while (wlast < row+1) { for (wlast++, i=0; i < 4; i++) window[(i+3) & 3] = window[i]; for (col = FC(wlast,1) & 1; col < width; col+=2) window[2][col] = BAYER(wlast,col); } thold = threshold/512; for (col = (FC(row,0) & 1)+1; col < width-1; col+=2) { avg = ( window[0][col-1] + window[0][col+1] + window[2][col-1] + window[2][col+1] - blk[~row & 1]*4 ) * mul[row & 1] + (window[1][col] + blk[row & 1]) * 0.5; avg = avg < 0 ? 0 : sqrt(avg); diff = sqrt((double)BAYER(row,col)) - avg; if (diff < -thold) diff += thold; else if (diff > thold) diff -= thold; else diff = 0; BAYER(row,col) = CLIP(SQR(avg+diff) + 0.5); } } } free (fimg); } #else /* LIBRAW_USE_OPENMP */ void CLASS wavelet_denoise() { float *fimg=0, *temp, thold, mul[2], avg, diff; int scale=1, size, lev, hpass, lpass, row, col, nc, c, i, wlast, blk[2]; ushort *window[4]; static const float noise[] = { 0.8002,0.2735,0.1202,0.0585,0.0291,0.0152,0.0080,0.0044 }; #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("Wavelet denoising...\n")); #endif while (maximum << scale < 0x10000) scale++; maximum <<= --scale; black <<= scale; FORC4 cblack[c] <<= scale; if ((size = iheight*iwidth) < 0x15550000) fimg = (float *) malloc ((size*3 + iheight + iwidth) * sizeof *fimg); merror (fimg, "wavelet_denoise()"); temp = fimg + size*3; if ((nc = colors) == 3 && filters) nc++; #ifdef LIBRAW_LIBRARY_BUILD #pragma omp parallel default(shared) private(i,col,row,thold,lev,lpass,hpass,temp,c) firstprivate(scale,size) #endif { temp = (float*)malloc( (iheight + iwidth) * sizeof *fimg); FORC(nc) { /* denoise R,G1,B,G3 individually */ #ifdef LIBRAW_LIBRARY_BUILD #pragma omp for #endif for (i=0; i < size; i++) fimg[i] = 256 * sqrt((double)(image[i][c] << scale)); for (hpass=lev=0; lev < 5; lev++) { lpass = size*((lev & 1)+1); #ifdef LIBRAW_LIBRARY_BUILD #pragma omp for #endif for (row=0; row < iheight; row++) { hat_transform (temp, fimg+hpass+row*iwidth, 1, iwidth, 1 << lev); for (col=0; col < iwidth; col++) fimg[lpass + row*iwidth + col] = temp[col] * 0.25; } #ifdef LIBRAW_LIBRARY_BUILD #pragma omp for #endif for (col=0; col < iwidth; col++) { hat_transform (temp, fimg+lpass+col, iwidth, iheight, 1 << lev); for (row=0; row < iheight; row++) fimg[lpass + row*iwidth + col] = temp[row] * 0.25; } thold = threshold * noise[lev]; #ifdef LIBRAW_LIBRARY_BUILD #pragma omp for #endif for (i=0; i < size; i++) { fimg[hpass+i] -= fimg[lpass+i]; if (fimg[hpass+i] < -thold) fimg[hpass+i] += thold; else if (fimg[hpass+i] > thold) fimg[hpass+i] -= thold; else fimg[hpass+i] = 0; if (hpass) fimg[i] += fimg[hpass+i]; } hpass = lpass; } #ifdef LIBRAW_LIBRARY_BUILD #pragma omp for #endif for (i=0; i < size; i++) image[i][c] = CLIP(SQR(fimg[i]+fimg[lpass+i])/0x10000); } free(temp); } /* end omp parallel */ /* the following loops are hard to parallize, no idea yes, * problem is wlast which is carrying dependency * second part should be easyer, but did not yet get it right. */ if (filters && colors == 3) { /* pull G1 and G3 closer together */ for (row=0; row < 2; row++){ mul[row] = 0.125 * pre_mul[FC(row+1,0) | 1] / pre_mul[FC(row,0) | 1]; blk[row] = cblack[FC(row,0) | 1]; } for (i=0; i < 4; i++) window[i] = (ushort *) fimg + width*i; for (wlast=-1, row=1; row < height-1; row++) { while (wlast < row+1) { for (wlast++, i=0; i < 4; i++) window[(i+3) & 3] = window[i]; for (col = FC(wlast,1) & 1; col < width; col+=2) window[2][col] = BAYER(wlast,col); } thold = threshold/512; for (col = (FC(row,0) & 1)+1; col < width-1; col+=2) { avg = ( window[0][col-1] + window[0][col+1] + window[2][col-1] + window[2][col+1] - blk[~row & 1]*4 ) * mul[row & 1] + (window[1][col] + blk[row & 1]) * 0.5; avg = avg < 0 ? 0 : sqrt(avg); diff = sqrt((double)BAYER(row,col)) - avg; if (diff < -thold) diff += thold; else if (diff > thold) diff -= thold; else diff = 0; BAYER(row,col) = CLIP(SQR(avg+diff) + 0.5); } } } free (fimg); } #endif // green equilibration void CLASS green_matching() { int i,j; double m1,m2,c1,c2; int o1_1,o1_2,o1_3,o1_4; int o2_1,o2_2,o2_3,o2_4; ushort (*img)[4]; const int margin = 3; int oj = 2, oi = 2; float f; const float thr = 0.01f; if(half_size || shrink) return; if(FC(oj, oi) != 3) oj++; if(FC(oj, oi) != 3) oi++; if(FC(oj, oi) != 3) oj--; img = (ushort (*)[4]) calloc (height*width, sizeof *image); merror (img, "green_matching()"); memcpy(img,image,height*width*sizeof *image); for(j=oj;j0xffff?0xffff:f; } } free(img); } void CLASS scale_colors() { unsigned bottom, right, size, row, col, ur, uc, i, x, y, c, sum[8]; int val, dark, sat; double dsum[8], dmin, dmax; float scale_mul[4], fr, fc; ushort *img=0, *pix; #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_SCALE_COLORS,0,2); #endif if (user_mul[0]) memcpy (pre_mul, user_mul, sizeof pre_mul); if (use_auto_wb || (use_camera_wb && cam_mul[0] == -1)) { memset (dsum, 0, sizeof dsum); bottom = MIN (greybox[1]+greybox[3], height); right = MIN (greybox[0]+greybox[2], width); for (row=greybox[1]; row < bottom; row += 8) for (col=greybox[0]; col < right; col += 8) { memset (sum, 0, sizeof sum); for (y=row; y < row+8 && y < bottom; y++) for (x=col; x < col+8 && x < right; x++) FORC4 { if (filters) { c = fcol(y,x); val = BAYER2(y,x); } else val = image[y*width+x][c]; if (val > maximum-25) goto skip_block; if ((val -= cblack[c]) < 0) val = 0; sum[c] += val; sum[c+4]++; if (filters) break; } FORC(8) dsum[c] += sum[c]; skip_block: ; } FORC4 if (dsum[c]) pre_mul[c] = dsum[c+4] / dsum[c]; } if (use_camera_wb && cam_mul[0] != -1) { memset (sum, 0, sizeof sum); for (row=0; row < 8; row++) for (col=0; col < 8; col++) { c = FC(row,col); if ((val = white[row][col] - cblack[c]) > 0) sum[c] += val; sum[c+4]++; } #ifdef LIBRAW_LIBRARY_BUILD if(load_raw == &LibRaw::nikon_load_sraw) { // Nikon sRAW: camera WB already applied: pre_mul[0]=pre_mul[1]=pre_mul[2]=pre_mul[3]=1.0; } else #endif if (sum[0] && sum[1] && sum[2] && sum[3]) FORC4 pre_mul[c] = (float) sum[c+4] / sum[c]; else if (cam_mul[0] && cam_mul[2]) memcpy (pre_mul, cam_mul, sizeof pre_mul); else { #ifdef LIBRAW_LIBRARY_BUILD imgdata.process_warnings |= LIBRAW_WARN_BAD_CAMERA_WB; #endif #ifdef DCRAW_VERBOSE fprintf (stderr,_("%s: Cannot use camera white balance.\n"), ifname); #endif } } #ifdef LIBRAW_LIBRARY_BUILD // Nikon sRAW, daylight if (load_raw == &LibRaw::nikon_load_sraw && !use_camera_wb && !use_auto_wb && cam_mul[0] > 0.001f && cam_mul[1] > 0.001f && cam_mul[2] > 0.001f ) { for(c=0;c<3;c++) pre_mul[c]/=cam_mul[c]; } #endif if (pre_mul[1] == 0) pre_mul[1] = 1; if (pre_mul[3] == 0) pre_mul[3] = colors < 4 ? pre_mul[1] : 1; dark = black; sat = maximum; if (threshold) wavelet_denoise(); maximum -= black; for (dmin=DBL_MAX, dmax=c=0; c < 4; c++) { if (dmin > pre_mul[c]) dmin = pre_mul[c]; if (dmax < pre_mul[c]) dmax = pre_mul[c]; } if (!highlight) dmax = dmin; FORC4 scale_mul[c] = (pre_mul[c] /= dmax) * 65535.0 / maximum; #ifdef DCRAW_VERBOSE if (verbose) { fprintf (stderr, _("Scaling with darkness %d, saturation %d, and\nmultipliers"), dark, sat); FORC4 fprintf (stderr, " %f", pre_mul[c]); fputc ('\n', stderr); } #endif if (filters > 1000 && (cblack[4]+1)/2 == 1 && (cblack[5]+1)/2 == 1) { FORC4 cblack[FC(c/2,c%2)] += cblack[6 + c/2 % cblack[4] * cblack[5] + c%2 % cblack[5]]; cblack[4] = cblack[5] = 0; } size = iheight*iwidth; #ifdef LIBRAW_LIBRARY_BUILD scale_colors_loop(scale_mul); #else for (i=0; i < size*4; i++) { if (!(val = ((ushort *)image)[i])) continue; if (cblack[4] && cblack[5]) val -= cblack[6 + i/4 / iwidth % cblack[4] * cblack[5] + i/4 % iwidth % cblack[5]]; val -= cblack[i & 3]; val *= scale_mul[i & 3]; ((ushort *)image)[i] = CLIP(val); } #endif if ((aber[0] != 1 || aber[2] != 1) && colors == 3) { #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("Correcting chromatic aberration...\n")); #endif for (c=0; c < 4; c+=2) { if (aber[c] == 1) continue; img = (ushort *) malloc (size * sizeof *img); merror (img, "scale_colors()"); for (i=0; i < size; i++) img[i] = image[i][c]; for (row=0; row < iheight; row++) { ur = fr = (row - iheight*0.5) * aber[c] + iheight*0.5; if (ur > iheight-2) continue; fr -= ur; for (col=0; col < iwidth; col++) { uc = fc = (col - iwidth*0.5) * aber[c] + iwidth*0.5; if (uc > iwidth-2) continue; fc -= uc; pix = img + ur*iwidth + uc; image[row*iwidth+col][c] = (pix[ 0]*(1-fc) + pix[ 1]*fc) * (1-fr) + (pix[iwidth]*(1-fc) + pix[iwidth+1]*fc) * fr; } } free(img); } } #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_SCALE_COLORS,1,2); #endif } void CLASS pre_interpolate() { ushort (*img)[4]; int row, col, c; #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_PRE_INTERPOLATE,0,2); #endif if (shrink) { if (half_size) { height = iheight; width = iwidth; if (filters == 9) { for (row=0; row < 3; row++) for (col=1; col < 4; col++) if (!(image[row*width+col][0] | image[row*width+col][2])) goto break2; break2: for ( ; row < height; row+=3) for (col=(col-1)%3+1; col < width-1; col+=3) { img = image + row*width+col; for (c=0; c < 3; c+=2) img[0][c] = (img[-1][c] + img[1][c]) >> 1; } } } else { img = (ushort (*)[4]) calloc (height, width*sizeof *img); merror (img, "pre_interpolate()"); for (row=0; row < height; row++) for (col=0; col < width; col++) { c = fcol(row,col); img[row*width+col][c] = image[(row >> 1)*iwidth+(col >> 1)][c]; } free (image); image = img; shrink = 0; } } if (filters > 1000 && colors == 3) { mix_green = four_color_rgb ^ half_size; if (four_color_rgb | half_size) colors++; else { for (row = FC(1,0) >> 1; row < height; row+=2) for (col = FC(row,1) & 1; col < width; col+=2) image[row*width+col][1] = image[row*width+col][3]; filters &= ~((filters & 0x55555555) << 1); } } if (half_size) filters = 0; #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_PRE_INTERPOLATE,1,2); #endif } void CLASS border_interpolate (int border) { unsigned row, col, y, x, f, c, sum[8]; for (row=0; row < height; row++) for (col=0; col < width; col++) { if (col==border && row >= border && row < height-border) col = width-border; memset (sum, 0, sizeof sum); for (y=row-1; y != row+2; y++) for (x=col-1; x != col+2; x++) if (y < height && x < width) { f = fcol(y,x); sum[f] += image[y*width+x][f]; sum[f+4]++; } f = fcol(row,col); FORCC if (c != f && sum[c+4]) image[row*width+col][c] = sum[c] / sum[c+4]; } } void CLASS lin_interpolate_loop(int code[16][16][32],int size) { int row; for (row=1; row < height-1; row++) { int col,*ip; ushort *pix; for (col=1; col < width-1; col++) { int i; int sum[4]; pix = image[row*width+col]; ip = code[row % size][col % size]; memset (sum, 0, sizeof sum); for (i=*ip++; i--; ip+=3) sum[ip[2]] += pix[ip[0]] << ip[1]; for (i=colors; --i; ip+=2) pix[ip[0]] = sum[ip[0]] * ip[1] >> 8; } } } void CLASS lin_interpolate() { int code[16][16][32], size=16, *ip, sum[4]; int f, c, x, y, row, col, shift, color; #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("Bilinear interpolation...\n")); #endif #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE,0,3); #endif if (filters == 9) size = 6; border_interpolate(1); for (row=0; row < size; row++) for (col=0; col < size; col++) { ip = code[row][col]+1; f = fcol(row,col); memset (sum, 0, sizeof sum); for (y=-1; y <= 1; y++) for (x=-1; x <= 1; x++) { shift = (y==0) + (x==0); color = fcol(row+y,col+x); if (color == f) continue; *ip++ = (width*y + x)*4 + color; *ip++ = shift; *ip++ = color; sum[color] += 1 << shift; } code[row][col][0] = (ip - code[row][col]) / 3; FORCC if (c != f) { *ip++ = c; *ip++ = sum[c]>0?256 / sum[c]:0; } } #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE,1,3); #endif lin_interpolate_loop(code,size); #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE,2,3); #endif } /* This algorithm is officially called: "Interpolation using a Threshold-based variable number of gradients" described in http://scien.stanford.edu/pages/labsite/1999/psych221/projects/99/tingchen/algodep/vargra.html I've extended the basic idea to work with non-Bayer filter arrays. Gradients are numbered clockwise from NW=0 to W=7. */ void CLASS vng_interpolate() { static const signed char *cp, terms[] = { -2,-2,+0,-1,0,0x01, -2,-2,+0,+0,1,0x01, -2,-1,-1,+0,0,0x01, -2,-1,+0,-1,0,0x02, -2,-1,+0,+0,0,0x03, -2,-1,+0,+1,1,0x01, -2,+0,+0,-1,0,0x06, -2,+0,+0,+0,1,0x02, -2,+0,+0,+1,0,0x03, -2,+1,-1,+0,0,0x04, -2,+1,+0,-1,1,0x04, -2,+1,+0,+0,0,0x06, -2,+1,+0,+1,0,0x02, -2,+2,+0,+0,1,0x04, -2,+2,+0,+1,0,0x04, -1,-2,-1,+0,0,-128, -1,-2,+0,-1,0,0x01, -1,-2,+1,-1,0,0x01, -1,-2,+1,+0,1,0x01, -1,-1,-1,+1,0,-120, -1,-1,+1,-2,0,0x40, -1,-1,+1,-1,0,0x22, -1,-1,+1,+0,0,0x33, -1,-1,+1,+1,1,0x11, -1,+0,-1,+2,0,0x08, -1,+0,+0,-1,0,0x44, -1,+0,+0,+1,0,0x11, -1,+0,+1,-2,1,0x40, -1,+0,+1,-1,0,0x66, -1,+0,+1,+0,1,0x22, -1,+0,+1,+1,0,0x33, -1,+0,+1,+2,1,0x10, -1,+1,+1,-1,1,0x44, -1,+1,+1,+0,0,0x66, -1,+1,+1,+1,0,0x22, -1,+1,+1,+2,0,0x10, -1,+2,+0,+1,0,0x04, -1,+2,+1,+0,1,0x04, -1,+2,+1,+1,0,0x04, +0,-2,+0,+0,1,-128, +0,-1,+0,+1,1,-120, +0,-1,+1,-2,0,0x40, +0,-1,+1,+0,0,0x11, +0,-1,+2,-2,0,0x40, +0,-1,+2,-1,0,0x20, +0,-1,+2,+0,0,0x30, +0,-1,+2,+1,1,0x10, +0,+0,+0,+2,1,0x08, +0,+0,+2,-2,1,0x40, +0,+0,+2,-1,0,0x60, +0,+0,+2,+0,1,0x20, +0,+0,+2,+1,0,0x30, +0,+0,+2,+2,1,0x10, +0,+1,+1,+0,0,0x44, +0,+1,+1,+2,0,0x10, +0,+1,+2,-1,1,0x40, +0,+1,+2,+0,0,0x60, +0,+1,+2,+1,0,0x20, +0,+1,+2,+2,0,0x10, +1,-2,+1,+0,0,-128, +1,-1,+1,+1,0,-120, +1,+0,+1,+2,0,0x08, +1,+0,+2,-1,0,0x40, +1,+0,+2,+1,0,0x10 }, chood[] = { -1,-1, -1,0, -1,+1, 0,+1, +1,+1, +1,0, +1,-1, 0,-1 }; ushort (*brow[5])[4], *pix; int prow=8, pcol=2, *ip, *code[16][16], gval[8], gmin, gmax, sum[4]; int row, col, x, y, x1, x2, y1, y2, t, weight, grads, color, diag; int g, diff, thold, num, c; lin_interpolate(); #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("VNG interpolation...\n")); #endif if (filters == 1) prow = pcol = 16; if (filters == 9) prow = pcol = 6; ip = (int *) calloc (prow*pcol, 1280); merror (ip, "vng_interpolate()"); for (row=0; row < prow; row++) /* Precalculate for VNG */ for (col=0; col < pcol; col++) { code[row][col] = ip; for (cp=terms, t=0; t < 64; t++) { y1 = *cp++; x1 = *cp++; y2 = *cp++; x2 = *cp++; weight = *cp++; grads = *cp++; color = fcol(row+y1,col+x1); if (fcol(row+y2,col+x2) != color) continue; diag = (fcol(row,col+1) == color && fcol(row+1,col) == color) ? 2:1; if (abs(y1-y2) == diag && abs(x1-x2) == diag) continue; *ip++ = (y1*width + x1)*4 + color; *ip++ = (y2*width + x2)*4 + color; *ip++ = weight; for (g=0; g < 8; g++) if (grads & 1< gval[g]) gmin = gval[g]; if (gmax < gval[g]) gmax = gval[g]; } if (gmax == 0) { memcpy (brow[2][col], pix, sizeof *image); continue; } thold = gmin + (gmax >> 1); memset (sum, 0, sizeof sum); color = fcol(row,col); for (num=g=0; g < 8; g++,ip+=2) { /* Average the neighbors */ if (gval[g] <= thold) { FORCC if (c == color && ip[1]) sum[c] += (pix[c] + pix[ip[1]]) >> 1; else sum[c] += pix[ip[0] + c]; num++; } } FORCC { /* Save to buffer */ t = pix[color]; if (c != color) t += (sum[c] - sum[color]) / num; brow[2][col][c] = CLIP(t); } } if (row > 3) /* Write buffer to image */ memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image); for (g=0; g < 4; g++) brow[(g-1) & 3] = brow[g]; } memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image); memcpy (image[(row-1)*width+2], brow[1]+2, (width-4)*sizeof *image); free (brow[4]); free (code[0][0]); } /* Patterned Pixel Grouping Interpolation by Alain Desbiolles */ void CLASS ppg_interpolate() { int dir[5] = { 1, width, -1, -width, 1 }; int row, col, diff[2], guess[2], c, d, i; ushort (*pix)[4]; border_interpolate(3); #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("PPG interpolation...\n")); #endif /* Fill in the green layer with gradients and pattern recognition: */ #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE,0,3); #ifdef LIBRAW_USE_OPENMP #pragma omp parallel for default(shared) private(guess, diff, row, col, d, c, i, pix) schedule(static) #endif #endif for (row=3; row < height-3; row++) for (col=3+(FC(row,3) & 1), c=FC(row,col); col < width-3; col+=2) { pix = image + row*width+col; for (i=0; (d=dir[i]) > 0; i++) { guess[i] = (pix[-d][1] + pix[0][c] + pix[d][1]) * 2 - pix[-2*d][c] - pix[2*d][c]; diff[i] = ( ABS(pix[-2*d][c] - pix[ 0][c]) + ABS(pix[ 2*d][c] - pix[ 0][c]) + ABS(pix[ -d][1] - pix[ d][1]) ) * 3 + ( ABS(pix[ 3*d][1] - pix[ d][1]) + ABS(pix[-3*d][1] - pix[-d][1]) ) * 2; } d = dir[i = diff[0] > diff[1]]; pix[0][1] = ULIM(guess[i] >> 2, pix[d][1], pix[-d][1]); } /* Calculate red and blue for each green pixel: */ #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE,1,3); #ifdef LIBRAW_USE_OPENMP #pragma omp parallel for default(shared) private(guess, diff, row, col, d, c, i, pix) schedule(static) #endif #endif for (row=1; row < height-1; row++) for (col=1+(FC(row,2) & 1), c=FC(row,col+1); col < width-1; col+=2) { pix = image + row*width+col; for (i=0; (d=dir[i]) > 0; c=2-c, i++) pix[0][c] = CLIP((pix[-d][c] + pix[d][c] + 2*pix[0][1] - pix[-d][1] - pix[d][1]) >> 1); } /* Calculate blue for red pixels and vice versa: */ #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE,2,3); #ifdef LIBRAW_USE_OPENMP #pragma omp parallel for default(shared) private(guess, diff, row, col, d, c, i, pix) schedule(static) #endif #endif for (row=1; row < height-1; row++) for (col=1+(FC(row,1) & 1), c=2-FC(row,col); col < width-1; col+=2) { pix = image + row*width+col; for (i=0; (d=dir[i]+dir[i+1]) > 0; i++) { diff[i] = ABS(pix[-d][c] - pix[d][c]) + ABS(pix[-d][1] - pix[0][1]) + ABS(pix[ d][1] - pix[0][1]); guess[i] = pix[-d][c] + pix[d][c] + 2*pix[0][1] - pix[-d][1] - pix[d][1]; } if (diff[0] != diff[1]) pix[0][c] = CLIP(guess[diff[0] > diff[1]] >> 1); else pix[0][c] = CLIP((guess[0]+guess[1]) >> 2); } } void CLASS cielab (ushort rgb[3], short lab[3]) { int c, i, j, k; float r, xyz[3]; #ifdef LIBRAW_NOTHREADS static float cbrt[0x10000], xyz_cam[3][4]; #else #define cbrt tls->ahd_data.cbrt #define xyz_cam tls->ahd_data.xyz_cam #endif if (!rgb) { #ifndef LIBRAW_NOTHREADS if(cbrt[0] < -1.0f) #endif for (i=0; i < 0x10000; i++) { r = i / 65535.0; cbrt[i] = r > 0.008856 ? pow(r,1.f/3.0f) : 7.787f*r + 16.f/116.0f; } for (i=0; i < 3; i++) for (j=0; j < colors; j++) for (xyz_cam[i][j] = k=0; k < 3; k++) xyz_cam[i][j] += xyz_rgb[i][k] * rgb_cam[k][j] / d65_white[i]; return; } xyz[0] = xyz[1] = xyz[2] = 0.5; FORCC { xyz[0] += xyz_cam[0][c] * rgb[c]; xyz[1] += xyz_cam[1][c] * rgb[c]; xyz[2] += xyz_cam[2][c] * rgb[c]; } xyz[0] = cbrt[CLIP((int) xyz[0])]; xyz[1] = cbrt[CLIP((int) xyz[1])]; xyz[2] = cbrt[CLIP((int) xyz[2])]; lab[0] = 64 * (116 * xyz[1] - 16); lab[1] = 64 * 500 * (xyz[0] - xyz[1]); lab[2] = 64 * 200 * (xyz[1] - xyz[2]); #ifndef LIBRAW_NOTHREADS #undef cbrt #undef xyz_cam #endif } #define TS 512 /* Tile Size */ #define fcol(row,col) xtrans[(row+6) % 6][(col+6) % 6] /* Frank Markesteijn's algorithm for Fuji X-Trans sensors */ void CLASS xtrans_interpolate (int passes) { int c, d, f, g, h, i, v, ng, row, col, top, left, mrow, mcol; #ifdef LIBRAW_LIBRARY_BUILD int cstat[4]={0,0,0,0}; #endif int val, ndir, pass, hm[8], avg[4], color[3][8]; static const short orth[12] = { 1,0,0,1,-1,0,0,-1,1,0,0,1 }, patt[2][16] = { { 0,1,0,-1,2,0,-1,0,1,1,1,-1,0,0,0,0 }, { 0,1,0,-2,1,0,-2,0,1,1,-2,-2,1,-1,-1,1 } }, dir[4] = { 1,TS,TS+1,TS-1 }; short allhex[3][3][2][8], *hex; ushort min, max, sgrow, sgcol; ushort (*rgb)[TS][TS][3], (*rix)[3], (*pix)[4]; short (*lab) [TS][3], (*lix)[3]; float (*drv)[TS][TS], diff[6], tr; char (*homo)[TS][TS], *buffer; #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("%d-pass X-Trans interpolation...\n"), passes); #endif #ifdef LIBRAW_LIBRARY_BUILD if(width < TS || height < TS) throw LIBRAW_EXCEPTION_IO_CORRUPT; // too small image /* Check against right pattern */ for (row = 0; row < 6; row++) for (col = 0; col < 6; col++) cstat[fcol(row,col)]++; if(cstat[0] < 6 || cstat[0]>10 || cstat[1]< 16 || cstat[1]>24 || cstat[2]< 6 || cstat[2]>10 || cstat[3]) throw LIBRAW_EXCEPTION_IO_CORRUPT; // Init allhex table to unreasonable values for(int i = 0; i < 3; i++) for(int j = 0; j < 3; j++) for(int k = 0; k < 2; k++) for(int l = 0; l < 8; l++) allhex[i][j][k][l]=32700; #endif cielab (0,0); ndir = 4 << (passes > 1); buffer = (char *) malloc (TS*TS*(ndir*11+6)); merror (buffer, "xtrans_interpolate()"); rgb = (ushort(*)[TS][TS][3]) buffer; lab = (short (*) [TS][3])(buffer + TS*TS*(ndir*6)); drv = (float (*)[TS][TS]) (buffer + TS*TS*(ndir*6+6)); homo = (char (*)[TS][TS]) (buffer + TS*TS*(ndir*10+6)); int minv=0,maxv=0,minh=0,maxh=0; /* Map a green hexagon around each non-green pixel and vice versa: */ for (row=0; row < 3; row++) for (col=0; col < 3; col++) for (ng=d=0; d < 10; d+=2) { g = fcol(row,col) == 1; if (fcol(row+orth[d],col+orth[d+2]) == 1) ng=0; else ng++; if (ng == 4) { sgrow = row; sgcol = col; } if (ng == g+1) FORC(8) { v = orth[d ]*patt[g][c*2] + orth[d+1]*patt[g][c*2+1]; h = orth[d+2]*patt[g][c*2] + orth[d+3]*patt[g][c*2+1]; minv=MIN(v,minv); maxv=MAX(v,maxv); minh=MIN(v,minh); maxh=MAX(v,maxh); allhex[row][col][0][c^(g*2 & d)] = h + v*width; allhex[row][col][1][c^(g*2 & d)] = h + v*TS; } } #ifdef LIBRAW_LIBRARY_BUILD // Check allhex table initialization for(int i = 0; i < 3; i++) for(int j = 0; j < 3; j++) for(int k = 0; k < 2; k++) for(int l = 0; l < 8; l++) if(allhex[i][j][k][l]>maxh+maxv*width+1 || allhex[i][j][k][l] val) min = val; if (max < val) max = val; } pix[0][1] = min; pix[0][3] = max; switch ((row-sgrow) % 3) { case 1: if (row < height-3) { row++; col--; } break; case 2: if ((min = ~(max = 0)) && (col += 2) < width - 3 && row > 2) { row--; #ifdef LIBRAW_LIBRARY_BUILD if(retrycount++ > width*height) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif } } } for (top=3; top < height-19; top += TS-16) for (left=3; left < width-19; left += TS-16) { mrow = MIN (top+TS, height-3); mcol = MIN (left+TS, width-3); for (row=top; row < mrow; row++) for (col=left; col < mcol; col++) memcpy (rgb[0][row-top][col-left], image[row*width+col], 6); FORC3 memcpy (rgb[c+1], rgb[0], sizeof *rgb); /* Interpolate green horizontally, vertically, and along both diagonals: */ for (row=top; row < mrow; row++) for (col=left; col < mcol; col++) { if ((f = fcol(row,col)) == 1) continue; pix = image + row*width + col; hex = allhex[row % 3][col % 3][0]; color[1][0] = 174 * (pix[ hex[1]][1] + pix[ hex[0]][1]) - 46 * (pix[2*hex[1]][1] + pix[2*hex[0]][1]); color[1][1] = 223 * pix[ hex[3]][1] + pix[ hex[2]][1] * 33 + 92 * (pix[ 0 ][f] - pix[ -hex[2]][f]); FORC(2) color[1][2+c] = 164 * pix[hex[4+c]][1] + 92 * pix[-2*hex[4+c]][1] + 33 * (2*pix[0][f] - pix[3*hex[4+c]][f] - pix[-3*hex[4+c]][f]); FORC4 rgb[c^!((row-sgrow) % 3)][row-top][col-left][1] = LIM(color[1][c] >> 8,pix[0][1],pix[0][3]); } for (pass=0; pass < passes; pass++) { if (pass == 1) memcpy (rgb+=4, buffer, 4*sizeof *rgb); /* Recalculate green from interpolated values of closer pixels: */ if (pass) { for (row=top+2; row < mrow-2; row++) for (col=left+2; col < mcol-2; col++) { if ((f = fcol(row,col)) == 1) continue; pix = image + row*width + col; hex = allhex[row % 3][col % 3][1]; for (d=3; d < 6; d++) { rix = &rgb[(d-2)^!((row-sgrow) % 3)][row-top][col-left]; val = rix[-2*hex[d]][1] + 2*rix[hex[d]][1] - rix[-2*hex[d]][f] - 2*rix[hex[d]][f] + 3*rix[0][f]; rix[0][1] = LIM(val/3,pix[0][1],pix[0][3]); } } } /* Interpolate red and blue values for solitary green pixels: */ for (row=(top-sgrow+4)/3*3+sgrow; row < mrow-2; row+=3) for (col=(left-sgcol+4)/3*3+sgcol; col < mcol-2; col+=3) { rix = &rgb[0][row-top][col-left]; h = fcol(row,col+1); memset (diff, 0, sizeof diff); for (i=1, d=0; d < 6; d++, i^=TS^1, h^=2) { for (c=0; c < 2; c++, h^=2) { g = 2*rix[0][1] - rix[i< 1) diff[d] += SQR (rix[i< 1 && (d & 1)) if (diff[d-1] < diff[d]) FORC(2) color[c*2][d] = color[c*2][d-1]; if (d < 2 || (d & 1)) { FORC(2) rix[0][c*2] = CLIP(color[c*2][d]/2); rix += TS*TS; } } } /* Interpolate red for blue pixels and vice versa: */ for (row=top+3; row < mrow-3; row++) for (col=left+3; col < mcol-3; col++) { if ((f = 2-fcol(row,col)) == 1) continue; rix = &rgb[0][row-top][col-left]; c = (row-sgrow) % 3 ? TS:1; h = 3 * (c ^ TS ^ 1); for (d=0; d < 4; d++, rix += TS*TS) { i = d > 1 || ((d ^ c) & 1) || ((ABS(rix[0][1]-rix[c][1])+ABS(rix[0][1]-rix[-c][1])) < 2*(ABS(rix[0][1]-rix[h][1])+ABS(rix[0][1]-rix[-h][1]))) ? c:h; rix[0][f] = CLIP((rix[i][f] + rix[-i][f] + 2*rix[0][1] - rix[i][1] - rix[-i][1])/2); } } /* Fill in red and blue for 2x2 blocks of green: */ for (row=top+2; row < mrow-2; row++) if ((row-sgrow) % 3) for (col=left+2; col < mcol-2; col++) if ((col-sgcol) % 3) { rix = &rgb[0][row-top][col-left]; hex = allhex[row % 3][col % 3][1]; for (d=0; d < ndir; d+=2, rix += TS*TS) if (hex[d] + hex[d+1]) { g = 3*rix[0][1] - 2*rix[hex[d]][1] - rix[hex[d+1]][1]; for (c=0; c < 4; c+=2) rix[0][c] = CLIP((g + 2*rix[hex[d]][c] + rix[hex[d+1]][c])/3); } else { g = 2*rix[0][1] - rix[hex[d]][1] - rix[hex[d+1]][1]; for (c=0; c < 4; c+=2) rix[0][c] = CLIP((g + rix[hex[d]][c] + rix[hex[d+1]][c])/2); } } } rgb = (ushort(*)[TS][TS][3]) buffer; mrow -= top; mcol -= left; /* Convert to CIELab and differentiate in all directions: */ for (d=0; d < ndir; d++) { for (row=2; row < mrow-2; row++) for (col=2; col < mcol-2; col++) cielab (rgb[d][row][col], lab[row][col]); for (f=dir[d & 3],row=3; row < mrow-3; row++) for (col=3; col < mcol-3; col++) { lix = &lab[row][col]; g = 2*lix[0][0] - lix[f][0] - lix[-f][0]; drv[d][row][col] = SQR(g) + SQR((2*lix[0][1] - lix[f][1] - lix[-f][1] + g*500/232)) + SQR((2*lix[0][2] - lix[f][2] - lix[-f][2] - g*500/580)); } } /* Build homogeneity maps from the derivatives: */ memset(homo, 0, ndir*TS*TS); for (row=4; row < mrow-4; row++) for (col=4; col < mcol-4; col++) { for (tr=FLT_MAX, d=0; d < ndir; d++) if (tr > drv[d][row][col]) tr = drv[d][row][col]; tr *= 8; for (d=0; d < ndir; d++) for (v=-1; v <= 1; v++) for (h=-1; h <= 1; h++) if (drv[d][row+v][col+h] <= tr) homo[d][row][col]++; } /* Average the most homogenous pixels for the final result: */ if (height-top < TS+4) mrow = height-top+2; if (width-left < TS+4) mcol = width-left+2; for (row = MIN(top,8); row < mrow-8; row++) for (col = MIN(left,8); col < mcol-8; col++) { for (d=0; d < ndir; d++) for (hm[d]=0, v=-2; v <= 2; v++) for (h=-2; h <= 2; h++) hm[d] += homo[d][row+v][col+h]; for (d=0; d < ndir-4; d++) if (hm[d] < hm[d+4]) hm[d ] = 0; else if (hm[d] > hm[d+4]) hm[d+4] = 0; for (max=hm[0],d=1; d < ndir; d++) if (max < hm[d]) max = hm[d]; max -= max >> 3; memset (avg, 0, sizeof avg); for (d=0; d < ndir; d++) if (hm[d] >= max) { FORC3 avg[c] += rgb[d][row][col][c]; avg[3]++; } FORC3 image[(row+top)*width+col+left][c] = avg[c]/avg[3]; } } free(buffer); border_interpolate(8); } #undef fcol /* Adaptive Homogeneity-Directed interpolation is based on the work of Keigo Hirakawa, Thomas Parks, and Paul Lee. */ #ifdef LIBRAW_LIBRARY_BUILD void CLASS ahd_interpolate_green_h_and_v(int top, int left, ushort (*out_rgb)[TS][TS][3]) { int row, col; int c, val; ushort (*pix)[4]; const int rowlimit = MIN(top+TS, height-2); const int collimit = MIN(left+TS, width-2); for (row = top; row < rowlimit; row++) { col = left + (FC(row,left) & 1); for (c = FC(row,col); col < collimit; col+=2) { pix = image + row*width+col; val = ((pix[-1][1] + pix[0][c] + pix[1][1]) * 2 - pix[-2][c] - pix[2][c]) >> 2; out_rgb[0][row-top][col-left][1] = ULIM(val,pix[-1][1],pix[1][1]); val = ((pix[-width][1] + pix[0][c] + pix[width][1]) * 2 - pix[-2*width][c] - pix[2*width][c]) >> 2; out_rgb[1][row-top][col-left][1] = ULIM(val,pix[-width][1],pix[width][1]); } } } void CLASS ahd_interpolate_r_and_b_in_rgb_and_convert_to_cielab(int top, int left, ushort (*inout_rgb)[TS][3], short (*out_lab)[TS][3]) { unsigned row, col; int c, val; ushort (*pix)[4]; ushort (*rix)[3]; short (*lix)[3]; float xyz[3]; const unsigned num_pix_per_row = 4*width; const unsigned rowlimit = MIN(top+TS-1, height-3); const unsigned collimit = MIN(left+TS-1, width-3); ushort *pix_above; ushort *pix_below; int t1, t2; for (row = top+1; row < rowlimit; row++) { pix = image + row*width + left; rix = &inout_rgb[row-top][0]; lix = &out_lab[row-top][0]; for (col = left+1; col < collimit; col++) { pix++; pix_above = &pix[0][0] - num_pix_per_row; pix_below = &pix[0][0] + num_pix_per_row; rix++; lix++; c = 2 - FC(row, col); if (c == 1) { c = FC(row+1,col); t1 = 2-c; val = pix[0][1] + (( pix[-1][t1] + pix[1][t1] - rix[-1][1] - rix[1][1] ) >> 1); rix[0][t1] = CLIP(val); val = pix[0][1] + (( pix_above[c] + pix_below[c] - rix[-TS][1] - rix[TS][1] ) >> 1); } else { t1 = -4+c; /* -4+c: pixel of color c to the left */ t2 = 4+c; /* 4+c: pixel of color c to the right */ val = rix[0][1] + (( pix_above[t1] + pix_above[t2] + pix_below[t1] + pix_below[t2] - rix[-TS-1][1] - rix[-TS+1][1] - rix[+TS-1][1] - rix[+TS+1][1] + 1) >> 2); } rix[0][c] = CLIP(val); c = FC(row,col); rix[0][c] = pix[0][c]; cielab(rix[0],lix[0]); } } } void CLASS ahd_interpolate_r_and_b_and_convert_to_cielab(int top, int left, ushort (*inout_rgb)[TS][TS][3], short (*out_lab)[TS][TS][3]) { int direction; for (direction = 0; direction < 2; direction++) { ahd_interpolate_r_and_b_in_rgb_and_convert_to_cielab(top, left, inout_rgb[direction], out_lab[direction]); } } void CLASS ahd_interpolate_build_homogeneity_map(int top, int left, short (*lab)[TS][TS][3], char (*out_homogeneity_map)[TS][2]) { int row, col; int tr, tc; int direction; int i; short (*lix)[3]; short (*lixs[2])[3]; short *adjacent_lix; unsigned ldiff[2][4], abdiff[2][4], leps, abeps; static const int dir[4] = { -1, 1, -TS, TS }; const int rowlimit = MIN(top+TS-2, height-4); const int collimit = MIN(left+TS-2, width-4); int homogeneity; char (*homogeneity_map_p)[2]; memset (out_homogeneity_map, 0, 2*TS*TS); for (row=top+2; row < rowlimit; row++) { tr = row-top; homogeneity_map_p = &out_homogeneity_map[tr][1]; for (direction=0; direction < 2; direction++) { lixs[direction] = &lab[direction][tr][1]; } for (col=left+2; col < collimit; col++) { tc = col-left; homogeneity_map_p++; for (direction=0; direction < 2; direction++) { lix = ++lixs[direction]; for (i=0; i < 4; i++) { adjacent_lix = lix[dir[i]]; ldiff[direction][i] = ABS(lix[0][0]-adjacent_lix[0]); abdiff[direction][i] = SQR(lix[0][1]-adjacent_lix[1]) + SQR(lix[0][2]-adjacent_lix[2]); } } leps = MIN(MAX(ldiff[0][0],ldiff[0][1]), MAX(ldiff[1][2],ldiff[1][3])); abeps = MIN(MAX(abdiff[0][0],abdiff[0][1]), MAX(abdiff[1][2],abdiff[1][3])); for (direction=0; direction < 2; direction++) { homogeneity = 0; for (i=0; i < 4; i++) { if (ldiff[direction][i] <= leps && abdiff[direction][i] <= abeps) { homogeneity++; } } homogeneity_map_p[0][direction] = homogeneity; } } } } void CLASS ahd_interpolate_combine_homogeneous_pixels(int top, int left, ushort (*rgb)[TS][TS][3], char (*homogeneity_map)[TS][2]) { int row, col; int tr, tc; int i, j; int direction; int hm[2]; int c; const int rowlimit = MIN(top+TS-3, height-5); const int collimit = MIN(left+TS-3, width-5); ushort (*pix)[4]; ushort (*rix[2])[3]; for (row=top+3; row < rowlimit; row++) { tr = row-top; pix = &image[row*width+left+2]; for (direction = 0; direction < 2; direction++) { rix[direction] = &rgb[direction][tr][2]; } for (col=left+3; col < collimit; col++) { tc = col-left; pix++; for (direction = 0; direction < 2; direction++) { rix[direction]++; } for (direction=0; direction < 2; direction++) { hm[direction] = 0; for (i=tr-1; i <= tr+1; i++) { for (j=tc-1; j <= tc+1; j++) { hm[direction] += homogeneity_map[i][j][direction]; } } } if (hm[0] != hm[1]) { memcpy(pix[0], rix[hm[1] > hm[0]][0], 3 * sizeof(ushort)); } else { FORC3 { pix[0][c] = (rix[0][0][c] + rix[1][0][c]) >> 1; } } } } } void CLASS ahd_interpolate() { int i, j, k, top, left; float xyz_cam[3][4],r; char *buffer; ushort (*rgb)[TS][TS][3]; short (*lab)[TS][TS][3]; char (*homo)[TS][2]; int terminate_flag = 0; cielab(0,0); border_interpolate(5); #ifdef LIBRAW_LIBRARY_BUILD #ifdef LIBRAW_USE_OPENMP #pragma omp parallel private(buffer,rgb,lab,homo,top,left,i,j,k) shared(xyz_cam,terminate_flag) #endif #endif { buffer = (char *) malloc (26*TS*TS); /* 1664 kB */ merror (buffer, "ahd_interpolate()"); rgb = (ushort(*)[TS][TS][3]) buffer; lab = (short (*)[TS][TS][3])(buffer + 12*TS*TS); homo = (char (*)[TS][2]) (buffer + 24*TS*TS); #ifdef LIBRAW_LIBRARY_BUILD #ifdef LIBRAW_USE_OPENMP #pragma omp for schedule(dynamic) #endif #endif for (top=2; top < height-5; top += TS-6){ #ifdef LIBRAW_LIBRARY_BUILD #ifdef LIBRAW_USE_OPENMP if(0== omp_get_thread_num()) #endif if(callbacks.progress_cb) { int rr = (*callbacks.progress_cb)(callbacks.progresscb_data,LIBRAW_PROGRESS_INTERPOLATE,top-2,height-7); if(rr) terminate_flag = 1; } #endif for (left=2; !terminate_flag && (left < width-5); left += TS-6) { ahd_interpolate_green_h_and_v(top, left, rgb); ahd_interpolate_r_and_b_and_convert_to_cielab(top, left, rgb, lab); ahd_interpolate_build_homogeneity_map(top, left, lab, homo); ahd_interpolate_combine_homogeneous_pixels(top, left, rgb, homo); } } free (buffer); } #ifdef LIBRAW_LIBRARY_BUILD if(terminate_flag) throw LIBRAW_EXCEPTION_CANCELLED_BY_CALLBACK; #endif } #else void CLASS ahd_interpolate() { int i, j, top, left, row, col, tr, tc, c, d, val, hm[2]; static const int dir[4] = { -1, 1, -TS, TS }; unsigned ldiff[2][4], abdiff[2][4], leps, abeps; ushort (*rgb)[TS][TS][3], (*rix)[3], (*pix)[4]; short (*lab)[TS][TS][3], (*lix)[3]; char (*homo)[TS][TS], *buffer; #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("AHD interpolation...\n")); #endif cielab (0,0); border_interpolate(5); buffer = (char *) malloc (26*TS*TS); merror (buffer, "ahd_interpolate()"); rgb = (ushort(*)[TS][TS][3]) buffer; lab = (short (*)[TS][TS][3])(buffer + 12*TS*TS); homo = (char (*)[TS][TS]) (buffer + 24*TS*TS); for (top=2; top < height-5; top += TS-6) for (left=2; left < width-5; left += TS-6) { /* Interpolate green horizontally and vertically: */ for (row=top; row < top+TS && row < height-2; row++) { col = left + (FC(row,left) & 1); for (c = FC(row,col); col < left+TS && col < width-2; col+=2) { pix = image + row*width+col; val = ((pix[-1][1] + pix[0][c] + pix[1][1]) * 2 - pix[-2][c] - pix[2][c]) >> 2; rgb[0][row-top][col-left][1] = ULIM(val,pix[-1][1],pix[1][1]); val = ((pix[-width][1] + pix[0][c] + pix[width][1]) * 2 - pix[-2*width][c] - pix[2*width][c]) >> 2; rgb[1][row-top][col-left][1] = ULIM(val,pix[-width][1],pix[width][1]); } } /* Interpolate red and blue, and convert to CIELab: */ for (d=0; d < 2; d++) for (row=top+1; row < top+TS-1 && row < height-3; row++) for (col=left+1; col < left+TS-1 && col < width-3; col++) { pix = image + row*width+col; rix = &rgb[d][row-top][col-left]; lix = &lab[d][row-top][col-left]; if ((c = 2 - FC(row,col)) == 1) { c = FC(row+1,col); val = pix[0][1] + (( pix[-1][2-c] + pix[1][2-c] - rix[-1][1] - rix[1][1] ) >> 1); rix[0][2-c] = CLIP(val); val = pix[0][1] + (( pix[-width][c] + pix[width][c] - rix[-TS][1] - rix[TS][1] ) >> 1); } else val = rix[0][1] + (( pix[-width-1][c] + pix[-width+1][c] + pix[+width-1][c] + pix[+width+1][c] - rix[-TS-1][1] - rix[-TS+1][1] - rix[+TS-1][1] - rix[+TS+1][1] + 1) >> 2); rix[0][c] = CLIP(val); c = FC(row,col); rix[0][c] = pix[0][c]; cielab (rix[0],lix[0]); } /* Build homogeneity maps from the CIELab images: */ memset (homo, 0, 2*TS*TS); for (row=top+2; row < top+TS-2 && row < height-4; row++) { tr = row-top; for (col=left+2; col < left+TS-2 && col < width-4; col++) { tc = col-left; for (d=0; d < 2; d++) { lix = &lab[d][tr][tc]; for (i=0; i < 4; i++) { ldiff[d][i] = ABS(lix[0][0]-lix[dir[i]][0]); abdiff[d][i] = SQR(lix[0][1]-lix[dir[i]][1]) + SQR(lix[0][2]-lix[dir[i]][2]); } } leps = MIN(MAX(ldiff[0][0],ldiff[0][1]), MAX(ldiff[1][2],ldiff[1][3])); abeps = MIN(MAX(abdiff[0][0],abdiff[0][1]), MAX(abdiff[1][2],abdiff[1][3])); for (d=0; d < 2; d++) for (i=0; i < 4; i++) if (ldiff[d][i] <= leps && abdiff[d][i] <= abeps) homo[d][tr][tc]++; } } /* Combine the most homogenous pixels for the final result: */ for (row=top+3; row < top+TS-3 && row < height-5; row++) { tr = row-top; for (col=left+3; col < left+TS-3 && col < width-5; col++) { tc = col-left; for (d=0; d < 2; d++) for (hm[d]=0, i=tr-1; i <= tr+1; i++) for (j=tc-1; j <= tc+1; j++) hm[d] += homo[d][i][j]; if (hm[0] != hm[1]) FORC3 image[row*width+col][c] = rgb[hm[1] > hm[0]][tr][tc][c]; else FORC3 image[row*width+col][c] = (rgb[0][tr][tc][c] + rgb[1][tr][tc][c]) >> 1; } } } free (buffer); } #endif #undef TS void CLASS median_filter() { ushort (*pix)[4]; int pass, c, i, j, k, med[9]; static const uchar opt[] = /* Optimal 9-element median search */ { 1,2, 4,5, 7,8, 0,1, 3,4, 6,7, 1,2, 4,5, 7,8, 0,3, 5,8, 4,7, 3,6, 1,4, 2,5, 4,7, 4,2, 6,4, 4,2 }; for (pass=1; pass <= med_passes; pass++) { #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_MEDIAN_FILTER,pass-1,med_passes); #endif #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("Median filter pass %d...\n"), pass); #endif for (c=0; c < 3; c+=2) { for (pix = image; pix < image+width*height; pix++) pix[0][3] = pix[0][c]; for (pix = image+width; pix < image+width*(height-1); pix++) { if ((pix-image+1) % width < 2) continue; for (k=0, i = -width; i <= width; i += width) for (j = i-1; j <= i+1; j++) med[k++] = pix[j][3] - pix[j][1]; for (i=0; i < sizeof opt; i+=2) if (med[opt[i]] > med[opt[i+1]]) SWAP (med[opt[i]] , med[opt[i+1]]); pix[0][c] = CLIP(med[4] + pix[0][1]); } } } } void CLASS blend_highlights() { int clip=INT_MAX, row, col, c, i, j; static const float trans[2][4][4] = { { { 1,1,1 }, { 1.7320508,-1.7320508,0 }, { -1,-1,2 } }, { { 1,1,1,1 }, { 1,-1,1,-1 }, { 1,1,-1,-1 }, { 1,-1,-1,1 } } }; static const float itrans[2][4][4] = { { { 1,0.8660254,-0.5 }, { 1,-0.8660254,-0.5 }, { 1,0,1 } }, { { 1,1,1,1 }, { 1,-1,1,-1 }, { 1,1,-1,-1 }, { 1,-1,-1,1 } } }; float cam[2][4], lab[2][4], sum[2], chratio; if ((unsigned) (colors-3) > 1) return; #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("Blending highlights...\n")); #endif #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_HIGHLIGHTS,0,2); #endif FORCC if (clip > (i = 65535*pre_mul[c])) clip = i; for (row=0; row < height; row++) for (col=0; col < width; col++) { FORCC if (image[row*width+col][c] > clip) break; if (c == colors) continue; FORCC { cam[0][c] = image[row*width+col][c]; cam[1][c] = MIN(cam[0][c],clip); } for (i=0; i < 2; i++) { FORCC for (lab[i][c]=j=0; j < colors; j++) lab[i][c] += trans[colors-3][c][j] * cam[i][j]; for (sum[i]=0,c=1; c < colors; c++) sum[i] += SQR(lab[i][c]); } chratio = sqrt(sum[1]/sum[0]); for (c=1; c < colors; c++) lab[0][c] *= chratio; FORCC for (cam[0][c]=j=0; j < colors; j++) cam[0][c] += itrans[colors-3][c][j] * lab[0][j]; FORCC image[row*width+col][c] = cam[0][c] / colors; } #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_HIGHLIGHTS,1,2); #endif } #define SCALE (4 >> shrink) void CLASS recover_highlights() { float *map, sum, wgt, grow; int hsat[4], count, spread, change, val, i; unsigned high, wide, mrow, mcol, row, col, kc, c, d, y, x; ushort *pixel; static const signed char dir[8][2] = { {-1,-1}, {-1,0}, {-1,1}, {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1} }; #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("Rebuilding highlights...\n")); #endif grow = pow (2.0, 4-highlight); FORCC hsat[c] = 32000 * pre_mul[c]; for (kc=0, c=1; c < colors; c++) if (pre_mul[kc] < pre_mul[c]) kc = c; high = height / SCALE; wide = width / SCALE; map = (float *) calloc (high, wide*sizeof *map); merror (map, "recover_highlights()"); FORCC if (c != kc) { #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_HIGHLIGHTS,c-1,colors-1); #endif memset (map, 0, high*wide*sizeof *map); for (mrow=0; mrow < high; mrow++) for (mcol=0; mcol < wide; mcol++) { sum = wgt = count = 0; for (row = mrow*SCALE; row < (mrow+1)*SCALE; row++) for (col = mcol*SCALE; col < (mcol+1)*SCALE; col++) { pixel = image[row*width+col]; if (pixel[c] / hsat[c] == 1 && pixel[kc] > 24000) { sum += pixel[c]; wgt += pixel[kc]; count++; } } if (count == SCALE*SCALE) map[mrow*wide+mcol] = sum / wgt; } for (spread = 32/grow; spread--; ) { for (mrow=0; mrow < high; mrow++) for (mcol=0; mcol < wide; mcol++) { if (map[mrow*wide+mcol]) continue; sum = count = 0; for (d=0; d < 8; d++) { y = mrow + dir[d][0]; x = mcol + dir[d][1]; if (y < high && x < wide && map[y*wide+x] > 0) { sum += (1 + (d & 1)) * map[y*wide+x]; count += 1 + (d & 1); } } if (count > 3) map[mrow*wide+mcol] = - (sum+grow) / (count+grow); } for (change=i=0; i < high*wide; i++) if (map[i] < 0) { map[i] = -map[i]; change = 1; } if (!change) break; } for (i=0; i < high*wide; i++) if (map[i] == 0) map[i] = 1; for (mrow=0; mrow < high; mrow++) for (mcol=0; mcol < wide; mcol++) { for (row = mrow*SCALE; row < (mrow+1)*SCALE; row++) for (col = mcol*SCALE; col < (mcol+1)*SCALE; col++) { pixel = image[row*width+col]; if (pixel[c] / hsat[c] > 1) { val = pixel[kc] * map[mrow*wide+mcol]; if (pixel[c] < val) pixel[c] = CLIP(val); } } } } free (map); } #undef SCALE void CLASS tiff_get (unsigned base, unsigned *tag, unsigned *type, unsigned *len, unsigned *save) { *tag = get2(); *type = get2(); *len = get4(); *save = ftell(ifp) + 4; if (*len * ("11124811248484"[*type < 14 ? *type:0]-'0') > 4) fseek (ifp, get4()+base, SEEK_SET); } void CLASS parse_thumb_note (int base, unsigned toff, unsigned tlen) { unsigned entries, tag, type, len, save; entries = get2(); while (entries--) { tiff_get (base, &tag, &type, &len, &save); if (tag == toff) thumb_offset = get4()+base; if (tag == tlen) thumb_length = get4(); fseek (ifp, save, SEEK_SET); } } //@end COMMON int CLASS parse_tiff_ifd (int base); //@out COMMON static float powf_lim(float a, float b, float limup) { return (b>limup || b < -limup)?0.f:powf(a,b); } static float libraw_powf64(float a, float b) { return powf_lim(a,b,64.f); } #ifdef LIBRAW_LIBRARY_BUILD static float my_roundf(float x) { float t; if (x >= 0.0) { t = ceilf(x); if (t - x > 0.5) t -= 1.0; return t; } else { t = ceilf(-x); if (t + x > 0.5) t -= 1.0; return -t; } } static float _CanonConvertAperture(ushort in) { if ((in == (ushort)0xffe0) || (in == (ushort)0x7fff)) return 0.0f; return libraw_powf64(2.0, in/64.0); } static float _CanonConvertEV (short in) { short EV, Sign, Frac; float Frac_f; EV = in; if (EV < 0) { EV = -EV; Sign = -1; } else { Sign = 1; } Frac = EV & 0x1f; EV -= Frac; // remove fraction if (Frac == 0x0c) { // convert 1/3 and 2/3 codes Frac_f = 32.0f / 3.0f; } else if (Frac == 0x14) { Frac_f = 64.0f / 3.0f; } else Frac_f = (float) Frac; return ((float)Sign * ((float)EV + Frac_f))/32.0f; } void CLASS setCanonBodyFeatures (unsigned id) { imgdata.lens.makernotes.CamID = id; if ( (id == 0x80000001) || // 1D (id == 0x80000174) || // 1D2 (id == 0x80000232) || // 1D2N (id == 0x80000169) || // 1D3 (id == 0x80000281) // 1D4 ) { imgdata.lens.makernotes.CameraFormat = LIBRAW_FORMAT_APSH; imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Canon_EF; } else if ( (id == 0x80000167) || // 1Ds (id == 0x80000188) || // 1Ds2 (id == 0x80000215) || // 1Ds3 (id == 0x80000269) || // 1DX (id == 0x80000328) || // 1DX2 (id == 0x80000324) || // 1DC (id == 0x80000213) || // 5D (id == 0x80000218) || // 5D2 (id == 0x80000285) || // 5D3 (id == 0x80000349) || // 5D4 (id == 0x80000382) || // 5DS (id == 0x80000401) || // 5DS R (id == 0x80000302) // 6D ) { imgdata.lens.makernotes.CameraFormat = LIBRAW_FORMAT_FF; imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Canon_EF; } else if ( (id == 0x80000331) || // M (id == 0x80000355) || // M2 (id == 0x80000374) || // M3 (id == 0x80000384) || // M10 (id == 0x80000394) // M5 ) { imgdata.lens.makernotes.CameraFormat = LIBRAW_FORMAT_APSC; imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Canon_EF_M; } else if ( (id == 0x01140000) || // D30 (id == 0x01668000) || // D60 (id > 0x80000000) ) { imgdata.lens.makernotes.CameraFormat = LIBRAW_FORMAT_APSC; imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Canon_EF; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Unknown; } else { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens; } return; } void CLASS processCanonCameraInfo (unsigned id, uchar *CameraInfo, unsigned maxlen) { ushort iCanonLensID = 0, iCanonMaxFocal = 0, iCanonMinFocal = 0, iCanonLens = 0, iCanonCurFocal = 0, iCanonFocalType = 0; if(maxlen<16) return; // too short, so broken CameraInfo[0] = 0; CameraInfo[1] = 0; switch (id) { case 0x80000001: // 1D case 0x80000167: // 1DS iCanonCurFocal = 10; iCanonLensID = 13; iCanonMinFocal = 14; iCanonMaxFocal = 16; if (!imgdata.lens.makernotes.CurFocal) imgdata.lens.makernotes.CurFocal = sget2(CameraInfo + iCanonCurFocal); if (!imgdata.lens.makernotes.MinFocal) imgdata.lens.makernotes.MinFocal = sget2(CameraInfo + iCanonMinFocal); if (!imgdata.lens.makernotes.MaxFocal) imgdata.lens.makernotes.MaxFocal = sget2(CameraInfo + iCanonMaxFocal); break; case 0x80000174: // 1DMkII case 0x80000188: // 1DsMkII iCanonCurFocal = 9; iCanonLensID = 12; iCanonMinFocal = 17; iCanonMaxFocal = 19; iCanonFocalType = 45; break; case 0x80000232: // 1DMkII N iCanonCurFocal = 9; iCanonLensID = 12; iCanonMinFocal = 17; iCanonMaxFocal = 19; break; case 0x80000169: // 1DMkIII case 0x80000215: // 1DsMkIII iCanonCurFocal = 29; iCanonLensID = 273; iCanonMinFocal = 275; iCanonMaxFocal = 277; break; case 0x80000281: // 1DMkIV iCanonCurFocal = 30; iCanonLensID = 335; iCanonMinFocal = 337; iCanonMaxFocal = 339; break; case 0x80000269: // 1D X iCanonCurFocal = 35; iCanonLensID = 423; iCanonMinFocal = 425; iCanonMaxFocal = 427; break; case 0x80000213: // 5D iCanonCurFocal = 40; if (!sget2Rev(CameraInfo + 12)) iCanonLensID = 151; else iCanonLensID = 12; iCanonMinFocal = 147; iCanonMaxFocal = 149; break; case 0x80000218: // 5DMkII iCanonCurFocal = 30; iCanonLensID = 230; iCanonMinFocal = 232; iCanonMaxFocal = 234; break; case 0x80000285: // 5DMkIII iCanonCurFocal = 35; iCanonLensID = 339; iCanonMinFocal = 341; iCanonMaxFocal = 343; break; case 0x80000302: // 6D iCanonCurFocal = 35; iCanonLensID = 353; iCanonMinFocal = 355; iCanonMaxFocal = 357; break; case 0x80000250: // 7D iCanonCurFocal = 30; iCanonLensID = 274; iCanonMinFocal = 276; iCanonMaxFocal = 278; break; case 0x80000190: // 40D iCanonCurFocal = 29; iCanonLensID = 214; iCanonMinFocal = 216; iCanonMaxFocal = 218; iCanonLens = 2347; break; case 0x80000261: // 50D iCanonCurFocal = 30; iCanonLensID = 234; iCanonMinFocal = 236; iCanonMaxFocal = 238; break; case 0x80000287: // 60D iCanonCurFocal = 30; iCanonLensID = 232; iCanonMinFocal = 234; iCanonMaxFocal = 236; break; case 0x80000325: // 70D iCanonCurFocal = 35; iCanonLensID = 358; iCanonMinFocal = 360; iCanonMaxFocal = 362; break; case 0x80000176: // 450D iCanonCurFocal = 29; iCanonLensID = 222; iCanonLens = 2355; break; case 0x80000252: // 500D iCanonCurFocal = 30; iCanonLensID = 246; iCanonMinFocal = 248; iCanonMaxFocal = 250; break; case 0x80000270: // 550D iCanonCurFocal = 30; iCanonLensID = 255; iCanonMinFocal = 257; iCanonMaxFocal = 259; break; case 0x80000286: // 600D case 0x80000288: // 1100D iCanonCurFocal = 30; iCanonLensID = 234; iCanonMinFocal = 236; iCanonMaxFocal = 238; break; case 0x80000301: // 650D case 0x80000326: // 700D iCanonCurFocal = 35; iCanonLensID = 295; iCanonMinFocal = 297; iCanonMaxFocal = 299; break; case 0x80000254: // 1000D iCanonCurFocal = 29; iCanonLensID = 226; iCanonMinFocal = 228; iCanonMaxFocal = 230; iCanonLens = 2359; break; } if (iCanonFocalType) { if(iCanonFocalType>=maxlen) return; // broken; imgdata.lens.makernotes.FocalType = CameraInfo[iCanonFocalType]; if (!imgdata.lens.makernotes.FocalType) // zero means 'fixed' here, replacing with standard '1' imgdata.lens.makernotes.FocalType = 1; } if (!imgdata.lens.makernotes.CurFocal) { if(iCanonCurFocal>=maxlen) return; // broken; imgdata.lens.makernotes.CurFocal = sget2Rev(CameraInfo + iCanonCurFocal); } if (!imgdata.lens.makernotes.LensID) { if(iCanonLensID>=maxlen) return; // broken; imgdata.lens.makernotes.LensID = sget2Rev(CameraInfo + iCanonLensID); } if (!imgdata.lens.makernotes.MinFocal) { if(iCanonMinFocal>=maxlen) return; // broken; imgdata.lens.makernotes.MinFocal = sget2Rev(CameraInfo + iCanonMinFocal); } if (!imgdata.lens.makernotes.MaxFocal) { if(iCanonMaxFocal>=maxlen) return; // broken; imgdata.lens.makernotes.MaxFocal = sget2Rev(CameraInfo + iCanonMaxFocal); } if (!imgdata.lens.makernotes.Lens[0] && iCanonLens) { if(iCanonLens+64>=maxlen) return; // broken; if (CameraInfo[iCanonLens] < 65) // non-Canon lens { memcpy(imgdata.lens.makernotes.Lens, CameraInfo + iCanonLens, 64); } else if (!strncmp((char *)CameraInfo + iCanonLens, "EF-S", 4)) { memcpy(imgdata.lens.makernotes.Lens, "EF-S ", 5); memcpy(imgdata.lens.makernotes.LensFeatures_pre, "EF-E", 4); imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Canon_EF_S; memcpy(imgdata.lens.makernotes.Lens + 5, CameraInfo + iCanonLens + 4, 60); } else if (!strncmp((char *)CameraInfo + iCanonLens, "TS-E", 4)) { memcpy(imgdata.lens.makernotes.Lens, "TS-E ", 5); memcpy(imgdata.lens.makernotes.LensFeatures_pre, "TS-E", 4); imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Canon_EF; memcpy(imgdata.lens.makernotes.Lens + 5, CameraInfo + iCanonLens + 4, 60); } else if (!strncmp((char *)CameraInfo + iCanonLens, "MP-E", 4)) { memcpy(imgdata.lens.makernotes.Lens, "MP-E ", 5); memcpy(imgdata.lens.makernotes.LensFeatures_pre, "MP-E", 4); imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Canon_EF; memcpy(imgdata.lens.makernotes.Lens + 5, CameraInfo + iCanonLens + 4, 60); } else if (!strncmp((char *)CameraInfo + iCanonLens, "EF-M", 4)) { memcpy(imgdata.lens.makernotes.Lens, "EF-M ", 5); memcpy(imgdata.lens.makernotes.LensFeatures_pre, "EF-M", 4); imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Canon_EF_M; memcpy(imgdata.lens.makernotes.Lens + 5, CameraInfo + iCanonLens + 4, 60); } else { memcpy(imgdata.lens.makernotes.Lens, CameraInfo + iCanonLens, 2); memcpy(imgdata.lens.makernotes.LensFeatures_pre, "EF", 2); imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Canon_EF; imgdata.lens.makernotes.Lens[2] = 32; memcpy(imgdata.lens.makernotes.Lens + 3, CameraInfo + iCanonLens + 2, 62); } } return; } void CLASS Canon_CameraSettings () { fseek(ifp, 10, SEEK_CUR); imgdata.shootinginfo.DriveMode = get2(); get2(); imgdata.shootinginfo.FocusMode = get2(); fseek(ifp, 18, SEEK_CUR); imgdata.shootinginfo.MeteringMode = get2(); get2(); imgdata.shootinginfo.AFPoint = get2(); imgdata.shootinginfo.ExposureMode = get2(); get2(); imgdata.lens.makernotes.LensID = get2(); imgdata.lens.makernotes.MaxFocal = get2(); imgdata.lens.makernotes.MinFocal = get2(); imgdata.lens.makernotes.CanonFocalUnits = get2(); if (imgdata.lens.makernotes.CanonFocalUnits > 1) { imgdata.lens.makernotes.MaxFocal /= (float)imgdata.lens.makernotes.CanonFocalUnits; imgdata.lens.makernotes.MinFocal /= (float)imgdata.lens.makernotes.CanonFocalUnits; } imgdata.lens.makernotes.MaxAp = _CanonConvertAperture(get2()); imgdata.lens.makernotes.MinAp = _CanonConvertAperture(get2()); fseek(ifp, 12, SEEK_CUR); imgdata.shootinginfo.ImageStabilization = get2(); } void CLASS Canon_WBpresets (int skip1, int skip2) { int c; FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][c ^ (c >> 1)] = get2(); if (skip1) fseek(ifp, skip1, SEEK_CUR); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][c ^ (c >> 1)] = get2(); if (skip1) fseek(ifp, skip1, SEEK_CUR); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][c ^ (c >> 1)] = get2(); if (skip1) fseek(ifp, skip1, SEEK_CUR); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][c ^ (c >> 1)] = get2(); if (skip1) fseek(ifp, skip1, SEEK_CUR); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][c ^ (c >> 1)] = get2(); if (skip2) fseek(ifp, skip2, SEEK_CUR); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][c ^ (c >> 1)] = get2(); return; } void CLASS Canon_WBCTpresets (short WBCTversion) { if (WBCTversion == 0) for (int i=0; i<15; i++)// tint, as shot R, as shot B, CСT { imgdata.color.WBCT_Coeffs[i][2] = imgdata.color.WBCT_Coeffs[i][4] = 1.0f; fseek (ifp, 2, SEEK_CUR); imgdata.color.WBCT_Coeffs[i][1] = 1024.0f /fMAX(get2(),1.f) ; imgdata.color.WBCT_Coeffs[i][3] = 1024.0f /fMAX(get2(),1.f); imgdata.color.WBCT_Coeffs[i][0] = get2(); } else if (WBCTversion == 1) for (int i=0; i<15; i++) // as shot R, as shot B, tint, CСT { imgdata.color.WBCT_Coeffs[i][2] = imgdata.color.WBCT_Coeffs[i][4] = 1.0f; imgdata.color.WBCT_Coeffs[i][1] = 1024.0f / fMAX(get2(),1.f); imgdata.color.WBCT_Coeffs[i][3] = 1024.0f / fMAX(get2(),1.f); fseek (ifp, 2, SEEK_CUR); imgdata.color.WBCT_Coeffs[i][0] = get2(); } else if ((WBCTversion == 2) && ((unique_id == 0x80000374) || // M3 (unique_id == 0x80000384) || // M10 (unique_id == 0x80000394) || // M5 (unique_id == 0x03970000))) // G7 X Mark II for (int i=0; i<15; i++) // tint, offset, as shot R, as shot B, CСT { fseek (ifp, 2, SEEK_CUR); fseek (ifp, 2, SEEK_CUR); imgdata.color.WBCT_Coeffs[i][2] = imgdata.color.WBCT_Coeffs[i][4] = 1.0f; imgdata.color.WBCT_Coeffs[i][1] = 1024.0f / fMAX(1.f,get2()); imgdata.color.WBCT_Coeffs[i][3] = 1024.0f / fMAX(1.f,get2()); imgdata.color.WBCT_Coeffs[i][0] = get2(); } else if ((WBCTversion == 2) && ((unique_id == 0x03950000) || (unique_id == 0x03930000))) // G5 X, G9 X for (int i=0; i<15; i++) // tint, offset, as shot R, as shot B, CСT { fseek (ifp, 2, SEEK_CUR); fseek (ifp, 2, SEEK_CUR); imgdata.color.WBCT_Coeffs[i][2] = imgdata.color.WBCT_Coeffs[i][4] = 1.0f; imgdata.color.WBCT_Coeffs[i][1] = (float)get2() / 512.0f; imgdata.color.WBCT_Coeffs[i][3] = (float)get2() / 512.0f; imgdata.color.WBCT_Coeffs[i][0] = get2(); } return; } void CLASS processNikonLensData (uchar *LensData, unsigned len) { ushort i; if (!(imgdata.lens.nikon.NikonLensType & 0x01)) { imgdata.lens.makernotes.LensFeatures_pre[0] = 'A'; imgdata.lens.makernotes.LensFeatures_pre[1] = 'F'; } else { imgdata.lens.makernotes.LensFeatures_pre[0] = 'M'; imgdata.lens.makernotes.LensFeatures_pre[1] = 'F'; } if (imgdata.lens.nikon.NikonLensType & 0x02) { if (imgdata.lens.nikon.NikonLensType & 0x04) imgdata.lens.makernotes.LensFeatures_suf[0] = 'G'; else imgdata.lens.makernotes.LensFeatures_suf[0] = 'D'; imgdata.lens.makernotes.LensFeatures_suf[1] = ' '; } if (imgdata.lens.nikon.NikonLensType & 0x08) { imgdata.lens.makernotes.LensFeatures_suf[2] = 'V'; imgdata.lens.makernotes.LensFeatures_suf[3] = 'R'; } if (imgdata.lens.nikon.NikonLensType & 0x10) { imgdata.lens.makernotes.LensMount = imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Nikon_CX; imgdata.lens.makernotes.CameraFormat = imgdata.lens.makernotes.LensFormat = LIBRAW_FORMAT_1INCH; } else imgdata.lens.makernotes.LensMount = imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Nikon_F; if (imgdata.lens.nikon.NikonLensType & 0x20) { strcpy(imgdata.lens.makernotes.Adapter, "FT-1"); imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Nikon_F; imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Nikon_CX; imgdata.lens.makernotes.CameraFormat = LIBRAW_FORMAT_1INCH; } imgdata.lens.nikon.NikonLensType = imgdata.lens.nikon.NikonLensType & 0xdf; if (len < 20) { switch (len) { case 9: i = 2; break; case 15: i = 7; break; case 16: i = 8; break; } imgdata.lens.nikon.NikonLensIDNumber = LensData[i]; imgdata.lens.nikon.NikonLensFStops = LensData[i + 1]; imgdata.lens.makernotes.LensFStops = (float)imgdata.lens.nikon.NikonLensFStops /12.0f; if (fabsf(imgdata.lens.makernotes.MinFocal) < 1.1f) { if ((imgdata.lens.nikon.NikonLensType ^ (uchar)0x01) || LensData[i + 2]) imgdata.lens.makernotes.MinFocal = 5.0f * libraw_powf64(2.0f, (float)LensData[i + 2] / 24.0f); if ((imgdata.lens.nikon.NikonLensType ^ (uchar)0x01) || LensData[i + 3]) imgdata.lens.makernotes.MaxFocal = 5.0f * libraw_powf64(2.0f, (float)LensData[i + 3] / 24.0f); if ((imgdata.lens.nikon.NikonLensType ^ (uchar)0x01) || LensData[i + 4]) imgdata.lens.makernotes.MaxAp4MinFocal = libraw_powf64(2.0f, (float)LensData[i + 4] / 24.0f); if ((imgdata.lens.nikon.NikonLensType ^ (uchar)0x01) || LensData[i + 5]) imgdata.lens.makernotes.MaxAp4MaxFocal = libraw_powf64(2.0f, (float)LensData[i + 5] / 24.0f); } imgdata.lens.nikon.NikonMCUVersion = LensData[i + 6]; if (i != 2) { if ((LensData[i - 1]) && (fabsf(imgdata.lens.makernotes.CurFocal) < 1.1f)) imgdata.lens.makernotes.CurFocal = 5.0f * libraw_powf64(2.0f, (float)LensData[i - 1] / 24.0f); if (LensData[i + 7]) imgdata.lens.nikon.NikonEffectiveMaxAp = libraw_powf64(2.0f, (float)LensData[i + 7] / 24.0f); } imgdata.lens.makernotes.LensID = (unsigned long long) LensData[i] << 56 | (unsigned long long) LensData[i + 1] << 48 | (unsigned long long) LensData[i + 2] << 40 | (unsigned long long) LensData[i + 3] << 32 | (unsigned long long) LensData[i + 4] << 24 | (unsigned long long) LensData[i + 5] << 16 | (unsigned long long) LensData[i + 6] << 8 | (unsigned long long) imgdata.lens.nikon.NikonLensType; } else if ((len == 459) || (len == 590)) { memcpy(imgdata.lens.makernotes.Lens, LensData + 390, 64); } else if (len == 509) { memcpy(imgdata.lens.makernotes.Lens, LensData + 391, 64); } else if (len == 879) { memcpy(imgdata.lens.makernotes.Lens, LensData + 680, 64); } return; } void CLASS setOlympusBodyFeatures (unsigned long long id) { imgdata.lens.makernotes.CamID = id; if ((id == 0x4434303430ULL) || // E-1 (id == 0x4434303431ULL) || // E-300 ((id & 0x00ffff0000ULL) == 0x0030300000ULL)) { imgdata.lens.makernotes.CameraFormat = LIBRAW_FORMAT_FT; if ((id == 0x4434303430ULL) || // E-1 (id == 0x4434303431ULL) || // E-330 ((id >= 0x5330303033ULL) && (id <= 0x5330303138ULL)) || // E-330 to E-520 (id == 0x5330303233ULL) || // E-620 (id == 0x5330303239ULL) || // E-450 (id == 0x5330303330ULL) || // E-600 (id == 0x5330303333ULL)) // E-5 { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FT; } else { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_mFT; } } else { imgdata.lens.makernotes.LensMount = imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens; } return; } void CLASS parseCanonMakernotes (unsigned tag, unsigned type, unsigned len) { if (tag == 0x0001) Canon_CameraSettings(); else if (tag == 0x0002) // focal length { imgdata.lens.makernotes.FocalType = get2(); imgdata.lens.makernotes.CurFocal = get2(); if (imgdata.lens.makernotes.CanonFocalUnits > 1) { imgdata.lens.makernotes.CurFocal /= (float)imgdata.lens.makernotes.CanonFocalUnits; } } else if (tag == 0x0004) // shot info { short tempAp; fseek(ifp, 30, SEEK_CUR); imgdata.other.FlashEC = _CanonConvertEV((signed short)get2()); fseek(ifp, 8-32, SEEK_CUR); if ((tempAp = get2()) != 0x7fff) imgdata.lens.makernotes.CurAp = _CanonConvertAperture(tempAp); if (imgdata.lens.makernotes.CurAp < 0.7f) { fseek(ifp, 32, SEEK_CUR); imgdata.lens.makernotes.CurAp = _CanonConvertAperture(get2()); } if (!aperture) aperture = imgdata.lens.makernotes.CurAp; } else if (tag == 0x0095 && // lens model tag !imgdata.lens.makernotes.Lens[0]) { fread(imgdata.lens.makernotes.Lens, 2, 1, ifp); imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Canon_EF; if (imgdata.lens.makernotes.Lens[0] < 65) // non-Canon lens fread(imgdata.lens.makernotes.Lens + 2, 62, 1, ifp); else { char efs[2]; imgdata.lens.makernotes.LensFeatures_pre[0] = imgdata.lens.makernotes.Lens[0]; imgdata.lens.makernotes.LensFeatures_pre[1] = imgdata.lens.makernotes.Lens[1]; fread(efs, 2, 1, ifp); if (efs[0] == 45 && (efs[1] == 83 || efs[1] == 69 || efs[1] == 77)) { // "EF-S, TS-E, MP-E, EF-M" lenses imgdata.lens.makernotes.Lens[2] = imgdata.lens.makernotes.LensFeatures_pre[2] = efs[0]; imgdata.lens.makernotes.Lens[3] = imgdata.lens.makernotes.LensFeatures_pre[3] = efs[1]; imgdata.lens.makernotes.Lens[4] = 32; if (efs[1] == 83) { imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Canon_EF_S; imgdata.lens.makernotes.LensFormat = LIBRAW_FORMAT_APSC; } else if (efs[1] == 77) { imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Canon_EF_M; } } else { // "EF" lenses imgdata.lens.makernotes.Lens[2] = 32; imgdata.lens.makernotes.Lens[3] = efs[0]; imgdata.lens.makernotes.Lens[4] = efs[1]; } fread(imgdata.lens.makernotes.Lens + 5, 58, 1, ifp); } } else if (tag == 0x00a9) { long int save1 = ftell(ifp); fseek (ifp, save1+(0x5<<1), SEEK_SET); Canon_WBpresets(0,0); fseek (ifp, save1, SEEK_SET); } else if (tag == 0x00e0) // sensor info { imgdata.makernotes.canon.SensorWidth = (get2(),get2()); imgdata.makernotes.canon.SensorHeight = get2(); imgdata.makernotes.canon.SensorLeftBorder = (get2(),get2(),get2()); imgdata.makernotes.canon.SensorTopBorder = get2(); imgdata.makernotes.canon.SensorRightBorder = get2(); imgdata.makernotes.canon.SensorBottomBorder = get2(); imgdata.makernotes.canon.BlackMaskLeftBorder = get2(); imgdata.makernotes.canon.BlackMaskTopBorder = get2(); imgdata.makernotes.canon.BlackMaskRightBorder = get2(); imgdata.makernotes.canon.BlackMaskBottomBorder = get2(); } else if (tag == 0x4001 && len > 500) { int c; long int save1 = ftell(ifp); switch (len) { case 582: imgdata.makernotes.canon.CanonColorDataVer = 1; // 20D / 350D { fseek (ifp, save1+(0x23<<1), SEEK_SET); Canon_WBpresets(2,2); fseek (ifp, save1+(0x4b<<1), SEEK_SET); Canon_WBCTpresets (1); // ABCT } break; case 653: imgdata.makernotes.canon.CanonColorDataVer = 2; // 1Dmk2 / 1DsMK2 { fseek (ifp, save1+(0x27<<1), SEEK_SET); Canon_WBpresets(2,12); fseek (ifp, save1+(0xa4<<1), SEEK_SET); Canon_WBCTpresets (1); // ABCT } break; case 796: imgdata.makernotes.canon.CanonColorDataVer = 3; // 1DmkIIN / 5D / 30D / 400D imgdata.makernotes.canon.CanonColorDataSubVer = get2(); { fseek (ifp, save1+(0x4e<<1), SEEK_SET); Canon_WBpresets(2,12); fseek (ifp, save1+(0x85<<1), SEEK_SET); Canon_WBCTpresets (0); // BCAT fseek (ifp, save1+(0x0c4<<1), SEEK_SET); // offset 196 short int bls=0; FORC4 bls+= (imgdata.makernotes.canon.ChannelBlackLevel[c]=get2()); imgdata.makernotes.canon.AverageBlackLevel = bls/4; } break; // 1DmkIII / 1DSmkIII / 1DmkIV / 5DmkII // 7D / 40D / 50D / 60D / 450D / 500D // 550D / 1000D / 1100D case 674: case 692: case 702: case 1227: case 1250: case 1251: case 1337: case 1338: case 1346: imgdata.makernotes.canon.CanonColorDataVer = 4; imgdata.makernotes.canon.CanonColorDataSubVer = get2(); { fseek (ifp, save1+(0x53<<1), SEEK_SET); Canon_WBpresets(2,12); fseek (ifp, save1+(0xa8<<1), SEEK_SET); Canon_WBCTpresets (0); // BCAT fseek (ifp, save1+(0x0e7<<1), SEEK_SET); // offset 231 short int bls=0; FORC4 bls+= (imgdata.makernotes.canon.ChannelBlackLevel[c]=get2()); imgdata.makernotes.canon.AverageBlackLevel = bls/4; } if ((imgdata.makernotes.canon.CanonColorDataSubVer == 4) || (imgdata.makernotes.canon.CanonColorDataSubVer == 5)) { fseek (ifp, save1+(0x2b9<<1), SEEK_SET); // offset 697 shorts imgdata.makernotes.canon.SpecularWhiteLevel = get2(); FORC4 imgdata.color.linear_max[c] = imgdata.makernotes.canon.SpecularWhiteLevel; } else if ((imgdata.makernotes.canon.CanonColorDataSubVer == 6) || (imgdata.makernotes.canon.CanonColorDataSubVer == 7)) { fseek (ifp, save1+(0x2d0<<1), SEEK_SET); // offset 720 shorts imgdata.makernotes.canon.SpecularWhiteLevel = get2(); FORC4 imgdata.color.linear_max[c] = imgdata.makernotes.canon.SpecularWhiteLevel; } else if (imgdata.makernotes.canon.CanonColorDataSubVer == 9) { fseek (ifp, save1+(0x2d4<<1), SEEK_SET); // offset 724 shorts imgdata.makernotes.canon.SpecularWhiteLevel = get2(); FORC4 imgdata.color.linear_max[c] = imgdata.makernotes.canon.SpecularWhiteLevel; } break; case 5120: imgdata.makernotes.canon.CanonColorDataVer = 5; // PowerSot G10, G12, G5 X, EOS M3, EOS M5 { fseek (ifp, save1+(0x56<<1), SEEK_SET); if ((unique_id == 0x03970000) || // G7 X Mark II (unique_id == 0x80000394)) // EOS M5 { fseek(ifp, 18, SEEK_CUR); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Other][c ^ (c >> 1)] = get2(); fseek(ifp, 8, SEEK_CUR); Canon_WBpresets(8,24); fseek(ifp, 168, SEEK_CUR); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_WW][c ^ (c >> 1)] = get2(); fseek(ifp, 24, SEEK_CUR); Canon_WBCTpresets (2); // BCADT fseek(ifp, 6, SEEK_CUR); } else { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Other][c ^ (c >> 1)] = get2(); get2(); Canon_WBpresets(2,12); fseek (ifp, save1+(0xba<<1), SEEK_SET); Canon_WBCTpresets (2); // BCADT fseek (ifp, save1+(0x108<<1), SEEK_SET); // offset 264 short } int bls=0; FORC4 bls+= (imgdata.makernotes.canon.ChannelBlackLevel[c]=get2()); imgdata.makernotes.canon.AverageBlackLevel = bls/4; } break; case 1273: case 1275: imgdata.makernotes.canon.CanonColorDataVer = 6; // 600D / 1200D imgdata.makernotes.canon.CanonColorDataSubVer = get2(); { fseek (ifp, save1+(0x67<<1), SEEK_SET); Canon_WBpresets(2,12); fseek (ifp, save1+(0xbc<<1), SEEK_SET); Canon_WBCTpresets (0); // BCAT fseek (ifp, save1+(0x0fb<<1), SEEK_SET); // offset 251 short int bls=0; FORC4 bls+= (imgdata.makernotes.canon.ChannelBlackLevel[c]=get2()); imgdata.makernotes.canon.AverageBlackLevel = bls/4; } fseek (ifp, save1+(0x1e4<<1), SEEK_SET); // offset 484 shorts imgdata.makernotes.canon.SpecularWhiteLevel = get2(); FORC4 imgdata.color.linear_max[c] = imgdata.makernotes.canon.SpecularWhiteLevel; break; // 1DX / 5DmkIII / 6D / 100D / 650D / 700D / EOS M / 7DmkII / 750D / 760D case 1312: case 1313: case 1316: case 1506: imgdata.makernotes.canon.CanonColorDataVer = 7; imgdata.makernotes.canon.CanonColorDataSubVer = get2(); { fseek (ifp, save1+(0x80<<1), SEEK_SET); Canon_WBpresets(2,12); fseek (ifp, save1+(0xd5<<1), SEEK_SET); Canon_WBCTpresets (0); // BCAT fseek (ifp, save1+(0x114<<1), SEEK_SET); // offset 276 shorts int bls=0; FORC4 bls+= (imgdata.makernotes.canon.ChannelBlackLevel[c]=get2()); imgdata.makernotes.canon.AverageBlackLevel = bls/4; } if (imgdata.makernotes.canon.CanonColorDataSubVer == 10) { fseek (ifp, save1+(0x1fd<<1), SEEK_SET); // offset 509 shorts imgdata.makernotes.canon.SpecularWhiteLevel = get2(); FORC4 imgdata.color.linear_max[c] = imgdata.makernotes.canon.SpecularWhiteLevel; } else if (imgdata.makernotes.canon.CanonColorDataSubVer == 11) { fseek (ifp, save1+(0x2dd<<1), SEEK_SET); // offset 733 shorts imgdata.makernotes.canon.SpecularWhiteLevel = get2(); FORC4 imgdata.color.linear_max[c] = imgdata.makernotes.canon.SpecularWhiteLevel; } break; // 5DS / 5DS R / 80D / 1300D / 5D4 case 1560: case 1592: case 1353: imgdata.makernotes.canon.CanonColorDataVer = 8; imgdata.makernotes.canon.CanonColorDataSubVer = get2(); { fseek (ifp, save1+(0x85<<1), SEEK_SET); Canon_WBpresets(2,12); fseek (ifp, save1+(0x107<<1), SEEK_SET); Canon_WBCTpresets (0); // BCAT fseek (ifp, save1+(0x146<<1), SEEK_SET); // offset 326 shorts int bls=0; FORC4 bls+= (imgdata.makernotes.canon.ChannelBlackLevel[c]=get2()); imgdata.makernotes.canon.AverageBlackLevel = bls/4; } if (imgdata.makernotes.canon.CanonColorDataSubVer == 14) // 1300D { fseek (ifp, save1+(0x231<<1), SEEK_SET); imgdata.makernotes.canon.SpecularWhiteLevel = get2(); FORC4 imgdata.color.linear_max[c] = imgdata.makernotes.canon.SpecularWhiteLevel; } else { fseek (ifp, save1+(0x30f<<1), SEEK_SET); // offset 783 shorts imgdata.makernotes.canon.SpecularWhiteLevel = get2(); FORC4 imgdata.color.linear_max[c] = imgdata.makernotes.canon.SpecularWhiteLevel; } break; } fseek (ifp, save1, SEEK_SET); } } void CLASS setPentaxBodyFeatures (unsigned id) { imgdata.lens.makernotes.CamID = id; switch (id) { case 0x12994: case 0x12aa2: case 0x12b1a: case 0x12b60: case 0x12b62: case 0x12b7e: case 0x12b80: case 0x12b9c: case 0x12b9d: case 0x12ba2: case 0x12c1e: case 0x12c20: case 0x12cd2: case 0x12cd4: case 0x12cfa: case 0x12d72: case 0x12d73: case 0x12db8: case 0x12dfe: case 0x12e6c: case 0x12e76: case 0x12ef8: case 0x12f52: case 0x12f70: case 0x12f71: case 0x12fb6: case 0x12fc0: case 0x12fca: case 0x1301a: case 0x13024: case 0x1309c: case 0x13222: imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Pentax_K; imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Pentax_K; imgdata.lens.makernotes.CameraFormat = LIBRAW_FORMAT_APSC; break; case 0x13092: imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Pentax_K; imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Pentax_K; imgdata.lens.makernotes.CameraFormat = LIBRAW_FORMAT_FF; break; case 0x12e08: case 0x13010: imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Pentax_645; imgdata.lens.makernotes.LensFormat = LIBRAW_FORMAT_MF; imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Pentax_645; imgdata.lens.makernotes.CameraFormat = LIBRAW_FORMAT_MF; break; case 0x12ee4: case 0x12f66: case 0x12f7a: case 0x1302e: imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Pentax_Q; imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Pentax_Q; break; default: imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens; imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens; } return; } void CLASS PentaxISO (ushort c) { int code [] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 50, 100, 200, 400, 800, 1600, 3200, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278}; double value [] = {50, 64, 80, 100, 125, 160, 200, 250, 320, 400, 500, 640, 800, 1000, 1250, 1600, 2000, 2500, 3200, 4000, 5000, 6400, 8000, 10000, 12800, 16000, 20000, 25600, 32000, 40000, 51200, 64000, 80000, 102400, 128000, 160000, 204800, 50, 100, 200, 400, 800, 1600, 3200, 50, 70, 100, 140, 200, 280, 400, 560, 800, 1100, 1600, 2200, 3200, 4500, 6400, 9000, 12800, 18000, 25600, 36000, 51200}; #define numel (sizeof(code)/sizeof(code[0])) int i; for (i = 0; i < numel; i++) { if (code[i] == c) { iso_speed = value[i]; return; } } if (i == numel) iso_speed = 65535.0f; } #undef numel void CLASS PentaxLensInfo (unsigned id, unsigned len) // tag 0x0207 { ushort iLensData = 0; uchar *table_buf; table_buf = (uchar*)malloc(MAX(len,128)); fread(table_buf, len, 1, ifp); if ((id < 0x12b9c) || (((id == 0x12b9c) || // K100D (id == 0x12b9d) || // K110D (id == 0x12ba2)) && // K100D Super ((!table_buf[20] || (table_buf[20] == 0xff))))) { iLensData = 3; if (imgdata.lens.makernotes.LensID == -1) imgdata.lens.makernotes.LensID = (((unsigned)table_buf[0]) << 8) + table_buf[1]; } else switch (len) { case 90: // LensInfo3 iLensData = 13; if (imgdata.lens.makernotes.LensID == -1) imgdata.lens.makernotes.LensID = ((unsigned)((table_buf[1] & 0x0f) + table_buf[3]) <<8) + table_buf[4]; break; case 91: // LensInfo4 iLensData = 12; if (imgdata.lens.makernotes.LensID == -1) imgdata.lens.makernotes.LensID = ((unsigned)((table_buf[1] & 0x0f) + table_buf[3]) <<8) + table_buf[4]; break; case 80: // LensInfo5 case 128: iLensData = 15; if (imgdata.lens.makernotes.LensID == -1) imgdata.lens.makernotes.LensID = ((unsigned)((table_buf[1] & 0x0f) + table_buf[4]) <<8) + table_buf[5]; break; default: if (id >= 0x12b9c) // LensInfo2 { iLensData = 4; if (imgdata.lens.makernotes.LensID == -1) imgdata.lens.makernotes.LensID = ((unsigned)((table_buf[0] & 0x0f) + table_buf[2]) <<8) + table_buf[3]; } } if (iLensData) { if (table_buf[iLensData+9] && (fabs(imgdata.lens.makernotes.CurFocal) < 0.1f)) imgdata.lens.makernotes.CurFocal = 10*(table_buf[iLensData+9]>>2) * libraw_powf64(4, (table_buf[iLensData+9] & 0x03)-2); if (table_buf[iLensData+10] & 0xf0) imgdata.lens.makernotes.MaxAp4CurFocal = libraw_powf64(2.0f, (float)((table_buf[iLensData+10] & 0xf0) >>4)/4.0f); if (table_buf[iLensData+10] & 0x0f) imgdata.lens.makernotes.MinAp4CurFocal = libraw_powf64(2.0f, (float)((table_buf[iLensData+10] & 0x0f) + 10)/4.0f); if (iLensData != 12) { switch (table_buf[iLensData] & 0x06) { case 0: imgdata.lens.makernotes.MinAp4MinFocal = 22.0f; break; case 2: imgdata.lens.makernotes.MinAp4MinFocal = 32.0f; break; case 4: imgdata.lens.makernotes.MinAp4MinFocal = 45.0f; break; case 6: imgdata.lens.makernotes.MinAp4MinFocal = 16.0f; break; } if (table_buf[iLensData] & 0x70) imgdata.lens.makernotes.LensFStops = ((float)(((table_buf[iLensData] & 0x70) >> 4) ^ 0x07)) / 2.0f + 5.0f; imgdata.lens.makernotes.MinFocusDistance = (float)(table_buf[iLensData+3] & 0xf8); imgdata.lens.makernotes.FocusRangeIndex = (float)(table_buf[iLensData+3] & 0x07); if ((table_buf[iLensData+14] > 1) && (fabs(imgdata.lens.makernotes.MaxAp4CurFocal) < 0.7f)) imgdata.lens.makernotes.MaxAp4CurFocal = libraw_powf64(2.0f, (float)((table_buf[iLensData+14] & 0x7f) -1)/32.0f); } else if ((id != 0x12e76) && // K-5 (table_buf[iLensData+15] > 1) && (fabs(imgdata.lens.makernotes.MaxAp4CurFocal) < 0.7f)) { imgdata.lens.makernotes.MaxAp4CurFocal = libraw_powf64(2.0f, (float)((table_buf[iLensData+15] & 0x7f) -1)/32.0f); } } free(table_buf); return; } void CLASS setPhaseOneFeatures (unsigned id) { ushort i; static const struct { ushort id; char t_model[32]; } p1_unique[] = { // Phase One section: {1, "Hasselblad V"}, {10, "PhaseOne/Mamiya"}, {12, "Contax 645"}, {16, "Hasselblad V"}, {17, "Hasselblad V"}, {18, "Contax 645"}, {19, "PhaseOne/Mamiya"}, {20, "Hasselblad V"}, {21, "Contax 645"}, {22, "PhaseOne/Mamiya"}, {23, "Hasselblad V"}, {24, "Hasselblad H"}, {25, "PhaseOne/Mamiya"}, {32, "Contax 645"}, {34, "Hasselblad V"}, {35, "Hasselblad V"}, {36, "Hasselblad H"}, {37, "Contax 645"}, {38, "PhaseOne/Mamiya"}, {39, "Hasselblad V"}, {40, "Hasselblad H"}, {41, "Contax 645"}, {42, "PhaseOne/Mamiya"}, {44, "Hasselblad V"}, {45, "Hasselblad H"}, {46, "Contax 645"}, {47, "PhaseOne/Mamiya"}, {48, "Hasselblad V"}, {49, "Hasselblad H"}, {50, "Contax 645"}, {51, "PhaseOne/Mamiya"}, {52, "Hasselblad V"}, {53, "Hasselblad H"}, {54, "Contax 645"}, {55, "PhaseOne/Mamiya"}, {67, "Hasselblad V"}, {68, "Hasselblad H"}, {69, "Contax 645"}, {70, "PhaseOne/Mamiya"}, {71, "Hasselblad V"}, {72, "Hasselblad H"}, {73, "Contax 645"}, {74, "PhaseOne/Mamiya"}, {76, "Hasselblad V"}, {77, "Hasselblad H"}, {78, "Contax 645"}, {79, "PhaseOne/Mamiya"}, {80, "Hasselblad V"}, {81, "Hasselblad H"}, {82, "Contax 645"}, {83, "PhaseOne/Mamiya"}, {84, "Hasselblad V"}, {85, "Hasselblad H"}, {86, "Contax 645"}, {87, "PhaseOne/Mamiya"}, {99, "Hasselblad V"}, {100, "Hasselblad H"}, {101, "Contax 645"}, {102, "PhaseOne/Mamiya"}, {103, "Hasselblad V"}, {104, "Hasselblad H"}, {105, "PhaseOne/Mamiya"}, {106, "Contax 645"}, {112, "Hasselblad V"}, {113, "Hasselblad H"}, {114, "Contax 645"}, {115, "PhaseOne/Mamiya"}, {131, "Hasselblad V"}, {132, "Hasselblad H"}, {133, "Contax 645"}, {134, "PhaseOne/Mamiya"}, {135, "Hasselblad V"}, {136, "Hasselblad H"}, {137, "Contax 645"}, {138, "PhaseOne/Mamiya"}, {140, "Hasselblad V"}, {141, "Hasselblad H"}, {142, "Contax 645"}, {143, "PhaseOne/Mamiya"}, {148, "Hasselblad V"}, {149, "Hasselblad H"}, {150, "Contax 645"}, {151, "PhaseOne/Mamiya"}, {160, "A-250"}, {161, "A-260"}, {162, "A-280"}, {167, "Hasselblad V"}, {168, "Hasselblad H"}, {169, "Contax 645"}, {170, "PhaseOne/Mamiya"}, {172, "Hasselblad V"}, {173, "Hasselblad H"}, {174, "Contax 645"}, {175, "PhaseOne/Mamiya"}, {176, "Hasselblad V"}, {177, "Hasselblad H"}, {178, "Contax 645"}, {179, "PhaseOne/Mamiya"}, {180, "Hasselblad V"}, {181, "Hasselblad H"}, {182, "Contax 645"}, {183, "PhaseOne/Mamiya"}, {208, "Hasselblad V"}, {211, "PhaseOne/Mamiya"}, {448, "Phase One 645AF"}, {457, "Phase One 645DF"}, {471, "Phase One 645DF+"}, {704, "Phase One iXA"}, {705, "Phase One iXA - R"}, {706, "Phase One iXU 150"}, {707, "Phase One iXU 150 - NIR"}, {708, "Phase One iXU 180"}, {721, "Phase One iXR"}, // Leaf section: {333,"Mamiya"}, {329,"Universal"}, {330,"Hasselblad H1/H2"}, {332,"Contax"}, {336,"AFi"}, {327,"Mamiya"}, {324,"Universal"}, {325,"Hasselblad H1/H2"}, {326,"Contax"}, {335,"AFi"}, {340,"Mamiya"}, {337,"Universal"}, {338,"Hasselblad H1/H2"}, {339,"Contax"}, {323,"Mamiya"}, {320,"Universal"}, {322,"Hasselblad H1/H2"}, {321,"Contax"}, {334,"AFi"}, {369,"Universal"}, {370,"Mamiya"}, {371,"Hasselblad H1/H2"}, {372,"Contax"}, {373,"Afi"}, }; imgdata.lens.makernotes.CamID = id; if (id && !imgdata.lens.makernotes.body[0]) { for (i=0; i < sizeof p1_unique / sizeof *p1_unique; i++) if (id == p1_unique[i].id) { strcpy(imgdata.lens.makernotes.body,p1_unique[i].t_model); } } return; } void CLASS parseFujiMakernotes (unsigned tag, unsigned type) { switch (tag) { case 0x1002: imgdata.makernotes.fuji.WB_Preset = get2(); break; case 0x1011: imgdata.other.FlashEC = getreal(type); break; case 0x1020: imgdata.makernotes.fuji.Macro = get2(); break; case 0x1021: imgdata.makernotes.fuji.FocusMode = get2(); break; case 0x1022: imgdata.makernotes.fuji.AFMode = get2(); break; case 0x1023: imgdata.makernotes.fuji.FocusPixel[0] = get2(); imgdata.makernotes.fuji.FocusPixel[1] = get2(); break; case 0x1034: imgdata.makernotes.fuji.ExrMode = get2(); break; case 0x1050: imgdata.makernotes.fuji.ShutterType = get2(); break; case 0x1400: imgdata.makernotes.fuji.FujiDynamicRange = get2(); break; case 0x1401: imgdata.makernotes.fuji.FujiFilmMode = get2(); break; case 0x1402: imgdata.makernotes.fuji.FujiDynamicRangeSetting = get2(); break; case 0x1403: imgdata.makernotes.fuji.FujiDevelopmentDynamicRange = get2(); break; case 0x140b: imgdata.makernotes.fuji.FujiAutoDynamicRange = get2(); break; case 0x1404: imgdata.lens.makernotes.MinFocal = getreal(type); break; case 0x1405: imgdata.lens.makernotes.MaxFocal = getreal(type); break; case 0x1406: imgdata.lens.makernotes.MaxAp4MinFocal = getreal(type); break; case 0x1407: imgdata.lens.makernotes.MaxAp4MaxFocal = getreal(type); break; case 0x1422: imgdata.makernotes.fuji.ImageStabilization[0] = get2(); imgdata.makernotes.fuji.ImageStabilization[1] = get2(); imgdata.makernotes.fuji.ImageStabilization[2] = get2(); imgdata.shootinginfo.ImageStabilization = (imgdata.makernotes.fuji.ImageStabilization[0]<<9) + imgdata.makernotes.fuji.ImageStabilization[1]; break; case 0x1431: imgdata.makernotes.fuji.Rating = get4(); break; case 0x3820: imgdata.makernotes.fuji.FrameRate = get2(); break; case 0x3821: imgdata.makernotes.fuji.FrameWidth = get2(); break; case 0x3822: imgdata.makernotes.fuji.FrameHeight = get2(); break; } return; } void CLASS setSonyBodyFeatures (unsigned id) { imgdata.lens.makernotes.CamID = id; if ( // FF cameras (id == 257) || // a900 (id == 269) || // a850 (id == 340) || // ILCE-7M2 (id == 318) || // ILCE-7S (id == 350) || // ILCE-7SM2 (id == 311) || // ILCE-7R (id == 347) || // ILCE-7RM2 (id == 306) || // ILCE-7 (id == 298) || // DSC-RX1 (id == 299) || // NEX-VG900 (id == 310) || // DSC-RX1R (id == 344) || // DSC-RX1RM2 (id == 354) || // ILCA-99M2 (id == 294) // SLT-99, Hasselblad HV ) { imgdata.lens.makernotes.CameraFormat = LIBRAW_FORMAT_FF; } else if ((id == 297) || // DSC-RX100 (id == 308) || // DSC-RX100M2 (id == 309) || // DSC-RX10 (id == 317) || // DSC-RX100M3 (id == 341) || // DSC-RX100M4 (id == 342) || // DSC-RX10M2 (id == 355) || // DSC-RX10M3 (id == 356) // DSC-RX100M5 ) { imgdata.lens.makernotes.CameraFormat = LIBRAW_FORMAT_1INCH; } else if (id != 002) // DSC-R1 { imgdata.lens.makernotes.CameraFormat = LIBRAW_FORMAT_APSC; } if ( // E-mount cameras, ILCE series (id == 302) || (id == 306) || (id == 311) || (id == 312) || (id == 313) || (id == 318) || (id == 339) || (id == 340) || (id == 346) || (id == 347) || (id == 350) || (id == 360) ) { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Sony_E; imgdata.makernotes.sony.SonyCameraType = LIBRAW_SONY_ILCE; } else if ( // E-mount cameras, NEX series (id == 278) || (id == 279) || (id == 284) || (id == 288) || (id == 289) || (id == 290) || (id == 293) || (id == 295) || (id == 296) || (id == 299) || (id == 300) || (id == 305) || (id == 307) ) { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Sony_E; imgdata.makernotes.sony.SonyCameraType = LIBRAW_SONY_NEX; } else if ( // A-mount cameras, DSLR series (id == 256) || (id == 257) || (id == 258) || (id == 259) || (id == 260) || (id == 261) || (id == 262) || (id == 263) || (id == 264) || (id == 265) || (id == 266) || (id == 269) || (id == 270) || (id == 273) || (id == 274) || (id == 275) || (id == 282) || (id == 283) ) { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Minolta_A; imgdata.makernotes.sony.SonyCameraType = LIBRAW_SONY_DSLR; } else if ( // A-mount cameras, SLT series (id == 280) || (id == 281) || (id == 285) || (id == 286) || (id == 287) || (id == 291) || (id == 292) || (id == 294) || (id == 303) ) { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Minolta_A; imgdata.makernotes.sony.SonyCameraType = LIBRAW_SONY_SLT; } else if ( // A-mount cameras, ILCA series (id == 319) || (id == 353) || (id == 354) ) { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Minolta_A; imgdata.makernotes.sony.SonyCameraType = LIBRAW_SONY_ILCA; } else if ( // DSC (id == 002) || // DSC-R1 (id == 297) || // DSC-RX100 (id == 298) || // DSC-RX1 (id == 308) || // DSC-RX100M2 (id == 309) || // DSC-RX10 (id == 310) || // DSC-RX1R (id == 344) || // DSC-RX1RM2 (id == 317) || // DSC-RX100M3 (id == 341) || // DSC-RX100M4 (id == 342) || // DSC-RX10M2 (id == 355) || // DSC-RX10M3 (id == 356) // DSC-RX100M5 ) { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens; imgdata.makernotes.sony.SonyCameraType = LIBRAW_SONY_DSC; } return; } void CLASS parseSonyLensType2 (uchar a, uchar b) { ushort lid2; lid2 = (((ushort)a)<<8) | ((ushort)b); if (!lid2) return; if (lid2 < 0x100) { if ((imgdata.lens.makernotes.AdapterID != 0x4900) && (imgdata.lens.makernotes.AdapterID != 0xEF00)) { imgdata.lens.makernotes.AdapterID = lid2; switch (lid2) { case 1: case 2: case 3: case 6: imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Minolta_A; break; case 44: case 78: case 239: imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Canon_EF; break; } } } else imgdata.lens.makernotes.LensID = lid2; if ((lid2 >= 50481) && (lid2 < 50500)) { strcpy(imgdata.lens.makernotes.Adapter, "MC-11"); imgdata.lens.makernotes.AdapterID = 0x4900; } return; } #define strnXcat(buf,string) strncat(buf,string,LIM(sizeof(buf)-strbuflen(buf)-1,0,sizeof(buf))) void CLASS parseSonyLensFeatures (uchar a, uchar b) { ushort features; features = (((ushort)a)<<8) | ((ushort)b); if ((imgdata.lens.makernotes.LensMount == LIBRAW_MOUNT_Canon_EF) || (imgdata.lens.makernotes.LensMount != LIBRAW_MOUNT_Sigma_X3F) || !features) return; imgdata.lens.makernotes.LensFeatures_pre[0] = 0; imgdata.lens.makernotes.LensFeatures_suf[0] = 0; if ((features & 0x0200) && (features & 0x0100)) strcpy(imgdata.lens.makernotes.LensFeatures_pre, "E"); else if (features & 0x0200) strcpy(imgdata.lens.makernotes.LensFeatures_pre, "FE"); else if (features & 0x0100) strcpy(imgdata.lens.makernotes.LensFeatures_pre, "DT"); if (!imgdata.lens.makernotes.LensFormat && !imgdata.lens.makernotes.LensMount) { imgdata.lens.makernotes.LensFormat = LIBRAW_FORMAT_FF; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Minolta_A; if ((features & 0x0200) && (features & 0x0100)) { imgdata.lens.makernotes.LensFormat = LIBRAW_FORMAT_APSC; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Sony_E; } else if (features & 0x0200) { imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Sony_E; } else if (features & 0x0100) { imgdata.lens.makernotes.LensFormat = LIBRAW_FORMAT_APSC; } } if (features & 0x4000) strnXcat(imgdata.lens.makernotes.LensFeatures_pre, " PZ"); if (features & 0x0008) strnXcat(imgdata.lens.makernotes.LensFeatures_suf, " G"); else if (features & 0x0004) strnXcat(imgdata.lens.makernotes.LensFeatures_suf, " ZA" ); if ((features & 0x0020) && (features & 0x0040)) strnXcat(imgdata.lens.makernotes.LensFeatures_suf, " Macro"); else if (features & 0x0020) strnXcat(imgdata.lens.makernotes.LensFeatures_suf, " STF"); else if (features & 0x0040) strnXcat(imgdata.lens.makernotes.LensFeatures_suf, " Reflex"); else if (features & 0x0080) strnXcat(imgdata.lens.makernotes.LensFeatures_suf, " Fisheye"); if (features & 0x0001) strnXcat(imgdata.lens.makernotes.LensFeatures_suf, " SSM"); else if (features & 0x0002) strnXcat(imgdata.lens.makernotes.LensFeatures_suf, " SAM"); if (features & 0x8000) strnXcat(imgdata.lens.makernotes.LensFeatures_suf, " OSS"); if (features & 0x2000) strnXcat(imgdata.lens.makernotes.LensFeatures_suf, " LE"); if (features & 0x0800) strnXcat(imgdata.lens.makernotes.LensFeatures_suf, " II"); if (imgdata.lens.makernotes.LensFeatures_suf[0] == ' ') memmove(imgdata.lens.makernotes.LensFeatures_suf, imgdata.lens.makernotes.LensFeatures_suf+1, strbuflen(imgdata.lens.makernotes.LensFeatures_suf)-1); return; } #undef strnXcat void CLASS process_Sony_0x940c (uchar * buf) { ushort lid2; if ((imgdata.lens.makernotes.LensMount != LIBRAW_MOUNT_Canon_EF) && (imgdata.lens.makernotes.LensMount != LIBRAW_MOUNT_Sigma_X3F)) { switch (SonySubstitution[buf[0x0008]]) { case 1: case 5: imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Minolta_A; break; case 4: imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Sony_E; break; } } lid2 = (((ushort)SonySubstitution[buf[0x000a]])<<8) | ((ushort)SonySubstitution[buf[0x0009]]); if ((lid2 > 0) && (lid2 < 32784)) parseSonyLensType2 (SonySubstitution[buf[0x000a]], // LensType2 - Sony lens ids SonySubstitution[buf[0x0009]]); return; } void CLASS process_Sony_0x9050 (uchar * buf, unsigned id) { ushort lid; if ((imgdata.lens.makernotes.CameraMount != LIBRAW_MOUNT_Sony_E) && (imgdata.lens.makernotes.CameraMount != LIBRAW_MOUNT_FixedLens)) { if (buf[0]) imgdata.lens.makernotes.MaxAp4CurFocal = my_roundf(libraw_powf64(2.0f, ((float)SonySubstitution[buf[0]] / 8.0 - 1.06f) / 2.0f)*10.0f) / 10.0f; if (buf[1]) imgdata.lens.makernotes.MinAp4CurFocal = my_roundf(libraw_powf64(2.0f, ((float)SonySubstitution[buf[1]] / 8.0 - 1.06f) / 2.0f)*10.0f) / 10.0f; } if (imgdata.lens.makernotes.CameraMount != LIBRAW_MOUNT_FixedLens) { if (buf[0x3d] | buf[0x3c]) { lid = SonySubstitution[buf[0x3d]] << 8 | SonySubstitution[buf[0x3c]]; imgdata.lens.makernotes.CurAp = libraw_powf64(2.0f, ((float)lid/256.0f - 16.0f) / 2.0f); } if (buf[0x105] && (imgdata.lens.makernotes.LensMount != LIBRAW_MOUNT_Canon_EF) && (imgdata.lens.makernotes.LensMount != LIBRAW_MOUNT_Sigma_X3F)) imgdata.lens.makernotes.LensMount = SonySubstitution[buf[0x105]]; if (buf[0x106]) imgdata.lens.makernotes.LensFormat = SonySubstitution[buf[0x106]]; } if (imgdata.lens.makernotes.CameraMount == LIBRAW_MOUNT_Sony_E) { parseSonyLensType2 (SonySubstitution[buf[0x0108]], // LensType2 - Sony lens ids SonySubstitution[buf[0x0107]]); } if ((imgdata.lens.makernotes.LensID == -1) && (imgdata.lens.makernotes.CameraMount == LIBRAW_MOUNT_Minolta_A) && (buf[0x010a] | buf[0x0109])) { imgdata.lens.makernotes.LensID = // LensType - Minolta/Sony lens ids SonySubstitution[buf[0x010a]] << 8 | SonySubstitution[buf[0x0109]]; if ((imgdata.lens.makernotes.LensID > 0x4900) && (imgdata.lens.makernotes.LensID <= 0x5900)) { imgdata.lens.makernotes.AdapterID = 0x4900; imgdata.lens.makernotes.LensID -= imgdata.lens.makernotes.AdapterID; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Sigma_X3F; strcpy(imgdata.lens.makernotes.Adapter, "MC-11"); } else if ((imgdata.lens.makernotes.LensID > 0xEF00) && (imgdata.lens.makernotes.LensID < 0xFFFF) && (imgdata.lens.makernotes.LensID != 0xFF00)) { imgdata.lens.makernotes.AdapterID = 0xEF00; imgdata.lens.makernotes.LensID -= imgdata.lens.makernotes.AdapterID; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Canon_EF; } } if ((id >= 286) && (id <= 293)) // "SLT-A65", "SLT-A77", "NEX-7", "NEX-VG20E", // "SLT-A37", "SLT-A57", "NEX-F3", "Lunar" parseSonyLensFeatures (SonySubstitution[buf[0x115]], SonySubstitution[buf[0x116]]); else if (imgdata.lens.makernotes.CameraMount != LIBRAW_MOUNT_FixedLens) parseSonyLensFeatures(SonySubstitution[buf[0x116]], SonySubstitution[buf[0x117]]); if ((id == 347) || (id == 350) || (id == 357)) { unsigned long long b88 = SonySubstitution[buf[0x88]]; unsigned long long b89 = SonySubstitution[buf[0x89]]; unsigned long long b8a = SonySubstitution[buf[0x8a]]; unsigned long long b8b = SonySubstitution[buf[0x8b]]; unsigned long long b8c = SonySubstitution[buf[0x8c]]; unsigned long long b8d = SonySubstitution[buf[0x8d]]; sprintf(imgdata.shootinginfo.InternalBodySerial, "%06llx", (b88 << 40) + (b89 << 32) + (b8a << 24) + (b8b << 16) + (b8c << 8) + b8d); } else if ((imgdata.lens.makernotes.CameraMount == LIBRAW_MOUNT_Minolta_A) && (id > 279) && (id != 282) && (id != 283)) { unsigned long long bf0 = SonySubstitution[buf[0xf0]]; unsigned long long bf1 = SonySubstitution[buf[0xf1]]; unsigned long long bf2 = SonySubstitution[buf[0xf2]]; unsigned long long bf3 = SonySubstitution[buf[0xf3]]; unsigned long long bf4 = SonySubstitution[buf[0xf4]]; sprintf(imgdata.shootinginfo.InternalBodySerial, "%05llx", (bf0 << 32) + (bf1 << 24) + (bf2 << 16) + (bf3 << 8) + bf4); } else if ((imgdata.lens.makernotes.CameraMount == LIBRAW_MOUNT_Sony_E) && (id != 288) && (id != 289) && (id != 290)) { unsigned b7c = SonySubstitution[buf[0x7c]]; unsigned b7d = SonySubstitution[buf[0x7d]]; unsigned b7e = SonySubstitution[buf[0x7e]]; unsigned b7f = SonySubstitution[buf[0x7f]]; sprintf(imgdata.shootinginfo.InternalBodySerial, "%04x", (b7c << 24) + (b7d << 16) + (b7e << 8) + b7f); } return; } void CLASS parse_makernote_0xc634(int base, int uptag, unsigned dng_writer) { unsigned ver97 = 0, offset = 0, entries, tag, type, len, save, c; unsigned i; uchar NikonKey, ci, cj, ck; unsigned serial = 0; unsigned custom_serial = 0; unsigned NikonLensDataVersion = 0; unsigned lenNikonLensData = 0; unsigned NikonFlashInfoVersion = 0; uchar *CanonCameraInfo; unsigned lenCanonCameraInfo = 0; uchar *table_buf; uchar *table_buf_0x9050; ushort table_buf_0x9050_present = 0; uchar *table_buf_0x940c; ushort table_buf_0x940c_present = 0; short morder, sorder = order; char buf[10]; INT64 fsize = ifp->size(); fread(buf, 1, 10, ifp); if (!strcmp(buf, "Nikon")) { base = ftell(ifp); order = get2(); if (get2() != 42) goto quit; offset = get4(); fseek(ifp, offset - 8, SEEK_CUR); } else if (!strcmp(buf, "OLYMPUS") || !strcmp(buf, "PENTAX ") || (!strncmp(make, "SAMSUNG", 7) && (dng_writer == CameraDNG))) { base = ftell(ifp) - 10; fseek(ifp, -2, SEEK_CUR); order = get2(); if (buf[0] == 'O') get2(); } else if (!strncmp(buf, "SONY", 4) || !strcmp(buf, "Panasonic")) { goto nf; } else if (!strncmp(buf, "FUJIFILM", 8)) { base = ftell(ifp) - 10; nf: order = 0x4949; fseek(ifp, 2, SEEK_CUR); } else if (!strcmp(buf, "OLYMP") || !strcmp(buf, "LEICA") || !strcmp(buf, "Ricoh") || !strcmp(buf, "EPSON")) fseek(ifp, -2, SEEK_CUR); else if (!strcmp(buf, "AOC") || !strcmp(buf, "QVC")) fseek(ifp, -4, SEEK_CUR); else { fseek(ifp, -10, SEEK_CUR); if ((!strncmp(make, "SAMSUNG", 7) && (dng_writer == AdobeDNG))) base = ftell(ifp); } entries = get2(); if (entries > 1000) return; morder = order; while (entries--) { order = morder; tiff_get(base, &tag, &type, &len, &save); INT64 pos = ifp->tell(); if(len > 8 && pos+len > 2* fsize) continue; tag |= uptag << 16; if(len > 100*1024*1024) goto next; // 100Mb tag? No! if (!strncmp(make, "Canon",5)) { if (tag == 0x000d && len < 256000) // camera info { CanonCameraInfo = (uchar*)malloc(MAX(16,len)); fread(CanonCameraInfo, len, 1, ifp); lenCanonCameraInfo = len; } else if (tag == 0x10) // Canon ModelID { unique_id = get4(); if (unique_id == 0x03740000) unique_id = 0x80000374; // M3 if (unique_id == 0x03840000) unique_id = 0x80000384; // M10 if (unique_id == 0x03940000) unique_id = 0x80000394; // M5 setCanonBodyFeatures(unique_id); if (lenCanonCameraInfo) { processCanonCameraInfo(unique_id, CanonCameraInfo,lenCanonCameraInfo); free(CanonCameraInfo); CanonCameraInfo = 0; lenCanonCameraInfo = 0; } } else parseCanonMakernotes (tag, type, len); } else if (!strncmp(make, "FUJI", 4)) parseFujiMakernotes (tag, type); else if (!strncasecmp(make, "LEICA", 5)) { if (((tag == 0x035e) || (tag == 0x035f)) && (type == 10) && (len == 9)) { int ind = tag == 0x035e?0:1; for (int j=0; j < 3; j++) FORCC imgdata.color.dng_color[ind].forwardmatrix[j][c]= getreal(type); } if ((tag == 0x0303) && (type != 4)) { stmread(imgdata.lens.makernotes.Lens, len,ifp); } if ((tag == 0x3405) || (tag == 0x0310) || (tag == 0x34003405)) { imgdata.lens.makernotes.LensID = get4(); imgdata.lens.makernotes.LensID = ((imgdata.lens.makernotes.LensID>>2)<<8) | (imgdata.lens.makernotes.LensID & 0x3); if (imgdata.lens.makernotes.LensID != -1) { if ((model[0] == 'M') || !strncasecmp (model, "LEICA M", 7)) { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Leica_M; if (imgdata.lens.makernotes.LensID) imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Leica_M; } else if ((model[0] == 'S') || !strncasecmp (model, "LEICA S", 7)) { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Leica_S; if (imgdata.lens.makernotes.Lens[0]) imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Leica_S; } } } else if ( ((tag == 0x0313) || (tag == 0x34003406)) && (fabs(imgdata.lens.makernotes.CurAp) < 0.17f) && ((type == 10) || (type == 5)) ) { imgdata.lens.makernotes.CurAp = getreal(type); if (imgdata.lens.makernotes.CurAp > 126.3) imgdata.lens.makernotes.CurAp = 0.0f; } else if (tag == 0x3400) { parse_makernote (base, 0x3400); } } else if (!strncmp(make, "NIKON", 5)) { if (tag == 0x1d) // serial number while ((c = fgetc(ifp)) && c != EOF) { if ((!custom_serial) && (!isdigit(c))) { if ((strbuflen(model) == 3) && (!strcmp(model,"D50"))) { custom_serial = 34; } else { custom_serial = 96; } } serial = serial*10 + (isdigit(c) ? c - '0' : c % 10); } else if (tag == 0x000a) { imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens; imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens; } else if (tag == 0x0082) // lens attachment { stmread(imgdata.lens.makernotes.Attachment, len, ifp); } else if (tag == 0x0083) // lens type { imgdata.lens.nikon.NikonLensType = fgetc(ifp); } else if (tag == 0x0084) // lens { imgdata.lens.makernotes.MinFocal = getreal(type); imgdata.lens.makernotes.MaxFocal = getreal(type); imgdata.lens.makernotes.MaxAp4MinFocal = getreal(type); imgdata.lens.makernotes.MaxAp4MaxFocal = getreal(type); } else if (tag == 0x008b) // lens f-stops { uchar a, b, c; a = fgetc(ifp); b = fgetc(ifp); c = fgetc(ifp); if (c) { imgdata.lens.nikon.NikonLensFStops = a*b*(12/c); imgdata.lens.makernotes.LensFStops = (float)imgdata.lens.nikon.NikonLensFStops /12.0f; } } else if (tag == 0x0093) { i = get2(); if ((i == 7) || (i == 9)) { imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens; imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens; } } else if (tag == 0x0097) { for (i=0; i < 4; i++) ver97 = ver97 * 10 + fgetc(ifp)-'0'; if (ver97 == 601) // Coolpix A { imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens; imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens; } } else if (tag == 0x0098) // contains lens data { for (i = 0; i < 4; i++) { NikonLensDataVersion = NikonLensDataVersion * 10 + fgetc(ifp) - '0'; } switch (NikonLensDataVersion) { case 100: lenNikonLensData = 9; break; case 101: case 201: // encrypted, starting from v.201 case 202: case 203: lenNikonLensData = 15; break; case 204: lenNikonLensData = 16; break; case 400: lenNikonLensData = 459; break; case 401: lenNikonLensData = 590; break; case 402: lenNikonLensData = 509; break; case 403: lenNikonLensData = 879; break; } if(lenNikonLensData) { table_buf = (uchar*)malloc(lenNikonLensData); fread(table_buf, lenNikonLensData, 1, ifp); if ((NikonLensDataVersion < 201) && lenNikonLensData) { processNikonLensData(table_buf, lenNikonLensData); free(table_buf); lenNikonLensData = 0; } } } else if (tag == 0xa7) // shutter count { NikonKey = fgetc(ifp) ^ fgetc(ifp) ^ fgetc(ifp) ^ fgetc(ifp); if ((NikonLensDataVersion > 200) && lenNikonLensData) { if (custom_serial) { ci = xlat[0][custom_serial]; } else { ci = xlat[0][serial & 0xff]; } cj = xlat[1][NikonKey]; ck = 0x60; for (i = 0; i < lenNikonLensData; i++) table_buf[i] ^= (cj += ci * ck++); processNikonLensData(table_buf, lenNikonLensData); lenNikonLensData = 0; free(table_buf); } } else if (tag == 0x00a8) // contains flash data { for (i = 0; i < 4; i++) { NikonFlashInfoVersion = NikonFlashInfoVersion * 10 + fgetc(ifp) - '0'; } } else if (tag == 37 && (!iso_speed || iso_speed == 65535)) { unsigned char cc; fread(&cc, 1, 1, ifp); iso_speed = (int)(100.0 * libraw_powf64(2.0, (double)(cc) / 12.0 - 5.0)); break; } } else if (!strncmp(make, "OLYMPUS", 7)) { int SubDirOffsetValid = strncmp (model, "E-300", 5) && strncmp (model, "E-330", 5) && strncmp (model, "E-400", 5) && strncmp (model, "E-500", 5) && strncmp (model, "E-1", 3); if ((tag == 0x2010) || (tag == 0x2020)) { fseek(ifp, save - 4, SEEK_SET); fseek(ifp, base + get4(), SEEK_SET); parse_makernote_0xc634(base, tag, dng_writer); } if (!SubDirOffsetValid && ((len > 4) || ( ((type == 3) || (type == 8)) && (len > 2)) || ( ((type == 4) || (type == 9)) && (len > 1)) || (type == 5) || (type > 9))) goto skip_Oly_broken_tags; switch (tag) { case 0x0207: case 0x20100100: { uchar sOlyID[8]; unsigned long long OlyID; fread (sOlyID, MIN(len,7), 1, ifp); sOlyID[7] = 0; OlyID = sOlyID[0]; i = 1; while (i < 7 && sOlyID[i]) { OlyID = OlyID << 8 | sOlyID[i]; i++; } setOlympusBodyFeatures(OlyID); } break; case 0x1002: imgdata.lens.makernotes.CurAp = libraw_powf64(2.0f, getreal(type)/2); break; case 0x20100102: stmread(imgdata.shootinginfo.InternalBodySerial, len, ifp); break; case 0x20100201: imgdata.lens.makernotes.LensID = (unsigned long long)fgetc(ifp)<<16 | (unsigned long long)(fgetc(ifp), fgetc(ifp))<<8 | (unsigned long long)fgetc(ifp); imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FT; imgdata.lens.makernotes.LensFormat = LIBRAW_FORMAT_FT; if (((imgdata.lens.makernotes.LensID < 0x20000) || (imgdata.lens.makernotes.LensID > 0x4ffff)) && (imgdata.lens.makernotes.LensID & 0x10)) { imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_mFT; } break; case 0x20100202: if ((!imgdata.lens.LensSerial[0])) stmread(imgdata.lens.LensSerial, len, ifp); break; case 0x20100203: stmread(imgdata.lens.makernotes.Lens,len, ifp); break; case 0x20100205: imgdata.lens.makernotes.MaxAp4MinFocal = libraw_powf64(sqrt(2.0f), get2() / 256.0f); break; case 0x20100206: imgdata.lens.makernotes.MaxAp4MaxFocal = libraw_powf64(sqrt(2.0f), get2() / 256.0f); break; case 0x20100207: imgdata.lens.makernotes.MinFocal = (float)get2(); break; case 0x20100208: imgdata.lens.makernotes.MaxFocal = (float)get2(); if (imgdata.lens.makernotes.MaxFocal > 1000.0f) imgdata.lens.makernotes.MaxFocal = imgdata.lens.makernotes.MinFocal; break; case 0x2010020a: imgdata.lens.makernotes.MaxAp4CurFocal = libraw_powf64(sqrt(2.0f), get2() / 256.0f); break; case 0x20100301: imgdata.lens.makernotes.TeleconverterID = fgetc(ifp) << 8; fgetc(ifp); imgdata.lens.makernotes.TeleconverterID = imgdata.lens.makernotes.TeleconverterID | fgetc(ifp); break; case 0x20100303: stmread(imgdata.lens.makernotes.Teleconverter, len, ifp); break; case 0x20100403: stmread(imgdata.lens.makernotes.Attachment,len, ifp); break; case 0x20200401: imgdata.other.FlashEC = getreal(type); break; } skip_Oly_broken_tags:; } else if (!strncmp(make, "PENTAX", 6) || !strncmp(model, "PENTAX", 6) || (!strncmp(make, "SAMSUNG", 7) && (dng_writer == CameraDNG))) { if (tag == 0x0005) { unique_id = get4(); setPentaxBodyFeatures(unique_id); } else if (tag == 0x0013) { imgdata.lens.makernotes.CurAp = (float)get2()/10.0f; } else if (tag == 0x0014) { PentaxISO(get2()); } else if (tag == 0x001d) { imgdata.lens.makernotes.CurFocal = (float)get4()/100.0f; } else if (tag == 0x003f) { imgdata.lens.makernotes.LensID = fgetc(ifp) << 8 | fgetc(ifp); } else if (tag == 0x004d) { if (type == 9) imgdata.other.FlashEC = getreal(type) / 256.0f; else imgdata.other.FlashEC = (float) ((signed short) fgetc(ifp)) / 6.0f; } else if (tag == 0x007e) { imgdata.color.linear_max[0] = imgdata.color.linear_max[1] = imgdata.color.linear_max[2] = imgdata.color.linear_max[3] = (long)(-1) * get4(); } else if (tag == 0x0207) { if(len < 65535) // Safety belt PentaxLensInfo(imgdata.lens.makernotes.CamID, len); } else if (tag == 0x020d) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][c ^ (c >> 1)] = get2(); } else if (tag == 0x020e) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][c ^ (c >> 1)] = get2(); } else if (tag == 0x020f) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][c ^ (c >> 1)] = get2(); } else if (tag == 0x0210) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][c ^ (c >> 1)] = get2(); } else if (tag == 0x0211) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][c ^ (c >> 1)] = get2(); } else if (tag == 0x0212) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][c ^ (c >> 1)] = get2(); } else if (tag == 0x0213) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][c ^ (c >> 1)] = get2(); } else if (tag == 0x0214) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][c ^ (c >> 1)] = get2(); } else if (tag == 0x0221) { int nWB = get2(); if(nWB<=sizeof(imgdata.color.WBCT_Coeffs)/sizeof(imgdata.color.WBCT_Coeffs[0])) for (int i = 0; i < nWB; i++) { imgdata.color.WBCT_Coeffs[i][0] = (unsigned)0xcfc6 - get2(); fseek(ifp, 2, SEEK_CUR); imgdata.color.WBCT_Coeffs[i][1] = get2(); imgdata.color.WBCT_Coeffs[i][2] = imgdata.color.WBCT_Coeffs[i][4] = 0x2000; imgdata.color.WBCT_Coeffs[i][3] = get2(); } } else if (tag == 0x0215) { fseek (ifp, 16, SEEK_CUR); sprintf(imgdata.shootinginfo.InternalBodySerial, "%d", get4()); } else if (tag == 0x0229) { stmread(imgdata.shootinginfo.BodySerial, len, ifp); } else if (tag == 0x022d) { fseek (ifp,2,SEEK_CUR); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][c ^ (c >> 1)] = get2(); getc(ifp); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][c ^ (c >> 1)] = get2(); getc(ifp); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][c ^ (c >> 1)] = get2(); getc(ifp); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][c ^ (c >> 1)] = get2(); getc(ifp); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][c ^ (c >> 1)] = get2(); getc(ifp); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][c ^ (c >> 1)] = get2(); getc(ifp); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][c ^ (c >> 1)] = get2(); getc(ifp); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][c ^ (c >> 1)] = get2(); getc(ifp); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_L][c ^ (c >> 1)] = get2(); } else if (tag == 0x0239) // Q-series lens info (LensInfoQ) { char LensInfo [20]; fseek (ifp, 12, SEEK_CUR); stread(imgdata.lens.makernotes.Lens, 30, ifp); strcat(imgdata.lens.makernotes.Lens, " "); stread(LensInfo, 20, ifp); strcat(imgdata.lens.makernotes.Lens, LensInfo); } } else if (!strncmp(make, "SAMSUNG", 7) && (dng_writer == AdobeDNG)) { if (tag == 0x0002) { if(get4() == 0x2000) { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Samsung_NX; } else if (!strncmp(model, "NX mini", 7)) { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Samsung_NX_M; } else { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens; } } else if (tag == 0x0003) { imgdata.lens.makernotes.CamID = unique_id = get4(); } else if (tag == 0xa003) { imgdata.lens.makernotes.LensID = get2(); if (imgdata.lens.makernotes.LensID) imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Samsung_NX; } else if (tag == 0xa005) { stmread(imgdata.lens.InternalLensSerial, len, ifp); } else if (tag == 0xa019) { imgdata.lens.makernotes.CurAp = getreal(type); } else if (tag == 0xa01a) { imgdata.lens.makernotes.FocalLengthIn35mmFormat = get4() / 10.0f; if (imgdata.lens.makernotes.FocalLengthIn35mmFormat < 10.0f) imgdata.lens.makernotes.FocalLengthIn35mmFormat *= 10.0f; } } else if (!strncasecmp(make, "SONY", 4) || !strncasecmp(make, "Konica", 6) || !strncasecmp(make, "Minolta", 7) || (!strncasecmp(make, "Hasselblad", 10) && (!strncasecmp(model, "Stellar", 7) || !strncasecmp(model, "Lunar", 5) || !strncasecmp(model, "Lusso", 5) || !strncasecmp(model, "HV",2)))) { ushort lid; if (tag == 0xb001) // Sony ModelID { unique_id = get2(); setSonyBodyFeatures(unique_id); if (table_buf_0x9050_present) { process_Sony_0x9050(table_buf_0x9050, unique_id); free (table_buf_0x9050); table_buf_0x9050_present = 0; } if (table_buf_0x940c_present) { if (imgdata.lens.makernotes.CameraMount == LIBRAW_MOUNT_Sony_E) { process_Sony_0x940c(table_buf_0x940c); } free (table_buf_0x940c); table_buf_0x940c_present = 0; } } else if ((tag == 0x0010) && // CameraInfo strncasecmp(model, "DSLR-A100", 9) && strncasecmp(model, "NEX-5C", 6) && !strncasecmp(make, "SONY", 4) && ((len == 368) || // a700 (len == 5478) || // a850, a900 (len == 5506) || // a200, a300, a350 (len == 6118) || // a230, a290, a330, a380, a390 // a450, a500, a550, a560, a580 // a33, a35, a55 // NEX3, NEX5, NEX5C, NEXC3, VG10E (len == 15360)) ) { table_buf = (uchar*)malloc(len); fread(table_buf, len, 1, ifp); if (memcmp(table_buf, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) && memcmp(table_buf, "\x00\x00\x00\x00\x00\x00\x00\x00", 8)) { switch (len) { case 368: case 5478: // a700, a850, a900: CameraInfo if (saneSonyCameraInfo(table_buf[0], table_buf[3], table_buf[2], table_buf[5], table_buf[4], table_buf[7])) { if (table_buf[0] | table_buf[3]) imgdata.lens.makernotes.MinFocal = bcd2dec(table_buf[0]) * 100 + bcd2dec(table_buf[3]); if (table_buf[2] | table_buf[5]) imgdata.lens.makernotes.MaxFocal = bcd2dec(table_buf[2]) * 100 + bcd2dec(table_buf[5]); if (table_buf[4]) imgdata.lens.makernotes.MaxAp4MinFocal = bcd2dec(table_buf[4]) / 10.0f; if (table_buf[4]) imgdata.lens.makernotes.MaxAp4MaxFocal = bcd2dec(table_buf[7]) / 10.0f; parseSonyLensFeatures(table_buf[1], table_buf[6]); } break; default: // CameraInfo2 & 3 if (saneSonyCameraInfo(table_buf[1], table_buf[2], table_buf[3], table_buf[4], table_buf[5], table_buf[6])) { if (table_buf[1] | table_buf[2]) imgdata.lens.makernotes.MinFocal = bcd2dec(table_buf[1]) * 100 + bcd2dec(table_buf[2]); if (table_buf[3] | table_buf[4]) imgdata.lens.makernotes.MaxFocal = bcd2dec(table_buf[3]) * 100 + bcd2dec(table_buf[4]); if (table_buf[5]) imgdata.lens.makernotes.MaxAp4MinFocal = bcd2dec(table_buf[5]) / 10.0f; if (table_buf[6]) imgdata.lens.makernotes.MaxAp4MaxFocal = bcd2dec(table_buf[6]) / 10.0f; parseSonyLensFeatures(table_buf[0], table_buf[7]); } } } free(table_buf); } else if (tag == 0x0104) { imgdata.other.FlashEC = getreal(type); } else if (tag == 0x0105) // Teleconverter { imgdata.lens.makernotes.TeleconverterID = get2(); } else if (tag == 0x0114 && len < 65535) // CameraSettings { table_buf = (uchar*)malloc(len); fread(table_buf, len, 1, ifp); switch (len) { case 280: case 364: case 332: // CameraSettings and CameraSettings2 are big endian if (table_buf[2] | table_buf[3]) { lid = (((ushort)table_buf[2])<<8) | ((ushort)table_buf[3]); imgdata.lens.makernotes.CurAp = libraw_powf64(2.0f, ((float)lid/8.0f-1.0f)/2.0f); } break; case 1536: case 2048: // CameraSettings3 are little endian parseSonyLensType2(table_buf[1016], table_buf[1015]); if (imgdata.lens.makernotes.LensMount != LIBRAW_MOUNT_Canon_EF) { switch (table_buf[153]) { case 16: imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Minolta_A; break; case 17: imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Sony_E; break; } } break; } free(table_buf); } else if (tag == 0x9050 && len < 256000) // little endian { table_buf_0x9050 = (uchar*)malloc(len); table_buf_0x9050_present = 1; fread(table_buf_0x9050, len, 1, ifp); if (imgdata.lens.makernotes.CamID) { process_Sony_0x9050(table_buf_0x9050, imgdata.lens.makernotes.CamID); free (table_buf_0x9050); table_buf_0x9050_present = 0; } } else if (tag == 0x940c && len < 256000) { table_buf_0x940c = (uchar*)malloc(len); table_buf_0x940c_present = 1; fread(table_buf_0x940c, len, 1, ifp); if ((imgdata.lens.makernotes.CamID) && (imgdata.lens.makernotes.CameraMount == LIBRAW_MOUNT_Sony_E)) { process_Sony_0x940c(table_buf_0x940c); free(table_buf_0x940c); table_buf_0x940c_present = 0; } } else if (((tag == 0xb027) || (tag == 0x010c)) && (imgdata.lens.makernotes.LensID == -1)) { imgdata.lens.makernotes.LensID = get4(); if ((imgdata.lens.makernotes.LensID > 0x4900) && (imgdata.lens.makernotes.LensID <= 0x5900)) { imgdata.lens.makernotes.AdapterID = 0x4900; imgdata.lens.makernotes.LensID -= imgdata.lens.makernotes.AdapterID; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Sigma_X3F; strcpy(imgdata.lens.makernotes.Adapter, "MC-11"); } else if ((imgdata.lens.makernotes.LensID > 0xEF00) && (imgdata.lens.makernotes.LensID < 0xFFFF) && (imgdata.lens.makernotes.LensID != 0xFF00)) { imgdata.lens.makernotes.AdapterID = 0xEF00; imgdata.lens.makernotes.LensID -= imgdata.lens.makernotes.AdapterID; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Canon_EF; } if (tag == 0x010c) imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Minolta_A; } else if (tag == 0xb02a && len < 256000) // Sony LensSpec { table_buf = (uchar*)malloc(len); fread(table_buf, len, 1, ifp); if (saneSonyCameraInfo(table_buf[1], table_buf[2], table_buf[3], table_buf[4], table_buf[5], table_buf[6])) { if (table_buf[1] | table_buf[2]) imgdata.lens.makernotes.MinFocal = bcd2dec(table_buf[1]) * 100 + bcd2dec(table_buf[2]); if (table_buf[3] | table_buf[4]) imgdata.lens.makernotes.MaxFocal = bcd2dec(table_buf[3]) * 100 + bcd2dec(table_buf[4]); if (table_buf[5]) imgdata.lens.makernotes.MaxAp4MinFocal = bcd2dec(table_buf[5]) / 10.0f; if (table_buf[6]) imgdata.lens.makernotes.MaxAp4MaxFocal = bcd2dec(table_buf[6]) / 10.0f; parseSonyLensFeatures(table_buf[0], table_buf[7]); } free(table_buf); } } next: fseek (ifp, save, SEEK_SET); } quit: order = sorder; } #else void CLASS parse_makernote_0xc634(int base, int uptag, unsigned dng_writer) { /*placeholder */ } #endif void CLASS parse_makernote (int base, int uptag) { unsigned offset=0, entries, tag, type, len, save, c; unsigned ver97=0, serial=0, i, wbi=0, wb[4]={0,0,0,0}; uchar buf97[324], ci, cj, ck; short morder, sorder=order; char buf[10]; unsigned SamsungKey[11]; uchar NikonKey; #ifdef LIBRAW_LIBRARY_BUILD unsigned custom_serial = 0; unsigned NikonLensDataVersion = 0; unsigned lenNikonLensData = 0; unsigned NikonFlashInfoVersion = 0; uchar *CanonCameraInfo; unsigned lenCanonCameraInfo = 0; uchar *table_buf; uchar *table_buf_0x9050; ushort table_buf_0x9050_present = 0; uchar *table_buf_0x940c; ushort table_buf_0x940c_present = 0; INT64 fsize = ifp->size(); #endif /* The MakerNote might have its own TIFF header (possibly with its own byte-order!), or it might just be a table. */ if (!strncmp(make,"Nokia",5)) return; fread (buf, 1, 10, ifp); if (!strncmp (buf,"KDK" ,3) || /* these aren't TIFF tables */ !strncmp (buf,"VER" ,3) || !strncmp (buf,"IIII",4) || !strncmp (buf,"MMMM",4)) return; if (!strncmp (buf,"KC" ,2) || /* Konica KD-400Z, KD-510Z */ !strncmp (buf,"MLY" ,3)) { /* Minolta DiMAGE G series */ order = 0x4d4d; while ((i=ftell(ifp)) < data_offset && i < 16384) { wb[0] = wb[2]; wb[2] = wb[1]; wb[1] = wb[3]; wb[3] = get2(); if (wb[1] == 256 && wb[3] == 256 && wb[0] > 256 && wb[0] < 640 && wb[2] > 256 && wb[2] < 640) FORC4 cam_mul[c] = wb[c]; } goto quit; } if (!strcmp (buf,"Nikon")) { base = ftell(ifp); order = get2(); if (get2() != 42) goto quit; offset = get4(); fseek (ifp, offset-8, SEEK_CUR); } else if (!strcmp (buf,"OLYMPUS") || !strcmp (buf,"PENTAX ")) { base = ftell(ifp)-10; fseek (ifp, -2, SEEK_CUR); order = get2(); if (buf[0] == 'O') get2(); } else if (!strncmp (buf,"SONY",4) || !strcmp (buf,"Panasonic")) { goto nf; } else if (!strncmp (buf,"FUJIFILM",8)) { base = ftell(ifp)-10; nf: order = 0x4949; fseek (ifp, 2, SEEK_CUR); } else if (!strcmp (buf,"OLYMP") || !strcmp (buf,"LEICA") || !strcmp (buf,"Ricoh") || !strcmp (buf,"EPSON")) fseek (ifp, -2, SEEK_CUR); else if (!strcmp (buf,"AOC") || !strcmp (buf,"QVC")) fseek (ifp, -4, SEEK_CUR); else { fseek (ifp, -10, SEEK_CUR); if (!strncmp(make,"SAMSUNG",7)) base = ftell(ifp); } // adjust pos & base for Leica M8/M9/M Mono tags and dir in tag 0x3400 if (!strncasecmp(make, "LEICA", 5)) { if (!strncmp(model, "M8", 2) || !strncasecmp(model, "Leica M8", 8) || !strncasecmp(model, "LEICA X", 7)) { base = ftell(ifp)-8; } else if (!strncasecmp(model, "LEICA M (Typ 240)", 17)) { base = 0; } else if (!strncmp(model, "M9", 2) || !strncasecmp(model, "Leica M9", 8) || !strncasecmp(model, "M Monochrom", 11) || !strncasecmp(model, "Leica M Monochrom", 11)) { if (!uptag) { base = ftell(ifp) - 10; fseek (ifp, 8, SEEK_CUR); } else if (uptag == 0x3400) { fseek (ifp, 10, SEEK_CUR); base += 10; } } else if (!strncasecmp(model, "LEICA T", 7)) { base = ftell(ifp)-8; #ifdef LIBRAW_LIBRARY_BUILD imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Leica_T; #endif } #ifdef LIBRAW_LIBRARY_BUILD else if (!strncasecmp(model, "LEICA SL", 8)) { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Leica_SL; imgdata.lens.makernotes.CameraFormat = LIBRAW_FORMAT_FF; } #endif } entries = get2(); if (entries > 1000) return; morder = order; while (entries--) { order = morder; tiff_get (base, &tag, &type, &len, &save); tag |= uptag << 16; #ifdef LIBRAW_LIBRARY_BUILD INT64 _pos = ftell(ifp); if(len > 8 && _pos+len > 2* fsize) continue; if (!strncmp(make, "Canon",5)) { if (tag == 0x000d && len < 256000) // camera info { CanonCameraInfo = (uchar*)malloc(MAX(16,len)); fread(CanonCameraInfo, len, 1, ifp); lenCanonCameraInfo = len; } else if (tag == 0x10) // Canon ModelID { unique_id = get4(); if (unique_id == 0x03740000) unique_id = 0x80000374; // M3 if (unique_id == 0x03840000) unique_id = 0x80000384; // M10 if (unique_id == 0x03940000) unique_id = 0x80000394; // M5 setCanonBodyFeatures(unique_id); if (lenCanonCameraInfo) { processCanonCameraInfo(unique_id, CanonCameraInfo,lenCanonCameraInfo); free(CanonCameraInfo); CanonCameraInfo = 0; lenCanonCameraInfo = 0; } } else parseCanonMakernotes (tag, type, len); } else if (!strncmp(make, "FUJI", 4)) { if (tag == 0x0010) { char FujiSerial[sizeof(imgdata.shootinginfo.InternalBodySerial)]; char *words[4]; char yy[2], mm[3], dd[3], ystr[16], ynum[16]; int year, nwords, ynum_len; unsigned c; stmread(FujiSerial, len, ifp); nwords = getwords(FujiSerial, words, 4,sizeof(imgdata.shootinginfo.InternalBodySerial)); for (int i = 0; i < nwords; i++) { mm[2] = dd[2] = 0; if (strnlen(words[i],sizeof(imgdata.shootinginfo.InternalBodySerial)-1) < 18) if (i == 0) strncpy (imgdata.shootinginfo.InternalBodySerial, words[0], sizeof(imgdata.shootinginfo.InternalBodySerial)-1); else { char tbuf[sizeof(imgdata.shootinginfo.InternalBodySerial)]; snprintf (tbuf, sizeof(tbuf), "%s %s", imgdata.shootinginfo.InternalBodySerial, words[i]); strncpy(imgdata.shootinginfo.InternalBodySerial,tbuf, sizeof(imgdata.shootinginfo.InternalBodySerial)-1); } else { strncpy (dd, words[i]+strnlen(words[i],sizeof(imgdata.shootinginfo.InternalBodySerial)-1)-14, 2); strncpy (mm, words[i]+strnlen(words[i],sizeof(imgdata.shootinginfo.InternalBodySerial)-1)-16, 2); strncpy (yy, words[i]+strnlen(words[i],sizeof(imgdata.shootinginfo.InternalBodySerial)-1)-18, 2); year = (yy[0]-'0')*10 + (yy[1]-'0'); if (year <70) year += 2000; else year += 1900; ynum_len = (int)strnlen(words[i],sizeof(imgdata.shootinginfo.InternalBodySerial)-1)-18; strncpy(ynum, words[i], ynum_len); ynum[ynum_len] = 0; for ( int j = 0; ynum[j] && ynum[j+1] && sscanf(ynum+j, "%2x", &c); j += 2) ystr[j/2] = c; ystr[ynum_len / 2 + 1] = 0; strcpy (model2, ystr); if (i == 0) { char tbuf[sizeof(imgdata.shootinginfo.InternalBodySerial)]; if (nwords == 1) snprintf (tbuf,sizeof(tbuf), "%s %s %d:%s:%s", words[0]+strnlen(words[0],sizeof(imgdata.shootinginfo.InternalBodySerial)-1)-12, ystr, year, mm, dd); else snprintf (tbuf,sizeof(tbuf), "%s %d:%s:%s %s", ystr, year, mm, dd, words[0]+strnlen(words[0],sizeof(imgdata.shootinginfo.InternalBodySerial)-1)-12); strncpy(imgdata.shootinginfo.InternalBodySerial,tbuf, sizeof(imgdata.shootinginfo.InternalBodySerial)-1); } else { char tbuf[sizeof(imgdata.shootinginfo.InternalBodySerial)]; snprintf (tbuf, sizeof(tbuf), "%s %s %d:%s:%s %s", imgdata.shootinginfo.InternalBodySerial, ystr, year, mm, dd, words[i]+strnlen(words[i],sizeof(imgdata.shootinginfo.InternalBodySerial)-1)-12); strncpy(imgdata.shootinginfo.InternalBodySerial,tbuf, sizeof(imgdata.shootinginfo.InternalBodySerial)-1); } } } } else parseFujiMakernotes (tag, type); } else if (!strncasecmp(make, "LEICA", 5)) { if (((tag == 0x035e) || (tag == 0x035f)) && (type == 10) && (len == 9)) { int ind = tag == 0x035e?0:1; for (int j=0; j < 3; j++) FORCC imgdata.color.dng_color[ind].forwardmatrix[j][c]= getreal(type); } if ((tag == 0x0303) && (type != 4)) { stmread(imgdata.lens.makernotes.Lens, len, ifp); } if ((tag == 0x3405) || (tag == 0x0310) || (tag == 0x34003405)) { imgdata.lens.makernotes.LensID = get4(); imgdata.lens.makernotes.LensID = ((imgdata.lens.makernotes.LensID>>2)<<8) | (imgdata.lens.makernotes.LensID & 0x3); if (imgdata.lens.makernotes.LensID != -1) { if ((model[0] == 'M') || !strncasecmp (model, "LEICA M", 7)) { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Leica_M; if (imgdata.lens.makernotes.LensID) imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Leica_M; } else if ((model[0] == 'S') || !strncasecmp (model, "LEICA S", 7)) { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Leica_S; if (imgdata.lens.makernotes.Lens[0]) imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Leica_S; } } } else if ( ((tag == 0x0313) || (tag == 0x34003406)) && (fabs(imgdata.lens.makernotes.CurAp) < 0.17f) && ((type == 10) || (type == 5)) ) { imgdata.lens.makernotes.CurAp = getreal(type); if (imgdata.lens.makernotes.CurAp > 126.3) imgdata.lens.makernotes.CurAp = 0.0f; } else if (tag == 0x3400) { parse_makernote (base, 0x3400); } } else if (!strncmp(make, "NIKON",5)) { if (tag == 0x000a) { imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens; imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens; } else if (tag == 0x0012) { char a, b, c; a = fgetc(ifp); b = fgetc(ifp); c = fgetc(ifp); if (c) imgdata.other.FlashEC = (float)(a*b)/(float)c; } else if (tag == 0x0082) // lens attachment { stmread(imgdata.lens.makernotes.Attachment, len, ifp); } else if (tag == 0x0083) // lens type { imgdata.lens.nikon.NikonLensType = fgetc(ifp); } else if (tag == 0x0084) // lens { imgdata.lens.makernotes.MinFocal = getreal(type); imgdata.lens.makernotes.MaxFocal = getreal(type); imgdata.lens.makernotes.MaxAp4MinFocal = getreal(type); imgdata.lens.makernotes.MaxAp4MaxFocal = getreal(type); } else if (tag == 0x008b) // lens f-stops { uchar a, b, c; a = fgetc(ifp); b = fgetc(ifp); c = fgetc(ifp); if (c) { imgdata.lens.nikon.NikonLensFStops = a*b*(12/c); imgdata.lens.makernotes.LensFStops = (float)imgdata.lens.nikon.NikonLensFStops /12.0f; } } else if (tag == 0x0093) { i = get2(); if ((i == 7) || (i == 9)) { imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens; imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens; } } else if (tag == 0x0098) // contains lens data { for (i = 0; i < 4; i++) { NikonLensDataVersion = NikonLensDataVersion * 10 + fgetc(ifp) - '0'; } switch (NikonLensDataVersion) { case 100: lenNikonLensData = 9; break; case 101: case 201: // encrypted, starting from v.201 case 202: case 203: lenNikonLensData = 15; break; case 204: lenNikonLensData = 16; break; case 400: lenNikonLensData = 459; break; case 401: lenNikonLensData = 590; break; case 402: lenNikonLensData = 509; break; case 403: lenNikonLensData = 879; break; } if(lenNikonLensData>0) { table_buf = (uchar*)malloc(lenNikonLensData); fread(table_buf, lenNikonLensData, 1, ifp); if ((NikonLensDataVersion < 201) && lenNikonLensData) { processNikonLensData(table_buf, lenNikonLensData); free(table_buf); lenNikonLensData = 0; } } } else if (tag == 0x00a0) { stmread(imgdata.shootinginfo.BodySerial, len, ifp); } else if (tag == 0x00a8) // contains flash data { for (i = 0; i < 4; i++) { NikonFlashInfoVersion = NikonFlashInfoVersion * 10 + fgetc(ifp) - '0'; } } } else if (!strncmp(make, "OLYMPUS", 7)) { switch (tag) { case 0x0404: case 0x101a: case 0x20100101: if (!imgdata.shootinginfo.BodySerial[0]) stmread(imgdata.shootinginfo.BodySerial, len, ifp); break; case 0x20100102: if (!imgdata.shootinginfo.InternalBodySerial[0]) stmread(imgdata.shootinginfo.InternalBodySerial, len, ifp); break; case 0x0207: case 0x20100100: { uchar sOlyID[8]; unsigned long long OlyID; fread (sOlyID, MIN(len,7), 1, ifp); sOlyID[7] = 0; OlyID = sOlyID[0]; i = 1; while (i < 7 && sOlyID[i]) { OlyID = OlyID << 8 | sOlyID[i]; i++; } setOlympusBodyFeatures(OlyID); } break; case 0x1002: imgdata.lens.makernotes.CurAp = libraw_powf64(2.0f, getreal(type)/2); break; case 0x20401112: imgdata.makernotes.olympus.OlympusCropID = get2(); break; case 0x20401113: FORC4 imgdata.makernotes.olympus.OlympusFrame[c] = get2(); break; case 0x20100201: { unsigned long long oly_lensid [3]; oly_lensid[0] = fgetc(ifp); fgetc(ifp); oly_lensid[1] = fgetc(ifp); oly_lensid[2] = fgetc(ifp); imgdata.lens.makernotes.LensID = (oly_lensid[0] << 16) | (oly_lensid[1] << 8) | oly_lensid[2]; } imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FT; imgdata.lens.makernotes.LensFormat = LIBRAW_FORMAT_FT; if (((imgdata.lens.makernotes.LensID < 0x20000) || (imgdata.lens.makernotes.LensID > 0x4ffff)) && (imgdata.lens.makernotes.LensID & 0x10)) { imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_mFT; } break; case 0x20100202: stmread(imgdata.lens.LensSerial, len, ifp); break; case 0x20100203: stmread(imgdata.lens.makernotes.Lens, len, ifp); break; case 0x20100205: imgdata.lens.makernotes.MaxAp4MinFocal = libraw_powf64(sqrt(2.0f), get2() / 256.0f); break; case 0x20100206: imgdata.lens.makernotes.MaxAp4MaxFocal = libraw_powf64(sqrt(2.0f), get2() / 256.0f); break; case 0x20100207: imgdata.lens.makernotes.MinFocal = (float)get2(); break; case 0x20100208: imgdata.lens.makernotes.MaxFocal = (float)get2(); if (imgdata.lens.makernotes.MaxFocal > 1000.0f) imgdata.lens.makernotes.MaxFocal = imgdata.lens.makernotes.MinFocal; break; case 0x2010020a: imgdata.lens.makernotes.MaxAp4CurFocal = libraw_powf64(sqrt(2.0f), get2() / 256.0f); break; case 0x20100301: imgdata.lens.makernotes.TeleconverterID = fgetc(ifp) << 8; fgetc(ifp); imgdata.lens.makernotes.TeleconverterID = imgdata.lens.makernotes.TeleconverterID | fgetc(ifp); break; case 0x20100303: stmread(imgdata.lens.makernotes.Teleconverter, len, ifp); break; case 0x20100403: stmread(imgdata.lens.makernotes.Attachment, len, ifp); break; } } else if ((!strncmp(make, "PENTAX", 6) || !strncmp(make, "RICOH", 5)) && !strncmp(model, "GR", 2)) { if (tag == 0x0005) { char buffer[17]; int count=0; fread(buffer, 16, 1, ifp); buffer[16] = 0; for (int i=0; i<16; i++) { // sprintf(imgdata.shootinginfo.InternalBodySerial+2*i, "%02x", buffer[i]); if ((isspace(buffer[i])) || (buffer[i] == 0x2D) || (isalnum(buffer[i]))) count++; } if (count == 16) { sprintf (imgdata.shootinginfo.BodySerial, "%8s", buffer+8); buffer[8] = 0; sprintf (imgdata.shootinginfo.InternalBodySerial, "%8s", buffer); } else { sprintf (imgdata.shootinginfo.BodySerial, "%02x%02x%02x%02x", buffer[4], buffer[5], buffer[6], buffer[7]); sprintf (imgdata.shootinginfo.InternalBodySerial, "%02x%02x%02x%02x", buffer[8], buffer[9], buffer[10], buffer[11]); } } else if ((tag == 0x1001) && (type == 3)) { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens; imgdata.lens.makernotes.CameraFormat = LIBRAW_FORMAT_APSC; imgdata.lens.makernotes.LensID = -1; imgdata.lens.makernotes.FocalType = 1; } else if ((tag == 0x100b) && (type == 10)) { imgdata.other.FlashEC = getreal(type); } else if ((tag == 0x1017) && (get2() == 2)) { strcpy(imgdata.lens.makernotes.Attachment, "Wide-Angle Adapter"); } else if (tag == 0x1500) { imgdata.lens.makernotes.CurFocal = getreal(type); } } else if (!strncmp(make, "RICOH", 5) && strncmp(model, "PENTAX", 6)) { if ((tag == 0x0005) && !strncmp(model, "GXR", 3)) { char buffer[9]; buffer[8] = 0; fread(buffer, 8, 1, ifp); sprintf (imgdata.shootinginfo.InternalBodySerial, "%8s", buffer); } else if ((tag == 0x100b) && (type == 10)) { imgdata.other.FlashEC = getreal(type); } else if ((tag == 0x1017) && (get2() == 2)) { strcpy(imgdata.lens.makernotes.Attachment, "Wide-Angle Adapter"); } else if (tag == 0x1500) { imgdata.lens.makernotes.CurFocal = getreal(type); } else if ((tag == 0x2001) && !strncmp(model, "GXR", 3)) { short ntags, cur_tag; fseek(ifp, 20, SEEK_CUR); ntags = get2(); cur_tag = get2(); while (cur_tag != 0x002c) { fseek(ifp, 10, SEEK_CUR); cur_tag = get2(); } fseek(ifp, 6, SEEK_CUR); fseek(ifp, get4()+20, SEEK_SET); stread(imgdata.shootinginfo.BodySerial, 12, ifp); get2(); imgdata.lens.makernotes.LensID = getc(ifp) - '0'; switch(imgdata.lens.makernotes.LensID) { case 1: case 2: case 3: case 5: case 6: imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_RicohModule; break; case 8: imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Leica_M; imgdata.lens.makernotes.CameraFormat = LIBRAW_FORMAT_APSC; imgdata.lens.makernotes.LensID = -1; break; default: imgdata.lens.makernotes.LensID = -1; } fseek(ifp, 17, SEEK_CUR); stread(imgdata.lens.LensSerial, 12, ifp); } } else if ((!strncmp(make, "PENTAX", 6) || !strncmp(model, "PENTAX", 6) || (!strncmp(make, "SAMSUNG", 7) && dng_version)) && strncmp(model, "GR", 2)) { if (tag == 0x0005) { unique_id = get4(); setPentaxBodyFeatures(unique_id); } else if (tag == 0x0013) { imgdata.lens.makernotes.CurAp = (float)get2()/10.0f; } else if (tag == 0x0014) { PentaxISO(get2()); } else if (tag == 0x001d) { imgdata.lens.makernotes.CurFocal = (float)get4()/100.0f; } else if (tag == 0x003f) { imgdata.lens.makernotes.LensID = fgetc(ifp) << 8 | fgetc(ifp); } else if (tag == 0x004d) { if (type == 9) imgdata.other.FlashEC = getreal(type) / 256.0f; else imgdata.other.FlashEC = (float) ((signed short) fgetc(ifp)) / 6.0f; } else if (tag == 0x007e) { imgdata.color.linear_max[0] = imgdata.color.linear_max[1] = imgdata.color.linear_max[2] = imgdata.color.linear_max[3] = (long)(-1) * get4(); } else if (tag == 0x0207) { if(len < 65535) // Safety belt PentaxLensInfo(imgdata.lens.makernotes.CamID, len); } else if (tag == 0x020d) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][c ^ (c >> 1)] = get2(); } else if (tag == 0x020e) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][c ^ (c >> 1)] = get2(); } else if (tag == 0x020f) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][c ^ (c >> 1)] = get2(); } else if (tag == 0x0210) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][c ^ (c >> 1)] = get2(); } else if (tag == 0x0211) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][c ^ (c >> 1)] = get2(); } else if (tag == 0x0212) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][c ^ (c >> 1)] = get2(); } else if (tag == 0x0213) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][c ^ (c >> 1)] = get2(); } else if (tag == 0x0214) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][c ^ (c >> 1)] = get2(); } else if (tag == 0x0221) { int nWB = get2(); if(nWB<=sizeof(imgdata.color.WBCT_Coeffs)/sizeof(imgdata.color.WBCT_Coeffs[0])) for (int i = 0; i < nWB; i++) { imgdata.color.WBCT_Coeffs[i][0] = (unsigned)0xcfc6 - get2(); fseek(ifp, 2, SEEK_CUR); imgdata.color.WBCT_Coeffs[i][1] = get2(); imgdata.color.WBCT_Coeffs[i][2] = imgdata.color.WBCT_Coeffs[i][4] = 0x2000; imgdata.color.WBCT_Coeffs[i][3] = get2(); } } else if (tag == 0x0215) { fseek (ifp, 16, SEEK_CUR); sprintf(imgdata.shootinginfo.InternalBodySerial, "%d", get4()); } else if (tag == 0x0229) { stmread(imgdata.shootinginfo.BodySerial, len, ifp); } else if (tag == 0x022d) { fseek (ifp,2,SEEK_CUR); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][c ^ (c >> 1)] = get2(); getc(ifp); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][c ^ (c >> 1)] = get2(); getc(ifp); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][c ^ (c >> 1)] = get2(); getc(ifp); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][c ^ (c >> 1)] = get2(); getc(ifp); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][c ^ (c >> 1)] = get2(); getc(ifp); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][c ^ (c >> 1)] = get2(); getc(ifp); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][c ^ (c >> 1)] = get2(); getc(ifp); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][c ^ (c >> 1)] = get2(); getc(ifp); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_L][c ^ (c >> 1)] = get2(); } else if (tag == 0x0239) // Q-series lens info (LensInfoQ) { char LensInfo [20]; fseek (ifp, 2, SEEK_CUR); stread(imgdata.lens.makernotes.Lens, 30, ifp); strcat(imgdata.lens.makernotes.Lens, " "); stread(LensInfo, 20, ifp); strcat(imgdata.lens.makernotes.Lens, LensInfo); } } else if (!strncmp(make, "SAMSUNG", 7)) { if (tag == 0x0002) { if(get4() == 0x2000) { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Samsung_NX; } else if (!strncmp(model, "NX mini", 7)) { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Samsung_NX_M; } else { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens; } } else if (tag == 0x0003) { unique_id = imgdata.lens.makernotes.CamID = get4(); } else if (tag == 0xa002) { stmread(imgdata.shootinginfo.BodySerial, len, ifp); } else if (tag == 0xa003) { imgdata.lens.makernotes.LensID = get2(); if (imgdata.lens.makernotes.LensID) imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Samsung_NX; } else if (tag == 0xa005) { stmread(imgdata.lens.InternalLensSerial, len, ifp); } else if (tag == 0xa019) { imgdata.lens.makernotes.CurAp = getreal(type); } else if (tag == 0xa01a) { imgdata.lens.makernotes.FocalLengthIn35mmFormat = get4() / 10.0f; if (imgdata.lens.makernotes.FocalLengthIn35mmFormat < 10.0f) imgdata.lens.makernotes.FocalLengthIn35mmFormat *= 10.0f; } } else if (!strncasecmp(make, "SONY", 4) || !strncasecmp(make, "Konica", 6) || !strncasecmp(make, "Minolta", 7) || (!strncasecmp(make, "Hasselblad", 10) && (!strncasecmp(model, "Stellar", 7) || !strncasecmp(model, "Lunar", 5) || !strncasecmp(model, "Lusso", 5) || !strncasecmp(model, "HV",2)))) { ushort lid; if (tag == 0xb001) // Sony ModelID { unique_id = get2(); setSonyBodyFeatures(unique_id); if (table_buf_0x9050_present) { process_Sony_0x9050(table_buf_0x9050, unique_id); free (table_buf_0x9050); table_buf_0x9050_present = 0; } if (table_buf_0x940c_present) { if (imgdata.lens.makernotes.CameraMount == LIBRAW_MOUNT_Sony_E) { process_Sony_0x940c(table_buf_0x940c); } free (table_buf_0x940c); table_buf_0x940c_present = 0; } } else if ((tag == 0x0010) && // CameraInfo strncasecmp(model, "DSLR-A100", 9) && strncasecmp(model, "NEX-5C", 6) && !strncasecmp(make, "SONY", 4) && ((len == 368) || // a700 (len == 5478) || // a850, a900 (len == 5506) || // a200, a300, a350 (len == 6118) || // a230, a290, a330, a380, a390 // a450, a500, a550, a560, a580 // a33, a35, a55 // NEX3, NEX5, NEX5C, NEXC3, VG10E (len == 15360)) ) { table_buf = (uchar*)malloc(len); fread(table_buf, len, 1, ifp); if (memcmp(table_buf, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) && memcmp(table_buf, "\x00\x00\x00\x00\x00\x00\x00\x00", 8)) { switch (len) { case 368: case 5478: // a700, a850, a900: CameraInfo if (table_buf[0] | table_buf[3]) imgdata.lens.makernotes.MinFocal = bcd2dec(table_buf[0]) * 100 + bcd2dec(table_buf[3]); if (table_buf[2] | table_buf[5]) imgdata.lens.makernotes.MaxFocal = bcd2dec(table_buf[2]) * 100 + bcd2dec(table_buf[5]); if (table_buf[4]) imgdata.lens.makernotes.MaxAp4MinFocal = bcd2dec(table_buf[4]) / 10.0f; if (table_buf[4]) imgdata.lens.makernotes.MaxAp4MaxFocal = bcd2dec(table_buf[7]) / 10.0f; parseSonyLensFeatures(table_buf[1], table_buf[6]); break; default: // CameraInfo2 & 3 if (table_buf[1] | table_buf[2]) imgdata.lens.makernotes.MinFocal = bcd2dec(table_buf[1]) * 100 + bcd2dec(table_buf[2]); if (table_buf[3] | table_buf[4]) imgdata.lens.makernotes.MaxFocal = bcd2dec(table_buf[3]) * 100 + bcd2dec(table_buf[4]); if (table_buf[5]) imgdata.lens.makernotes.MaxAp4MinFocal = bcd2dec(table_buf[5]) / 10.0f; if (table_buf[6]) imgdata.lens.makernotes.MaxAp4MaxFocal = bcd2dec(table_buf[6]) / 10.0f; parseSonyLensFeatures(table_buf[0], table_buf[7]); } } free(table_buf); } else if ((tag == 0x0020) && // WBInfoA100, needs 0xb028 processing !strncasecmp(model, "DSLR-A100", 9)) { fseek(ifp,0x49dc,SEEK_CUR); stmread(imgdata.shootinginfo.InternalBodySerial, 12, ifp); } else if (tag == 0x0104) { imgdata.other.FlashEC = getreal(type); } else if (tag == 0x0105) // Teleconverter { imgdata.lens.makernotes.TeleconverterID = get2(); } else if (tag == 0x0114 && len < 256000) // CameraSettings { table_buf = (uchar*)malloc(len); fread(table_buf, len, 1, ifp); switch (len) { case 280: case 364: case 332: // CameraSettings and CameraSettings2 are big endian if (table_buf[2] | table_buf[3]) { lid = (((ushort)table_buf[2])<<8) | ((ushort)table_buf[3]); imgdata.lens.makernotes.CurAp = libraw_powf64(2.0f, ((float)lid/8.0f-1.0f)/2.0f); } break; case 1536: case 2048: // CameraSettings3 are little endian parseSonyLensType2(table_buf[1016], table_buf[1015]); if (imgdata.lens.makernotes.LensMount != LIBRAW_MOUNT_Canon_EF) { switch (table_buf[153]) { case 16: imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Minolta_A; break; case 17: imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Sony_E; break; } } break; } free(table_buf); } else if (tag == 0x9050 && len < 256000) // little endian { table_buf_0x9050 = (uchar*)malloc(len); table_buf_0x9050_present = 1; fread(table_buf_0x9050, len, 1, ifp); if (imgdata.lens.makernotes.CamID) { process_Sony_0x9050(table_buf_0x9050, imgdata.lens.makernotes.CamID); free (table_buf_0x9050); table_buf_0x9050_present = 0; } } else if (tag == 0x940c && len <256000) { table_buf_0x940c = (uchar*)malloc(len); table_buf_0x940c_present = 1; fread(table_buf_0x940c, len, 1, ifp); if ((imgdata.lens.makernotes.CamID) && (imgdata.lens.makernotes.CameraMount == LIBRAW_MOUNT_Sony_E)) { process_Sony_0x940c(table_buf_0x940c); free(table_buf_0x940c); table_buf_0x940c_present = 0; } } else if (((tag == 0xb027) || (tag == 0x010c)) && (imgdata.lens.makernotes.LensID == -1)) { imgdata.lens.makernotes.LensID = get4(); if ((imgdata.lens.makernotes.LensID > 0x4900) && (imgdata.lens.makernotes.LensID <= 0x5900)) { imgdata.lens.makernotes.AdapterID = 0x4900; imgdata.lens.makernotes.LensID -= imgdata.lens.makernotes.AdapterID; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Sigma_X3F; strcpy(imgdata.lens.makernotes.Adapter, "MC-11"); } else if ((imgdata.lens.makernotes.LensID > 0xEF00) && (imgdata.lens.makernotes.LensID < 0xFFFF) && (imgdata.lens.makernotes.LensID != 0xFF00)) { imgdata.lens.makernotes.AdapterID = 0xEF00; imgdata.lens.makernotes.LensID -= imgdata.lens.makernotes.AdapterID; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Canon_EF; } if (tag == 0x010c) imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Minolta_A; } else if (tag == 0xb02a && len < 256000) // Sony LensSpec { table_buf = (uchar*)malloc(len); fread(table_buf, len, 1, ifp); if (table_buf[1] | table_buf[2]) imgdata.lens.makernotes.MinFocal = bcd2dec(table_buf[1]) * 100 + bcd2dec(table_buf[2]); if (table_buf[3] | table_buf[4]) imgdata.lens.makernotes.MaxFocal = bcd2dec(table_buf[3]) * 100 + bcd2dec(table_buf[4]); if (table_buf[5]) imgdata.lens.makernotes.MaxAp4MinFocal = bcd2dec(table_buf[5]) / 10.0f; if (table_buf[6]) imgdata.lens.makernotes.MaxAp4MaxFocal = bcd2dec(table_buf[6]) / 10.0f; parseSonyLensFeatures(table_buf[0], table_buf[7]); free(table_buf); } } fseek(ifp,_pos,SEEK_SET); #endif if (tag == 2 && strstr(make,"NIKON") && !iso_speed) iso_speed = (get2(),get2()); if (tag == 37 && strstr(make,"NIKON") && (!iso_speed || iso_speed == 65535)) { unsigned char cc; fread(&cc,1,1,ifp); iso_speed = int(100.0 * libraw_powf64(2.0f,float(cc)/12.0-5.0)); } if (tag == 4 && len > 26 && len < 35) { if ((i=(get4(),get2())) != 0x7fff && (!iso_speed || iso_speed == 65535)) iso_speed = 50 * libraw_powf64(2.0, i/32.0 - 4); #ifdef LIBRAW_LIBRARY_BUILD get4(); #else if ((i=(get2(),get2())) != 0x7fff && !aperture) aperture = libraw_powf64(2.0, i/64.0); #endif if ((i=get2()) != 0xffff && !shutter) shutter = libraw_powf64(2.0, (short) i/-32.0); wbi = (get2(),get2()); shot_order = (get2(),get2()); } if ((tag == 4 || tag == 0x114) && !strncmp(make,"KONICA",6)) { fseek (ifp, tag == 4 ? 140:160, SEEK_CUR); switch (get2()) { case 72: flip = 0; break; case 76: flip = 6; break; case 82: flip = 5; break; } } if (tag == 7 && type == 2 && len > 20) fgets (model2, 64, ifp); if (tag == 8 && type == 4) shot_order = get4(); if (tag == 9 && !strncmp(make,"Canon",5)) fread (artist, 64, 1, ifp); if (tag == 0xc && len == 4) FORC3 cam_mul[(c << 1 | c >> 1) & 3] = getreal(type); if (tag == 0xd && type == 7 && get2() == 0xaaaa) { for (c=i=2; (ushort) c != 0xbbbb && i < len; i++) c = c << 8 | fgetc(ifp); while ((i+=4) < len-5) if (get4() == 257 && (i=len) && (c = (get4(),fgetc(ifp))) < 3) flip = "065"[c]-'0'; } #ifndef LIBRAW_LIBRARY_BUILD if (tag == 0x10 && type == 4) unique_id = get4(); #endif #ifdef LIBRAW_LIBRARY_BUILD INT64 _pos2 = ftell(ifp); if (!strncasecmp(make,"Olympus",7)) { short nWB, tWB; if ((tag == 0x20300108) || (tag == 0x20310109)) imgdata.makernotes.olympus.ColorSpace = get2(); if ((tag == 0x20400102) && (len == 2) && (!strncasecmp(model, "E-410", 5) || !strncasecmp(model, "E-510", 5))) { int i; for (i=0; i<64; i++) imgdata.color.WBCT_Coeffs[i][2] = imgdata.color.WBCT_Coeffs[i][4] = imgdata.color.WB_Coeffs[i][1] = imgdata.color.WB_Coeffs[i][3] = 0x100; for (i=64; i<256; i++) imgdata.color.WB_Coeffs[i][1] = imgdata.color.WB_Coeffs[i][3] = 0x100; } if ((tag >= 0x20400102) && (tag <= 0x2040010d)) { ushort CT; nWB = tag-0x20400102; switch (nWB) { case 0 : CT = 3000; tWB = LIBRAW_WBI_Tungsten; break; case 1 : CT = 3300; tWB = 0x100; break; case 2 : CT = 3600; tWB = 0x100; break; case 3 : CT = 3900; tWB = 0x100; break; case 4 : CT = 4000; tWB = LIBRAW_WBI_FL_W; break; case 5 : CT = 4300; tWB = 0x100; break; case 6 : CT = 4500; tWB = LIBRAW_WBI_FL_D; break; case 7 : CT = 4800; tWB = 0x100; break; case 8 : CT = 5300; tWB = LIBRAW_WBI_FineWeather; break; case 9 : CT = 6000; tWB = LIBRAW_WBI_Cloudy; break; case 10: CT = 6600; tWB = LIBRAW_WBI_FL_N; break; case 11: CT = 7500; tWB = LIBRAW_WBI_Shade; break; default: CT = 0; tWB = 0x100; } if (CT) { imgdata.color.WBCT_Coeffs[nWB][0] = CT; imgdata.color.WBCT_Coeffs[nWB][1] = get2(); imgdata.color.WBCT_Coeffs[nWB][3] = get2(); if (len == 4) { imgdata.color.WBCT_Coeffs[nWB][2] = get2(); imgdata.color.WBCT_Coeffs[nWB][4] = get2(); } } if (tWB != 0x100) FORC4 imgdata.color.WB_Coeffs[tWB][c] = imgdata.color.WBCT_Coeffs[nWB][c+1]; } if ((tag >= 0x20400113) && (tag <= 0x2040011e)) { nWB = tag-0x20400113; imgdata.color.WBCT_Coeffs[nWB][2] = imgdata.color.WBCT_Coeffs[nWB][4] = get2(); switch (nWB) { case 0: tWB = LIBRAW_WBI_Tungsten; break; case 4: tWB = LIBRAW_WBI_FL_W; break; case 6: tWB = LIBRAW_WBI_FL_D; break; case 8: tWB = LIBRAW_WBI_FineWeather; break; case 9: tWB = LIBRAW_WBI_Cloudy; break; case 10: tWB = LIBRAW_WBI_FL_N; break; case 11: tWB = LIBRAW_WBI_Shade; break; default: tWB = 0x100; } if (tWB != 0x100) imgdata.color.WB_Coeffs[tWB][1] = imgdata.color.WB_Coeffs[tWB][3] = imgdata.color.WBCT_Coeffs[nWB][2]; } if (tag == 0x20400121) { imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][2] = get2(); if (len == 4) { imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][1] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][3] = get2(); } } if (tag == 0x2040011f) { imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][3] = get2(); } if (tag == 0x30000120) { imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][2] = get2(); if (len == 2) { for (int i=0; i<256; i++) imgdata.color.WB_Coeffs[i][1] = imgdata.color.WB_Coeffs[i][3] = 0x100; } } if (tag == 0x30000121) { imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][2] = get2(); } if (tag == 0x30000122) { imgdata.color.WB_Coeffs[LIBRAW_WBI_FineWeather][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_FineWeather][2] = get2(); } if (tag == 0x30000123) { imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][2] = get2(); } if (tag == 0x30000124) { imgdata.color.WB_Coeffs[LIBRAW_WBI_Sunset][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Sunset][2] = get2(); } if (tag == 0x30000130) { imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][2] = get2(); } if (tag == 0x30000131) { imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][2] = get2(); } if (tag == 0x30000132) { imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][2] = get2(); } if (tag == 0x30000133) { imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_WW][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_WW][2] = get2(); } if((tag == 0x20400805) && (len == 2)) { imgdata.makernotes.olympus.OlympusSensorCalibration[0]=getreal(type); imgdata.makernotes.olympus.OlympusSensorCalibration[1]=getreal(type); FORC4 imgdata.color.linear_max[c] = imgdata.makernotes.olympus.OlympusSensorCalibration[0]; } if (tag == 0x20200401) { imgdata.other.FlashEC = getreal(type); } } fseek(ifp,_pos2,SEEK_SET); #endif if (tag == 0x11 && is_raw && !strncmp(make,"NIKON",5)) { fseek (ifp, get4()+base, SEEK_SET); parse_tiff_ifd (base); } if (tag == 0x14 && type == 7) { if (len == 2560) { fseek (ifp, 1248, SEEK_CUR); goto get2_256; } fread (buf, 1, 10, ifp); if (!strncmp(buf,"NRW ",4)) { fseek (ifp, strcmp(buf+4,"0100") ? 46:1546, SEEK_CUR); cam_mul[0] = get4() << 2; cam_mul[1] = get4() + get4(); cam_mul[2] = get4() << 2; } } if (tag == 0x15 && type == 2 && is_raw) fread (model, 64, 1, ifp); if (strstr(make,"PENTAX")) { if (tag == 0x1b) tag = 0x1018; if (tag == 0x1c) tag = 0x1017; } if (tag == 0x1d) { while ((c = fgetc(ifp)) && c != EOF) #ifdef LIBRAW_LIBRARY_BUILD { if ((!custom_serial) && (!isdigit(c))) { if ((strbuflen(model) == 3) && (!strcmp(model,"D50"))) { custom_serial = 34; } else { custom_serial = 96; } } #endif serial = serial*10 + (isdigit(c) ? c - '0' : c % 10); #ifdef LIBRAW_LIBRARY_BUILD } if (!imgdata.shootinginfo.BodySerial[0]) sprintf(imgdata.shootinginfo.BodySerial, "%d", serial); #endif } if (tag == 0x29 && type == 1) { // Canon PowerShot G9 c = wbi < 18 ? "012347800000005896"[wbi]-'0' : 0; fseek (ifp, 8 + c*32, SEEK_CUR); FORC4 cam_mul[c ^ (c >> 1) ^ 1] = get4(); } #ifndef LIBRAW_LIBRARY_BUILD if (tag == 0x3d && type == 3 && len == 4) FORC4 cblack[c ^ c >> 1] = get2() >> (14-tiff_bps); #endif if (tag == 0x81 && type == 4) { data_offset = get4(); fseek (ifp, data_offset + 41, SEEK_SET); raw_height = get2() * 2; raw_width = get2(); filters = 0x61616161; } if ((tag == 0x81 && type == 7) || (tag == 0x100 && type == 7) || (tag == 0x280 && type == 1)) { thumb_offset = ftell(ifp); thumb_length = len; } if (tag == 0x88 && type == 4 && (thumb_offset = get4())) thumb_offset += base; if (tag == 0x89 && type == 4) thumb_length = get4(); if (tag == 0x8c || tag == 0x96) meta_offset = ftell(ifp); if (tag == 0x97) { for (i=0; i < 4; i++) ver97 = ver97 * 10 + fgetc(ifp)-'0'; switch (ver97) { case 100: fseek (ifp, 68, SEEK_CUR); FORC4 cam_mul[(c >> 1) | ((c & 1) << 1)] = get2(); break; case 102: fseek (ifp, 6, SEEK_CUR); FORC4 cam_mul[c ^ (c >> 1)] = get2(); break; case 103: fseek (ifp, 16, SEEK_CUR); FORC4 cam_mul[c] = get2(); } if (ver97 >= 200) { if (ver97 != 205) fseek (ifp, 280, SEEK_CUR); fread (buf97, 324, 1, ifp); } } if (tag == 0xa1 && type == 7) { order = 0x4949; fseek (ifp, 140, SEEK_CUR); FORC3 cam_mul[c] = get4(); } if (tag == 0xa4 && type == 3) { fseek (ifp, wbi*48, SEEK_CUR); FORC3 cam_mul[c] = get2(); } if (tag == 0xa7) { // shutter count NikonKey = fgetc(ifp)^fgetc(ifp)^fgetc(ifp)^fgetc(ifp); if ( (unsigned) (ver97-200) < 17) { ci = xlat[0][serial & 0xff]; cj = xlat[1][NikonKey]; ck = 0x60; for (i=0; i < 324; i++) buf97[i] ^= (cj += ci * ck++); i = "66666>666;6A;:;55"[ver97-200] - '0'; FORC4 cam_mul[c ^ (c >> 1) ^ (i & 1)] = sget2 (buf97 + (i & -2) + c*2); } #ifdef LIBRAW_LIBRARY_BUILD if ((NikonLensDataVersion > 200) && lenNikonLensData) { if (custom_serial) { ci = xlat[0][custom_serial]; } else { ci = xlat[0][serial & 0xff]; } cj = xlat[1][NikonKey]; ck = 0x60; for (i = 0; i < lenNikonLensData; i++) table_buf[i] ^= (cj += ci * ck++); processNikonLensData(table_buf, lenNikonLensData); lenNikonLensData = 0; free(table_buf); } if (ver97 == 601) // Coolpix A { imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens; imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens; } #endif } if(tag == 0xb001 && type == 3) // Sony ModelID { unique_id = get2(); } if (tag == 0x200 && len == 3) shot_order = (get4(),get4()); if (tag == 0x200 && len == 4) FORC4 cblack[c ^ c >> 1] = get2(); if (tag == 0x201 && len == 4) FORC4 cam_mul[c ^ (c >> 1)] = get2(); if (tag == 0x220 && type == 7) meta_offset = ftell(ifp); if (tag == 0x401 && type == 4 && len == 4) FORC4 cblack[c ^ c >> 1] = get4(); #ifdef LIBRAW_LIBRARY_BUILD // not corrected for file bitcount, to be patched in open_datastream if (tag == 0x03d && strstr(make,"NIKON") && len == 4) { FORC4 cblack[c ^ c >> 1] = get2(); i = cblack[3]; FORC3 if(i>cblack[c]) i = cblack[c]; FORC4 cblack[c]-=i; black += i; } #endif if (tag == 0xe01) { /* Nikon Capture Note */ #ifdef LIBRAW_LIBRARY_BUILD int loopc = 0; #endif order = 0x4949; fseek (ifp, 22, SEEK_CUR); for (offset=22; offset+22 < len; offset += 22+i) { #ifdef LIBRAW_LIBRARY_BUILD if(loopc++>1024) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif tag = get4(); fseek (ifp, 14, SEEK_CUR); i = get4()-4; if (tag == 0x76a43207) flip = get2(); else fseek (ifp, i, SEEK_CUR); } } if (tag == 0xe80 && len == 256 && type == 7) { fseek (ifp, 48, SEEK_CUR); cam_mul[0] = get2() * 508 * 1.078 / 0x10000; cam_mul[2] = get2() * 382 * 1.173 / 0x10000; } if (tag == 0xf00 && type == 7) { if (len == 614) fseek (ifp, 176, SEEK_CUR); else if (len == 734 || len == 1502) fseek (ifp, 148, SEEK_CUR); else goto next; goto get2_256; } if ((tag == 0x1011 && len == 9) || tag == 0x20400200) for (i=0; i < 3; i++) { #ifdef LIBRAW_LIBRARY_BUILD if (!imgdata.makernotes.olympus.ColorSpace) { FORC3 cmatrix[i][c] = ((short) get2()) / 256.0; } else { FORC3 imgdata.color.ccm[i][c] = ((short) get2()) / 256.0; } #else FORC3 cmatrix[i][c] = ((short) get2()) / 256.0; #endif } if ((tag == 0x1012 || tag == 0x20400600) && len == 4) FORC4 cblack[c ^ c >> 1] = get2(); if (tag == 0x1017 || tag == 0x20400100) cam_mul[0] = get2() / 256.0; if (tag == 0x1018 || tag == 0x20400100) cam_mul[2] = get2() / 256.0; if (tag == 0x2011 && len == 2) { get2_256: order = 0x4d4d; cam_mul[0] = get2() / 256.0; cam_mul[2] = get2() / 256.0; } if ((tag | 0x70) == 0x2070 && (type == 4 || type == 13)) fseek (ifp, get4()+base, SEEK_SET); #ifdef LIBRAW_LIBRARY_BUILD // IB start if (tag == 0x2010) { INT64 _pos3 = ftell(ifp); parse_makernote(base, 0x2010); fseek(ifp,_pos3,SEEK_SET); } if ( ((tag == 0x2020) || (tag == 0x3000) || (tag == 0x2030) || (tag == 0x2031)) && ((type == 7) || (type == 13)) && !strncasecmp(make,"Olympus",7) ) { INT64 _pos3 = ftell(ifp); parse_makernote(base, tag); fseek(ifp,_pos3,SEEK_SET); } // IB end #endif if ((tag == 0x2020) && ((type == 7) || (type == 13)) && !strncmp(buf,"OLYMP",5)) parse_thumb_note (base, 257, 258); if (tag == 0x2040) parse_makernote (base, 0x2040); if (tag == 0xb028) { fseek (ifp, get4()+base, SEEK_SET); parse_thumb_note (base, 136, 137); } if (tag == 0x4001 && len > 500 && len < 100000) { i = len == 582 ? 50 : len == 653 ? 68 : len == 5120 ? 142 : 126; fseek (ifp, i, SEEK_CUR); FORC4 cam_mul[c ^ (c >> 1)] = get2(); for (i+=18; i <= len; i+=10) { get2(); FORC4 sraw_mul[c ^ (c >> 1)] = get2(); if (sraw_mul[1] == 1170) break; } } if(!strncasecmp(make,"Samsung",7)) { if (tag == 0xa020) // get the full Samsung encryption key for (i=0; i<11; i++) SamsungKey[i] = get4(); if (tag == 0xa021) // get and decode Samsung cam_mul array FORC4 cam_mul[c ^ (c >> 1)] = get4() - SamsungKey[c]; #ifdef LIBRAW_LIBRARY_BUILD if (tag == 0xa023) { imgdata.color.WB_Coeffs[LIBRAW_WBI_Ill_A][0] = get4() - SamsungKey[8]; imgdata.color.WB_Coeffs[LIBRAW_WBI_Ill_A][1] = get4() - SamsungKey[9]; imgdata.color.WB_Coeffs[LIBRAW_WBI_Ill_A][3] = get4() - SamsungKey[10]; imgdata.color.WB_Coeffs[LIBRAW_WBI_Ill_A][2] = get4() - SamsungKey[0]; if (imgdata.color.WB_Coeffs[LIBRAW_WBI_Ill_A][0] < (imgdata.color.WB_Coeffs[LIBRAW_WBI_Ill_A][1]>>1)) { imgdata.color.WB_Coeffs[LIBRAW_WBI_Ill_A][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Ill_A][1] >> 4; imgdata.color.WB_Coeffs[LIBRAW_WBI_Ill_A][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Ill_A][3] >> 4; } } if (tag == 0xa024) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_D65][c ^ (c >> 1)] = get4() - SamsungKey[c+1]; if (imgdata.color.WB_Coeffs[LIBRAW_WBI_D65][0] < (imgdata.color.WB_Coeffs[LIBRAW_WBI_D65][1]>>1)) { imgdata.color.WB_Coeffs[LIBRAW_WBI_D65][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_D65][1] >> 4; imgdata.color.WB_Coeffs[LIBRAW_WBI_D65][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_D65][3] >> 4; } } if (tag == 0xa025) imgdata.color.linear_max[0]= imgdata.color.linear_max[1]= imgdata.color.linear_max[2]= imgdata.color.linear_max[3]= get4() - SamsungKey[0]; if (tag == 0xa030 && len == 9) for (i=0; i < 3; i++) FORC3 imgdata.color.ccm[i][c] = (float)((short)((get4() + SamsungKey[i*3+c])))/256.0; #endif if (tag == 0xa031 && len == 9) // get and decode Samsung color matrix for (i=0; i < 3; i++) FORC3 cmatrix[i][c] = (float)((short)((get4() + SamsungKey[i*3+c])))/256.0; if (tag == 0xa028) FORC4 cblack[c ^ (c >> 1)] = get4() - SamsungKey[c]; } else { // Somebody else use 0xa021 and 0xa028? if (tag == 0xa021) FORC4 cam_mul[c ^ (c >> 1)] = get4(); if (tag == 0xa028) FORC4 cam_mul[c ^ (c >> 1)] -= get4(); } if (tag == 0x4021 && get4() && get4()) FORC4 cam_mul[c] = 1024; next: fseek (ifp, save, SEEK_SET); } quit: order = sorder; } /* Since the TIFF DateTime string has no timezone information, assume that the camera's clock was set to Universal Time. */ void CLASS get_timestamp (int reversed) { struct tm t; char str[20]; int i; str[19] = 0; if (reversed) for (i=19; i--; ) str[i] = fgetc(ifp); else fread (str, 19, 1, ifp); memset (&t, 0, sizeof t); if (sscanf (str, "%d:%d:%d %d:%d:%d", &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec) != 6) return; t.tm_year -= 1900; t.tm_mon -= 1; t.tm_isdst = -1; if (mktime(&t) > 0) timestamp = mktime(&t); } void CLASS parse_exif (int base) { unsigned kodak, entries, tag, type, len, save, c; double expo,ape; kodak = !strncmp(make,"EASTMAN",7) && tiff_nifds < 3; entries = get2(); if(!strncmp(make,"Hasselblad",10) && (tiff_nifds > 3) && (entries > 512)) return; #ifdef LIBRAW_LIBRARY_BUILD INT64 fsize = ifp->size(); #endif while (entries--) { tiff_get (base, &tag, &type, &len, &save); #ifdef LIBRAW_LIBRARY_BUILD INT64 savepos = ftell(ifp); if(len > 8 && savepos + len > fsize*2) continue; if(callbacks.exif_cb) { callbacks.exif_cb(callbacks.exifparser_data,tag,type,len,order,ifp); fseek(ifp,savepos,SEEK_SET); } #endif switch (tag) { #ifdef LIBRAW_LIBRARY_BUILD case 0xa405: // FocalLengthIn35mmFormat imgdata.lens.FocalLengthIn35mmFormat = get2(); break; case 0xa431: // BodySerialNumber stmread(imgdata.shootinginfo.BodySerial, len, ifp); break; case 0xa432: // LensInfo, 42034dec, Lens Specification per EXIF standard imgdata.lens.MinFocal = getreal(type); imgdata.lens.MaxFocal = getreal(type); imgdata.lens.MaxAp4MinFocal = getreal(type); imgdata.lens.MaxAp4MaxFocal = getreal(type); break; case 0xa435: // LensSerialNumber stmread(imgdata.lens.LensSerial, len, ifp); break; case 0xc630: // DNG LensInfo, Lens Specification per EXIF standard imgdata.lens.dng.MinFocal = getreal(type); imgdata.lens.dng.MaxFocal = getreal(type); imgdata.lens.dng.MaxAp4MinFocal = getreal(type); imgdata.lens.dng.MaxAp4MaxFocal = getreal(type); break; case 0xa433: // LensMake stmread(imgdata.lens.LensMake, len, ifp); break; case 0xa434: // LensModel stmread(imgdata.lens.Lens, len, ifp); if (!strncmp(imgdata.lens.Lens, "----", 4)) imgdata.lens.Lens[0] = 0; break; case 0x9205: imgdata.lens.EXIF_MaxAp = libraw_powf64(2.0f, (getreal(type) / 2.0f)); break; #endif case 33434: tiff_ifd[tiff_nifds-1].t_shutter = shutter = getreal(type); break; case 33437: aperture = getreal(type); break; // 0x829d FNumber case 34855: iso_speed = get2(); break; case 34866: if (iso_speed == 0xffff && (!strncasecmp(make, "SONY",4) || !strncasecmp(make, "CANON",5))) iso_speed = getreal(type); break; case 36867: case 36868: get_timestamp(0); break; case 37377: if ((expo = -getreal(type)) < 128 && shutter == 0.) tiff_ifd[tiff_nifds-1].t_shutter = shutter = libraw_powf64(2.0, expo); break; case 37378: // 0x9202 ApertureValue if ((fabs(ape = getreal(type))<256.0) && (!aperture)) aperture = libraw_powf64(2.0, ape/2); break; case 37385: flash_used = getreal(type); break; case 37386: focal_len = getreal(type); break; case 37500: // tag 0x927c #ifdef LIBRAW_LIBRARY_BUILD if (((make[0] == '\0') && (!strncmp(model, "ov5647",6))) || ((!strncmp(make, "RaspberryPi",11)) && (!strncmp(model, "RP_OV5647",9))) || ((!strncmp(make, "RaspberryPi",11)) && (!strncmp(model, "RP_imx219",9)))) { char mn_text[512]; char* pos; char ccms[512]; ushort l; float num; fgets(mn_text, len, ifp); pos = strstr(mn_text, "gain_r="); if (pos) cam_mul[0] = atof(pos+7); pos = strstr(mn_text, "gain_b="); if (pos) cam_mul[2] = atof(pos+7); if ((cam_mul[0] > 0.001f) && (cam_mul[2] > 0.001f)) cam_mul[1] = cam_mul[3] = 1.0f; else cam_mul[0] = cam_mul[2] = 0.0f; pos = strstr(mn_text, "ccm=") + 4; l = strstr(pos, " ") - pos; memcpy (ccms, pos, l); ccms[l] = '\0'; pos = strtok (ccms, ","); for (l=0; l<4; l++) { num = 0.0; for (c=0; c<3; c++) { imgdata.color.ccm[l][c] = (float)atoi(pos); num += imgdata.color.ccm[l][c]; pos = strtok (NULL, ","); } if (num > 0.01) FORC3 imgdata.color.ccm[l][c] = imgdata.color.ccm[l][c] / num; } } else #endif parse_makernote (base, 0); break; case 40962: if (kodak) raw_width = get4(); break; case 40963: if (kodak) raw_height = get4(); break; case 41730: if (get4() == 0x20002) for (exif_cfa=c=0; c < 8; c+=2) exif_cfa |= fgetc(ifp) * 0x01010101 << c; } fseek (ifp, save, SEEK_SET); } } #ifdef LIBRAW_LIBRARY_BUILD void CLASS parse_gps_libraw(int base) { unsigned entries, tag, type, len, save, c; entries = get2(); if (entries > 200) return; if (entries > 0) imgdata.other.parsed_gps.gpsparsed = 1; while (entries--) { tiff_get(base, &tag, &type, &len, &save); if(len > 1024) continue; // no GPS tags are 1k or larger switch (tag) { case 1: imgdata.other.parsed_gps.latref = getc(ifp); break; case 3: imgdata.other.parsed_gps.longref = getc(ifp); break; case 5: imgdata.other.parsed_gps.altref = getc(ifp); break; case 2: if (len == 3) FORC(3) imgdata.other.parsed_gps.latitude[c] = getreal(type); break; case 4: if (len == 3) FORC(3) imgdata.other.parsed_gps.longtitude[c] = getreal(type); break; case 7: if (len == 3) FORC(3) imgdata.other.parsed_gps.gpstimestamp[c] = getreal(type); break; case 6: imgdata.other.parsed_gps.altitude = getreal(type); break; case 9: imgdata.other.parsed_gps.gpsstatus = getc(ifp); break; } fseek(ifp, save, SEEK_SET); } } #endif void CLASS parse_gps (int base) { unsigned entries, tag, type, len, save, c; entries = get2(); while (entries--) { tiff_get (base, &tag, &type, &len, &save); if(len > 1024) continue; // no GPS tags are 1k or larger switch (tag) { case 1: case 3: case 5: gpsdata[29+tag/2] = getc(ifp); break; case 2: case 4: case 7: FORC(6) gpsdata[tag/3*6+c] = get4(); break; case 6: FORC(2) gpsdata[18+c] = get4(); break; case 18: case 29: fgets ((char *) (gpsdata+14+tag/3), MIN(len,12), ifp); } fseek (ifp, save, SEEK_SET); } } void CLASS romm_coeff (float romm_cam[3][3]) { static const float rgb_romm[3][3] = /* ROMM == Kodak ProPhoto */ { { 2.034193, -0.727420, -0.306766 }, { -0.228811, 1.231729, -0.002922 }, { -0.008565, -0.153273, 1.161839 } }; int i, j, k; for (i=0; i < 3; i++) for (j=0; j < 3; j++) for (cmatrix[i][j] = k=0; k < 3; k++) cmatrix[i][j] += rgb_romm[i][k] * romm_cam[k][j]; } void CLASS parse_mos (int offset) { char data[40]; int skip, from, i, c, neut[4], planes=0, frot=0; static const char *mod[] = { "","DCB2","Volare","Cantare","CMost","Valeo 6","Valeo 11","Valeo 22", "Valeo 11p","Valeo 17","","Aptus 17","Aptus 22","Aptus 75","Aptus 65", "Aptus 54S","Aptus 65S","Aptus 75S","AFi 5","AFi 6","AFi 7", "AFi-II 7","Aptus-II 7","","Aptus-II 6","","","Aptus-II 10","Aptus-II 5", "","","","","Aptus-II 10R","Aptus-II 8","","Aptus-II 12","","AFi-II 12" }; float romm_cam[3][3]; fseek (ifp, offset, SEEK_SET); while (1) { if (get4() != 0x504b5453) break; get4(); fread (data, 1, 40, ifp); skip = get4(); from = ftell(ifp); // IB start #ifdef LIBRAW_LIBRARY_BUILD if (!strcmp(data,"CameraObj_camera_type")) { stmread(imgdata.lens.makernotes.body, skip, ifp); } if (!strcmp(data,"back_serial_number")) { char buffer [sizeof(imgdata.shootinginfo.BodySerial)]; char *words[4]; int nwords; stmread(buffer, skip, ifp); nwords = getwords(buffer, words, 4,sizeof(imgdata.shootinginfo.BodySerial)); strcpy (imgdata.shootinginfo.BodySerial, words[0]); } if (!strcmp(data,"CaptProf_serial_number")) { char buffer [sizeof(imgdata.shootinginfo.InternalBodySerial)]; char *words[4]; int nwords; stmread(buffer, skip, ifp); nwords = getwords(buffer, words, 4,sizeof(imgdata.shootinginfo.InternalBodySerial)); strcpy (imgdata.shootinginfo.InternalBodySerial, words[0]); } #endif // IB end if (!strcmp(data,"JPEG_preview_data")) { thumb_offset = from; thumb_length = skip; } if (!strcmp(data,"icc_camera_profile")) { profile_offset = from; profile_length = skip; } if (!strcmp(data,"ShootObj_back_type")) { fscanf (ifp, "%d", &i); if ((unsigned) i < sizeof mod / sizeof (*mod)) strcpy (model, mod[i]); } if (!strcmp(data,"icc_camera_to_tone_matrix")) { for (i=0; i < 9; i++) ((float *)romm_cam)[i] = int_to_float(get4()); romm_coeff (romm_cam); } if (!strcmp(data,"CaptProf_color_matrix")) { for (i=0; i < 9; i++) fscanf (ifp, "%f", (float *)romm_cam + i); romm_coeff (romm_cam); } if (!strcmp(data,"CaptProf_number_of_planes")) fscanf (ifp, "%d", &planes); if (!strcmp(data,"CaptProf_raw_data_rotation")) fscanf (ifp, "%d", &flip); if (!strcmp(data,"CaptProf_mosaic_pattern")) FORC4 { fscanf (ifp, "%d", &i); if (i == 1) frot = c ^ (c >> 1); } if (!strcmp(data,"ImgProf_rotation_angle")) { fscanf (ifp, "%d", &i); flip = i - flip; } if (!strcmp(data,"NeutObj_neutrals") && !cam_mul[0]) { FORC4 fscanf (ifp, "%d", neut+c); FORC3 cam_mul[c] = (float) neut[0] / neut[c+1]; } if (!strcmp(data,"Rows_data")) load_flags = get4(); parse_mos (from); fseek (ifp, skip+from, SEEK_SET); } if (planes) filters = (planes == 1) * 0x01010101 * (uchar) "\x94\x61\x16\x49"[(flip/90 + frot) & 3]; } void CLASS linear_table (unsigned len) { int i; if (len > 0x10000) len = 0x10000; read_shorts (curve, len); for (i=len; i < 0x10000; i++) curve[i] = curve[i-1]; maximum = curve[len<0x1000?0xfff:len-1]; } #ifdef LIBRAW_LIBRARY_BUILD void CLASS Kodak_WB_0x08tags (int wb, unsigned type) { float mul[3]={1,1,1}, num, mul2; int c; FORC3 mul[c] = (num=getreal(type))==0 ? 1 : num; imgdata.color.WB_Coeffs[wb][1] = imgdata.color.WB_Coeffs[wb][3] = mul[1]; mul2 = mul[1] * mul[1]; imgdata.color.WB_Coeffs[wb][0] = mul2 / mul[0]; imgdata.color.WB_Coeffs[wb][2] = mul2 / mul[2]; return; } /* Thanks to Alexey Danilchenko for wb as-shot parsing code */ void CLASS parse_kodak_ifd (int base) { unsigned entries, tag, type, len, save; int i, c, wbi=-2; float mul[3]={1,1,1}, num; static const int wbtag[] = { 64037,64040,64039,64041,-1,-1,64042 }; entries = get2(); if (entries > 1024) return; INT64 fsize = ifp->size(); while (entries--) { tiff_get (base, &tag, &type, &len, &save); INT64 savepos = ftell(ifp); if(len > 8 && len + savepos > 2*fsize) continue; if(callbacks.exif_cb) { callbacks.exif_cb(callbacks.exifparser_data,tag | 0x20000,type,len,order,ifp); fseek(ifp,savepos,SEEK_SET); } if (tag == 1011) imgdata.other.FlashEC = getreal(type); if (tag == 1020) wbi = getint(type); if (tag == 1021 && len == 72) { /* WB set in software */ fseek (ifp, 40, SEEK_CUR); FORC3 cam_mul[c] = 2048.0 / fMAX(1.0f,get2()); wbi = -2; } if (tag == 0x0848) Kodak_WB_0x08tags(LIBRAW_WBI_Daylight, type); if (tag == 0x0849) Kodak_WB_0x08tags(LIBRAW_WBI_Tungsten, type); if (tag == 0x084a) Kodak_WB_0x08tags(LIBRAW_WBI_Fluorescent, type); if (tag == 0x084b) Kodak_WB_0x08tags(LIBRAW_WBI_Flash, type); if (tag == 0x0e93) imgdata.color.linear_max[0] = imgdata.color.linear_max[1] = imgdata.color.linear_max[2] = imgdata.color.linear_max[3] = get2(); if (tag == 0x09ce) stmread(imgdata.shootinginfo.InternalBodySerial,len, ifp); if (tag == 0xfa00) stmread(imgdata.shootinginfo.BodySerial, len, ifp); if (tag == 0xfa27) { FORC3 imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][c] = get4(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][1]; } if (tag == 0xfa28) { FORC3 imgdata.color.WB_Coeffs[LIBRAW_WBI_Fluorescent][c] = get4(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Fluorescent][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Fluorescent][1]; } if (tag == 0xfa29) { FORC3 imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][c] = get4(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][1]; } if (tag == 0xfa2a) { FORC3 imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][c] = get4(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][1]; } if (tag == 2120 + wbi || (wbi<0 && tag == 2125)) /* use Auto WB if illuminant index is not set */ { FORC3 mul[c] = (num=getreal(type))==0 ? 1 : num; FORC3 cam_mul[c] = mul[1] / mul[c]; /* normalise against green */ } if (tag == 2317) linear_table (len); if (tag == 0x903) iso_speed = getreal(type); //if (tag == 6020) iso_speed = getint(type); if (tag == 64013) wbi = fgetc(ifp); if ((unsigned) wbi < 7 && tag == wbtag[wbi]) FORC3 cam_mul[c] = get4(); if (tag == 64019) width = getint(type); if (tag == 64020) height = (getint(type)+1) & -2; fseek (ifp, save, SEEK_SET); } } #else void CLASS parse_kodak_ifd (int base) { unsigned entries, tag, type, len, save; int i, c, wbi=-2, wbtemp=6500; float mul[3]={1,1,1}, num; static const int wbtag[] = { 64037,64040,64039,64041,-1,-1,64042 }; entries = get2(); if (entries > 1024) return; while (entries--) { tiff_get (base, &tag, &type, &len, &save); if (tag == 1020) wbi = getint(type); if (tag == 1021 && len == 72) { /* WB set in software */ fseek (ifp, 40, SEEK_CUR); FORC3 cam_mul[c] = 2048.0 / fMAX(1.0,get2()); wbi = -2; } if (tag == 2118) wbtemp = getint(type); if (tag == 2120 + wbi && wbi >= 0) FORC3 cam_mul[c] = 2048.0 / fMAX(1.0,getreal(type)); if (tag == 2130 + wbi) FORC3 mul[c] = getreal(type); if (tag == 2140 + wbi && wbi >= 0) FORC3 { for (num=i=0; i < 4; i++) num += getreal(type) * pow (wbtemp/100.0, i); cam_mul[c] = 2048 / fMAX(1.0,(num * mul[c])); } if (tag == 2317) linear_table (len); if (tag == 6020) iso_speed = getint(type); if (tag == 64013) wbi = fgetc(ifp); if ((unsigned) wbi < 7 && tag == wbtag[wbi]) FORC3 cam_mul[c] = get4(); if (tag == 64019) width = getint(type); if (tag == 64020) height = (getint(type)+1) & -2; fseek (ifp, save, SEEK_SET); } } #endif //@end COMMON void CLASS parse_minolta (int base); int CLASS parse_tiff (int base); //@out COMMON int CLASS parse_tiff_ifd (int base) { unsigned entries, tag, type, len, plen=16, save; int ifd, use_cm=0, cfa, i, j, c, ima_len=0; char *cbuf, *cp; uchar cfa_pat[16], cfa_pc[] = { 0,1,2,3 }, tab[256]; double fm[3][4], cc[4][4], cm[4][3], cam_xyz[4][3], num; double ab[]={ 1,1,1,1 }, asn[] = { 0,0,0,0 }, xyz[] = { 1,1,1 }; unsigned sony_curve[] = { 0,0,0,0,0,4095 }; unsigned *buf, sony_offset=0, sony_length=0, sony_key=0; struct jhead jh; int pana_raw = 0; #ifndef LIBRAW_LIBRARY_BUILD FILE *sfp; #endif if (tiff_nifds >= sizeof tiff_ifd / sizeof tiff_ifd[0]) return 1; ifd = tiff_nifds++; for (j=0; j < 4; j++) for (i=0; i < 4; i++) cc[j][i] = i == j; entries = get2(); if (entries > 512) return 1; #ifdef LIBRAW_LIBRARY_BUILD INT64 fsize = ifp->size(); #endif while (entries--) { tiff_get (base, &tag, &type, &len, &save); #ifdef LIBRAW_LIBRARY_BUILD INT64 savepos = ftell(ifp); if(len > 8 && len + savepos > fsize*2) continue; // skip tag pointing out of 2xfile if(callbacks.exif_cb) { callbacks.exif_cb(callbacks.exifparser_data,tag|(pana_raw?0x30000:0),type,len,order,ifp); fseek(ifp,savepos,SEEK_SET); } #endif #ifdef LIBRAW_LIBRARY_BUILD if (!strncasecmp(make, "SONY", 4) || (!strncasecmp(make, "Hasselblad", 10) && (!strncasecmp(model, "Stellar", 7) || !strncasecmp(model, "Lunar", 5) || !strncasecmp(model, "HV",2)))) { switch (tag) { case 0x7300: // SR2 black level for (int i = 0; i < 4 && i < len; i++) cblack[i] = get2(); break; case 0x7480: case 0x7820: FORC3 imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][c] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][1]; break; case 0x7481: case 0x7821: FORC3 imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][c] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][1]; break; case 0x7482: case 0x7822: FORC3 imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][c] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][1]; break; case 0x7483: case 0x7823: FORC3 imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][c] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][1]; break; case 0x7484: case 0x7824: imgdata.color.WBCT_Coeffs[0][0] = 4500; FORC3 imgdata.color.WBCT_Coeffs[0][c+1] = get2(); imgdata.color.WBCT_Coeffs[0][4] = imgdata.color.WBCT_Coeffs[0][2]; break; case 0x7486: FORC3 imgdata.color.WB_Coeffs[LIBRAW_WBI_Fluorescent][c] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Fluorescent][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Fluorescent][1]; break; case 0x7825: FORC3 imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][c] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][1]; break; case 0x7826: FORC3 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][c] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][1]; break; case 0x7827: FORC3 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][c] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][1]; break; case 0x7828: FORC3 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][c] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][1]; break; case 0x7829: FORC3 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_L][c] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_L][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_L][1]; break; case 0x782a: imgdata.color.WBCT_Coeffs[1][0] = 8500; FORC3 imgdata.color.WBCT_Coeffs[1][c+1] = get2(); imgdata.color.WBCT_Coeffs[1][4] = imgdata.color.WBCT_Coeffs[1][2]; break; case 0x782b: imgdata.color.WBCT_Coeffs[2][0] = 6000; FORC3 imgdata.color.WBCT_Coeffs[2][c+1] = get2(); imgdata.color.WBCT_Coeffs[2][4] = imgdata.color.WBCT_Coeffs[2][2]; break; case 0x782c: imgdata.color.WBCT_Coeffs[3][0] = 3200; FORC3 imgdata.color.WB_Coeffs[LIBRAW_WBI_StudioTungsten][c] = imgdata.color.WBCT_Coeffs[3][c+1] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_StudioTungsten][3] = imgdata.color.WBCT_Coeffs[3][4] = imgdata.color.WB_Coeffs[LIBRAW_WBI_StudioTungsten][1]; break; case 0x782d: imgdata.color.WBCT_Coeffs[4][0] = 2500; FORC3 imgdata.color.WBCT_Coeffs[4][c+1] = get2(); imgdata.color.WBCT_Coeffs[4][4] = imgdata.color.WBCT_Coeffs[4][2]; break; case 0x787f: FORC3 imgdata.color.linear_max[c] = get2(); imgdata.color.linear_max[3] = imgdata.color.linear_max[1]; break; } } #endif switch (tag) { case 1: if(len==4) pana_raw = get4(); break; case 5: width = get2(); break; case 6: height = get2(); break; case 7: width += get2(); break; case 9: if ((i = get2())) filters = i; #ifdef LIBRAW_LIBRARY_BUILD if(pana_raw && len == 1 && type ==3) pana_black[3]+=i; #endif break; case 8: case 10: #ifdef LIBRAW_LIBRARY_BUILD if(pana_raw && len == 1 && type ==3) pana_black[3]+=get2(); #endif break; case 14: case 15: case 16: #ifdef LIBRAW_LIBRARY_BUILD if(pana_raw) { imgdata.color.linear_max[tag-14] = get2(); if (tag == 15 ) imgdata.color.linear_max[3] = imgdata.color.linear_max[1]; } #endif break; case 17: case 18: if (type == 3 && len == 1) cam_mul[(tag-17)*2] = get2() / 256.0; break; #ifdef LIBRAW_LIBRARY_BUILD case 19: if(pana_raw) { ushort nWB, cnt, tWB; nWB = get2(); if (nWB > 0x100) break; for (cnt=0; cnt 0x100) break; for (cnt=0; cnt 12) break; load_raw = &CLASS packed_load_raw; load_flags = get4() ? 24:80; break; case 259: /* Compression */ tiff_ifd[ifd].comp = getint(type); break; case 262: /* PhotometricInterpretation */ tiff_ifd[ifd].phint = get2(); break; case 270: /* ImageDescription */ fread (desc, 512, 1, ifp); break; case 271: /* Make */ fgets (make, 64, ifp); break; case 272: /* Model */ fgets (model, 64, ifp); break; #ifdef LIBRAW_LIBRARY_BUILD case 278: tiff_ifd[ifd].rows_per_strip = getint(type); break; #endif case 280: /* Panasonic RW2 offset */ if (type != 4) break; load_raw = &CLASS panasonic_load_raw; load_flags = 0x2008; case 273: /* StripOffset */ #ifdef LIBRAW_LIBRARY_BUILD if(len > 1 && len < 16384) { off_t sav = ftell(ifp); tiff_ifd[ifd].strip_offsets = (int*)calloc(len,sizeof(int)); tiff_ifd[ifd].strip_offsets_count = len; for(int i=0; i< len; i++) tiff_ifd[ifd].strip_offsets[i]=get4()+base; fseek(ifp,sav,SEEK_SET); // restore position } /* fallback */ #endif case 513: /* JpegIFOffset */ case 61447: tiff_ifd[ifd].offset = get4()+base; if (!tiff_ifd[ifd].bps && tiff_ifd[ifd].offset > 0) { fseek (ifp, tiff_ifd[ifd].offset, SEEK_SET); if (ljpeg_start (&jh, 1)) { tiff_ifd[ifd].comp = 6; tiff_ifd[ifd].t_width = jh.wide; tiff_ifd[ifd].t_height = jh.high; tiff_ifd[ifd].bps = jh.bits; tiff_ifd[ifd].samples = jh.clrs; if (!(jh.sraw || (jh.clrs & 1))) tiff_ifd[ifd].t_width *= jh.clrs; if ((tiff_ifd[ifd].t_width > 4*tiff_ifd[ifd].t_height) & ~jh.clrs) { tiff_ifd[ifd].t_width /= 2; tiff_ifd[ifd].t_height *= 2; } i = order; parse_tiff (tiff_ifd[ifd].offset + 12); order = i; } } break; case 274: /* Orientation */ tiff_ifd[ifd].t_flip = "50132467"[get2() & 7]-'0'; break; case 277: /* SamplesPerPixel */ tiff_ifd[ifd].samples = getint(type) & 7; break; case 279: /* StripByteCounts */ #ifdef LIBRAW_LIBRARY_BUILD if(len > 1 && len < 16384) { off_t sav = ftell(ifp); tiff_ifd[ifd].strip_byte_counts = (int*)calloc(len,sizeof(int)); tiff_ifd[ifd].strip_byte_counts_count = len; for(int i=0; i< len; i++) tiff_ifd[ifd].strip_byte_counts[i]=get4(); fseek(ifp,sav,SEEK_SET); // restore position } /* fallback */ #endif case 514: case 61448: tiff_ifd[ifd].bytes = get4(); break; case 61454: FORC3 cam_mul[(4-c) % 3] = getint(type); break; case 305: case 11: /* Software */ fgets (software, 64, ifp); if (!strncmp(software,"Adobe",5) || !strncmp(software,"dcraw",5) || !strncmp(software,"UFRaw",5) || !strncmp(software,"Bibble",6) || !strcmp (software,"Digital Photo Professional")) is_raw = 0; break; case 306: /* DateTime */ get_timestamp(0); break; case 315: /* Artist */ fread (artist, 64, 1, ifp); break; case 317: tiff_ifd[ifd].predictor = getint(type); break; case 322: /* TileWidth */ tiff_ifd[ifd].t_tile_width = getint(type); break; case 323: /* TileLength */ tiff_ifd[ifd].t_tile_length = getint(type); break; case 324: /* TileOffsets */ tiff_ifd[ifd].offset = len > 1 ? ftell(ifp) : get4(); if (len == 1) tiff_ifd[ifd].t_tile_width = tiff_ifd[ifd].t_tile_length = 0; if (len == 4) { load_raw = &CLASS sinar_4shot_load_raw; is_raw = 5; } break; case 325: tiff_ifd[ifd].bytes = len > 1 ? ftell(ifp): get4(); break; case 330: /* SubIFDs */ if (!strcmp(model,"DSLR-A100") && tiff_ifd[ifd].t_width == 3872) { load_raw = &CLASS sony_arw_load_raw; data_offset = get4()+base; ifd++; #ifdef LIBRAW_LIBRARY_BUILD if (ifd >= sizeof tiff_ifd / sizeof tiff_ifd[0]) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif break; } #ifdef LIBRAW_LIBRARY_BUILD if (!strncmp(make,"Hasselblad",10) && libraw_internal_data.unpacker_data.hasselblad_parser_flag) { fseek (ifp, ftell(ifp)+4, SEEK_SET); fseek (ifp, get4()+base, SEEK_SET); parse_tiff_ifd (base); break; } #endif if(len > 1000) len=1000; /* 1000 SubIFDs is enough */ while (len--) { i = ftell(ifp); fseek (ifp, get4()+base, SEEK_SET); if (parse_tiff_ifd (base)) break; fseek (ifp, i+4, SEEK_SET); } break; case 339: tiff_ifd[ifd].sample_format = getint(type); break; case 400: strcpy (make, "Sarnoff"); maximum = 0xfff; break; #ifdef LIBRAW_LIBRARY_BUILD case 700: if((type == 1 || type == 2 || type == 6 || type == 7) && len > 1 && len < 5100000) { xmpdata = (char*)malloc(xmplen = len+1); fread(xmpdata,len,1,ifp); xmpdata[len]=0; } break; #endif case 28688: FORC4 sony_curve[c+1] = get2() >> 2 & 0xfff; for (i=0; i < 5; i++) for (j = sony_curve[i]+1; j <= sony_curve[i+1]; j++) curve[j] = curve[j-1] + (1 << i); break; case 29184: sony_offset = get4(); break; case 29185: sony_length = get4(); break; case 29217: sony_key = get4(); break; case 29264: parse_minolta (ftell(ifp)); raw_width = 0; break; case 29443: FORC4 cam_mul[c ^ (c < 2)] = get2(); break; case 29459: FORC4 cam_mul[c] = get2(); i = (cam_mul[1] == 1024 && cam_mul[2] == 1024) << 1; SWAP (cam_mul[i],cam_mul[i+1]) break; #ifdef LIBRAW_LIBRARY_BUILD case 30720: // Sony matrix, Sony_SR2SubIFD_0x7800 for (i=0; i < 3; i++) { float num = 0.0; for (c=0; c<3; c++) { imgdata.color.ccm[i][c] = (float) ((short)get2()); num += imgdata.color.ccm[i][c]; } if (num > 0.01) FORC3 imgdata.color.ccm[i][c] = imgdata.color.ccm[i][c] / num; } break; #endif case 29456: // Sony black level, Sony_SR2SubIFD_0x7310, no more needs to be divided by 4 FORC4 cblack[c ^ c >> 1] = get2(); i = cblack[3]; FORC3 if(i>cblack[c]) i = cblack[c]; FORC4 cblack[c]-=i; black = i; #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr, _("...Sony black: %u cblack: %u %u %u %u\n"),black, cblack[0],cblack[1],cblack[2], cblack[3]); #endif break; case 33405: /* Model2 */ fgets (model2, 64, ifp); break; case 33421: /* CFARepeatPatternDim */ if (get2() == 6 && get2() == 6) filters = 9; break; case 33422: /* CFAPattern */ if (filters == 9) { FORC(36) ((char *)xtrans)[c] = fgetc(ifp) & 3; break; } case 64777: /* Kodak P-series */ if(len == 36) { filters = 9; colors = 3; FORC(36) xtrans[0][c] = fgetc(ifp) & 3; } else if(len > 0) { if ((plen=len) > 16) plen = 16; fread (cfa_pat, 1, plen, ifp); for (colors=cfa=i=0; i < plen && colors < 4; i++) { colors += !(cfa & (1 << cfa_pat[i])); cfa |= 1 << cfa_pat[i]; } if (cfa == 070) memcpy (cfa_pc,"\003\004\005",3); /* CMY */ if (cfa == 072) memcpy (cfa_pc,"\005\003\004\001",4); /* GMCY */ goto guess_cfa_pc; } break; case 33424: case 65024: fseek (ifp, get4()+base, SEEK_SET); parse_kodak_ifd (base); break; case 33434: /* ExposureTime */ tiff_ifd[ifd].t_shutter = shutter = getreal(type); break; case 33437: /* FNumber */ aperture = getreal(type); break; #ifdef LIBRAW_LIBRARY_BUILD // IB start case 0xa405: // FocalLengthIn35mmFormat imgdata.lens.FocalLengthIn35mmFormat = get2(); break; case 0xa431: // BodySerialNumber case 0xc62f: stmread(imgdata.shootinginfo.BodySerial, len, ifp); break; case 0xa432: // LensInfo, 42034dec, Lens Specification per EXIF standard imgdata.lens.MinFocal = getreal(type); imgdata.lens.MaxFocal = getreal(type); imgdata.lens.MaxAp4MinFocal = getreal(type); imgdata.lens.MaxAp4MaxFocal = getreal(type); break; case 0xa435: // LensSerialNumber stmread(imgdata.lens.LensSerial, len, ifp); break; case 0xc630: // DNG LensInfo, Lens Specification per EXIF standard imgdata.lens.MinFocal = getreal(type); imgdata.lens.MaxFocal = getreal(type); imgdata.lens.MaxAp4MinFocal = getreal(type); imgdata.lens.MaxAp4MaxFocal = getreal(type); break; case 0xa433: // LensMake stmread(imgdata.lens.LensMake, len, ifp); break; case 0xa434: // LensModel stmread(imgdata.lens.Lens, len, ifp); if (!strncmp(imgdata.lens.Lens, "----", 4)) imgdata.lens.Lens[0] = 0; break; case 0x9205: imgdata.lens.EXIF_MaxAp = libraw_powf64(2.0f, (getreal(type) / 2.0f)); break; // IB end #endif case 34306: /* Leaf white balance */ FORC4 cam_mul[c ^ 1] = 4096.0 / get2(); break; case 34307: /* Leaf CatchLight color matrix */ fread (software, 1, 7, ifp); if (strncmp(software,"MATRIX",6)) break; colors = 4; for (raw_color = i=0; i < 3; i++) { FORC4 fscanf (ifp, "%f", &rgb_cam[i][c^1]); if (!use_camera_wb) continue; num = 0; FORC4 num += rgb_cam[i][c]; FORC4 rgb_cam[i][c] /= MAX(1,num); } break; case 34310: /* Leaf metadata */ parse_mos (ftell(ifp)); case 34303: strcpy (make, "Leaf"); break; case 34665: /* EXIF tag */ fseek (ifp, get4()+base, SEEK_SET); parse_exif (base); break; case 34853: /* GPSInfo tag */ { unsigned pos; fseek(ifp, pos = (get4() + base), SEEK_SET); parse_gps(base); #ifdef LIBRAW_LIBRARY_BUILD fseek(ifp, pos, SEEK_SET); parse_gps_libraw(base); #endif } break; case 34675: /* InterColorProfile */ case 50831: /* AsShotICCProfile */ profile_offset = ftell(ifp); profile_length = len; break; case 37122: /* CompressedBitsPerPixel */ kodak_cbpp = get4(); break; case 37386: /* FocalLength */ focal_len = getreal(type); break; case 37393: /* ImageNumber */ shot_order = getint(type); break; case 37400: /* old Kodak KDC tag */ for (raw_color = i=0; i < 3; i++) { getreal(type); FORC3 rgb_cam[i][c] = getreal(type); } break; case 40976: strip_offset = get4(); switch (tiff_ifd[ifd].comp) { case 32770: load_raw = &CLASS samsung_load_raw; break; case 32772: load_raw = &CLASS samsung2_load_raw; break; case 32773: load_raw = &CLASS samsung3_load_raw; break; } break; case 46275: /* Imacon tags */ strcpy (make, "Imacon"); data_offset = ftell(ifp); ima_len = len; break; case 46279: if (!ima_len) break; fseek (ifp, 38, SEEK_CUR); case 46274: fseek (ifp, 40, SEEK_CUR); raw_width = get4(); raw_height = get4(); left_margin = get4() & 7; width = raw_width - left_margin - (get4() & 7); top_margin = get4() & 7; height = raw_height - top_margin - (get4() & 7); if (raw_width == 7262 && ima_len == 234317952 ) { height = 5412; width = 7216; left_margin = 7; filters=0; } else if (raw_width == 7262) { height = 5444; width = 7244; left_margin = 7; } fseek (ifp, 52, SEEK_CUR); FORC3 cam_mul[c] = getreal(11); fseek (ifp, 114, SEEK_CUR); flip = (get2() >> 7) * 90; if (width * height * 6 == ima_len) { if (flip % 180 == 90) SWAP(width,height); raw_width = width; raw_height = height; left_margin = top_margin = filters = flip = 0; } sprintf (model, "Ixpress %d-Mp", height*width/1000000); load_raw = &CLASS imacon_full_load_raw; if (filters) { if (left_margin & 1) filters = 0x61616161; load_raw = &CLASS unpacked_load_raw; } maximum = 0xffff; break; case 50454: /* Sinar tag */ case 50455: if (len < 1 || len > 2560000 || !(cbuf = (char *) malloc(len))) break; #ifndef LIBRAW_LIBRARY_BUILD fread (cbuf, 1, len, ifp); #else if(fread (cbuf, 1, len, ifp) != len) throw LIBRAW_EXCEPTION_IO_CORRUPT; // cbuf to be free'ed in recycle #endif cbuf[len-1] = 0; for (cp = cbuf-1; cp && cp < cbuf+len; cp = strchr(cp,'\n')) if (!strncmp (++cp,"Neutral ",8)) sscanf (cp+8, "%f %f %f", cam_mul, cam_mul+1, cam_mul+2); free (cbuf); break; case 50458: if (!make[0]) strcpy (make, "Hasselblad"); break; case 50459: /* Hasselblad tag */ #ifdef LIBRAW_LIBRARY_BUILD libraw_internal_data.unpacker_data.hasselblad_parser_flag=1; #endif i = order; j = ftell(ifp); c = tiff_nifds; order = get2(); fseek (ifp, j+(get2(),get4()), SEEK_SET); parse_tiff_ifd (j); maximum = 0xffff; tiff_nifds = c; order = i; break; case 50706: /* DNGVersion */ FORC4 dng_version = (dng_version << 8) + fgetc(ifp); if (!make[0]) strcpy (make, "DNG"); is_raw = 1; break; case 50708: /* UniqueCameraModel */ #ifdef LIBRAW_LIBRARY_BUILD stmread(imgdata.color.UniqueCameraModel, len, ifp); imgdata.color.UniqueCameraModel[sizeof(imgdata.color.UniqueCameraModel)-1] = 0; #endif if (model[0]) break; #ifndef LIBRAW_LIBRARY_BUILD fgets (make, 64, ifp); #else strncpy (make, imgdata.color.UniqueCameraModel, MIN(len, sizeof(imgdata.color.UniqueCameraModel))); #endif if ((cp = strchr(make,' '))) { strcpy(model,cp+1); *cp = 0; } break; case 50710: /* CFAPlaneColor */ if (filters == 9) break; if (len > 4) len = 4; colors = len; fread (cfa_pc, 1, colors, ifp); guess_cfa_pc: FORCC tab[cfa_pc[c]] = c; cdesc[c] = 0; for (i=16; i--; ) filters = filters << 2 | tab[cfa_pat[i % plen]]; filters -= !filters; break; case 50711: /* CFALayout */ if (get2() == 2) fuji_width = 1; break; case 291: case 50712: /* LinearizationTable */ linear_table (len); break; case 50713: /* BlackLevelRepeatDim */ #ifdef LIBRAW_LIBRARY_BUILD imgdata.color.dng_levels.dng_cblack[4] = #endif cblack[4] = get2(); #ifdef LIBRAW_LIBRARY_BUILD imgdata.color.dng_levels.dng_cblack[5] = #endif cblack[5] = get2(); if (cblack[4] * cblack[5] > (sizeof(cblack) / sizeof (cblack[0]) - 6)) #ifdef LIBRAW_LIBRARY_BUILD imgdata.color.dng_levels.dng_cblack[4]= imgdata.color.dng_levels.dng_cblack[5]= #endif cblack[4] = cblack[5] = 1; break; #ifdef LIBRAW_LIBRARY_BUILD case 0xf00c: { unsigned fwb[4]; FORC4 fwb[c] = get4(); if (fwb[3] < 0x100) { imgdata.color.WB_Coeffs[fwb[3]][0] = fwb[1]; imgdata.color.WB_Coeffs[fwb[3]][1] = imgdata.color.WB_Coeffs[fwb[3]][3] = fwb[0]; imgdata.color.WB_Coeffs[fwb[3]][2] = fwb[2]; if ((fwb[3] == 17) && libraw_internal_data.unpacker_data.lenRAFData>3 && libraw_internal_data.unpacker_data.lenRAFData < 10240000) { long long f_save = ftell(ifp); int fj, found = 0; ushort *rafdata = (ushort*) malloc (sizeof(ushort)*libraw_internal_data.unpacker_data.lenRAFData); fseek (ifp, libraw_internal_data.unpacker_data.posRAFData, SEEK_SET); fread (rafdata, sizeof(ushort), libraw_internal_data.unpacker_data.lenRAFData, ifp); fseek(ifp, f_save, SEEK_SET); for (int fi=0; fi<(libraw_internal_data.unpacker_data.lenRAFData-3); fi++) { if ((fwb[0]==rafdata[fi]) && (fwb[1]==rafdata[fi+1]) && (fwb[2]==rafdata[fi+2])) { if (rafdata[fi-15] != fwb[0]) continue; fi = fi - 15; imgdata.color.WB_Coeffs[LIBRAW_WBI_FineWeather][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_FineWeather][3] = rafdata[fi]; imgdata.color.WB_Coeffs[LIBRAW_WBI_FineWeather][0] = rafdata[fi+1]; imgdata.color.WB_Coeffs[LIBRAW_WBI_FineWeather][2] = rafdata[fi+2]; imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][3] = rafdata[fi+3]; imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][0] = rafdata[fi+4]; imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][2] = rafdata[fi+5]; imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][3] = rafdata[fi+6]; imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][0] = rafdata[fi+7]; imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][2] = rafdata[fi+8]; imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_L][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_L][3] = rafdata[fi+9]; imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_L][0] = rafdata[fi+10]; imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_L][2] = rafdata[fi+11]; imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][3] = rafdata[fi+12]; imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][0] = rafdata[fi+13]; imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][2] = rafdata[fi+14]; imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][3] = rafdata[fi+15]; imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][0] = rafdata[fi+16]; imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][2] = rafdata[fi+17]; fi += 111; for (fj = fi; fj<(fi+15); fj+=3) if (rafdata[fj] != rafdata[fi]) { found = 1; break; } if (found) { int FujiCCT_K [31] = {2500,2550,2650,2700,2800,2850,2950,3000,3100,3200,3300,3400,3600,3700,3800,4000,4200,4300,4500,4800,5000,5300,5600,5900,6300,6700,7100,7700,8300,9100,10000}; fj = fj - 93; for (int iCCT=0; iCCT < 31; iCCT++) { imgdata.color.WBCT_Coeffs[iCCT][0] = FujiCCT_K[iCCT]; imgdata.color.WBCT_Coeffs[iCCT][1] = rafdata[iCCT*3+1+fj]; imgdata.color.WBCT_Coeffs[iCCT][2] = imgdata.color.WBCT_Coeffs[iCCT][4] = rafdata[iCCT*3+fj]; imgdata.color.WBCT_Coeffs[iCCT][3] = rafdata[iCCT*3+2+fj]; } } free (rafdata); break; } } } } FORC4 fwb[c] = get4(); if (fwb[3] < 0x100) { imgdata.color.WB_Coeffs[fwb[3]][0] = fwb[1]; imgdata.color.WB_Coeffs[fwb[3]][1] = imgdata.color.WB_Coeffs[fwb[3]][3] = fwb[0]; imgdata.color.WB_Coeffs[fwb[3]][2] = fwb[2]; } } break; #endif #ifdef LIBRAW_LIBRARY_BUILD case 50709: stmread(imgdata.color.LocalizedCameraModel,len, ifp); break; #endif case 61450: cblack[4] = cblack[5] = MIN(sqrt((double)len),64); case 50714: /* BlackLevel */ #ifdef LIBRAW_LIBRARY_BUILD if(tiff_ifd[ifd].samples > 1 && tiff_ifd[ifd].samples == len) // LinearDNG, per-channel black { for(i=0; i < colors && i < 4 && i < len; i++) imgdata.color.dng_levels.dng_cblack[i]= cblack[i]= getreal(type)+0.5; imgdata.color.dng_levels.dng_black= black = 0; } else #endif if((cblack[4] * cblack[5] < 2) && len == 1) { #ifdef LIBRAW_LIBRARY_BUILD imgdata.color.dng_levels.dng_black= #endif black = getreal(type); } else if(cblack[4] * cblack[5] <= len) { FORC (cblack[4] * cblack[5]) cblack[6+c] = getreal(type); black = 0; FORC4 cblack[c] = 0; #ifdef LIBRAW_LIBRARY_BUILD if(tag == 50714) { FORC (cblack[4] * cblack[5]) imgdata.color.dng_levels.dng_cblack[6+c]= cblack[6+c]; imgdata.color.dng_levels.dng_black=0; FORC4 imgdata.color.dng_levels.dng_cblack[c]= 0; } #endif } break; case 50715: /* BlackLevelDeltaH */ case 50716: /* BlackLevelDeltaV */ for (num=i=0; i < len && i < 65536; i++) num += getreal(type); black += num/len + 0.5; #ifdef LIBRAW_LIBRARY_BUILD imgdata.color.dng_levels.dng_black += num/len + 0.5; #endif break; case 50717: /* WhiteLevel */ #ifdef LIBRAW_LIBRARY_BUILD imgdata.color.dng_levels.dng_whitelevel[0]= #endif maximum = getint(type); #ifdef LIBRAW_LIBRARY_BUILD if(tiff_ifd[ifd].samples > 1 ) // Linear DNG case for(i=1; i < colors && i < 4 && i < len; i++) imgdata.color.dng_levels.dng_whitelevel[i]=getint(type); #endif break; case 50718: /* DefaultScale */ pixel_aspect = getreal(type); pixel_aspect /= getreal(type); if(pixel_aspect > 0.995 && pixel_aspect < 1.005) pixel_aspect = 1.0; break; #ifdef LIBRAW_LIBRARY_BUILD case 50778: imgdata.color.dng_color[0].illuminant = get2(); break; case 50779: imgdata.color.dng_color[1].illuminant = get2(); break; #endif case 50721: /* ColorMatrix1 */ case 50722: /* ColorMatrix2 */ #ifdef LIBRAW_LIBRARY_BUILD i = tag == 50721?0:1; #endif FORCC for (j=0; j < 3; j++) { #ifdef LIBRAW_LIBRARY_BUILD imgdata.color.dng_color[i].colormatrix[c][j]= #endif cm[c][j] = getreal(type); } use_cm = 1; break; case 0xc714: /* ForwardMatrix1 */ case 0xc715: /* ForwardMatrix2 */ #ifdef LIBRAW_LIBRARY_BUILD i = tag == 0xc714?0:1; #endif for (j=0; j < 3; j++) FORCC { #ifdef LIBRAW_LIBRARY_BUILD imgdata.color.dng_color[i].forwardmatrix[j][c]= #endif fm[j][c] = getreal(type); } break; case 50723: /* CameraCalibration1 */ case 50724: /* CameraCalibration2 */ #ifdef LIBRAW_LIBRARY_BUILD j = tag == 50723?0:1; #endif for (i=0; i < colors; i++) FORCC { #ifdef LIBRAW_LIBRARY_BUILD imgdata.color.dng_color[j].calibration[i][c]= #endif cc[i][c] = getreal(type); } break; case 50727: /* AnalogBalance */ FORCC{ #ifdef LIBRAW_LIBRARY_BUILD imgdata.color.dng_levels.analogbalance[c]= #endif ab[c] = getreal(type); } break; case 50728: /* AsShotNeutral */ FORCC asn[c] = getreal(type); break; case 50729: /* AsShotWhiteXY */ xyz[0] = getreal(type); xyz[1] = getreal(type); xyz[2] = 1 - xyz[0] - xyz[1]; FORC3 xyz[c] /= d65_white[c]; break; #ifdef LIBRAW_LIBRARY_BUILD case 50730: /* DNG: Baseline Exposure */ baseline_exposure = getreal(type); break; #endif // IB start case 50740: /* tag 0xc634 : DNG Adobe, DNG Pentax, Sony SR2, DNG Private */ #ifdef LIBRAW_LIBRARY_BUILD { char mbuf[64]; unsigned short makernote_found = 0; INT64 curr_pos, start_pos = ftell(ifp); unsigned MakN_order, m_sorder = order; unsigned MakN_length; unsigned pos_in_original_raw; fread(mbuf, 1, 6, ifp); if (!strcmp(mbuf, "Adobe")) { order = 0x4d4d; // Adobe header is always in "MM" / big endian curr_pos = start_pos + 6; while (curr_pos + 8 - start_pos <= len) { fread(mbuf, 1, 4, ifp); curr_pos += 8; if (!strncmp(mbuf, "MakN", 4)) { makernote_found = 1; MakN_length = get4(); MakN_order = get2(); pos_in_original_raw = get4(); order = MakN_order; parse_makernote_0xc634(curr_pos + 6 - pos_in_original_raw, 0, AdobeDNG); break; } } } else { fread(mbuf + 6, 1, 2, ifp); if (!strcmp(mbuf, "PENTAX ") || !strcmp(mbuf, "SAMSUNG")) { makernote_found = 1; fseek(ifp, start_pos, SEEK_SET); parse_makernote_0xc634(base, 0, CameraDNG); } } fseek(ifp, start_pos, SEEK_SET); order = m_sorder; } // IB end #endif if (dng_version) break; parse_minolta (j = get4()+base); fseek (ifp, j, SEEK_SET); parse_tiff_ifd (base); break; case 50752: read_shorts (cr2_slice, 3); break; case 50829: /* ActiveArea */ top_margin = getint(type); left_margin = getint(type); height = getint(type) - top_margin; width = getint(type) - left_margin; break; case 50830: /* MaskedAreas */ for (i=0; i < len && i < 32; i++) ((int*)mask)[i] = getint(type); black = 0; break; case 51009: /* OpcodeList2 */ meta_offset = ftell(ifp); break; case 64772: /* Kodak P-series */ if (len < 13) break; fseek (ifp, 16, SEEK_CUR); data_offset = get4(); fseek (ifp, 28, SEEK_CUR); data_offset += get4(); load_raw = &CLASS packed_load_raw; break; case 65026: if (type == 2) fgets (model2, 64, ifp); } fseek (ifp, save, SEEK_SET); } if (sony_length && sony_length < 10240000 && (buf = (unsigned *) malloc(sony_length))) { fseek (ifp, sony_offset, SEEK_SET); fread (buf, sony_length, 1, ifp); sony_decrypt (buf, sony_length/4, 1, sony_key); #ifndef LIBRAW_LIBRARY_BUILD sfp = ifp; if ((ifp = tmpfile())) { fwrite (buf, sony_length, 1, ifp); fseek (ifp, 0, SEEK_SET); parse_tiff_ifd (-sony_offset); fclose (ifp); } ifp = sfp; #else if( !ifp->tempbuffer_open(buf,sony_length)) { parse_tiff_ifd(-sony_offset); ifp->tempbuffer_close(); } #endif free (buf); } for (i=0; i < colors; i++) FORCC cc[i][c] *= ab[i]; if (use_cm) { FORCC for (i=0; i < 3; i++) for (cam_xyz[c][i]=j=0; j < colors; j++) cam_xyz[c][i] += cc[c][j] * cm[j][i] * xyz[i]; cam_xyz_coeff (cmatrix, cam_xyz); } if (asn[0]) { cam_mul[3] = 0; FORCC cam_mul[c] = 1 / asn[c]; } if (!use_cm) FORCC pre_mul[c] /= cc[c][c]; return 0; } int CLASS parse_tiff (int base) { int doff; fseek (ifp, base, SEEK_SET); order = get2(); if (order != 0x4949 && order != 0x4d4d) return 0; get2(); while ((doff = get4())) { fseek (ifp, doff+base, SEEK_SET); if (parse_tiff_ifd (base)) break; } return 1; } void CLASS apply_tiff() { int max_samp=0, ties=0, os, ns, raw=-1, thm=-1, i; struct jhead jh; thumb_misc = 16; if (thumb_offset) { fseek (ifp, thumb_offset, SEEK_SET); if (ljpeg_start (&jh, 1)) { if((unsigned)jh.bits<17 && (unsigned)jh.wide < 0x10000 && (unsigned)jh.high < 0x10000) { thumb_misc = jh.bits; thumb_width = jh.wide; thumb_height = jh.high; } } } for (i=tiff_nifds; i--; ) { if (tiff_ifd[i].t_shutter) shutter = tiff_ifd[i].t_shutter; tiff_ifd[i].t_shutter = shutter; } for (i=0; i < tiff_nifds; i++) { if (max_samp < tiff_ifd[i].samples) max_samp = tiff_ifd[i].samples; if (max_samp > 3) max_samp = 3; os = raw_width*raw_height; ns = tiff_ifd[i].t_width*tiff_ifd[i].t_height; if (tiff_bps) { os *= tiff_bps; ns *= tiff_ifd[i].bps; } if ((tiff_ifd[i].comp != 6 || tiff_ifd[i].samples != 3) && unsigned(tiff_ifd[i].t_width | tiff_ifd[i].t_height) < 0x10000 && (unsigned)tiff_ifd[i].bps < 33 && (unsigned)tiff_ifd[i].samples < 13 && ns && ((ns > os && (ties = 1)) || (ns == os && shot_select == ties++))) { raw_width = tiff_ifd[i].t_width; raw_height = tiff_ifd[i].t_height; tiff_bps = tiff_ifd[i].bps; tiff_compress = tiff_ifd[i].comp; data_offset = tiff_ifd[i].offset; #ifdef LIBRAW_LIBRARY_BUILD data_size = tiff_ifd[i].bytes; #endif tiff_flip = tiff_ifd[i].t_flip; tiff_samples = tiff_ifd[i].samples; tile_width = tiff_ifd[i].t_tile_width; tile_length = tiff_ifd[i].t_tile_length; shutter = tiff_ifd[i].t_shutter; raw = i; } } if (is_raw == 1 && ties) is_raw = ties; if (!tile_width ) tile_width = INT_MAX; if (!tile_length) tile_length = INT_MAX; for (i=tiff_nifds; i--; ) if (tiff_ifd[i].t_flip) tiff_flip = tiff_ifd[i].t_flip; if (raw >= 0 && !load_raw) switch (tiff_compress) { case 32767: if (tiff_ifd[raw].bytes == raw_width*raw_height) { tiff_bps = 12; load_raw = &CLASS sony_arw2_load_raw; break; } if (!strncasecmp(make,"Sony",4) && tiff_ifd[raw].bytes == raw_width*raw_height*2) { tiff_bps = 14; load_raw = &CLASS unpacked_load_raw; break; } if (tiff_ifd[raw].bytes*8 != raw_width*raw_height*tiff_bps) { raw_height += 8; load_raw = &CLASS sony_arw_load_raw; break; } load_flags = 79; case 32769: load_flags++; case 32770: case 32773: goto slr; case 0: case 1: #ifdef LIBRAW_LIBRARY_BUILD // Sony 14-bit uncompressed if(!strncasecmp(make,"Sony",4) && tiff_ifd[raw].bytes == raw_width*raw_height*2) { tiff_bps = 14; load_raw = &CLASS unpacked_load_raw; break; } if(!strncasecmp(make,"Nikon",5) && !strncmp(software,"Nikon Scan",10)) { load_raw = &CLASS nikon_coolscan_load_raw; raw_color = 1; filters = 0; break; } #endif if (!strncmp(make,"OLYMPUS",7) && tiff_ifd[raw].bytes*2 == raw_width*raw_height*3) load_flags = 24; if (tiff_ifd[raw].bytes*5 == raw_width*raw_height*8) { load_flags = 81; tiff_bps = 12; } slr: switch (tiff_bps) { case 8: load_raw = &CLASS eight_bit_load_raw; break; case 12: if (tiff_ifd[raw].phint == 2) load_flags = 6; load_raw = &CLASS packed_load_raw; break; case 14: load_flags = 0; case 16: load_raw = &CLASS unpacked_load_raw; if (!strncmp(make,"OLYMPUS",7) && tiff_ifd[raw].bytes*7 > raw_width*raw_height) load_raw = &CLASS olympus_load_raw; } break; case 6: case 7: case 99: load_raw = &CLASS lossless_jpeg_load_raw; break; case 262: load_raw = &CLASS kodak_262_load_raw; break; case 34713: if ((raw_width+9)/10*16*raw_height == tiff_ifd[raw].bytes) { load_raw = &CLASS packed_load_raw; load_flags = 1; } else if (raw_width*raw_height*3 == tiff_ifd[raw].bytes*2) { load_raw = &CLASS packed_load_raw; if (model[0] == 'N') load_flags = 80; } else if (raw_width*raw_height*3 == tiff_ifd[raw].bytes) { load_raw = &CLASS nikon_yuv_load_raw; gamma_curve (1/2.4, 12.92, 1, 4095); memset (cblack, 0, sizeof cblack); filters = 0; } else if (raw_width*raw_height*2 == tiff_ifd[raw].bytes) { load_raw = &CLASS unpacked_load_raw; load_flags = 4; order = 0x4d4d; } else #ifdef LIBRAW_LIBRARY_BUILD if(raw_width*raw_height*3 == tiff_ifd[raw].bytes*2) { load_raw = &CLASS packed_load_raw; load_flags=80; } else if(tiff_ifd[raw].rows_per_strip && tiff_ifd[raw].strip_offsets_count && tiff_ifd[raw].strip_offsets_count == tiff_ifd[raw].strip_byte_counts_count) { int fit = 1; for(int i = 0; i < tiff_ifd[raw].strip_byte_counts_count-1; i++) // all but last if(tiff_ifd[raw].strip_byte_counts[i]*2 != tiff_ifd[raw].rows_per_strip*raw_width*3) { fit = 0; break; } if(fit) load_raw = &CLASS nikon_load_striped_packed_raw; else load_raw = &CLASS nikon_load_raw; // fallback } else #endif load_raw = &CLASS nikon_load_raw; break; case 65535: load_raw = &CLASS pentax_load_raw; break; case 65000: switch (tiff_ifd[raw].phint) { case 2: load_raw = &CLASS kodak_rgb_load_raw; filters = 0; break; case 6: load_raw = &CLASS kodak_ycbcr_load_raw; filters = 0; break; case 32803: load_raw = &CLASS kodak_65000_load_raw; } case 32867: case 34892: break; #ifdef LIBRAW_LIBRARY_BUILD case 8: break; #endif default: is_raw = 0; } if (!dng_version) if ( ((tiff_samples == 3 && tiff_ifd[raw].bytes && tiff_bps != 14 && (tiff_compress & -16) != 32768) || (tiff_bps == 8 && strncmp(make,"Phase",5) && !strcasestr(make,"Kodak") && !strstr(model2,"DEBUG RAW"))) && strncmp(software,"Nikon Scan",10)) is_raw = 0; for (i=0; i < tiff_nifds; i++) if (i != raw && (tiff_ifd[i].samples == max_samp || (tiff_ifd[i].comp == 7 && tiff_ifd[i].samples == 1)) /* Allow 1-bps JPEGs */ && tiff_ifd[i].bps>0 && tiff_ifd[i].bps < 33 && tiff_ifd[i].phint != 32803 && tiff_ifd[i].phint != 34892 && unsigned(tiff_ifd[i].t_width | tiff_ifd[i].t_height) < 0x10000 && tiff_ifd[i].t_width * tiff_ifd[i].t_height / (SQR(tiff_ifd[i].bps)+1) > thumb_width * thumb_height / (SQR(thumb_misc)+1) && tiff_ifd[i].comp != 34892) { thumb_width = tiff_ifd[i].t_width; thumb_height = tiff_ifd[i].t_height; thumb_offset = tiff_ifd[i].offset; thumb_length = tiff_ifd[i].bytes; thumb_misc = tiff_ifd[i].bps; thm = i; } if (thm >= 0) { thumb_misc |= tiff_ifd[thm].samples << 5; switch (tiff_ifd[thm].comp) { case 0: write_thumb = &CLASS layer_thumb; break; case 1: if (tiff_ifd[thm].bps <= 8) write_thumb = &CLASS ppm_thumb; else if (!strncmp(make,"Imacon",6)) write_thumb = &CLASS ppm16_thumb; else thumb_load_raw = &CLASS kodak_thumb_load_raw; break; case 65000: thumb_load_raw = tiff_ifd[thm].phint == 6 ? &CLASS kodak_ycbcr_load_raw : &CLASS kodak_rgb_load_raw; } } } void CLASS parse_minolta (int base) { int save, tag, len, offset, high=0, wide=0, i, c; short sorder=order; fseek (ifp, base, SEEK_SET); if (fgetc(ifp) || fgetc(ifp)-'M' || fgetc(ifp)-'R') return; order = fgetc(ifp) * 0x101; offset = base + get4() + 8; while ((save=ftell(ifp)) < offset) { for (tag=i=0; i < 4; i++) tag = tag << 8 | fgetc(ifp); len = get4(); switch (tag) { case 0x505244: /* PRD */ fseek (ifp, 8, SEEK_CUR); high = get2(); wide = get2(); break; #ifdef LIBRAW_LIBRARY_BUILD case 0x524946: /* RIF */ if (!strncasecmp(model,"DSLR-A100", 9)) { fseek(ifp, 8, SEEK_CUR); imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][2] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][2] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][2] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][2] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][2] = get2(); get4(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][2] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][2] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][2] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_WW][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_WW][2] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_WW][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_WW][3] = 0x100; } break; #endif case 0x574247: /* WBG */ get4(); i = strcmp(model,"DiMAGE A200") ? 0:3; FORC4 cam_mul[c ^ (c >> 1) ^ i] = get2(); break; case 0x545457: /* TTW */ parse_tiff (ftell(ifp)); data_offset = offset; } fseek (ifp, save+len+8, SEEK_SET); } raw_height = high; raw_width = wide; order = sorder; } /* Many cameras have a "debug mode" that writes JPEG and raw at the same time. The raw file has no header, so try to to open the matching JPEG file and read its metadata. */ void CLASS parse_external_jpeg() { const char *file, *ext; char *jname, *jfile, *jext; #ifndef LIBRAW_LIBRARY_BUILD FILE *save=ifp; #else #if defined(_WIN32) && !defined(__MINGW32__) && defined(_MSC_VER) && (_MSC_VER > 1310) if(ifp->wfname()) { std::wstring rawfile(ifp->wfname()); rawfile.replace(rawfile.length()-3,3,L"JPG"); if(!ifp->subfile_open(rawfile.c_str())) { parse_tiff (12); thumb_offset = 0; is_raw = 1; ifp->subfile_close(); } else imgdata.process_warnings |= LIBRAW_WARN_NO_METADATA ; return; } #endif if(!ifp->fname()) { imgdata.process_warnings |= LIBRAW_WARN_NO_METADATA ; return; } #endif ext = strrchr (ifname, '.'); file = strrchr (ifname, '/'); if (!file) file = strrchr (ifname, '\\'); #ifndef LIBRAW_LIBRARY_BUILD if (!file) file = ifname-1; #else if (!file) file = (char*)ifname-1; #endif file++; if (!ext || strlen(ext) != 4 || ext-file != 8) return; jname = (char *) malloc (strlen(ifname) + 1); merror (jname, "parse_external_jpeg()"); strcpy (jname, ifname); jfile = file - ifname + jname; jext = ext - ifname + jname; if (strcasecmp (ext, ".jpg")) { strcpy (jext, isupper(ext[1]) ? ".JPG":".jpg"); if (isdigit(*file)) { memcpy (jfile, file+4, 4); memcpy (jfile+4, file, 4); } } else while (isdigit(*--jext)) { if (*jext != '9') { (*jext)++; break; } *jext = '0'; } #ifndef LIBRAW_LIBRARY_BUILD if (strcmp (jname, ifname)) { if ((ifp = fopen (jname, "rb"))) { #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("Reading metadata from %s ...\n"), jname); #endif parse_tiff (12); thumb_offset = 0; is_raw = 1; fclose (ifp); } } #else if (strcmp (jname, ifname)) { if(!ifp->subfile_open(jname)) { parse_tiff (12); thumb_offset = 0; is_raw = 1; ifp->subfile_close(); } else imgdata.process_warnings |= LIBRAW_WARN_NO_METADATA ; } #endif if (!timestamp) { #ifdef LIBRAW_LIBRARY_BUILD imgdata.process_warnings |= LIBRAW_WARN_NO_METADATA ; #endif #ifdef DCRAW_VERBOSE fprintf (stderr,_("Failed to read metadata from %s\n"), jname); #endif } free (jname); #ifndef LIBRAW_LIBRARY_BUILD ifp = save; #endif } /* CIFF block 0x1030 contains an 8x8 white sample. Load this into white[][] for use in scale_colors(). */ void CLASS ciff_block_1030() { static const ushort key[] = { 0x410, 0x45f3 }; int i, bpp, row, col, vbits=0; unsigned long bitbuf=0; if ((get2(),get4()) != 0x80008 || !get4()) return; bpp = get2(); if (bpp != 10 && bpp != 12) return; for (i=row=0; row < 8; row++) for (col=0; col < 8; col++) { if (vbits < bpp) { bitbuf = bitbuf << 16 | (get2() ^ key[i++ & 1]); vbits += 16; } white[row][col] = bitbuf >> (vbits -= bpp) & ~(-1 << bpp); } } /* Parse a CIFF file, better known as Canon CRW format. */ void CLASS parse_ciff (int offset, int length, int depth) { int tboff, nrecs, c, type, len, save, wbi=-1; ushort key[] = { 0x410, 0x45f3 }; fseek (ifp, offset+length-4, SEEK_SET); tboff = get4() + offset; fseek (ifp, tboff, SEEK_SET); nrecs = get2(); if ((nrecs | depth) > 127) return; while (nrecs--) { type = get2(); len = get4(); save = ftell(ifp) + 4; fseek (ifp, offset+get4(), SEEK_SET); if ((((type >> 8) + 8) | 8) == 0x38) { parse_ciff (ftell(ifp), len, depth+1); /* Parse a sub-table */ } #ifdef LIBRAW_LIBRARY_BUILD if (type == 0x3004) parse_ciff (ftell(ifp), len, depth+1); #endif if (type == 0x0810) fread (artist, 64, 1, ifp); if (type == 0x080a) { fread (make, 64, 1, ifp); fseek (ifp, strbuflen(make) - 63, SEEK_CUR); fread (model, 64, 1, ifp); } if (type == 0x1810) { width = get4(); height = get4(); pixel_aspect = int_to_float(get4()); flip = get4(); } if (type == 0x1835) /* Get the decoder table */ tiff_compress = get4(); if (type == 0x2007) { thumb_offset = ftell(ifp); thumb_length = len; } if (type == 0x1818) { shutter = libraw_powf64(2.0f, -int_to_float((get4(),get4()))); aperture = libraw_powf64(2.0f, int_to_float(get4())/2); #ifdef LIBRAW_LIBRARY_BUILD imgdata.lens.makernotes.CurAp = aperture; #endif } if (type == 0x102a) { // iso_speed = pow (2.0, (get4(),get2())/32.0 - 4) * 50; iso_speed = libraw_powf64(2.0f, ((get2(),get2()) + get2())/32.0f - 5.0f) * 100.0f; #ifdef LIBRAW_LIBRARY_BUILD aperture = _CanonConvertAperture((get2(),get2())); imgdata.lens.makernotes.CurAp = aperture; #else aperture = libraw_powf64(2.0, (get2(),(short)get2())/64.0); #endif shutter = libraw_powf64(2.0,-((short)get2())/32.0); wbi = (get2(),get2()); if (wbi > 17) wbi = 0; fseek (ifp, 32, SEEK_CUR); if (shutter > 1e6) shutter = get2()/10.0; } if (type == 0x102c) { if (get2() > 512) { /* Pro90, G1 */ fseek (ifp, 118, SEEK_CUR); FORC4 cam_mul[c ^ 2] = get2(); } else { /* G2, S30, S40 */ fseek (ifp, 98, SEEK_CUR); FORC4 cam_mul[c ^ (c >> 1) ^ 1] = get2(); } } #ifdef LIBRAW_LIBRARY_BUILD if (type == 0x10a9) { INT64 o = ftell(ifp); fseek (ifp, (0x5<<1), SEEK_CUR); Canon_WBpresets(0,0); fseek(ifp,o,SEEK_SET); } if (type == 0x102d) { INT64 o = ftell(ifp); Canon_CameraSettings(); fseek(ifp,o,SEEK_SET); } if (type == 0x580b) { if (strcmp(model,"Canon EOS D30")) sprintf(imgdata.shootinginfo.BodySerial, "%d", len); else sprintf(imgdata.shootinginfo.BodySerial, "%0x-%05d", len>>16, len&0xffff); } #endif if (type == 0x0032) { if (len == 768) { /* EOS D30 */ fseek (ifp, 72, SEEK_CUR); FORC4 cam_mul[c ^ (c >> 1)] = 1024.0 / get2(); if (!wbi) cam_mul[0] = -1; /* use my auto white balance */ } else if (!cam_mul[0]) { if (get2() == key[0]) /* Pro1, G6, S60, S70 */ c = (strstr(model,"Pro1") ? "012346000000000000":"01345:000000006008")[LIM(0,wbi,17)]-'0'+ 2; else { /* G3, G5, S45, S50 */ c = "023457000000006000"[LIM(0,wbi,17)]-'0'; key[0] = key[1] = 0; } fseek (ifp, 78 + c*8, SEEK_CUR); FORC4 cam_mul[c ^ (c >> 1) ^ 1] = get2() ^ key[c & 1]; if (!wbi) cam_mul[0] = -1; } } if (type == 0x10a9) { /* D60, 10D, 300D, and clones */ if (len > 66) wbi = "0134567028"[LIM(0,wbi,9)]-'0'; fseek (ifp, 2 + wbi*8, SEEK_CUR); FORC4 cam_mul[c ^ (c >> 1)] = get2(); } if (type == 0x1030 && wbi>=0 && (0x18040 >> wbi & 1)) ciff_block_1030(); /* all that don't have 0x10a9 */ if (type == 0x1031) { raw_width = (get2(),get2()); raw_height = get2(); } if (type == 0x501c) { iso_speed = len & 0xffff; } if (type == 0x5029) { #ifdef LIBRAW_LIBRARY_BUILD imgdata.lens.makernotes.CurFocal = len >> 16; imgdata.lens.makernotes.FocalType = len & 0xffff; if (imgdata.lens.makernotes.FocalType == 2) { imgdata.lens.makernotes.CanonFocalUnits = 32; if(imgdata.lens.makernotes.CanonFocalUnits>1) imgdata.lens.makernotes.CurFocal /= (float)imgdata.lens.makernotes.CanonFocalUnits; } focal_len = imgdata.lens.makernotes.CurFocal; #else focal_len = len >> 16; if ((len & 0xffff) == 2) focal_len /= 32; #endif } if (type == 0x5813) flash_used = int_to_float(len); if (type == 0x5814) canon_ev = int_to_float(len); if (type == 0x5817) shot_order = len; if (type == 0x5834) { unique_id = len; #ifdef LIBRAW_LIBRARY_BUILD setCanonBodyFeatures(unique_id); #endif } if (type == 0x580e) timestamp = len; if (type == 0x180e) timestamp = get4(); #ifdef LOCALTIME if ((type | 0x4000) == 0x580e) timestamp = mktime (gmtime (×tamp)); #endif fseek (ifp, save, SEEK_SET); } } void CLASS parse_rollei() { char line[128], *val; struct tm t; fseek (ifp, 0, SEEK_SET); memset (&t, 0, sizeof t); do { fgets (line, 128, ifp); if ((val = strchr(line,'='))) *val++ = 0; else val = line + strbuflen(line); if (!strcmp(line,"DAT")) sscanf (val, "%d.%d.%d", &t.tm_mday, &t.tm_mon, &t.tm_year); if (!strcmp(line,"TIM")) sscanf (val, "%d:%d:%d", &t.tm_hour, &t.tm_min, &t.tm_sec); if (!strcmp(line,"HDR")) thumb_offset = atoi(val); if (!strcmp(line,"X ")) raw_width = atoi(val); if (!strcmp(line,"Y ")) raw_height = atoi(val); if (!strcmp(line,"TX ")) thumb_width = atoi(val); if (!strcmp(line,"TY ")) thumb_height = atoi(val); } while (strncmp(line,"EOHD",4)); data_offset = thumb_offset + thumb_width * thumb_height * 2; t.tm_year -= 1900; t.tm_mon -= 1; if (mktime(&t) > 0) timestamp = mktime(&t); strcpy (make, "Rollei"); strcpy (model,"d530flex"); write_thumb = &CLASS rollei_thumb; } void CLASS parse_sinar_ia() { int entries, off; char str[8], *cp; order = 0x4949; fseek (ifp, 4, SEEK_SET); entries = get4(); fseek (ifp, get4(), SEEK_SET); while (entries--) { off = get4(); get4(); fread (str, 8, 1, ifp); if (!strcmp(str,"META")) meta_offset = off; if (!strcmp(str,"THUMB")) thumb_offset = off; if (!strcmp(str,"RAW0")) data_offset = off; } fseek (ifp, meta_offset+20, SEEK_SET); fread (make, 64, 1, ifp); make[63] = 0; if ((cp = strchr(make,' '))) { strcpy (model, cp+1); *cp = 0; } raw_width = get2(); raw_height = get2(); load_raw = &CLASS unpacked_load_raw; thumb_width = (get4(),get2()); thumb_height = get2(); write_thumb = &CLASS ppm_thumb; maximum = 0x3fff; } void CLASS parse_phase_one (int base) { unsigned entries, tag, type, len, data, save, i, c; float romm_cam[3][3]; char *cp; memset (&ph1, 0, sizeof ph1); fseek (ifp, base, SEEK_SET); order = get4() & 0xffff; if (get4() >> 8 != 0x526177) return; /* "Raw" */ fseek (ifp, get4()+base, SEEK_SET); entries = get4(); get4(); while (entries--) { tag = get4(); type = get4(); len = get4(); data = get4(); save = ftell(ifp); fseek (ifp, base+data, SEEK_SET); switch (tag) { #ifdef LIBRAW_LIBRARY_BUILD case 0x0102: stmread(imgdata.shootinginfo.BodySerial, len, ifp); if ((imgdata.shootinginfo.BodySerial[0] == 0x4c) && (imgdata.shootinginfo.BodySerial[1] == 0x49)) { unique_id = (((imgdata.shootinginfo.BodySerial[0] & 0x3f) << 5) | (imgdata.shootinginfo.BodySerial[2] & 0x3f)) - 0x41; } else { unique_id = (((imgdata.shootinginfo.BodySerial[0] & 0x3f) << 5) | (imgdata.shootinginfo.BodySerial[1] & 0x3f)) - 0x41; } setPhaseOneFeatures(unique_id); break; case 0x0401: if (type == 4) imgdata.lens.makernotes.CurAp = libraw_powf64(2.0f, (int_to_float(data)/2.0f)); else imgdata.lens.makernotes.CurAp = libraw_powf64(2.0f, (getreal(type)/2.0f)); break; case 0x0403: if (type == 4) imgdata.lens.makernotes.CurFocal = int_to_float(data); else imgdata.lens.makernotes.CurFocal = getreal(type); break; case 0x0410: stmread(imgdata.lens.makernotes.body, len, ifp); break; case 0x0412: stmread(imgdata.lens.makernotes.Lens, len, ifp); break; case 0x0414: if (type == 4) { imgdata.lens.makernotes.MaxAp4CurFocal = libraw_powf64(2.0f, (int_to_float(data)/2.0f)); } else { imgdata.lens.makernotes.MaxAp4CurFocal = libraw_powf64(2.0f, (getreal(type) / 2.0f)); } break; case 0x0415: if (type == 4) { imgdata.lens.makernotes.MinAp4CurFocal = libraw_powf64(2.0f, (int_to_float(data)/2.0f)); } else { imgdata.lens.makernotes.MinAp4CurFocal = libraw_powf64(2.0f, (getreal(type) / 2.0f)); } break; case 0x0416: if (type == 4) { imgdata.lens.makernotes.MinFocal = int_to_float(data); } else { imgdata.lens.makernotes.MinFocal = getreal(type); } if (imgdata.lens.makernotes.MinFocal > 1000.0f) { imgdata.lens.makernotes.MinFocal = 0.0f; } break; case 0x0417: if (type == 4) { imgdata.lens.makernotes.MaxFocal = int_to_float(data); } else { imgdata.lens.makernotes.MaxFocal = getreal(type); } break; #endif case 0x100: flip = "0653"[data & 3]-'0'; break; case 0x106: for (i=0; i < 9; i++) #ifdef LIBRAW_LIBRARY_BUILD imgdata.color.P1_color[0].romm_cam[i]= #endif ((float *)romm_cam)[i] = getreal(11); romm_coeff (romm_cam); break; case 0x107: FORC3 cam_mul[c] = getreal(11); break; case 0x108: raw_width = data; break; case 0x109: raw_height = data; break; case 0x10a: left_margin = data; break; case 0x10b: top_margin = data; break; case 0x10c: width = data; break; case 0x10d: height = data; break; case 0x10e: ph1.format = data; break; case 0x10f: data_offset = data+base; break; case 0x110: meta_offset = data+base; meta_length = len; break; case 0x112: ph1.key_off = save - 4; break; case 0x210: ph1.tag_210 = int_to_float(data); break; case 0x21a: ph1.tag_21a = data; break; case 0x21c: strip_offset = data+base; break; case 0x21d: ph1.t_black = data; break; case 0x222: ph1.split_col = data; break; case 0x223: ph1.black_col = data+base; break; case 0x224: ph1.split_row = data; break; case 0x225: ph1.black_row = data+base; break; #ifdef LIBRAW_LIBRARY_BUILD case 0x226: for (i=0; i < 9; i++) imgdata.color.P1_color[1].romm_cam[i] = getreal(11); break; #endif case 0x301: model[63] = 0; fread (model, 1, 63, ifp); if ((cp = strstr(model," camera"))) *cp = 0; } fseek (ifp, save, SEEK_SET); } #ifdef LIBRAW_LIBRARY_BUILD if (!imgdata.lens.makernotes.body[0] && !imgdata.shootinginfo.BodySerial[0]) { fseek (ifp, meta_offset, SEEK_SET); order = get2(); fseek (ifp, 6, SEEK_CUR); fseek (ifp, meta_offset+get4(), SEEK_SET); entries = get4(); get4(); while (entries--) { tag = get4(); len = get4(); data = get4(); save = ftell(ifp); fseek (ifp, meta_offset+data, SEEK_SET); if (tag == 0x0407) { stmread(imgdata.shootinginfo.BodySerial, len, ifp); if ((imgdata.shootinginfo.BodySerial[0] == 0x4c) && (imgdata.shootinginfo.BodySerial[1] == 0x49)) { unique_id = (((imgdata.shootinginfo.BodySerial[0] & 0x3f) << 5) | (imgdata.shootinginfo.BodySerial[2] & 0x3f)) - 0x41; } else { unique_id = (((imgdata.shootinginfo.BodySerial[0] & 0x3f) << 5) | (imgdata.shootinginfo.BodySerial[1] & 0x3f)) - 0x41; } setPhaseOneFeatures(unique_id); } fseek (ifp, save, SEEK_SET); } } #endif load_raw = ph1.format < 3 ? &CLASS phase_one_load_raw : &CLASS phase_one_load_raw_c; maximum = 0xffff; strcpy (make, "Phase One"); if (model[0]) return; switch (raw_height) { case 2060: strcpy (model,"LightPhase"); break; case 2682: strcpy (model,"H 10"); break; case 4128: strcpy (model,"H 20"); break; case 5488: strcpy (model,"H 25"); break; } } void CLASS parse_fuji (int offset) { unsigned entries, tag, len, save, c; fseek (ifp, offset, SEEK_SET); entries = get4(); if (entries > 255) return; #ifdef LIBRAW_LIBRARY_BUILD imgdata.process_warnings |= LIBRAW_WARN_PARSEFUJI_PROCESSED; #endif while (entries--) { tag = get2(); len = get2(); save = ftell(ifp); if (tag == 0x100) { raw_height = get2(); raw_width = get2(); } else if (tag == 0x121) { height = get2(); if ((width = get2()) == 4284) width += 3; } else if (tag == 0x130) { fuji_layout = fgetc(ifp) >> 7; fuji_width = !(fgetc(ifp) & 8); } else if (tag == 0x131) { filters = 9; FORC(36) { int q = fgetc(ifp); xtrans_abs[0][35 - c] = MAX(0,MIN(q,2)); /* & 3;*/ } } else if (tag == 0x2ff0) { FORC4 cam_mul[c ^ 1] = get2(); } // IB start #ifdef LIBRAW_LIBRARY_BUILD else if (tag == 0x9650) { short a = (short)get2(); float b =fMAX(1.0f, get2()); imgdata.makernotes.fuji.FujiExpoMidPointShift = a / b; } else if (tag == 0x2100) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][c ^ 1] = get2(); } else if (tag == 0x2200) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][c ^ 1] = get2(); } else if (tag == 0x2300) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][c ^ 1] = get2(); } else if (tag == 0x2301) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][c ^ 1] = get2(); } else if (tag == 0x2302) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_WW][c ^ 1] = get2(); } else if (tag == 0x2310) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_L][c ^ 1] = get2(); } else if (tag == 0x2400) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][c ^ 1] = get2(); } #endif // IB end else if (tag == 0xc000) { c = order; order = 0x4949; if ((tag = get4()) > 10000) tag = get4(); if (tag > 10000) tag = get4(); width = tag; height = get4(); #ifdef LIBRAW_LIBRARY_BUILD libraw_internal_data.unpacker_data.posRAFData = save; libraw_internal_data.unpacker_data.lenRAFData = (len>>1); #endif order = c; } fseek (ifp, save+len, SEEK_SET); } height <<= fuji_layout; width >>= fuji_layout; } int CLASS parse_jpeg (int offset) { int len, save, hlen, mark; fseek (ifp, offset, SEEK_SET); if (fgetc(ifp) != 0xff || fgetc(ifp) != 0xd8) return 0; while (fgetc(ifp) == 0xff && (mark = fgetc(ifp)) != 0xda) { order = 0x4d4d; len = get2() - 2; save = ftell(ifp); if (mark == 0xc0 || mark == 0xc3 || mark == 0xc9) { fgetc(ifp); raw_height = get2(); raw_width = get2(); } order = get2(); hlen = get4(); if (get4() == 0x48454150 #ifdef LIBRAW_LIBRARY_BUILD && (save+hlen) >= 0 && (save+hlen)<=ifp->size() #endif ) /* "HEAP" */ { #ifdef LIBRAW_LIBRARY_BUILD imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens; #endif parse_ciff (save+hlen, len-hlen, 0); } if (parse_tiff (save+6)) apply_tiff(); fseek (ifp, save+len, SEEK_SET); } return 1; } void CLASS parse_riff() { unsigned i, size, end; char tag[4], date[64], month[64]; static const char mon[12][4] = { "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" }; struct tm t; order = 0x4949; fread (tag, 4, 1, ifp); size = get4(); end = ftell(ifp) + size; if (!memcmp(tag,"RIFF",4) || !memcmp(tag,"LIST",4)) { int maxloop = 1000; get4(); while (ftell(ifp)+7 < end && !feof(ifp) && maxloop--) parse_riff(); } else if (!memcmp(tag,"nctg",4)) { while (ftell(ifp)+7 < end) { i = get2(); size = get2(); if ((i+1) >> 1 == 10 && size == 20) get_timestamp(0); else fseek (ifp, size, SEEK_CUR); } } else if (!memcmp(tag,"IDIT",4) && size < 64) { fread (date, 64, 1, ifp); date[size] = 0; memset (&t, 0, sizeof t); if (sscanf (date, "%*s %s %d %d:%d:%d %d", month, &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec, &t.tm_year) == 6) { for (i=0; i < 12 && strcasecmp(mon[i],month); i++); t.tm_mon = i; t.tm_year -= 1900; if (mktime(&t) > 0) timestamp = mktime(&t); } } else fseek (ifp, size, SEEK_CUR); } void CLASS parse_qt (int end) { unsigned save, size; char tag[4]; order = 0x4d4d; while (ftell(ifp)+7 < end) { save = ftell(ifp); if ((size = get4()) < 8) return; fread (tag, 4, 1, ifp); if (!memcmp(tag,"moov",4) || !memcmp(tag,"udta",4) || !memcmp(tag,"CNTH",4)) parse_qt (save+size); if (!memcmp(tag,"CNDA",4)) parse_jpeg (ftell(ifp)); fseek (ifp, save+size, SEEK_SET); } } void CLASS parse_smal (int offset, int fsize) { int ver; fseek (ifp, offset+2, SEEK_SET); order = 0x4949; ver = fgetc(ifp); if (ver == 6) fseek (ifp, 5, SEEK_CUR); if (get4() != fsize) return; if (ver > 6) data_offset = get4(); raw_height = height = get2(); raw_width = width = get2(); strcpy (make, "SMaL"); sprintf (model, "v%d %dx%d", ver, width, height); if (ver == 6) load_raw = &CLASS smal_v6_load_raw; if (ver == 9) load_raw = &CLASS smal_v9_load_raw; } void CLASS parse_cine() { unsigned off_head, off_setup, off_image, i; order = 0x4949; fseek (ifp, 4, SEEK_SET); is_raw = get2() == 2; fseek (ifp, 14, SEEK_CUR); is_raw *= get4(); off_head = get4(); off_setup = get4(); off_image = get4(); timestamp = get4(); if ((i = get4())) timestamp = i; fseek (ifp, off_head+4, SEEK_SET); raw_width = get4(); raw_height = get4(); switch (get2(),get2()) { case 8: load_raw = &CLASS eight_bit_load_raw; break; case 16: load_raw = &CLASS unpacked_load_raw; } fseek (ifp, off_setup+792, SEEK_SET); strcpy (make, "CINE"); sprintf (model, "%d", get4()); fseek (ifp, 12, SEEK_CUR); switch ((i=get4()) & 0xffffff) { case 3: filters = 0x94949494; break; case 4: filters = 0x49494949; break; default: is_raw = 0; } fseek (ifp, 72, SEEK_CUR); switch ((get4()+3600) % 360) { case 270: flip = 4; break; case 180: flip = 1; break; case 90: flip = 7; break; case 0: flip = 2; } cam_mul[0] = getreal(11); cam_mul[2] = getreal(11); maximum = ~((~0u) << get4()); fseek (ifp, 668, SEEK_CUR); shutter = get4()/1000000000.0; fseek (ifp, off_image, SEEK_SET); if (shot_select < is_raw) fseek (ifp, shot_select*8, SEEK_CUR); data_offset = (INT64) get4() + 8; data_offset += (INT64) get4() << 32; } void CLASS parse_redcine() { unsigned i, len, rdvo; order = 0x4d4d; is_raw = 0; fseek (ifp, 52, SEEK_SET); width = get4(); height = get4(); fseek (ifp, 0, SEEK_END); fseek (ifp, -(i = ftello(ifp) & 511), SEEK_CUR); if (get4() != i || get4() != 0x52454f42) { #ifdef DCRAW_VERBOSE fprintf (stderr,_("%s: Tail is missing, parsing from head...\n"), ifname); #endif fseek (ifp, 0, SEEK_SET); while ((len = get4()) != EOF) { if (get4() == 0x52454456) if (is_raw++ == shot_select) data_offset = ftello(ifp) - 8; fseek (ifp, len-8, SEEK_CUR); } } else { rdvo = get4(); fseek (ifp, 12, SEEK_CUR); is_raw = get4(); fseeko (ifp, rdvo+8 + shot_select*4, SEEK_SET); data_offset = get4(); } } //@end COMMON char * CLASS foveon_gets (int offset, char *str, int len) { int i; fseek (ifp, offset, SEEK_SET); for (i=0; i < len-1; i++) if ((str[i] = get2()) == 0) break; str[i] = 0; return str; } void CLASS parse_foveon() { int entries, img=0, off, len, tag, save, i, wide, high, pent, poff[256][2]; char name[64], value[64]; order = 0x4949; /* Little-endian */ fseek (ifp, 36, SEEK_SET); flip = get4(); fseek (ifp, -4, SEEK_END); fseek (ifp, get4(), SEEK_SET); if (get4() != 0x64434553) return; /* SECd */ entries = (get4(),get4()); while (entries--) { off = get4(); len = get4(); tag = get4(); save = ftell(ifp); fseek (ifp, off, SEEK_SET); if (get4() != (0x20434553 | (tag << 24))) return; switch (tag) { case 0x47414d49: /* IMAG */ case 0x32414d49: /* IMA2 */ fseek (ifp, 8, SEEK_CUR); pent = get4(); wide = get4(); high = get4(); if (wide > raw_width && high > raw_height) { switch (pent) { case 5: load_flags = 1; case 6: load_raw = &CLASS foveon_sd_load_raw; break; case 30: load_raw = &CLASS foveon_dp_load_raw; break; default: load_raw = 0; } raw_width = wide; raw_height = high; data_offset = off+28; is_foveon = 1; } fseek (ifp, off+28, SEEK_SET); if (fgetc(ifp) == 0xff && fgetc(ifp) == 0xd8 && thumb_length < len-28) { thumb_offset = off+28; thumb_length = len-28; write_thumb = &CLASS jpeg_thumb; } if (++img == 2 && !thumb_length) { thumb_offset = off+24; thumb_width = wide; thumb_height = high; write_thumb = &CLASS foveon_thumb; } break; case 0x464d4143: /* CAMF */ meta_offset = off+8; meta_length = len-28; break; case 0x504f5250: /* PROP */ pent = (get4(),get4()); fseek (ifp, 12, SEEK_CUR); off += pent*8 + 24; if ((unsigned) pent > 256) pent=256; for (i=0; i < pent*2; i++) ((int *)poff)[i] = off + get4()*2; for (i=0; i < pent; i++) { foveon_gets (poff[i][0], name, 64); foveon_gets (poff[i][1], value, 64); if (!strcmp (name, "ISO")) iso_speed = atoi(value); if (!strcmp (name, "CAMMANUF")) strcpy (make, value); if (!strcmp (name, "CAMMODEL")) strcpy (model, value); if (!strcmp (name, "WB_DESC")) strcpy (model2, value); if (!strcmp (name, "TIME")) timestamp = atoi(value); if (!strcmp (name, "EXPTIME")) shutter = atoi(value) / 1000000.0; if (!strcmp (name, "APERTURE")) aperture = atof(value); if (!strcmp (name, "FLENGTH")) focal_len = atof(value); #ifdef LIBRAW_LIBRARY_BUILD if (!strcmp (name, "CAMSERIAL")) strcpy (imgdata.shootinginfo.BodySerial, value); if (!strcmp (name, "FLEQ35MM")) imgdata.lens.makernotes.FocalLengthIn35mmFormat = atof(value); if (!strcmp (name, "LENSARANGE")) { char *sp; imgdata.lens.makernotes.MaxAp4CurFocal = imgdata.lens.makernotes.MinAp4CurFocal = atof(value); sp = strrchr (value, ' '); if (sp) { imgdata.lens.makernotes.MinAp4CurFocal = atof(sp); if (imgdata.lens.makernotes.MaxAp4CurFocal > imgdata.lens.makernotes.MinAp4CurFocal) my_swap (float, imgdata.lens.makernotes.MaxAp4CurFocal, imgdata.lens.makernotes.MinAp4CurFocal); } } if (!strcmp (name, "LENSFRANGE")) { char *sp; imgdata.lens.makernotes.MinFocal = imgdata.lens.makernotes.MaxFocal = atof(value); sp = strrchr (value, ' '); if (sp) { imgdata.lens.makernotes.MaxFocal = atof(sp); if ((imgdata.lens.makernotes.MaxFocal + 0.17f) < imgdata.lens.makernotes.MinFocal) my_swap (float, imgdata.lens.makernotes.MaxFocal, imgdata.lens.makernotes.MinFocal); } } if (!strcmp (name, "LENSMODEL")) { char *sp; imgdata.lens.makernotes.LensID = strtol (value, &sp, 16); // atoi(value); if (imgdata.lens.makernotes.LensID) imgdata.lens.makernotes.LensMount = Sigma_X3F; } } #endif } #ifdef LOCALTIME timestamp = mktime (gmtime (×tamp)); #endif } fseek (ifp, save, SEEK_SET); } } //@out COMMON /* All matrices are from Adobe DNG Converter unless otherwise noted. */ void CLASS adobe_coeff (const char *t_make, const char *t_model #ifdef LIBRAW_LIBRARY_BUILD ,int internal_only #endif ) { static const struct { const char *prefix; int t_black, t_maximum, trans[12]; } table[] = { { "AgfaPhoto DC-833m", 0, 0, /* DJC */ { 11438,-3762,-1115,-2409,9914,2497,-1227,2295,5300 } }, { "Apple QuickTake", 0, 0, /* DJC */ { 21392,-5653,-3353,2406,8010,-415,7166,1427,2078 } }, {"Broadcom RPi IMX219", 66, 0x3ff, { 5302,1083,-728,-5320,14112,1699,-863,2371,5136 } }, /* LibRaw */ { "Broadcom RPi OV5647", 16, 0x3ff, { 12782,-4059,-379,-478,9066,1413,1340,1513,5176 } }, /* DJC */ { "Canon EOS D2000", 0, 0, { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } }, { "Canon EOS D6000", 0, 0, { 20482,-7172,-3125,-1033,10410,-285,2542,226,3136 } }, { "Canon EOS D30", 0, 0, { 9805,-2689,-1312,-5803,13064,3068,-2438,3075,8775 } }, { "Canon EOS D60", 0, 0xfa0, { 6188,-1341,-890,-7168,14489,2937,-2640,3228,8483 } }, { "Canon EOS 5DS", 0, 0x3c96, { 6250,-711,-808,-5153,12794,2636,-1249,2198,5610 } }, { "Canon EOS 5D Mark IV", 0, 0, { 6446, -366, -864, -4436, 12204, 2513, -952, 2496, 6348 }}, { "Canon EOS 5D Mark III", 0, 0x3c80, { 6722,-635,-963,-4287,12460,2028,-908,2162,5668 } }, { "Canon EOS 5D Mark II", 0, 0x3cf0, { 4716,603,-830,-7798,15474,2480,-1496,1937,6651 } }, { "Canon EOS 5D", 0, 0xe6c, { 6347,-479,-972,-8297,15954,2480,-1968,2131,7649 } }, { "Canon EOS 6D", 0, 0x3c82, { 8621,-2197,-787,-3150,11358,912,-1161,2400,4836 } }, { "Canon EOS 7D Mark II", 0, 0x3510, { 7268,-1082,-969,-4186,11839,2663,-825,2029,5839 } }, { "Canon EOS 7D", 0, 0x3510, { 6844,-996,-856,-3876,11761,2396,-593,1772,6198 } }, { "Canon EOS 80D", 0, 0, { 7457,-671,-937,-4849,12495,2643,-1213,2354,5492 } }, { "Canon EOS 10D", 0, 0xfa0, { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } }, { "Canon EOS 20Da", 0, 0, { 14155,-5065,-1382,-6550,14633,2039,-1623,1824,6561 } }, { "Canon EOS 20D", 0, 0xfff, { 6599,-537,-891,-8071,15783,2424,-1983,2234,7462 } }, { "Canon EOS 30D", 0, 0, { 6257,-303,-1000,-7880,15621,2396,-1714,1904,7046 } }, { "Canon EOS 40D", 0, 0x3f60, { 6071,-747,-856,-7653,15365,2441,-2025,2553,7315 } }, { "Canon EOS 50D", 0, 0x3d93, { 4920,616,-593,-6493,13964,2784,-1774,3178,7005 } }, { "Canon EOS 60D", 0, 0x2ff7, { 6719,-994,-925,-4408,12426,2211,-887,2129,6051 } }, { "Canon EOS 70D", 0, 0x3bc7, { 7034,-804,-1014,-4420,12564,2058,-851,1994,5758 } }, { "Canon EOS 100D", 0, 0x350f, { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } }, { "Canon EOS 300D", 0, 0xfa0, { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } }, { "Canon EOS 350D", 0, 0xfff, { 6018,-617,-965,-8645,15881,2975,-1530,1719,7642 } }, { "Canon EOS 400D", 0, 0xe8e, { 7054,-1501,-990,-8156,15544,2812,-1278,1414,7796 } }, { "Canon EOS 450D", 0, 0x390d, { 5784,-262,-821,-7539,15064,2672,-1982,2681,7427 } }, { "Canon EOS 500D", 0, 0x3479, { 4763,712,-646,-6821,14399,2640,-1921,3276,6561 } }, { "Canon EOS 550D", 0, 0x3dd7, { 6941,-1164,-857,-3825,11597,2534,-416,1540,6039 } }, { "Canon EOS 600D", 0, 0x3510, { 6461,-907,-882,-4300,12184,2378,-819,1944,5931 } }, { "Canon EOS 650D", 0, 0x354d, { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } }, { "Canon EOS 750D", 0, 0x3c00, { 6362,-823,-847,-4426,12109,2616,-743,1857,5635 } }, { "Canon EOS 760D", 0, 0x3c00, { 6362,-823,-847,-4426,12109,2616,-743,1857,5635 } }, { "Canon EOS 700D", 0, 0x3c00, { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } }, { "Canon EOS 1000D", 0, 0xe43, { 6771,-1139,-977,-7818,15123,2928,-1244,1437,7533 } }, { "Canon EOS 1100D", 0, 0x3510, { 6444,-904,-893,-4563,12308,2535,-903,2016,6728 } }, { "Canon EOS 1200D", 0, 0x37c2, { 6461,-907,-882,-4300,12184,2378,-819,1944,5931 } }, { "Canon EOS 1300D", 0, 0x37c2, { 6939, -1016, -866, -4428, 12473, 2177, -1175, 2178, 6162 } }, { "Canon EOS M3", 0, 0, { 6362,-823,-847,-4426,12109,2616,-743,1857,5635 } }, { "Canon EOS M5", 0, 0, /* Adobe */ { 8532, -701, -1167, -4095, 11879, 2508, -797, 2424, 7010 }}, { "Canon EOS M10", 0, 0, { 6400,-480,-888,-5294,13416,2047,-1296,2203,6137 } }, { "Canon EOS M", 0, 0, { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } }, { "Canon EOS-1Ds Mark III", 0, 0x3bb0, { 5859,-211,-930,-8255,16017,2353,-1732,1887,7448 } }, { "Canon EOS-1Ds Mark II", 0, 0xe80, { 6517,-602,-867,-8180,15926,2378,-1618,1771,7633 } }, { "Canon EOS-1D Mark IV", 0, 0x3bb0, { 6014,-220,-795,-4109,12014,2361,-561,1824,5787 } }, { "Canon EOS-1D Mark III", 0, 0x3bb0, { 6291,-540,-976,-8350,16145,2311,-1714,1858,7326 } }, { "Canon EOS-1D Mark II N", 0, 0xe80, { 6240,-466,-822,-8180,15825,2500,-1801,1938,8042 } }, { "Canon EOS-1D Mark II", 0, 0xe80, { 6264,-582,-724,-8312,15948,2504,-1744,1919,8664 } }, { "Canon EOS-1DS", 0, 0xe20, { 4374,3631,-1743,-7520,15212,2472,-2892,3632,8161 } }, { "Canon EOS-1D C", 0, 0x3c4e, { 6847,-614,-1014,-4669,12737,2139,-1197,2488,6846 } }, { "Canon EOS-1D X Mark II", 0, 0x3c4e, { 7596,-978,967,-4808,12571,2503,-1398,2567,5752 } }, { "Canon EOS-1D X", 0, 0x3c4e, { 6847,-614,-1014,-4669,12737,2139,-1197,2488,6846 } }, { "Canon EOS-1D", 0, 0xe20, { 6806,-179,-1020,-8097,16415,1687,-3267,4236,7690 } }, { "Canon EOS C500", 853, 0, /* DJC */ { 17851,-10604,922,-7425,16662,763,-3660,3636,22278 } }, { "Canon PowerShot A530", 0, 0, { 0 } }, /* don't want the A5 matrix */ { "Canon PowerShot A50", 0, 0, { -5300,9846,1776,3436,684,3939,-5540,9879,6200,-1404,11175,217 } }, { "Canon PowerShot A5", 0, 0, { -4801,9475,1952,2926,1611,4094,-5259,10164,5947,-1554,10883,547 } }, { "Canon PowerShot G10", 0, 0, { 11093,-3906,-1028,-5047,12492,2879,-1003,1750,5561 } }, { "Canon PowerShot G11", 0, 0, { 12177,-4817,-1069,-1612,9864,2049,-98,850,4471 } }, { "Canon PowerShot G12", 0, 0, { 13244,-5501,-1248,-1508,9858,1935,-270,1083,4366 } }, { "Canon PowerShot G15", 0, 0, { 7474,-2301,-567,-4056,11456,2975,-222,716,4181 } }, { "Canon PowerShot G16", 0, 0, { 14130,-8071,127,2199,6528,1551,3402,-1721,4960 } }, { "Canon PowerShot G1 X Mark II", 0, 0, { 7378,-1255,-1043,-4088,12251,2048,-876,1946,5805 } }, { "Canon PowerShot G1 X", 0, 0, { 7378,-1255,-1043,-4088,12251,2048,-876,1946,5805 } }, { "Canon PowerShot G1", 0, 0, { -4778,9467,2172,4743,-1141,4344,-5146,9908,6077,-1566,11051,557 } }, { "Canon PowerShot G2", 0, 0, { 9087,-2693,-1049,-6715,14382,2537,-2291,2819,7790 } }, { "Canon PowerShot G3 X", 0, 0, { 9701,-3857,-921,-3149,11537,1817,-786,1817,5147 } }, { "Canon PowerShot G3", 0, 0, { 9212,-2781,-1073,-6573,14189,2605,-2300,2844,7664 } }, { "Canon PowerShot G5 X",0, 0, { 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 } }, { "Canon PowerShot G5", 0, 0, { 9757,-2872,-933,-5972,13861,2301,-1622,2328,7212 } }, { "Canon PowerShot G6", 0, 0, { 9877,-3775,-871,-7613,14807,3072,-1448,1305,7485 } }, { "Canon PowerShot G7 X Mark II", 0, 0, { 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 } }, { "Canon PowerShot G7 X", 0, 0, { 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 } }, { "Canon PowerShot G9 X",0, 0, { 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 } }, { "Canon PowerShot G9", 0, 0, { 7368,-2141,-598,-5621,13254,2625,-1418,1696,5743 } }, { "Canon PowerShot Pro1", 0, 0, { 10062,-3522,-999,-7643,15117,2730,-765,817,7323 } }, { "Canon PowerShot Pro70", 34, 0, { -4155,9818,1529,3939,-25,4522,-5521,9870,6610,-2238,10873,1342 } }, { "Canon PowerShot Pro90", 0, 0, { -4963,9896,2235,4642,-987,4294,-5162,10011,5859,-1770,11230,577 } }, { "Canon PowerShot S30", 0, 0, { 10566,-3652,-1129,-6552,14662,2006,-2197,2581,7670 } }, { "Canon PowerShot S40", 0, 0, { 8510,-2487,-940,-6869,14231,2900,-2318,2829,9013 } }, { "Canon PowerShot S45", 0, 0, { 8163,-2333,-955,-6682,14174,2751,-2077,2597,8041 } }, { "Canon PowerShot S50", 0, 0, { 8882,-2571,-863,-6348,14234,2288,-1516,2172,6569 } }, { "Canon PowerShot S60", 0, 0, { 8795,-2482,-797,-7804,15403,2573,-1422,1996,7082 } }, { "Canon PowerShot S70", 0, 0, { 9976,-3810,-832,-7115,14463,2906,-901,989,7889 } }, { "Canon PowerShot S90", 0, 0, { 12374,-5016,-1049,-1677,9902,2078,-83,852,4683 } }, { "Canon PowerShot S95", 0, 0, { 13440,-5896,-1279,-1236,9598,1931,-180,1001,4651 } }, { "Canon PowerShot S120", 0, 0, { 6961,-1685,-695,-4625,12945,1836,-1114,2152,5518 } }, { "Canon PowerShot S110", 0, 0, { 8039,-2643,-654,-3783,11230,2930,-206,690,4194 } }, { "Canon PowerShot S100", 0, 0, { 7968,-2565,-636,-2873,10697,2513,180,667,4211 } }, { "Canon PowerShot SX1 IS", 0, 0, { 6578,-259,-502,-5974,13030,3309,-308,1058,4970 } }, { "Canon PowerShot SX50 HS", 0, 0, { 12432,-4753,-1247,-2110,10691,1629,-412,1623,4926 } }, { "Canon PowerShot SX60 HS", 0, 0, { 13161,-5451,-1344,-1989,10654,1531,-47,1271,4955 } }, { "Canon PowerShot A3300", 0, 0, /* DJC */ { 10826,-3654,-1023,-3215,11310,1906,0,999,4960 } }, { "Canon PowerShot A470", 0, 0, /* DJC */ { 12513,-4407,-1242,-2680,10276,2405,-878,2215,4734 } }, { "Canon PowerShot A610", 0, 0, /* DJC */ { 15591,-6402,-1592,-5365,13198,2168,-1300,1824,5075 } }, { "Canon PowerShot A620", 0, 0, /* DJC */ { 15265,-6193,-1558,-4125,12116,2010,-888,1639,5220 } }, { "Canon PowerShot A630", 0, 0, /* DJC */ { 14201,-5308,-1757,-6087,14472,1617,-2191,3105,5348 } }, { "Canon PowerShot A640", 0, 0, /* DJC */ { 13124,-5329,-1390,-3602,11658,1944,-1612,2863,4885 } }, { "Canon PowerShot A650", 0, 0, /* DJC */ { 9427,-3036,-959,-2581,10671,1911,-1039,1982,4430 } }, { "Canon PowerShot A720", 0, 0, /* DJC */ { 14573,-5482,-1546,-1266,9799,1468,-1040,1912,3810 } }, { "Canon PowerShot S3 IS", 0, 0, /* DJC */ { 14062,-5199,-1446,-4712,12470,2243,-1286,2028,4836 } }, { "Canon PowerShot SX110 IS", 0, 0, /* DJC */ { 14134,-5576,-1527,-1991,10719,1273,-1158,1929,3581 } }, { "Canon PowerShot SX220", 0, 0, /* DJC */ { 13898,-5076,-1447,-1405,10109,1297,-244,1860,3687 } }, { "Canon IXUS 160", 0, 0, /* DJC */ { 11657,-3781,-1136,-3544,11262,2283,-160,1219,4700 } }, { "Casio EX-S20", 0, 0, /* DJC */ { 11634,-3924,-1128,-4968,12954,2015,-1588,2648,7206 } }, { "Casio EX-Z750", 0, 0, /* DJC */ { 10819,-3873,-1099,-4903,13730,1175,-1755,3751,4632 } }, { "Casio EX-Z10", 128, 0xfff, /* DJC */ { 9790,-3338,-603,-2321,10222,2099,-344,1273,4799 } }, { "CINE 650", 0, 0, { 3390,480,-500,-800,3610,340,-550,2336,1192 } }, { "CINE 660", 0, 0, { 3390,480,-500,-800,3610,340,-550,2336,1192 } }, { "CINE", 0, 0, { 20183,-4295,-423,-3940,15330,3985,-280,4870,9800 } }, { "Contax N Digital", 0, 0xf1e, { 7777,1285,-1053,-9280,16543,2916,-3677,5679,7060 } }, { "DXO ONE", 0, 0, { 6596,-2079,-562,-4782,13016,1933,-970,1581,5181 } }, { "Epson R-D1", 0, 0, { 6827,-1878,-732,-8429,16012,2564,-704,592,7145 } }, { "Fujifilm E550", 0, 0, { 11044,-3888,-1120,-7248,15168,2208,-1531,2277,8069 } }, { "Fujifilm E900", 0, 0, { 9183,-2526,-1078,-7461,15071,2574,-2022,2440,8639 } }, { "Fujifilm F5", 0, 0, { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, { "Fujifilm F6", 0, 0, { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, { "Fujifilm F77", 0, 0xfe9, { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, { "Fujifilm F7", 0, 0, { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } }, { "Fujifilm F8", 0, 0, { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, { "Fujifilm S100FS", 514, 0, { 11521,-4355,-1065,-6524,13767,3058,-1466,1984,6045 } }, { "Fujifilm S1", 0, 0, { 12297,-4882,-1202,-2106,10691,1623,-88,1312,4790 } }, { "Fujifilm S20Pro", 0, 0, { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } }, { "Fujifilm S20", 512, 0x3fff, { 11401,-4498,-1312,-5088,12751,2613,-838,1568,5941 } }, { "Fujifilm S2Pro", 128, 0, { 12492,-4690,-1402,-7033,15423,1647,-1507,2111,7697 } }, { "Fujifilm S3Pro", 0, 0, { 11807,-4612,-1294,-8927,16968,1988,-2120,2741,8006 } }, { "Fujifilm S5Pro", 0, 0, { 12300,-5110,-1304,-9117,17143,1998,-1947,2448,8100 } }, { "Fujifilm S5000", 0, 0, { 8754,-2732,-1019,-7204,15069,2276,-1702,2334,6982 } }, { "Fujifilm S5100", 0, 0, { 11940,-4431,-1255,-6766,14428,2542,-993,1165,7421 } }, { "Fujifilm S5500", 0, 0, { 11940,-4431,-1255,-6766,14428,2542,-993,1165,7421 } }, { "Fujifilm S5200", 0, 0, { 9636,-2804,-988,-7442,15040,2589,-1803,2311,8621 } }, { "Fujifilm S5600", 0, 0, { 9636,-2804,-988,-7442,15040,2589,-1803,2311,8621 } }, { "Fujifilm S6", 0, 0, { 12628,-4887,-1401,-6861,14996,1962,-2198,2782,7091 } }, { "Fujifilm S7000", 0, 0, { 10190,-3506,-1312,-7153,15051,2238,-2003,2399,7505 } }, { "Fujifilm S9000", 0, 0, { 10491,-3423,-1145,-7385,15027,2538,-1809,2275,8692 } }, { "Fujifilm S9500", 0, 0, { 10491,-3423,-1145,-7385,15027,2538,-1809,2275,8692 } }, { "Fujifilm S9100", 0, 0, { 12343,-4515,-1285,-7165,14899,2435,-1895,2496,8800 } }, { "Fujifilm S9600", 0, 0, { 12343,-4515,-1285,-7165,14899,2435,-1895,2496,8800 } }, { "Fujifilm SL1000", 0, 0, { 11705,-4262,-1107,-2282,10791,1709,-555,1713,4945 } }, { "Fujifilm IS-1", 0, 0, { 21461,-10807,-1441,-2332,10599,1999,289,875,7703 } }, { "Fujifilm IS Pro", 0, 0, { 12300,-5110,-1304,-9117,17143,1998,-1947,2448,8100 } }, { "Fujifilm HS10 HS11", 0, 0xf68, { 12440,-3954,-1183,-1123,9674,1708,-83,1614,4086 } }, { "Fujifilm HS2", 0, 0, { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, { "Fujifilm HS3", 0, 0, { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, { "Fujifilm HS50EXR", 0, 0, { 12085,-4727,-953,-3257,11489,2002,-511,2046,4592 } }, { "Fujifilm F900EXR", 0, 0, { 12085,-4727,-953,-3257,11489,2002,-511,2046,4592 } }, { "Fujifilm X100S", 0, 0, { 10592,-4262,-1008,-3514,11355,2465,-870,2025,6386 } }, { "Fujifilm X100T", 0, 0, { 10592,-4262,-1008,-3514,11355,2465,-870,2025,6386 } }, { "Fujifilm X100", 0, 0, { 12161,-4457,-1069,-5034,12874,2400,-795,1724,6904 } }, { "Fujifilm X10", 0, 0, { 13509,-6199,-1254,-4430,12733,1865,-331,1441,5022 } }, { "Fujifilm X20", 0, 0, { 11768,-4971,-1133,-4904,12927,2183,-480,1723,4605 } }, { "Fujifilm X30", 0, 0, { 12328,-5256,-1144,-4469,12927,1675,-87,1291,4351 } }, { "Fujifilm X70", 0, 0, { 10450,-4329,-878,-3217,11105,2421,-752,1758,6519 } }, { "Fujifilm X-Pro1", 0, 0, { 10413,-3996,-993,-3721,11640,2361,-733,1540,6011 } }, { "Fujifilm X-Pro2", 0, 0, { 11434,-4948,-1210,-3746,12042,1903,-666,1479,5235 } }, { "Fujifilm X-A1", 0, 0, { 11086,-4555,-839,-3512,11310,2517,-815,1341,5940 } }, { "Fujifilm X-A2", 0, 0, { 10763,-4560,-917,-3346,11311,2322,-475,1135,5843 } }, { "Fujifilm X-E1", 0, 0, { 10413,-3996,-993,-3721,11640,2361,-733,1540,6011 } }, { "Fujifilm X-E2S", 0, 0, { 11562,-5118,-961,-3022,11007,2311,-525,1569,6097 } }, { "Fujifilm X-E2", 0, 0, { 12066,-5927,-367,-1969,9878,1503,-721,2034,5453 } }, { "Fujifilm XF1", 0, 0, { 13509,-6199,-1254,-4430,12733,1865,-331,1441,5022 } }, { "Fujifilm X-M1", 0, 0, { 13193,-6685,-425,-2229,10458,1534,-878,1763,5217 } }, { "Fujifilm X-S1", 0, 0, { 13509,-6199,-1254,-4430,12733,1865,-331,1441,5022 } }, { "Fujifilm X-T10", 0, 0, { 10763,-4560,-917,-3346,11311,2322,-475,1135,5843 } }, { "Fujifilm X-T1", 0, 0, { 8458,-2451,-855,-4597,12447,2407,-1475,2482,6526 } }, { "Fujifilm X-T2", 0, 0, { 11434,-4948,-1210,-3746,12042,1903,-666,1479,5235 } }, { "Fujifilm XQ1", 0, 0, { 9252,-2704,-1064,-5893,14265,1717,-1101,2341,4349 } }, { "Fujifilm XQ2", 0, 0, { 9252,-2704,-1064,-5893,14265,1717,-1101,2341,4349 } }, { "GITUP GIT2", 3200, 0, {8489, -2583,-1036,-8051,15583,2643,-1307,1407,7354}}, { "Hasselblad Lunar", 0, 0, { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } }, { "Hasselblad Stellar", -800, 0, { 8651,-2754,-1057,-3464,12207,1373,-568,1398,4434 } }, { "Hasselblad CFV", 0, 0, /* Adobe */ { 8519, -3260, -280, -5081, 13459, 1738, -1449, 2960, 7809, } }, { "Hasselblad H-16MP", 0, 0, /* LibRaw */ { 17765,-5322,-1734,-6168,13354,2135,-264,2524,7440 } }, { "Hasselblad H-22MP", 0, 0, /* LibRaw */ { 17765,-5322,-1734,-6168,13354,2135,-264,2524,7440 } }, { "Hasselblad H-31MP",0, 0, /* LibRaw */ { 14480,-5448,-1686,-3534,13123,2260,384,2952,7232 } }, { "Hasselblad H-39MP",0, 0, /* Adobe */ { 3857,452, -46, -6008, 14477, 1596, -2627, 4481, 5718 } }, { "Hasselblad H3D-50", 0, 0, /* Adobe */ { 3857,452, -46, -6008, 14477, 1596, -2627, 4481, 5718 } }, { "Hasselblad H4D-40",0, 0, /* LibRaw */ { 6325,-860,-957,-6559,15945,266,167,770,5936 } }, { "Hasselblad H4D-50",0, 0, /* LibRaw */ { 15283,-6272,-465,-2030,16031,478,-2379,390,7965 } }, { "Hasselblad H4D-60",0, 0, /* Adobe */ { 9662, -684, -279, -4903, 12293, 2950, -344, 1669, 6024 } }, { "Hasselblad H5D-50c",0, 0, /* Adobe */ { 4932, -835, 141, -4878, 11868, 3437, -1138, 1961, 7067 } }, { "Hasselblad H5D-50",0, 0, /* Adobe */ { 5656, -659, -346, -3923, 12306, 1791, -1602, 3509, 5442 } }, { "Hasselblad X1D",0, 0, /* Adobe */ {4932, -835, 141, -4878, 11868, 3437, -1138, 1961, 7067 }}, { "HTC One A9", 64, 1023, /* this is CM1 transposed */ { 101, -20, -2, -11, 145, 41, -24, 1, 56 } }, { "Imacon Ixpress", 0, 0, /* DJC */ { 7025,-1415,-704,-5188,13765,1424,-1248,2742,6038 } }, { "Kodak NC2000", 0, 0, { 13891,-6055,-803,-465,9919,642,2121,82,1291 } }, { "Kodak DCS315C", -8, 0, { 17523,-4827,-2510,756,8546,-137,6113,1649,2250 } }, { "Kodak DCS330C", -8, 0, { 20620,-7572,-2801,-103,10073,-396,3551,-233,2220 } }, { "Kodak DCS420", 0, 0, { 10868,-1852,-644,-1537,11083,484,2343,628,2216 } }, { "Kodak DCS460", 0, 0, { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } }, { "Kodak EOSDCS1", 0, 0, { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } }, { "Kodak EOSDCS3B", 0, 0, { 9898,-2700,-940,-2478,12219,206,1985,634,1031 } }, { "Kodak DCS520C", -178, 0, { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } }, { "Kodak DCS560C", -177, 0, { 20482,-7172,-3125,-1033,10410,-285,2542,226,3136 } }, { "Kodak DCS620C", -177, 0, { 23617,-10175,-3149,-2054,11749,-272,2586,-489,3453 } }, { "Kodak DCS620X", -176, 0, { 13095,-6231,154,12221,-21,-2137,895,4602,2258 } }, { "Kodak DCS660C", -173, 0, { 18244,-6351,-2739,-791,11193,-521,3711,-129,2802 } }, { "Kodak DCS720X", 0, 0, { 11775,-5884,950,9556,1846,-1286,-1019,6221,2728 } }, { "Kodak DCS760C", 0, 0, { 16623,-6309,-1411,-4344,13923,323,2285,274,2926 } }, { "Kodak DCS Pro SLR", 0, 0, { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } }, { "Kodak DCS Pro 14nx", 0, 0, { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } }, { "Kodak DCS Pro 14", 0, 0, { 7791,3128,-776,-8588,16458,2039,-2455,4006,6198 } }, { "Kodak ProBack645", 0, 0, { 16414,-6060,-1470,-3555,13037,473,2545,122,4948 } }, { "Kodak ProBack", 0, 0, { 21179,-8316,-2918,-915,11019,-165,3477,-180,4210 } }, { "Kodak P712", 0, 0, { 9658,-3314,-823,-5163,12695,2768,-1342,1843,6044 } }, { "Kodak P850", 0, 0xf7c, { 10511,-3836,-1102,-6946,14587,2558,-1481,1792,6246 } }, { "Kodak P880", 0, 0xfff, { 12805,-4662,-1376,-7480,15267,2360,-1626,2194,7904 } }, { "Kodak EasyShare Z980", 0, 0, { 11313,-3559,-1101,-3893,11891,2257,-1214,2398,4908 } }, { "Kodak EasyShare Z981", 0, 0, { 12729,-4717,-1188,-1367,9187,2582,274,860,4411 } }, { "Kodak EasyShare Z990", 0, 0xfed, { 11749,-4048,-1309,-1867,10572,1489,-138,1449,4522 } }, { "Kodak EASYSHARE Z1015", 0, 0xef1, { 11265,-4286,-992,-4694,12343,2647,-1090,1523,5447 } }, { "Leaf CMost", 0, 0, { 3952,2189,449,-6701,14585,2275,-4536,7349,6536 } }, { "Leaf Valeo 6", 0, 0, { 3952,2189,449,-6701,14585,2275,-4536,7349,6536 } }, { "Leaf Aptus 54S", 0, 0, { 8236,1746,-1314,-8251,15953,2428,-3673,5786,5771 } }, { "Leaf Aptus 65", 0, 0, { 7914,1414,-1190,-8777,16582,2280,-2811,4605,5562 } }, { "Leaf Aptus 75", 0, 0, { 7914,1414,-1190,-8777,16582,2280,-2811,4605,5562 } }, { "Leaf Credo 40", 0, 0, { 8035, 435, -962, -6001, 13872, 2320, -1159, 3065, 5434 } }, { "Leaf Credo 50", 0, 0, { 3984, 0, 0, 0, 10000, 0, 0, 0, 7666 } }, { "Leaf Credo 60", 0, 0, { 8035, 435, -962, -6001, 13872,2320,-1159,3065,5434 } }, { "Leaf Credo 80", 0, 0, { 6294, 686, -712, -5435, 13417, 2211, -1006, 2435, 5042 } }, { "Leaf", 0, 0, { 8236,1746,-1314,-8251,15953,2428,-3673,5786,5771 } }, { "Mamiya ZD", 0, 0, { 7645,2579,-1363,-8689,16717,2015,-3712,5941,5961 } }, { "Micron 2010", 110, 0, /* DJC */ { 16695,-3761,-2151,155,9682,163,3433,951,4904 } }, { "Minolta DiMAGE 5", 0, 0xf7d, { 8983,-2942,-963,-6556,14476,2237,-2426,2887,8014 } }, { "Minolta DiMAGE 7Hi", 0, 0xf7d, { 11368,-3894,-1242,-6521,14358,2339,-2475,3056,7285 } }, { "Minolta DiMAGE 7", 0, 0xf7d, { 9144,-2777,-998,-6676,14556,2281,-2470,3019,7744 } }, { "Minolta DiMAGE A1", 0, 0xf8b, { 9274,-2547,-1167,-8220,16323,1943,-2273,2720,8340 } }, { "Minolta DiMAGE A200", 0, 0, { 8560,-2487,-986,-8112,15535,2771,-1209,1324,7743 } }, { "Minolta DiMAGE A2", 0, 0xf8f, { 9097,-2726,-1053,-8073,15506,2762,-966,981,7763 } }, { "Minolta DiMAGE Z2", 0, 0, /* DJC */ { 11280,-3564,-1370,-4655,12374,2282,-1423,2168,5396 } }, { "Minolta DYNAX 5", 0, 0xffb, { 10284,-3283,-1086,-7957,15762,2316,-829,882,6644 } }, { "Minolta DYNAX 7", 0, 0xffb, { 10239,-3104,-1099,-8037,15727,2451,-927,925,6871 } }, { "Motorola PIXL", 0, 0, /* DJC */ { 8898,-989,-1033,-3292,11619,1674,-661,3178,5216 } }, { "Nikon D100", 0, 0, { 5902,-933,-782,-8983,16719,2354,-1402,1455,6464 } }, { "Nikon D1H", 0, 0, { 7577,-2166,-926,-7454,15592,1934,-2377,2808,8606 } }, { "Nikon D1X", 0, 0, { 7702,-2245,-975,-9114,17242,1875,-2679,3055,8521 } }, { "Nikon D1", 0, 0, /* multiplied by 2.218750, 1.0, 1.148438 */ { 16772,-4726,-2141,-7611,15713,1972,-2846,3494,9521 } }, { "Nikon D200", 0, 0xfbc, { 8367,-2248,-763,-8758,16447,2422,-1527,1550,8053 } }, { "Nikon D2H", 0, 0, { 5710,-901,-615,-8594,16617,2024,-2975,4120,6830 } }, { "Nikon D2X", 0, 0, { 10231,-2769,-1255,-8301,15900,2552,-797,680,7148 } }, { "Nikon D3000", 0, 0, { 8736,-2458,-935,-9075,16894,2251,-1354,1242,8263 } }, { "Nikon D3100", 0, 0, { 7911,-2167,-813,-5327,13150,2408,-1288,2483,7968 } }, { "Nikon D3200", 0, 0xfb9, { 7013,-1408,-635,-5268,12902,2640,-1470,2801,7379 } }, { "Nikon D3300", 0, 0, { 6988,-1384,-714,-5631,13410,2447,-1485,2204,7318 } }, { "Nikon D3400", 0, 0, { 6988,-1384,-714,-5631,13410,2447,-1485,2204,7318 } }, { "Nikon D300", 0, 0, { 9030,-1992,-715,-8465,16302,2255,-2689,3217,8069 } }, { "Nikon D3X", 0, 0, { 7171,-1986,-648,-8085,15555,2718,-2170,2512,7457 } }, { "Nikon D3S", 0, 0, { 8828,-2406,-694,-4874,12603,2541,-660,1509,7587 } }, { "Nikon D3", 0, 0, { 8139,-2171,-663,-8747,16541,2295,-1925,2008,8093 } }, { "Nikon D40X", 0, 0, { 8819,-2543,-911,-9025,16928,2151,-1329,1213,8449 } }, { "Nikon D40", 0, 0, { 6992,-1668,-806,-8138,15748,2543,-874,850,7897 } }, { "Nikon D4S", 0, 0, { 8598,-2848,-857,-5618,13606,2195,-1002,1773,7137 } }, { "Nikon D4", 0, 0, { 8598,-2848,-857,-5618,13606,2195,-1002,1773,7137 } }, { "Nikon Df", 0, 0, { 8598,-2848,-857,-5618,13606,2195,-1002,1773,7137 } }, { "Nikon D5000", 0, 0xf00, { 7309,-1403,-519,-8474,16008,2622,-2433,2826,8064 } }, { "Nikon D5100", 0, 0x3de6, { 8198,-2239,-724,-4871,12389,2798,-1043,2050,7181 } }, { "Nikon D5200", 0, 0, { 8322,-3112,-1047,-6367,14342,2179,-988,1638,6394 } }, { "Nikon D5300", 0, 0, { 6988,-1384,-714,-5631,13410,2447,-1485,2204,7318 } }, { "Nikon D5500", 0, 0, { 8821,-2938,-785,-4178,12142,2287,-824,1651,6860 } }, { "Nikon D500", 0, 0, { 8813,-3210,-1036,-4703,12868,2021,-1054,1940,6129 } }, { "Nikon D50", 0, 0, { 7732,-2422,-789,-8238,15884,2498,-859,783,7330 } }, { "Nikon D5", 0, 0, { 9200,-3522,-992,-5755,13803,2117,-753,1486,6338 } }, { "Nikon D600", 0, 0x3e07, { 8178,-2245,-609,-4857,12394,2776,-1207,2086,7298 } }, { "Nikon D610",0, 0, { 10426,-4005,-444,-3565,11764,1403,-1206,2266,6549 } }, { "Nikon D60", 0, 0, { 8736,-2458,-935,-9075,16894,2251,-1354,1242,8263 } }, { "Nikon D7000", 0, 0, { 8198,-2239,-724,-4871,12389,2798,-1043,2050,7181 } }, { "Nikon D7100", 0, 0, { 8322,-3112,-1047,-6367,14342,2179,-988,1638,6394 } }, { "Nikon D7200", 0, 0, { 8322,-3112,-1047,-6367,14342,2179,-988,1638,6394 } }, { "Nikon D750", -600, 0, { 9020,-2890,-715,-4535,12436,2348,-934,1919,7086 } }, { "Nikon D700", 0, 0, { 8139,-2171,-663,-8747,16541,2295,-1925,2008,8093 } }, { "Nikon D70", 0, 0, { 7732,-2422,-789,-8238,15884,2498,-859,783,7330 } }, { "Nikon D810A", 0, 0, { 11973, -5685, -888, -1965, 10326, 1901, -115, 1123, 7169 } }, { "Nikon D810", 0, 0, { 9369,-3195,-791,-4488,12430,2301,-893,1796,6872 } }, { "Nikon D800", 0, 0, { 7866,-2108,-555,-4869,12483,2681,-1176,2069,7501 } }, { "Nikon D80", 0, 0, { 8629,-2410,-883,-9055,16940,2171,-1490,1363,8520 } }, { "Nikon D90", 0, 0xf00, { 7309,-1403,-519,-8474,16008,2622,-2434,2826,8064 } }, { "Nikon E700", 0, 0x3dd, /* DJC */ { -3746,10611,1665,9621,-1734,2114,-2389,7082,3064,3406,6116,-244 } }, { "Nikon E800", 0, 0x3dd, /* DJC */ { -3746,10611,1665,9621,-1734,2114,-2389,7082,3064,3406,6116,-244 } }, { "Nikon E950", 0, 0x3dd, /* DJC */ { -3746,10611,1665,9621,-1734,2114,-2389,7082,3064,3406,6116,-244 } }, { "Nikon E995", 0, 0, /* copied from E5000 */ { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, { "Nikon E2100", 0, 0, /* copied from Z2, new white balance */ { 13142,-4152,-1596,-4655,12374,2282,-1769,2696,6711 } }, { "Nikon E2500", 0, 0, { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, { "Nikon E3200", 0, 0, /* DJC */ { 9846,-2085,-1019,-3278,11109,2170,-774,2134,5745 } }, { "Nikon E4300", 0, 0, /* copied from Minolta DiMAGE Z2 */ { 11280,-3564,-1370,-4655,12374,2282,-1423,2168,5396 } }, { "Nikon E4500", 0, 0, { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, { "Nikon E5000", 0, 0, { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, { "Nikon E5400", 0, 0, { 9349,-2987,-1001,-7919,15766,2266,-2098,2680,6839 } }, { "Nikon E5700", 0, 0, { -5368,11478,2368,5537,-113,3148,-4969,10021,5782,778,9028,211 } }, { "Nikon E8400", 0, 0, { 7842,-2320,-992,-8154,15718,2599,-1098,1342,7560 } }, { "Nikon E8700", 0, 0, { 8489,-2583,-1036,-8051,15583,2643,-1307,1407,7354 } }, { "Nikon E8800", 0, 0, { 7971,-2314,-913,-8451,15762,2894,-1442,1520,7610 } }, { "Nikon COOLPIX A", 0, 0, { 8198,-2239,-724,-4871,12389,2798,-1043,2050,7181 } }, { "Nikon COOLPIX B700", 0, 0, { 14387,-6014,-1299,-1357,9975,1616,467,1047,4744 } }, { "Nikon COOLPIX P330", -200, 0, { 10321,-3920,-931,-2750,11146,1824,-442,1545,5539 } }, { "Nikon COOLPIX P340", -200, 0, { 10321,-3920,-931,-2750,11146,1824,-442,1545,5539 } }, { "Nikon COOLPIX P6000", 0, 0, { 9698,-3367,-914,-4706,12584,2368,-837,968,5801 } }, { "Nikon COOLPIX P7000", 0, 0, { 11432,-3679,-1111,-3169,11239,2202,-791,1380,4455 } }, { "Nikon COOLPIX P7100", 0, 0, { 11053,-4269,-1024,-1976,10182,2088,-526,1263,4469 } }, { "Nikon COOLPIX P7700", -3200, 0, { 10321,-3920,-931,-2750,11146,1824,-442,1545,5539 } }, { "Nikon COOLPIX P7800", -3200, 0, { 10321,-3920,-931,-2750,11146,1824,-442,1545,5539 } }, { "Nikon 1 V3", -200, 0, { 5958,-1559,-571,-4021,11453,2939,-634,1548,5087 } }, { "Nikon 1 J4", 0, 0, { 5958,-1559,-571,-4021,11453,2939,-634,1548,5087 } }, { "Nikon 1 J5", 0, 0, { 7520,-2518,-645,-3844,12102,1945,-913,2249,6835} }, { "Nikon 1 S2", -200, 0, { 6612,-1342,-618,-3338,11055,2623,-174,1792,5075 } }, { "Nikon 1 V2", 0, 0, { 6588,-1305,-693,-3277,10987,2634,-355,2016,5106 } }, { "Nikon 1 J3", 0, 0, { 8144,-2671,-473,-1740,9834,1601,-58,1971,4296 } }, { "Nikon 1 AW1", 0, 0, { 6588,-1305,-693,-3277,10987,2634,-355,2016,5106 } }, { "Nikon 1 ", 0, 0, /* J1, J2, S1, V1 */ { 8994,-2667,-865,-4594,12324,2552,-699,1786,6260 } }, { "Olympus AIR-A01", 0, 0xfe1, { 8992,-3093,-639,-2563,10721,2122,-437,1270,5473 } }, { "Olympus C5050", 0, 0, { 10508,-3124,-1273,-6079,14294,1901,-1653,2306,6237 } }, { "Olympus C5060", 0, 0, { 10445,-3362,-1307,-7662,15690,2058,-1135,1176,7602 } }, { "Olympus C7070", 0, 0, { 10252,-3531,-1095,-7114,14850,2436,-1451,1723,6365 } }, { "Olympus C70", 0, 0, { 10793,-3791,-1146,-7498,15177,2488,-1390,1577,7321 } }, { "Olympus C80", 0, 0, { 8606,-2509,-1014,-8238,15714,2703,-942,979,7760 } }, { "Olympus E-10", 0, 0xffc, { 12745,-4500,-1416,-6062,14542,1580,-1934,2256,6603 } }, { "Olympus E-1", 0, 0, { 11846,-4767,-945,-7027,15878,1089,-2699,4122,8311 } }, { "Olympus E-20", 0, 0xffc, { 13173,-4732,-1499,-5807,14036,1895,-2045,2452,7142 } }, { "Olympus E-300", 0, 0, { 7828,-1761,-348,-5788,14071,1830,-2853,4518,6557 } }, { "Olympus E-330", 0, 0, { 8961,-2473,-1084,-7979,15990,2067,-2319,3035,8249 } }, { "Olympus E-30", 0, 0xfbc, { 8144,-1861,-1111,-7763,15894,1929,-1865,2542,7607 } }, { "Olympus E-3", 0, 0xf99, { 9487,-2875,-1115,-7533,15606,2010,-1618,2100,7389 } }, { "Olympus E-400", 0, 0, { 6169,-1483,-21,-7107,14761,2536,-2904,3580,8568 } }, { "Olympus E-410", 0, 0xf6a, { 8856,-2582,-1026,-7761,15766,2082,-2009,2575,7469 } }, { "Olympus E-420", 0, 0xfd7, { 8746,-2425,-1095,-7594,15612,2073,-1780,2309,7416 } }, { "Olympus E-450", 0, 0xfd2, { 8745,-2425,-1095,-7594,15613,2073,-1780,2309,7416 } }, { "Olympus E-500", 0, 0, { 8136,-1968,-299,-5481,13742,1871,-2556,4205,6630 } }, { "Olympus E-510", 0, 0xf6a, { 8785,-2529,-1033,-7639,15624,2112,-1783,2300,7817 } }, { "Olympus E-520", 0, 0xfd2, { 8344,-2322,-1020,-7596,15635,2048,-1748,2269,7287 } }, { "Olympus E-5", 0, 0xeec, { 11200,-3783,-1325,-4576,12593,2206,-695,1742,7504 } }, { "Olympus E-600", 0, 0xfaf, { 8453,-2198,-1092,-7609,15681,2008,-1725,2337,7824 } }, { "Olympus E-620", 0, 0xfaf, { 8453,-2198,-1092,-7609,15681,2008,-1725,2337,7824 } }, { "Olympus E-P1", 0, 0xffd, { 8343,-2050,-1021,-7715,15705,2103,-1831,2380,8235 } }, { "Olympus E-P2", 0, 0xffd, { 8343,-2050,-1021,-7715,15705,2103,-1831,2380,8235 } }, { "Olympus E-P3", 0, 0, { 7575,-2159,-571,-3722,11341,2725,-1434,2819,6271 } }, { "Olympus E-P5", 0, 0, { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, { "Olympus E-PL1s", 0, 0, { 11409,-3872,-1393,-4572,12757,2003,-709,1810,7415 } }, { "Olympus E-PL1", 0, 0, { 11408,-4289,-1215,-4286,12385,2118,-387,1467,7787 } }, { "Olympus E-PL2", 0, 0xcf3, { 15030,-5552,-1806,-3987,12387,1767,-592,1670,7023 } }, { "Olympus E-PL3", 0, 0, { 7575,-2159,-571,-3722,11341,2725,-1434,2819,6271 } }, { "Olympus E-PL5", 0, 0xfcb, { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, { "Olympus E-PL6", 0, 0, { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, { "Olympus E-PL7", 0, 0, { 9197,-3190,-659,-2606,10830,2039,-458,1250,5458 } }, { "Olympus E-PL8", 0, 0, { 9197,-3190,-659,-2606,10830,2039,-458,1250,5458 } }, { "Olympus E-PM1", 0, 0, { 7575,-2159,-571,-3722,11341,2725,-1434,2819,6271 } }, { "Olympus E-PM2", 0, 0, { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, { "Olympus E-M10", 0, 0, /* Same for E-M10MarkII */ { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, { "Olympus E-M1MarkII", 0, 0, /* Adobe */ { 8380, -2630, -639, -2887, 10725, 2496, -627, 1427, 5438 }}, { "Olympus E-M1", 0, 0, { 7687,-1984,-606,-4327,11928,2721,-1381,2339,6452 } }, { "Olympus E-M5MarkII", 0, 0, { 9422,-3258,-711,-2655,10898,2015,-512,1354,5512 } }, { "Olympus E-M5", 0, 0xfe1, { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, { "Olympus PEN-F",0, 0, { 9476,-3182,-765,-2613,10958,1893,-449,1315,5268 } }, { "Olympus SP350", 0, 0, { 12078,-4836,-1069,-6671,14306,2578,-786,939,7418 } }, { "Olympus SP3", 0, 0, { 11766,-4445,-1067,-6901,14421,2707,-1029,1217,7572 } }, { "Olympus SP500UZ", 0, 0xfff, { 9493,-3415,-666,-5211,12334,3260,-1548,2262,6482 } }, { "Olympus SP510UZ", 0, 0xffe, { 10593,-3607,-1010,-5881,13127,3084,-1200,1805,6721 } }, { "Olympus SP550UZ", 0, 0xffe, { 11597,-4006,-1049,-5432,12799,2957,-1029,1750,6516 } }, { "Olympus SP560UZ", 0, 0xff9, { 10915,-3677,-982,-5587,12986,2911,-1168,1968,6223 } }, { "Olympus SP570UZ", 0, 0, { 11522,-4044,-1146,-4736,12172,2904,-988,1829,6039 } }, { "Olympus SH-2", 0, 0, { 10156,-3425,-1077,-2611,11177,1624,-385,1592,5080 } }, { "Olympus SH-3", 0, 0, /* Alias of SH-2 */ { 10156,-3425,-1077,-2611,11177,1624,-385,1592,5080 } }, { "Olympus STYLUS1",0, 0, { 11976,-5518,-545,-1419,10472,846,-475,1766,4524 } }, { "Olympus TG-4", 0, 0, { 11426,-4159,-1126,-2066,10678,1593,-120,1327,4998 } }, { "Olympus XZ-10", 0, 0, { 9777,-3483,-925,-2886,11297,1800,-602,1663,5134 } }, { "Olympus XZ-1", 0, 0, { 10901,-4095,-1074,-1141,9208,2293,-62,1417,5158 } }, { "Olympus XZ-2", 0, 0, { 9777,-3483,-925,-2886,11297,1800,-602,1663,5134 } }, { "OmniVision", 16, 0x3ff, { 12782,-4059,-379,-478,9066,1413,1340,1513,5176 } }, /* DJC */ { "Pentax *ist DL2", 0, 0, { 10504,-2438,-1189,-8603,16207,2531,-1022,863,12242 } }, { "Pentax *ist DL", 0, 0, { 10829,-2838,-1115,-8339,15817,2696,-837,680,11939 } }, { "Pentax *ist DS2", 0, 0, { 10504,-2438,-1189,-8603,16207,2531,-1022,863,12242 } }, { "Pentax *ist DS", 0, 0, { 10371,-2333,-1206,-8688,16231,2602,-1230,1116,11282 } }, { "Pentax *ist D", 0, 0, { 9651,-2059,-1189,-8881,16512,2487,-1460,1345,10687 } }, { "Pentax K10D", 0, 0, { 9566,-2863,-803,-7170,15172,2112,-818,803,9705 } }, { "Pentax K1", 0, 0, { 11095,-3157,-1324,-8377,15834,2720,-1108,947,11688 } }, { "Pentax K20D", 0, 0, { 9427,-2714,-868,-7493,16092,1373,-2199,3264,7180 } }, { "Pentax K200D", 0, 0, { 9186,-2678,-907,-8693,16517,2260,-1129,1094,8524 } }, { "Pentax K2000", 0, 0, { 11057,-3604,-1155,-5152,13046,2329,-282,375,8104 } }, { "Pentax K-m", 0, 0, { 11057,-3604,-1155,-5152,13046,2329,-282,375,8104 } }, { "Pentax K-x", 0, 0, { 8843,-2837,-625,-5025,12644,2668,-411,1234,7410 } }, { "Pentax K-r", 0, 0, { 9895,-3077,-850,-5304,13035,2521,-883,1768,6936 } }, { "Pentax K-1", 0, 0, { 8566,-2746,-1201,-3612,12204,1550,-893,1680,6264 } }, { "Pentax K-30", 0, 0, { 8710,-2632,-1167,-3995,12301,1881,-981,1719,6535 } }, { "Pentax K-3 II", 0, 0, { 8626,-2607,-1155,-3995,12301,1881,-1039,1822,6925 } }, { "Pentax K-3", 0, 0, { 7415,-2052,-721,-5186,12788,2682,-1446,2157,6773 } }, { "Pentax K-5 II", 0, 0, { 8170,-2725,-639,-4440,12017,2744,-771,1465,6599 } }, { "Pentax K-5", 0, 0, { 8713,-2833,-743,-4342,11900,2772,-722,1543,6247 } }, { "Pentax K-70", 0, 0, {8766, -3149, -747, -3976, 11943, 2292, -517, 1259, 5552 }}, { "Pentax K-7", 0, 0, { 9142,-2947,-678,-8648,16967,1663,-2224,2898,8615 } }, { "Pentax K-S1", 0, 0, { 8512,-3211,-787,-4167,11966,2487,-638,1288,6054 } }, { "Pentax K-S2", 0, 0, { 8662,-3280,-798,-3928,11771,2444,-586,1232,6054 } }, { "Pentax Q-S1", 0, 0, { 12995,-5593,-1107,-1879,10139,2027,-64,1233,4919 } }, { "Pentax MX-1", 0, 0, { 8804,-2523,-1238,-2423,11627,860,-682,1774,4753 } }, { "Pentax Q10", 0, 0, { 12995,-5593,-1107,-1879,10139,2027,-64,1233,4919 } }, { "Pentax 645D", 0, 0x3e00, { 10646,-3593,-1158,-3329,11699,1831,-667,2874,6287 } }, { "Pentax 645Z", 0, 0, /* Adobe */ { 9702, -3060, -1254, -3685, 12133, 1721, -1086, 2010, 6971}}, { "Panasonic DMC-CM10", -15, 0, { 8770, -3194,-820,-2871,11281,1803,-513,1552,4434 } }, { "Panasonic DMC-CM1", -15, 0, { 8770, -3194,-820,-2871,11281,1803,-513,1552,4434 } }, { "Panasonic DMC-FZ8", 0, 0xf7f, { 8986,-2755,-802,-6341,13575,3077,-1476,2144,6379 } }, { "Panasonic DMC-FZ18", 0, 0, { 9932,-3060,-935,-5809,13331,2753,-1267,2155,5575 } }, { "Panasonic DMC-FZ28", -15, 0xf96, { 10109,-3488,-993,-5412,12812,2916,-1305,2140,5543 } }, { "Panasonic DMC-FZ300", -15, 0xfff, { 8378,-2798,-769,-3068,11410,1877,-538,1792,4623 } }, { "Panasonic DMC-FZ330", -15, 0xfff, // same as FZ300 { 8378,-2798,-769,-3068,11410,1877,-538,1792,4623 } }, { "Panasonic DMC-FZ30", 0, 0xf94, { 10976,-4029,-1141,-7918,15491,2600,-1670,2071,8246 } }, { "Panasonic DMC-FZ3", -15, 0, { 9938,-2780,-890,-4604,12393,2480,-1117,2304,4620 } }, { "Panasonic DMC-FZ4", -15, 0, { 13639,-5535,-1371,-1698,9633,2430,316,1152,4108 } }, { "Panasonic DMC-FZ50", 0, 0, { 7906,-2709,-594,-6231,13351,3220,-1922,2631,6537 } }, { "Panasonic DMC-FZ7", -15, 0, { 11532,-4324,-1066,-2375,10847,1749,-564,1699,4351 } }, { "Leica V-LUX1", 0, 0, { 7906,-2709,-594,-6231,13351,3220,-1922,2631,6537 } }, { "Panasonic DMC-L10", -15, 0xf96, { 8025,-1942,-1050,-7920,15904,2100,-2456,3005,7039 } }, { "Panasonic DMC-L1", 0, 0xf7f, { 8054,-1885,-1025,-8349,16367,2040,-2805,3542,7629 } }, { "Leica DIGILUX 3", 0, 0xf7f, { 8054,-1885,-1025,-8349,16367,2040,-2805,3542,7629 } }, { "Panasonic DMC-LC1", 0, 0, { 11340,-4069,-1275,-7555,15266,2448,-2960,3426,7685 } }, { "Leica DIGILUX 2", 0, 0, { 11340,-4069,-1275,-7555,15266,2448,-2960,3426,7685 } }, { "Panasonic DMC-LX100", -15, 0, { 8844,-3538,-768,-3709,11762,2200,-698,1792,5220 } }, { "Leica D-LUX (Typ 109)", -15, 0, { 8844,-3538,-768,-3709,11762,2200,-698,1792,5220 } }, { "Panasonic DMC-LF1", -15, 0, { 9379,-3267,-816,-3227,11560,1881,-926,1928,5340 } }, { "Leica C (Typ 112)", -15, 0, { 9379,-3267,-816,-3227,11560,1881,-926,1928,5340 } }, { "Panasonic DMC-LX9", -15, 0, /* markets: LX9 LX10 LX15 */ { 7790, -2736, -755, -3452, 11870, 1769, -628, 1647, 4898 }}, /* Adobe*/ { "Panasonic DMC-LX10", -15, 0, /* markets: LX9 LX10 LX15 */ { 7790, -2736, -755, -3452, 11870, 1769, -628, 1647, 4898 }}, /* Adobe*/ { "Panasonic DMC-LX15", -15, 0, /* markets: LX9 LX10 LX15 */ { 7790, -2736, -755, -3452, 11870, 1769, -628, 1647, 4898 }}, /* Adobe*/ { "Panasonic DMC-LX1", 0, 0xf7f, { 10704,-4187,-1230,-8314,15952,2501,-920,945,8927 } }, { "Leica D-Lux (Typ 109)", 0, 0xf7f, { 8844,-3538,-768,-3709,11762,2200,-698,1792,5220 } }, { "Leica D-LUX2", 0, 0xf7f, { 10704,-4187,-1230,-8314,15952,2501,-920,945,8927 } }, { "Panasonic DMC-LX2", 0, 0, { 8048,-2810,-623,-6450,13519,3272,-1700,2146,7049 } }, { "Leica D-LUX3", 0, 0, { 8048,-2810,-623,-6450,13519,3272,-1700,2146,7049 } }, { "Panasonic DMC-LX3", -15, 0, { 8128,-2668,-655,-6134,13307,3161,-1782,2568,6083 } }, { "Leica D-LUX 4", -15, 0, { 8128,-2668,-655,-6134,13307,3161,-1782,2568,6083 } }, { "Panasonic DMC-LX5", -15, 0, { 10909,-4295,-948,-1333,9306,2399,22,1738,4582 } }, { "Leica D-LUX 5", -15, 0, { 10909,-4295,-948,-1333,9306,2399,22,1738,4582 } }, { "Panasonic DMC-LX7", -15, 0, { 10148,-3743,-991,-2837,11366,1659,-701,1893,4899 } }, { "Leica D-LUX 6", -15, 0, { 10148,-3743,-991,-2837,11366,1659,-701,1893,4899 } }, { "Panasonic DMC-FZ1000", -15, 0, { 7830,-2696,-763,-3325,11667,1866,-641,1712,4824 } }, { "Leica V-LUX (Typ 114)", 15, 0, { 7830,-2696,-763,-3325,11667,1866,-641,1712,4824 } }, { "Panasonic DMC-FZ100", -15, 0xfff, { 16197,-6146,-1761,-2393,10765,1869,366,2238,5248 } }, { "Leica V-LUX 2", -15, 0xfff, { 16197,-6146,-1761,-2393,10765,1869,366,2238,5248 } }, { "Panasonic DMC-FZ150", -15, 0xfff, { 11904,-4541,-1189,-2355,10899,1662,-296,1586,4289 } }, { "Leica V-LUX 3", -15, 0xfff, { 11904,-4541,-1189,-2355,10899,1662,-296,1586,4289 } }, { "Panasonic DMC-FZ2000", -15, 0, /* markets: DMC-FZ2000,DMC-FZ2500,FZH1 */ { 7386, -2443, -743, -3437, 11864, 1757, -608, 1660, 4766 }}, { "Panasonic DMC-FZ2500", -15, 0, { 7386, -2443, -743, -3437, 11864, 1757, -608, 1660, 4766 }}, { "Panasonic DMC-FZH1", -15, 0, { 7386, -2443, -743, -3437, 11864, 1757, -608, 1660, 4766 }}, { "Panasonic DMC-FZ200", -15, 0xfff, { 8112,-2563,-740,-3730,11784,2197,-941,2075,4933 } }, { "Leica V-LUX 4", -15, 0xfff, { 8112,-2563,-740,-3730,11784,2197,-941,2075,4933 } }, { "Panasonic DMC-FX150", -15, 0xfff, { 9082,-2907,-925,-6119,13377,3058,-1797,2641,5609 } }, { "Panasonic DMC-G10", 0, 0, { 10113,-3400,-1114,-4765,12683,2317,-377,1437,6710 } }, { "Panasonic DMC-G1", -15, 0xf94, { 8199,-2065,-1056,-8124,16156,2033,-2458,3022,7220 } }, { "Panasonic DMC-G2", -15, 0xf3c, { 10113,-3400,-1114,-4765,12683,2317,-377,1437,6710 } }, { "Panasonic DMC-G3", -15, 0xfff, { 6763,-1919,-863,-3868,11515,2684,-1216,2387,5879 } }, { "Panasonic DMC-G5", -15, 0xfff, { 7798,-2562,-740,-3879,11584,2613,-1055,2248,5434 } }, { "Panasonic DMC-G6", -15, 0xfff, { 8294,-2891,-651,-3869,11590,2595,-1183,2267,5352 } }, { "Panasonic DMC-G7", -15, 0xfff, { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, { "Panasonic DMC-G8", -15, 0xfff, /* markets: DMC-G8, DMC-G80, DMC-G81, DMC-G85 */ { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, { "Panasonic DMC-GF1", -15, 0xf92, { 7888,-1902,-1011,-8106,16085,2099,-2353,2866,7330 } }, { "Panasonic DMC-GF2", -15, 0xfff, { 7888,-1902,-1011,-8106,16085,2099,-2353,2866,7330 } }, { "Panasonic DMC-GF3", -15, 0xfff, { 9051,-2468,-1204,-5212,13276,2121,-1197,2510,6890 } }, { "Panasonic DMC-GF5", -15, 0xfff, { 8228,-2945,-660,-3938,11792,2430,-1094,2278,5793 } }, { "Panasonic DMC-GF6", -15, 0, { 8130,-2801,-946,-3520,11289,2552,-1314,2511,5791 } }, { "Panasonic DMC-GF7", -15, 0, { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, { "Panasonic DMC-GF8", -15, 0, { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, { "Panasonic DMC-GH1", -15, 0xf92, { 6299,-1466,-532,-6535,13852,2969,-2331,3112,5984 } }, { "Panasonic DMC-GH2", -15, 0xf95, { 7780,-2410,-806,-3913,11724,2484,-1018,2390,5298 } }, { "Panasonic DMC-GH3", -15, 0, { 6559,-1752,-491,-3672,11407,2586,-962,1875,5130 } }, { "Panasonic DMC-GH4", -15, 0, { 7122,-2108,-512,-3155,11201,2231,-541,1423,5045 } }, { "Yuneec CGO4", -15, 0, { 7122,-2108,-512,-3155,11201,2231,-541,1423,5045 } }, { "Panasonic DMC-GM1", -15, 0, { 6770,-1895,-744,-5232,13145,2303,-1664,2691,5703 } }, { "Panasonic DMC-GM5", -15, 0, { 8238,-3244,-679,-3921,11814,2384,-836,2022,5852 } }, { "Panasonic DMC-GX1", -15, 0, { 6763,-1919,-863,-3868,11515,2684,-1216,2387,5879 } }, { "Panasonic DMC-GX85", -15, 0, /* markets: GX85 GX80 GX7MK2 */ { 7771,-3020,-629,4029,11950,2345,-821,1977,6119 } }, { "Panasonic DMC-GX80", -15, 0, /* markets: GX85 GX80 GX7MK2 */ { 7771,-3020,-629,4029,11950,2345,-821,1977,6119 } }, { "Panasonic DMC-GX7MK2", -15, 0, /* markets: GX85 GX80 GX7MK2 */ { 7771,-3020,-629,4029,11950,2345,-821,1977,6119 } }, { "Panasonic DMC-GX7", -15,0, { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, { "Panasonic DMC-GX8", -15,0, { 7564,-2263,-606,-3148,11239,2177,-540,1435,4853 } }, { "Panasonic DMC-TZ6", -15, 0, /* markets: ZS40 TZ60 TZ61 */ { 8607,-2822,-808,-3755,11930,2049,-820,2060,5224 } }, { "Panasonic DMC-TZ8", -15, 0, /* markets: ZS60 TZ80 TZ81 TZ85 */ { 8550,-2908,-842,-3195,11529,1881,-338,1603,4631 } }, { "Panasonic DMC-ZS4", -15, 0, /* markets: ZS40 TZ60 TZ61 */ { 8607,-2822,-808,-3755,11930,2049,-820,2060,5224 } }, { "Panasonic DMC-TZ7", -15, 0, /* markets: ZS50 TZ70 TZ71 */ { 8802,-3135,-789,-3151,11468,1904,-550,1745,4810 } }, { "Panasonic DMC-ZS5", -15, 0, /* markets: ZS50 TZ70 TZ71 */ { 8802,-3135,-789,-3151,11468,1904,-550,1745,4810 } }, { "Panasonic DMC-ZS6", -15, 0, /* markets: ZS60 TZ80 TZ81 TZ85 */ { 8550,-2908,-842,-3195,11529,1881,-338,1603,4631 } }, { "Panasonic DMC-ZS100", -15, 0, /* markets: ZS100 ZS110 TZ100 TZ101 TZ110 TX1 */ { 7790,-2736,-755,-3452,11870,1769,-628,1647,4898 } }, { "Panasonic DMC-ZS110", -15, 0, /* markets: ZS100 ZS110 TZ100 TZ101 TZ110 TX1 */ { 7790,-2736,-755,-3452,11870,1769,-628,1647,4898 } }, { "Panasonic DMC-TZ100", -15, 0, /* markets: ZS100 ZS110 TZ100 TZ101 TZ110 TX1 */ { 7790,-2736,-755,-3452,11870,1769,-628,1647,4898 } }, { "Panasonic DMC-TZ101", -15, 0, /* markets: ZS100 ZS110 TZ100 TZ101 TZ110 TX1 */ { 7790,-2736,-755,-3452,11870,1769,-628,1647,4898 } }, { "Panasonic DMC-TZ110", -15, 0, /* markets: ZS100 ZS110 TZ100 TZ101 TZ110 TX1 */ { 7790,-2736,-755,-3452,11870,1769,-628,1647,4898 } }, { "Panasonic DMC-TX1", -15, 0, /* markets: ZS100 ZS110 TZ100 TZ101 TZ110 TX1 */ { 7790,-2736,-755,-3452,11870,1769,-628,1647,4898 } }, { "Leica S (Typ 007)", 0, 0, { 6063,-2234,-231,-5210,13787,1500,-1043,2866,6997 } }, { "Leica X", 0, 0, /* X and X-U, both (Typ 113) */ { 7712,-2059,-653,-3882,11494,2726,-710,1332,5958 } }, { "Leica Q (Typ 116)", 0, 0, { 11865,-4523,-1441,-5423,14458,935,-1587,2687,4830 } }, { "Leica M (Typ 262)", 0, 0, { 6653,-1486,-611,-4221,13303,929,-881,2416,7226 } }, { "Leica SL (Typ 601)", 0, 0, { 11865,-4523,-1441,-5423,14458,935,-1587,2687,4830} }, { "Phase One H 20", 0, 0, /* DJC */ { 1313,1855,-109,-6715,15908,808,-327,1840,6020 } }, { "Phase One H 25", 0, 0, { 2905,732,-237,-8134,16626,1476,-3038,4253,7517 } }, { "Phase One IQ250",0, 0, { 4396,-153,-249,-5267,12249,2657,-1397,2323,6014 } }, { "Phase One P 2", 0, 0, { 2905,732,-237,-8134,16626,1476,-3038,4253,7517 } }, { "Phase One P 30", 0, 0, { 4516,-245,-37,-7020,14976,2173,-3206,4671,7087 } }, { "Phase One P 45", 0, 0, { 5053,-24,-117,-5684,14076,1702,-2619,4492,5849 } }, { "Phase One P40", 0, 0, { 8035,435,-962,-6001,13872,2320,-1159,3065,5434 } }, { "Phase One P65", 0, 0, { 8035,435,-962,-6001,13872,2320,-1159,3065,5434 } }, { "Photron BC2-HD", 0, 0, /* DJC */ { 14603,-4122,-528,-1810,9794,2017,-297,2763,5936 } }, { "Red One", 704, 0xffff, /* DJC */ { 21014,-7891,-2613,-3056,12201,856,-2203,5125,8042 } }, { "Ricoh GR II", 0, 0, { 4630,-834,-423,-4977,12805,2417,-638,1467,6115 } }, { "Ricoh GR", 0, 0, { 3708,-543,-160,-5381,12254,3556,-1471,1929,8234 } }, { "Samsung EK-GN120", 0, 0, /* Adobe; Galaxy NX */ { 7557,-2522,-739,-4679,12949,1894,-840,1777,5311 } }, { "Samsung EX1", 0, 0x3e00, { 8898,-2498,-994,-3144,11328,2066,-760,1381,4576 } }, { "Samsung EX2F", 0, 0x7ff, { 10648,-3897,-1055,-2022,10573,1668,-492,1611,4742 } }, { "Samsung NX mini", 0, 0, { 5222,-1196,-550,-6540,14649,2009,-1666,2819,5657 } }, { "Samsung NX3300", 0, 0, /* same as NX3000 */ { 8060,-2933,-761,-4504,12890,1762,-630,1489,5227 } }, { "Samsung NX3000", 0, 0, { 8060,-2933,-761,-4504,12890,1762,-630,1489,5227 } }, { "Samsung NX30", 0, 0, /* NX30, NX300, NX300M */ { 7557,-2522,-739,-4679,12949,1894,-840,1777,5311 } }, { "Samsung NX2000", 0, 0, { 7557,-2522,-739,-4679,12949,1894,-840,1777,5311 } }, { "Samsung NX2", 0, 0xfff, /* NX20, NX200, NX210 */ { 6933,-2268,-753,-4921,13387,1647,-803,1641,6096 } }, { "Samsung NX1000", 0, 0, { 6933,-2268,-753,-4921,13387,1647,-803,1641,6096 } }, { "Samsung NX1100", 0, 0, { 6933,-2268,-753,-4921,13387,1647,-803,1641,6096 } }, { "Samsung NX11", 0, 0, { 10332,-3234,-1168,-6111,14639,1520,-1352,2647,8331 } }, { "Samsung NX10", 0, 0, /* also NX100 */ { 10332,-3234,-1168,-6111,14639,1520,-1352,2647,8331 } }, { "Samsung NX500", 0, 0, { 10686,-4042,-1052,-3595,13238,276,-464,1259,5931 } }, { "Samsung NX5", 0, 0, { 10332,-3234,-1168,-6111,14639,1520,-1352,2647,8331 } }, { "Samsung NX1", 0, 0, { 10686,-4042,-1052,-3595,13238,276,-464,1259,5931 } }, { "Samsung WB2000", 0, 0xfff, { 12093,-3557,-1155,-1000,9534,1733,-22,1787,4576 } }, { "Samsung GX-1", 0, 0, { 10504,-2438,-1189,-8603,16207,2531,-1022,863,12242 } }, { "Samsung GX20", 0, 0, /* copied from Pentax K20D */ { 9427,-2714,-868,-7493,16092,1373,-2199,3264,7180 } }, { "Samsung S85", 0, 0, /* DJC */ { 11885,-3968,-1473,-4214,12299,1916,-835,1655,5549 } }, // Foveon: LibRaw color data { "Sigma dp0 Quattro", 2047, 0, { 13801,-3390,-1016,5535,3802,877,1848,4245,3730 } }, { "Sigma dp1 Quattro", 2047, 0, { 13801,-3390,-1016,5535,3802,877,1848,4245,3730 } }, { "Sigma dp2 Quattro", 2047, 0, { 13801,-3390,-1016,5535,3802,877,1848,4245,3730 } }, { "Sigma dp3 Quattro", 2047, 0, { 13801,-3390,-1016,5535,3802,877,1848,4245,3730 } }, { "Sigma sd Quattro H", 256, 0, {1295,108,-311, 256,828,-65,-28,750,254}}, /* temp, same as sd Quattro */ { "Sigma sd Quattro", 2047, 0, {1295,108,-311, 256,828,-65,-28,750,254}}, /* temp */ { "Sigma SD9", 15, 4095, /* LibRaw */ { 14082,-2201,-1056,-5243,14788,167,-121,196,8881 } }, { "Sigma SD10", 15, 16383, /* LibRaw */ { 14082,-2201,-1056,-5243,14788,167,-121,196,8881 } }, { "Sigma SD14", 15, 16383, /* LibRaw */ { 14082,-2201,-1056,-5243,14788,167,-121,196,8881 } }, { "Sigma SD15", 15, 4095, /* LibRaw */ { 14082,-2201,-1056,-5243,14788,167,-121,196,8881 } }, // Merills + SD1 { "Sigma SD1", 31, 4095, /* LibRaw */ { 5133,-1895,-353,4978,744,144,3837,3069,2777 } }, { "Sigma DP1 Merrill", 31, 4095, /* LibRaw */ { 5133,-1895,-353,4978,744,144,3837,3069,2777 } }, { "Sigma DP2 Merrill", 31, 4095, /* LibRaw */ { 5133,-1895,-353,4978,744,144,3837,3069,2777 } }, { "Sigma DP3 Merrill", 31, 4095, /* LibRaw */ { 5133,-1895,-353,4978,744,144,3837,3069,2777 } }, // Sigma DP (non-Merill Versions) { "Sigma DP", 0, 4095, /* LibRaw */ // { 7401,-1169,-567,2059,3769,1510,664,3367,5328 } }, { 13100,-3638,-847,6855,2369,580,2723,3218,3251 } }, { "Sinar", 0, 0, /* DJC */ { 16442,-2956,-2422,-2877,12128,750,-1136,6066,4559 } }, { "Sony DSC-F828", 0, 0, { 7924,-1910,-777,-8226,15459,2998,-1517,2199,6818,-7242,11401,3481 } }, { "Sony DSC-R1", 0, 0, { 8512,-2641,-694,-8042,15670,2526,-1821,2117,7414 } }, { "Sony DSC-V3", 0, 0, { 7511,-2571,-692,-7894,15088,3060,-948,1111,8128 } }, {"Sony DSC-RX100M5", -800, 0, /* Adobe */ {6596, -2079, -562, -4782, 13016, 1933, -970, 1581, 5181 }}, { "Sony DSC-RX100M", -800, 0, /* M2 and M3 and M4 */ { 6596,-2079,-562,-4782,13016,1933,-970,1581,5181 } }, { "Sony DSC-RX100", 0, 0, { 8651,-2754,-1057,-3464,12207,1373,-568,1398,4434 } }, { "Sony DSC-RX10",0, 0, /* And M2/M3 too */ { 6679,-1825,-745,-5047,13256,1953,-1580,2422,5183 } }, { "Sony DSC-RX1RM2", 0, 0, { 6629,-1900,-483,-4618,12349,2550,-622,1381,6514 } }, { "Sony DSC-RX1R", 0, 0, { 8195,-2800,-422,-4261,12273,1709,-1505,2400,5624 } }, { "Sony DSC-RX1", 0, 0, { 6344,-1612,-462,-4863,12477,2681,-865,1786,6899 } }, { "Sony DSLR-A100", 0, 0xfeb, { 9437,-2811,-774,-8405,16215,2290,-710,596,7181 } }, { "Sony DSLR-A290", 0, 0, { 6038,-1484,-579,-9145,16746,2512,-875,746,7218 } }, { "Sony DSLR-A2", 0, 0, { 9847,-3091,-928,-8485,16345,2225,-715,595,7103 } }, { "Sony DSLR-A300", 0, 0, { 9847,-3091,-928,-8485,16345,2225,-715,595,7103 } }, { "Sony DSLR-A330", 0, 0, { 9847,-3091,-929,-8485,16346,2225,-714,595,7103 } }, { "Sony DSLR-A350", 0, 0xffc, { 6038,-1484,-578,-9146,16746,2513,-875,746,7217 } }, { "Sony DSLR-A380", 0, 0, { 6038,-1484,-579,-9145,16746,2512,-875,746,7218 } }, { "Sony DSLR-A390", 0, 0, { 6038,-1484,-579,-9145,16746,2512,-875,746,7218 } }, { "Sony DSLR-A450", 0, 0xfeb, { 4950,-580,-103,-5228,12542,3029,-709,1435,7371 } }, { "Sony DSLR-A580", 0, 0xfeb, { 5932,-1492,-411,-4813,12285,2856,-741,1524,6739 } }, { "Sony DSLR-A500", 0, 0xfeb, { 6046,-1127,-278,-5574,13076,2786,-691,1419,7625 } }, { "Sony DSLR-A5", 0, 0xfeb, { 4950,-580,-103,-5228,12542,3029,-709,1435,7371 } }, { "Sony DSLR-A700", 0, 0, { 5775,-805,-359,-8574,16295,2391,-1943,2341,7249 } }, { "Sony DSLR-A850", 0, 0, { 5413,-1162,-365,-5665,13098,2866,-608,1179,8440 } }, { "Sony DSLR-A900", 0, 0, { 5209,-1072,-397,-8845,16120,2919,-1618,1803,8654 } }, { "Sony ILCA-68", 0, 0, { 6435,-1903,-536,-4722,12449,2550,-663,1363,6517 } }, { "Sony ILCA-77M2", 0, 0, { 5991,-1732,-443,-4100,11989,2381,-704,1467,5992 } }, { "Sony ILCA-99M2", 0, 0, /* Adobe */ { 6660, -1918, -471, -4613, 12398, 2485, -649, 1433, 6447}}, { "Sony ILCE-7M2", 0, 0, { 5271,-712,-347,-6153,13653,2763,-1601,2366,7242 } }, { "Sony ILCE-7SM2", 0, 0, { 5838,-1430,-246,-3497,11477,2297,-748,1885,5778 } }, { "Sony ILCE-7S", 0, 0, { 5838,-1430,-246,-3497,11477,2297,-748,1885,5778 } }, { "Sony ILCE-7RM2", 0, 0, { 6629,-1900,-483,-4618,12349,2550,-622,1381,6514 } }, { "Sony ILCE-7R", 0, 0, { 4913,-541,-202,-6130,13513,2906,-1564,2151,7183 } }, { "Sony ILCE-7", 0, 0, { 5271,-712,-347,-6153,13653,2763,-1601,2366,7242 } }, { "Sony ILCE-6300", 0, 0, { 5973,-1695,-419,-3826,11797,2293,-639,1398,5789 } }, { "Sony ILCE-6500", 0, 0, /* Adobe */ { 5973,-1695,-419,-3826,11797,2293,-639,1398,5789 } }, { "Sony ILCE", 0, 0, /* 3000, 5000, 5100, 6000, and QX1 */ { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, { "Sony NEX-5N", 0, 0, { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, { "Sony NEX-5R", 0, 0, { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, { "Sony NEX-5T", 0, 0, { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, { "Sony NEX-3N", 0, 0, { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, { "Sony NEX-3", 0, 0, /* Adobe */ { 6549,-1550,-436,-4880,12435,2753,-854,1868,6976 } }, { "Sony NEX-5", 0, 0, /* Adobe */ { 6549,-1550,-436,-4880,12435,2753,-854,1868,6976 } }, { "Sony NEX-6", 0, 0, { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, { "Sony NEX-7", 0, 0, { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } }, { "Sony NEX", 0, 0, /* NEX-C3, NEX-F3 */ { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, { "Sony SLT-A33", 0, 0, { 6069,-1221,-366,-5221,12779,2734,-1024,2066,6834 } }, { "Sony SLT-A35", 0, 0, { 5986,-1618,-415,-4557,11820,3120,-681,1404,6971 } }, { "Sony SLT-A37", 0, 0, { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, { "Sony SLT-A55", 0, 0, { 5932,-1492,-411,-4813,12285,2856,-741,1524,6739 } }, { "Sony SLT-A57", 0, 0, { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, { "Sony SLT-A58", 0, 0, { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, { "Sony SLT-A65", 0, 0, { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } }, { "Sony SLT-A77", 0, 0, { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } }, { "Sony SLT-A99", 0, 0, { 6344,-1612,-462,-4863,12477,2681,-865,1786,6899 } }, }; double cam_xyz[4][3]; char name[130]; int i, j; if(colors>4 || colors < 1) return; int bl4=(cblack[0]+cblack[1]+cblack[2]+cblack[3])/4,bl64=0; if(cblack[4]*cblack[5]>0) { for (unsigned c = 0; c < 4096 && c < cblack[4]*cblack[5]; c++) bl64+=cblack[c+6]; bl64 /= cblack[4]*cblack[5]; } int rblack = black+bl4+bl64; sprintf (name, "%s %s", t_make, t_model); for (i=0; i < sizeof table / sizeof *table; i++) if (!strncasecmp(name, table[i].prefix, strlen(table[i].prefix))) { if(!dng_version) { if (table[i].t_black>0) { black = (ushort) table[i].t_black; memset(cblack,0,sizeof(cblack)); } else if(table[i].t_black <0 && rblack == 0 ) { black = (ushort) (-table[i].t_black); memset(cblack,0,sizeof(cblack)); } if (table[i].t_maximum) maximum = (ushort) table[i].t_maximum; } if (table[i].trans[0]) { for (raw_color = j=0; j < 12; j++) #ifdef LIBRAW_LIBRARY_BUILD if(internal_only) imgdata.color.cam_xyz[0][j] = table[i].trans[j] / 10000.0; else imgdata.color.cam_xyz[0][j] = #endif ((double*)cam_xyz)[j] = table[i].trans[j] / 10000.0; #ifdef LIBRAW_LIBRARY_BUILD if(!internal_only) #endif cam_xyz_coeff (rgb_cam, cam_xyz); } break; } } void CLASS simple_coeff (int index) { static const float table[][12] = { /* index 0 -- all Foveon cameras */ { 1.4032,-0.2231,-0.1016,-0.5263,1.4816,0.017,-0.0112,0.0183,0.9113 }, /* index 1 -- Kodak DC20 and DC25 */ { 2.25,0.75,-1.75,-0.25,-0.25,0.75,0.75,-0.25,-0.25,-1.75,0.75,2.25 }, /* index 2 -- Logitech Fotoman Pixtura */ { 1.893,-0.418,-0.476,-0.495,1.773,-0.278,-1.017,-0.655,2.672 }, /* index 3 -- Nikon E880, E900, and E990 */ { -1.936280, 1.800443, -1.448486, 2.584324, 1.405365, -0.524955, -0.289090, 0.408680, -1.204965, 1.082304, 2.941367, -1.818705 } }; int i, c; for (raw_color = i=0; i < 3; i++) FORCC rgb_cam[i][c] = table[index][i*colors+c]; } short CLASS guess_byte_order (int words) { uchar test[4][2]; int t=2, msb; double diff, sum[2] = {0,0}; fread (test[0], 2, 2, ifp); for (words-=2; words--; ) { fread (test[t], 2, 1, ifp); for (msb=0; msb < 2; msb++) { diff = (test[t^2][msb] << 8 | test[t^2][!msb]) - (test[t ][msb] << 8 | test[t ][!msb]); sum[msb] += diff*diff; } t = (t+1) & 3; } return sum[0] < sum[1] ? 0x4d4d : 0x4949; } float CLASS find_green (int bps, int bite, int off0, int off1) { UINT64 bitbuf=0; int vbits, col, i, c; ushort img[2][2064]; double sum[]={0,0}; FORC(2) { fseek (ifp, c ? off1:off0, SEEK_SET); for (vbits=col=0; col < width; col++) { for (vbits -= bps; vbits < 0; vbits += bite) { bitbuf <<= bite; for (i=0; i < bite; i+=8) bitbuf |= (unsigned) (fgetc(ifp) << i); } img[c][col] = bitbuf << (64-bps-vbits) >> (64-bps); } } FORC(width-1) { sum[ c & 1] += ABS(img[0][c]-img[1][c+1]); sum[~c & 1] += ABS(img[1][c]-img[0][c+1]); } return 100 * log(sum[0]/sum[1]); } #ifdef LIBRAW_LIBRARY_BUILD static void remove_trailing_spaces(char *string, size_t len) { if(len<1) return; // not needed, b/c sizeof of make/model is 64 string[len-1]=0; if(len<3) return; // also not needed len = strnlen(string,len-1); for(int i=len-1; i>=0; i--) { if(isspace(string[i])) string[i]=0; else break; } } #endif /* Identify which camera created this file, and set global variables accordingly. */ void CLASS identify() { static const short pana[][6] = { { 3130, 1743, 4, 0, -6, 0 }, { 3130, 2055, 4, 0, -6, 0 }, { 3130, 2319, 4, 0, -6, 0 }, { 3170, 2103, 18, 0,-42, 20 }, { 3170, 2367, 18, 13,-42,-21 }, { 3177, 2367, 0, 0, -1, 0 }, { 3304, 2458, 0, 0, -1, 0 }, { 3330, 2463, 9, 0, -5, 0 }, { 3330, 2479, 9, 0,-17, 4 }, { 3370, 1899, 15, 0,-44, 20 }, { 3370, 2235, 15, 0,-44, 20 }, { 3370, 2511, 15, 10,-44,-21 }, { 3690, 2751, 3, 0, -8, -3 }, { 3710, 2751, 0, 0, -3, 0 }, { 3724, 2450, 0, 0, 0, -2 }, { 3770, 2487, 17, 0,-44, 19 }, { 3770, 2799, 17, 15,-44,-19 }, { 3880, 2170, 6, 0, -6, 0 }, { 4060, 3018, 0, 0, 0, -2 }, { 4290, 2391, 3, 0, -8, -1 }, { 4330, 2439, 17, 15,-44,-19 }, { 4508, 2962, 0, 0, -3, -4 }, { 4508, 3330, 0, 0, -3, -6 }, }; static const ushort canon[][11] = { { 1944, 1416, 0, 0, 48, 0 }, { 2144, 1560, 4, 8, 52, 2, 0, 0, 0, 25 }, { 2224, 1456, 48, 6, 0, 2 }, { 2376, 1728, 12, 6, 52, 2 }, { 2672, 1968, 12, 6, 44, 2 }, { 3152, 2068, 64, 12, 0, 0, 16 }, { 3160, 2344, 44, 12, 4, 4 }, { 3344, 2484, 4, 6, 52, 6 }, { 3516, 2328, 42, 14, 0, 0 }, { 3596, 2360, 74, 12, 0, 0 }, { 3744, 2784, 52, 12, 8, 12 }, { 3944, 2622, 30, 18, 6, 2 }, { 3948, 2622, 42, 18, 0, 2 }, { 3984, 2622, 76, 20, 0, 2, 14 }, { 4104, 3048, 48, 12, 24, 12 }, { 4116, 2178, 4, 2, 0, 0 }, { 4152, 2772, 192, 12, 0, 0 }, { 4160, 3124, 104, 11, 8, 65 }, { 4176, 3062, 96, 17, 8, 0, 0, 16, 0, 7, 0x49 }, { 4192, 3062, 96, 17, 24, 0, 0, 16, 0, 0, 0x49 }, { 4312, 2876, 22, 18, 0, 2 }, { 4352, 2874, 62, 18, 0, 0 }, { 4476, 2954, 90, 34, 0, 0 }, { 4480, 3348, 12, 10, 36, 12, 0, 0, 0, 18, 0x49 }, { 4480, 3366, 80, 50, 0, 0 }, { 4496, 3366, 80, 50, 12, 0 }, { 4768, 3516, 96, 16, 0, 0, 0, 16 }, { 4832, 3204, 62, 26, 0, 0 }, { 4832, 3228, 62, 51, 0, 0 }, { 5108, 3349, 98, 13, 0, 0 }, { 5120, 3318, 142, 45, 62, 0 }, { 5280, 3528, 72, 52, 0, 0 }, /* EOS M */ { 5344, 3516, 142, 51, 0, 0 }, { 5344, 3584, 126,100, 0, 2 }, { 5360, 3516, 158, 51, 0, 0 }, { 5568, 3708, 72, 38, 0, 0 }, { 5632, 3710, 96, 17, 0, 0, 0, 16, 0, 0, 0x49 }, { 5712, 3774, 62, 20, 10, 2 }, { 5792, 3804, 158, 51, 0, 0 }, { 5920, 3950, 122, 80, 2, 0 }, { 6096, 4056, 72, 34, 0, 0 }, /* EOS M3 */ { 6288, 4056, 266, 36, 0, 0 }, /* EOS 80D */ { 6880, 4544, 136, 42, 0, 0 }, /* EOS 5D4 */ { 8896, 5920, 160, 64, 0, 0 }, }; static const struct { ushort id; char t_model[20]; } unique[] = { { 0x001, "EOS-1D" }, { 0x167, "EOS-1DS" }, { 0x168, "EOS 10D" }, { 0x169, "EOS-1D Mark III" }, { 0x170, "EOS 300D" }, { 0x174, "EOS-1D Mark II" }, { 0x175, "EOS 20D" }, { 0x176, "EOS 450D" }, { 0x188, "EOS-1Ds Mark II" }, { 0x189, "EOS 350D" }, { 0x190, "EOS 40D" }, { 0x213, "EOS 5D" }, { 0x215, "EOS-1Ds Mark III" }, { 0x218, "EOS 5D Mark II" }, { 0x232, "EOS-1D Mark II N" }, { 0x234, "EOS 30D" }, { 0x236, "EOS 400D" }, { 0x250, "EOS 7D" }, { 0x252, "EOS 500D" }, { 0x254, "EOS 1000D" }, { 0x261, "EOS 50D" }, { 0x269, "EOS-1D X" }, { 0x270, "EOS 550D" }, { 0x281, "EOS-1D Mark IV" }, { 0x285, "EOS 5D Mark III" }, { 0x286, "EOS 600D" }, { 0x287, "EOS 60D" }, { 0x288, "EOS 1100D" }, { 0x289, "EOS 7D Mark II" }, { 0x301, "EOS 650D" }, { 0x302, "EOS 6D" }, { 0x324, "EOS-1D C" }, { 0x325, "EOS 70D" }, { 0x326, "EOS 700D" }, { 0x327, "EOS 1200D" }, { 0x328, "EOS-1D X Mark II" }, { 0x331, "EOS M" }, { 0x335, "EOS M2" }, { 0x374, "EOS M3"}, /* temp */ { 0x384, "EOS M10"}, /* temp */ { 0x394, "EOS M5"}, /* temp */ { 0x346, "EOS 100D" }, { 0x347, "EOS 760D" }, { 0x349, "EOS 5D Mark IV" }, { 0x350, "EOS 80D"}, { 0x382, "EOS 5DS" }, { 0x393, "EOS 750D" }, { 0x401, "EOS 5DS R" }, { 0x404, "EOS 1300D" }, }, sonique[] = { { 0x002, "DSC-R1" }, { 0x100, "DSLR-A100" }, { 0x101, "DSLR-A900" }, { 0x102, "DSLR-A700" }, { 0x103, "DSLR-A200" }, { 0x104, "DSLR-A350" }, { 0x105, "DSLR-A300" }, { 0x106, "DSLR-A900" }, { 0x107, "DSLR-A380" }, { 0x108, "DSLR-A330" }, { 0x109, "DSLR-A230" }, { 0x10a, "DSLR-A290" }, { 0x10d, "DSLR-A850" }, { 0x10e, "DSLR-A850" }, { 0x111, "DSLR-A550" }, { 0x112, "DSLR-A500" }, { 0x113, "DSLR-A450" }, { 0x116, "NEX-5" }, { 0x117, "NEX-3" }, { 0x118, "SLT-A33" }, { 0x119, "SLT-A55V" }, { 0x11a, "DSLR-A560" }, { 0x11b, "DSLR-A580" }, { 0x11c, "NEX-C3" }, { 0x11d, "SLT-A35" }, { 0x11e, "SLT-A65V" }, { 0x11f, "SLT-A77V" }, { 0x120, "NEX-5N" }, { 0x121, "NEX-7" }, { 0x122, "NEX-VG20E"}, { 0x123, "SLT-A37" }, { 0x124, "SLT-A57" }, { 0x125, "NEX-F3" }, { 0x126, "SLT-A99V" }, { 0x127, "NEX-6" }, { 0x128, "NEX-5R" }, { 0x129, "DSC-RX100" }, { 0x12a, "DSC-RX1" }, { 0x12b, "NEX-VG900" }, { 0x12c, "NEX-VG30E" }, { 0x12e, "ILCE-3000" }, { 0x12f, "SLT-A58" }, { 0x131, "NEX-3N" }, { 0x132, "ILCE-7" }, { 0x133, "NEX-5T" }, { 0x134, "DSC-RX100M2" }, { 0x135, "DSC-RX10" }, { 0x136, "DSC-RX1R" }, { 0x137, "ILCE-7R" }, { 0x138, "ILCE-6000" }, { 0x139, "ILCE-5000" }, { 0x13d, "DSC-RX100M3" }, { 0x13e, "ILCE-7S" }, { 0x13f, "ILCA-77M2" }, { 0x153, "ILCE-5100" }, { 0x154, "ILCE-7M2" }, { 0x155, "DSC-RX100M4" }, { 0x156, "DSC-RX10M2" }, { 0x158, "DSC-RX1RM2" }, { 0x15a, "ILCE-QX1" }, { 0x15b, "ILCE-7RM2" }, { 0x15e, "ILCE-7SM2" }, { 0x161, "ILCA-68" }, { 0x162, "ILCA-99M2" }, { 0x163, "DSC-RX10M3" }, { 0x164, "DSC-RX100M5"}, { 0x165, "ILCE-6300" }, { 0x168, "ILCE-6500"}, }; #ifdef LIBRAW_LIBRARY_BUILD static const libraw_custom_camera_t const_table[] #else static const struct { unsigned fsize; ushort rw, rh; uchar lm, tm, rm, bm, lf, cf, max, flags; char t_make[10], t_model[20]; ushort offset; } table[] #endif = { { 786432,1024, 768, 0, 0, 0, 0, 0,0x94,0,0,"AVT","F-080C" }, { 1447680,1392,1040, 0, 0, 0, 0, 0,0x94,0,0,"AVT","F-145C" }, { 1920000,1600,1200, 0, 0, 0, 0, 0,0x94,0,0,"AVT","F-201C" }, { 5067304,2588,1958, 0, 0, 0, 0, 0,0x94,0,0,"AVT","F-510C" }, { 5067316,2588,1958, 0, 0, 0, 0, 0,0x94,0,0,"AVT","F-510C",12 }, { 10134608,2588,1958, 0, 0, 0, 0, 9,0x94,0,0,"AVT","F-510C" }, { 10134620,2588,1958, 0, 0, 0, 0, 9,0x94,0,0,"AVT","F-510C",12 }, { 16157136,3272,2469, 0, 0, 0, 0, 9,0x94,0,0,"AVT","F-810C" }, { 15980544,3264,2448, 0, 0, 0, 0, 8,0x61,0,1,"AgfaPhoto","DC-833m" }, { 9631728,2532,1902, 0, 0, 0, 0,96,0x61,0,0,"Alcatel","5035D" }, { 31850496,4608,3456, 0, 0, 0, 0,0,0x94,0,0,"GITUP","GIT2 4:3" }, { 23887872,4608,2592, 0, 0, 0, 0,0,0x94,0,0,"GITUP","GIT2 16:9" }, // Android Raw dumps id start // File Size in bytes Horizontal Res Vertical Flag then bayer order eg 0x16 bbgr 0x94 rggb { 1540857,2688,1520, 0, 0, 0, 0, 1,0x61,0,0,"Samsung","S3" }, { 2658304,1212,1096, 0, 0, 0, 0, 1 ,0x16,0,0,"LG","G3FrontMipi" }, { 2842624,1296,1096, 0, 0, 0, 0, 1 ,0x16,0,0,"LG","G3FrontQCOM" }, { 2969600,1976,1200, 0, 0, 0, 0, 1 ,0x16,0,0,"Xiaomi","MI3wMipi" }, { 3170304,1976,1200, 0, 0, 0, 0, 1 ,0x16,0,0,"Xiaomi","MI3wQCOM" }, { 3763584,1584,1184, 0, 0, 0, 0, 96,0x61,0,0,"I_Mobile","I_StyleQ6" }, { 5107712,2688,1520, 0, 0, 0, 0, 1 ,0x61,0,0,"OmniVisi","UltraPixel1" }, { 5382640,2688,1520, 0, 0, 0, 0, 1 ,0x61,0,0,"OmniVisi","UltraPixel2" }, { 5664912,2688,1520, 0, 0, 0, 0, 1 ,0x61,0,0,"OmniVisi","4688" }, { 5664912,2688,1520, 0, 0, 0, 0, 1 ,0x61,0,0,"OmniVisi","4688" }, { 5364240,2688,1520, 0, 0, 0, 0, 1 ,0x61,0,0,"OmniVisi","4688" }, { 6299648,2592,1944, 0, 0, 0, 0, 1 ,0x16,0,0,"OmniVisi","OV5648" }, { 6721536,2592,1944, 0, 0, 0, 0, 0 ,0x16,0,0,"OmniVisi","OV56482" }, { 6746112,2592,1944, 0, 0, 0, 0, 0 ,0x16,0,0,"HTC","OneSV" }, { 9631728,2532,1902, 0, 0, 0, 0, 96,0x61,0,0,"Sony","5mp" }, { 9830400,2560,1920, 0, 0, 0, 0, 96,0x61,0,0,"NGM","ForwardArt" }, { 10186752,3264,2448, 0, 0, 0, 0, 1,0x94,0,0,"Sony","IMX219-mipi 8mp" }, { 10223360,2608,1944, 0, 0, 0, 0, 96,0x16,0,0,"Sony","IMX" }, { 10782464,3282,2448, 0, 0, 0, 0, 0 ,0x16,0,0,"HTC","MyTouch4GSlide" }, { 10788864,3282,2448, 0, 0, 0, 0, 0, 0x16,0,0,"Xperia","L" }, { 15967488,3264,2446, 0, 0, 0, 0, 96,0x16,0,0,"OmniVison","OV8850" }, { 16224256,4208,3082, 0, 0, 0, 0, 1, 0x16,0,0,"LG","G3MipiL" }, { 16424960,4208,3120, 0, 0, 0, 0, 1, 0x16,0,0,"IMX135","MipiL" }, { 17326080,4164,3120, 0, 0, 0, 0, 1, 0x16,0,0,"LG","G3LQCom" }, { 17522688,4212,3120, 0, 0, 0, 0, 0,0x16,0,0,"Sony","IMX135-QCOM" }, { 19906560,4608,3456, 0, 0, 0, 0, 1, 0x16,0,0,"Gione","E7mipi" }, { 19976192,5312,2988, 0, 0, 0, 0, 1, 0x16,0,0,"LG","G4" }, { 20389888,4632,3480, 0, 0, 0, 0, 1, 0x16,0,0,"Xiaomi","RedmiNote3Pro" }, { 20500480,4656,3496, 0, 0, 0, 0, 1,0x94,0,0,"Sony","IMX298-mipi 16mp" }, { 21233664,4608,3456, 0, 0, 0, 0, 1, 0x16,0,0,"Gione","E7qcom" }, { 26023936,4192,3104, 0, 0, 0, 0, 96,0x94,0,0,"THL","5000" }, { 26257920,4208,3120, 0, 0, 0, 0, 96,0x94,0,0,"Sony","IMX214" }, { 26357760,4224,3120, 0, 0, 0, 0, 96,0x61,0,0,"OV","13860" }, { 41312256,5248,3936, 0, 0, 0, 0, 96,0x61,0,0,"Meizu","MX4" }, { 42923008,5344,4016, 0, 0, 0, 0, 96,0x61,0,0,"Sony","IMX230" }, // Android Raw dumps id end { 20137344,3664,2748,0, 0, 0, 0,0x40,0x49,0,0,"Aptina","MT9J003",0xffff }, { 2868726,1384,1036, 0, 0, 0, 0,64,0x49,0,8,"Baumer","TXG14",1078 }, { 5298000,2400,1766,12,12,44, 2,40,0x94,0,2,"Canon","PowerShot SD300" }, { 6553440,2664,1968, 4, 4,44, 4,40,0x94,0,2,"Canon","PowerShot A460" }, { 6573120,2672,1968,12, 8,44, 0,40,0x94,0,2,"Canon","PowerShot A610" }, { 6653280,2672,1992,10, 6,42, 2,40,0x94,0,2,"Canon","PowerShot A530" }, { 7710960,2888,2136,44, 8, 4, 0,40,0x94,0,2,"Canon","PowerShot S3 IS" }, { 9219600,3152,2340,36,12, 4, 0,40,0x94,0,2,"Canon","PowerShot A620" }, { 9243240,3152,2346,12, 7,44,13,40,0x49,0,2,"Canon","PowerShot A470" }, { 10341600,3336,2480, 6, 5,32, 3,40,0x94,0,2,"Canon","PowerShot A720 IS" }, { 10383120,3344,2484,12, 6,44, 6,40,0x94,0,2,"Canon","PowerShot A630" }, { 12945240,3736,2772,12, 6,52, 6,40,0x94,0,2,"Canon","PowerShot A640" }, { 15636240,4104,3048,48,12,24,12,40,0x94,0,2,"Canon","PowerShot A650" }, { 15467760,3720,2772, 6,12,30, 0,40,0x94,0,2,"Canon","PowerShot SX110 IS" }, { 15534576,3728,2778,12, 9,44, 9,40,0x94,0,2,"Canon","PowerShot SX120 IS" }, { 18653760,4080,3048,24,12,24,12,40,0x94,0,2,"Canon","PowerShot SX20 IS" }, { 19131120,4168,3060,92,16, 4, 1,40,0x94,0,2,"Canon","PowerShot SX220 HS" }, { 21936096,4464,3276,25,10,73,12,40,0x16,0,2,"Canon","PowerShot SX30 IS" }, { 24724224,4704,3504, 8,16,56, 8,40,0x49,0,2,"Canon","PowerShot A3300 IS" }, { 30858240,5248,3920, 8,16,56,16,40,0x94,0,2,"Canon","IXUS 160" }, { 1976352,1632,1211, 0, 2, 0, 1, 0,0x94,0,1,"Casio","QV-2000UX" }, { 3217760,2080,1547, 0, 0,10, 1, 0,0x94,0,1,"Casio","QV-3*00EX" }, { 6218368,2585,1924, 0, 0, 9, 0, 0,0x94,0,1,"Casio","QV-5700" }, { 7816704,2867,2181, 0, 0,34,36, 0,0x16,0,1,"Casio","EX-Z60" }, { 2937856,1621,1208, 0, 0, 1, 0, 0,0x94,7,13,"Casio","EX-S20" }, { 4948608,2090,1578, 0, 0,32,34, 0,0x94,7,1,"Casio","EX-S100" }, { 6054400,2346,1720, 2, 0,32, 0, 0,0x94,7,1,"Casio","QV-R41" }, { 7426656,2568,1928, 0, 0, 0, 0, 0,0x94,0,1,"Casio","EX-P505" }, { 7530816,2602,1929, 0, 0,22, 0, 0,0x94,7,1,"Casio","QV-R51" }, { 7542528,2602,1932, 0, 0,32, 0, 0,0x94,7,1,"Casio","EX-Z50" }, { 7562048,2602,1937, 0, 0,25, 0, 0,0x16,7,1,"Casio","EX-Z500" }, { 7753344,2602,1986, 0, 0,32,26, 0,0x94,7,1,"Casio","EX-Z55" }, { 9313536,2858,2172, 0, 0,14,30, 0,0x94,7,1,"Casio","EX-P600" }, { 10834368,3114,2319, 0, 0,27, 0, 0,0x94,0,1,"Casio","EX-Z750" }, { 10843712,3114,2321, 0, 0,25, 0, 0,0x94,0,1,"Casio","EX-Z75" }, { 10979200,3114,2350, 0, 0,32,32, 0,0x94,7,1,"Casio","EX-P700" }, { 12310144,3285,2498, 0, 0, 6,30, 0,0x94,0,1,"Casio","EX-Z850" }, { 12489984,3328,2502, 0, 0,47,35, 0,0x94,0,1,"Casio","EX-Z8" }, { 15499264,3754,2752, 0, 0,82, 0, 0,0x94,0,1,"Casio","EX-Z1050" }, { 18702336,4096,3044, 0, 0,24, 0,80,0x94,7,1,"Casio","EX-ZR100" }, { 7684000,2260,1700, 0, 0, 0, 0,13,0x94,0,1,"Casio","QV-4000" }, { 787456,1024, 769, 0, 1, 0, 0, 0,0x49,0,0,"Creative","PC-CAM 600" }, { 28829184,4384,3288, 0, 0, 0, 0,36,0x61,0,0,"DJI" }, { 15151104,4608,3288, 0, 0, 0, 0, 0,0x94,0,0,"Matrix" }, { 3840000,1600,1200, 0, 0, 0, 0,65,0x49,0,0,"Foculus","531C" }, { 307200, 640, 480, 0, 0, 0, 0, 0,0x94,0,0,"Generic" }, { 62464, 256, 244, 1, 1, 6, 1, 0,0x8d,0,0,"Kodak","DC20" }, { 124928, 512, 244, 1, 1,10, 1, 0,0x8d,0,0,"Kodak","DC20" }, { 1652736,1536,1076, 0,52, 0, 0, 0,0x61,0,0,"Kodak","DCS200" }, { 4159302,2338,1779, 1,33, 1, 2, 0,0x94,0,0,"Kodak","C330" }, { 4162462,2338,1779, 1,33, 1, 2, 0,0x94,0,0,"Kodak","C330",3160 }, { 2247168,1232, 912, 0, 0,16, 0, 0,0x00,0,0,"Kodak","C330" }, { 3370752,1232, 912, 0, 0,16, 0, 0,0x00,0,0,"Kodak","C330" }, { 6163328,2864,2152, 0, 0, 0, 0, 0,0x94,0,0,"Kodak","C603" }, { 6166488,2864,2152, 0, 0, 0, 0, 0,0x94,0,0,"Kodak","C603",3160 }, { 460800, 640, 480, 0, 0, 0, 0, 0,0x00,0,0,"Kodak","C603" }, { 9116448,2848,2134, 0, 0, 0, 0, 0,0x00,0,0,"Kodak","C603" }, { 12241200,4040,3030, 2, 0, 0,13, 0,0x49,0,0,"Kodak","12MP" }, { 12272756,4040,3030, 2, 0, 0,13, 0,0x49,0,0,"Kodak","12MP",31556 }, { 18000000,4000,3000, 0, 0, 0, 0, 0,0x00,0,0,"Kodak","12MP" }, { 614400, 640, 480, 0, 3, 0, 0,64,0x94,0,0,"Kodak","KAI-0340" }, { 15360000,3200,2400, 0, 0, 0, 0,96,0x16,0,0,"Lenovo","A820" }, { 3884928,1608,1207, 0, 0, 0, 0,96,0x16,0,0,"Micron","2010",3212 }, { 1138688,1534, 986, 0, 0, 0, 0, 0,0x61,0,0,"Minolta","RD175",513 }, { 1581060,1305, 969, 0, 0,18, 6, 6,0x1e,4,1,"Nikon","E900" }, { 2465792,1638,1204, 0, 0,22, 1, 6,0x4b,5,1,"Nikon","E950" }, { 2940928,1616,1213, 0, 0, 0, 7,30,0x94,0,1,"Nikon","E2100" }, { 4771840,2064,1541, 0, 0, 0, 1, 6,0xe1,0,1,"Nikon","E990" }, { 4775936,2064,1542, 0, 0, 0, 0,30,0x94,0,1,"Nikon","E3700" }, { 5865472,2288,1709, 0, 0, 0, 1, 6,0xb4,0,1,"Nikon","E4500" }, { 5869568,2288,1710, 0, 0, 0, 0, 6,0x16,0,1,"Nikon","E4300" }, { 7438336,2576,1925, 0, 0, 0, 1, 6,0xb4,0,1,"Nikon","E5000" }, { 8998912,2832,2118, 0, 0, 0, 0,30,0x94,7,1,"Nikon","COOLPIX S6" }, { 5939200,2304,1718, 0, 0, 0, 0,30,0x16,0,0,"Olympus","C770UZ" }, { 3178560,2064,1540, 0, 0, 0, 0, 0,0x94,0,1,"Pentax","Optio S" }, { 4841984,2090,1544, 0, 0,22, 0, 0,0x94,7,1,"Pentax","Optio S" }, { 6114240,2346,1737, 0, 0,22, 0, 0,0x94,7,1,"Pentax","Optio S4" }, { 10702848,3072,2322, 0, 0, 0,21,30,0x94,0,1,"Pentax","Optio 750Z" }, { 4147200,1920,1080, 0, 0, 0, 0, 0,0x49,0,0,"Photron","BC2-HD" }, { 4151666,1920,1080, 0, 0, 0, 0, 0,0x49,0,0,"Photron","BC2-HD",8 }, { 13248000,2208,3000, 0, 0, 0, 0,13,0x61,0,0,"Pixelink","A782" }, { 6291456,2048,1536, 0, 0, 0, 0,96,0x61,0,0,"RoverShot","3320AF" }, { 311696, 644, 484, 0, 0, 0, 0, 0,0x16,0,8,"ST Micro","STV680 VGA" }, { 16098048,3288,2448, 0, 0,24, 0, 9,0x94,0,1,"Samsung","S85" }, { 16215552,3312,2448, 0, 0,48, 0, 9,0x94,0,1,"Samsung","S85" }, { 20487168,3648,2808, 0, 0, 0, 0,13,0x94,5,1,"Samsung","WB550" }, { 24000000,4000,3000, 0, 0, 0, 0,13,0x94,5,1,"Samsung","WB550" }, { 12582980,3072,2048, 0, 0, 0, 0,33,0x61,0,0,"Sinar","",68 }, { 33292868,4080,4080, 0, 0, 0, 0,33,0x61,0,0,"Sinar","",68 }, { 44390468,4080,5440, 0, 0, 0, 0,33,0x61,0,0,"Sinar","",68 }, { 1409024,1376,1024, 0, 0, 1, 0, 0,0x49,0,0,"Sony","XCD-SX910CR" }, { 2818048,1376,1024, 0, 0, 1, 0,97,0x49,0,0,"Sony","XCD-SX910CR" }, }; #ifdef LIBRAW_LIBRARY_BUILD libraw_custom_camera_t table[64 + sizeof(const_table)/sizeof(const_table[0])]; #endif static const char *corp[] = { "AgfaPhoto", "Canon", "Casio", "Epson", "Fujifilm", "Mamiya", "Minolta", "Motorola", "Kodak", "Konica", "Leica", "Nikon", "Nokia", "Olympus", "Pentax", "Phase One", "Ricoh", "Samsung", "Sigma", "Sinar", "Sony" }; #ifdef LIBRAW_LIBRARY_BUILD char head[64], *cp; #else char head[32], *cp; #endif int hlen, flen, fsize, zero_fsize=1, i, c; struct jhead jh; #ifdef LIBRAW_LIBRARY_BUILD unsigned camera_count = parse_custom_cameras(64,table,imgdata.params.custom_camera_strings); for(int q = 0; q < sizeof(const_table)/sizeof(const_table[0]); q++) memmove(&table[q+camera_count],&const_table[q],sizeof(const_table[0])); camera_count += sizeof(const_table)/sizeof(const_table[0]); #endif tiff_flip = flip = filters = UINT_MAX; /* unknown */ raw_height = raw_width = fuji_width = fuji_layout = cr2_slice[0] = 0; maximum = height = width = top_margin = left_margin = 0; cdesc[0] = desc[0] = artist[0] = make[0] = model[0] = model2[0] = 0; iso_speed = shutter = aperture = focal_len = unique_id = 0; tiff_nifds = 0; memset (tiff_ifd, 0, sizeof tiff_ifd); memset (gpsdata, 0, sizeof gpsdata); memset (cblack, 0, sizeof cblack); memset (white, 0, sizeof white); memset (mask, 0, sizeof mask); thumb_offset = thumb_length = thumb_width = thumb_height = 0; load_raw = thumb_load_raw = 0; write_thumb = &CLASS jpeg_thumb; data_offset = meta_offset = meta_length = tiff_bps = tiff_compress = 0; kodak_cbpp = zero_after_ff = dng_version = load_flags = 0; timestamp = shot_order = tiff_samples = black = is_foveon = 0; mix_green = profile_length = data_error = zero_is_bad = 0; pixel_aspect = is_raw = raw_color = 1; tile_width = tile_length = 0; for (i=0; i < 4; i++) { cam_mul[i] = i == 1; pre_mul[i] = i < 3; FORC3 cmatrix[c][i] = 0; FORC3 rgb_cam[c][i] = c == i; } colors = 3; for (i=0; i < 0x10000; i++) curve[i] = i; order = get2(); hlen = get4(); fseek (ifp, 0, SEEK_SET); #ifdef LIBRAW_LIBRARY_BUILD fread (head, 1, 64, ifp); libraw_internal_data.unpacker_data.lenRAFData = libraw_internal_data.unpacker_data.posRAFData = 0; #else fread (head, 1, 32, ifp); #endif fseek (ifp, 0, SEEK_END); flen = fsize = ftell(ifp); if ((cp = (char *) memmem (head, 32, (char*)"MMMM", 4)) || (cp = (char *) memmem (head, 32, (char*)"IIII", 4))) { parse_phase_one (cp-head); if (cp-head && parse_tiff(0)) apply_tiff(); } else if (order == 0x4949 || order == 0x4d4d) { if (!memcmp (head+6,"HEAPCCDR",8)) { data_offset = hlen; #ifdef LIBRAW_LIBRARY_BUILD imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens; #endif parse_ciff (hlen, flen-hlen, 0); load_raw = &CLASS canon_load_raw; } else if (parse_tiff(0)) apply_tiff(); } else if (!memcmp (head,"\xff\xd8\xff\xe1",4) && !memcmp (head+6,"Exif",4)) { fseek (ifp, 4, SEEK_SET); data_offset = 4 + get2(); fseek (ifp, data_offset, SEEK_SET); if (fgetc(ifp) != 0xff) parse_tiff(12); thumb_offset = 0; } else if (!memcmp (head+25,"ARECOYK",7)) { strcpy (make, "Contax"); strcpy (model,"N Digital"); fseek (ifp, 33, SEEK_SET); get_timestamp(1); fseek (ifp, 52, SEEK_SET); switch (get4()) { case 7: iso_speed = 25; break; case 8: iso_speed = 32; break; case 9: iso_speed = 40; break; case 10: iso_speed = 50; break; case 11: iso_speed = 64; break; case 12: iso_speed = 80; break; case 13: iso_speed = 100; break; case 14: iso_speed = 125; break; case 15: iso_speed = 160; break; case 16: iso_speed = 200; break; case 17: iso_speed = 250; break; case 18: iso_speed = 320; break; case 19: iso_speed = 400; break; } shutter = libraw_powf64(2.0f, (((float)get4())/8.0f)) / 16000.0f; FORC4 cam_mul[c ^ (c >> 1)] = get4(); fseek (ifp, 88, SEEK_SET); aperture = libraw_powf64(2.0f, ((float)get4())/16.0f); fseek (ifp, 112, SEEK_SET); focal_len = get4(); #ifdef LIBRAW_LIBRARY_BUILD fseek (ifp, 104, SEEK_SET); imgdata.lens.makernotes.MaxAp4CurFocal = libraw_powf64(2.0f, ((float)get4())/16.0f); fseek (ifp, 124, SEEK_SET); stmread(imgdata.lens.makernotes.Lens, 32, ifp); imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Contax_N; if (imgdata.lens.makernotes.Lens[0]) imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Contax_N; #endif } else if (!strcmp (head, "PXN")) { strcpy (make, "Logitech"); strcpy (model,"Fotoman Pixtura"); } else if (!strcmp (head, "qktk")) { strcpy (make, "Apple"); strcpy (model,"QuickTake 100"); load_raw = &CLASS quicktake_100_load_raw; } else if (!strcmp (head, "qktn")) { strcpy (make, "Apple"); strcpy (model,"QuickTake 150"); load_raw = &CLASS kodak_radc_load_raw; } else if (!memcmp (head,"FUJIFILM",8)) { #ifdef LIBRAW_LIBRARY_BUILD strcpy(model, head+0x1c); memcpy(model2, head+0x3c, 4); model2[4]=0; #endif fseek (ifp, 84, SEEK_SET); thumb_offset = get4(); thumb_length = get4(); fseek (ifp, 92, SEEK_SET); parse_fuji (get4()); if (thumb_offset > 120) { fseek (ifp, 120, SEEK_SET); is_raw += (i = get4())?1:0; if (is_raw == 2 && shot_select) parse_fuji (i); } load_raw = &CLASS unpacked_load_raw; fseek (ifp, 100+28*(shot_select > 0), SEEK_SET); parse_tiff (data_offset = get4()); parse_tiff (thumb_offset+12); apply_tiff(); } else if (!memcmp (head,"RIFF",4)) { fseek (ifp, 0, SEEK_SET); parse_riff(); } else if (!memcmp (head+4,"ftypqt ",9)) { fseek (ifp, 0, SEEK_SET); parse_qt (fsize); is_raw = 0; } else if (!memcmp (head,"\0\001\0\001\0@",6)) { fseek (ifp, 6, SEEK_SET); fread (make, 1, 8, ifp); fread (model, 1, 8, ifp); fread (model2, 1, 16, ifp); data_offset = get2(); get2(); raw_width = get2(); raw_height = get2(); load_raw = &CLASS nokia_load_raw; filters = 0x61616161; } else if (!memcmp (head,"NOKIARAW",8)) { strcpy (make, "NOKIA"); order = 0x4949; fseek (ifp, 300, SEEK_SET); data_offset = get4(); i = get4(); width = get2(); height = get2(); #ifdef LIBRAW_LIBRARY_BUILD // data length should be in range w*h..w*h*2 if(width*height < (LIBRAW_MAX_ALLOC_MB*1024*512L) && width*height>1 && i >= width * height && i <= width*height*2) { #endif switch (tiff_bps = i*8 / (width * height)) { case 8: load_raw = &CLASS eight_bit_load_raw; break; case 10: load_raw = &CLASS nokia_load_raw; } raw_height = height + (top_margin = i / (width * tiff_bps/8) - height); mask[0][3] = 1; filters = 0x61616161; #ifdef LIBRAW_LIBRARY_BUILD } else is_raw = 0; #endif } else if (!memcmp (head,"ARRI",4)) { order = 0x4949; fseek (ifp, 20, SEEK_SET); width = get4(); height = get4(); strcpy (make, "ARRI"); fseek (ifp, 668, SEEK_SET); fread (model, 1, 64, ifp); data_offset = 4096; load_raw = &CLASS packed_load_raw; load_flags = 88; filters = 0x61616161; } else if (!memcmp (head,"XPDS",4)) { order = 0x4949; fseek (ifp, 0x800, SEEK_SET); fread (make, 1, 41, ifp); raw_height = get2(); raw_width = get2(); fseek (ifp, 56, SEEK_CUR); fread (model, 1, 30, ifp); data_offset = 0x10000; load_raw = &CLASS canon_rmf_load_raw; gamma_curve (0, 12.25, 1, 1023); } else if (!memcmp (head+4,"RED1",4)) { strcpy (make, "Red"); strcpy (model,"One"); parse_redcine(); load_raw = &CLASS redcine_load_raw; gamma_curve (1/2.4, 12.92, 1, 4095); filters = 0x49494949; } else if (!memcmp (head,"DSC-Image",9)) parse_rollei(); else if (!memcmp (head,"PWAD",4)) parse_sinar_ia(); else if (!memcmp (head,"\0MRM",4)) parse_minolta(0); else if (!memcmp (head,"FOVb",4)) { #ifdef LIBRAW_LIBRARY_BUILD #ifdef LIBRAW_DEMOSAIC_PACK_GPL2 if(!(imgdata.params.raw_processing_options & LIBRAW_PROCESSING_FORCE_FOVEON_X3F)) parse_foveon(); else #endif parse_x3f(); #else #ifdef LIBRAW_DEMOSAIC_PACK_GPL2 parse_foveon(); #endif #endif } else if (!memcmp (head,"CI",2)) parse_cine(); if(make[0] == 0) #ifdef LIBRAW_LIBRARY_BUILD for (zero_fsize=i=0; i < camera_count; i++) #else for (zero_fsize=i=0; i < sizeof table / sizeof *table; i++) #endif if (fsize == table[i].fsize) { strcpy (make, table[i].t_make ); #ifdef LIBRAW_LIBRARY_BUILD if (!strncmp(make, "Canon",5)) { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens; } #endif strcpy (model, table[i].t_model); flip = table[i].flags >> 2; zero_is_bad = table[i].flags & 2; if (table[i].flags & 1) parse_external_jpeg(); data_offset = table[i].offset == 0xffff?0:table[i].offset; raw_width = table[i].rw; raw_height = table[i].rh; left_margin = table[i].lm; top_margin = table[i].tm; width = raw_width - left_margin - table[i].rm; height = raw_height - top_margin - table[i].bm; filters = 0x1010101 * table[i].cf; colors = 4 - !((filters & filters >> 1) & 0x5555); load_flags = table[i].lf; switch (tiff_bps = (fsize-data_offset)*8 / (raw_width*raw_height)) { case 6: load_raw = &CLASS minolta_rd175_load_raw; break; case 8: load_raw = &CLASS eight_bit_load_raw; break; case 10: if ((fsize-data_offset)/raw_height*3 >= raw_width*4) { load_raw = &CLASS android_loose_load_raw; break; } else if (load_flags & 1) { load_raw = &CLASS android_tight_load_raw; break; } case 12: load_flags |= 128; load_raw = &CLASS packed_load_raw; break; case 16: order = 0x4949 | 0x404 * (load_flags & 1); tiff_bps -= load_flags >> 4; tiff_bps -= load_flags = load_flags >> 1 & 7; load_raw = table[i].offset == 0xffff ? &CLASS unpacked_load_raw_reversed : &CLASS unpacked_load_raw; } maximum = (1 << tiff_bps) - (1 << table[i].max); } if (zero_fsize) fsize = 0; if (make[0] == 0) parse_smal (0, flen); if (make[0] == 0) { parse_jpeg(0); fseek(ifp,0,SEEK_END); int sz = ftell(ifp); #ifdef LIBRAW_LIBRARY_BUILD if (!strncmp(model,"RP_imx219",9) && sz >= 0x9cb600 && !fseek (ifp, -0x9cb600, SEEK_END) && fread (head, 1, 0x20, ifp) && !strncmp(head, "BRCM", 4)) { strcpy (make, "Broadcom"); strcpy (model, "RPi IMX219"); if (raw_height > raw_width) flip = 5; data_offset = ftell(ifp) + 0x8000 - 0x20; parse_broadcom(); black = 66; maximum = 0x3ff; load_raw = &CLASS broadcom_load_raw; thumb_offset = 0; thumb_length = sz - 0x9cb600 - 1; } else if (!(strncmp(model,"ov5647",6) && strncmp(model,"RP_OV5647",9)) && sz >= 0x61b800 && !fseek (ifp, -0x61b800, SEEK_END) && fread (head, 1, 0x20, ifp) && !strncmp(head, "BRCM", 4)) { strcpy (make, "Broadcom"); if (!strncmp(model,"ov5647",6)) strcpy (model, "RPi OV5647 v.1"); else strcpy (model, "RPi OV5647 v.2"); if (raw_height > raw_width) flip = 5; data_offset = ftell(ifp) + 0x8000 - 0x20; parse_broadcom(); black = 16; maximum = 0x3ff; load_raw = &CLASS broadcom_load_raw; thumb_offset = 0; thumb_length = sz - 0x61b800 - 1; #else if (!(strncmp(model,"ov",2) && strncmp(model,"RP_OV",5)) && sz>=6404096 && !fseek (ifp, -6404096, SEEK_END) && fread (head, 1, 32, ifp) && !strcmp(head,"BRCMn")) { strcpy (make, "OmniVision"); data_offset = ftell(ifp) + 0x8000-32; width = raw_width; raw_width = 2611; load_raw = &CLASS nokia_load_raw; filters = 0x16161616; #endif } else is_raw = 0; } #ifdef LIBRAW_LIBRARY_BUILD // make sure strings are terminated desc[511] = artist[63] = make[63] = model[63] = model2[63] = 0; #endif for (i=0; i < sizeof corp / sizeof *corp; i++) if (strcasestr (make, corp[i])) /* Simplify company names */ strcpy (make, corp[i]); if ((!strncmp(make,"Kodak",5) || !strncmp(make,"Leica",5)) && ((cp = strcasestr(model," DIGITAL CAMERA")) || (cp = strstr(model,"FILE VERSION")))) *cp = 0; if (!strncasecmp(model,"PENTAX",6)) strcpy (make, "Pentax"); #ifdef LIBRAW_LIBRARY_BUILD remove_trailing_spaces(make,sizeof(make)); remove_trailing_spaces(model,sizeof(model)); #else cp = make + strlen(make); /* Remove trailing spaces */ while (*--cp == ' ') *cp = 0; cp = model + strlen(model); while (*--cp == ' ') *cp = 0; #endif i = strbuflen(make); /* Remove make from model */ if (!strncasecmp (model, make, i) && model[i++] == ' ') memmove (model, model+i, 64-i); if (!strncmp (model,"FinePix ",8)) strcpy (model, model+8); if (!strncmp (model,"Digital Camera ",15)) strcpy (model, model+15); desc[511] = artist[63] = make[63] = model[63] = model2[63] = 0; if (!is_raw) goto notraw; if (!height) height = raw_height; if (!width) width = raw_width; if (height == 2624 && width == 3936) /* Pentax K10D and Samsung GX10 */ { height = 2616; width = 3896; } if (height == 3136 && width == 4864) /* Pentax K20D and Samsung GX20 */ { height = 3124; width = 4688; filters = 0x16161616; } if (width == 4352 && (!strcmp(model,"K-r") || !strcmp(model,"K-x"))) { width = 4309; filters = 0x16161616; } if (width >= 4960 && !strncmp(model,"K-5",3)) { left_margin = 10; width = 4950; filters = 0x16161616; } if (width == 6080 && !strcmp(model,"K-70")) { height = 4016; top_margin=32; width=6020; left_margin = 60; } if (width == 4736 && !strcmp(model,"K-7")) { height = 3122; width = 4684; filters = 0x16161616; top_margin = 2; } if (width == 6080 && !strcmp(model,"K-3 II")) /* moved back */ { left_margin = 4; width = 6040; } if (width == 6080 && !strcmp(model,"K-3")) { left_margin = 4; width = 6040; } if (width == 7424 && !strcmp(model,"645D")) { height = 5502; width = 7328; filters = 0x61616161; top_margin = 29; left_margin = 48; } if (height == 3014 && width == 4096) /* Ricoh GX200 */ width = 4014; if (dng_version) { if (filters == UINT_MAX) filters = 0; if (filters) is_raw *= tiff_samples; else colors = tiff_samples; switch (tiff_compress) { case 0: /* Compression not set, assuming uncompressed */ case 1: load_raw = &CLASS packed_dng_load_raw; break; case 7: load_raw = &CLASS lossless_dng_load_raw; break; #ifdef LIBRAW_LIBRARY_BUILD case 8: load_raw = &CLASS deflate_dng_load_raw; break; #endif case 34892: load_raw = &CLASS lossy_dng_load_raw; break; default: load_raw = 0; } if (!strncmp(make, "Canon",5) && unique_id) { for (i = 0; i < sizeof unique / sizeof *unique; i++) if (unique_id == 0x80000000 + unique[i].id) { strcpy(model, unique[i].t_model); break; } } if (!strncasecmp(make, "Sony",4) && unique_id) { for (i = 0; i < sizeof sonique / sizeof *sonique; i++) if (unique_id == sonique[i].id) { strcpy(model, sonique[i].t_model); break; } } goto dng_skip; } if (!strncmp(make,"Canon",5) && !fsize && tiff_bps != 15) { if (!load_raw) load_raw = &CLASS lossless_jpeg_load_raw; for (i=0; i < sizeof canon / sizeof *canon; i++) if (raw_width == canon[i][0] && raw_height == canon[i][1]) { width = raw_width - (left_margin = canon[i][2]); height = raw_height - (top_margin = canon[i][3]); width -= canon[i][4]; height -= canon[i][5]; mask[0][1] = canon[i][6]; mask[0][3] = -canon[i][7]; mask[1][1] = canon[i][8]; mask[1][3] = -canon[i][9]; if (canon[i][10]) filters = canon[i][10] * 0x01010101; } if ((unique_id | 0x20000) == 0x2720000) { left_margin = 8; top_margin = 16; } } if (!strncmp(make,"Canon",5) && unique_id) { for (i=0; i < sizeof unique / sizeof *unique; i++) if (unique_id == 0x80000000 + unique[i].id) { adobe_coeff ("Canon", unique[i].t_model); strcpy(model,unique[i].t_model); } } if (!strncasecmp(make,"Sony",4) && unique_id) { for (i=0; i < sizeof sonique / sizeof *sonique; i++) if (unique_id == sonique[i].id) { adobe_coeff ("Sony", sonique[i].t_model); strcpy(model,sonique[i].t_model); } } if (!strncmp(make,"Nikon",5)) { if (!load_raw) load_raw = &CLASS packed_load_raw; if (model[0] == 'E') load_flags |= !data_offset << 2 | 2; } /* Set parameters based on camera name (for non-DNG files). */ if (!strcmp(model,"KAI-0340") && find_green (16, 16, 3840, 5120) < 25) { height = 480; top_margin = filters = 0; strcpy (model,"C603"); } if (!strcmp(make, "Sony") && raw_width > 3888 && !black && !cblack[0]) black = 128 << (tiff_bps - 12); if (is_foveon) { if (height*2 < width) pixel_aspect = 0.5; if (height > width) pixel_aspect = 2; filters = 0; #ifdef LIBRAW_DEMOSAIC_PACK_GPL2 if(!(imgdata.params.raw_processing_options & LIBRAW_PROCESSING_FORCE_FOVEON_X3F)) simple_coeff(0); #endif } else if(!strncmp(make,"Pentax",6)) { if(!strncmp(model,"K-1",3)) { top_margin = 18; height = raw_height - top_margin; if(raw_width == 7392) { left_margin = 6; width = 7376; } } } else if (!strncmp(make,"Canon",5) && tiff_bps == 15) { switch (width) { case 3344: width -= 66; case 3872: width -= 6; } if (height > width) { SWAP(height,width); SWAP(raw_height,raw_width); } if (width == 7200 && height == 3888) { raw_width = width = 6480; raw_height = height = 4320; } filters = 0; tiff_samples = colors = 3; load_raw = &CLASS canon_sraw_load_raw; } else if (!strcmp(model,"PowerShot 600")) { height = 613; width = 854; raw_width = 896; colors = 4; filters = 0xe1e4e1e4; load_raw = &CLASS canon_600_load_raw; } else if (!strcmp(model,"PowerShot A5") || !strcmp(model,"PowerShot A5 Zoom")) { height = 773; width = 960; raw_width = 992; pixel_aspect = 256/235.0; filters = 0x1e4e1e4e; goto canon_a5; } else if (!strcmp(model,"PowerShot A50")) { height = 968; width = 1290; raw_width = 1320; filters = 0x1b4e4b1e; goto canon_a5; } else if (!strcmp(model,"PowerShot Pro70")) { height = 1024; width = 1552; filters = 0x1e4b4e1b; canon_a5: colors = 4; tiff_bps = 10; load_raw = &CLASS packed_load_raw; load_flags = 40; } else if (!strcmp(model,"PowerShot Pro90 IS") || !strcmp(model,"PowerShot G1")) { colors = 4; filters = 0xb4b4b4b4; } else if (!strcmp(model,"PowerShot A610")) { if (canon_s2is()) strcpy (model+10, "S2 IS"); } else if (!strcmp(model,"PowerShot SX220 HS")) { mask[1][3] = -4; top_margin=16; left_margin = 92; } else if (!strcmp(model,"PowerShot S120")) { raw_width = 4192; raw_height = 3062; width = 4022; height = 3016; mask[0][0] = top_margin = 31; mask[0][2] = top_margin + height; left_margin = 120; mask[0][1] = 23; mask[0][3] = 72; } else if (!strcmp(model,"PowerShot G16")) { mask[0][0] = 0; mask[0][2] = 80; mask[0][1] = 0; mask[0][3] = 16; top_margin = 29; left_margin = 120; width = raw_width-left_margin-48; height = raw_height-top_margin-14; } else if (!strcmp(model,"PowerShot SX50 HS")) { top_margin = 17; } else if (!strcmp(model,"EOS D2000C")) { filters = 0x61616161; black = curve[200]; } else if (!strcmp(model,"D1")) { cam_mul[0] *= 256/527.0; cam_mul[2] *= 256/317.0; } else if (!strcmp(model,"D1X")) { width -= 4; pixel_aspect = 0.5; } else if (!strcmp(model,"D40X") || !strcmp(model,"D60") || !strcmp(model,"D80") || !strcmp(model,"D3000")) { height -= 3; width -= 4; } else if (!strcmp(model,"D3") || !strcmp(model,"D3S") || !strcmp(model,"D700")) { width -= 4; left_margin = 2; } else if (!strcmp(model,"D3100")) { width -= 28; left_margin = 6; } else if (!strcmp(model,"D5000") || !strcmp(model,"D90")) { width -= 42; } else if (!strcmp(model,"D5100") || !strcmp(model,"D7000") || !strcmp(model,"COOLPIX A")) { width -= 44; } else if (!strcmp(model,"D3200") || !strncmp(model,"D6",2) || !strncmp(model,"D800",4)) { width -= 46; } else if (!strcmp(model,"D4") || !strcmp(model,"Df")) { width -= 52; left_margin = 2; } else if (!strncmp(model,"D40",3) || !strncmp(model,"D50",3) || !strncmp(model,"D70",3)) { width--; } else if (!strcmp(model,"D100")) { if (load_flags) raw_width = (width += 3) + 3; } else if (!strcmp(model,"D200")) { left_margin = 1; width -= 4; filters = 0x94949494; } else if (!strncmp(model,"D2H",3)) { left_margin = 6; width -= 14; } else if (!strncmp(model,"D2X",3)) { if (width == 3264) width -= 32; else width -= 8; } else if (!strncmp(model,"D300",4)) { width -= 32; } else if (!strncmp(make,"Nikon",5) && raw_width == 4032) { if(!strcmp(model,"COOLPIX P7700")) { adobe_coeff ("Nikon","COOLPIX P7700"); maximum = 65504; load_flags = 0; } else if(!strcmp(model,"COOLPIX P7800")) { adobe_coeff ("Nikon","COOLPIX P7800"); maximum = 65504; load_flags = 0; } else if(!strcmp(model,"COOLPIX P340")) load_flags=0; } else if (!strncmp(model,"COOLPIX P",9) && raw_width != 4032) { load_flags = 24; filters = 0x94949494; if (model[9] == '7' && (iso_speed >= 400 || iso_speed==0) && !strstr(software,"V1.2") ) black = 255; } else if (!strncmp(model,"1 ",2)) { height -= 2; } else if (fsize == 1581060) { simple_coeff(3); pre_mul[0] = 1.2085; pre_mul[1] = 1.0943; pre_mul[3] = 1.1103; } else if (fsize == 3178560) { cam_mul[0] *= 4; cam_mul[2] *= 4; } else if (fsize == 4771840) { if (!timestamp && nikon_e995()) strcpy (model, "E995"); if (strcmp(model,"E995")) { filters = 0xb4b4b4b4; simple_coeff(3); pre_mul[0] = 1.196; pre_mul[1] = 1.246; pre_mul[2] = 1.018; } } else if (fsize == 2940928) { if (!timestamp && !nikon_e2100()) strcpy (model,"E2500"); if (!strcmp(model,"E2500")) { height -= 2; load_flags = 6; colors = 4; filters = 0x4b4b4b4b; } } else if (fsize == 4775936) { if (!timestamp) nikon_3700(); if (model[0] == 'E' && atoi(model+1) < 3700) filters = 0x49494949; if (!strcmp(model,"Optio 33WR")) { flip = 1; filters = 0x16161616; } if (make[0] == 'O') { i = find_green (12, 32, 1188864, 3576832); c = find_green (12, 32, 2383920, 2387016); if (abs(i) < abs(c)) { SWAP(i,c); load_flags = 24; } if (i < 0) filters = 0x61616161; } } else if (fsize == 5869568) { if (!timestamp && minolta_z2()) { strcpy (make, "Minolta"); strcpy (model,"DiMAGE Z2"); } load_flags = 6 + 24*(make[0] == 'M'); } else if (fsize == 6291456) { fseek (ifp, 0x300000, SEEK_SET); if ((order = guess_byte_order(0x10000)) == 0x4d4d) { height -= (top_margin = 16); width -= (left_margin = 28); maximum = 0xf5c0; strcpy (make, "ISG"); model[0] = 0; } } else if (!strncmp(make,"Fujifilm",8)) { if (!strcmp(model+7,"S2Pro")) { strcpy (model,"S2Pro"); height = 2144; width = 2880; flip = 6; } else if (load_raw != &CLASS packed_load_raw) maximum = (is_raw == 2 && shot_select) ? 0x2f00 : 0x3e00; top_margin = (raw_height - height) >> 2 << 1; left_margin = (raw_width - width ) >> 2 << 1; if (width == 2848 || width == 3664) filters = 0x16161616; if (width == 4032 || width == 4952) left_margin = 0; if (width == 3328 && (width -= 66)) left_margin = 34; if (width == 4936) left_margin = 4; if (width == 6032) left_margin = 0; if (!strcmp(model,"HS50EXR") || !strcmp(model,"F900EXR")) { width += 2; left_margin = 0; filters = 0x16161616; } if(!strcmp(model,"S5500")) { height -= (top_margin=6); } if (fuji_layout) raw_width *= is_raw; if (filters == 9) FORC(36) ((char *)xtrans)[c] = xtrans_abs[(c/6+top_margin) % 6][(c+left_margin) % 6]; } else if (!strcmp(model,"KD-400Z")) { height = 1712; width = 2312; raw_width = 2336; goto konica_400z; } else if (!strcmp(model,"KD-510Z")) { goto konica_510z; } else if (!strncasecmp(make,"Minolta",7)) { if (!load_raw && (maximum = 0xfff)) load_raw = &CLASS unpacked_load_raw; if (!strncmp(model,"DiMAGE A",8)) { if (!strcmp(model,"DiMAGE A200")) filters = 0x49494949; tiff_bps = 12; load_raw = &CLASS packed_load_raw; } else if (!strncmp(model,"ALPHA",5) || !strncmp(model,"DYNAX",5) || !strncmp(model,"MAXXUM",6)) { sprintf (model+20, "DYNAX %-10s", model+6+(model[0]=='M')); adobe_coeff (make, model+20); load_raw = &CLASS packed_load_raw; } else if (!strncmp(model,"DiMAGE G",8)) { if (model[8] == '4') { height = 1716; width = 2304; } else if (model[8] == '5') { konica_510z: height = 1956; width = 2607; raw_width = 2624; } else if (model[8] == '6') { height = 2136; width = 2848; } data_offset += 14; filters = 0x61616161; konica_400z: load_raw = &CLASS unpacked_load_raw; maximum = 0x3df; order = 0x4d4d; } } else if (!strcmp(model,"*ist D")) { load_raw = &CLASS unpacked_load_raw; data_error = -1; } else if (!strcmp(model,"*ist DS")) { height -= 2; } else if (!strncmp(make,"Samsung",7) && raw_width == 4704) { height -= top_margin = 8; width -= 2 * (left_margin = 8); load_flags = 32; } else if (!strncmp(make,"Samsung",7) && !strcmp(model,"NX3000")) { top_margin = 24; left_margin = 64; width = 5472; height = 3648; filters = 0x61616161; colors = 3; } else if (!strncmp(make,"Samsung",7) && raw_height == 3714) { height -= top_margin = 18; left_margin = raw_width - (width = 5536); if (raw_width != 5600) left_margin = top_margin = 0; filters = 0x61616161; colors = 3; } else if (!strncmp(make,"Samsung",7) && raw_width == 5632) { order = 0x4949; height = 3694; top_margin = 2; width = 5574 - (left_margin = 32 + tiff_bps); if (tiff_bps == 12) load_flags = 80; } else if (!strncmp(make,"Samsung",7) && raw_width == 5664) { height -= top_margin = 17; left_margin = 96; width = 5544; filters = 0x49494949; } else if (!strncmp(make,"Samsung",7) && raw_width == 6496) { filters = 0x61616161; #ifdef LIBRAW_LIBRARY_BUILD if(!black && !cblack[0] && !cblack[1] && !cblack[2] && !cblack[3]) #endif black = 1 << (tiff_bps - 7); } else if (!strcmp(model,"EX1")) { order = 0x4949; height -= 20; top_margin = 2; if ((width -= 6) > 3682) { height -= 10; width -= 46; top_margin = 8; } } else if (!strcmp(model,"WB2000")) { order = 0x4949; height -= 3; top_margin = 2; if ((width -= 10) > 3718) { height -= 28; width -= 56; top_margin = 8; } } else if (strstr(model,"WB550")) { strcpy (model, "WB550"); } else if (!strcmp(model,"EX2F")) { height = 3030; width = 4040; top_margin = 15; left_margin=24; order = 0x4949; filters = 0x49494949; load_raw = &CLASS unpacked_load_raw; } else if (!strcmp(model,"STV680 VGA")) { black = 16; } else if (!strcmp(model,"N95")) { height = raw_height - (top_margin = 2); } else if (!strcmp(model,"640x480")) { gamma_curve (0.45, 4.5, 1, 255); } else if (!strncmp(make,"Hasselblad",10)) { if (load_raw == &CLASS lossless_jpeg_load_raw) load_raw = &CLASS hasselblad_load_raw; if (raw_width == 7262) { height = 5444; width = 7248; top_margin = 4; left_margin = 7; filters = 0x61616161; if(!strncasecmp(model,"H3D",3)) { adobe_coeff("Hasselblad","H3DII-39"); strcpy(model,"H3DII-39"); } } else if (raw_width == 7410 || raw_width == 8282) { height -= 84; width -= 82; top_margin = 4; left_margin = 41; filters = 0x61616161; adobe_coeff("Hasselblad","H4D-40"); strcpy(model,"H4D-40"); } else if( raw_width == 8384) // X1D { top_margin = 96; height -= 96; left_margin = 48; width -= 106; adobe_coeff("Hasselblad","X1D"); } else if (raw_width == 9044) { if(black > 500) { top_margin = 12; left_margin = 44; width = 8956; height = 6708; memset(cblack,0,sizeof(cblack)); adobe_coeff("Hasselblad","H4D-60"); strcpy(model,"H4D-60"); black = 512; } else { height = 6716; width = 8964; top_margin = 8; left_margin = 40; black += load_flags = 256; maximum = 0x8101; strcpy(model,"H3DII-60"); } } else if (raw_width == 4090) { strcpy (model, "V96C"); height -= (top_margin = 6); width -= (left_margin = 3) + 7; filters = 0x61616161; } else if (raw_width == 8282 && raw_height == 6240) { if(!strncasecmp(model,"H5D",3)) { /* H5D 50*/ left_margin = 54; top_margin = 16; width = 8176; height = 6132; black = 256; strcpy(model,"H5D-50"); } else if(!strncasecmp(model,"H3D",3)) { black=0; left_margin = 54; top_margin = 16; width = 8176; height = 6132; memset(cblack,0,sizeof(cblack)); adobe_coeff("Hasselblad","H3D-50"); strcpy(model,"H3D-50"); } } else if (raw_width == 8374 && raw_height == 6304) { /* H5D 50c*/ left_margin = 52; top_margin = 100; width = 8272; height = 6200; black = 256; strcpy(model,"H5D-50c"); } if (tiff_samples > 1) { is_raw = tiff_samples+1; if (!shot_select && !half_size) filters = 0; } } else if (!strncmp(make,"Sinar",5)) { if (!load_raw) load_raw = &CLASS unpacked_load_raw; if (is_raw > 1 && !shot_select && !half_size) filters = 0; maximum = 0x3fff; } else if (!strncmp(make,"Leaf",4)) { maximum = 0x3fff; fseek (ifp, data_offset, SEEK_SET); if (ljpeg_start (&jh, 1) && jh.bits == 15) maximum = 0x1fff; if (tiff_samples > 1) filters = 0; if (tiff_samples > 1 || tile_length < raw_height) { load_raw = &CLASS leaf_hdr_load_raw; raw_width = tile_width; } if ((width | height) == 2048) { if (tiff_samples == 1) { filters = 1; strcpy (cdesc, "RBTG"); strcpy (model, "CatchLight"); top_margin = 8; left_margin = 18; height = 2032; width = 2016; } else { strcpy (model, "DCB2"); top_margin = 10; left_margin = 16; height = 2028; width = 2022; } } else if (width+height == 3144+2060) { if (!model[0]) strcpy (model, "Cantare"); if (width > height) { top_margin = 6; left_margin = 32; height = 2048; width = 3072; filters = 0x61616161; } else { left_margin = 6; top_margin = 32; width = 2048; height = 3072; filters = 0x16161616; } if (!cam_mul[0] || model[0] == 'V') filters = 0; else is_raw = tiff_samples; } else if (width == 2116) { strcpy (model, "Valeo 6"); height -= 2 * (top_margin = 30); width -= 2 * (left_margin = 55); filters = 0x49494949; } else if (width == 3171) { strcpy (model, "Valeo 6"); height -= 2 * (top_margin = 24); width -= 2 * (left_margin = 24); filters = 0x16161616; } } else if (!strncmp(make,"Leica",5) || !strncmp(make,"Panasonic",9) || !strncasecmp(make,"YUNEEC",6)) { if (raw_width > 0&& ((flen - data_offset) / (raw_width*8/7) == raw_height) ) load_raw = &CLASS panasonic_load_raw; if (!load_raw) { load_raw = &CLASS unpacked_load_raw; load_flags = 4; } zero_is_bad = 1; if ((height += 12) > raw_height) height = raw_height; for (i=0; i < sizeof pana / sizeof *pana; i++) if (raw_width == pana[i][0] && raw_height == pana[i][1]) { left_margin = pana[i][2]; top_margin = pana[i][3]; width += pana[i][4]; height += pana[i][5]; } filters = 0x01010101 * (uchar) "\x94\x61\x49\x16" [((filters-1) ^ (left_margin & 1) ^ (top_margin << 1)) & 3]; } else if (!strcmp(model,"C770UZ")) { height = 1718; width = 2304; filters = 0x16161616; load_raw = &CLASS packed_load_raw; load_flags = 30; } else if (!strncmp(make,"Olympus",7)) { height += height & 1; if (exif_cfa) filters = exif_cfa; if (width == 4100) width -= 4; if (width == 4080) width -= 24; if (width == 9280) { width -= 6; height -= 6; } if (load_raw == &CLASS unpacked_load_raw) load_flags = 4; tiff_bps = 12; if (!strcmp(model,"E-300") || !strcmp(model,"E-500")) { width -= 20; if (load_raw == &CLASS unpacked_load_raw) { maximum = 0xfc3; memset (cblack, 0, sizeof cblack); } } else if (!strcmp(model,"STYLUS1")) { width -= 14; maximum = 0xfff; } else if (!strcmp(model,"E-330")) { width -= 30; if (load_raw == &CLASS unpacked_load_raw) maximum = 0xf79; } else if (!strcmp(model,"SP550UZ")) { thumb_length = flen - (thumb_offset = 0xa39800); thumb_height = 480; thumb_width = 640; } else if (!strcmp(model,"TG-4")) { width -= 16; } } else if (!strcmp(model,"N Digital")) { height = 2047; width = 3072; filters = 0x61616161; data_offset = 0x1a00; load_raw = &CLASS packed_load_raw; } else if (!strcmp(model,"DSC-F828")) { width = 3288; left_margin = 5; mask[1][3] = -17; data_offset = 862144; load_raw = &CLASS sony_load_raw; filters = 0x9c9c9c9c; colors = 4; strcpy (cdesc, "RGBE"); } else if (!strcmp(model,"DSC-V3")) { width = 3109; left_margin = 59; mask[0][1] = 9; data_offset = 787392; load_raw = &CLASS sony_load_raw; } else if (!strncmp(make,"Sony",4) && raw_width == 3984) { width = 3925; order = 0x4d4d; } else if (!strncmp(make,"Sony",4) && raw_width == 4288) { width -= 32; } else if (!strcmp(make, "Sony") && raw_width == 4600) { if (!strcmp(model, "DSLR-A350")) height -= 4; black = 0; } else if (!strncmp(make,"Sony",4) && raw_width == 4928) { if (height < 3280) width -= 8; } else if (!strncmp(make,"Sony",4) && raw_width == 5504) { // ILCE-3000//5000 width -= height > 3664 ? 8 : 32; } else if (!strncmp(make,"Sony",4) && raw_width == 6048) { width -= 24; if (strstr(model,"RX1") || strstr(model,"A99")) width -= 6; } else if (!strncmp(make,"Sony",4) && raw_width == 7392) { width -= 30; } else if (!strncmp(make,"Sony",4) && raw_width == 8000) { width -= 32; if (!strncmp(model, "DSC", 3)) { tiff_bps = 14; load_raw = &CLASS unpacked_load_raw; } } else if (!strcmp(model,"DSLR-A100")) { if (width == 3880) { height--; width = ++raw_width; } else { height -= 4; width -= 4; order = 0x4d4d; load_flags = 2; } filters = 0x61616161; } else if (!strcmp(model,"PIXL")) { height -= top_margin = 4; width -= left_margin = 32; gamma_curve (0, 7, 1, 255); } else if (!strcmp(model,"C603") || !strcmp(model,"C330") || !strcmp(model,"12MP")) { order = 0x4949; if (filters && data_offset) { fseek (ifp, data_offset < 4096 ? 168 : 5252, SEEK_SET); read_shorts (curve, 256); } else gamma_curve (0, 3.875, 1, 255); load_raw = filters ? &CLASS eight_bit_load_raw : strcmp(model,"C330") ? &CLASS kodak_c603_load_raw : &CLASS kodak_c330_load_raw; load_flags = tiff_bps > 16; tiff_bps = 8; } else if (!strncasecmp(model,"EasyShare",9)) { data_offset = data_offset < 0x15000 ? 0x15000 : 0x17000; load_raw = &CLASS packed_load_raw; } else if (!strncasecmp(make,"Kodak",5)) { if (filters == UINT_MAX) filters = 0x61616161; if (!strncmp(model,"NC2000",6) || !strncmp(model,"EOSDCS",6) || !strncmp(model,"DCS4",4)) { width -= 4; left_margin = 2; if (model[6] == ' ') model[6] = 0; if (!strcmp(model,"DCS460A")) goto bw; } else if (!strcmp(model,"DCS660M")) { black = 214; goto bw; } else if (!strcmp(model,"DCS760M")) { bw: colors = 1; filters = 0; } if (!strcmp(model+4,"20X")) strcpy (cdesc, "MYCY"); if (strstr(model,"DC25")) { strcpy (model, "DC25"); data_offset = 15424; } if (!strncmp(model,"DC2",3)) { raw_height = 2 + (height = 242); if (!strncmp(model, "DC290", 5)) iso_speed = 100; if (!strncmp(model, "DC280", 5)) iso_speed = 70; if (flen < 100000) { raw_width = 256; width = 249; pixel_aspect = (4.0*height) / (3.0*width); } else { raw_width = 512; width = 501; pixel_aspect = (493.0*height) / (373.0*width); } top_margin = left_margin = 1; colors = 4; filters = 0x8d8d8d8d; simple_coeff(1); pre_mul[1] = 1.179; pre_mul[2] = 1.209; pre_mul[3] = 1.036; load_raw = &CLASS eight_bit_load_raw; } else if (!strcmp(model,"40")) { strcpy (model, "DC40"); height = 512; width = 768; data_offset = 1152; load_raw = &CLASS kodak_radc_load_raw; tiff_bps = 12; } else if (strstr(model,"DC50")) { strcpy (model, "DC50"); height = 512; width = 768; iso_speed=84; data_offset = 19712; load_raw = &CLASS kodak_radc_load_raw; } else if (strstr(model,"DC120")) { strcpy (model, "DC120"); height = 976; width = 848; iso_speed=160; pixel_aspect = height/0.75/width; load_raw = tiff_compress == 7 ? &CLASS kodak_jpeg_load_raw : &CLASS kodak_dc120_load_raw; } else if (!strcmp(model,"DCS200")) { thumb_height = 128; thumb_width = 192; thumb_offset = 6144; thumb_misc = 360; iso_speed=140; write_thumb = &CLASS layer_thumb; black = 17; } } else if (!strcmp(model,"Fotoman Pixtura")) { height = 512; width = 768; data_offset = 3632; load_raw = &CLASS kodak_radc_load_raw; filters = 0x61616161; simple_coeff(2); } else if (!strncmp(model,"QuickTake",9)) { if (head[5]) strcpy (model+10, "200"); fseek (ifp, 544, SEEK_SET); height = get2(); width = get2(); data_offset = (get4(),get2()) == 30 ? 738:736; if (height > width) { SWAP(height,width); fseek (ifp, data_offset-6, SEEK_SET); flip = ~get2() & 3 ? 5:6; } filters = 0x61616161; } else if (!strncmp(make,"Rollei",6) && !load_raw) { switch (raw_width) { case 1316: height = 1030; width = 1300; top_margin = 1; left_margin = 6; break; case 2568: height = 1960; width = 2560; top_margin = 2; left_margin = 8; } filters = 0x16161616; load_raw = &CLASS rollei_load_raw; } else if (!strcmp(model,"GRAS-50S5C")) { height = 2048; width = 2440; load_raw = &CLASS unpacked_load_raw; data_offset = 0; filters = 0x49494949; order = 0x4949; maximum = 0xfffC; } else if (!strcmp(model,"BB-500CL")) { height = 2058; width = 2448; load_raw = &CLASS unpacked_load_raw; data_offset = 0; filters = 0x94949494; order = 0x4949; maximum = 0x3fff; } else if (!strcmp(model,"BB-500GE")) { height = 2058; width = 2456; load_raw = &CLASS unpacked_load_raw; data_offset = 0; filters = 0x94949494; order = 0x4949; maximum = 0x3fff; } else if (!strcmp(model,"SVS625CL")) { height = 2050; width = 2448; load_raw = &CLASS unpacked_load_raw; data_offset = 0; filters = 0x94949494; order = 0x4949; maximum = 0x0fff; } /* Early reject for damaged images */ if (!load_raw || height < 22 || width < 22 || #ifdef LIBRAW_LIBRARY_BUILD (tiff_bps > 16 && load_raw != &LibRaw::deflate_dng_load_raw) #else tiff_bps > 16 #endif || tiff_samples > 4 || colors > 4 || colors < 1 /* alloc in unpack() may be fooled by size adjust */ || ( (int)width + (int)left_margin > 65535) || ( (int)height + (int)top_margin > 65535) ) { is_raw = 0; #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_IDENTIFY,1,2); #endif return; } if (!model[0]) sprintf (model, "%dx%d", width, height); if (filters == UINT_MAX) filters = 0x94949494; if (thumb_offset && !thumb_height) { fseek (ifp, thumb_offset, SEEK_SET); if (ljpeg_start (&jh, 1)) { thumb_width = jh.wide; thumb_height = jh.high; } } dng_skip: #ifdef LIBRAW_LIBRARY_BUILD if(dng_version) /* Override black level by DNG tags */ { black = imgdata.color.dng_levels.dng_black; int ll = LIM(0, (sizeof(cblack)/sizeof(cblack[0])), (sizeof(imgdata.color.dng_levels.dng_cblack)/sizeof(imgdata.color.dng_levels.dng_cblack[0]))); for(int i=0; i < ll; i++) cblack[i] = imgdata.color.dng_levels.dng_cblack[i]; } #endif /* Early reject for damaged images */ if (!load_raw || height < 22 || width < 22 || #ifdef LIBRAW_LIBRARY_BUILD (tiff_bps > 16 && load_raw != &LibRaw::deflate_dng_load_raw) #else tiff_bps > 16 #endif || tiff_samples > 4 || colors > 4 || colors < 1) { is_raw = 0; #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_IDENTIFY,1,2); #endif return; } if ((use_camera_matrix & ((use_camera_wb || dng_version) | 0x2) ) && cmatrix[0][0] > 0.125) { memcpy (rgb_cam, cmatrix, sizeof cmatrix); raw_color = 0; } if (raw_color) adobe_coeff (make, model); #ifdef LIBRAW_LIBRARY_BUILD else if(imgdata.color.cam_xyz[0][0]<0.01) adobe_coeff (make, model,1); #endif if (load_raw == &CLASS kodak_radc_load_raw) if (raw_color) adobe_coeff ("Apple","Quicktake"); #ifdef LIBRAW_LIBRARY_BUILD // Clear erorneus fuji_width if not set through parse_fuji or for DNG if(fuji_width && !dng_version && !(imgdata.process_warnings & LIBRAW_WARN_PARSEFUJI_PROCESSED )) fuji_width = 0; #endif if (fuji_width) { fuji_width = width >> !fuji_layout; filters = fuji_width & 1 ? 0x94949494 : 0x49494949; width = (height >> fuji_layout) + fuji_width; height = width - 1; pixel_aspect = 1; } else { if (raw_height < height) raw_height = height; if (raw_width < width ) raw_width = width; } if (!tiff_bps) tiff_bps = 12; if (!maximum) { maximum = (1 << tiff_bps) - 1; if(maximum < 0x10000 && curve[maximum]>0 && load_raw == &CLASS sony_arw2_load_raw) maximum = curve[maximum]; } if (!load_raw || height < 22 || width < 22 || #ifdef LIBRAW_LIBRARY_BUILD (tiff_bps > 16 && load_raw != &LibRaw::deflate_dng_load_raw) #else tiff_bps > 16 #endif || tiff_samples > 6 || colors > 4) is_raw = 0; if(raw_width < 22 || raw_width > 64000 || raw_height < 22 || raw_width > 64000) is_raw = 0; #ifdef NO_JASPER if (load_raw == &CLASS redcine_load_raw) { #ifdef DCRAW_VERBOSE fprintf (stderr,_("%s: You must link dcraw with %s!!\n"), ifname, "libjasper"); #endif is_raw = 0; #ifdef LIBRAW_LIBRARY_BUILD imgdata.process_warnings |= LIBRAW_WARN_NO_JASPER; #endif } #endif #ifdef NO_JPEG if (load_raw == &CLASS kodak_jpeg_load_raw || load_raw == &CLASS lossy_dng_load_raw) { #ifdef DCRAW_VERBOSE fprintf (stderr,_("%s: You must link dcraw with %s!!\n"), ifname, "libjpeg"); #endif is_raw = 0; #ifdef LIBRAW_LIBRARY_BUILD imgdata.process_warnings |= LIBRAW_WARN_NO_JPEGLIB; #endif } #endif if (!cdesc[0]) strcpy (cdesc, colors == 3 ? "RGBG":"GMCY"); if (!raw_height) raw_height = height; if (!raw_width ) raw_width = width; if (filters > 999 && colors == 3) filters |= ((filters >> 2 & 0x22222222) | (filters << 2 & 0x88888888)) & filters << 1; notraw: if (flip == UINT_MAX) flip = tiff_flip; if (flip == UINT_MAX) flip = 0; // Convert from degrees to bit-field if needed if(flip > 89 || flip < -89) { switch ((flip+3600) % 360) { case 270: flip = 5; break; case 180: flip = 3; break; case 90: flip = 6; break; } } #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_IDENTIFY,1,2); #endif } //@end COMMON //@out FILEIO #ifndef NO_LCMS void CLASS apply_profile (const char *input, const char *output) { char *prof; cmsHPROFILE hInProfile=0, hOutProfile=0; cmsHTRANSFORM hTransform; FILE *fp; unsigned size; if (strcmp (input, "embed")) hInProfile = cmsOpenProfileFromFile (input, "r"); else if (profile_length) { #ifndef LIBRAW_LIBRARY_BUILD prof = (char *) malloc (profile_length); merror (prof, "apply_profile()"); fseek (ifp, profile_offset, SEEK_SET); fread (prof, 1, profile_length, ifp); hInProfile = cmsOpenProfileFromMem (prof, profile_length); free (prof); #else hInProfile = cmsOpenProfileFromMem (imgdata.color.profile, profile_length); #endif } else { #ifdef LIBRAW_LIBRARY_BUILD imgdata.process_warnings |= LIBRAW_WARN_NO_EMBEDDED_PROFILE; #endif #ifdef DCRAW_VERBOSE fprintf (stderr,_("%s has no embedded profile.\n"), ifname); #endif } if (!hInProfile) { #ifdef LIBRAW_LIBRARY_BUILD imgdata.process_warnings |= LIBRAW_WARN_NO_INPUT_PROFILE; #endif return; } if (!output) hOutProfile = cmsCreate_sRGBProfile(); else if ((fp = fopen (output, "rb"))) { fread (&size, 4, 1, fp); fseek (fp, 0, SEEK_SET); oprof = (unsigned *) malloc (size = ntohl(size)); merror (oprof, "apply_profile()"); fread (oprof, 1, size, fp); fclose (fp); if (!(hOutProfile = cmsOpenProfileFromMem (oprof, size))) { free (oprof); oprof = 0; } } #ifdef DCRAW_VERBOSE else fprintf (stderr,_("Cannot open file %s!\n"), output); #endif if (!hOutProfile) { #ifdef LIBRAW_LIBRARY_BUILD imgdata.process_warnings |= LIBRAW_WARN_BAD_OUTPUT_PROFILE; #endif goto quit; } #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("Applying color profile...\n")); #endif #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_APPLY_PROFILE,0,2); #endif hTransform = cmsCreateTransform (hInProfile, TYPE_RGBA_16, hOutProfile, TYPE_RGBA_16, INTENT_PERCEPTUAL, 0); cmsDoTransform (hTransform, image, image, width*height); raw_color = 1; /* Don't use rgb_cam with a profile */ cmsDeleteTransform (hTransform); cmsCloseProfile (hOutProfile); quit: cmsCloseProfile (hInProfile); #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_APPLY_PROFILE,1,2); #endif } #endif //@end FILEIO //@out COMMON void CLASS convert_to_rgb() { #ifndef LIBRAW_LIBRARY_BUILD int row, col, c; #endif int i, j, k; #ifndef LIBRAW_LIBRARY_BUILD ushort *img; float out[3]; #endif float out_cam[3][4]; double num, inverse[3][3]; static const double xyzd50_srgb[3][3] = { { 0.436083, 0.385083, 0.143055 }, { 0.222507, 0.716888, 0.060608 }, { 0.013930, 0.097097, 0.714022 } }; static const double rgb_rgb[3][3] = { { 1,0,0 }, { 0,1,0 }, { 0,0,1 } }; static const double adobe_rgb[3][3] = { { 0.715146, 0.284856, 0.000000 }, { 0.000000, 1.000000, 0.000000 }, { 0.000000, 0.041166, 0.958839 } }; static const double wide_rgb[3][3] = { { 0.593087, 0.404710, 0.002206 }, { 0.095413, 0.843149, 0.061439 }, { 0.011621, 0.069091, 0.919288 } }; static const double prophoto_rgb[3][3] = { { 0.529317, 0.330092, 0.140588 }, { 0.098368, 0.873465, 0.028169 }, { 0.016879, 0.117663, 0.865457 } }; static const double aces_rgb[3][3] = { { 0.432996, 0.375380, 0.189317 }, { 0.089427, 0.816523, 0.102989 }, { 0.019165, 0.118150, 0.941914 } }; static const double (*out_rgb[])[3] = { rgb_rgb, adobe_rgb, wide_rgb, prophoto_rgb, xyz_rgb, aces_rgb }; static const char *name[] = { "sRGB", "Adobe RGB (1998)", "WideGamut D65", "ProPhoto D65", "XYZ", "ACES" }; static const unsigned phead[] = { 1024, 0, 0x2100000, 0x6d6e7472, 0x52474220, 0x58595a20, 0, 0, 0, 0x61637370, 0, 0, 0x6e6f6e65, 0, 0, 0, 0, 0xf6d6, 0x10000, 0xd32d }; unsigned pbody[] = { 10, 0x63707274, 0, 36, /* cprt */ 0x64657363, 0, 40, /* desc */ 0x77747074, 0, 20, /* wtpt */ 0x626b7074, 0, 20, /* bkpt */ 0x72545243, 0, 14, /* rTRC */ 0x67545243, 0, 14, /* gTRC */ 0x62545243, 0, 14, /* bTRC */ 0x7258595a, 0, 20, /* rXYZ */ 0x6758595a, 0, 20, /* gXYZ */ 0x6258595a, 0, 20 }; /* bXYZ */ static const unsigned pwhite[] = { 0xf351, 0x10000, 0x116cc }; unsigned pcurve[] = { 0x63757276, 0, 1, 0x1000000 }; #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_CONVERT_RGB,0,2); #endif gamma_curve (gamm[0], gamm[1], 0, 0); memcpy (out_cam, rgb_cam, sizeof out_cam); #ifndef LIBRAW_LIBRARY_BUILD raw_color |= colors == 1 || document_mode || output_color < 1 || output_color > 6; #else raw_color |= colors == 1 || output_color < 1 || output_color > 6; #endif if (!raw_color) { oprof = (unsigned *) calloc (phead[0], 1); merror (oprof, "convert_to_rgb()"); memcpy (oprof, phead, sizeof phead); if (output_color == 5) oprof[4] = oprof[5]; oprof[0] = 132 + 12*pbody[0]; for (i=0; i < pbody[0]; i++) { oprof[oprof[0]/4] = i ? (i > 1 ? 0x58595a20 : 0x64657363) : 0x74657874; pbody[i*3+2] = oprof[0]; oprof[0] += (pbody[i*3+3] + 3) & -4; } memcpy (oprof+32, pbody, sizeof pbody); oprof[pbody[5]/4+2] = strlen(name[output_color-1]) + 1; memcpy ((char *)oprof+pbody[8]+8, pwhite, sizeof pwhite); pcurve[3] = (short)(256/gamm[5]+0.5) << 16; for (i=4; i < 7; i++) memcpy ((char *)oprof+pbody[i*3+2], pcurve, sizeof pcurve); pseudoinverse ((double (*)[3]) out_rgb[output_color-1], inverse, 3); for (i=0; i < 3; i++) for (j=0; j < 3; j++) { for (num = k=0; k < 3; k++) num += xyzd50_srgb[i][k] * inverse[j][k]; oprof[pbody[j*3+23]/4+i+2] = num * 0x10000 + 0.5; } for (i=0; i < phead[0]/4; i++) oprof[i] = htonl(oprof[i]); strcpy ((char *)oprof+pbody[2]+8, "auto-generated by dcraw"); strcpy ((char *)oprof+pbody[5]+12, name[output_color-1]); for (i=0; i < 3; i++) for (j=0; j < colors; j++) for (out_cam[i][j] = k=0; k < 3; k++) out_cam[i][j] += out_rgb[output_color-1][i][k] * rgb_cam[k][j]; } #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr, raw_color ? _("Building histograms...\n") : _("Converting to %s colorspace...\n"), name[output_color-1]); #endif #ifdef LIBRAW_LIBRARY_BUILD convert_to_rgb_loop(out_cam); #else memset (histogram, 0, sizeof histogram); for (img=image[0], row=0; row < height; row++) for (col=0; col < width; col++, img+=4) { if (!raw_color) { out[0] = out[1] = out[2] = 0; FORCC { out[0] += out_cam[0][c] * img[c]; out[1] += out_cam[1][c] * img[c]; out[2] += out_cam[2][c] * img[c]; } FORC3 img[c] = CLIP((int) out[c]); } else if (document_mode) img[0] = img[fcol(row,col)]; FORCC histogram[c][img[c] >> 3]++; } #endif if (colors == 4 && output_color) colors = 3; #ifndef LIBRAW_LIBRARY_BUILD if (document_mode && filters) colors = 1; #endif #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_CONVERT_RGB,1,2); #endif } void CLASS fuji_rotate() { int i, row, col; double step; float r, c, fr, fc; unsigned ur, uc; ushort wide, high, (*img)[4], (*pix)[4]; if (!fuji_width) return; #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("Rotating image 45 degrees...\n")); #endif fuji_width = (fuji_width - 1 + shrink) >> shrink; step = sqrt(0.5); wide = fuji_width / step; high = (height - fuji_width) / step; img = (ushort (*)[4]) calloc (high, wide*sizeof *img); merror (img, "fuji_rotate()"); #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_FUJI_ROTATE,0,2); #endif for (row=0; row < high; row++) for (col=0; col < wide; col++) { ur = r = fuji_width + (row-col)*step; uc = c = (row+col)*step; if (ur > height-2 || uc > width-2) continue; fr = r - ur; fc = c - uc; pix = image + ur*width + uc; for (i=0; i < colors; i++) img[row*wide+col][i] = (pix[ 0][i]*(1-fc) + pix[ 1][i]*fc) * (1-fr) + (pix[width][i]*(1-fc) + pix[width+1][i]*fc) * fr; } free (image); width = wide; height = high; image = img; fuji_width = 0; #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_FUJI_ROTATE,1,2); #endif } void CLASS stretch() { ushort newdim, (*img)[4], *pix0, *pix1; int row, col, c; double rc, frac; if (pixel_aspect == 1) return; #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_STRETCH,0,2); #endif #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("Stretching the image...\n")); #endif if (pixel_aspect < 1) { newdim = height / pixel_aspect + 0.5; img = (ushort (*)[4]) calloc (width, newdim*sizeof *img); merror (img, "stretch()"); for (rc=row=0; row < newdim; row++, rc+=pixel_aspect) { frac = rc - (c = rc); pix0 = pix1 = image[c*width]; if (c+1 < height) pix1 += width*4; for (col=0; col < width; col++, pix0+=4, pix1+=4) FORCC img[row*width+col][c] = pix0[c]*(1-frac) + pix1[c]*frac + 0.5; } height = newdim; } else { newdim = width * pixel_aspect + 0.5; img = (ushort (*)[4]) calloc (height, newdim*sizeof *img); merror (img, "stretch()"); for (rc=col=0; col < newdim; col++, rc+=1/pixel_aspect) { frac = rc - (c = rc); pix0 = pix1 = image[c]; if (c+1 < width) pix1 += 4; for (row=0; row < height; row++, pix0+=width*4, pix1+=width*4) FORCC img[row*newdim+col][c] = pix0[c]*(1-frac) + pix1[c]*frac + 0.5; } width = newdim; } free (image); image = img; #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_STRETCH,1,2); #endif } int CLASS flip_index (int row, int col) { if (flip & 4) SWAP(row,col); if (flip & 2) row = iheight - 1 - row; if (flip & 1) col = iwidth - 1 - col; return row * iwidth + col; } //@end COMMON struct tiff_tag { ushort tag, type; int count; union { char c[4]; short s[2]; int i; } val; }; struct tiff_hdr { ushort t_order, magic; int ifd; ushort pad, ntag; struct tiff_tag tag[23]; int nextifd; ushort pad2, nexif; struct tiff_tag exif[4]; ushort pad3, ngps; struct tiff_tag gpst[10]; short bps[4]; int rat[10]; unsigned gps[26]; char t_desc[512], t_make[64], t_model[64], soft[32], date[20], t_artist[64]; }; //@out COMMON void CLASS tiff_set (struct tiff_hdr *th, ushort *ntag, ushort tag, ushort type, int count, int val) { struct tiff_tag *tt; int c; tt = (struct tiff_tag *)(ntag+1) + (*ntag)++; tt->val.i = val; if (type == 1 && count <= 4) FORC(4) tt->val.c[c] = val >> (c << 3); else if (type == 2) { count = strnlen((char *)th + val, count-1) + 1; if (count <= 4) FORC(4) tt->val.c[c] = ((char *)th)[val+c]; } else if (type == 3 && count <= 2) FORC(2) tt->val.s[c] = val >> (c << 4); tt->count = count; tt->type = type; tt->tag = tag; } #define TOFF(ptr) ((char *)(&(ptr)) - (char *)th) void CLASS tiff_head (struct tiff_hdr *th, int full) { int c, psize=0; struct tm *t; memset (th, 0, sizeof *th); th->t_order = htonl(0x4d4d4949) >> 16; th->magic = 42; th->ifd = 10; th->rat[0] = th->rat[2] = 300; th->rat[1] = th->rat[3] = 1; FORC(6) th->rat[4+c] = 1000000; th->rat[4] *= shutter; th->rat[6] *= aperture; th->rat[8] *= focal_len; strncpy (th->t_desc, desc, 512); strncpy (th->t_make, make, 64); strncpy (th->t_model, model, 64); strcpy (th->soft, "dcraw v" DCRAW_VERSION); t = localtime (×tamp); sprintf (th->date, "%04d:%02d:%02d %02d:%02d:%02d", t->tm_year+1900,t->tm_mon+1,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec); strncpy (th->t_artist, artist, 64); if (full) { tiff_set (th, &th->ntag, 254, 4, 1, 0); tiff_set (th, &th->ntag, 256, 4, 1, width); tiff_set (th, &th->ntag, 257, 4, 1, height); tiff_set (th, &th->ntag, 258, 3, colors, output_bps); if (colors > 2) th->tag[th->ntag-1].val.i = TOFF(th->bps); FORC4 th->bps[c] = output_bps; tiff_set (th, &th->ntag, 259, 3, 1, 1); tiff_set (th, &th->ntag, 262, 3, 1, 1 + (colors > 1)); } tiff_set (th, &th->ntag, 270, 2, 512, TOFF(th->t_desc)); tiff_set (th, &th->ntag, 271, 2, 64, TOFF(th->t_make)); tiff_set (th, &th->ntag, 272, 2, 64, TOFF(th->t_model)); if (full) { if (oprof) psize = ntohl(oprof[0]); tiff_set (th, &th->ntag, 273, 4, 1, sizeof *th + psize); tiff_set (th, &th->ntag, 277, 3, 1, colors); tiff_set (th, &th->ntag, 278, 4, 1, height); tiff_set (th, &th->ntag, 279, 4, 1, height*width*colors*output_bps/8); } else tiff_set (th, &th->ntag, 274, 3, 1, "12435867"[flip]-'0'); tiff_set (th, &th->ntag, 282, 5, 1, TOFF(th->rat[0])); tiff_set (th, &th->ntag, 283, 5, 1, TOFF(th->rat[2])); tiff_set (th, &th->ntag, 284, 3, 1, 1); tiff_set (th, &th->ntag, 296, 3, 1, 2); tiff_set (th, &th->ntag, 305, 2, 32, TOFF(th->soft)); tiff_set (th, &th->ntag, 306, 2, 20, TOFF(th->date)); tiff_set (th, &th->ntag, 315, 2, 64, TOFF(th->t_artist)); tiff_set (th, &th->ntag, 34665, 4, 1, TOFF(th->nexif)); if (psize) tiff_set (th, &th->ntag, 34675, 7, psize, sizeof *th); tiff_set (th, &th->nexif, 33434, 5, 1, TOFF(th->rat[4])); tiff_set (th, &th->nexif, 33437, 5, 1, TOFF(th->rat[6])); tiff_set (th, &th->nexif, 34855, 3, 1, iso_speed); tiff_set (th, &th->nexif, 37386, 5, 1, TOFF(th->rat[8])); if (gpsdata[1]) { tiff_set (th, &th->ntag, 34853, 4, 1, TOFF(th->ngps)); tiff_set (th, &th->ngps, 0, 1, 4, 0x202); tiff_set (th, &th->ngps, 1, 2, 2, gpsdata[29]); tiff_set (th, &th->ngps, 2, 5, 3, TOFF(th->gps[0])); tiff_set (th, &th->ngps, 3, 2, 2, gpsdata[30]); tiff_set (th, &th->ngps, 4, 5, 3, TOFF(th->gps[6])); tiff_set (th, &th->ngps, 5, 1, 1, gpsdata[31]); tiff_set (th, &th->ngps, 6, 5, 1, TOFF(th->gps[18])); tiff_set (th, &th->ngps, 7, 5, 3, TOFF(th->gps[12])); tiff_set (th, &th->ngps, 18, 2, 12, TOFF(th->gps[20])); tiff_set (th, &th->ngps, 29, 2, 12, TOFF(th->gps[23])); memcpy (th->gps, gpsdata, sizeof th->gps); } } #ifdef LIBRAW_LIBRARY_BUILD void CLASS jpeg_thumb_writer (FILE *tfp,char *t_humb,int t_humb_length) { ushort exif[5]; struct tiff_hdr th; fputc (0xff, tfp); fputc (0xd8, tfp); if (strcmp (t_humb+6, "Exif")) { memcpy (exif, "\xff\xe1 Exif\0\0", 10); exif[1] = htons (8 + sizeof th); fwrite (exif, 1, sizeof exif, tfp); tiff_head (&th, 0); fwrite (&th, 1, sizeof th, tfp); } fwrite (t_humb+2, 1, t_humb_length-2, tfp); } void CLASS jpeg_thumb() { char *thumb; thumb = (char *) malloc (thumb_length); merror (thumb, "jpeg_thumb()"); fread (thumb, 1, thumb_length, ifp); jpeg_thumb_writer(ofp,thumb,thumb_length); free (thumb); } #else void CLASS jpeg_thumb() { char *thumb; ushort exif[5]; struct tiff_hdr th; thumb = (char *) malloc (thumb_length); merror (thumb, "jpeg_thumb()"); fread (thumb, 1, thumb_length, ifp); fputc (0xff, ofp); fputc (0xd8, ofp); if (strcmp (thumb+6, "Exif")) { memcpy (exif, "\xff\xe1 Exif\0\0", 10); exif[1] = htons (8 + sizeof th); fwrite (exif, 1, sizeof exif, ofp); tiff_head (&th, 0); fwrite (&th, 1, sizeof th, ofp); } fwrite (thumb+2, 1, thumb_length-2, ofp); free (thumb); } #endif void CLASS write_ppm_tiff() { struct tiff_hdr th; uchar *ppm; ushort *ppm2; int c, row, col, soff, rstep, cstep; int perc, val, total, t_white=0x2000; #ifdef LIBRAW_LIBRARY_BUILD perc = width * height * auto_bright_thr; #else perc = width * height * 0.01; /* 99th percentile white level */ #endif if (fuji_width) perc /= 2; if (!((highlight & ~2) || no_auto_bright)) for (t_white=c=0; c < colors; c++) { for (val=0x2000, total=0; --val > 32; ) if ((total += histogram[c][val]) > perc) break; if (t_white < val) t_white = val; } gamma_curve (gamm[0], gamm[1], 2, (t_white << 3)/bright); iheight = height; iwidth = width; if (flip & 4) SWAP(height,width); ppm = (uchar *) calloc (width, colors*output_bps/8); ppm2 = (ushort *) ppm; merror (ppm, "write_ppm_tiff()"); if (output_tiff) { tiff_head (&th, 1); fwrite (&th, sizeof th, 1, ofp); if (oprof) fwrite (oprof, ntohl(oprof[0]), 1, ofp); } else if (colors > 3) fprintf (ofp, "P7\nWIDTH %d\nHEIGHT %d\nDEPTH %d\nMAXVAL %d\nTUPLTYPE %s\nENDHDR\n", width, height, colors, (1 << output_bps)-1, cdesc); else fprintf (ofp, "P%d\n%d %d\n%d\n", colors/2+5, width, height, (1 << output_bps)-1); soff = flip_index (0, 0); cstep = flip_index (0, 1) - soff; rstep = flip_index (1, 0) - flip_index (0, width); for (row=0; row < height; row++, soff += rstep) { for (col=0; col < width; col++, soff += cstep) if (output_bps == 8) FORCC ppm [col*colors+c] = curve[image[soff][c]] >> 8; else FORCC ppm2[col*colors+c] = curve[image[soff][c]]; if (output_bps == 16 && !output_tiff && htons(0x55aa) != 0x55aa) swab ((char*)ppm2, (char*)ppm2, width*colors*2); fwrite (ppm, colors*output_bps/8, width, ofp); } free (ppm); } //@end COMMON int CLASS main (int argc, const char **argv) { int arg, status=0, quality, i, c; int timestamp_only=0, thumbnail_only=0, identify_only=0; int user_qual=-1, user_black=-1, user_sat=-1, user_flip=-1; int use_fuji_rotate=1, write_to_stdout=0, read_from_stdin=0; const char *sp, *bpfile=0, *dark_frame=0, *write_ext; char opm, opt, *ofname, *cp; struct utimbuf ut; #ifndef NO_LCMS const char *cam_profile=0, *out_profile=0; #endif #ifndef LOCALTIME putenv ((char *) "TZ=UTC"); #endif #ifdef LOCALEDIR setlocale (LC_CTYPE, ""); setlocale (LC_MESSAGES, ""); bindtextdomain ("dcraw", LOCALEDIR); textdomain ("dcraw"); #endif if (argc == 1) { printf(_("\nRaw photo decoder \"dcraw\" v%s"), DCRAW_VERSION); printf(_("\nby Dave Coffin, dcoffin a cybercom o net\n")); printf(_("\nUsage: %s [OPTION]... [FILE]...\n\n"), argv[0]); puts(_("-v Print verbose messages")); puts(_("-c Write image data to standard output")); puts(_("-e Extract embedded thumbnail image")); puts(_("-i Identify files without decoding them")); puts(_("-i -v Identify files and show metadata")); puts(_("-z Change file dates to camera timestamp")); puts(_("-w Use camera white balance, if possible")); puts(_("-a Average the whole image for white balance")); puts(_("-A Average a grey box for white balance")); puts(_("-r Set custom white balance")); puts(_("+M/-M Use/don't use an embedded color matrix")); puts(_("-C Correct chromatic aberration")); puts(_("-P Fix the dead pixels listed in this file")); puts(_("-K Subtract dark frame (16-bit raw PGM)")); puts(_("-k Set the darkness level")); puts(_("-S Set the saturation level")); puts(_("-n Set threshold for wavelet denoising")); puts(_("-H [0-9] Highlight mode (0=clip, 1=unclip, 2=blend, 3+=rebuild)")); puts(_("-t [0-7] Flip image (0=none, 3=180, 5=90CCW, 6=90CW)")); puts(_("-o [0-5] Output colorspace (raw,sRGB,Adobe,Wide,ProPhoto,XYZ)")); #ifndef NO_LCMS puts(_("-o Apply output ICC profile from file")); puts(_("-p Apply camera ICC profile from file or \"embed\"")); #endif puts(_("-d Document mode (no color, no interpolation)")); puts(_("-D Document mode without scaling (totally raw)")); puts(_("-j Don't stretch or rotate raw pixels")); puts(_("-W Don't automatically brighten the image")); puts(_("-b Adjust brightness (default = 1.0)")); puts(_("-g

Set custom gamma curve (default = 2.222 4.5)")); puts(_("-q [0-3] Set the interpolation quality")); puts(_("-h Half-size color image (twice as fast as \"-q 0\")")); puts(_("-f Interpolate RGGB as four colors")); puts(_("-m Apply a 3x3 median filter to R-G and B-G")); puts(_("-s [0..N-1] Select one raw image or \"all\" from each file")); puts(_("-6 Write 16-bit instead of 8-bit")); puts(_("-4 Linear 16-bit, same as \"-6 -W -g 1 1\"")); puts(_("-T Write TIFF instead of PPM")); puts(""); return 1; } argv[argc] = ""; for (arg=1; (((opm = argv[arg][0]) - 2) | 2) == '+'; ) { opt = argv[arg++][1]; if ((cp = (char *) strchr (sp="nbrkStqmHACg", opt))) for (i=0; i < "114111111422"[cp-sp]-'0'; i++) if (!isdigit(argv[arg+i][0])) { fprintf (stderr,_("Non-numeric argument to \"-%c\"\n"), opt); return 1; } switch (opt) { case 'n': threshold = atof(argv[arg++]); break; case 'b': bright = atof(argv[arg++]); break; case 'r': FORC4 user_mul[c] = atof(argv[arg++]); break; case 'C': aber[0] = 1 / atof(argv[arg++]); aber[2] = 1 / atof(argv[arg++]); break; case 'g': gamm[0] = atof(argv[arg++]); gamm[1] = atof(argv[arg++]); if (gamm[0]) gamm[0] = 1/gamm[0]; break; case 'k': user_black = atoi(argv[arg++]); break; case 'S': user_sat = atoi(argv[arg++]); break; case 't': user_flip = atoi(argv[arg++]); break; case 'q': user_qual = atoi(argv[arg++]); break; case 'm': med_passes = atoi(argv[arg++]); break; case 'H': highlight = atoi(argv[arg++]); break; case 's': shot_select = abs(atoi(argv[arg])); multi_out = !strcmp(argv[arg++],"all"); break; case 'o': if (isdigit(argv[arg][0]) && !argv[arg][1]) output_color = atoi(argv[arg++]); #ifndef NO_LCMS else out_profile = argv[arg++]; break; case 'p': cam_profile = argv[arg++]; #endif break; case 'P': bpfile = argv[arg++]; break; case 'K': dark_frame = argv[arg++]; break; case 'z': timestamp_only = 1; break; case 'e': thumbnail_only = 1; break; case 'i': identify_only = 1; break; case 'c': write_to_stdout = 1; break; case 'v': verbose = 1; break; case 'h': half_size = 1; break; case 'f': four_color_rgb = 1; break; case 'A': FORC4 greybox[c] = atoi(argv[arg++]); case 'a': use_auto_wb = 1; break; case 'w': use_camera_wb = 1; break; case 'M': use_camera_matrix = 3 * (opm == '+'); break; case 'I': read_from_stdin = 1; break; case 'E': document_mode++; case 'D': document_mode++; case 'd': document_mode++; case 'j': use_fuji_rotate = 0; break; case 'W': no_auto_bright = 1; break; case 'T': output_tiff = 1; break; case '4': gamm[0] = gamm[1] = no_auto_bright = 1; case '6': output_bps = 16; break; default: fprintf (stderr,_("Unknown option \"-%c\".\n"), opt); return 1; } } if (arg == argc) { fprintf (stderr,_("No files to process.\n")); return 1; } if (write_to_stdout) { if (isatty(1)) { fprintf (stderr,_("Will not write an image to the terminal!\n")); return 1; } #if defined(WIN32) || defined(DJGPP) || defined(__CYGWIN__) if (setmode(1,O_BINARY) < 0) { perror ("setmode()"); return 1; } #endif } for ( ; arg < argc; arg++) { status = 1; raw_image = 0; image = 0; oprof = 0; meta_data = ofname = 0; ofp = stdout; if (setjmp (failure)) { if (fileno(ifp) > 2) fclose(ifp); if (fileno(ofp) > 2) fclose(ofp); status = 1; goto cleanup; } ifname = argv[arg]; if (!(ifp = fopen (ifname, "rb"))) { perror (ifname); continue; } status = (identify(),!is_raw); if (user_flip >= 0) flip = user_flip; switch ((flip+3600) % 360) { case 270: flip = 5; break; case 180: flip = 3; break; case 90: flip = 6; } if (timestamp_only) { if ((status = !timestamp)) fprintf (stderr,_("%s has no timestamp.\n"), ifname); else if (identify_only) printf ("%10ld%10d %s\n", (long) timestamp, shot_order, ifname); else { if (verbose) fprintf (stderr,_("%s time set to %d.\n"), ifname, (int) timestamp); ut.actime = ut.modtime = timestamp; utime (ifname, &ut); } goto next; } write_fun = &CLASS write_ppm_tiff; if (thumbnail_only) { if ((status = !thumb_offset)) { fprintf (stderr,_("%s has no thumbnail.\n"), ifname); goto next; } else if (thumb_load_raw) { load_raw = thumb_load_raw; data_offset = thumb_offset; height = thumb_height; width = thumb_width; filters = 0; colors = 3; } else { fseek (ifp, thumb_offset, SEEK_SET); write_fun = write_thumb; goto thumbnail; } } if (load_raw == &CLASS kodak_ycbcr_load_raw) { height += height & 1; width += width & 1; } if (identify_only && verbose && make[0]) { printf (_("\nFilename: %s\n"), ifname); printf (_("Timestamp: %s"), ctime(×tamp)); printf (_("Camera: %s %s\n"), make, model); if (artist[0]) printf (_("Owner: %s\n"), artist); if (dng_version) { printf (_("DNG Version: ")); for (i=24; i >= 0; i -= 8) printf ("%d%c", dng_version >> i & 255, i ? '.':'\n'); } printf (_("ISO speed: %d\n"), (int) iso_speed); printf (_("Shutter: ")); if (shutter > 0 && shutter < 1) shutter = (printf ("1/"), 1 / shutter); printf (_("%0.1f sec\n"), shutter); printf (_("Aperture: f/%0.1f\n"), aperture); printf (_("Focal length: %0.1f mm\n"), focal_len); printf (_("Embedded ICC profile: %s\n"), profile_length ? _("yes"):_("no")); printf (_("Number of raw images: %d\n"), is_raw); if (pixel_aspect != 1) printf (_("Pixel Aspect Ratio: %0.6f\n"), pixel_aspect); if (thumb_offset) printf (_("Thumb size: %4d x %d\n"), thumb_width, thumb_height); printf (_("Full size: %4d x %d\n"), raw_width, raw_height); } else if (!is_raw) fprintf (stderr,_("Cannot decode file %s\n"), ifname); if (!is_raw) goto next; shrink = filters && (half_size || (!identify_only && (threshold || aber[0] != 1 || aber[2] != 1))); iheight = (height + shrink) >> shrink; iwidth = (width + shrink) >> shrink; if (identify_only) { if (verbose) { if (document_mode == 3) { top_margin = left_margin = fuji_width = 0; height = raw_height; width = raw_width; } iheight = (height + shrink) >> shrink; iwidth = (width + shrink) >> shrink; if (use_fuji_rotate) { if (fuji_width) { fuji_width = (fuji_width - 1 + shrink) >> shrink; iwidth = fuji_width / sqrt(0.5); iheight = (iheight - fuji_width) / sqrt(0.5); } else { if (pixel_aspect < 1) iheight = iheight / pixel_aspect + 0.5; if (pixel_aspect > 1) iwidth = iwidth * pixel_aspect + 0.5; } } if (flip & 4) SWAP(iheight,iwidth); printf (_("Image size: %4d x %d\n"), width, height); printf (_("Output size: %4d x %d\n"), iwidth, iheight); printf (_("Raw colors: %d"), colors); if (filters) { int fhigh = 2, fwide = 2; if ((filters ^ (filters >> 8)) & 0xff) fhigh = 4; if ((filters ^ (filters >> 16)) & 0xffff) fhigh = 8; if (filters == 1) fhigh = fwide = 16; if (filters == 9) fhigh = fwide = 6; printf (_("\nFilter pattern: ")); for (i=0; i < fhigh; i++) for (c = i && putchar('/') && 0; c < fwide; c++) putchar (cdesc[fcol(i,c)]); } printf (_("\nDaylight multipliers:")); FORCC printf (" %f", pre_mul[c]); if (cam_mul[0] > 0) { printf (_("\nCamera multipliers:")); FORC4 printf (" %f", cam_mul[c]); } putchar ('\n'); } else printf (_("%s is a %s %s image.\n"), ifname, make, model); next: fclose(ifp); continue; } if (meta_length) { meta_data = (char *) malloc (meta_length); merror (meta_data, "main()"); } if (filters || colors == 1) { raw_image = (ushort *) calloc ((raw_height+7), raw_width*2); merror (raw_image, "main()"); } else { image = (ushort (*)[4]) calloc (iheight, iwidth*sizeof *image); merror (image, "main()"); } if (verbose) fprintf (stderr,_("Loading %s %s image from %s ...\n"), make, model, ifname); if (shot_select >= is_raw) fprintf (stderr,_("%s: \"-s %d\" requests a nonexistent image!\n"), ifname, shot_select); fseeko (ifp, data_offset, SEEK_SET); if (raw_image && read_from_stdin) fread (raw_image, 2, raw_height*raw_width, stdin); else (*load_raw)(); if (document_mode == 3) { top_margin = left_margin = fuji_width = 0; height = raw_height; width = raw_width; } iheight = (height + shrink) >> shrink; iwidth = (width + shrink) >> shrink; if (raw_image) { image = (ushort (*)[4]) calloc (iheight, iwidth*sizeof *image); merror (image, "main()"); crop_masked_pixels(); free (raw_image); } if (zero_is_bad) remove_zeroes(); bad_pixels (bpfile); if (dark_frame) subtract (dark_frame); quality = 2 + !fuji_width; if (user_qual >= 0) quality = user_qual; i = cblack[3]; FORC3 if (i > cblack[c]) i = cblack[c]; FORC4 cblack[c] -= i; black += i; i = cblack[6]; FORC (cblack[4] * cblack[5]) if (i > cblack[6+c]) i = cblack[6+c]; FORC (cblack[4] * cblack[5]) cblack[6+c] -= i; black += i; if (user_black >= 0) black = user_black; FORC4 cblack[c] += black; if (user_sat > 0) maximum = user_sat; #ifdef COLORCHECK colorcheck(); #endif if (is_foveon) { if (document_mode || load_raw == &CLASS foveon_dp_load_raw) { for (i=0; i < height*width*4; i++) if ((short) image[0][i] < 0) image[0][i] = 0; } else foveon_interpolate(); } else if (document_mode < 2) scale_colors(); pre_interpolate(); if (filters && !document_mode) { if (quality == 0) lin_interpolate(); else if (quality == 1 || colors > 3) vng_interpolate(); else if (quality == 2 && filters > 1000) ppg_interpolate(); else if (filters == 9) xtrans_interpolate (quality*2-3); else ahd_interpolate(); } if (mix_green) for (colors=3, i=0; i < height*width; i++) image[i][1] = (image[i][1] + image[i][3]) >> 1; if (!is_foveon && colors == 3) median_filter(); if (!is_foveon && highlight == 2) blend_highlights(); if (!is_foveon && highlight > 2) recover_highlights(); if (use_fuji_rotate) fuji_rotate(); #ifndef NO_LCMS if (cam_profile) apply_profile (cam_profile, out_profile); #endif convert_to_rgb(); if (use_fuji_rotate) stretch(); thumbnail: if (write_fun == &CLASS jpeg_thumb) write_ext = ".jpg"; else if (output_tiff && write_fun == &CLASS write_ppm_tiff) write_ext = ".tiff"; else write_ext = ".pgm\0.ppm\0.ppm\0.pam" + colors*5-5; ofname = (char *) malloc (strlen(ifname) + 64); merror (ofname, "main()"); if (write_to_stdout) strcpy (ofname,_("standard output")); else { strcpy (ofname, ifname); if ((cp = strrchr (ofname, '.'))) *cp = 0; if (multi_out) sprintf (ofname+strlen(ofname), "_%0*d", snprintf(0,0,"%d",is_raw-1), shot_select); if (thumbnail_only) strcat (ofname, ".thumb"); strcat (ofname, write_ext); ofp = fopen (ofname, "wb"); if (!ofp) { status = 1; perror (ofname); goto cleanup; } } if (verbose) fprintf (stderr,_("Writing data to %s ...\n"), ofname); (*write_fun)(); fclose(ifp); if (ofp != stdout) fclose(ofp); cleanup: if (meta_data) free (meta_data); if (ofname) free (ofname); if (oprof) free (oprof); if (image) free (image); if (multi_out) { if (++shot_select < is_raw) arg--; else shot_select = 0; } } return status; } #endif LibRaw-0.18.8/doc/000077500000000000000000000000001324423227700135435ustar00rootroot00000000000000LibRaw-0.18.8/doc/API-C.html000077500000000000000000000216711324423227700152340ustar00rootroot00000000000000

LibRaw: C API[back to Index]

LibRaw: C API

LibRaw C API is a wrapper around C++ API; therefore, virtually all documentation to C API functions is represented by a set of hyperlinks to the corresponding places in the description of C++ API.

Contents

  1. Initialization: libraw_data_t *libraw_init(unsigned int flags);
  2. Returned values
  3. Data loading
  4. Parameters getters/setters
  5. Auxiliary Functions
  6. Data Postprocessing, Emulation of dcraw Behavior
  7. Writing to Output Files
  8. Writing processing results to memory buffer

Initialization: libraw_data_t *libraw_init(unsigned int flags);

The function returns the pointer to the instance of libraw_data_t structure.
The resultant pointer should be passed as the first argument to all C API functions (except for libraw_strerror).

Returns NULL in case of error, pointer to the structure in all other cases.

Returned values

Functions of C API return EINVAL (see errno.h) if the null pointer was passed to them as the first argument. In all other cases, the C++ API return code is returned.

Data Loading from a File

int libraw_open_file(libraw_data_t*, const char *)
int libraw_open_file_ex(libraw_data_t*, const char *,INT64 bigfile_size)
WIN32: int libraw_open_wfile(libraw_data_t*, const wchar_t *)
WIN32: int libraw_open_wfile_ex(libraw_data_t*, const wchar_t *,INT64 bigfile_size)
See LibRaw::open_file()
int libraw_open_buffer(libraw_data_t*, void *buffer, size_t bufsize)
See LibRaw::open_buffer()
int libraw_unpack(libraw_data_t*);
See LibRaw::unpack()
int libraw_unpack_thumb(libraw_data_t*);
See LibRaw::unpack_thumb()

Parameters setters/getters

These functions provides interface to imgdata.params, .sizes and .color fields which works regardless of LibRaw versions used when building calling app and the library itself.

  • int libraw_get_raw_height(libraw_data_t *lr);
  • int libraw_get_raw_width(libraw_data_t *lr);
  • int libraw_get_iheight(libraw_data_t *lr);
  • int libraw_get_iwidth(libraw_data_t *lr);
  • float libraw_get_cam_mul(libraw_data_t *lr,int index);
  • float libraw_get_pre_mul(libraw_data_t *lr,int index);
  • float libraw_get_rgb_cam(libraw_data_t *lr,int index1, int index2);
  • int libraw_get_color_maximum(libraw_data_t *lr);
  • void libraw_set_user_mul(libraw_data_t *lr,int index, float val);
  • void libraw_set_demosaic(libraw_data_t *lr,int value);
  • void libraw_set_output_color(libraw_data_t *lr,int value);
  • void libraw_set_user_mul(libraw_data_t *lr,int index, float val);
  • void libraw_set_output_bps(libraw_data_t *lr,int value);
  • void libraw_set_gamma(libraw_data_t *lr,int index, float value);
  • void libraw_set_no_auto_bright(libraw_data_t *lr,int value);
  • void libraw_set_bright(libraw_data_t *lr,float value);
  • void libraw_set_highlight(libraw_data_t *lr,int value);
  • void libraw_set_fbdd_noiserd(libraw_data_t *lr,int value);
  • void libraw_set_ca_correction(libraw_data_t *lr,int ca_correc, float ca_red, float ca_blue);
  • void libraw_set_ca_correction(libraw_data_t *lr,int ca_correc, float ca_red, float ca_blue);
  • void libraw_set_cfalinenoise(libraw_data_t *lr,int cfaline, float linenoise);
  • void libraw_set_wf_debanding(libraw_data_t *lr, int wf_debanding, float wfd0, float wfd1, float wfd2, float wfd3);
  • void libraw_set_interpolation_passes(libraw_data_t *lr,int passes);

Auxiliary Functions

const char* libraw_version()
See LibRaw::version()
const char* libraw_versionNumber()
See LibRaw::versionNumber()q
bool LIBRAW_CHECK_VERSION(major,minor,patch)
See LIBRAW_CHECK_VERSION
unsigned libraw_capabilities()
See LibRaw::capabilities()
int libraw_cameraCount()
See LibRaw::cameraCount()
int libraw_cameraList()
See LibRaw::cameraList()
void libraw_get_decoder_info(libraw_data_t*,libraw_decoder_info_t *);
See LibRaw::get_decoder_info()
void libraw_unpack_function_name(libraw_data_t*);
See LibRaw::unpack_function_name()
void libraw_COLOR(libraw_data_t*,int row,int col);
See LibRaw::COLOR()
void libraw_subtract_black(libraw_data_t*);
See LibRaw::subtract_black()
void libraw_recycle_datastream(libraw_data_t*);
See LibRaw::recycle_datastream()
void libraw_recycle(libraw_data_t*);
See LibRaw::recycle()
void libraw_close(libraw_data_t*);
See LibRaw::~LibRaw()
const char *libraw_strerror(int errorcode);
See LibRaw::strerror
const char *libraw_strprogress(enum LibRaw_progress);
See LibRaw::strprogress
void libraw_set_memerror_handler(libraw_data_t*, memory_callback cb);
See LibRaw::set_memerror_handler()
void libraw_set_dataerror_handler(libraw_data_t*,data_callback func);
See LibRaw::set_dataerror_handler()
void libraw_set_progress_handler(libraw_data_t*,progress_callback func);
See LibRaw::set_progress_handler()

Data Postprocessing, Emulation of dcraw Behavior

Setting of Parameters

The postprocessing parameters for the calls described below are set, just as for C++ API, via setting of fields in the libraw_output_params_t structure:

 libraw_data_t *ptr = libraw_init(0);
 ptr->params.output_tiff = 1; //  output to TIFF
    

Fields of this structure are described in the documentation to libraw_output_params_t. For notes on their use, see API notes.

Emulation of dcraw Behavior

int libraw_raw2image(libraw_data_t*);
See LibRaw::raw2image
int libraw_free_image(libraw_data_t*);
See LibRaw::free_image
int libraw_adjust_sizes_info_only(libraw_data_t*);
See LibRaw::adjust_sizes_info_only()
int libraw_dcraw_process(libraw_data_t* lr);
See LibRaw::dcraw_process()

Writing to Output Files

int libraw_dcraw_ppm_tiff_writer(libraw_data_t* lr,const char *filename);
See LibRaw::dcraw_ppm_tiff_writer()
int libraw_dcraw_thumb_writer(libraw_data_t* lr,const char *fname);
See LibRaw::dcraw_thumb_writer()

Writing processing results to memory buffer

libraw_processed_image_t *libraw_dcraw_make_mem_image(libraw_data_t* lr,int * errcode)
See LibRaw::dcraw_make_mem_image()
libraw_processed_image_t *libraw_dcraw_make_mem_thumb(libraw_data_t* lr,int * errcode)
See LibRaw::dcraw_make_mem_thumb()

[back to Index]

LibRaw-0.18.8/doc/API-CXX.html000077500000000000000000001323101324423227700155050ustar00rootroot00000000000000

LibRaw C++ API[back to Index]

LibRaw C++ API

Contents

  1. LibRaw Objects
  2. Returned values
  3. Methods Loading Data from a File
  4. Auxiliary Functions
  5. Data Postprocessing: Emulation of dcraw Behavior
  6. Data Output to Files: Emulation of dcraw Behavior
  7. Copying unpacked data into memory buffer
  8. Input layer abstraction

LibRaw Objects

The main LibRaw object (class) is created either without parameters or with flags determining the object behavior.

#include "libraw/libraw.h"
...

LibRaw ImageProcessor(unsigned int flags=0);
...

Flags (several flags are combined via operator |, i.e., bitwise OR):

  • LIBRAW_OPTIONS_NO_MEMERR_CALLBACK: do not set the standard out-of-memory error handler (standard handler outputs the error report in stderr);
  • LIBRAW_OPTIONS_NO_DATAERR_CALLBACK: do not set the standard file read error handler (standard handler outputs the error report in stderr).

Three groups of methods are used for image processing

The results of processing are placed in the imgdata field of type libraw_data_t; the same data set contains fields that control the postprocessing and output.

Returned Values

All LibRaw API functions return an integer number in accordance with the return code convention. Please read the descriptions of this convention and LibRaw behavior in cases of fatal errors.

Methods Loading Data from a File

int LibRaw::open_datastream(LibRaw_abstract_datastream *stream)

Opens a datastream with RAW data, reads metadata (EXIF) from it, and fills the following structures:

The function returns an integer number in accordance with the return code convention: positive if any system call has returned an error, negative (from the LibRaw error list) if there has been an error situation within LibRaw.

Before file opening, recycle() is always called; hence, if several images are processed in the batch mode, there is no need to call recycle() at the end of each processing cycle.

Input data: pointer to object, derived from LibRaw_abstract_datastream class. This object should be initialized and ready to read. This object should be destroyed in calling application after use.

int LibRaw::open_file(const char *filename[,INT64 bigfile_size])

Win32 only: int LibRaw::open_file(const wchar_t *filename[,INT64 bigfile_size])

Creates an LibRaw_file_datastream object, calls open_datastream(). If succeed, sets internal flag which signals to destroy internal datastream object on recycle(). On failure, just created file_datastream destroyed immediately.

Second optional parameter bigfile_size controls background I/O interface used for file operations. For files smaller than bigfile_size the LibRaw_file_datastream will be used and the LibRaw_bigfile_datastream otherwise.

The function returns an integer number in accordance with the return code convention: positive if any system call has returned an error, negative (from the LibRaw error list) if there has been an error situation within LibRaw.

int LibRaw::open_buffer(void *buffer, size_t bufsize)

Created an LibRaw_buffer_datastream object, calls open_datastream(). If succeed, sets internal flag which signals to destroy internal datastream object on recycle(). On failure, just created file_datastream destroyed immediately.

The function returns an integer number in accordance with the return code convention: positive if any system call has returned an error, negative (from the LibRaw error list) if there has been an error situation within LibRaw.

int LibRaw::unpack(void)

Unpacks the RAW files of the image, calculates the black level (not for all formats). The results are placed in imgdata.image.

Data reading is sometimes (not frequently) affected by settings made in imgdata.params (libraw_output_params_t); see API notes for details.

The function returns an integer number in accordance with the return code convention: positive if any system call has returned an error, negative (from the LibRaw error list) if there has been an error situation within LibRaw.

int LibRaw::unpack_thumb(void)

Reads (or unpacks) the image preview (thumbnail), placing the result into the imgdata.thumbnail.thumb buffer.
JPEG previews are placed into this buffer without any changes (with the header etc.). Other preview formats are placed into the buffer in the form of the unpacked bitmap image (three components, 8 bits per component).
The thumbnail format is written to the imgdata.thumbnail.tformat field; for the possible values, see description of constants and data structures.

The function returns an integer number in accordance with the return code convention: positive if any system call has returned an error, negative (from the LibRaw error list) if there has been an error situation within LibRaw.

Auxiliary Functions

Library version check

const char* LibRaw::version()

Returns string representation of LibRaw version in MAJOR.MINOR.PATCH-Status format (i.e. 0.6.0-Alpha2 or 0.6.1-Release).

int LibRaw::versionNumber()

Returns integer representation of LibRaw version. During LibRaw development, the version number is always increase .

bool LIBRAW_CHECK_VERSION(major,minor,patch)

Macro for version check in caller applications. Returns 'true' if current library version is greater or equal to set in macro parameters. This macro executes at runtime (not at compile time) and may be used for checking version of dynamically loaded LibRaw (from DLL/shared library).

List of supported RAW formats (cameras)

int LibRaw::cameraCount()

Returns count of cameras supported.

const char** LibRaw::cameraList()

Returns list of supported cameras. Latest item of list is set to NULL (for easy printing).

int LibRaw::set_rawspeed_camerafile(char *path_to_cameras_xml)

(Only if LibRaw was built with RawSpeed support).

Loads XML file with RawSpeed camera description data (cameras.xml) specified by path_to_cameras_xml. Returns 0 on success, nonzero on error.

int LibRaw::get_decoder_info(libraw_decoder_info_t *)

The function fills libraw_decoder_info_t structure by passed pointer with current raw decoder data.

The function returns an integer number in accordance with the return code convention: positive if any system call has returned an error, negative (from the LibRaw error list) if there has been an error situation within LibRaw.

const char* LibRaw::unpack_function_name()

Returns function name of file unpacking function. Intended only for LibRaw test suite designers to use in test coverage evaluation.

void LibRaw::setCancelFlag()

This call sets internal fast cancel flags. If set, current Raw decoder will be terminated ASAP. This call is useful if you need to cancel all LibRaw decoders in multithreaded program (e.g. for fast program termination or just for cancel current processing).

void LibRaw::clearCancelFlag()

This call clears internal fast cancel flags, so (early) terminated LibRaw decoder may work again.

int LibRaw::COLOR(int row, int col)

This call returns pixel color (color component number) in bayer patter at row,col. The returned value is in 0..3 range for 4-component Bayer (RGBG2, CMYG and so on) and in 0..2 range for 3-color data.

int LibRaw::error_count()

This call returns count of non-fatal data errors (out of range, etc) occured in unpack() stage.

void LibRaw::subtract_black()

This call will subtract black level values from RAW data (for suitable RAW data). colordata.data_maximum and colordata.maximum and black level data (colordata.black and colordata.cblack) will be adjusted too.

This call should be used if you postprocess RAW data by your own code. LibRaw postprocessing functions will call subtract_black() by oneself.

The function returns an integer number in accordance with the return code convention: positive if any system call has returned an error, negative (from the LibRaw error list) if there has been an error situation within LibRaw.

Support for floating point data

Libraw can read floating point DNG files (no other RAW formats may use floating point) with or without conversion to integer data. Floating point values are stored in imgdata.rawdata buffers:

  • float * float_image (if not NULL) points to floating point bayer data
  • float (*float3_image)[3] (if not NULL) points to floating point 3-channel buffer
  • float (*float4_image)[4] (if not NULL) points to floating point 4-channel buffer

Function calls for floating point support:

  • int LibRaw::is_floating_point(); function will return 1 if file contains floating point data
  • int LibRaw::have_fpdata(); function will return 1 if FP data has read (decoded) into memory and not converted to integer data
  • int LibRaw::convertFloatToInt(float dmin=4096.f, float dmax=32767.f, float dtarget = 16383.f) converts floating point data to integer. If data maximum is out of dmin..dmax range, than data scaled to set maximum to dtarget

Support for YCC formats (Canon sRAW/mRAW and Nikon Small NEF)

       int LibRaw::is_sraw();
int LibRaw::is_nikon_sraw();
int LibRaw::sraw_midpoint()
  • is_sraw() call returns nonzero if current image is YCC-based.
  • is_nikon_sraw() call returns nonzero for Nikon Small NEF files
  • sraw_midpoint() call returns neutral (gray) point for color channels

void LibRaw::set_dng_host(void* p)

If LibRaw is compiled with Adobe DNG SDK support and you wish to use this support:

  • you need to create own dng_host object
  • and pass it to LibRaw object using this function

void LibRaw::recycle_datastream(void)

This call closes input datastream with associated data buffer and unblocks opened file.

void LibRaw::recycle(void)

Frees the allocated data of LibRaw instance, enabling one to process the next file using the same processor. Repeated calls of recycle() are quite possible and do not conflict with anything.

LibRaw::~LibRaw()

Destructor, which consists in calling recycle().

const char* LibRaw::strprogress(enum LibRaw_progress code)

Converts progress stage code to description string (in English).

const char* LibRaw::strerror(int errorcode)

Analog of strerror(3) function: outputs the text descriptions of LibRaw error codes (in English).

Setting Error Notification Functions

In process of RAW conversion LibRaw can call user-setted callback. This callback can be used for:

  • Dynamic status update (progress bar and so on).
  • Cancel of processing (for example, user pressed Cancel button).

Also, work of the library may cause two types of exceptional situations that require notification of the calling application:

  • Memory shortage
  • Data read error.

An application may set its own callbacks that will be called in the cases mentioned above to notify the user (or the calling program).

Progress indication/processing termination

        typedef int (*progress_callback)(void *callback_data,enum LibRaw_progress stage, int iteration, int expected);
void LibRaw::set_progress_handler(progress_callback func,void *callback_data);

LibRaw user can set own callback which will be called 10-50 times during RAW postprocessing by dcraw_process().

This callback may terminate current image processing by returning of non-zero value. In such case all processing will be cancelled immediately and all resources will be returned to system by recycle() call. Current call of dcraw_process() will return error code LIBRAW_CANCELLED_BY_CALLBACK.

Callback parameters:

void *callback_data
void*-pointer, passed as 2nd argument to set_progress_handler(). This pointer should be used to pass additional data to callback (i.e. thread local data and so on).
enum LibRaw_progress stage
Current processing stage. This number can be converted to string by call to LibRaw::strprogress. Not all processing stages are covered by callback calls.
int iteration
Iteration number within current stage (from 0 to expected-1).
int expected
Expected number of iterations on current stage.

Callback should return value of: 0 for continue processing and non-zero for immediate cancel of processing.

 

If LibRaw compiled with OpenMP support, iteration parameter may not always increase within one stage. Out of order callback calls are possible.

Callback code sample:

int my_progress_callback(void *data,enum LibRaw_progress p,int iteration, int expected)
{
char *passed_string = (char *data);
printf("Callback: %s pass %d of %d, data passed: %s\n",libraw_strprogress(p),iteration,expected,passed_string);
if(timeout || key_pressed )
return 1; // cancel processing immediately
else
return 0; // can continue
}

User-specified exif tag parser callback

       typedef void (*exif_parser_callback) (void *context, int tag, int type, int len,unsigned int ord, void *ifp);
void LibRaw::set_exifparser_handler( exif_parser_callback cb,void *context);

Callback to be called on each parsed EXIF/Makernotes tag with parameters:

  • context - pointer to context passed to set_exifparser_handler();
  • tag - EXIF/Makernotes tag value
  • type - TIFF(EXIF) tag type
  • len - tag length
  • ord - byte order (II or MM)
  • void *ifp - pointer to LibRaw_abstract_datastream, positioned to tag data

 

Out-of-Memory Notifier

        typedef void (* memory_callback)(void *callback_data,const char *file, const char *where);
void LibRaw::set_memerror_handler(memory_callback func,void *callback_data);

The user may set his or her own function called in the case of memory shortage. It is a void function receiving two string parameters:

  • void *callback_data - void*-pointer, passed as 2nd argument to set_progress_handler(). This pointer should be used to pass additional data to callback (i.e. thread local data and so on).
  • file is the name of the RAW file whose processing evoked the out-of-memory error. This name can be NULL if underlying data input layer does not know the name. So, if calling application sets own callback, this callback should work with NULL file name.
  • where is the name of the function where memory shortage occurred.

The callback function is intended for information purposes: it notifies the user or the program code that processing is impossible.

If the user does not set his or her own handler, the standard one (output of error message in stderr) will be used.

One can set the null handler by passing NULL to set_memerror_handler; then no notifier function will be called. The same effect can be achieved by creating a LibRaw object with the LIBRAW_OPTIONS_NO_MEMERR_CALLBACK flag in the contructor.

In the case of memory shortage, processing of the current file is terminated and a notifier is called; all allocated resources are freed, and recycle() is performed. The current call will return LIBRAW_UNSUFFICIENT_MEMORY.
At an attempt to continue data processing, all subsequent calls will return LIBRAW_OUT_OF_ORDER_CALL. Processing of a new file may be started in the usual way, by calling LibRaw::open_file().

File Read Error Notifier

        typedef void (*data_callback)(void *callback_data,const char *file, const int offset);
void LibRaw::set_dataerror_handler(data_callback func, void *callback_data);

The user can define his or her own function to be called in the case of error in the input data. It is a void function receiving two parameters:

  • void *callback_data - void*-pointer, passed as 2nd argument to set_progress_handler(). This pointer should be used to pass additional data to callback (i.e. thread local data and so on).
  • file is the name of the RAW file whose processing evoked the file read error. This name can be NULL if underlying data input layer does not know the name. So, if calling application sets own callback, this callback should work with NULL file name.
  • offset is -1 at end-of-file (if LibRaw expects more data) or a positive number equal to the file position (bytes from file beginning) where the unpacking error occurred.

The callback function is intended for information purposes: it notifies the user or the program code that processing is impossible.

If the user does not set his or her own handler, the standard one (output of error message in stderr) will be used.

One can set the null handler by passing NULL to set_memerror_handler; then no notifier function will be called. The same effect can be achieved by creating a LibRaw object with the LIBRAW_OPTIONS_NO_DATAERR_CALLBACK flag in the contructor.

In the case of error in the input data, processing of the current file is terminated and a notifier is called; all allocated resources are freed, and recycle() is performed. The current call will return LIBRAW_IO_ERROR.
At an attempt to continue data processing, all subsequent calls will return LIBRAW_OUT_OF_ORDER_CALL. Processing of a new file may be started in the usual way, by calling LibRaw::open_file().

Data Postprocessing: Emulation of dcraw Behavior

Instead of writing one's own Bayer pattern postprocessing, one can use the dcraw functions, which are called after the calls of open_file() + unpack() /+ unpack_thumb()/

Parameter Setting

Virtually all parameters that can be set through the dcraw command line are specified by assigning values to fields of the LibRaw::imgdata.params structure. The type of this structure is libraw_output_params_t; all fields are listed and described in sufficient detail in the description of data structures.

int LibRaw::raw2image

This function allocates buffer for postprocessing (imgdata.image) and fills it with data layout compatible with LibRaw 0.13/0.14 and below. If the buffer is already allocated, it will be free()ed and allocated again.

This function should be called only if your code do postprocessing stage. If you use LibRaw's postprocessing calls (see below) you don't need to call raw2image().

The function returns an integer number in accordance with the return code convention: positive if any system call has returned an error, negative (from the LibRaw error list) if there has been an error situation within LibRaw.

void LibRaw::free_image

This function releases the imgdata.image buffer allocated by raw2image();

This method should be called if current postprocessing results are not needed by the program (e.g. already copied somewhere), but new postprocessing calls (with another settings) are possible, so it is to early to call recycle().

int LibRaw::adjust_sizes_info_only(void)

The function calculates the correct size of the output image (imgdata.sizes.iwidth and imgdata.sizes.iheight) for the following cases:

  • Files from Fuji cameras (with a 45-degree rotation)
  • Files from cameras with non-square pixels
  • Images shot by a rotated camera.

In the aforementioned cases, the function changes the fields of the image output size; note that this change cannot be repeated again.

int LibRaw::dcraw_process(void)

The function emulates the postprocessing capabilities available in dcraw.
Called after calling LibRaw::unpack();

The entire functionality of dcraw (set via the field values in imgdata.params) is supported, except for

  • Dark frame subtraction
  • Work with bad pixels.

The function is intended solely for demonstration and testing purposes; it is assumed that its source code will be used in most real applications as the reference material concerning the order of RAW data processing.

The function returns an integer number in accordance with the error code convention: positive if any system call has returned an error, negative (from the LibRaw error list) if there has been an error situation within LibRaw.

Data Output to Files: Emulation of dcraw Behavior

In spite of the abundance of libraries for file output in any formats, LibRaw includes calls that emulate the file output provided by dcraw. This is done primarily for easier verification of library work: the resultant files must be binary identical.

int LibRaw::dcraw_ppm_tiff_writer(const char *outfile)

The function outputs the postprocessing results to a file in the PPM/PGM or TIFF format (the format is set via imgdata.params.output_tiff). The results are binary identical to those provided by dcraw.

The function returns an integer number in accordance with the error code convention: positive if any system call has returned an error, negative (from the LibRaw error list) if there has been an error situation within LibRaw.

int LibRaw::dcraw_thumb_writer(const char *thumbfile)

Writes the thumbnail to a file in the PPM format for bitmap thumbnails and in the JPEG format for JPEG thumbnails, i.e., in the format completely identical to the results provided by dcraw.

The function returns an integer number in accordance with the error code convention: positive if any system call has returned an error, negative (from the LibRaw error list) if there has been an error situation within LibRaw.

Copying unpacked data into memory buffer

There is several function calls for store unpacked data into memory buffer (after using dcraw_process() and so on):

  • get_mem_image_format - get resulting bitmap size and bit depth.
  • copy_mem_image - copy postprocessed data into some memory buffer with different color order and line stride.
  • dcraw_make_mem_image - store processed image data into allocated buffer;
  • dcraw_make_mem_thumb - store extracted thumbnail into buffer as JPEG-file image (for most cameras) or as RGB-bitmap.

For usage primer see samples/mem_image.c sample.

 

void get_mem_image_format(int *widthp, int *heightp, int *colorsp, int *bpp) const - return processing bitmap size

This function returns size of postprocessed image:

  • Image width is returned in *widthp;
  • Bitmap height is returned in *heightp;
  • Image color count is returned in *colorsp;
  • Bits per pixel (8 or 16) is returned in *bpp;

int LibRaw::copy_mem_image(void* scan0, int stride, int bgr) - copies postprocessed bitmap data into buffer

Function parameters:

  • void *scan0 - pointer to buffer to copy data to. The buffer should be at least stride*image_height bytes;
  • int stride - stride of each other image line (row) in bytes. Usually image_width*(bit_per_pixel/8)*image_colors, but may be more if you wish to align image rows to, for example, 8 or 16 or 32 bytes to make CPU more happy.
  • int bgr - pixel copy order. RGB if bgr==0 and BGR overwise.

The function returns an integer number in accordance with the error code convention: positive if any system call has returned an error, negative (from the LibRaw error list) if there has been an error situation within LibRaw.

libraw_processed_image_t *dcraw_make_mem_image(int *errorcode=NULL) - store unpacked and processed image into memory buffer as RGB-bitmap

This function allocates memory buffer and stores unpacked-preprocessed image into this buffer. Function returns allocated structure libraw_processed_image_t with filled fields. Always returns data as RGB bitmap (i.e. type field is equal to LIBRAW_IMAGE_BITMAP).

dcraw_process() should be called before dcraw_make_mem_image();

Returns NULL in case of an error. If caller has passed not-NULL value as errorcode parameter, than *errorcode will be set to error code according to error code convention.

NOTE! Memory, allocated for return value will not be fried at destructor or LibRaw::recycle calls. Caller of dcraw_make_mem_image should free this memory by call to LibRaw::dcraw_clear_mem().

libraw_processed_image_t *dcraw_make_mem_thumb(int *errorcode=NULL) - store unpacked thumbnail into memory buffer

This function allocates memory buffer and stores thumbnail data in it. Function returns allocated structure libraw_processed_image_t with filled fields. For most RAW images allocated structure will contains JPEG image (i.e. type field is equal to LIBRAW_IMAGE_JPEG). For some cameras with RGB-bitmap thumbnail (Kodak SLRs) returned structure contains RGB bitmap (type field is equal to LIBRAW_IMAGE_JPEG, see structure description for details).

unpack_thumb() should be called before dcraw_make_mem_thumb();

Returns NULL in case of an error. If caller has passed not-NULL value as errorcode parameter, than *errorcode will be set to error code according to error code convention.

NOTE! Memory, allocated for return value will not be fried at destructor or LibRaw::recycle calls. Caller of dcraw_make_mem_image should free this memory by call to LibRaw::dcraw_clear_mem().

void LibRaw::dcraw_clear_mem(libraw_processed_image_t *)

This function will free the memory allocated by dcraw_make_mem_image or dcraw_make_mem_thumb.

This is static class member, so call syntax should be LibRaw::dcraw_clear_mem(...).

This call translates directly to free() system function, but it is better to use dcraw_clear_mem because LibRaw (DLL) may be compiled with memory manager other than in calling application.

Input layer abstraction

class LibRaw_abstract_datastream - abstract RAW read interface

LibRaw reads RAW-data by calling (virtual) methods of C++ object derived from LibRaw_abstract_datastream. This C++ class does not implement any read, but defines interface to be called. Call to base class methods always results in error.

LibRaw_abstract_datastream class methods

Object verification
virtual int valid()
Checks input datastream validity. Returns 1 on valid stream and 0 if datastream was created on non-valid input parameters (wrong filename for file stream and so on).

Stream read and positioning

This group of methods implements file object (FILE*) semantics.

virtual int read(void * ptr,size_t size, size_t nmemb)
Similar to fread(ptr,size,nmemb,file).
virtual int seek(off_t o, int whence)
Similar to fseek(file,o,whence).
virtual int tell(
Similar to ftell(file).
virtual int get_char()
Similar to getc(file)/fgetc(file).
virtual char* gets(char *s, int n)
Similar to fgets(s,n,file).
virtual int eof()
Similar to feof(file).
virtual int scanf_one(const char *fmt, void *val)
Simplified variant of fscanf(file,fmt,val): format string is always contains one argument to read. So, variable args call is not needed and only one pointer to data passed.
virtual int jpeg_src(void * p);
Initializes read structures in j_decompress_ptr object passed as *p. This object is used by libjpeg for JPEG data reading from datastream.

Retuens -1 on error and 0 on success.

virtual void * make_jas_stream();
Creates LibJasper input stream (for JPEG2000 decoding).

returns NULL on error or data pointer on success.

Other methods

This group of methods includes several supplementary calls. These calls are used to temporary switch to another data stream (file and/or memory buffer).

virtual const char* fname()
Returns name of opened file if datastream object knows it (for example, LibRaw_file_datastream used). Filename used in:
  • error notification callbacks;
  • generation of filename of JPEG-file with metadata when needed (i.e. cameras with 'Diag RAW hack').
virtual int subfile_open(const char *fn)
This call temporary switches input to file fn. Returns 0 on success and error code on error.
The function used to read metadata from external JPEG file (on cameras with "Diag RAW hack").
This call is not implemented for LibRaw_buffer_datastream, so external JPEG processing is not possible when buffer datastream used.
This functon should be implemented in real input class, base class call always return error.
Working implementation sample can be found in LibRaw_file_datastream implementation in libraw/libraw_datastream.h file.
virtual void subfile_close()
This call switches input stream from temporary open file back to main data stream.
virtual int tempbuffer_open(void *buf, size_t size)
This call temporary switches input to LibRaw_buffer_datastream object, created from buf.
This method is needed for Sony encrypted metadata parser.

This call implemented in base class (LibRaw_abstract_datastream), there is no need to reimplement in in derived classes.
Possible activity of temporary datastream requires very accurate programming when implementing datastreams derived from base LibRaw_abstract_datastream. See below for more details.

virtual void tempbuffer_close()
This call switch input back from temporary datastream to main stream. This call implemented in base LibRaw_abstract_datastream class.

Derived input classes included in LibRaw

There is three "standard" input classes in LibRaw distribution:

LibRaw C++ interface users can implement their own input classes and use them via LibRaw::open_datastream call. Requirements and implementation specifics are described below.

class LibRaw_file_datastream - file input interface

This class implements input from file.

Class methods:

LibRaw_file_datastream(const char *fname)
This constructor creates LibRaw_file_datastream object from file fname.
Unfortunately, C++ constructor cannot return an error. So if bad filename passed (e.g. nonexistent file) object is created as non-valid (valid() call returns zero).

All other class methods are described above.
This class implements all possble methods, including fname() and subfile_open().

class LibRaw_bigfile_datastream - file input interface

This class implements input from file.

Class methods:

LibRaw_bigfile_datastream(const char *fname)
This constructor creates LibRaw_bigfile_datastream object from file fname.
Unfortunately, C++ constructor cannot return an error. So if bad filename passed (e.g. nonexistent file) object is created as non-valid (valid() call returns zero).

The difference between file and bigfile datastreams are obvious from class name: bigfile one supports large files (more than 2Gb) on all supported systems. File one uses streambuf interface which is limited to 2Gb on many systems.

All other class methods are described above.
This class implements all possble methods, including fname() and subfile_open().

class LibRaw_buffer_datastream - memory buffer input interface

This class implements input from memory buffer.

Class methods:

LibRaw_buffer_datastream(void *buffer, size_t bsize)
This constructor creates datastream object from buffer with size bsize.
It is not possibly to verify the pointer passed, so buffer address is checked against 0 and -1 only.

All other class methods are described above.
This class does not implement fname() and subfile_open() calls, so external JPEG metadata parsing is not possible.

Own datastream derived classes

To create own read interface LibRaw user should implement C++ class derived from LibRaw_abstract_datastream with all read methods.
LibRaw standard implementations may be used as reference. See libraw/libraw_datastream.h file for details (all standard LibRaw input classes are implemented using inline functions only).

substream field: secondary input stream

substream field, defined in base LibRaw_abstract_datastream class requires some additional notes. This field is used when input switched to temporary buffer (used for Sony metadata processing). Unfortunately, there is now ideal C++ way to hide this functionality into base class internals. So, any read call in derived class should include 1-line statement like this:
int method(...args...){ if(substream) return substream->method(...args...). For example:

    virtual int eof() 
{
if(substream) return substream->eof();
....
virtual int scanf_one(const char *fmt, void* val)
{
if(substream) return substream->scanf_one(fmt,val);

[back to Index]

LibRaw-0.18.8/doc/API-datastruct.html000077500000000000000000001535231324423227700172320ustar00rootroot00000000000000

LibRaw: Data Structures and Constants [back to Index]

LibRaw: Data Structures and Constants

LibRaw data structures are defined in header file libraw/libraw_types.h
Constants used in its work are defined in file libraw/libraw_const.h

Contents:

  1. Data structures
    1. libraw_data_t: Main Data Structure in LibRaw
    2. Structure libraw_iparams_t: Main Parameters of the Image
    3. Structure libraw_image_sizes_t: Image Dimensions
    4. Structure libraw_colordata_t: Color Information
    5. Structure libraw_imgother_t: Other Parameters of the Image
    6. Structure libraw_rawdata_t: holds unpacked RAW data
    7. Structure libraw_thumbnail_t: Description of Thumbnail
    8. Structure libraw_lensinfo_t - lens data, extracted from EXIF/Makernotes
    9. Structure libraw_output_params_t: Management of dcraw-Style Postprocessing .
    10. Stucture libraw_processed_image_t - result set for dcraw_make_mem_image()/dcraw_make_mem_thumb() functions
  2. Input abstraction layer
  3. Constants
    1. enum LibRaw_errors: Error Codes
    2. enum LibRaw_decoder_flags - RAW data format description
    3. enum LibRaw_progress: Current State of LibRaw Object
    4. enum LibRaw_thumbnail_formats: Thumbnail Data Formats
    5. Nonstandard Situations (Warnings) during RAW Data Processing
    6. enum LibRaw_image_formats - possible types of data, contains in libraw_processed_image_t structure

Data Structures

libraw_data_t: Main Data Structure of LibRaw

Structure libraw_data_t is a "wrapping" for data structures accessible to the user of the library.
When one uses C++ API, it is accessible as LibRaw::imgdata (class_instance.imgdata). The data in this structure appear after a file is opened through open_file (and other open_ calls), except for the image itself (filled by unpack()) and data containing the preview information (filled by calling unpack_thumb()).
Data fields:

unsigned int progress_flags;
This field records the past phases of image processing .
unsigned int process_warnings;
This field records suspicious situations (warnings) that have emerged during image processing.
libraw_iparams_t idata;
The structure describes the main image parameters retrieved from the RAW file. Fields of this structure are described in detail below .
libraw_image_sizes_t sizes;
The structure describes the geometrical parameters of the image. Fields of this structure are described in detail below .
libraw_lensinfo_t lens;
The structure describes lens used for the shot. Fields of this structure are described in detail below .
libraw_makernotes_t makernotes;
The structure contains camera/vendor specific metadata extracted from file. No description provided, sorry, if you're interested in particular tag/camera/vendor - use Exiftool documentation as a reference
libraw_colordata_t color;
The structure contains color data retrieved from the file. Fields of this structure are described in detail below .
libraw_imgother_t other;
Data structure for information purposes: it contains the image parameters that have been extracted from the file but are not needed in further file processing. Fields of this structure are described in detail below .
libraw_thumbnail_t thumbnail;
Data structure containing information on the preview and the preview data themselves. All fields of this structure but thumbnail itself are filled when open_file() is called. Thumbnail readed by unpack_thumb() call. The fields are described in detail below .
libraw_rawdata_t rawdata;
Data structure with pointer to raw-data buffer. Details are described below .
ushort (*image)[4];
The memory area that contains the image pixels per se. It is filled when raw2image() or dcraw_process() is called.
libraw_output_params_t params;
Data structure intended for management of image postprocessing (using the dcraw emulator). Fields of this structure are described in detail below .
void (LibRaw::*interpolate_bayer)()
Pointer to user-specified bayer interpolation function. If not null, this function to be called instead of standard one specified by user_qual (or not specified)
void (LibRaw::*interpolate_xtrans)()
Pointer to user-specified X-Trans interpolation function. If not null, this function to be called instead of standard one specified by user_qual (or not specified)

Structure libraw_iparams_t: Main Parameters of the Image

char make[64];
Camera manufacturer.
char model[64];
Camera model.
char software[64];
Softwary name/version (mostly for DNG files, to distinguish in-camera DNGs from Adobe DNG Converter produced ones).
unsigned raw_count;
Number of RAW images in file (0 means that the file has not been recognized).
unsigned is_foveon;
Nonzero for Sigma Foveon images
unsigned dng_version;
DNG version (for the DNG format).
1 for Foveon matrices, 0 for others. Foveon is supported in LibRaw-demosaic-pack-GPL2.
int colors;
Number of colors in the file.
unsigned filters;
Bit mask describing the order of color pixels in the matrix (0 for full-color images). 32 bits of this field describe 16 pixels (8 rows with two pixels in each, from left to right and from top to bottom). Each two bits have values 0 to 3, which correspond to four possible colors. Convenient work with this field is ensured by the COLOR(row,column) function, which returns the number of the active color for a given pixel.

values less than 1000 are reserved as special cases:

  • 1 - Leaf Catchlight with 16x16 bayer matrix;
  • 9 - Fuji X-Trans (6x6 matrix)
  • 3..8 and 10..999 - are unused.
char xtrans[6][6];
char xtrans_abs[6][6];
These matrices contains Fuji X-Trans row/col to color mapping. First one is relative to visible area, while second is positioned relative to sensor edges.
char cdesc[5];
Description of colors numbered from 0 to 3 (RGBG,RGBE,GMCY, or GBTG).
unsigned xmplen; char *xmpdata;
XMP packed data length and pointer to extracted XMP packet.

Structure libraw_image_sizes_t: Image Dimensions

Structure libraw_image_sizes_t is a collection of all file data that describe the size of the image.
Data fields:

ushort raw_height, raw_width;
Full size of RAW image (including the frame) in pixels.
ushort height, width;
Size of visible ("meaningful") part of the image (without the frame).
ushort top_margin, left_margin;
Coordinates of the top left corner of the frame (the second corner is calculated from the full size of the image and size of its visible part).
ushort iheight, iwidth;
Size of the output image (may differ from height/width for cameras that require image rotation or have non-square pixels).
unsigned raw_pitch;
Full size of raw data row in bytes .
double pixel_aspect;
Pixel width/height ratio. If it is not unity, scaling of the image along one of the axes is required during output.
int flip;
Image orientation (0 if does not require rotation; 3 if requires 180-deg rotation; 5 if 90 deg counterclockwise, 6 if 90 deg clockwise).

Structure libraw_colordata_t: Color Information

Structure libraw_colordata_t unites all color data, both retrieved from the RAW file and calculated on the basis of the image itself. For different cameras, there are different ways of color handling.
Data fields:

ushort curve[0x10000];
Camera tone curve. May be read from file as is, or calculated, depending on file format;
unsigned black;
Black level. Depending on the camera, it may be zero (this means that black has been subtracted at the unpacking stage or by the camera itself), calculated at the unpacking stage, read from the RAW file, or hardcoded.
unsigned cblack[4102];
Per-channel black level correction. First 4 values are per-channel correction, next two are black level pattern block size, than cblack[5]*cblack[6] correction values.
unsigned data_maximum;
Maximum pixel value in current file. Calculated at raw2image or dcraw_process() calls.
unsigned maximum;
Maximum pixel value. Calculated from the data for most cameras, hardcoded for others. This value may be changed on postprocessing stage (when black subtraction performed) and by automated maximum adjustment (this adjustment performed if params.adjust_maximum_thr is set to nonzero).
float fmaximum;
Maximum pixel value in real image for floating data files.
float fnorm;
Normalization coefficient used while converting floating point raw data to integer.
ushort white[8][8];
Block of white pixels extracted from files CIFF/CRW. Not extracted for other formats. Used to calculate white balance coefficients.
float cam_xyz[4][3];
Camera RGB - XYZ conversion matrix. This matrix is constant (different for different models). Last row is zero for RGB cameras and non-zero for different color models (CMYG and so on).
float cam_mul[4];
White balance coefficients (as shot). Either read from file or calculated.
float pre_mul[4];
White balance coefficients for daylight (daylight balance). Either read from file, or calculated on the basis of file data, or taken from hardcoded constants.
float cmatrix[3][4];
Camera color data read from RAW file (if any)
float rgb_cam[3][4];
Camera to sRGB conversion matrix
float ccm[3][4];
Camera color correction matrix readed from file metadata (uniform matrix if no such data in file)
ph1_t phase_one_data;
Color data block that is read for Phase One cameras.
float flash_used;
float canon_ev;
Fields used for white balance calculations (for some P&S Canon cameras).
char model2[64];
Firmware revision (for some cameras).
char UniqueCameraModel[64],LocalizedCameraModel[64];
Values from DNG tags with same names.
void *profile;
Pointer to the retrieved ICC profile (if it is present in the RAW file).
unsigned profile_length;
Length of ICC profile in bytes.
unsigned black_stat[8];
Black level statistics if calcluated from masked area: 4 sum of pixel values, than 4 pixel counts (per channel).
libraw_dng_color_t dng_color[2];
Color data read from DNG: illuminant, calbiration matrix and color matrix for two light sources. (see DNG specs for details).
float baseline_exposure;
DNG-files: value of BaselineExposure tag.

Structure libraw_imgother_t: Other Parameters of the Image

Data fields:

float iso_speed;
ISO sensitivity.
float shutter;
Shutter speed.
float aperture;
Aperture.
float focal_len;
Focal length.
time_t timestamp;
Date of shooting.
unsigned shot_order;
Serial number of image.
unsigned gpsdata[32];
GPS data (unparsed block, to write to output as is).
libraw_gps_info_t parsed_gps;
Parsed GPS-data: longtitude/lattitude/altitude and time stamp.
char desc[512];
Image description.
char artist[64];
Author of image.
float FlashEC;
Flash exposure compensation.

Structure libraw_rawdata_t: holds unpacked RAW data

Structure libraw_rawdata_t holds:

  • RAW-data from sensor, readed and unpacked by the unpack() call.
  • "backup" copy of color and over data modified during postprocessing. When postprocessing calls repeats, the needed data is restored from this backup.

Data fields:

void *raw_alloc;
Buffer allocated to hold RAW-data
unsigned short *raw_image;
Pointer to buffer with one-component (bayer) data.
unsigned short (*color3_image)[3];
Pointer to 3-component pixel array.
unsigned short (*color4_image)[4];
Pointer to buffer with 4-component pixel data data
float *float_image;
Pointer to buffer with one-component (bayer) data in FP-format.
float (*float3_image)[3];
Pointer to 3-component FP pixel array.
float (*float4_image)[4];
Pointer to buffer with 4-component pixel data data

After call to unpack() only one of these fields is non-NULL.

All other fields of this structure are for internal use and should not be touched by user code.

Structure libraw_thumbnail_t: Description of Thumbnail

Structure libraw_thumbnail_t describes all parameters associated with the preview saved in the RAW file.
Data fields:

LibRaw_thumbnail_formats tformat;
Thumbnail data format. One of the values among enum LibRaw_thumbnail_formats .
ushort twidth, theight;
Dimensions of the preview image in pixels.
unsigned tlength;
Thumbnail length in bytes.
int tcolors;
Number of colors in the preview.
char *thumb;
Pointer to thumbmail, extracted from the data file.

Structure libraw_lensinfo_t: parsed lens data

The following parameters are extracted from Makernotes and EXIF, to help identify which lens was mounted on the camera. If the value is missing in Makernotes or EXIF, the parameter is set to zero with some exceptions noted below. In some cases the values for the fields like CameraFormat and CameraMount are set based on the camera model and/or camera ID.

libraw_makernotes_lens_t structure:

  • LensID (if not -1) and CamID (camera id, if non-zero) values are compatible with those used in exiftool, like |0x0010 CanonModelID| and |22 LensType| see http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Canon.html or 0x0207/CameraType and 0x0201/LensType (see http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Olympus.html )
  • Lens string, if not empty, contains the lens name present in Makernotes.
  • LensFormat and CameraFormat' currently provide one of value from enum LibRaw_camera_formats;
  • In a similar manner, values for 'LensMount' and 'CameraMount' follow the enum LibRaw_camera_mounts;
  • In some cases, the Makernotes for MF cameras contain either an id for the body, or a string containing the name of the body. The name is copied to 'body' field, while the id is converted to the appropriate body name and also copied to 'body' field. In other cases the 'body' field is empty.
  • FocalType is set based on Makernotes tag, if present. The values are: -1 Undefined; 0 Unknown;1 Fixed focal length lens; 2 Zoom lens
  • LensFeatures_pre - lens name prefix and LensFeatures_suf - lens name suffix: (if not empty) some cameras record alphabet soup that characterizes the lens in separate Makernote tags (see, for example, 0xb02a LensSpec at http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Sony.html ), and for some lenses those acronyms can be derived from the 'Lens' field itself (see processCanonCameraInfo). Those can also help better lens identification.
  • 'MinFocal' and 'MaxFocal' , if non-zero, contain the minimum and maximum focal lengths for the lens mounted on the camera.
  • 'MaxAp4MinFocal', 'MaxAp4MaxFocal', 'MinAp4MinFocal', 'MinAp4MaxFocal' - if non-zero, contain maximum aperture available at minimal focal length, maximum aperture available at maximum focal length, minimum aperture available at minimal focal length, minimum aperture available at maximum focal length, respectively.
  • 'MaxAp' and 'MinAp', if non-zero, contain the maximum aperture for the lens (usually it is the maximum aperture for minimal focal length) and the minimum aperture across the focal length range. For zooms with variable maximum aperture this is usually the minimum aperture for the maximum focal length.
  • 'CurFocal', if non-zero, is current focal length - that is the focal length used to take the shot.
  • 'CurAp', if non-zero, is current aperture.
  • 'MaxAp4CurFocal' and 'MinAp4CurFocal', if non-zero, contain the minimum and maximum apertures for the current focal length.
  • 'LensFStops' - if non-zero, contains the number of aperture "clicks" or the number of f-stops, depending on the model of the camera.
  • 'TeleconverterID', 'AdapterID', 'AttachmentID', if non-zero, are the numbers extracted from Makernotes to identify lens accessories used to take the shot.
  • 'Teleconverter', 'Adapter', 'Attachment', if non-empty, are the strings containing the names of the accessories as they appear in Makernotes, or for some cameras, decoded from a numeric field in Makernotes.
  • 'CanonFocalUnits' - an auxiliary field, should not be needed most of the cases. See Canon.pm module in exiftool for more information on this value.
  • 'FocalLengthIn35mmFormat', if non-zero: for some reason certain Samsung cameras record this value in Makernotes instead of the EXIF proper. Also used for Sigma cameras.

libraw_nikonlens_t structure:

Contains additional parameters needed to identify the lens on a Nikon camera using a table - please see Nikon LensID Values at http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html

libraw_dnglens_t structure:

Contains minimum focal length, maximum focal length, maximum aperture available at minimal focal length, and maximum aperture available at maximum focal length, extracted from EXIF field of a DNG raw file.

libraw_lensinfo_t structure:

Contains all the structures described above, plus parameters extracted directly from EXIF fields:

  • 'MinFocal' and 'MaxFocal' , if non-zero, contain the minimum and maximum focal lengths for the lens mounted on the camera.
  • 'MaxAp4MinFocal', 'MaxAp4MaxFocal' - if non-zero, contain maximum aperture available at minimal focal length and maximum aperture available at maximum focal length
  • 'LensMake', if not empty, contains a string with the lens manufacturer name.
  • 'Lens', if not empty, contains the lens name as recorded in EXIF
  • 'FocalLengthIn35mmFormat' - if non-zero, same as FocalLengthIn35mmFilm in EXIF standard, tag 0xa405.
  • 'EXIF_MaxAp' - if non-zero, contains the value derived from EXIF tag 0x9205.

Structure libraw_output_params_t: Management of dcraw-Style Postprocessing

Structure libraw_output_params_t is used for management of dcraw-compatible calls dcraw_process(), dcraw_ppm_tiff_writer(), and dcraw_thumb_writer(). Fields of this structure correspond to command line keys of dcraw.
Data fields:

unsigned greybox[4];
dcraw keys: -A x y w h
4 numbers corresponding to the coordinates (in pixels) of the rectangle that is used to calculate the white balance. X and Y are coordinates of the left-top rectangle corner; w and h are the rectangle's width and height, respectively.
unsigned cropbox[4];
dcraw keys: none
This field sets the image cropping rectangle. Cropbox[0] and cropbox[1] are the rectangle's top-left corner coordinates, remaining two values are width and height respectively. All coordinates are applied before any image rotation.
double aber[4];
dcraw keys: -C
Correction of chromatic aberrations; the only specified values are
aber[0], the red multiplier
aber[2], the green multiplier. For some formats, it affects RAW data reading , since correction of aberrations changes the output size.
double gamm[6];
dcraw keys: -g power toe_slope
Sets user gamma-curve. Library user should set first two fields of gamm array:
gamm[0] - inverted gamma value)
gamm[1] - slope for linear part (so called toe slope). Set to zero for simple power curve.
Remaining 4 values are filled automatically.

By default settings for rec. BT.709 are used: power 2.222 (i.e. gamm[0]=1/2.222) and slope 4.5. For sRGB curve use gamm[0]=1/2.4 and gamm[1]=12.92, for linear curve set gamm[0]/gamm[1] to 1.0.

float user_mul[4];
dcraw keys: -r mul0 mul1 mul2 mul3
4 multipliers (r,g,b,g) of the user's white balance.
unsigned shot_select;
dcraw keys: -s
Selection of image number for processing (for formats that contain several RAW images in one file).
float bright;
dcraw keys: -b
Brightness (default 1.0).
float threshold;
dcraw keys: -n
Parameter for noise reduction through wavelet denoising.
int half_size;
dcraw keys: -h
Outputs the image in 50% size. For some formats, it affects RAW data reading .
int four_color_rgb;
dcraw keys: -f
Switches on separate interpolations for two green components.
int highlight;
dcraw keys: -H
0-9: Highlight mode (0=clip, 1=unclip, 2=blend, 3+=rebuild).
int use_auto_wb;
dcraw keys: -a
Use automatic white balance obtained after averaging over the entire image.
int use_camera_wb;
dcraw keys: -w
If possible, use the white balance from the camera.
int use_camera_matrix;
dcraw keys: +M/-M
  • 0: do not use embedded color profile
  • 1 (default): use embedded color profile (if present) for DNG files (always); for other files only if use_camera_wb is set;
  • 3: use embedded color data (if present) regardless of white balance setting.
int output_color;
dcraw keys: -o
[0-5] Output colorspace (raw, sRGB, Adobe, Wide, ProPhoto, XYZ).
char* output_profile;
dcraw keys: -o filename
Path to output profile ICC file (used only if LibRaw compiled with LCMS support)
char* camera_profile;
dcraw keys: -p file
Path to input (camera) profile ICC file (or 'embed' for embedded profile). Used only if LCMS support compiled in.
char* bad_pixels;
dcraw keys: -P file
Path to file with bad pixels map (in dcraw format: "column row date-of-pixel-death-in-UNIX-format", one pixel per row).
char* dark_frame;
dcraw keys: -K file
Path to dark frame file (in 16-bit PGM format)
int output_bps;
dcraw keys: -4
8 bit (default)/16 bit (key -4).
int output_tiff;
dcraw keys: -T
0/1: output PPM/TIFF.
int user_flip;
dcraw keys: -t
[0-7] Flip image (0=none, 3=180, 5=90CCW, 6=90CW). Default -1, which means taking the corresponding value from RAW.
For some formats, affects RAW data reading , e.g., unpacking of thumbnails from Kodak cameras.
int user_qual;
dcraw keys: -q
0-10: interpolation quality:
  • 0 - linear interpolation
  • 1 - VNG interpolation
  • 2 - PPG interpolation
  • 3 - AHD interpolation
  • 4 - DCB interpolation
  • 5 - Modified AHD interpolation by Paul Lee
  • 6 - AFD interpolation (5-pass)
  • 7 - VCD interpolation
  • 8 - Mixed VCD/Modified AHD interpolation
  • 9 - LMMSE interpolation
  • 10 - AMaZE intepolation
  • 11 - DHT intepolation
  • 12 - Modified AHD intepolation (by Anton Petrusevich)
Values 5-9 are useful only if "LibRaw demosaic pack GPL2" compiled in (see README.demosaic-packs in your distribution for details). Value 10 is useful only if LibRaw compiled with "LibRaw demosaic pack GPL3". If some interpolation method is unsupported because LibRaw compiled without corresponding demosaic pack, AHD interpolation will be used and  LIBRAW_WARN_FALLBACK_TO_AHD will be set in process_warniong field.
int user_black;
dcraw keys: -k
User black level.
int user_cblack[4];
dcraw keys: none
Per-channel corrections to user_black.
int user_sat;
dcraw keys: -S
Saturation adjustment.
int med_passes;
dcraw keys: -m
Number of median filter passes.
int no_auto_bright;
dcraw keys: -W
Don't use automatic increase of brightness by histogram.
float auto_bright_thr;
dcraw keys: none
Portion of clipped pixels when auto brighness increase is used. Default value is 0.01 (1%) for dcraw compatibility. Recommended value for modern low-noise multimegapixel cameras depends on shooting style. Values in 0.001-0.00003 range looks reasonable.
float adjust_maximum_thr;
dcraw keys: none
This parameters controls auto-adjusting of maximum value based on channel_maximum[] data, calculated from real frame data. If calculated maximum is greater than adjust_maximum_thr*maximum, than maximum is set to calculated_maximum.
Default: 0.75. If you set this value above 0.99999, than default value will be used. If you set this value below 0.00001, than no maximum adjustment will be performed.
Adjusting maximum should not damage any picture (esp. if you use default value) and is very useful for correcting channel overflow problems (magenta clouds on landscape shots, green-blue highlights for indoor shots).
int use_fuji_rotate;
dcraw keys: -j
Default -1 (use), 0 - don't use rotation for cameras on a Fuji sensor.
int green_matching;
Turns on fixing of green channels disbalance. dcraw keys: none
Default: 0 (not use), 1 - turns on this postprocessing stage. green_matching requires additional memory for image data.
int dcb_iterations
dcraw keys: none
Number of DCB correction passes. Default is -1 (no correction). Useful only for DCB interpolation.
int dcb_enhance_fl
dcraw keys: none
nonzero: DCB interpolation with enhance interpolated colors.
int fbdd_noiserd
dcraw keys: none
Controls FBDD noise reduction before demosaic.
  • 0 - do not use FBDD noise reduction
  • 1 - light FBDD reduction
  • 2 (and more) - full FBDD reduction
int eeci_refine
dcraw keys: none
nonzero- Use EECI refine for VCD interpolation.
int es_med_passes
dcraw keys: none
Number of edge-sensitive median filter passes after VCD+AHD demosaic. Value above 1 is highly not recommended.
int ca_correc
dcraw keys: none
positive value turns on chromatic aberrations suppression (default:0 i.e. off).
float cared,cablue
dcraw keys: none
If one of these fields is non-zero, then these values will be used instead of automatic ones. Useable range is +-0.1..+-4.0.
int cfaline; float linenoise;
Line noise (banding) reduction.
positive value turns this feature on (default: off).
linenoise - amount of reduction. Useful range is 0.001 to 0.02. Default value is 0.0 i.e. not clean anything.
int cfa_clean; float lclean,cclean;
Reduce impulse noise and Gaussian high frequency.
cfa_clean: positive value turns the feature on (default: off).
lclean,cclean - amount of noise reduction for (L)uminance and (C)olor. Useable range from 0.005 to 0.05, common value 0.01
int cfa_green; float green_thresh;
Reduces maze artifacts produced by bad balance of green channels.
cfa_green: positive value turns the feature on (default: off).
green_thresh - max difference between channels allowed for equalization. Useful range between 0.01 and 0.1.
int exp_correc; float exp_shift,exp_preser;
Exposure correction before demosaic.
  • exp_correc: positive value turns the feature on (default: off).
  • exp_shift: exposure shift in linear scale. Usable range from 0.25 (2-stop darken) to 8.0 (3-stop lighter). Default: 1.0 (no exposure shift).
  • exp_preser: preserve highlights when lighten the image. Usable range from 0.0 (no preservation) to 1.0 (full preservation). 0.0 is the default value.
int wf_debanding; float wf_deband_treshold[4];
wf_debanding: 1 turns on banding suppression (slow!), 0 turns it off.
wf_deband_treshold[] - per channel debanding thresholds.
int use_rawspeed;
Turns on using RawSpeed library for data unpacking (only if RawSpeed support compiled in).
int no_auto_scale;
Disables pixel values scaling (call to LibRaw::scale_colors()) in LibRaw::dcraw_process()
int no_interpolation;
Disables call to demosaic code in LibRaw::dcraw_process()
int raw_processing_options
Processing options used on unpack() phase for specific image formats

Sigma Quattro decoding flags:

  • LIBRAW_DP2Q_INTERPOLATERG - turn on R/G channels interpolation
  • LIBRAW_DP2Q_INTERPOLATEAF - turn on data interpolation of low-sensitivity (AF or overexposure control) points on Quattro sensors.

Pentax 4-shot options:

  • LIBRAW_PROCESSING_PENTAX_PS_ALLFRAMES - merge all frames for Pentax 4-shot files

Floating point DNG files:

  • LIBRAW_PROCESSING_CONVERTFLOAT_TO_INT - convert FP data to 16-bit integer

Sony ARW2.3 processing options: (for more details see http://www.rawdigger.com/howtouse/sony-craw-arw2-posterization-detection)

  • LIBRAW_PROCESSING_SONYARW2_BASEONLY - decode only base pixels, leave delta pixels as zero;
  • LIBRAW_PROCESSING_SONYARW2_DELTAONLY - decode only delta pixels with base pixels zeroed;
  • LIBRAW_PROCESSING_SONYARW2_DELTAZEROBASE - decode delta pixels, do not add base value;
  • LIBRAW_PROCESSING_SONYARW2_DELTATOVALUE - show possible posterization areas;

Canon/Nikon small RAW (YCC) decoding flags (do not use both at same time):

  • LIBRAW_PROCESSING_SRAW_NO_RGB - disable YCC to RGB conversion
  • LIBRAW_PROCESSING_SRAW_NO_INTERPOLATE - disable missing color values interpolation

Foveon processing flags:

  • LIBRAW_PROCESSING_FORCE_FOVEON_X3F - use X3F tools for foveon processing even if compiled with Demosaic Packs GPL2
int sony_arw2_posterization_thr
If LIBRAW_PROCESSING_SONYARW2_DELTATOVALUE used for arw2_options, sets the level to suppress posterization display in shadows.
float coolscan_nef_gamma;
Gamma value for Coolscan NEF decoding (no way to get if from file, it should be set by calling application).
char p4shot_order[5];
Shot order for Pentax 4shot files. Default is "3102".

Structure libraw_decoder_info_t: RAW decoder name and data format

This structure describes RAW format decoder name and data format:

const char *decoder_name
Decoder function name
unsigned decoder_flags
Decoder data format. See list of LibRaw_decoder_flags for details.

Stucture libraw_processed_image_t - result set for dcraw_make_mem_image()/dcraw_make_mem_thumb() functions

Structure libraw_processed_image_t is produced by call of dcraw_make_mem_image()/dcraw_make_mem_thumb() and contains in-memory image of interpolated data or thumbnail.
Data fields:

LibRaw_image_formats type
This field records type of data, containing in remaining fields of structure.
  • LIBRAW_IMAGE_BITMAP - structure contains RGB bitmap. All metadata fields (see below) are valid and describes image data.
  • LIBRAW_IMAGE_JPEG - structure contain in-memory image of JPEG file. Only type, data_size and data fields are valid (and nonzero);
ushort height,width
Image size (in pixels). Valid only if type==LIBRAW_IMAGE_BITMAP.
ushort colors, bits
Number of colors components (1 or 3) and color depth in bits (8 or 16). These fields are valid only if type==LIBRAW_IMAGE_BITMAP.
ushort gamma_corrected
Is bitmap data gamma-corrected (always 1 for 8-bit data, may be 0 or 1 for 16-bit). Valid only if type==LIBRAW_IMAGE_BITMAP.
unsigned int data_size
Size of data field (in bytes). For bitmap image equal to (height*width*colors * (bits/8)). For JPEG image - exact JPEG size (i.e. extracted thnumbnail size + JPEG header + EXIF header).
unsigned char data[]
Data array itself. Should be interpreted as RGB triplets for bitmap type and as JPEG file for JPEG type.

Input abstraction layer

RAW data input (read) in LibRaw implemented by calling methods of object derived from LibRaw_abstract_datastream abstract class. Full list of methods is described in href="API-CXX.html#datastream">C++ API reference.

There is two ready to use implementations of datastream objects:

LibRaw user can create own datastream object derived from LibRaw_abstract_datastream . For example, such object may implement reading RAW data directly from camera (by remote interface). LibRaw can use these objects via LibRaw::open_datastream() interface.

Datastreams can be used either via LibRaw::open_datastream() call (in this case datastream object should be created an maintained by user) or via LibRaw::open_file() and LibRaw::open_buffer() shortcuts.

Only C++ API users may use object-oriented interface and implement own input interfaces. For C API users only built-on libraw_open_file()/libraw_open_buffer() shortcuts are avaliable.

Data fields

Definition:

	class LibRaw_abstract_datastream {...protected: LibRaw_abstract_datastream *substream;}

Description: Ojects derived from LibRaw_abstract_datastream always contains pointer to secondary data stream (substream). This substream initialized internally when needed (really used only for Sony RAW data) and used for temporary switch input stream to temporary memory buffer allocated internally in LibRaw.

Substream usage details described more precisely in own datastream objects creation guide .

Constants

enum LibRaw_errors: Error Codes

All functions returning integer numbers must return either errno or one of the following error codes (see also error code conventions ).

Fatal errors (return of such an error code implies that file processing has to be terminated, since the state of data structures is unknown).

LIBRAW_UNSUFFICIENT_MEMORY
Attempt to get memory from the system has failed.
All allocated resources will be freed, recycle() will be called, and the LibRaw object will be brought to the state "right after creation."
LIBRAW_DATA_ERROR
A fatal error emerged during data unpacking.
All allocated resources will be freed, recycle() will be called, and the LibRaw object will be brought to the state "right after creation."
LIBRAW_IO_ERROR
A fatal error emerged during file reading (premature end-of-file encountered or file is corrupt).
All allocated resources will be freed, recycle() will be called, and the LibRaw object will be brought to the state "right after creation."
LIBRAW_CANCELLED_BY_CALLBACK
Processing cancelled due to calling application demand (by returning nonzero code from progress callback ).
All allocated resources will be freed, recycle() will be called, and the LibRaw object will be brought to the state "right after creation."
LIBRAW_BAD_CROP
The incorrect cropping coordinates are set via params.cropbox[]: the left-top corner of cropping rectangle is outside the image. The processing will be cancelled, all allocated resources will be freed, recycle() will be called, and the LibRaw object will be brought to the state "right after creation."

Non-Fatal Errors

LIBRAW_SUCCESS=0
No error; function terminated successfully.
LIBRAW_UNSPECIFIED_ERROR
An unknown error has been encountered. This code should never be generated.
LIBRAW_FILE_UNSUPPORTED
Unsupported file format (attempt to open a RAW file with a format unknown to the program).
LIBRAW_REQUEST_FOR_NONEXISTENT_IMAGE
Attempt to retrieve a RAW image with a number absent in the data file (only for formats supporting storage of several images in a file).
LIBRAW_OUT_OF_ORDER_CALL
API functions have been called in wrong order (e.g., unpack() before open_file() ) or the previous stage has ended with an error (e.g., unpack() is called after open_file() has returned an error).
LIBRAW_NO_THUMBNAIL
Returned upon an attempt to retrieve a thumbnail from a file containing no preview.
LIBRAW_UNSUPPORTED_THUMBNAIL
RAW file contains a preview of unsupported format.

enum LibRaw_decoder_flags - RAW data format description

Depending of capabilities of given data format, the buffer with RAW data may have different layouts:

LIBRAW_DECODER_HASCURVE
This flag is set if decoder uses RAW tone curve and curve data may be modified before call to decoder (i.e. curve values are not read or calculated within decoder).
LIBRAW_DECODER_SONYARW2
This flag is set if file format is Sony ARW2.3, so sony_arw2_options is applicable.
LIBRAW_DECODER_TRYRAWSPEED
This flag is set if file format is (possibly) supported by RawSpeed library, so unpack() will try to use it.
LIBRAW_DECODER_FIXEDMAXC
Do not use automated maximum calculation for this data format.
LIBRAW_DECODER_OWNALLOC
Decoder allocates data, no need to pass allocated memory to decoder.

enum LibRaw_progress: Current State of LibRaw Object

LibRaw::imgdata.progress_flags contains a bit mask describing all stages of file processing that have already been performed.

File opening and RAW data extraction phase.

LIBRAW_PROGRESS_START=0
Object just created, no processing carried out.
LIBRAW_PROGRESS_OPEN
File to be processed has been opened.
LIBRAW_PROGRESS_IDENTIFY
Data identification performed, format recognized, metadata extracted.
LIBRAW_PROGRESS_SIZE_ADJUST
Data sizes adjusted (for files that require such adjustment, namely, certain files from Kodak cameras).
LIBRAW_PROGRESS_LOAD_RAW
RAW data loaded.

The following flags are set during usage of image processing that has been taken from dcraw.

LIBRAW_PROGRESS_RAW2_IMAGE
imgdata.image array allocated and filled with data.
LIBRAW_PROGRESS_REMOVE_ZEROES
Zero values removed for cameras that require such removal (Panasonic cameras).
LIBRAW_PROGRESS_BAD_PIXELS
Bad (dead) pixels removed.
LIBRAW_PROGRESS_DARK_FRAME
Dark frame subtracted from RAW data.
LIBRAW_PROGRESS_FOVEON_INTERPOLATE
Interpolation for cameras with a Foveon sensor performed.
LIBRAW_PROGRESS_SCALE_COLORS
White balance performed.
LIBRAW_PROGRESS_PRE_INTERPOLATE
Image size reduction (for the half_size mode) performed, as well as copying of 2nd green channel to the 1st one in points where the second channel is present and the first one is absent.
LIBRAW_PROGRESS_INTERPOLATE
Interpolation (debayer) performed.
LIBRAW_PROGRESS_MIX_GREEN
Averaging of green channels performed.
LIBRAW_PROGRESS_MEDIAN_FILTER
Median filtration performed.
LIBRAW_PROGRESS_HIGHLIGHTS
Work with highlights performed.
LIBRAW_PROGRESS_FUJI_ROTATE
For images from Fuji cameras, rotation performed (or adjust_sizes_info_only() called).
LIBRAW_PROGRESS_FLIP
Dimensions recalculated for images shot with a rotated camera (sizes.iwidth/sizes.iheight swapped).
LIBRAW_PROGRESS_CONVERT_RGB
Conversion into output RGB space performed.
LIBRAW_PROGRESS_STRETCH
Image dimensions changed for cameras with non-square pixels.
LIBRAW_PROGRESS_STAGE17 - LIBRAW_PROGRESS_STAGE27
Reserved for possible appearance of other processing stages.

The following flags are set during loading of thumbnails.

LIBRAW_PROGRESS_THUMB_LOAD Thumbnail data have been loaded (for Kodak cameras, the necessary conversions have also been made). LIBRAW_PROGRESS_TRESERVED1 - LIBRAW_PROGRESS_TRESERVED3 Reserved for possible future processing stages.

enum LibRaw_whitebalance_code - names for standard light sources

LIBRAW_WBI_lightsource_name, where name and value are standard EXIF light sources.

enum LibRaw_camera_mounts - codes for camera mounts

Constant name (e.g. LIBRAW_MOUNT_Leica_SL) speaks for itself

enum LibRaw_runtime_capabilities - libraw capabilities set at build

  • LIBRAW_CAPS_RAWSPEED - compiled with RawSpeed
  • LIBRAW_CAPS_DNGSDK - compiled with Adobe DNG SDK
  • LIBRAW_CAPS_DEMOSAICSGPL2 - compiled with Demosaic Pack GPL2
  • LIBRAW_CAPS_DEMOSAICSGPL3 - compiled with Demosaic Pack GPL3

enum LibRaw_thumbnail_formats: Thumbnail Data Formats

Thumbnail data format is written in the imgdata.thumbnail.tformat data field.
Presently LibRaw knows about four thumbnail formats, among which two are unpacked:

LIBRAW_THUMBNAIL_UNKNOWN
Format unknown or thumbnail not yet read.
LIBRAW_THUMBNAIL_JPEG
The thumbnail buffer contains a JPEG file (read from the RAW file "as is," without any manipulations performed on it).
LIBRAW_THUMBNAIL_BITMAP
The thumbnail buffer contains the gamma-adjusted RGB bitmap (for Kodak cameras, the gamma correction is performed with allowance for maximum values and the white balance is set in accordance with the camera settings).
In this format, each pixel of the image is represented by a 8-bit RGB triplet.
LIBRAW_THUMBNAIL_LAYER
Data format is presently recognized upon opening of RAW file but not supported: not unpacked into LibRaw::unpack_thumb.
LIBRAW_THUMBNAIL_ROLLEI
Data format is presently recognized upon opening of RAW file but not supported: not unpacked into LibRaw::unpack_thumb.

Nonstandard Situations (Warnings) during RAW Data Processing

Some suspicious situations emerging during image processing are not fatal but may affect the result of data retrieval or postprocessing. Such states are indicated by setting a bit in the imgdata.process_warnings field.

LIBRAW_WARN_FOVEON_NOMATRIX
Only for cameras with Foveon: extraction of one of data matrices has failed.
LIBRAW_WARN_FOVEON_INVALIDWB
Only for cameras with Foveon: extraction of white balance data has failed.
LIBRAW_WARN_BAD_CAMERA_WB
Postprocessing must use white balance of the camera but this balance is not suitable for use.
LIBRAW_WARN_NO_METADATA
Only for cameras where the metadata are taken from an external JPEG file: metadata extraction has failed.
LIBRAW_WARN_NO_JPEGLIB
Only for P&S Kodak cameras: data in JPEG format. At the same time, open_file() will return LIBRAW_FILE_UNSUPPORTED.
LIBRAW_WARN_NO_EMBEDDED_PROFILE
(only if LCMS support compiled in). Caller set embedded input profile use, but no such profile exists in RAW.
LIBRAW_WARN_NO_INPUT_PROFILE
(only if LCMS support compiled in). Error when opening input profile ICC file.
LIBRAW_WARN_BAD_OUTPUT_PROFILE
(only if LCMS support compiled in). Error when opening output profile ICC file.
LIBRAW_WARN_NO_BADPIXELMAP
Error when opening bad pixels map file.
LIBRAW_WARN_BAD_DARKFRAME_FILE
Error when opening dark frame file.
LIBRAW_WARN_BAD_DARKFRAME_DIM
Dark frame file either differs in dimensions from RAW-file processed, or have wrong format. Dark frame should be in 16-bit PGM format (one can generate it using simple_dcraw -4 -D).
LIBRAW_WARN_RAWSPEED_PROBLEM
Problems detected in RawSpeed decompressor. The image data processed by LibRaw own decoder.
LIBRAW_WARN_RAWSPEED_UNSUPPORTED
This file not supported by RawSpeed (although compatible decoder exists).
LIBRAW_WARN_RAWSPEED_PROCESSED
Not warning, but information. The file was decoded by RawSpeed.
LIBRAW_WARN_FALLBACK_TO_AHD
Incorrect/unsupported user_qual was set, AHD demosaic used instead.

enum LibRaw_image_formats - possible types of data, contains in libraw_processed_image_t structure

type field of libraw_processed_image_t structure may have one of these values:

LIBRAW_IMAGE_BITMAP
The structure contains RGB-bitmap, metadata described in other fields of libraw_processed_image_t.
LIBRAW_IMAGE_JPEG
libraw_processed_image_t structure contains JPEG image (in memory). Only data_size field is meaningful.

[back to Index]

Never forget to clean JavaScript JS files before a web project goes live.

The free JavaScript formatter will handle dirty JS codes.

LibRaw-0.18.8/doc/API-notes.html000077500000000000000000000400311324423227700161710ustar00rootroot00000000000000

LibRaw: General Notes on API[back to Index]

LibRaw: General Notes on API

Contents

  1. LibRaw editions
  2. Error Code Conventions and Error Handling
  3. Nonstandard Situations That Are Not Errors
  4. Input Layer Abstraction
  5. Thread Safety
  6. The Use of C++
  7. Parameters of the LibRaw::imgdata.params Structure Affecting the Behavior of open_file/unpack/unpack_thumb
  8. Memory Usage
    1. Stack Usage
    2. Dynamic Memory Management
    3. Dynamic Memory Usage
      1. Memory Buffer for the RAW Image
      2. Memory for the Postprocessed Image
      3. Memory for the Decoded Thumbnail
      4. Memory for the Decoded ICC Profile
      5. Memory for RAW Unpacking
      6. Memory for Postprocessing
      7. Memory for File Writing
      8. Unpacking into memory buffer
  9. Incompatibilities with dcraw
    1. Automatic maximum search/brightness adjustment
    2. Processing of Thumbnails from Kodak cameras

LibRaw Versions

Since version 0.9, there is only one LibRaw variants. Older versions have three separate editions (normal, -Lite and -Commercial versions).

Error Code Conventions and Error Handling

The following conventions concern the returned errors:

  1. All functions that can return an error code have integer type of return data.
  2. If there is no error, the return value is 0 (LIBRAW_SUCCESS).
  3. If an error has happened in a system call, the return value is errno (a positive number), which can be analyzed using strerror() or similar means.
  4. All LibRaw's own error codes are negative; each of these errors belongs to one of two types:
    Non-fatal errors
    Non-fatal errors do not forbid execution of other functions in the processing succession (e.g., unpack_thumb() can easily return the code corresponding to "preview is absent" but this does not prevent further call of unpack().
    Fatal errors
    In the case of fatal errors (memory shortage, input data error, data unpacking failure), the current stage of processing is terminated and all allocated resouces are freed.
    If an attempt to continue processing is made, all subsequent API calls will return the LIBRAW_OUT_OF_ORDER_CALL error.
    At the same time, the LibRaw instance in which a fatal error has occurred can process the next RAW files in the usual way (by calling open_file() (or other input methods), then unpack(), etc.).
  5. The macro LIBRAW_FATAL_ERROR(error code) checks if an error is fatal or not.
  6. The error codes are listed and deciphered here.

Nonstandard Situations That Are Not Errors

If the program has encountered a nonstandard situation that does not prevent retrieval of some data from a file, it sends a signal by setting the corresponding bit in imgdata.process_warnings. The possible types of warnings are listed and deciphered here.

Input Layer Abstraction

LibRaw uses objects derived from LibRaw_abstract_datastream for data input. Semantics of these objects is similar to 'file with arbitrary seek' object: both read and seek operations are used.

Some RAW formats requires temporary switch to another data stream created on top on memory buffer for metadata read. Methods for doing so are implemented in base class LibRaw_abstract_datastream by internal data field substream. Look into source code of LibRaw_file_datastream class in libraw/libraw_datastream.h file for more details.
When implementing own datastream classes, you need to take substream into account and pass control to methods of this field if it is active (not NULL).

If datastream implementaton knows name of input file, it should provide fname() call. This name will be used in error callbacks and in guessing name of JPEG file with metadata (for RAW files with external metadata).

For external metadata support input class should implement subfile_open()/subfile_close() methods. .
Sample of these methods implementation may be found in LibRaw_file_datastream class (look into libraw/libraw_datastream.h file for details).

Thread safety

Thread safety is ensured if a LibRaw object is created and used within one thread. At the same time, the number of threads (each with its own LibRaw object) is not limited in any way (except by memory requirements).

If a LibRaw object is created in one execution thread and used in another, external synchronization is necessary.

There is two libraries under Unix enviroment (Linux/FreeBSD/MacOS): libraw_r.a (thread-safe) and libraw.a (single-threaded, slightly faster).

Thread-safe library version stores intermediate unpacker data into LibRaw class data. So, several copies of LibRaw, working in parallel, is possible.

Not thread-safe library uses global variable for intermediate data store which is faster but not reenterant. This non-thread-safe library still may be used in multi-threaded apps, but only if exactly one LibRaw class copy exists in program.

Windows version is similar to multi-threaded Unix one.

The Use of C++

Exception situations within LibRaw are handled using the C++ exception mechanism. All exceptions are caught inside the library functions and should not penetrate outside.

Memory is allocated/freed using functions malloc(calloc)/free rather than new/delete.

If C API is used, references to C++ calls new/delete still remain, and so linking with libstdc++(Unix)/....(Windows) is necessary.

Parameters of the LibRaw::imgdata.params Structure Affecting the Behavior of open_file/unpack/unpack_thumb

Most data fields of structure LibRaw::imgdata.params affect only data postprocessing, but there are some exceptions, which have been inherited by the current version of LibRaw from/ dcraw source texts (these dependences will be gradually removed).

imgdata.params.use_camera_matrix and imgdata.params.use_camera_wb
These fields affect loading of RAW data for cameras with a color matrix.
Attention! If parameter imgdata.params.use_camera_matrix is not set by the user, it is copied from imgdata.params.use_camera_wb at the stage of file opening.
imgdata.params.user_flip
If this parameter is greater than or equal to zero, assignment imgdata.sizes.flip = imgdata.params.user_flip is performed at the open_file() stage.
imgdata.params.shot_select
This parameter makes it possible to select the number of the extracted image for data formats in which storage of several RAW images in one data file is possible.
imgdata.params.half_size
Affects RAW data loading for Phase One and Sinar backs. Also, it this parameter is set then image bitmap will be reduced by half in each dimension. In later case, all 4 components of bitmap will be filled during data extraction phase.
imgdata.params.threshold, imgdata.params.aber
If these parameters used, then half-sized bitmap will be used for data unpacking. See above for details.
imgdata.params.use_camera_wb
Affects loading of white balance matrix for Leaf backs.

Memory Usage

Stack Usage

An instance of the LibRaw class has its own size about 100 Kb; if constructions like LibRaw imageProcessor; are used, this memory is stack-allocated.

Methods of class LibRaw (and C API calls) may allocate up to 130-140 Kb of data on the stack (to place auto variables) during their work.

Thus, the work of one LibRaw instance may require about 250 Kb of stack memory. This is not a problem for most contemporary architectures. However, when working in a multithreaded environment, one should not forget to allocate a sufficient amount of memory for the thread stack.

In the case of dynamic allocation (LibRaw *iProcessor = new LibRaw;), the requirements to stack memory will decrease by 100 Kb, which is the size of a class instance). If C API is used, the LibRaw instance is allocated dynamically.

Dynamic Memory Management

LibRaw keeps record of all allocated dynamic memory blocks; in the case of an exceptional situation (fatal error), they are all freed. The code for keeping this record is fairly primitive and not designed to consider allocation of many blocks (in the normal situation, allocation takes place from 2 to 6 times during file processing); this fact should be taken into account by developers trying to add new methods to LibRaw.

Dynamic Memory Usage

LibRaw uses dynamic memory

  • for the decoded image;
  • for the decoded thumbnail;
  • for the postprocessed image;
  • for the ICC profile retrieved from the RAW file (if available);
  • for temporary data at the stage of RAW file unpacking;
  • for temporary data at the stage of postprocessing and result output;
  • for reading of the RAW source file (only under Win32).

Memory buffer for the RAW image

Decoded RAW data are stored:

  • one 16-bit value per pixel for "bayer" images. The masked pixels (black or dark or masked frame) are stored with image data.
  • Four 16-bit values for full-color images (Foveon, Linear DNG, Canon sRAW etc.).

The buffer for RAW data is allocated by unpack() call and freeed upon calling recycle().

Memory for the Postprocessed Image

On postprocessing stage each pixel contains four 16-bit values, one for each possible color channel (some sensors are actually 4-color).

The buffer for the decoded image is allocated upon calling raw2image() or dcraw_process()

The buffer freed upon calling recycle() or free_image() calls.

Memory for the Decoded Thumbnail

Memory for the thumbmail is allocated upon calling unpack_thumb() and freed upon calling recycle(). The size of the allocated buffer is precisely adjusted to the thumbnail size, i.e., up to several Mb.

Memory for the Decoded ICC Profile

Memory for the ICC profile is allocated upon calling unpack_profile() and freed upon calling recycle(). The size of the allocated buffer is precisely adjusted to the ICC profile size, i.e., up to several hundred Kb.

Memory for RAW Unpacking

Memory for temporary buffer needed during RAW data unpacking may be allocated during the work of unpack() and freed before completion of this function. The sizes of the allocated buffers are small, up to tens of Kb.

Memory for Postprocessing

During image postprocessing (inherited from dcraw), memory for the histogram (128 Kb) is allocated. This memory is allocated upon calling dcraw_process() and freed upon calling recycle().

In addition, during the work of dcraw_process() and during the usage of some available possibilities, like

  • rotation of images from FUJI cameras;
  • correction of chromatic aberrations;
  • image size changes (including correction of non-square pixels);
  • highlight recovery;

a temporary buffer with the size equal to the size of the resultant image (6-8 bytes per pixel for various processing stages) will be allocated. As soon as the intermediate substage of processing is completed, the buffer with the previous copy of the image will be freed.
If postprocessing is not used, then temporary buffers are not allocated.

Memory for File Writing

Upon calling dcraw_ppm_tiff_writer(), memory for a single row of the output image is allocated. The allocated memory is freed before the end of this call.

Unpacking into memory buffer

Functons dcraw_make_mem_image() dcraw_make_mem_thumb() (and complementary calls in C-API) allocates memory for entire output datasets (full RGB bitmap and thumbnail, respectively). Calling function should free() this memory themself.

Incompatibilities with dcraw

Automatic maximum search/brightness adjustment

Many camera formats really use less data range, than possible by format nature (bit count). If data maximum estimated incorrectly (too low) this may resuls in colored highlights ('pink clouds') because of data cut at wrong level.

To prevent this, LibRaw uses real data maximum from current file if this maximum is larger than format maximum multiplied by imdata.params.adjust_maximum_thr value (default is 0.75).

To turn off this feature (and repeat dcraw.c pink clouds) set imdata.params.adjust_maximum_thr to 0.0

Processing of Thumbnails from Kodak cameras

In some Kodak cameras, the preview (thumbnail) is stored in the form of uncorrected image. During its extraction using dcraw -e, the white balance, color conversion, and other settings are the same as those used for extraction of the main RAW data (including defect removal and dark frame subtraction, which is erroneous, since the image size is different).
In LibRaw::unpack_thumb() calls, the white balance taken from the camera ("as shot") is used and no settings from imgdata.params are considered.

For all other cameras, thumbnails are extracted "as is," without any color conversions, both in dcraw and in LibRaw.

[back to Index]

LibRaw-0.18.8/doc/API-overview.html000077500000000000000000000053531324423227700167170ustar00rootroot00000000000000 Overview of LibRaw API (C++) [back to Index]

Overview of LibRaw API (C++)

General Remarks

  1. The entire processing is carried out by an instance of the LibRaw class, which is an image processor.
  2. One image processor can simultaneously process only one data source file, but consecutive processing of any number of files is possible.
  3. There may be several simultaneously working image processors in a software program (e.g., in different threads), although one should remember that each image processor may require much memory.
  4. Reading of source data from the RAW file requires virtually no customization (see API Notes for exceptions to this rule).
  5. All data extracted from the RAW file are accessible through data fields of the image processor (LibRaw class instance).
  6. Although LibRaw is not intended for RAW data postprocessing, the library includes calls that enable complete emulation of the dcraw utility.
  7. All customization for the processing is performed via data fields of the LibRaw class.

Brief Demonstration

The example below contains no error processing for the sake of brevity.

#include "libraw/libraw.h"
int process_image(char *file)
{
        // Let us create an image processor
        LibRaw iProcessor;

        // Open the file and read the metadata
        iProcessor.open_file(file);

        // The metadata are accessible through data fields of the class
        printf("Image size: %d x %d\n",iProcessor.imgdata.sizes.width,iProcessor.imgdata.sizes.height);

        // Let us unpack the image
        iProcessor.unpack();

        // Convert from imgdata.rawdata to imgdata.image:
        iProcessor.raw2image();

        // And let us print its dump; the data are accessible through data fields of the class
        for(i = 0;i lt; iProcessor.imgdata.sizes.iwidth *  iProcessor.imgdata.sizes.iheight; i++)
           printf("i=%d R=%d G=%d B=%d G2=%d\n",
                        i,
                        iProcessor.imgdata.image[i][0],
                        iProcessor.imgdata.image[i][1],
                        iProcessor.imgdata.image[i][2],
                        iProcessor.imgdata.image[i][3]
                );

        // Finally, let us free the image processor for work with the next image
        iProcessor.recycle();
}
[back to Index] LibRaw-0.18.8/doc/Install-LibRaw.html000077500000000000000000000160701324423227700172240ustar00rootroot00000000000000 LibRaw Compilation and Installation [back to Index]

LibRaw Compilation and Installation

LibRaw is distributed in the form of source codes. For further use, they should be compiled (and, if desired, placed into system folders with libraries and include-files).

Unix Systems (FreeBSD, Linux, Mac OS X)

To build the library, you will need a working C++ compiler (gcc ver. 3.x or 4.x will be OK; other compilers have not been tested) and the make utility. No other libraries or utilities are required.

LibRaw has been tested on 32- and 64-bit Unix systems working on x86- (and AMD64-) compatible processors. Building and work on other architectures have not been tested.

Compilation of Library and Examples

Unpack the downloaded distribution package. If you wish to use LibRaw-demosaic-pack(s), unpack these archives too:

        tar xzvf LibRaw-X.YY.tar.gz
        tar xzvf LibRaw-demosaic-pack-GPL2-X.YY.tar.gz
        tar xzvf LibRaw-demosaic-pack-GPL3-X.YY.tar.gz
        tar xzvf LibRaw-X.YY.tar.gz
    

Go to LibRaw directory and run ./configure and make:

cd LibRaw-X.YY
./condigure # with optional args
make
    

As a result, you will compile

  • Library libraw.a in the lib/ folder
  • Examples in the bin/ folder (source codes of examples are in the samples/ folder).

In the current version, only static libraries are built:

  • libraw.a: non-thread-safe version
  • libraw_r.a: thread-safe

Build parameters

./configure script have some non-standard parameters:

--enable-openmp
--disable-openmp
Enable/disable OpenMP support if compiler supports it. OpenMP is enabled by default.
--enable-lcms
--disable-lcms
Enable/disable LCMS color engine support. If enabled, ./configure will try to find lcms library. Both LCMS-1.x and LCMS-2.x are supported LCMS support is enabled by default
--enable-examples
--disable-examples
Enables/disables examples compilation and installation. Enabled by default
--enable-demosaic-pack-gpl2
--enable-demosaic-pack-gpl2=FOLDERNAME
--enable-demosaic-pack-gpl2=no
--disable-demosaic-pack-gpl2
Enables/disables support of additional demosaic methods licensed under GPL2 You need to download and unpack LibRaw-demosaic-pack-GPL2 archive to use this feature.
./configure will try to find demosaic pack in:
  • If folder is specified via --enable-demosaic-pack-gpl2=FOLDERNAME command-line option, then only this folder will be checked.
  • If no folder is specified in --enable-demosaic-pack-gpl2 switch:
    • ./LibRaw-demosaic-pack-GPL2 (in LibRaw folder)
    • ../LibRaw-demosaic-pack*GPL2* - upper level folder
    If several ../LibRaw-demosaic-pack*GPL2* folders exists in upper level catalog, then ./configure will NOT use any of them due of ambiguity. Specify exact folder name in this case using --enable-demosaic-pack-gpl2=FOLDERNAME
--enable-demosaic-pack-gpl3
--enable-demosaic-pack-gpl3=FOLDERNAME
--enable-demosaic-pack-gpl3=no
--disable-demosaic-pack-gpl3
Same as above, but for GPL3-licensed demosaic pack.

Installation and Usage

To install the library, run

    sudo make install
    

It will place the libraries in /usr/local/lib, the include-files in /usr/local/include (subfolder of libraw) and LibRaw samples to /usr/local/bin. You can override installation path by using ./configure script.
To use LibRaw, add the following parameters to the compiler call (when building your own projects):

  • Path to include-files: -I/usr/local/include
  • Path to libraries: -L/usr/local/lib
  • Library: -lraw (ordinary version) or -lraw_r (thread-safe version).

Windows: Building under Cygwin

Building and installation are completely similar to building and installation under Unix systems.

Windows: Native Building

Building under Windows has three steps:

  • Unpack the distribution package (if you have got no tar+gzip, take the LibRaw distribution package in the .ZIP format) and go to folder LibRaw-X.YYY.
  • Set the environment parameters so that the compiler/linker would find the libraries and include-files. For Visual C++, this is done by running vcvars32.bat.
  • Run
    nmake -f Makefile.msvc

If all paths are set correctly and the include-files/libraries have been found, then the following will be compiled:

  • Library libraw_static.lib in folder lib
  • Dynamic library bin/libraw.dll and linking library for it lib/libraw.lib
  • Examples in folder bin/.

Only the thread-safe library is built under Win32, but it can be used with non-threaded applications as well. All examples are linked with the dynamic library (DLL); if static linking is necessary, one should link applications with library libraw_static.lib and set the preprocessor option /DLIBRAW_NODLL during compilation.

Windows-version compiles without LCMS support for now.

During building of DLL, all public functions are exported; further, the exported subset may be reduced.

Unfortunately, paths to include/ libraries depend on the way Visual C (or other compiler) is installed; therefore, it is impossible to specify some standard paths in Makefile.msvc.

Windows Installation

No installation under Windows is supported. It is assumed that all DLLs will be supplied together with the software using them (and this software will perform the installation). Accordingly, in building of programs using LibRaw, the paths to libraries, DLLs, and include-files should be specified manually.

[back to Index] LibRaw-0.18.8/doc/Samples-LibRaw.html000077500000000000000000000265071324423227700172300ustar00rootroot00000000000000

LibRaw: Usage Examples[back to Index]

LibRaw: Usage Examples

Overview of Examples in the Distribution Package (samples/*)

The LibRaw package contains several examples illustrating the use of this library. Their source codes are located in the samples/ folder, and after library build they will be in the bin/ folder:

  • raw-identify The only LibRaw call it uses is open_file(); further code prints the values of the fields of the imgdata structure. The output of raw-identify (without switches) is virtually identical to the output of dcraw -i.
    raw-identify -v provides data similar to dcraw -i -v and also lot of additional metadata is dumped too
    Command line key -u shows unpacking function name, while -u -f prints function name and masked are sizes.
    raw-identify -w will print white balance tables stored in RAW file.
  • simple_dcraw A simple "emulation" of dcraw reproducing the behavior of dcraw [-D] [-e] [-v] [-T]. The result of its work must be binary identical to the result produced by a dcraw run with relevant keys. A simplified version of this example is considered below.
    -B command-line switch turns on use of open_buffer() API call used via mmap() of input file (Unix only).
  • dcraw_half Demonstrates the use of C API. The example emulates the behavior of dcraw -h (no other control parameters can be specified in this example). The result of its work must be binary identical to the results produced by dcraw -h.
  • dcraw_emu Complete emulation of dcraw (except for keys -D -d -P -K -i -e, which are considered in other usage examples). Of most interest is processing of command line keys (copied from dcraw). The result of its work must be binary identical to the results produced by dcraw with the same command line keys.

    This sample supports additional command-line parameters absent in original dcraw:

    -mmap
    Use open_buffer() interface. Buffer prepared by mmap() call. This option not supported under Win32.
    -meme
    Use open_buffer() interface. Buffer prepared by malloc()+read() calls.
    -c float-value
    This key sets params.adjust_maximum_thr parameter.
    Use -c 0 to completely disable automatic maximum calculation.
    Default value: 0.75
    -timing
    Turns on detailed timing print.
    -G
    Turns on "green_matching" mode to suppress color mazes on cameras with different green channels.
    -B x y w h
    Crops output to rectangle with width w, height h and x,y coordinates of left upper corner. All coordinates applied before any image rotation.
    -F
    Will use FILE I/O (bigfile_datastream) instead on standard LibRaw_file_datastream.
    -dcbi N
    Sets number of additional DCB-demosaic iterations (option valid only for -q 4, i.e. for DCB demosaic).
    -dcbe
    Turns on DCB color enhance mode (only for DCB demosaic, -q 4).
    -eeci
    Turns on EECI refine (only for mixed VCD/AHD -q 8)
    -esmed N
    Number of passes of edge-sensitive median filter for VCD+AHD demosaic.
    -acae r b
    Turns on chromatic aberration suppression. r and b parameters are amount of red and blue axis correction respectively. For automatic correction use -acae 0 0.
    -aline l
    Turns on banding suppression. l is the correction amount, useable range is from 0.001 to 0.02, typical value is 0.005.
    -aclean l c
    Turns on impulse noise suppression. l and c are luminocity and chrominance suppression values, respectively. Useable range for both is 0.005-0.05 and typical value is 0.01.
    -agreen g
    Turns on green channels equalization on uniform surfaces. g is the algorithm sensitivity with useable range 0.01-0.1 and typical value 0.03.
    -aexpo e p
    Turns on exposure correction. e is exposure shift in linear scale from 0.25 (darken 2 stops) to 8.0 (lighten 3 stops). p is highlights preservation amount from 0.0 (no preservation, full clipping) to 1.0 (full preservation, S-like curve in highlights).
    -apentax4shot
    Will merge 4 frames from Pentax 4-shot RAWs
    -apentax4shotorder abce
    Order of frames in pentax 4-shot files (default is 3102)
    -dbnd r g b g
    Turns on debanding code
    -mmap
    Use mmap + memory IO instead of file IO (unix only)
    -disars
    Disable RawSpeed library (if compiled with this library)
    -disinterp
    Do not run interpolation step
    -dsrawrgb1
    Disable YCbCr to RGB conversion for sRAW (Cb/Cr interpolation enabled)
    -dsrawrgb2
    Disable YCbCr to RGB conversion for sRAW (Cb/Cr interpolation disabled)
    -disadcf
    Do not use dcraw Foveon code even if compiled with demosaic-pack-GPL2
  • half_mt Emulation of dcraw -h. It "understands" the following keys: -a (automatic white balance over the entire image), -w (white balance of the camera), -T (output in the tiff format), and -J n (number of parallel threads launched for image processing).
    On multiprocessor/multicore computers, the speed gain is notable in the case of mass processing. On a Win32 machine, the example is assembled from the initial file half_mt_win32.c, since work with threads under Windows is fundamentally different and it it easier to copy simple source codes than write one complex code.
  • mem_image This sample uses dcraw_make_mem_image and dcraw_make_mem_thumb calls, than writes data in PPM format. Results should be identical with dcraw with same command-line options (options supported: -4, -1, -e, -h).
  • unprocessed_raw This sample extracts (mostly) unaltered RAW data including masked pixels data (on supported cameras). If black frame exists and black frame extraction is supported for given format, masked pixels data is added to resulting .TIFF file. Command line options: -q - be quiet, -A - autoscale data (integer multiplier), -g gamma-correction (gamma 2.2) for data (instead of precise linear one), -B turns on black level subtraction
  • 4channnels - splits RAW-file into four separate 16-bit grayscale TIFFs (per RAW channel).
    Command line switches:
    • -s N selects N-th image from RAW with multiple images
    • -g gamma correction (gamma 2.2)
    • -A values autoscale by auto-calculated integer factor
    • -B turn off black subtraction
    • -N no RAW curve
  • multirender_test - very simple example of multiple rendering on one file without reopen.
  • postprocessing_benchmark - will print timings of RAW processing steps

Example of docmode

Below we consider the samples/simple_dcraw.cpp example, which emulates the behavior of dcraw [-D] [-e][-v][-t]. To save space, let us assume that keys -t -v are always specified (to avoid comments on command line parsing) and there is always one parameter (name of file), which is the only one and always passed to the program.

int main(int ac, char *av[])
{
 int i, ret, verbose=0, output_thumbs=0;
 char outfn[1024],thumbfn[1024];
 // Creation of image processing object
 LibRaw RawProcessor;
 // The date in TIFF is written in the local format; let us specify the timezone for compatibility with dcraw
 putenv ((char*)"TZ=UTC");
// Let us define variables for convenient access to fields of RawProcessor
#define P1 RawProcessor.imgdata.idata
#define S RawProcessor.imgdata.sizes
#define C RawProcessor.imgdata.color
#define T RawProcessor.imgdata.thumbnail
#define P2 RawProcessor.imgdata.other
#define OUT RawProcessor.imgdata.params
 OUT.output_tiff = 1; // Let us output TIFF
 // Let us open the file
 if( (ret = RawProcessor.open_file(av[1])) != LIBRAW_SUCCESS)
 {
 fprintf(stderr,"Cannot open %s: %s\n",av[i],libraw_strerror(ret));
 // recycle() is needed only if we want to free the resources right now.
 // If we process files in a cycle, the next open_file()
 // will also call recycle(). If a fatal error has happened, it means that recycle()
 // has already been called (repeated call will not cause any harm either).
 RawProcessor.recycle();
 goto end;
 }
 // Let us unpack the image
 if( (ret = RawProcessor.unpack() ) != LIBRAW_SUCCESS)
 {
 fprintf(stderr,"Cannot unpack_thumb %s: %s\n",av[i],libraw_strerror(ret));
 if(LIBRAW_FATAL_ERROR(ret))
 goto end;
 // if there has been a non-fatal error, we will try to continue
 }
 // Let us unpack the thumbnail
 if( (ret = RawProcessor.unpack_thumb() ) != LIBRAW_SUCCESS)
 {
 // error processing is completely similar to the previous case
 fprintf(stderr,"Cannot unpack_thumb %s: %s\n",av[i],libraw_strerror(ret));
 if(LIBRAW_FATAL_ERROR(ret))
 goto end;
 }
 else // We have successfully unpacked the thumbnail, now let us write it to a file
 {
 snprintf(thumbfn,sizeof(thumbfn),"%s.%s",av[i],T.tformat == LIBRAW_THUMBNAIL_JPEG ? "thumb.jpg" : "thumb.ppm");
 if( LIBRAW_SUCCESS != (ret = RawProcessor.dcraw_thumb_writer(thumbfn)))
 {
 fprintf(stderr,"Cannot write %s: %s\n",thumbfn,libraw_strerror(ret));
 // in the case of fatal error, we should terminate processing of the current file
 if(LIBRAW_FATAL_ERROR(ret))
 goto end;
 }
 }
 // Data unpacking
 ret = RawProcessor.dcraw_process();
 if(LIBRAW_SUCCESS != ret ) // error at the previous step
 {
 fprintf(stderr,"Cannot do postprocessing on %s: %s\n",av[i],libraw_strerror(ret));
 if(LIBRAW_FATAL_ERROR(ret))
 goto end;
 }
 else // Successful document processing
 {
 snprintf(outfn,sizeof(outfn),"%s.%s", av[i], "tiff");
 if( LIBRAW_SUCCESS != (ret = RawProcessor.dcraw_ppm_tiff_writer(outfn)))
 fprintf(stderr,"Cannot write %s: error %d\n",outfn,ret);
 }
 // we don't evoke recycle() or call the desctructor; C++ will do everything for us
 return 0;
end:
 // got here after an error
 return 1;
}

[back to Index]

Use the free online HTML CSS JavaScript cleaner to tidy up the code for websites.

LibRaw-0.18.8/doc/Why-LibRaw.html000077500000000000000000000120121324423227700163550ustar00rootroot00000000000000

Purpose and Objectives[back to Index]

LibRaw Project Goals and Objectives

Contents

  1. Who May Be Interested in This Project
  2. Goals and Objectives
  3. LibRaw Support Principles

Who May Be Interested in This Project

The proposed project and the software products generated within this project are intended for

  • Developers of RAW converters, including current and new developments
  • Those willing to write their own graphic interface for RAW file processing
  • Developers and enthusiasts creating their own primary and auxiliary data processing algorithms, including
    • Interpolation (de-Bayer),
    • Noise reduction
    • White balance
    • Correction of aberrations and distortions
    • Color conversions (e.g., creation, editing and application of camera profiles )
    • RAW data analysis
    • Comparison of cameras and lenses
    • and so on...

Among the few existing implementations of RAW converters, those based on the dcraw utility by Dave Coffin are the most used. It is hard to find a more or less popular camera that is not supported by this utility; while the implementation of RAW data extraction in dcraw is of a very high quality.

However, developers and enthusiasts who use or are going to use dcraw for fulfilling the above-listed and similar objectives encounter a number of difficulties. First, the author of dcraw refuses to turn his product into a handy library, yet permitting anybody else to do so. Besides, dcraw contains a number of questionable features which may hinder its use without modifications, as well as instances of distortions in the photographic sense of it. As a result, once every several months, virtually all developers, part of them listed on the dcraw Web site, independently convert each subsequent release of the software into the library.

As for enthusiasts, the "entry cost" of verifying their own ideas and implementing their own algorithms is often unreasonably high: they have to either use the dcraw command line, thus being forced to use the unavoidable early processing stages, or understand the source code and maintain their own library based on it.

Thus, the inconveniences of dcraw make the developers' community quite small and halt further evolution and improvement of RAW format converters.

Goals and Objectives

We are going to create LibRaw in order to "get a library based on dcraw, only better". Thus:

  1. To "librarize" dcraw, i.e., to develop a stable and consistent API suitable for other applications (RAW converters, data analyzers, panorama stitchers, etc.).
  2. To divide processing into independent parts (groups of API calls)
    • Reading, decoding, and unpacking of RAW data: this is the main functionality of LibRaw
    • Data conversions: interpolation, white balance, etc: this part of LibRaw is frozen: we ported dcraw functionality (and several 3rd-party demosaics), but expect that library users will create own postprocessing code.
    • File output of the processing results. This part is very primitive, only tiff and ppm output is supported.
    The latter two groups of functions are maintained primarily for dcraw compatibility testing.
  3. To improve the procedures of RAW data retrieval and decoding (see below for details)
  4. To supply other developers with a "framework" (freeware and open-source), e.g., for experimenting with their own methods of RAW data processing (interpolation, noise reduction, white balance, etc.; some directions of the possible efforts are listed above), so that they could create their own GUI programs and interfaces without developing the entire RAW converter.
  5. To ensure easy modification for code synchronization with dcraw releases.

LibRaw Support Principles

  1. To reproduce the functionality of dcraw using its source code as the basis for our work; to achieve binary identity of results generated by dcraw and by LibRaw-based utilities, provided the same processing settings are used.
  2. To eliminate the shortcomings of dcraw.
  3. To monitor future improvements in dcraw (support of new cameras, error correction, use of better algorithms) and import them from dcraw to LibRaw.
  4. API modifications: the planned improvements will require extending of the API. Such changes will be introduced in the form of large change-sets, while the compatibility mode supporting older applications based on the legacy API set will be preserved as long as possible.

[back to Index]

LibRaw-0.18.8/doc/index.html000077500000000000000000000040231324423227700155420ustar00rootroot00000000000000 LibRaw: better dcraw (library)

LibRaw: A Better dcraw

LibRaw is a library for reading RAW files from digital photo cameras (CRW/CR2, NEF, RAF, DNG, MOS, KDC, DCR, etc.; virtually all RAW formats are supported). It pays special attention to correct retrieval of data required for subsequent RAW conversion.

The library is intended for embedding in RAW converters, data analyzers, and other programs using RAW files as the initial data.

Contents

  1. Copyright
  2. Purpose and Objectives
  3. Overview of LibRaw API (C++)
  4. Compilation and Installation
  5. Data Structures, Error Codes, and Constants
  6. C++ API
  7. C API
  8. Notes on API (error code conventions, memory usage)
  9. Examples

Copyright

LibRaw library, Copyright (C) 2008-2017 LibRaw LLC (info@libraw.org)
The library includes source code from
dcraw.c, Dave Coffin's raw photo decoder
Copyright 1997-2016 by Dave Coffin, dcoffin a cybercom o net

LibRaw is distributed for free under two different licenses:

You may use one of these licensing modes and switch between them.

LibRaw-0.18.8/export-dist.sh000077500000000000000000000007641324423227700156260ustar00rootroot00000000000000#!/bin/sh DEST=$1 VERSION=$2 if test x$VERSION = x ; then VERSION=`./version.sh` echo VERSION set to $VERSION fi if test -d $DEST ; then echo Using $DEST/$VERSION else echo Usage: $0 destination-dir exit 1 fi cd .. for dir in LibRaw LibRaw-demosaic-pack-GPL2 LibRaw-demosaic-pack-GPL3 do cd $dir git pull origin cd .. done for dir in LibRaw LibRaw-demosaic-pack-GPL2 LibRaw-demosaic-pack-GPL3 do cd $dir git archive --prefix=$dir-$VERSION/ $VERSION | (cd $DEST; tar xvf - ) cd .. done LibRaw-0.18.8/internal/000077500000000000000000000000001324423227700146125ustar00rootroot00000000000000LibRaw-0.18.8/internal/aahd_demosaic.cpp000066400000000000000000000515721324423227700200710ustar00rootroot00000000000000/* -*- C++ -*- * File: aahd_demosaic.cpp * Copyright 2013 Anton Petrusevich * Created: Wed May 15, 2013 * * This code is licensed under one of two licenses as you choose: * * 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 * (See file LICENSE.LGPL provided in LibRaw distribution archive for details). * * 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 * (See file LICENSE.CDDL provided in LibRaw distribution archive for details). * */ typedef ushort ushort3[3]; typedef int int3[3]; #ifndef Pnw #define Pnw (-1-nr_width) #define Pn (-nr_width) #define Pne (+1-nr_width) #define Pe (+1) #define Pse (+1+nr_width) #define Ps (+nr_width) #define Psw (-1+nr_width) #define Pw (-1) #endif struct AAHD { int nr_height, nr_width; static const int nr_margin = 4; static const int Thot = 4; static const int Tdead = 4; static const int OverFraction = 8; ushort3 *rgb_ahd[2]; int3 *yuv[2]; char *ndir, *homo[2]; ushort channel_maximum[3], channels_max; ushort channel_minimum[3]; static const float yuv_coeff[3][3]; static float gammaLUT[0x10000]; float yuv_cam[3][3]; LibRaw &libraw; enum { HVSH = 1, HOR = 2, VER = 4, HORSH = HOR | HVSH, VERSH = VER | HVSH, HOT = 8 }; static inline float calc_dist(int c1, int c2) throw () { return c1 > c2 ? (float) c1 / c2 : (float) c2 / c1; } int inline Y(ushort3 &rgb) throw () { return yuv_cam[0][0] * rgb[0] + yuv_cam[0][1] * rgb[1] + yuv_cam[0][2] * rgb[2]; } int inline U(ushort3 &rgb) throw () { return yuv_cam[1][0] * rgb[0] + yuv_cam[1][1] * rgb[1] + yuv_cam[1][2] * rgb[2]; } int inline V(ushort3 &rgb) throw () { return yuv_cam[2][0] * rgb[0] + yuv_cam[2][1] * rgb[1] + yuv_cam[2][2] * rgb[2]; } inline int nr_offset(int row, int col) throw () { return (row * nr_width + col); } ~AAHD(); AAHD(LibRaw &_libraw); void make_ahd_greens(); void make_ahd_gline(int i); void make_ahd_rb(); void make_ahd_rb_hv(int i); void make_ahd_rb_last(int i); void evaluate_ahd(); void combine_image(); void hide_hots(); void refine_hv_dirs(); void refine_hv_dirs(int i, int js); void refine_ihv_dirs(int i); void illustrate_dirs(); void illustrate_dline(int i); }; const float AAHD::yuv_coeff[3][3] = { // YPbPr // { // 0.299f, // 0.587f, // 0.114f }, // { // -0.168736, // -0.331264f, // 0.5f }, // { // 0.5f, // -0.418688f, // -0.081312f } // // Rec. 2020 // Y'= 0,2627R' + 0,6780G' + 0,0593B' // U = (B-Y)/1.8814 = (-0,2627R' - 0,6780G' + 0.9407B) / 1.8814 = -0.13963R - 0.36037G + 0.5B // V = (R-Y)/1.4647 = (0.7373R - 0,6780G - 0,0593B) / 1.4647 = 0.5R - 0.4629G - 0.04049B { +0.2627f, +0.6780f, +0.0593f }, { -0.13963f, -0.36037f, +0.5f }, { +0.5034f, -0.4629f, -0.0405f } }; float AAHD::gammaLUT[0x10000] = { -1.f }; AAHD::AAHD(LibRaw& _libraw) : libraw(_libraw) { nr_height = libraw.imgdata.sizes.iheight + nr_margin * 2; nr_width = libraw.imgdata.sizes.iwidth + nr_margin * 2; rgb_ahd[0] = (ushort3*) calloc(nr_height * nr_width, (sizeof(ushort3) * 2 + sizeof(int3) * 2 + 3)); rgb_ahd[1] = rgb_ahd[0] + nr_height * nr_width; yuv[0] = (int3 *) (rgb_ahd[1] + nr_height * nr_width); yuv[1] = yuv[0] + nr_height * nr_width; ndir = (char*) (yuv[1] + nr_height * nr_width); homo[0] = ndir + nr_height * nr_width; homo[1] = homo[0] + nr_height * nr_width; channel_maximum[0] = channel_maximum[1] = channel_maximum[2] = 0; channel_minimum[0] = libraw.imgdata.image[0][0]; channel_minimum[1] = libraw.imgdata.image[0][1]; channel_minimum[2] = libraw.imgdata.image[0][2]; int iwidth = libraw.imgdata.sizes.iwidth; for (int i = 0; i < 3; ++i) for (int j = 0; j < 3; ++j) { yuv_cam[i][j] = 0; for (int k = 0; k < 3; ++k) yuv_cam[i][j] += yuv_coeff[i][k] * libraw.imgdata.color.rgb_cam[k][j]; } if (gammaLUT[0] < -0.1f) { float r; for (int i = 0; i < 0x10000; i++) { r = (float) i / 0x10000; gammaLUT[i] = 0x10000 * (r < 0.0181 ? 4.5f * r : 1.0993f * pow(r, 0.45f) - .0993f); } } for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) { int col_cache[48]; for (int j = 0; j < 48; ++j) { int c = libraw.COLOR(i, j); if (c == 3) c = 1; col_cache[j] = c; } int moff = nr_offset(i + nr_margin, nr_margin); for (int j = 0; j < iwidth; ++j, ++moff) { int c = col_cache[j % 48]; unsigned short d = libraw.imgdata.image[i * iwidth + j][c]; if (d != 0) { if (channel_maximum[c] < d) channel_maximum[c] = d; if (channel_minimum[c] > d) channel_minimum[c] = d; rgb_ahd[1][moff][c] = rgb_ahd[0][moff][c] = d; } } } channels_max = MAX(MAX(channel_maximum[0], channel_maximum[1]), channel_maximum[2]); } void AAHD::hide_hots() { int iwidth = libraw.imgdata.sizes.iwidth; for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) { int js = libraw.COLOR(i, 0) & 1; int kc = libraw.COLOR(i, js); /* * js -- начальная х-координата, которая попадает мимо известного зелёного * kc -- известный цвет в точке интерполирования */ int moff = nr_offset(i + nr_margin, nr_margin + js); for (int j = js; j < iwidth; j += 2, moff += 2) { ushort3 *rgb = &rgb_ahd[0][moff]; int c = rgb[0][kc]; if ((c > rgb[2 * Pe][kc] && c > rgb[2 * Pw][kc] && c > rgb[2 * Pn][kc] && c > rgb[2 * Ps][kc] && c > rgb[Pe][1] && c > rgb[Pw][1] && c > rgb[Pn][1] && c > rgb[Ps][1]) || (c < rgb[2 * Pe][kc] && c < rgb[2 * Pw][kc] && c < rgb[2 * Pn][kc] && c < rgb[2 * Ps][kc] && c < rgb[Pe][1] && c < rgb[Pw][1] && c < rgb[Pn][1] && c < rgb[Ps][1])) { int chot = c >> Thot; int cdead = c << Tdead; int avg = 0; for (int k = -2; k < 3; k += 2) for (int m = -2; m < 3; m += 2) if (m == 0 && k == 0) continue; else avg += rgb[nr_offset(k, m)][kc]; avg /= 8; if (chot > avg || cdead < avg) { ndir[moff] |= HOT; int dh = ABS(rgb[2 * Pw][kc] - rgb[2 * Pe][kc]) + ABS(rgb[Pw][1] - rgb[Pe][1]) + ABS(rgb[Pw][1] - rgb[Pe][1] + rgb[2 * Pe][kc] - rgb[2 * Pw][kc]); int dv = ABS(rgb[2 * Pn][kc] - rgb[2 * Ps][kc]) + ABS(rgb[Pn][1] - rgb[Ps][1]) + ABS(rgb[Pn][1] - rgb[Ps][1] + rgb[2 * Ps][kc] - rgb[2 * Pn][kc]); int d; if (dv > dh) d = Pw; else d = Pn; rgb_ahd[1][moff][kc] = rgb[0][kc] = (rgb[+2 * d][kc] + rgb[-2 * d][kc]) / 2; } } } js ^= 1; moff = nr_offset(i + nr_margin, nr_margin + js); for (int j = js; j < iwidth; j += 2, moff += 2) { ushort3 *rgb = &rgb_ahd[0][moff]; int c = rgb[0][1]; if ((c > rgb[2 * Pe][1] && c > rgb[2 * Pw][1] && c > rgb[2 * Pn][1] && c > rgb[2 * Ps][1] && c > rgb[Pe][kc] && c > rgb[Pw][kc] && c > rgb[Pn][kc ^ 2] && c > rgb[Ps][kc ^ 2]) || (c < rgb[2 * Pe][1] && c < rgb[2 * Pw][1] && c < rgb[2 * Pn][1] && c < rgb[2 * Ps][1] && c < rgb[Pe][kc] && c < rgb[Pw][kc] && c < rgb[Pn][kc ^ 2] && c < rgb[Ps][kc ^ 2])) { int chot = c >> Thot; int cdead = c << Tdead; int avg = 0; for (int k = -2; k < 3; k += 2) for (int m = -2; m < 3; m += 2) if (k == 0 && m == 0) continue; else avg += rgb[nr_offset(k, m)][1]; avg /= 8; if (chot > avg || cdead < avg) { ndir[moff] |= HOT; int dh = ABS(rgb[2 * Pw][1] - rgb[2 * Pe][1]) + ABS(rgb[Pw][kc] - rgb[Pe][kc]) + ABS(rgb[Pw][kc] - rgb[Pe][kc] + rgb[2 * Pe][1] - rgb[2 * Pw][1]); int dv = ABS(rgb[2 * Pn][1] - rgb[2 * Ps][1]) + ABS(rgb[Pn][kc ^ 2] - rgb[Ps][kc ^ 2]) + ABS( rgb[Pn][kc ^ 2] - rgb[Ps][kc ^ 2] + rgb[2 * Ps][1] - rgb[2 * Pn][1]); int d; if (dv > dh) d = Pw; else d = Pn; rgb_ahd[1][moff][1] = rgb[0][1] = (rgb[+2 * d][1] + rgb[-2 * d][1]) / 2; } } } } } const static double xyz_rgb[3][3] = { { 0.412453, 0.357580, 0.180423 }, { 0.212671, 0.715160, 0.072169 }, { 0.019334, 0.119193, 0.950227 } }; const static float d65_white[3] = { 0.950456f, 1.0f, 1.088754f }; void AAHD::evaluate_ahd() { int hvdir[4] = { Pw, Pe, Pn, Ps }; /* * YUV * */ for (int d = 0; d < 2; ++d) { for (int i = 0; i < nr_width * nr_height; ++i) { ushort3 rgb; for (int c = 0; c < 3; ++c) { rgb[c] = gammaLUT[rgb_ahd[d][i][c]]; } yuv[d][i][0] = Y(rgb); yuv[d][i][1] = U(rgb); yuv[d][i][2] = V(rgb); } } /* */ /* * Lab * float r, cbrt[0x10000], xyz[3], xyz_cam[3][4]; for (int i = 0; i < 0x10000; i++) { r = i / 65535.0; cbrt[i] = r > 0.008856 ? pow((double) r, (double) (1 / 3.0)) : 7.787 * r + 16 / 116.0; } for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) { xyz_cam[i][j] = 0; for (int k = 0; k < 3; k++) xyz_cam[i][j] += xyz_rgb[i][k] * libraw.imgdata.color.rgb_cam[k][j] / d65_white[i]; } for (int d = 0; d < 2; ++d) for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) { int moff = nr_offset(i + nr_margin, nr_margin); for (int j = 0; j < libraw.imgdata.sizes.iwidth; j++, ++moff) { xyz[0] = xyz[1] = xyz[2] = 0.5; for (int c = 0; c < 3; c++) { xyz[0] += xyz_cam[0][c] * rgb_ahd[d][moff][c]; xyz[1] += xyz_cam[1][c] * rgb_ahd[d][moff][c]; xyz[2] += xyz_cam[2][c] * rgb_ahd[d][moff][c]; } xyz[0] = cbrt[CLIP((int) xyz[0])]; xyz[1] = cbrt[CLIP((int) xyz[1])]; xyz[2] = cbrt[CLIP((int) xyz[2])]; yuv[d][moff][0] = 64 * (116 * xyz[1] - 16); yuv[d][moff][1] = 64 * 500 * (xyz[0] - xyz[1]); yuv[d][moff][2] = 64 * 200 * (xyz[1] - xyz[2]); } } * Lab */ for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) { int moff = nr_offset(i + nr_margin, nr_margin); for (int j = 0; j < libraw.imgdata.sizes.iwidth; j++, ++moff) { int3 *ynr; float ydiff[2][4]; int uvdiff[2][4]; for (int d = 0; d < 2; ++d) { ynr = &yuv[d][moff]; for (int k = 0; k < 4; k++) { ydiff[d][k] = ABS(ynr[0][0] - ynr[hvdir[k]][0]); uvdiff[d][k] = SQR(ynr[0][1] - ynr[hvdir[k]][1]) + SQR(ynr[0][2] - ynr[hvdir[k]][2]); } } float yeps = MIN(MAX(ydiff[0][0], ydiff[0][1]), MAX(ydiff[1][2], ydiff[1][3])); int uveps = MIN(MAX(uvdiff[0][0], uvdiff[0][1]), MAX(uvdiff[1][2], uvdiff[1][3])); for (int d = 0; d < 2; d++) { ynr = &yuv[d][moff]; for (int k = 0; k < 4; k++) if (ydiff[d][k] <= yeps && uvdiff[d][k] <= uveps) { homo[d][moff + hvdir[k]]++; if (k / 2 == d) { // если в сонаправленном направлении интеполяции следующие точки так же гомогенны, учтём их тоже for (int m = 2; m < 4; ++m) { int hvd = m * hvdir[k]; if (ABS(ynr[0][0] - ynr[hvd][0]) < yeps && SQR(ynr[0][1] - ynr[hvd][1]) + SQR(ynr[0][2] - ynr[hvd][2]) < uveps) { homo[d][moff + hvd]++; } else break; } } } } } } for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) { int moff = nr_offset(i + nr_margin, nr_margin); for (int j = 0; j < libraw.imgdata.sizes.iwidth; j++, ++moff) { char hm[2]; for (int d = 0; d < 2; d++) { hm[d] = 0; char *hh = &homo[d][moff]; for (int hx = -1; hx < 2; hx++) for (int hy = -1; hy < 2; hy++) hm[d] += hh[nr_offset(hy, hx)]; } char d = 0; if (hm[0] != hm[1]) { if (hm[1] > hm[0]) { d = VERSH; } else { d = HORSH; } } else { int3 *ynr = &yuv[1][moff]; int gv = SQR(2 * ynr[0][0] - ynr[Pn][0] - ynr[Ps][0]); gv += SQR(2 * ynr[0][1] - ynr[Pn][1] - ynr[Ps][1]) + SQR(2 * ynr[0][2] - ynr[Pn][2] - ynr[Ps][2]); ynr = &yuv[1][moff + Pn]; gv += (SQR(2 * ynr[0][0] - ynr[Pn][0] - ynr[Ps][0]) + SQR(2 * ynr[0][1] - ynr[Pn][1] - ynr[Ps][1]) + SQR(2 * ynr[0][2] - ynr[Pn][2] - ynr[Ps][2])) / 2; ynr = &yuv[1][moff + Ps]; gv += (SQR(2 * ynr[0][0] - ynr[Pn][0] - ynr[Ps][0]) + SQR(2 * ynr[0][1] - ynr[Pn][1] - ynr[Ps][1]) + SQR(2 * ynr[0][2] - ynr[Pn][2] - ynr[Ps][2])) / 2; ynr = &yuv[0][moff]; int gh = SQR(2 * ynr[0][0] - ynr[Pw][0] - ynr[Pe][0]); gh += SQR(2 * ynr[0][1] - ynr[Pw][1] - ynr[Pe][1]) + SQR(2 * ynr[0][2] - ynr[Pw][2] - ynr[Pe][2]); ynr = &yuv[0][moff + Pw]; gh += (SQR(2 * ynr[0][0] - ynr[Pw][0] - ynr[Pe][0]) + SQR(2 * ynr[0][1] - ynr[Pw][1] - ynr[Pe][1]) + SQR(2 * ynr[0][2] - ynr[Pw][2] - ynr[Pe][2])) / 2; ynr = &yuv[0][moff + Pe]; gh += (SQR(2 * ynr[0][0] - ynr[Pw][0] - ynr[Pe][0]) + SQR(2 * ynr[0][1] - ynr[Pw][1] - ynr[Pe][1]) + SQR(2 * ynr[0][2] - ynr[Pw][2] - ynr[Pe][2])) / 2; if (gv > gh) d = HOR; else d = VER; } ndir[moff] |= d; } } } void AAHD::combine_image() { for (int i = 0, i_out = 0; i < libraw.imgdata.sizes.iheight; ++i) { int moff = nr_offset(i + nr_margin, nr_margin); for (int j = 0; j < libraw.imgdata.sizes.iwidth; j++, ++moff, ++i_out) { if (ndir[moff] & HOT) { int c = libraw.COLOR(i, j); rgb_ahd[1][moff][c] = rgb_ahd[0][moff][c] = libraw.imgdata.image[i_out][c]; } if (ndir[moff] & VER) { libraw.imgdata.image[i_out][0] = rgb_ahd[1][moff][0]; libraw.imgdata.image[i_out][3] = libraw.imgdata.image[i_out][1] = rgb_ahd[1][moff][1]; libraw.imgdata.image[i_out][2] = rgb_ahd[1][moff][2]; } else { libraw.imgdata.image[i_out][0] = rgb_ahd[0][moff][0]; libraw.imgdata.image[i_out][3] = libraw.imgdata.image[i_out][1] = rgb_ahd[0][moff][1]; libraw.imgdata.image[i_out][2] = rgb_ahd[0][moff][2]; } } } } void AAHD::refine_hv_dirs() { for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) { refine_hv_dirs(i, i & 1); } for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) { refine_hv_dirs(i, (i & 1) ^ 1); } for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) { refine_ihv_dirs(i); } } void AAHD::refine_ihv_dirs(int i) { int iwidth = libraw.imgdata.sizes.iwidth; int moff = nr_offset(i + nr_margin, nr_margin); for (int j = 0; j < iwidth; j++, ++moff) { if (ndir[moff] & HVSH) continue; int nv = (ndir[moff + Pn] & VER) + (ndir[moff + Ps] & VER) + (ndir[moff + Pw] & VER) + (ndir[moff + Pe] & VER); int nh = (ndir[moff + Pn] & HOR) + (ndir[moff + Ps] & HOR) + (ndir[moff + Pw] & HOR) + (ndir[moff + Pe] & HOR); nv /= VER; nh /= HOR; if ((ndir[moff] & VER) && nh > 3) { ndir[moff] &= ~VER; ndir[moff] |= HOR; } if ((ndir[moff] & HOR) && nv > 3) { ndir[moff] &= ~HOR; ndir[moff] |= VER; } } } void AAHD::refine_hv_dirs(int i, int js) { int iwidth = libraw.imgdata.sizes.iwidth; int moff = nr_offset(i + nr_margin, nr_margin + js); for (int j = js; j < iwidth; j += 2, moff += 2) { int nv = (ndir[moff + Pn] & VER) + (ndir[moff + Ps] & VER) + (ndir[moff + Pw] & VER) + (ndir[moff + Pe] & VER); int nh = (ndir[moff + Pn] & HOR) + (ndir[moff + Ps] & HOR) + (ndir[moff + Pw] & HOR) + (ndir[moff + Pe] & HOR); bool codir = (ndir[moff] & VER) ? ((ndir[moff + Pn] & VER) || (ndir[moff + Ps] & VER)) : ((ndir[moff + Pw] & HOR) || (ndir[moff + Pe] & HOR)); nv /= VER; nh /= HOR; if ((ndir[moff] & VER) && (nh > 2 && !codir)) { ndir[moff] &= ~VER; ndir[moff] |= HOR; } if ((ndir[moff] & HOR) && (nv > 2 && !codir)) { ndir[moff] &= ~HOR; ndir[moff] |= VER; } } } /* * вычисление недостающих зелёных точек. */ void AAHD::make_ahd_greens() { for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) { make_ahd_gline(i); } } void AAHD::make_ahd_gline(int i) { int iwidth = libraw.imgdata.sizes.iwidth; int js = libraw.COLOR(i, 0) & 1; int kc = libraw.COLOR(i, js); /* * js -- начальная х-координата, которая попадает мимо известного зелёного * kc -- известный цвет в точке интерполирования */ int hvdir[2] = { Pe, Ps }; for (int d = 0; d < 2; ++d) { int moff = nr_offset(i + nr_margin, nr_margin + js); for (int j = js; j < iwidth; j += 2, moff += 2) { ushort3 *cnr; cnr = &rgb_ahd[d][moff]; int h1 = 2 * cnr[-hvdir[d]][1] - int(cnr[-2 * hvdir[d]][kc] + cnr[0][kc]); int h2 = 2 * cnr[+hvdir[d]][1] - int(cnr[+2 * hvdir[d]][kc] + cnr[0][kc]); int h0 = (h1 + h2) / 4; int eg = cnr[0][kc] + h0; int min = MIN(cnr[-hvdir[d]][1], cnr[+hvdir[d]][1]); int max = MAX(cnr[-hvdir[d]][1], cnr[+hvdir[d]][1]); min -= min / OverFraction; max += max / OverFraction; if (eg < min) eg = min - sqrt(float(min - eg)); else if (eg > max) eg = max + sqrt(float(eg - max)); if (eg > channel_maximum[1]) eg = channel_maximum[1]; else if (eg < channel_minimum[1]) eg = channel_minimum[1]; cnr[0][1] = eg; } } } /* * отладочная функция */ void AAHD::illustrate_dirs() { for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) { illustrate_dline(i); } } void AAHD::illustrate_dline(int i) { int iwidth = libraw.imgdata.sizes.iwidth; for (int j = 0; j < iwidth; j++) { int x = j + nr_margin; int y = i + nr_margin; rgb_ahd[1][nr_offset(y, x)][0] = rgb_ahd[1][nr_offset(y, x)][1] = rgb_ahd[1][nr_offset(y, x)][2] = rgb_ahd[0][nr_offset(y, x)][0] = rgb_ahd[0][nr_offset(y, x)][1] = rgb_ahd[0][nr_offset(y, x)][2] = 0; int l = ndir[nr_offset(y, x)] & HVSH; l /= HVSH; if (ndir[nr_offset(y, x)] & VER) rgb_ahd[1][nr_offset(y, x)][0] = l * channel_maximum[0] / 4 + channel_maximum[0] / 4; else rgb_ahd[0][nr_offset(y, x)][2] = l * channel_maximum[2] / 4 + channel_maximum[2] / 4; } } void AAHD::make_ahd_rb_hv(int i) { int iwidth = libraw.imgdata.sizes.iwidth; int js = libraw.COLOR(i, 0) & 1; int kc = libraw.COLOR(i, js); js ^= 1; // начальная координата зелёного int hvdir[2] = { Pe, Ps }; // интерполяция вертикальных вертикально и горизонтальных горизонтально for (int j = js; j < iwidth; j += 2) { int x = j + nr_margin; int y = i + nr_margin; int moff = nr_offset(y, x); for (int d = 0; d < 2; ++d) { ushort3 *cnr; cnr = &rgb_ahd[d][moff]; int c = kc ^ (d << 1); // цвет соответсвенного направления, для горизонтального c = kc, для вертикального c=kc^2 int h1 = cnr[-hvdir[d]][c] - cnr[-hvdir[d]][1]; int h2 = cnr[+hvdir[d]][c] - cnr[+hvdir[d]][1]; int h0 = (h1 + h2) / 2; int eg = cnr[0][1] + h0; // int min = MIN(cnr[-hvdir[d]][c], cnr[+hvdir[d]][c]); // int max = MAX(cnr[-hvdir[d]][c], cnr[+hvdir[d]][c]); // min -= min / OverFraction; // max += max / OverFraction; // if (eg < min) // eg = min - sqrt(min - eg); // else if (eg > max) // eg = max + sqrt(eg - max); if (eg > channel_maximum[c]) eg = channel_maximum[c]; else if (eg < channel_minimum[c]) eg = channel_minimum[c]; cnr[0][c] = eg; } } } void AAHD::make_ahd_rb() { for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) { make_ahd_rb_hv(i); } for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) { make_ahd_rb_last(i); } } void AAHD::make_ahd_rb_last(int i) { int iwidth = libraw.imgdata.sizes.iwidth; int js = libraw.COLOR(i, 0) & 1; int kc = libraw.COLOR(i, js); /* * js -- начальная х-координата, которая попадает мимо известного зелёного * kc -- известный цвет в точке интерполирования */ int dirs[2][3] = { { Pnw, Pn, Pne }, { Pnw, Pw, Psw } }; int moff = nr_offset(i + nr_margin, nr_margin); for (int j = 0; j < iwidth; j++) { for (int d = 0; d < 2; ++d) { ushort3 *cnr; cnr = &rgb_ahd[d][moff + j]; int c = kc ^ 2; if ((j & 1) != js) { // точка зелёного, для вертикального направления нужен альтернативный строчному цвет c ^= d << 1; } int bh, bk; int bgd = 0; for (int k = 0; k < 3; ++k) for (int h = 0; h < 3; ++h) { // градиент зелёного плюс градиент {r,b} int gd = ABS(2 * cnr[0][1] - (cnr[+dirs[d][k]][1] + cnr[-dirs[d][h]][1])) + ABS(cnr[+dirs[d][k]][c] - cnr[-dirs[d][h]][c]) / 4 + ABS( cnr[+dirs[d][k]][c] - cnr[+dirs[d][k]][1] + cnr[-dirs[d][h]][1] - cnr[-dirs[d][h]][c]) / 4; if (bgd == 0 || gd < bgd) { bgd = gd; bh = h; bk = k; } } int h1 = cnr[+dirs[d][bk]][c] - cnr[+dirs[d][bk]][1]; int h2 = cnr[-dirs[d][bh]][c] - cnr[-dirs[d][bh]][1]; int eg = cnr[0][1] + (h1 + h2) / 2; // int min = MIN(cnr[+dirs[d][bk]][c], cnr[-dirs[d][bh]][c]); // int max = MAX(cnr[+dirs[d][bk]][c], cnr[-dirs[d][bh]][c]); // min -= min / OverFraction; // max += max / OverFraction; // if (eg < min) // eg = min - sqrt(min - eg); // else if (eg > max) // eg = max + sqrt(eg - max); if (eg > channel_maximum[c]) eg = channel_maximum[c]; else if (eg < channel_minimum[c]) eg = channel_minimum[c]; cnr[0][c] = eg; } } } AAHD::~AAHD() { free(rgb_ahd[0]); } void LibRaw::aahd_interpolate() { printf("AAHD interpolating\n"); AAHD aahd(*this); aahd.hide_hots(); aahd.make_ahd_greens(); aahd.make_ahd_rb(); aahd.evaluate_ahd(); aahd.refine_hv_dirs(); // aahd.illustrate_dirs(); aahd.combine_image(); } LibRaw-0.18.8/internal/dcb_demosaicing.c000066400000000000000000000606061324423227700200600ustar00rootroot00000000000000/* * Copyright (C) 2010, Jacek Gozdz (cuniek@kft.umcs.lublin.pl) * * This code is licensed under a (3-clause) BSD license as follows : * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of the author nor the names of its * contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. */ // DCB demosaicing by Jacek Gozdz (cuniek@kft.umcs.lublin.pl) // FBDD denoising by Jacek Gozdz (cuniek@kft.umcs.lublin.pl) and // Luis Sanz Rodríguez (luis.sanz.rodriguez@gmail.com) // last modification: 11.07.2010 // interpolates green vertically and saves it to image3 void CLASS dcb_ver(float (*image3)[3]) { int row, col, u=width, v=2*u, indx; for (row=2; row < height-2; row++) for (col=2+(FC(row,2)&1),indx=row*width+col; col < u-2; col+=2,indx+=2) { image3[indx][1] = CLIP((image[indx+u][1] + image[indx-u][1])/2.0); } } // interpolates green horizontally and saves it to image2 void CLASS dcb_hor(float (*image2)[3]) { int row, col, u=width, v=2*u, indx; for (row=2; row < height-2; row++) for (col=2+(FC(row,2)&1),indx=row*width+col; col < u-2; col+=2,indx+=2) { image2[indx][1] = CLIP((image[indx+1][1] + image[indx-1][1])/2.0); } } // missing colors are interpolated void CLASS dcb_color() { int row, col, c, d, u=width, indx; for (row=1; row < height-1; row++) for (col=1+(FC(row,1) & 1), indx=row*width+col, c=2-FC(row,col); col < u-1; col+=2, indx+=2) { image[indx][c] = CLIP(( 4*image[indx][1] - image[indx+u+1][1] - image[indx+u-1][1] - image[indx-u+1][1] - image[indx-u-1][1] + image[indx+u+1][c] + image[indx+u-1][c] + image[indx-u+1][c] + image[indx-u-1][c] )/4.0); } for (row=1; row ( image[indx-1][1] + image[indx+1][1] + image[indx-u][1] + image[indx+u][1])/4.0) image[indx][3] = ((MIN( image[indx-1][1], image[indx+1][1]) + image[indx-1][1] + image[indx+1][1]) < (MIN( image[indx-u][1], image[indx+u][1]) + image[indx-u][1] + image[indx+u][1])); else image[indx][3] = ((MAX( image[indx-1][1], image[indx+1][1]) + image[indx-1][1] + image[indx+1][1]) > (MAX( image[indx-u][1], image[indx+u][1]) + image[indx-u][1] + image[indx+u][1])); } } } // interpolated green pixels are corrected using the map void CLASS dcb_correction() { int current, row, col, u=width, v=2*u, indx; for (row=2; row < height-2; row++) for (col=2+(FC(row,2)&1),indx=row*width+col; col < u-2; col+=2,indx+=2) { current = 4*image[indx][3] + 2*(image[indx+u][3] + image[indx-u][3] + image[indx+1][3] + image[indx-1][3]) + image[indx+v][3] + image[indx-v][3] + image[indx+2][3] + image[indx-2][3]; image[indx][1] = ((16-current)*(image[indx-1][1] + image[indx+1][1])/2.0 + current*(image[indx-u][1] + image[indx+u][1])/2.0)/16.0; } } // interpolated green pixels are corrected using the map // with contrast correction void CLASS dcb_correction2() { int current, row, col, c, u=width, v=2*u, indx; ushort (*pix)[4]; for (row=4; row < height-4; row++) for (col=4+(FC(row,2)&1),indx=row*width+col, c=FC(row,col); col < u-4; col+=2,indx+=2) { current = 4*image[indx][3] + 2*(image[indx+u][3] + image[indx-u][3] + image[indx+1][3] + image[indx-1][3]) + image[indx+v][3] + image[indx-v][3] + image[indx+2][3] + image[indx-2][3]; image[indx][1] = CLIP(((16-current)*((image[indx-1][1] + image[indx+1][1])/2.0 + image[indx][c] - (image[indx+2][c] + image[indx-2][c])/2.0) + current*((image[indx-u][1] + image[indx+u][1])/2.0 + image[indx][c] - (image[indx+v][c] + image[indx-v][c])/2.0))/16.0); } } void CLASS dcb_refinement() { int row, col, c, u=width, v=2*u, w=3*u, indx, current; float f[5], g1, g2, tmp, tmp2=0, tmp3=0; for (row=4; row < height-4; row++) for (col=4+(FC(row,2)&1),indx=row*width+col, c=FC(row,col); col < u-4; col+=2,indx+=2) { current = 4*image[indx][3] + 2*(image[indx+u][3] + image[indx-u][3] + image[indx+1][3] + image[indx-1][3]) +image[indx+v][3] + image[indx-v][3] + image[indx-2][3] + image[indx+2][3]; if (image[indx][c] > 1) { f[0] = (float)(image[indx-u][1] + image[indx+u][1])/(2*image[indx][c]); if (image[indx-v][c] > 0) f[1] = 2*(float)image[indx-u][1]/(image[indx-v][c] + image[indx][c]); else f[1] = f[0]; if (image[indx-v][c] > 0) f[2] = (float)(image[indx-u][1] + image[indx-w][1])/(2*image[indx-v][c]); else f[2] = f[0]; if (image[indx+v][c] > 0) f[3] = 2*(float)image[indx+u][1]/(image[indx+v][c] + image[indx][c]); else f[3] = f[0]; if (image[indx+v][c] > 0) f[4] = (float)(image[indx+u][1] + image[indx+w][1])/(2*image[indx+v][c]); else f[4] = f[0]; g1 = (5*f[0] + 3*f[1] + f[2] + 3*f[3] + f[4])/13.0; f[0] = (float)(image[indx-1][1] + image[indx+1][1])/(2*image[indx][c]); if (image[indx-2][c] > 0) f[1] = 2*(float)image[indx-1][1]/(image[indx-2][c] + image[indx][c]); else f[1] = f[0]; if (image[indx-2][c] > 0) f[2] = (float)(image[indx-1][1] + image[indx-3][1])/(2*image[indx-2][c]); else f[2] = f[0]; if (image[indx+2][c] > 0) f[3] = 2*(float)image[indx+1][1]/(image[indx+2][c] + image[indx][c]); else f[3] = f[0]; if (image[indx+2][c] > 0) f[4] = (float)(image[indx+1][1] + image[indx+3][1])/(2*image[indx+2][c]); else f[4] = f[0]; g2 = (5*f[0] + 3*f[1] + f[2] + 3*f[3] + f[4])/13.0; image[indx][1] = CLIP((image[indx][c])*(current*g1 + (16-current)*g2)/16.0); } else image[indx][1] = image[indx][c]; // get rid of overshooted pixels g1 = MIN(image[indx+1+u][1], MIN(image[indx+1-u][1], MIN(image[indx-1+u][1], MIN(image[indx-1-u][1], MIN(image[indx-1][1], MIN(image[indx+1][1], MIN(image[indx-u][1], image[indx+u][1]))))))); g2 = MAX(image[indx+1+u][1], MAX(image[indx+1-u][1], MAX(image[indx-1+u][1], MAX(image[indx-1-u][1], MAX(image[indx-1][1], MAX(image[indx+1][1], MAX(image[indx-u][1], image[indx+u][1]))))))); image[indx][1] = ULIM(image[indx][1], g2, g1); } } // converts RGB to LCH colorspace and saves it to image3 void CLASS rgb_to_lch(double (*image2)[3]) { int indx; for (indx=0; indx < height*width; indx++) { image2[indx][0] = image[indx][0] + image[indx][1] + image[indx][2]; // L image2[indx][1] = 1.732050808 *(image[indx][0] - image[indx][1]); // C image2[indx][2] = 2.0*image[indx][2] - image[indx][0] - image[indx][1]; // H } } // converts LCH to RGB colorspace and saves it back to image void CLASS lch_to_rgb(double (*image2)[3]) { int indx; for (indx=0; indx < height*width; indx++) { image[indx][0] = CLIP(image2[indx][0] / 3.0 - image2[indx][2] / 6.0 + image2[indx][1] / 3.464101615); image[indx][1] = CLIP(image2[indx][0] / 3.0 - image2[indx][2] / 6.0 - image2[indx][1] / 3.464101615); image[indx][2] = CLIP(image2[indx][0] / 3.0 + image2[indx][2] / 3.0); } } // denoising using interpolated neighbours void CLASS fbdd_correction() { int row, col, c, u=width, indx; ushort (*pix)[4]; for (row=2; row < height-2; row++) { for (col=2, indx=row*width+col; col < width-2; col++, indx++) { c = fcol(row,col); image[indx][c] = ULIM(image[indx][c], MAX(image[indx-1][c], MAX(image[indx+1][c], MAX(image[indx-u][c], image[indx+u][c]))), MIN(image[indx-1][c], MIN(image[indx+1][c], MIN(image[indx-u][c], image[indx+u][c])))); } } } // corrects chroma noise void CLASS fbdd_correction2(double (*image2)[3]) { int indx, u=width, v=2*width; int col, row; double Co, Ho, ratio; for (row=6; row < height-6; row++) { for (col=6; col < width-6; col++) { indx = row*width+col; if ( image2[indx][1]*image2[indx][2] != 0 ) { Co = (image2[indx+v][1] + image2[indx-v][1] + image2[indx-2][1] + image2[indx+2][1] - MAX(image2[indx-2][1], MAX(image2[indx+2][1], MAX(image2[indx-v][1], image2[indx+v][1]))) - MIN(image2[indx-2][1], MIN(image2[indx+2][1], MIN(image2[indx-v][1], image2[indx+v][1]))))/2.0; Ho = (image2[indx+v][2] + image2[indx-v][2] + image2[indx-2][2] + image2[indx+2][2] - MAX(image2[indx-2][2], MAX(image2[indx+2][2], MAX(image2[indx-v][2], image2[indx+v][2]))) - MIN(image2[indx-2][2], MIN(image2[indx+2][2], MIN(image2[indx-v][2], image2[indx+v][2]))))/2.0; ratio = sqrt ((Co*Co+Ho*Ho) / (image2[indx][1]*image2[indx][1] + image2[indx][2]*image2[indx][2])); if (ratio < 0.85) { image2[indx][0] = -(image2[indx][1] + image2[indx][2] - Co - Ho) + image2[indx][0]; image2[indx][1] = Co; image2[indx][2] = Ho; } } } } } // Cubic Spline Interpolation by Li and Randhawa, modified by Jacek Gozdz and Luis Sanz Rodríguez void CLASS fbdd_green() { int row, col, c, u=width, v=2*u, w=3*u, x=4*u, y=5*u, indx, min, max, current; float f[4], g[4]; for (row=5; row < height-5; row++) for (col=5+(FC(row,1)&1),indx=row*width+col,c=FC(row,col); col < u-5; col+=2,indx+=2) { f[0]=1.0/(1.0+abs(image[indx-u][1]-image[indx-w][1])+abs(image[indx-w][1]-image[indx+y][1])); f[1]=1.0/(1.0+abs(image[indx+1][1]-image[indx+3][1])+abs(image[indx+3][1]-image[indx-5][1])); f[2]=1.0/(1.0+abs(image[indx-1][1]-image[indx-3][1])+abs(image[indx-3][1]-image[indx+5][1])); f[3]=1.0/(1.0+abs(image[indx+u][1]-image[indx+w][1])+abs(image[indx+w][1]-image[indx-y][1])); g[0]=CLIP((23*image[indx-u][1]+23*image[indx-w][1]+2*image[indx-y][1]+8*(image[indx-v][c]-image[indx-x][c])+40*(image[indx][c]-image[indx-v][c]))/48.0); g[1]=CLIP((23*image[indx+1][1]+23*image[indx+3][1]+2*image[indx+5][1]+8*(image[indx+2][c]-image[indx+4][c])+40*(image[indx][c]-image[indx+2][c]))/48.0); g[2]=CLIP((23*image[indx-1][1]+23*image[indx-3][1]+2*image[indx-5][1]+8*(image[indx-2][c]-image[indx-4][c])+40*(image[indx][c]-image[indx-2][c]))/48.0); g[3]=CLIP((23*image[indx+u][1]+23*image[indx+w][1]+2*image[indx+y][1]+8*(image[indx+v][c]-image[indx+x][c])+40*(image[indx][c]-image[indx+v][c]))/48.0); image[indx][1]=CLIP((f[0]*g[0]+f[1]*g[1]+f[2]*g[2]+f[3]*g[3])/(f[0]+f[1]+f[2]+f[3])); min = MIN(image[indx+1+u][1], MIN(image[indx+1-u][1], MIN(image[indx-1+u][1], MIN(image[indx-1-u][1], MIN(image[indx-1][1], MIN(image[indx+1][1], MIN(image[indx-u][1], image[indx+u][1]))))))); max = MAX(image[indx+1+u][1], MAX(image[indx+1-u][1], MAX(image[indx-1+u][1], MAX(image[indx-1-u][1], MAX(image[indx-1][1], MAX(image[indx+1][1], MAX(image[indx-u][1], image[indx+u][1]))))))); image[indx][1] = ULIM(image[indx][1], max, min); } } // FBDD (Fake Before Demosaicing Denoising) void CLASS fbdd(int noiserd) { double (*image2)[3]; // safety net: disable for 4-color bayer or full-color images if(colors!=3 || !filters) return; image2 = (double (*)[3]) calloc(width*height, sizeof *image2); border_interpolate(4); if (noiserd>1) { #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("FBDD full noise reduction...\n")); #endif fbdd_green(); //dcb_color_full(image2); dcb_color_full(); fbdd_correction(); dcb_color(); rgb_to_lch(image2); fbdd_correction2(image2); fbdd_correction2(image2); lch_to_rgb(image2); } else { #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("FBDD noise reduction...\n")); #endif fbdd_green(); //dcb_color_full(image2); dcb_color_full(); fbdd_correction(); } free(image2); } // DCB demosaicing main routine void CLASS dcb(int iterations, int dcb_enhance) { int i=1; float (*image2)[3]; image2 = (float (*)[3]) calloc(width*height, sizeof *image2); float (*image3)[3]; image3 = (float (*)[3]) calloc(width*height, sizeof *image3); #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("DCB demosaicing...\n")); #endif border_interpolate(6); dcb_hor(image2); dcb_color2(image2); dcb_ver(image3); dcb_color3(image3); dcb_decide(image2, image3); free(image3); dcb_copy_to_buffer(image2); while (i<=iterations) { #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("DCB correction pass %d...\n"), i); #endif dcb_nyquist(); dcb_nyquist(); dcb_nyquist(); dcb_map(); dcb_correction(); i++; } dcb_color(); dcb_pp(); #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("finishing DCB...\n")); #endif dcb_map(); dcb_correction2(); dcb_map(); dcb_correction(); dcb_map(); dcb_correction(); dcb_map(); dcb_correction(); dcb_map(); dcb_restore_from_buffer(image2); dcb_color(); if (dcb_enhance) { #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("optional DCB refinement...\n")); #endif dcb_refinement(); //dcb_color_full(image2); dcb_color_full(); } free(image2); } LibRaw-0.18.8/internal/dcraw_common.cpp000066400000000000000000020167651324423227700200070ustar00rootroot00000000000000/* Copyright 2008-2017 LibRaw LLC (info@libraw.org) LibRaw is free software; you can redistribute it and/or modify it under the terms of the one of two licenses as you choose: 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 (See file LICENSE.LGPL provided in LibRaw distribution archive for details). 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 (See file LICENSE.CDDL provided in LibRaw distribution archive for details). This file is generated from Dave Coffin's dcraw.c dcraw.c -- Dave Coffin's raw photo decoder Copyright 1997-2010 by Dave Coffin, dcoffin a cybercom o net Look into dcraw homepage (probably http://cybercom.net/~dcoffin/dcraw/) for more information */ #include #define CLASS LibRaw:: #include "libraw/libraw_types.h" #define LIBRAW_LIBRARY_BUILD #define LIBRAW_IO_REDEFINED #include "libraw/libraw.h" #include "internal/defines.h" #include "internal/var_defines.h" int CLASS fcol (int row, int col) { static const char filter[16][16] = { { 2,1,1,3,2,3,2,0,3,2,3,0,1,2,1,0 }, { 0,3,0,2,0,1,3,1,0,1,1,2,0,3,3,2 }, { 2,3,3,2,3,1,1,3,3,1,2,1,2,0,0,3 }, { 0,1,0,1,0,2,0,2,2,0,3,0,1,3,2,1 }, { 3,1,1,2,0,1,0,2,1,3,1,3,0,1,3,0 }, { 2,0,0,3,3,2,3,1,2,0,2,0,3,2,2,1 }, { 2,3,3,1,2,1,2,1,2,1,1,2,3,0,0,1 }, { 1,0,0,2,3,0,0,3,0,3,0,3,2,1,2,3 }, { 2,3,3,1,1,2,1,0,3,2,3,0,2,3,1,3 }, { 1,0,2,0,3,0,3,2,0,1,1,2,0,1,0,2 }, { 0,1,1,3,3,2,2,1,1,3,3,0,2,1,3,2 }, { 2,3,2,0,0,1,3,0,2,0,1,2,3,0,1,0 }, { 1,3,1,2,3,2,3,2,0,2,0,1,1,0,3,0 }, { 0,2,0,3,1,0,0,1,1,3,3,2,3,2,2,1 }, { 2,1,3,2,3,1,2,1,0,3,0,2,0,2,0,2 }, { 0,3,1,0,0,2,0,3,2,1,3,1,1,3,1,3 } }; if (filters == 1) return filter[(row+top_margin)&15][(col+left_margin)&15]; if (filters == 9) return xtrans[(row+6) % 6][(col+6) % 6]; return FC(row,col); } static size_t local_strnlen(const char *s, size_t n) { const char *p = (const char *)memchr(s, 0, n); return(p ? p-s : n); } /* add OS X version check here ?? */ #define strnlen(a,b) local_strnlen(a,b) #ifdef LIBRAW_LIBRARY_BUILD static int stread(char *buf, size_t len, LibRaw_abstract_datastream *fp) { int r = fp->read(buf,len,1); buf[len-1] = 0; return r; } #define stmread(buf,maxlen,fp) stread(buf,MIN(maxlen,sizeof(buf)),fp) #endif #ifndef __GLIBC__ char *my_memmem (char *haystack, size_t haystacklen, char *needle, size_t needlelen) { char *c; for (c = haystack; c <= haystack + haystacklen - needlelen; c++) if (!memcmp (c, needle, needlelen)) return c; return 0; } #define memmem my_memmem char *my_strcasestr (char *haystack, const char *needle) { char *c; for (c = haystack; *c; c++) if (!strncasecmp(c, needle, strlen(needle))) return c; return 0; } #define strcasestr my_strcasestr #endif #define strbuflen(buf) strnlen(buf,sizeof(buf)-1) ushort CLASS sget2 (uchar *s) { if (order == 0x4949) /* "II" means little-endian */ return s[0] | s[1] << 8; else /* "MM" means big-endian */ return s[0] << 8 | s[1]; } // DNG was written by: #define CameraDNG 1 #define AdobeDNG 2 #ifdef LIBRAW_LIBRARY_BUILD static int getwords(char *line, char *words[], int maxwords,int maxlen) { line[maxlen-1] = 0; char *p = line; int nwords = 0; while(1) { while(isspace(*p)) p++; if(*p == '\0') return nwords; words[nwords++] = p; while(!isspace(*p) && *p != '\0') p++; if(*p == '\0') return nwords; *p++ = '\0'; if(nwords >= maxwords) return nwords; } } static ushort saneSonyCameraInfo(uchar a, uchar b, uchar c, uchar d, uchar e, uchar f){ if ((a >> 4) > 9) return 0; else if ((a & 0x0f) > 9) return 0; else if ((b >> 4) > 9) return 0; else if ((b & 0x0f) > 9) return 0; else if ((c >> 4) > 9) return 0; else if ((c & 0x0f) > 9) return 0; else if ((d >> 4) > 9) return 0; else if ((d & 0x0f) > 9) return 0; else if ((e >> 4) > 9) return 0; else if ((e & 0x0f) > 9) return 0; else if ((f >> 4) > 9) return 0; else if ((f & 0x0f) > 9) return 0; return 1; } static ushort bcd2dec(uchar data){ if ((data >> 4) > 9) return 0; else if ((data & 0x0f) > 9) return 0; else return (data >> 4) * 10 + (data & 0x0f); } static uchar SonySubstitution[257] = "\x00\x01\x32\xb1\x0a\x0e\x87\x28\x02\xcc\xca\xad\x1b\xdc\x08\xed\x64\x86\xf0\x4f\x8c\x6c\xb8\xcb\x69\xc4\x2c\x03\x97\xb6\x93\x7c\x14\xf3\xe2\x3e\x30\x8e\xd7\x60\x1c\xa1\xab\x37\xec\x75\xbe\x23\x15\x6a\x59\x3f\xd0\xb9\x96\xb5\x50\x27\x88\xe3\x81\x94\xe0\xc0\x04\x5c\xc6\xe8\x5f\x4b\x70\x38\x9f\x82\x80\x51\x2b\xc5\x45\x49\x9b\x21\x52\x53\x54\x85\x0b\x5d\x61\xda\x7b\x55\x26\x24\x07\x6e\x36\x5b\x47\xb7\xd9\x4a\xa2\xdf\xbf\x12\x25\xbc\x1e\x7f\x56\xea\x10\xe6\xcf\x67\x4d\x3c\x91\x83\xe1\x31\xb3\x6f\xf4\x05\x8a\x46\xc8\x18\x76\x68\xbd\xac\x92\x2a\x13\xe9\x0f\xa3\x7a\xdb\x3d\xd4\xe7\x3a\x1a\x57\xaf\x20\x42\xb2\x9e\xc3\x8b\xf2\xd5\xd3\xa4\x7e\x1f\x98\x9c\xee\x74\xa5\xa6\xa7\xd8\x5e\xb0\xb4\x34\xce\xa8\x79\x77\x5a\xc1\x89\xae\x9a\x11\x33\x9d\xf5\x39\x19\x65\x78\x16\x71\xd2\xa9\x44\x63\x40\x29\xba\xa0\x8f\xe4\xd6\x3b\x84\x0d\xc2\x4e\x58\xdd\x99\x22\x6b\xc9\xbb\x17\x06\xe5\x7d\x66\x43\x62\xf6\xcd\x35\x90\x2e\x41\x8d\x6d\xaa\x09\x73\x95\x0c\xf1\x1d\xde\x4c\x2f\x2d\xf7\xd1\x72\xeb\xef\x48\xc7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"; ushort CLASS sget2Rev(uchar *s) // specific to some Canon Makernotes fields, where they have endian in reverse { if (order == 0x4d4d) /* "II" means little-endian, and we reverse to "MM" - big endian */ return s[0] | s[1] << 8; else /* "MM" means big-endian... */ return s[0] << 8 | s[1]; } #endif ushort CLASS get2() { uchar str[2] = { 0xff,0xff }; fread (str, 1, 2, ifp); return sget2(str); } unsigned CLASS sget4 (uchar *s) { if (order == 0x4949) return s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24; else return s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]; } #define sget4(s) sget4((uchar *)s) unsigned CLASS get4() { uchar str[4] = { 0xff,0xff,0xff,0xff }; fread (str, 1, 4, ifp); return sget4(str); } unsigned CLASS getint (int type) { return type == 3 ? get2() : get4(); } float CLASS int_to_float (int i) { union { int i; float f; } u; u.i = i; return u.f; } double CLASS getreal (int type) { union { char c[8]; double d; } u,v; int i, rev; switch (type) { case 3: return (unsigned short) get2(); case 4: return (unsigned int) get4(); case 5: u.d = (unsigned int) get4(); v.d = (unsigned int)get4(); return u.d / (v.d ? v.d : 1); case 8: return (signed short) get2(); case 9: return (signed int) get4(); case 10: u.d = (signed int) get4(); v.d = (signed int)get4(); return u.d / (v.d?v.d:1); case 11: return int_to_float (get4()); case 12: rev = 7 * ((order == 0x4949) == (ntohs(0x1234) == 0x1234)); for (i=0; i < 8; i++) u.c[i ^ rev] = fgetc(ifp); return u.d; default: return fgetc(ifp); } } void CLASS read_shorts (ushort *pixel, unsigned count) { if (fread (pixel, 2, count, ifp) < count) derror(); if ((order == 0x4949) == (ntohs(0x1234) == 0x1234)) swab ((char*)pixel, (char*)pixel, count*2); } void CLASS cubic_spline (const int *x_, const int *y_, const int len) { float **A, *b, *c, *d, *x, *y; int i, j; A = (float **) calloc (((2*len + 4)*sizeof **A + sizeof *A), 2*len); if (!A) return; A[0] = (float *) (A + 2*len); for (i = 1; i < 2*len; i++) A[i] = A[0] + 2*len*i; y = len + (x = i + (d = i + (c = i + (b = A[0] + i*i)))); for (i = 0; i < len; i++) { x[i] = x_[i] / 65535.0; y[i] = y_[i] / 65535.0; } for (i = len-1; i > 0; i--) { b[i] = (y[i] - y[i-1]) / (x[i] - x[i-1]); d[i-1] = x[i] - x[i-1]; } for (i = 1; i < len-1; i++) { A[i][i] = 2 * (d[i-1] + d[i]); if (i > 1) { A[i][i-1] = d[i-1]; A[i-1][i] = d[i-1]; } A[i][len-1] = 6 * (b[i+1] - b[i]); } for(i = 1; i < len-2; i++) { float v = A[i+1][i] / A[i][i]; for(j = 1; j <= len-1; j++) A[i+1][j] -= v * A[i][j]; } for(i = len-2; i > 0; i--) { float acc = 0; for(j = i; j <= len-2; j++) acc += A[i][j]*c[j]; c[i] = (A[i][len-1] - acc) / A[i][i]; } for (i = 0; i < 0x10000; i++) { float x_out = (float)(i / 65535.0); float y_out = 0; for (j = 0; j < len-1; j++) { if (x[j] <= x_out && x_out <= x[j+1]) { float v = x_out - x[j]; y_out = y[j] + ((y[j+1] - y[j]) / d[j] - (2 * d[j] * c[j] + c[j+1] * d[j])/6) * v + (c[j] * 0.5) * v*v + ((c[j+1] - c[j]) / (6 * d[j])) * v*v*v; } } curve[i] = y_out < 0.0 ? 0 : (y_out >= 1.0 ? 65535 : (ushort)(y_out * 65535.0 + 0.5)); } free (A); } void CLASS canon_600_fixed_wb (int temp) { static const short mul[4][5] = { { 667, 358,397,565,452 }, { 731, 390,367,499,517 }, { 1119, 396,348,448,537 }, { 1399, 485,431,508,688 } }; int lo, hi, i; float frac=0; for (lo=4; --lo; ) if (*mul[lo] <= temp) break; for (hi=0; hi < 3; hi++) if (*mul[hi] >= temp) break; if (lo != hi) frac = (float) (temp - *mul[lo]) / (*mul[hi] - *mul[lo]); for (i=1; i < 5; i++) pre_mul[i-1] = 1 / (frac * mul[hi][i] + (1-frac) * mul[lo][i]); } /* Return values: 0 = white 1 = near white 2 = not white */ int CLASS canon_600_color (int ratio[2], int mar) { int clipped=0, target, miss; if (flash_used) { if (ratio[1] < -104) { ratio[1] = -104; clipped = 1; } if (ratio[1] > 12) { ratio[1] = 12; clipped = 1; } } else { if (ratio[1] < -264 || ratio[1] > 461) return 2; if (ratio[1] < -50) { ratio[1] = -50; clipped = 1; } if (ratio[1] > 307) { ratio[1] = 307; clipped = 1; } } target = flash_used || ratio[1] < 197 ? -38 - (398 * ratio[1] >> 10) : -123 + (48 * ratio[1] >> 10); if (target - mar <= ratio[0] && target + 20 >= ratio[0] && !clipped) return 0; miss = target - ratio[0]; if (abs(miss) >= mar*4) return 2; if (miss < -20) miss = -20; if (miss > mar) miss = mar; ratio[0] = target - miss; return 1; } void CLASS canon_600_auto_wb() { int mar, row, col, i, j, st, count[] = { 0,0 }; int test[8], total[2][8], ratio[2][2], stat[2]; memset (&total, 0, sizeof total); i = canon_ev + 0.5; if (i < 10) mar = 150; else if (i > 12) mar = 20; else mar = 280 - 20 * i; if (flash_used) mar = 80; for (row=14; row < height-14; row+=4) for (col=10; col < width; col+=2) { for (i=0; i < 8; i++) test[(i & 4) + FC(row+(i >> 1),col+(i & 1))] = BAYER(row+(i >> 1),col+(i & 1)); for (i=0; i < 8; i++) if (test[i] < 150 || test[i] > 1500) goto next; for (i=0; i < 4; i++) if (abs(test[i] - test[i+4]) > 50) goto next; for (i=0; i < 2; i++) { for (j=0; j < 4; j+=2) ratio[i][j >> 1] = ((test[i*4+j+1]-test[i*4+j]) << 10) / test[i*4+j]; stat[i] = canon_600_color (ratio[i], mar); } if ((st = stat[0] | stat[1]) > 1) goto next; for (i=0; i < 2; i++) if (stat[i]) for (j=0; j < 2; j++) test[i*4+j*2+1] = test[i*4+j*2] * (0x400 + ratio[i][j]) >> 10; for (i=0; i < 8; i++) total[st][i] += test[i]; count[st]++; next: ; } if (count[0] | count[1]) { st = count[0]*200 < count[1]; for (i=0; i < 4; i++) pre_mul[i] = 1.0 / (total[st][i] + total[st][i+4]); } } void CLASS canon_600_coeff() { static const short table[6][12] = { { -190,702,-1878,2390, 1861,-1349,905,-393, -432,944,2617,-2105 }, { -1203,1715,-1136,1648, 1388,-876,267,245, -1641,2153,3921,-3409 }, { -615,1127,-1563,2075, 1437,-925,509,3, -756,1268,2519,-2007 }, { -190,702,-1886,2398, 2153,-1641,763,-251, -452,964,3040,-2528 }, { -190,702,-1878,2390, 1861,-1349,905,-393, -432,944,2617,-2105 }, { -807,1319,-1785,2297, 1388,-876,769,-257, -230,742,2067,-1555 } }; int t=0, i, c; float mc, yc; mc = pre_mul[1] / pre_mul[2]; yc = pre_mul[3] / pre_mul[2]; if (mc > 1 && mc <= 1.28 && yc < 0.8789) t=1; if (mc > 1.28 && mc <= 2) { if (yc < 0.8789) t=3; else if (yc <= 2) t=4; } if (flash_used) t=5; for (raw_color = i=0; i < 3; i++) FORCC rgb_cam[i][c] = table[t][i*4 + c] / 1024.0; } void CLASS canon_600_load_raw() { uchar data[1120], *dp; ushort *pix; int irow, row; for (irow=row=0; irow < height; irow++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif if (fread (data, 1, 1120, ifp) < 1120) derror(); pix = raw_image + row*raw_width; for (dp=data; dp < data+1120; dp+=10, pix+=8) { pix[0] = (dp[0] << 2) + (dp[1] >> 6 ); pix[1] = (dp[2] << 2) + (dp[1] >> 4 & 3); pix[2] = (dp[3] << 2) + (dp[1] >> 2 & 3); pix[3] = (dp[4] << 2) + (dp[1] & 3); pix[4] = (dp[5] << 2) + (dp[9] & 3); pix[5] = (dp[6] << 2) + (dp[9] >> 2 & 3); pix[6] = (dp[7] << 2) + (dp[9] >> 4 & 3); pix[7] = (dp[8] << 2) + (dp[9] >> 6 ); } if ((row+=2) > height) row = 1; } } void CLASS canon_600_correct() { int row, col, val; static const short mul[4][2] = { { 1141,1145 }, { 1128,1109 }, { 1178,1149 }, { 1128,1109 } }; for (row=0; row < height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col=0; col < width; col++) { if ((val = BAYER(row,col) - black) < 0) val = 0; val = val * mul[row & 3][col & 1] >> 9; BAYER(row,col) = val; } } canon_600_fixed_wb(1311); canon_600_auto_wb(); canon_600_coeff(); maximum = (0x3ff - black) * 1109 >> 9; black = 0; } int CLASS canon_s2is() { unsigned row; for (row=0; row < 100; row++) { fseek (ifp, row*3340 + 3284, SEEK_SET); if (getc(ifp) > 15) return 1; } return 0; } unsigned CLASS getbithuff (int nbits, ushort *huff) { #ifdef LIBRAW_NOTHREADS static unsigned bitbuf=0; static int vbits=0, reset=0; #else #define bitbuf tls->getbits.bitbuf #define vbits tls->getbits.vbits #define reset tls->getbits.reset #endif unsigned c; if (nbits > 25) return 0; if (nbits < 0) return bitbuf = vbits = reset = 0; if (nbits == 0 || vbits < 0) return 0; while (!reset && vbits < nbits && (c = fgetc(ifp)) != EOF && !(reset = zero_after_ff && c == 0xff && fgetc(ifp))) { bitbuf = (bitbuf << 8) + (uchar) c; vbits += 8; } c = bitbuf << (32-vbits) >> (32-nbits); if (huff) { vbits -= huff[c] >> 8; c = (uchar) huff[c]; } else vbits -= nbits; if (vbits < 0) derror(); return c; #ifndef LIBRAW_NOTHREADS #undef bitbuf #undef vbits #undef reset #endif } #define getbits(n) getbithuff(n,0) #define gethuff(h) getbithuff(*h,h+1) /* Construct a decode tree according the specification in *source. The first 16 bytes specify how many codes should be 1-bit, 2-bit 3-bit, etc. Bytes after that are the leaf values. For example, if the source is { 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0, 0x04,0x03,0x05,0x06,0x02,0x07,0x01,0x08,0x09,0x00,0x0a,0x0b,0xff }, then the code is 00 0x04 010 0x03 011 0x05 100 0x06 101 0x02 1100 0x07 1101 0x01 11100 0x08 11101 0x09 11110 0x00 111110 0x0a 1111110 0x0b 1111111 0xff */ ushort * CLASS make_decoder_ref (const uchar **source) { int max, len, h, i, j; const uchar *count; ushort *huff; count = (*source += 16) - 17; for (max=16; max && !count[max]; max--); huff = (ushort *) calloc (1 + (1 << max), sizeof *huff); merror (huff, "make_decoder()"); huff[0] = max; for (h=len=1; len <= max; len++) for (i=0; i < count[len]; i++, ++*source) for (j=0; j < 1 << (max-len); j++) if (h <= 1 << max) huff[h++] = len << 8 | **source; return huff; } ushort * CLASS make_decoder (const uchar *source) { return make_decoder_ref (&source); } void CLASS crw_init_tables (unsigned table, ushort *huff[2]) { static const uchar first_tree[3][29] = { { 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0, 0x04,0x03,0x05,0x06,0x02,0x07,0x01,0x08,0x09,0x00,0x0a,0x0b,0xff }, { 0,2,2,3,1,1,1,1,2,0,0,0,0,0,0,0, 0x03,0x02,0x04,0x01,0x05,0x00,0x06,0x07,0x09,0x08,0x0a,0x0b,0xff }, { 0,0,6,3,1,1,2,0,0,0,0,0,0,0,0,0, 0x06,0x05,0x07,0x04,0x08,0x03,0x09,0x02,0x00,0x0a,0x01,0x0b,0xff }, }; static const uchar second_tree[3][180] = { { 0,2,2,2,1,4,2,1,2,5,1,1,0,0,0,139, 0x03,0x04,0x02,0x05,0x01,0x06,0x07,0x08, 0x12,0x13,0x11,0x14,0x09,0x15,0x22,0x00,0x21,0x16,0x0a,0xf0, 0x23,0x17,0x24,0x31,0x32,0x18,0x19,0x33,0x25,0x41,0x34,0x42, 0x35,0x51,0x36,0x37,0x38,0x29,0x79,0x26,0x1a,0x39,0x56,0x57, 0x28,0x27,0x52,0x55,0x58,0x43,0x76,0x59,0x77,0x54,0x61,0xf9, 0x71,0x78,0x75,0x96,0x97,0x49,0xb7,0x53,0xd7,0x74,0xb6,0x98, 0x47,0x48,0x95,0x69,0x99,0x91,0xfa,0xb8,0x68,0xb5,0xb9,0xd6, 0xf7,0xd8,0x67,0x46,0x45,0x94,0x89,0xf8,0x81,0xd5,0xf6,0xb4, 0x88,0xb1,0x2a,0x44,0x72,0xd9,0x87,0x66,0xd4,0xf5,0x3a,0xa7, 0x73,0xa9,0xa8,0x86,0x62,0xc7,0x65,0xc8,0xc9,0xa1,0xf4,0xd1, 0xe9,0x5a,0x92,0x85,0xa6,0xe7,0x93,0xe8,0xc1,0xc6,0x7a,0x64, 0xe1,0x4a,0x6a,0xe6,0xb3,0xf1,0xd3,0xa5,0x8a,0xb2,0x9a,0xba, 0x84,0xa4,0x63,0xe5,0xc5,0xf3,0xd2,0xc4,0x82,0xaa,0xda,0xe4, 0xf2,0xca,0x83,0xa3,0xa2,0xc3,0xea,0xc2,0xe2,0xe3,0xff,0xff }, { 0,2,2,1,4,1,4,1,3,3,1,0,0,0,0,140, 0x02,0x03,0x01,0x04,0x05,0x12,0x11,0x06, 0x13,0x07,0x08,0x14,0x22,0x09,0x21,0x00,0x23,0x15,0x31,0x32, 0x0a,0x16,0xf0,0x24,0x33,0x41,0x42,0x19,0x17,0x25,0x18,0x51, 0x34,0x43,0x52,0x29,0x35,0x61,0x39,0x71,0x62,0x36,0x53,0x26, 0x38,0x1a,0x37,0x81,0x27,0x91,0x79,0x55,0x45,0x28,0x72,0x59, 0xa1,0xb1,0x44,0x69,0x54,0x58,0xd1,0xfa,0x57,0xe1,0xf1,0xb9, 0x49,0x47,0x63,0x6a,0xf9,0x56,0x46,0xa8,0x2a,0x4a,0x78,0x99, 0x3a,0x75,0x74,0x86,0x65,0xc1,0x76,0xb6,0x96,0xd6,0x89,0x85, 0xc9,0xf5,0x95,0xb4,0xc7,0xf7,0x8a,0x97,0xb8,0x73,0xb7,0xd8, 0xd9,0x87,0xa7,0x7a,0x48,0x82,0x84,0xea,0xf4,0xa6,0xc5,0x5a, 0x94,0xa4,0xc6,0x92,0xc3,0x68,0xb5,0xc8,0xe4,0xe5,0xe6,0xe9, 0xa2,0xa3,0xe3,0xc2,0x66,0x67,0x93,0xaa,0xd4,0xd5,0xe7,0xf8, 0x88,0x9a,0xd7,0x77,0xc4,0x64,0xe2,0x98,0xa5,0xca,0xda,0xe8, 0xf3,0xf6,0xa9,0xb2,0xb3,0xf2,0xd2,0x83,0xba,0xd3,0xff,0xff }, { 0,0,6,2,1,3,3,2,5,1,2,2,8,10,0,117, 0x04,0x05,0x03,0x06,0x02,0x07,0x01,0x08, 0x09,0x12,0x13,0x14,0x11,0x15,0x0a,0x16,0x17,0xf0,0x00,0x22, 0x21,0x18,0x23,0x19,0x24,0x32,0x31,0x25,0x33,0x38,0x37,0x34, 0x35,0x36,0x39,0x79,0x57,0x58,0x59,0x28,0x56,0x78,0x27,0x41, 0x29,0x77,0x26,0x42,0x76,0x99,0x1a,0x55,0x98,0x97,0xf9,0x48, 0x54,0x96,0x89,0x47,0xb7,0x49,0xfa,0x75,0x68,0xb6,0x67,0x69, 0xb9,0xb8,0xd8,0x52,0xd7,0x88,0xb5,0x74,0x51,0x46,0xd9,0xf8, 0x3a,0xd6,0x87,0x45,0x7a,0x95,0xd5,0xf6,0x86,0xb4,0xa9,0x94, 0x53,0x2a,0xa8,0x43,0xf5,0xf7,0xd4,0x66,0xa7,0x5a,0x44,0x8a, 0xc9,0xe8,0xc8,0xe7,0x9a,0x6a,0x73,0x4a,0x61,0xc7,0xf4,0xc6, 0x65,0xe9,0x72,0xe6,0x71,0x91,0x93,0xa6,0xda,0x92,0x85,0x62, 0xf3,0xc5,0xb2,0xa4,0x84,0xba,0x64,0xa5,0xb3,0xd2,0x81,0xe5, 0xd3,0xaa,0xc4,0xca,0xf2,0xb1,0xe4,0xd1,0x83,0x63,0xea,0xc3, 0xe2,0x82,0xf1,0xa3,0xc2,0xa1,0xc1,0xe3,0xa2,0xe1,0xff,0xff } }; if (table > 2) table = 2; huff[0] = make_decoder ( first_tree[table]); huff[1] = make_decoder (second_tree[table]); } /* Return 0 if the image starts with compressed data, 1 if it starts with uncompressed low-order bits. In Canon compressed data, 0xff is always followed by 0x00. */ int CLASS canon_has_lowbits() { uchar test[0x4000]; int ret=1, i; fseek (ifp, 0, SEEK_SET); fread (test, 1, sizeof test, ifp); for (i=540; i < sizeof test - 1; i++) if (test[i] == 0xff) { if (test[i+1]) return 1; ret=0; } return ret; } void CLASS canon_load_raw() { ushort *pixel, *prow, *huff[2]; int nblocks, lowbits, i, c, row, r, save, val; int block, diffbuf[64], leaf, len, diff, carry=0, pnum=0, base[2]; crw_init_tables (tiff_compress, huff); lowbits = canon_has_lowbits(); if (!lowbits) maximum = 0x3ff; fseek (ifp, 540 + lowbits*raw_height*raw_width/4, SEEK_SET); zero_after_ff = 1; getbits(-1); #ifdef LIBRAW_LIBRARY_BUILD try { #endif for (row=0; row < raw_height; row+=8) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif pixel = raw_image + row*raw_width; nblocks = MIN (8, raw_height-row) * raw_width >> 6; for (block=0; block < nblocks; block++) { memset (diffbuf, 0, sizeof diffbuf); for (i=0; i < 64; i++ ) { leaf = gethuff(huff[i > 0]); if (leaf == 0 && i) break; if (leaf == 0xff) continue; i += leaf >> 4; len = leaf & 15; if (len == 0) continue; diff = getbits(len); if ((diff & (1 << (len-1))) == 0) diff -= (1 << len) - 1; if (i < 64) diffbuf[i] = diff; } diffbuf[0] += carry; carry = diffbuf[0]; for (i=0; i < 64; i++ ) { if (pnum++ % raw_width == 0) base[0] = base[1] = 512; if ((pixel[(block << 6) + i] = base[i & 1] += diffbuf[i]) >> 10) derror(); } } if (lowbits) { save = ftell(ifp); fseek (ifp, 26 + row*raw_width/4, SEEK_SET); for (prow=pixel, i=0; i < raw_width*2; i++) { c = fgetc(ifp); for (r=0; r < 8; r+=2, prow++) { val = (*prow << 2) + ((c >> r) & 3); if (raw_width == 2672 && val < 512) val += 2; *prow = val; } } fseek (ifp, save, SEEK_SET); } } #ifdef LIBRAW_LIBRARY_BUILD } catch (...) { FORC(2) free (huff[c]); throw; } #endif FORC(2) free (huff[c]); } int CLASS ljpeg_start (struct jhead *jh, int info_only) { ushort c, tag, len; int cnt = 0; uchar data[0x10000]; const uchar *dp; memset (jh, 0, sizeof *jh); jh->restart = INT_MAX; if ((fgetc(ifp),fgetc(ifp)) != 0xd8) return 0; do { if(feof(ifp)) return 0; if(cnt++ > 1024) return 0; // 1024 tags limit if (!fread (data, 2, 2, ifp)) return 0; tag = data[0] << 8 | data[1]; len = (data[2] << 8 | data[3]) - 2; if (tag <= 0xff00) return 0; fread (data, 1, len, ifp); switch (tag) { case 0xffc3: // start of frame; lossless, Huffman jh->sraw = ((data[7] >> 4) * (data[7] & 15) - 1) & 3; case 0xffc1: case 0xffc0: jh->algo = tag & 0xff; jh->bits = data[0]; jh->high = data[1] << 8 | data[2]; jh->wide = data[3] << 8 | data[4]; jh->clrs = data[5] + jh->sraw; if (len == 9 && !dng_version) getc(ifp); break; case 0xffc4: // define Huffman tables if (info_only) break; for (dp = data; dp < data+len && !((c = *dp++) & -20); ) jh->free[c] = jh->huff[c] = make_decoder_ref (&dp); break; case 0xffda: // start of scan jh->psv = data[1+data[0]*2]; jh->bits -= data[3+data[0]*2] & 15; break; case 0xffdb: FORC(64) jh->quant[c] = data[c*2+1] << 8 | data[c*2+2]; break; case 0xffdd: jh->restart = data[0] << 8 | data[1]; } } while (tag != 0xffda); if (jh->bits > 16 || jh->clrs > 6 || !jh->bits || !jh->high || !jh->wide || !jh->clrs) return 0; if (info_only) return 1; if (!jh->huff[0]) return 0; FORC(19) if (!jh->huff[c+1]) jh->huff[c+1] = jh->huff[c]; if (jh->sraw) { FORC(4) jh->huff[2+c] = jh->huff[1]; FORC(jh->sraw) jh->huff[1+c] = jh->huff[0]; } jh->row = (ushort *) calloc (jh->wide*jh->clrs, 4); merror (jh->row, "ljpeg_start()"); return zero_after_ff = 1; } void CLASS ljpeg_end (struct jhead *jh) { int c; FORC4 if (jh->free[c]) free (jh->free[c]); free (jh->row); } int CLASS ljpeg_diff (ushort *huff) { int len, diff; if(!huff) #ifdef LIBRAW_LIBRARY_BUILD throw LIBRAW_EXCEPTION_IO_CORRUPT; #else longjmp (failure, 2); #endif len = gethuff(huff); if (len == 16 && (!dng_version || dng_version >= 0x1010000)) return -32768; diff = getbits(len); if ((diff & (1 << (len-1))) == 0) diff -= (1 << len) - 1; return diff; } ushort * CLASS ljpeg_row (int jrow, struct jhead *jh) { int col, c, diff, pred, spred=0; ushort mark=0, *row[3]; if (jrow * jh->wide % jh->restart == 0) { FORC(6) jh->vpred[c] = 1 << (jh->bits-1); if (jrow) { fseek (ifp, -2, SEEK_CUR); do mark = (mark << 8) + (c = fgetc(ifp)); while (c != EOF && mark >> 4 != 0xffd); } getbits(-1); } FORC3 row[c] = jh->row + jh->wide*jh->clrs*((jrow+c) & 1); for (col=0; col < jh->wide; col++) FORC(jh->clrs) { diff = ljpeg_diff (jh->huff[c]); if (jh->sraw && c <= jh->sraw && (col | c)) pred = spred; else if (col) pred = row[0][-jh->clrs]; else pred = (jh->vpred[c] += diff) - diff; if (jrow && col) switch (jh->psv) { case 1: break; case 2: pred = row[1][0]; break; case 3: pred = row[1][-jh->clrs]; break; case 4: pred = pred + row[1][0] - row[1][-jh->clrs]; break; case 5: pred = pred + ((row[1][0] - row[1][-jh->clrs]) >> 1); break; case 6: pred = row[1][0] + ((pred - row[1][-jh->clrs]) >> 1); break; case 7: pred = (pred + row[1][0]) >> 1; break; default: pred = 0; } if ((**row = pred + diff) >> jh->bits) derror(); if (c <= jh->sraw) spred = **row; row[0]++; row[1]++; } return row[2]; } void CLASS lossless_jpeg_load_raw() { int jwide, jhigh, jrow, jcol, val, jidx, i, j, row=0, col=0; struct jhead jh; ushort *rp; if (!ljpeg_start (&jh, 0)) return; if(jh.wide<1 || jh.high<1 || jh.clrs<1 || jh.bits <1) #ifdef LIBRAW_LIBRARY_BUILD throw LIBRAW_EXCEPTION_IO_CORRUPT; #else longjmp (failure, 2); #endif jwide = jh.wide * jh.clrs; jhigh = jh.high; if(jh.clrs == 4 && jwide >= raw_width*2) jhigh *= 2; #ifdef LIBRAW_LIBRARY_BUILD try { #endif for (jrow=0; jrow < jh.high; jrow++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif rp = ljpeg_row (jrow, &jh); if (load_flags & 1) row = jrow & 1 ? height-1-jrow/2 : jrow/2; for (jcol=0; jcol < jwide; jcol++) { val = curve[*rp++]; if (cr2_slice[0]) { jidx = jrow*jwide + jcol; i = jidx / (cr2_slice[1]*raw_height); if ((j = i >= cr2_slice[0])) i = cr2_slice[0]; jidx -= i * (cr2_slice[1]*raw_height); row = jidx / cr2_slice[1+j]; col = jidx % cr2_slice[1+j] + i*cr2_slice[1]; } if (raw_width == 3984 && (col -= 2) < 0) col += (row--,raw_width); if(row>raw_height) #ifdef LIBRAW_LIBRARY_BUILD throw LIBRAW_EXCEPTION_IO_CORRUPT; #else longjmp (failure, 3); #endif if ((unsigned) row < raw_height) RAW(row,col) = val; if (++col >= raw_width) col = (row++,0); } } #ifdef LIBRAW_LIBRARY_BUILD } catch (...) { ljpeg_end (&jh); throw; } #endif ljpeg_end (&jh); } void CLASS canon_sraw_load_raw() { struct jhead jh; short *rp=0, (*ip)[4]; int jwide, slice, scol, ecol, row, col, jrow=0, jcol=0, pix[3], c; int v[3]={0,0,0}, ver, hue; #ifdef LIBRAW_LIBRARY_BUILD int saved_w = width, saved_h = height; #endif char *cp; if (!ljpeg_start (&jh, 0) || jh.clrs < 4) return; jwide = (jh.wide >>= 1) * jh.clrs; #ifdef LIBRAW_LIBRARY_BUILD if(load_flags & 256) { width = raw_width; height = raw_height; } try { #endif for (ecol=slice=0; slice <= cr2_slice[0]; slice++) { scol = ecol; ecol += cr2_slice[1] * 2 / jh.clrs; if (!cr2_slice[0] || ecol > raw_width-1) ecol = raw_width & -2; for (row=0; row < height; row += (jh.clrs >> 1) - 1) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif ip = (short (*)[4]) image + row*width; for (col=scol; col < ecol; col+=2, jcol+=jh.clrs) { if ((jcol %= jwide) == 0) rp = (short *) ljpeg_row (jrow++, &jh); if (col >= width) continue; #ifdef LIBRAW_LIBRARY_BUILD if(imgdata.params.raw_processing_options & LIBRAW_PROCESSING_SRAW_NO_INTERPOLATE) { FORC (jh.clrs-2) { ip[col + (c >> 1)*width + (c & 1)][0] = rp[jcol+c]; ip[col + (c >> 1)*width + (c & 1)][1] = ip[col + (c >> 1)*width + (c & 1)][2] = 8192; } ip[col][1] = rp[jcol+jh.clrs-2] - 8192; ip[col][2] = rp[jcol+jh.clrs-1] - 8192; } else if(imgdata.params.raw_processing_options & LIBRAW_PROCESSING_SRAW_NO_RGB) { FORC (jh.clrs-2) ip[col + (c >> 1)*width + (c & 1)][0] = rp[jcol+c]; ip[col][1] = rp[jcol+jh.clrs-2] - 8192; ip[col][2] = rp[jcol+jh.clrs-1] - 8192; } else #endif { FORC (jh.clrs-2) ip[col + (c >> 1)*width + (c & 1)][0] = rp[jcol+c]; ip[col][1] = rp[jcol+jh.clrs-2] - 16384; ip[col][2] = rp[jcol+jh.clrs-1] - 16384; } } } } #ifdef LIBRAW_LIBRARY_BUILD } catch (...) { ljpeg_end (&jh); throw ; } #endif #ifdef LIBRAW_LIBRARY_BUILD if(imgdata.params.raw_processing_options & LIBRAW_PROCESSING_SRAW_NO_INTERPOLATE) { ljpeg_end (&jh); maximum = 0x3fff; height = saved_h; width = saved_w; return; } #endif #ifdef LIBRAW_LIBRARY_BUILD try { #endif for (cp=model2; *cp && !isdigit(*cp); cp++); sscanf (cp, "%d.%d.%d", v, v+1, v+2); ver = (v[0]*1000 + v[1])*1000 + v[2]; hue = (jh.sraw+1) << 2; if (unique_id >= 0x80000281 || (unique_id == 0x80000218 && ver > 1000006)) hue = jh.sraw << 1; ip = (short (*)[4]) image; rp = ip[0]; for (row=0; row < height; row++, ip+=width) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif if (row & (jh.sraw >> 1)) { for (col=0; col < width; col+=2) for (c=1; c < 3; c++) if (row == height-1) { ip[col][c] = ip[col-width][c]; } else { ip[col][c] = (ip[col-width][c] + ip[col+width][c] + 1) >> 1; } } for (col=1; col < width; col+=2) for (c=1; c < 3; c++) if (col == width-1) ip[col][c] = ip[col-1][c]; else ip[col][c] = (ip[col-1][c] + ip[col+1][c] + 1) >> 1; } #ifdef LIBRAW_LIBRARY_BUILD if(!(imgdata.params.raw_processing_options & LIBRAW_PROCESSING_SRAW_NO_RGB) ) #endif for ( ; rp < ip[0]; rp+=4) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif if (unique_id == 0x80000218 || unique_id == 0x80000250 || unique_id == 0x80000261 || unique_id == 0x80000281 || unique_id == 0x80000287) { rp[1] = (rp[1] << 2) + hue; rp[2] = (rp[2] << 2) + hue; pix[0] = rp[0] + (( 50*rp[1] + 22929*rp[2]) >> 14); pix[1] = rp[0] + ((-5640*rp[1] - 11751*rp[2]) >> 14); pix[2] = rp[0] + ((29040*rp[1] - 101*rp[2]) >> 14); } else { if (unique_id < 0x80000218) rp[0] -= 512; pix[0] = rp[0] + rp[2]; pix[2] = rp[0] + rp[1]; pix[1] = rp[0] + ((-778*rp[1] - (rp[2] << 11)) >> 12); } FORC3 rp[c] = CLIP(pix[c] * sraw_mul[c] >> 10); } #ifdef LIBRAW_LIBRARY_BUILD } catch (...) { ljpeg_end (&jh); throw ; } height = saved_h; width = saved_w; #endif ljpeg_end (&jh); maximum = 0x3fff; } void CLASS adobe_copy_pixel (unsigned row, unsigned col, ushort **rp) { int c; if (tiff_samples == 2 && shot_select) (*rp)++; if (raw_image) { if (row < raw_height && col < raw_width) RAW(row,col) = curve[**rp]; *rp += tiff_samples; } else { if (row < height && col < width) FORC(tiff_samples) image[row*width+col][c] = curve[(*rp)[c]]; *rp += tiff_samples; } if (tiff_samples == 2 && shot_select) (*rp)--; } void CLASS ljpeg_idct (struct jhead *jh) { int c, i, j, len, skip, coef; float work[3][8][8]; static float cs[106] = { 0 }; static const uchar zigzag[80] = { 0, 1, 8,16, 9, 2, 3,10,17,24,32,25,18,11, 4, 5,12,19,26,33, 40,48,41,34,27,20,13, 6, 7,14,21,28,35,42,49,56,57,50,43,36, 29,22,15,23,30,37,44,51,58,59,52,45,38,31,39,46,53,60,61,54, 47,55,62,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63 }; if (!cs[0]) FORC(106) cs[c] = cos((c & 31)*M_PI/16)/2; memset (work, 0, sizeof work); work[0][0][0] = jh->vpred[0] += ljpeg_diff (jh->huff[0]) * jh->quant[0]; for (i=1; i < 64; i++ ) { len = gethuff (jh->huff[16]); i += skip = len >> 4; if (!(len &= 15) && skip < 15) break; coef = getbits(len); if ((coef & (1 << (len-1))) == 0) coef -= (1 << len) - 1; ((float *)work)[zigzag[i]] = coef * jh->quant[i]; } FORC(8) work[0][0][c] *= M_SQRT1_2; FORC(8) work[0][c][0] *= M_SQRT1_2; for (i=0; i < 8; i++) for (j=0; j < 8; j++) FORC(8) work[1][i][j] += work[0][i][c] * cs[(j*2+1)*c]; for (i=0; i < 8; i++) for (j=0; j < 8; j++) FORC(8) work[2][i][j] += work[1][c][j] * cs[(i*2+1)*c]; FORC(64) jh->idct[c] = CLIP(((float *)work[2])[c]+0.5); } void CLASS lossless_dng_load_raw() { unsigned save, trow=0, tcol=0, jwide, jrow, jcol, row, col, i, j; struct jhead jh; ushort *rp; while (trow < raw_height) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif save = ftell(ifp); if (tile_length < INT_MAX) fseek (ifp, get4(), SEEK_SET); if (!ljpeg_start (&jh, 0)) break; jwide = jh.wide; if (filters) jwide *= jh.clrs; jwide /= MIN (is_raw, tiff_samples); #ifdef LIBRAW_LIBRARY_BUILD try { #endif switch (jh.algo) { case 0xc1: jh.vpred[0] = 16384; getbits(-1); for (jrow=0; jrow+7 < jh.high; jrow += 8) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (jcol=0; jcol+7 < jh.wide; jcol += 8) { ljpeg_idct (&jh); rp = jh.idct; row = trow + jcol/tile_width + jrow*2; col = tcol + jcol%tile_width; for (i=0; i < 16; i+=2) for (j=0; j < 8; j++) adobe_copy_pixel (row+i, col+j, &rp); } } break; case 0xc3: for (row=col=jrow=0; jrow < jh.high; jrow++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif rp = ljpeg_row (jrow, &jh); for (jcol=0; jcol < jwide; jcol++) { adobe_copy_pixel (trow+row, tcol+col, &rp); if (++col >= tile_width || col >= raw_width) row += 1 + (col = 0); } } } #ifdef LIBRAW_LIBRARY_BUILD } catch (...) { ljpeg_end (&jh); throw ; } #endif fseek (ifp, save+4, SEEK_SET); if ((tcol += tile_width) >= raw_width) trow += tile_length + (tcol = 0); ljpeg_end (&jh); } } void CLASS packed_dng_load_raw() { ushort *pixel, *rp; int row, col; pixel = (ushort *) calloc (raw_width, tiff_samples*sizeof *pixel); merror (pixel, "packed_dng_load_raw()"); #ifdef LIBRAW_LIBRARY_BUILD try { #endif for (row=0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif if (tiff_bps == 16) read_shorts (pixel, raw_width * tiff_samples); else { getbits(-1); for (col=0; col < raw_width * tiff_samples; col++) pixel[col] = getbits(tiff_bps); } for (rp=pixel, col=0; col < raw_width; col++) adobe_copy_pixel (row, col, &rp); } #ifdef LIBRAW_LIBRARY_BUILD } catch (...) { free (pixel); throw ; } #endif free (pixel); } void CLASS pentax_load_raw() { ushort bit[2][15], huff[4097]; int dep, row, col, diff, c, i; ushort vpred[2][2] = {{0,0},{0,0}}, hpred[2]; fseek (ifp, meta_offset, SEEK_SET); dep = (get2() + 12) & 15; fseek (ifp, 12, SEEK_CUR); FORC(dep) bit[0][c] = get2(); FORC(dep) bit[1][c] = fgetc(ifp); FORC(dep) for (i=bit[0][c]; i <= ((bit[0][c]+(4096 >> bit[1][c])-1) & 4095); ) huff[++i] = bit[1][c] << 8 | c; huff[0] = 12; fseek (ifp, data_offset, SEEK_SET); getbits(-1); for (row=0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col=0; col < raw_width; col++) { diff = ljpeg_diff (huff); if (col < 2) hpred[col] = vpred[row & 1][col] += diff; else hpred[col & 1] += diff; RAW(row,col) = hpred[col & 1]; if (hpred[col & 1] >> tiff_bps) derror(); } } } #ifdef LIBRAW_LIBRARY_BUILD void CLASS nikon_coolscan_load_raw() { int bufsize = width*3*tiff_bps/8; if(tiff_bps <= 8) gamma_curve(1.0/imgdata.params.coolscan_nef_gamma,0.,1,255); else gamma_curve(1.0/imgdata.params.coolscan_nef_gamma,0.,1,65535); fseek (ifp, data_offset, SEEK_SET); unsigned char *buf = (unsigned char*)malloc(bufsize); unsigned short *ubuf = (unsigned short *)buf; for(int row = 0; row < raw_height; row++) { int red = fread (buf, 1, bufsize, ifp); unsigned short (*ip)[4] = (unsigned short (*)[4]) image + row*width; if(tiff_bps <= 8) for(int col=0; col 1) step = max / (csize-1); if (ver0 == 0x44 && ver1 == 0x20 && step > 0) { for (i=0; i < csize; i++) curve[i*step] = get2(); for (i=0; i < max; i++) curve[i] = ( curve[i-i%step]*(step-i%step) + curve[i-i%step+step]*(i%step) ) / step; fseek (ifp, meta_offset+562, SEEK_SET); split = get2(); } else if (ver0 != 0x46 && csize <= 0x4001) read_shorts (curve, max=csize); while (curve[max-2] == curve[max-1]) max--; huff = make_decoder (nikon_tree[tree]); fseek (ifp, data_offset, SEEK_SET); getbits(-1); #ifdef LIBRAW_LIBRARY_BUILD try { #endif for (min=row=0; row < height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif if (split && row == split) { free (huff); huff = make_decoder (nikon_tree[tree+1]); max += (min = 16) << 1; } for (col=0; col < raw_width; col++) { i = gethuff(huff); len = i & 15; shl = i >> 4; diff = ((getbits(len-shl) << 1) + 1) << shl >> 1; if ((diff & (1 << (len-1))) == 0) diff -= (1 << len) - !shl; if (col < 2) hpred[col] = vpred[row & 1][col] += diff; else hpred[col & 1] += diff; if ((ushort)(hpred[col & 1] + min) >= max) derror(); RAW(row,col) = curve[LIM((short)hpred[col & 1],0,0x3fff)]; } } #ifdef LIBRAW_LIBRARY_BUILD } catch (...) { free (huff); throw; } #endif free (huff); } void CLASS nikon_yuv_load_raw() { #ifdef LIBRAW_LIBRARY_BUILD if(!image) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif int row, col, yuv[4], rgb[3], b, c; UINT64 bitbuf=0; float cmul[4]; FORC4 { cmul[c] = cam_mul[c]>0.001f?cam_mul[c]:1.f; } for (row=0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col=0; col < raw_width; col++) { if (!(b = col & 1)) { bitbuf = 0; FORC(6) bitbuf |= (UINT64) fgetc(ifp) << c*8; FORC(4) yuv[c] = (bitbuf >> c*12 & 0xfff) - (c >> 1 << 11); } rgb[0] = yuv[b] + 1.370705*yuv[3]; rgb[1] = yuv[b] - 0.337633*yuv[2] - 0.698001*yuv[3]; rgb[2] = yuv[b] + 1.732446*yuv[2]; FORC3 image[row*width+col][c] = curve[LIM(rgb[c],0,0xfff)] / cmul[c]; } } } /* Returns 1 for a Coolpix 995, 0 for anything else. */ int CLASS nikon_e995() { int i, histo[256]; const uchar often[] = { 0x00, 0x55, 0xaa, 0xff }; memset (histo, 0, sizeof histo); fseek (ifp, -2000, SEEK_END); for (i=0; i < 2000; i++) histo[fgetc(ifp)]++; for (i=0; i < 4; i++) if (histo[often[i]] < 200) return 0; return 1; } /* Returns 1 for a Coolpix 2100, 0 for anything else. */ int CLASS nikon_e2100() { uchar t[12]; int i; fseek (ifp, 0, SEEK_SET); for (i=0; i < 1024; i++) { fread (t, 1, 12, ifp); if (((t[2] & t[4] & t[7] & t[9]) >> 4 & t[1] & t[6] & t[8] & t[11] & 3) != 3) return 0; } return 1; } void CLASS nikon_3700() { int bits, i; uchar dp[24]; static const struct { int bits; char t_make[12], t_model[15]; } table[] = { { 0x00, "Pentax", "Optio 33WR" }, { 0x03, "Nikon", "E3200" }, { 0x32, "Nikon", "E3700" }, { 0x33, "Olympus", "C740UZ" } }; fseek (ifp, 3072, SEEK_SET); fread (dp, 1, 24, ifp); bits = (dp[8] & 3) << 4 | (dp[20] & 3); for (i=0; i < sizeof table / sizeof *table; i++) if (bits == table[i].bits) { strcpy (make, table[i].t_make ); strcpy (model, table[i].t_model); } } /* Separates a Minolta DiMAGE Z2 from a Nikon E4300. */ int CLASS minolta_z2() { int i, nz; char tail[424]; fseek (ifp, -sizeof tail, SEEK_END); fread (tail, 1, sizeof tail, ifp); for (nz=i=0; i < sizeof tail; i++) if (tail[i]) nz++; return nz > 20; } void CLASS ppm_thumb() { char *thumb; thumb_length = thumb_width*thumb_height*3; thumb = (char *) malloc (thumb_length); merror (thumb, "ppm_thumb()"); fprintf (ofp, "P6\n%d %d\n255\n", thumb_width, thumb_height); fread (thumb, 1, thumb_length, ifp); fwrite (thumb, 1, thumb_length, ofp); free (thumb); } void CLASS ppm16_thumb() { int i; char *thumb; thumb_length = thumb_width*thumb_height*3; thumb = (char *) calloc (thumb_length, 2); merror (thumb, "ppm16_thumb()"); read_shorts ((ushort *) thumb, thumb_length); for (i=0; i < thumb_length; i++) thumb[i] = ((ushort *) thumb)[i] >> 8; fprintf (ofp, "P6\n%d %d\n255\n", thumb_width, thumb_height); fwrite (thumb, 1, thumb_length, ofp); free (thumb); } void CLASS layer_thumb() { int i, c; char *thumb, map[][4] = { "012","102" }; colors = thumb_misc >> 5 & 7; thumb_length = thumb_width*thumb_height; thumb = (char *) calloc (colors, thumb_length); merror (thumb, "layer_thumb()"); fprintf (ofp, "P%d\n%d %d\n255\n", 5 + (colors >> 1), thumb_width, thumb_height); fread (thumb, thumb_length, colors, ifp); for (i=0; i < thumb_length; i++) FORCC putc (thumb[i+thumb_length*(map[thumb_misc >> 8][c]-'0')], ofp); free (thumb); } void CLASS rollei_thumb() { unsigned i; ushort *thumb; thumb_length = thumb_width * thumb_height; thumb = (ushort *) calloc (thumb_length, 2); merror (thumb, "rollei_thumb()"); fprintf (ofp, "P6\n%d %d\n255\n", thumb_width, thumb_height); read_shorts (thumb, thumb_length); for (i=0; i < thumb_length; i++) { putc (thumb[i] << 3, ofp); putc (thumb[i] >> 5 << 2, ofp); putc (thumb[i] >> 11 << 3, ofp); } free (thumb); } void CLASS rollei_load_raw() { uchar pixel[10]; unsigned iten=0, isix, i, buffer=0, todo[16]; isix = raw_width * raw_height * 5 / 8; while (fread (pixel, 1, 10, ifp) == 10) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (i=0; i < 10; i+=2) { todo[i] = iten++; todo[i+1] = pixel[i] << 8 | pixel[i+1]; buffer = pixel[i] >> 2 | buffer << 6; } for ( ; i < 16; i+=2) { todo[i] = isix++; todo[i+1] = buffer >> (14-i)*5; } for (i=0; i < 16; i+=2) raw_image[todo[i]] = (todo[i+1] & 0x3ff); } maximum = 0x3ff; } int CLASS raw (unsigned row, unsigned col) { return (row < raw_height && col < raw_width) ? RAW(row,col) : 0; } void CLASS phase_one_flat_field (int is_float, int nc) { ushort head[8]; unsigned wide, high, y, x, c, rend, cend, row, col; float *mrow, num, mult[4]; read_shorts (head, 8); if (head[2] * head[3] * head[4] * head[5] == 0) return; wide = head[2] / head[4] + (head[2] % head[4] != 0); high = head[3] / head[5] + (head[3] % head[5] != 0); mrow = (float *) calloc (nc*wide, sizeof *mrow); merror (mrow, "phase_one_flat_field()"); for (y=0; y < high; y++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (x=0; x < wide; x++) for (c=0; c < nc; c+=2) { num = is_float ? getreal(11) : get2()/32768.0; if (y==0) mrow[c*wide+x] = num; else mrow[(c+1)*wide+x] = (num - mrow[c*wide+x]) / head[5]; } if (y==0) continue; rend = head[1] + y*head[5]; for (row = rend-head[5]; row < raw_height && row < rend && row < head[1]+head[3]-head[5]; row++) { for (x=1; x < wide; x++) { for (c=0; c < nc; c+=2) { mult[c] = mrow[c*wide+x-1]; mult[c+1] = (mrow[c*wide+x] - mult[c]) / head[4]; } cend = head[0] + x*head[4]; for (col = cend-head[4]; col < raw_width && col < cend && col < head[0]+head[2]-head[4]; col++) { c = nc > 2 ? FC(row-top_margin,col-left_margin) : 0; if (!(c & 1)) { c = RAW(row,col) * mult[c]; RAW(row,col) = LIM(c,0,65535); } for (c=0; c < nc; c+=2) mult[c] += mult[c+1]; } } for (x=0; x < wide; x++) for (c=0; c < nc; c+=2) mrow[c*wide+x] += mrow[(c+1)*wide+x]; } } free (mrow); } int CLASS phase_one_correct() { unsigned entries, tag, data, save, col, row, type; int len, i, j, k, cip, val[4], dev[4], sum, max; int head[9], diff, mindiff=INT_MAX, off_412=0; /* static */ const signed char dir[12][2] = { {-1,-1}, {-1,1}, {1,-1}, {1,1}, {-2,0}, {0,-2}, {0,2}, {2,0}, {-2,-2}, {-2,2}, {2,-2}, {2,2} }; float poly[8], num, cfrac, frac, mult[2], *yval[2]={NULL,NULL}; ushort *xval[2]; int qmult_applied = 0, qlin_applied = 0; #ifdef LIBRAW_LIBRARY_BUILD if (!meta_length) #else if (half_size || !meta_length) #endif return 0; #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("Phase One correction...\n")); #endif fseek (ifp, meta_offset, SEEK_SET); order = get2(); fseek (ifp, 6, SEEK_CUR); fseek (ifp, meta_offset+get4(), SEEK_SET); entries = get4(); get4(); #ifdef LIBRAW_LIBRARY_BUILD try { #endif while (entries--) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif tag = get4(); len = get4(); data = get4(); save = ftell(ifp); fseek (ifp, meta_offset+data, SEEK_SET); if (tag == 0x419) { /* Polynomial curve */ for (get4(), i=0; i < 8; i++) poly[i] = getreal(11); poly[3] += (ph1.tag_210 - poly[7]) * poly[6] + 1; for (i=0; i < 0x10000; i++) { num = (poly[5]*i + poly[3])*i + poly[1]; curve[i] = LIM(num,0,65535); } goto apply; /* apply to right half */ } else if (tag == 0x41a) { /* Polynomial curve */ for (i=0; i < 4; i++) poly[i] = getreal(11); for (i=0; i < 0x10000; i++) { for (num=0, j=4; j--; ) num = num * i + poly[j]; curve[i] = LIM(num+i,0,65535); } apply: /* apply to whole image */ for (row=0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col = (tag & 1)*ph1.split_col; col < raw_width; col++) RAW(row,col) = curve[RAW(row,col)]; } } else if (tag == 0x400) { /* Sensor defects */ while ((len -= 8) >= 0) { col = get2(); row = get2(); type = get2(); get2(); if (col >= raw_width) continue; if (type == 131 || type == 137) /* Bad column */ for (row=0; row < raw_height; row++) if (FC(row-top_margin,col-left_margin) == 1) { for (sum=i=0; i < 4; i++) sum += val[i] = raw (row+dir[i][0], col+dir[i][1]); for (max=i=0; i < 4; i++) { dev[i] = abs((val[i] << 2) - sum); if (dev[max] < dev[i]) max = i; } RAW(row,col) = (sum - val[max])/3.0 + 0.5; } else { for (sum=0, i=8; i < 12; i++) sum += raw (row+dir[i][0], col+dir[i][1]); RAW(row,col) = 0.5 + sum * 0.0732233 + (raw(row,col-2) + raw(row,col+2)) * 0.3535534; } else if (type == 129) { /* Bad pixel */ if (row >= raw_height) continue; j = (FC(row-top_margin,col-left_margin) != 1) * 4; for (sum=0, i=j; i < j+8; i++) sum += raw (row+dir[i][0], col+dir[i][1]); RAW(row,col) = (sum + 4) >> 3; } } } else if (tag == 0x401) { /* All-color flat fields */ phase_one_flat_field (1, 2); } else if (tag == 0x416 || tag == 0x410) { phase_one_flat_field (0, 2); } else if (tag == 0x40b) { /* Red+blue flat field */ phase_one_flat_field (0, 4); } else if (tag == 0x412) { fseek (ifp, 36, SEEK_CUR); diff = abs (get2() - ph1.tag_21a); if (mindiff > diff) { mindiff = diff; off_412 = ftell(ifp) - 38; } } else if (tag == 0x41f && !qlin_applied) { /* Quadrant linearization */ ushort lc[2][2][16], ref[16]; int qr, qc; for (qr = 0; qr < 2; qr++) for (qc = 0; qc < 2; qc++) for (i = 0; i < 16; i++) lc[qr][qc][i] = get4(); for (i = 0; i < 16; i++) { int v = 0; for (qr = 0; qr < 2; qr++) for (qc = 0; qc < 2; qc++) v += lc[qr][qc][i]; ref[i] = (v + 2) >> 2; } for (qr = 0; qr < 2; qr++) { for (qc = 0; qc < 2; qc++) { int cx[19], cf[19]; for (i = 0; i < 16; i++) { cx[1+i] = lc[qr][qc][i]; cf[1+i] = ref[i]; } cx[0] = cf[0] = 0; cx[17] = cf[17] = ((unsigned int)ref[15] * 65535) / lc[qr][qc][15]; cf[18] = cx[18] = 65535; cubic_spline(cx, cf, 19); for (row = (qr ? ph1.split_row : 0); row < (qr ? raw_height : ph1.split_row); row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col = (qc ? ph1.split_col : 0); col < (qc ? raw_width : ph1.split_col); col++) RAW(row,col) = curve[RAW(row,col)]; } } } qlin_applied = 1; } else if (tag == 0x41e && !qmult_applied) { /* Quadrant multipliers */ float qmult[2][2] = { { 1, 1 }, { 1, 1 } }; get4(); get4(); get4(); get4(); qmult[0][0] = 1.0 + getreal(11); get4(); get4(); get4(); get4(); get4(); qmult[0][1] = 1.0 + getreal(11); get4(); get4(); get4(); qmult[1][0] = 1.0 + getreal(11); get4(); get4(); get4(); qmult[1][1] = 1.0 + getreal(11); for (row=0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col=0; col < raw_width; col++) { i = qmult[row >= ph1.split_row][col >= ph1.split_col] * RAW(row,col); RAW(row,col) = LIM(i,0,65535); } } qmult_applied = 1; } else if (tag == 0x431 && !qmult_applied) { /* Quadrant combined */ ushort lc[2][2][7], ref[7]; int qr, qc; for (i = 0; i < 7; i++) ref[i] = get4(); for (qr = 0; qr < 2; qr++) for (qc = 0; qc < 2; qc++) for (i = 0; i < 7; i++) lc[qr][qc][i] = get4(); for (qr = 0; qr < 2; qr++) { for (qc = 0; qc < 2; qc++) { int cx[9], cf[9]; for (i = 0; i < 7; i++) { cx[1+i] = ref[i]; cf[1+i] = ((unsigned) ref[i] * lc[qr][qc][i]) / 10000; } cx[0] = cf[0] = 0; cx[8] = cf[8] = 65535; cubic_spline(cx, cf, 9); for (row = (qr ? ph1.split_row : 0); row < (qr ? raw_height : ph1.split_row); row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col = (qc ? ph1.split_col : 0); col < (qc ? raw_width : ph1.split_col); col++) RAW(row,col) = curve[RAW(row,col)]; } } } qmult_applied = 1; qlin_applied = 1; } fseek (ifp, save, SEEK_SET); } if (off_412) { fseek (ifp, off_412, SEEK_SET); for (i=0; i < 9; i++) head[i] = get4() & 0x7fff; yval[0] = (float *) calloc (head[1]*head[3] + head[2]*head[4], 6); merror (yval[0], "phase_one_correct()"); yval[1] = (float *) (yval[0] + head[1]*head[3]); xval[0] = (ushort *) (yval[1] + head[2]*head[4]); xval[1] = (ushort *) (xval[0] + head[1]*head[3]); get2(); for (i=0; i < 2; i++) for (j=0; j < head[i+1]*head[i+3]; j++) yval[i][j] = getreal(11); for (i=0; i < 2; i++) for (j=0; j < head[i+1]*head[i+3]; j++) xval[i][j] = get2(); for (row=0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col=0; col < raw_width; col++) { cfrac = (float) col * head[3] / raw_width; cfrac -= cip = cfrac; num = RAW(row,col) * 0.5; for (i=cip; i < cip+2; i++) { for (k=j=0; j < head[1]; j++) if (num < xval[0][k = head[1]*i+j]) break; frac = (j == 0 || j == head[1]) ? 0 : (xval[0][k] - num) / (xval[0][k] - xval[0][k-1]); mult[i-cip] = yval[0][k-1] * frac + yval[0][k] * (1-frac); } i = ((mult[0] * (1-cfrac) + mult[1] * cfrac) * row + num) * 2; RAW(row,col) = LIM(i,0,65535); } } free (yval[0]); } #ifdef LIBRAW_LIBRARY_BUILD } catch (...) { if(yval[0]) free(yval[0]); return LIBRAW_CANCELLED_BY_CALLBACK; } #endif return 0; } void CLASS phase_one_load_raw() { int a, b, i; ushort akey, bkey, t_mask; fseek (ifp, ph1.key_off, SEEK_SET); akey = get2(); bkey = get2(); t_mask = ph1.format == 1 ? 0x5555:0x1354; #ifdef LIBRAW_LIBRARY_BUILD if (ph1.black_col || ph1.black_row ) { imgdata.rawdata.ph1_cblack = (short(*)[2])calloc(raw_height*2,sizeof(ushort)); merror(imgdata.rawdata.ph1_cblack,"phase_one_load_raw()"); imgdata.rawdata.ph1_rblack = (short(*)[2])calloc(raw_width*2,sizeof(ushort)); merror(imgdata.rawdata.ph1_rblack,"phase_one_load_raw()"); if (ph1.black_col) { fseek (ifp, ph1.black_col, SEEK_SET); read_shorts ((ushort *)imgdata.rawdata.ph1_cblack[0], raw_height*2); } if (ph1.black_row) { fseek (ifp, ph1.black_row, SEEK_SET); read_shorts ((ushort *) imgdata.rawdata.ph1_rblack[0], raw_width*2); } } #endif fseek (ifp, data_offset, SEEK_SET); read_shorts (raw_image, raw_width*raw_height); if (ph1.format) for (i=0; i < raw_width*raw_height; i+=2) { a = raw_image[i+0] ^ akey; b = raw_image[i+1] ^ bkey; raw_image[i+0] = (a & t_mask) | (b & ~t_mask); raw_image[i+1] = (b & t_mask) | (a & ~t_mask); } } unsigned CLASS ph1_bithuff (int nbits, ushort *huff) { #ifndef LIBRAW_NOTHREADS #define bitbuf tls->ph1_bits.bitbuf #define vbits tls->ph1_bits.vbits #else static UINT64 bitbuf=0; static int vbits=0; #endif unsigned c; if (nbits == -1) return bitbuf = vbits = 0; if (nbits == 0) return 0; if (vbits < nbits) { bitbuf = bitbuf << 32 | get4(); vbits += 32; } c = bitbuf << (64-vbits) >> (64-nbits); if (huff) { vbits -= huff[c] >> 8; return (uchar) huff[c]; } vbits -= nbits; return c; #ifndef LIBRAW_NOTHREADS #undef bitbuf #undef vbits #endif } #define ph1_bits(n) ph1_bithuff(n,0) #define ph1_huff(h) ph1_bithuff(*h,h+1) void CLASS phase_one_load_raw_c() { static const int length[] = { 8,7,6,9,11,10,5,12,14,13 }; int *offset, len[2], pred[2], row, col, i, j; ushort *pixel; short (*c_black)[2], (*r_black)[2]; #ifdef LIBRAW_LIBRARY_BUILD if(ph1.format == 6) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif pixel = (ushort *) calloc (raw_width*3 + raw_height*4, 2); merror (pixel, "phase_one_load_raw_c()"); offset = (int *) (pixel + raw_width); fseek (ifp, strip_offset, SEEK_SET); for (row=0; row < raw_height; row++) offset[row] = get4(); c_black = (short (*)[2]) (offset + raw_height); fseek (ifp, ph1.black_col, SEEK_SET); if (ph1.black_col) read_shorts ((ushort *) c_black[0], raw_height*2); r_black = c_black + raw_height; fseek (ifp, ph1.black_row, SEEK_SET); if (ph1.black_row) read_shorts ((ushort *) r_black[0], raw_width*2); #ifdef LIBRAW_LIBRARY_BUILD // Copy data to internal copy (ever if not read) if (ph1.black_col || ph1.black_row ) { imgdata.rawdata.ph1_cblack = (short(*)[2])calloc(raw_height*2,sizeof(ushort)); merror(imgdata.rawdata.ph1_cblack,"phase_one_load_raw_c()"); memmove(imgdata.rawdata.ph1_cblack,(ushort*)c_black[0],raw_height*2*sizeof(ushort)); imgdata.rawdata.ph1_rblack = (short(*)[2])calloc(raw_width*2,sizeof(ushort)); merror(imgdata.rawdata.ph1_rblack,"phase_one_load_raw_c()"); memmove(imgdata.rawdata.ph1_rblack,(ushort*)r_black[0],raw_width*2*sizeof(ushort)); } #endif for (i=0; i < 256; i++) curve[i] = i*i / 3.969 + 0.5; #ifdef LIBRAW_LIBRARY_BUILD try { #endif for (row=0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif fseek (ifp, data_offset + offset[row], SEEK_SET); ph1_bits(-1); pred[0] = pred[1] = 0; for (col=0; col < raw_width; col++) { if (col >= (raw_width & -8)) len[0] = len[1] = 14; else if ((col & 7) == 0) for (i=0; i < 2; i++) { for (j=0; j < 5 && !ph1_bits(1); j++); if (j--) len[i] = length[j*2 + ph1_bits(1)]; } if ((i = len[col & 1]) == 14) pixel[col] = pred[col & 1] = ph1_bits(16); else pixel[col] = pred[col & 1] += ph1_bits(i) + 1 - (1 << (i - 1)); if (pred[col & 1] >> 16) derror(); if (ph1.format == 5 && pixel[col] < 256) pixel[col] = curve[pixel[col]]; } #ifndef LIBRAW_LIBRARY_BUILD for (col=0; col < raw_width; col++) { int shift = ph1.format == 8? 0: 2; i = (pixel[col] << shift) - ph1.t_black + c_black[row][col >= ph1.split_col] + r_black[col][row >= ph1.split_row]; if (i > 0) RAW(row,col) = i; } #else if(ph1.format == 8) memmove(&RAW(row,0),&pixel[0],raw_width*2); else for (col=0; col < raw_width; col++) RAW(row,col) = pixel[col] << 2; #endif } #ifdef LIBRAW_LIBRARY_BUILD } catch(...) { free (pixel); throw; } #endif free (pixel); maximum = 0xfffc - ph1.t_black; } void CLASS hasselblad_load_raw() { struct jhead jh; int shot, row, col, *back[5], len[2], diff[12], pred, sh, f, s, c; unsigned upix, urow, ucol; ushort *ip; if (!ljpeg_start (&jh, 0)) return; order = 0x4949; ph1_bits(-1); #ifdef LIBRAW_LIBRARY_BUILD try { #endif back[4] = (int *) calloc (raw_width, 3*sizeof **back); merror (back[4], "hasselblad_load_raw()"); FORC3 back[c] = back[4] + c*raw_width; cblack[6] >>= sh = tiff_samples > 1; shot = LIM(shot_select, 1, tiff_samples) - 1; for (row=0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif FORC4 back[(c+3) & 3] = back[c]; for (col=0; col < raw_width; col+=2) { for (s=0; s < tiff_samples*2; s+=2) { FORC(2) len[c] = ph1_huff(jh.huff[0]); FORC(2) { diff[s+c] = ph1_bits(len[c]); if ((diff[s+c] & (1 << (len[c]-1))) == 0) diff[s+c] -= (1 << len[c]) - 1; if (diff[s+c] == 65535) diff[s+c] = -32768; } } for (s=col; s < col+2; s++) { pred = 0x8000 + load_flags; if (col) pred = back[2][s-2]; if (col && row > 1) switch (jh.psv) { case 11: pred += back[0][s]/2 - back[0][s-2]/2; break; } f = (row & 1)*3 ^ ((col+s) & 1); FORC (tiff_samples) { pred += diff[(s & 1)*tiff_samples+c]; upix = pred >> sh & 0xffff; if (raw_image && c == shot) RAW(row,s) = upix; if (image) { urow = row-top_margin + (c & 1); ucol = col-left_margin - ((c >> 1) & 1); ip = &image[urow*width+ucol][f]; if (urow < height && ucol < width) *ip = c < 4 ? upix : (*ip + upix) >> 1; } } back[2][s] = pred; } } } #ifdef LIBRAW_LIBRARY_BUILD } catch (...){ free (back[4]); ljpeg_end (&jh); throw; } #endif free (back[4]); ljpeg_end (&jh); if (image) mix_green = 1; } void CLASS leaf_hdr_load_raw() { ushort *pixel=0; unsigned tile=0, r, c, row, col; if (!filters) { #ifdef LIBRAW_LIBRARY_BUILD if(!image) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif pixel = (ushort *) calloc (raw_width, sizeof *pixel); merror (pixel, "leaf_hdr_load_raw()"); } #ifdef LIBRAW_LIBRARY_BUILD try { #endif FORC(tiff_samples) for (r=0; r < raw_height; r++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif if (r % tile_length == 0) { fseek (ifp, data_offset + 4*tile++, SEEK_SET); fseek (ifp, get4(), SEEK_SET); } if (filters && c != shot_select) continue; if (filters) pixel = raw_image + r*raw_width; read_shorts (pixel, raw_width); if (!filters && (row = r - top_margin) < height) for (col=0; col < width; col++) image[row*width+col][c] = pixel[col+left_margin]; } #ifdef LIBRAW_LIBRARY_BUILD } catch (...) { if(!filters) free(pixel); throw; } #endif if (!filters) { maximum = 0xffff; raw_color = 1; free (pixel); } } void CLASS unpacked_load_raw() { int row, col, bits=0; while (1 << ++bits < maximum); read_shorts (raw_image, raw_width*raw_height); for (row=0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col=0; col < raw_width; col++) if ((RAW(row,col) >>= load_flags) >> bits && (unsigned) (row-top_margin) < height && (unsigned) (col-left_margin) < width) derror(); } } void CLASS unpacked_load_raw_reversed() { int row, col, bits=0; while (1 << ++bits < maximum); for (row=raw_height-1; row >= 0; row--) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif read_shorts (&raw_image[row*raw_width], raw_width); for (col=0; col < raw_width; col++) if ((RAW(row,col) >>= load_flags) >> bits && (unsigned) (row-top_margin) < height && (unsigned) (col-left_margin) < width) derror(); } } void CLASS sinar_4shot_load_raw() { ushort *pixel; unsigned shot, row, col, r, c; if (raw_image) { shot = LIM (shot_select, 1, 4) - 1; fseek (ifp, data_offset + shot*4, SEEK_SET); fseek (ifp, get4(), SEEK_SET); unpacked_load_raw(); return; } #ifdef LIBRAW_LIBRARY_BUILD else if(!image) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif pixel = (ushort *) calloc (raw_width, sizeof *pixel); merror (pixel, "sinar_4shot_load_raw()"); #ifdef LIBRAW_LIBRARY_BUILD try { #endif for (shot=0; shot < 4; shot++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif fseek (ifp, data_offset + shot*4, SEEK_SET); fseek (ifp, get4(), SEEK_SET); for (row=0; row < raw_height; row++) { read_shorts (pixel, raw_width); if ((r = row-top_margin - (shot >> 1 & 1)) >= height) continue; for (col=0; col < raw_width; col++) { if ((c = col-left_margin - (shot & 1)) >= width) continue; image[r*width+c][(row & 1)*3 ^ (~col & 1)] = pixel[col]; } } } #ifdef LIBRAW_LIBRARY_BUILD } catch (...) { free(pixel); throw; } #endif free (pixel); mix_green = 1; } void CLASS imacon_full_load_raw() { int row, col; if (!image) return; #ifdef LIBRAW_LIBRARY_BUILD unsigned short *buf = (unsigned short *)malloc(width*3*sizeof(unsigned short)); merror(buf,"imacon_full_load_raw"); #endif for (row=0; row < height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); read_shorts(buf,width*3); unsigned short (*rowp)[4] = &image[row*width]; for (col=0; col < width; col++) { rowp[col][0]=buf[col*3]; rowp[col][1]=buf[col*3+1]; rowp[col][2]=buf[col*3+2]; rowp[col][3]=0; } #else for (col=0; col < width; col++) read_shorts (image[row*width+col], 3); #endif } #ifdef LIBRAW_LIBRARY_BUILD free(buf); #endif } void CLASS packed_load_raw() { int vbits=0, bwide, rbits, bite, half, irow, row, col, val, i; UINT64 bitbuf=0; bwide = raw_width * tiff_bps / 8; bwide += bwide & load_flags >> 7; rbits = bwide * 8 - raw_width * tiff_bps; if (load_flags & 1) bwide = bwide * 16 / 15; bite = 8 + (load_flags & 24); half = (raw_height+1) >> 1; for (irow=0; irow < raw_height; irow++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif row = irow; if (load_flags & 2 && (row = irow % half * 2 + irow / half) == 1 && load_flags & 4) { if (vbits=0, tiff_compress) fseek (ifp, data_offset - (-half*bwide & -2048), SEEK_SET); else { fseek (ifp, 0, SEEK_END); fseek (ifp, ftell(ifp) >> 3 << 2, SEEK_SET); } } for (col=0; col < raw_width; col++) { for (vbits -= tiff_bps; vbits < 0; vbits += bite) { bitbuf <<= bite; for (i=0; i < bite; i+=8) bitbuf |= (unsigned) (fgetc(ifp) << i); } val = bitbuf << (64-tiff_bps-vbits) >> (64-tiff_bps); RAW(row,col ^ (load_flags >> 6 & 1)) = val; if (load_flags & 1 && (col % 10) == 9 && fgetc(ifp) && row < height+top_margin && col < width+left_margin) derror(); } vbits -= rbits; } } #ifdef LIBRAW_LIBRARY_BUILD ushort raw_stride; void CLASS parse_broadcom () { /* This structure is at offset 0xb0 from the 'BRCM' ident. */ struct { uint8_t umode[32]; uint16_t uwidth; uint16_t uheight; uint16_t padding_right; uint16_t padding_down; uint32_t unknown_block[6]; uint16_t transform; uint16_t format; uint8_t bayer_order; uint8_t bayer_format; } header; header.bayer_order = 0; fseek (ifp, 0xb0 - 0x20, SEEK_CUR); fread (&header, 1, sizeof(header), ifp); raw_stride = ((((((header.uwidth + header.padding_right)*5)+3)>>2) + 0x1f)&(~0x1f)); raw_width = width = header.uwidth; raw_height = height = header.uheight; filters = 0x16161616; /* default Bayer order is 2, BGGR */ switch (header.bayer_order) { case 0: /* RGGB */ filters = 0x94949494; break; case 1: /* GBRG */ filters = 0x49494949; break; case 3: /* GRBG */ filters = 0x61616161; break; } } void CLASS broadcom_load_raw() { uchar *data, *dp; int rev, row, col, c; rev = 3 * (order == 0x4949); data = (uchar *) malloc (raw_stride*2); merror (data, "broadcom_load_raw()"); for (row=0; row < raw_height; row++) { if (fread (data+raw_stride, 1, raw_stride, ifp) < raw_stride) derror(); FORC(raw_stride) data[c] = data[raw_stride+(c ^ rev)]; for (dp=data, col=0; col < raw_width; dp+=5, col+=4) FORC4 RAW(row,col+c) = (dp[c] << 2) | (dp[4] >> (c << 1) & 3); } free (data); } #endif void CLASS nokia_load_raw() { uchar *data, *dp; int rev, dwide, row, col, c; double sum[]={0,0}; rev = 3 * (order == 0x4949); dwide = (raw_width * 5 + 1) / 4; data = (uchar *) malloc (dwide*2); merror (data, "nokia_load_raw()"); #ifdef LIBRAW_LIBRARY_BUILD try { #endif for (row=0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif if (fread (data+dwide, 1, dwide, ifp) < dwide) derror(); FORC(dwide) data[c] = data[dwide+(c ^ rev)]; for (dp=data, col=0; col < raw_width; dp+=5, col+=4) FORC4 RAW(row,col+c) = (dp[c] << 2) | (dp[4] >> (c << 1) & 3); } #ifdef LIBRAW_LIBRARY_BUILD } catch (...){ free (data); throw; } #endif free (data); maximum = 0x3ff; if (strncmp(make,"OmniVision",10)) return; row = raw_height/2; FORC(width-1) { sum[ c & 1] += SQR(RAW(row,c)-RAW(row+1,c+1)); sum[~c & 1] += SQR(RAW(row+1,c)-RAW(row,c+1)); } if (sum[1] > sum[0]) filters = 0x4b4b4b4b; } void CLASS android_tight_load_raw() { uchar *data, *dp; int bwide, row, col, c; bwide = -(-5*raw_width >> 5) << 3; data = (uchar *) malloc (bwide); merror (data, "android_tight_load_raw()"); for (row=0; row < raw_height; row++) { if (fread (data, 1, bwide, ifp) < bwide) derror(); for (dp=data, col=0; col < raw_width; dp+=5, col+=4) FORC4 RAW(row,col+c) = (dp[c] << 2) | (dp[4] >> (c << 1) & 3); } free (data); } void CLASS android_loose_load_raw() { uchar *data, *dp; int bwide, row, col, c; UINT64 bitbuf=0; bwide = (raw_width+5)/6 << 3; data = (uchar *) malloc (bwide); merror (data, "android_loose_load_raw()"); for (row=0; row < raw_height; row++) { if (fread (data, 1, bwide, ifp) < bwide) derror(); for (dp=data, col=0; col < raw_width; dp+=8, col+=6) { FORC(8) bitbuf = (bitbuf << 8) | dp[c^7]; FORC(6) RAW(row,col+c) = (bitbuf >> c*10) & 0x3ff; } } free (data); } void CLASS canon_rmf_load_raw() { int row, col, bits, orow, ocol, c; #ifdef LIBRAW_LIBRARY_BUILD int *words = (int*)malloc(sizeof(int)*(raw_width/3+1)); merror(words,"canon_rmf_load_raw"); #endif for (row=0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); fread(words,sizeof(int),raw_width/3,ifp); for (col=0; col < raw_width-2; col+=3) { bits = words[col/3]; FORC3 { orow = row; if ((ocol = col+c-4) < 0) { ocol += raw_width; if ((orow -= 2) < 0) orow += raw_height; } RAW(orow,ocol) = curve[bits >> (10*c+2) & 0x3ff]; } } #else for (col=0; col < raw_width-2; col+=3) { bits = get4(); FORC3 { orow = row; if ((ocol = col+c-4) < 0) { ocol += raw_width; if ((orow -= 2) < 0) orow += raw_height; } RAW(orow,ocol) = curve[bits >> (10*c+2) & 0x3ff]; } } #endif } #ifdef LIBRAW_LIBRARY_BUILD free(words); #endif maximum = curve[0x3ff]; } unsigned CLASS pana_bits (int nbits) { #ifndef LIBRAW_NOTHREADS #define buf tls->pana_bits.buf #define vbits tls->pana_bits.vbits #else static uchar buf[0x4000]; static int vbits; #endif int byte; if (!nbits) return vbits=0; if (!vbits) { fread (buf+load_flags, 1, 0x4000-load_flags, ifp); fread (buf, 1, load_flags, ifp); } vbits = (vbits - nbits) & 0x1ffff; byte = vbits >> 3 ^ 0x3ff0; return (buf[byte] | buf[byte+1] << 8) >> (vbits & 7) & ~((~0u) << nbits); #ifndef LIBRAW_NOTHREADS #undef buf #undef vbits #endif } void CLASS panasonic_load_raw() { int row, col, i, j, sh=0, pred[2], nonz[2]; pana_bits(0); for (row = 0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col=0; col < raw_width; col++) { if ((i = col % 14) == 0) pred[0] = pred[1] = nonz[0] = nonz[1] = 0; if (i % 3 == 2) sh = 4 >> (3 - pana_bits(2)); if (nonz[i & 1]) { if ((j = pana_bits(8))) { if ((pred[i & 1] -= 0x80 << sh) < 0 || sh == 4) pred[i & 1] &= ~((~0u) << sh); pred[i & 1] += j << sh; } } else if ((nonz[i & 1] = pana_bits(8)) || i > 11) pred[i & 1] = nonz[i & 1] << 4 | pana_bits(4); if ((RAW(row, col) = pred[col & 1]) > 4098 && col < width && row < height) derror(); } } } void CLASS olympus_load_raw() { ushort huff[4096]; int row, col, nbits, sign, low, high, i, c, w, n, nw; int acarry[2][3], *carry, pred, diff; huff[n=0] = 0xc0c; for (i=12; i--; ) FORC(2048 >> i) huff[++n] = (i+1) << 8 | i; fseek (ifp, 7, SEEK_CUR); getbits(-1); for (row=0; row < height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif memset (acarry, 0, sizeof acarry); for (col=0; col < raw_width; col++) { carry = acarry[col & 1]; i = 2 * (carry[2] < 3); for (nbits=2+i; (ushort) carry[0] >> (nbits+i); nbits++); low = (sign = getbits(3)) & 3; sign = sign << 29 >> 31; if ((high = getbithuff(12,huff)) == 12) high = getbits(16-nbits) >> 1; carry[0] = (high << nbits) | getbits(nbits); diff = (carry[0] ^ sign) + carry[1]; carry[1] = (diff*3 + carry[1]) >> 5; carry[2] = carry[0] > 16 ? 0 : carry[2]+1; if (col >= width) continue; if (row < 2 && col < 2) pred = 0; else if (row < 2) pred = RAW(row,col-2); else if (col < 2) pred = RAW(row-2,col); else { w = RAW(row,col-2); n = RAW(row-2,col); nw = RAW(row-2,col-2); if ((w < nw && nw < n) || (n < nw && nw < w)) { if (ABS(w-nw) > 32 || ABS(n-nw) > 32) pred = w + n - nw; else pred = (w + n) >> 1; } else pred = ABS(w-nw) > ABS(n-nw) ? w : n; } if ((RAW(row,col) = pred + ((diff << 2) | low)) >> 12) derror(); } } } void CLASS minolta_rd175_load_raw() { uchar pixel[768]; unsigned irow, box, row, col; for (irow=0; irow < 1481; irow++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif if (fread (pixel, 1, 768, ifp) < 768) derror(); box = irow / 82; row = irow % 82 * 12 + ((box < 12) ? box | 1 : (box-12)*2); switch (irow) { case 1477: case 1479: continue; case 1476: row = 984; break; case 1480: row = 985; break; case 1478: row = 985; box = 1; } if ((box < 12) && (box & 1)) { for (col=0; col < 1533; col++, row ^= 1) if (col != 1) RAW(row,col) = (col+1) & 2 ? pixel[col/2-1] + pixel[col/2+1] : pixel[col/2] << 1; RAW(row,1) = pixel[1] << 1; RAW(row,1533) = pixel[765] << 1; } else for (col=row & 1; col < 1534; col+=2) RAW(row,col) = pixel[col/2] << 1; } maximum = 0xff << 1; } void CLASS quicktake_100_load_raw() { uchar pixel[484][644]; static const short gstep[16] = { -89,-60,-44,-32,-22,-15,-8,-2,2,8,15,22,32,44,60,89 }; static const short rstep[6][4] = { { -3,-1,1,3 }, { -5,-1,1,5 }, { -8,-2,2,8 }, { -13,-3,3,13 }, { -19,-4,4,19 }, { -28,-6,6,28 } }; static const short t_curve[256] = { 0,1,2,3,4,5,6,7,8,9,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27, 28,29,30,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,53, 54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,74,75,76,77,78, 79,80,81,82,83,84,86,88,90,92,94,97,99,101,103,105,107,110,112,114,116, 118,120,123,125,127,129,131,134,136,138,140,142,144,147,149,151,153,155, 158,160,162,164,166,168,171,173,175,177,179,181,184,186,188,190,192,195, 197,199,201,203,205,208,210,212,214,216,218,221,223,226,230,235,239,244, 248,252,257,261,265,270,274,278,283,287,291,296,300,305,309,313,318,322, 326,331,335,339,344,348,352,357,361,365,370,374,379,383,387,392,396,400, 405,409,413,418,422,426,431,435,440,444,448,453,457,461,466,470,474,479, 483,487,492,496,500,508,519,531,542,553,564,575,587,598,609,620,631,643, 654,665,676,687,698,710,721,732,743,754,766,777,788,799,810,822,833,844, 855,866,878,889,900,911,922,933,945,956,967,978,989,1001,1012,1023 }; int rb, row, col, sharp, val=0; #ifdef LIBRAW_LIBRARY_BUILD if(width>640 || height > 480) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif getbits(-1); memset (pixel, 0x80, sizeof pixel); for (row=2; row < height+2; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col=2+(row & 1); col < width+2; col+=2) { val = ((pixel[row-1][col-1] + 2*pixel[row-1][col+1] + pixel[row][col-2]) >> 2) + gstep[getbits(4)]; pixel[row][col] = val = LIM(val,0,255); if (col < 4) pixel[row][col-2] = pixel[row+1][~row & 1] = val; if (row == 2) pixel[row-1][col+1] = pixel[row-1][col+3] = val; } pixel[row][col] = val; } for (rb=0; rb < 2; rb++) for (row=2+rb; row < height+2; row+=2) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col=3-(row & 1); col < width+2; col+=2) { if (row < 4 || col < 4) sharp = 2; else { val = ABS(pixel[row-2][col] - pixel[row][col-2]) + ABS(pixel[row-2][col] - pixel[row-2][col-2]) + ABS(pixel[row][col-2] - pixel[row-2][col-2]); sharp = val < 4 ? 0 : val < 8 ? 1 : val < 16 ? 2 : val < 32 ? 3 : val < 48 ? 4 : 5; } val = ((pixel[row-2][col] + pixel[row][col-2]) >> 1) + rstep[sharp][getbits(2)]; pixel[row][col] = val = LIM(val,0,255); if (row < 4) pixel[row-2][col+2] = val; if (col < 4) pixel[row+2][col-2] = val; } } for (row=2; row < height+2; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col=3-(row & 1); col < width+2; col+=2) { val = ((pixel[row][col-1] + (pixel[row][col] << 2) + pixel[row][col+1]) >> 1) - 0x100; pixel[row][col] = LIM(val,0,255); } } for (row=0; row < height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col=0; col < width; col++) RAW(row,col) = t_curve[pixel[row+2][col+2]]; } maximum = 0x3ff; } #define radc_token(tree) ((signed char) getbithuff(8,huff[tree])) #define FORYX for (y=1; y < 3; y++) for (x=col+1; x >= col; x--) #define PREDICTOR (c ? (buf[c][y-1][x] + buf[c][y][x+1]) / 2 \ : (buf[c][y-1][x+1] + 2*buf[c][y-1][x] + buf[c][y][x+1]) / 4) #ifdef __GNUC__ # if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) # pragma GCC optimize("no-aggressive-loop-optimizations") # endif #endif void CLASS kodak_radc_load_raw() { #ifdef LIBRAW_LIBRARY_BUILD // All kodak radc images are 768x512 if(width>768 || raw_width>768 || height > 512 || raw_height>512 ) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif static const signed char src[] = { 1,1, 2,3, 3,4, 4,2, 5,7, 6,5, 7,6, 7,8, 1,0, 2,1, 3,3, 4,4, 5,2, 6,7, 7,6, 8,5, 8,8, 2,1, 2,3, 3,0, 3,2, 3,4, 4,6, 5,5, 6,7, 6,8, 2,0, 2,1, 2,3, 3,2, 4,4, 5,6, 6,7, 7,5, 7,8, 2,1, 2,4, 3,0, 3,2, 3,3, 4,7, 5,5, 6,6, 6,8, 2,3, 3,1, 3,2, 3,4, 3,5, 3,6, 4,7, 5,0, 5,8, 2,3, 2,6, 3,0, 3,1, 4,4, 4,5, 4,7, 5,2, 5,8, 2,4, 2,7, 3,3, 3,6, 4,1, 4,2, 4,5, 5,0, 5,8, 2,6, 3,1, 3,3, 3,5, 3,7, 3,8, 4,0, 5,2, 5,4, 2,0, 2,1, 3,2, 3,3, 4,4, 4,5, 5,6, 5,7, 4,8, 1,0, 2,2, 2,-2, 1,-3, 1,3, 2,-17, 2,-5, 2,5, 2,17, 2,-7, 2,2, 2,9, 2,18, 2,-18, 2,-9, 2,-2, 2,7, 2,-28, 2,28, 3,-49, 3,-9, 3,9, 4,49, 5,-79, 5,79, 2,-1, 2,13, 2,26, 3,39, 4,-16, 5,55, 6,-37, 6,76, 2,-26, 2,-13, 2,1, 3,-39, 4,16, 5,-55, 6,-76, 6,37 }; ushort huff[19][256]; int row, col, tree, nreps, rep, step, i, c, s, r, x, y, val; short last[3] = { 16,16,16 }, mul[3], buf[3][3][386]; static const ushort pt[] = { 0,0, 1280,1344, 2320,3616, 3328,8000, 4095,16383, 65535,16383 }; for (i=2; i < 12; i+=2) for (c=pt[i-2]; c <= pt[i]; c++) curve[c] = (float) (c-pt[i-2]) / (pt[i]-pt[i-2]) * (pt[i+1]-pt[i-1]) + pt[i-1] + 0.5; for (s=i=0; i < sizeof src; i+=2) FORC(256 >> src[i]) ((ushort *)huff)[s++] = src[i] << 8 | (uchar) src[i+1]; s = kodak_cbpp == 243 ? 2 : 3; FORC(256) huff[18][c] = (8-s) << 8 | c >> s << s | 1 << (s-1); getbits(-1); for (i=0; i < sizeof(buf)/sizeof(short); i++) ((short *)buf)[i] = 2048; for (row=0; row < height; row+=4) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif FORC3 mul[c] = getbits(6); #ifdef LIBRAW_LIBRARY_BUILD if(!mul[0] || !mul[1] || !mul[2]) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif FORC3 { val = ((0x1000000/last[c] + 0x7ff) >> 12) * mul[c]; s = val > 65564 ? 10:12; x = ~((~0u) << (s-1)); val <<= 12-s; for (i=0; i < sizeof(buf[0])/sizeof(short); i++) ((short *)buf[c])[i] = (((short *)buf[c])[i] * val + x) >> s; last[c] = mul[c]; for (r=0; r <= !c; r++) { buf[c][1][width/2] = buf[c][2][width/2] = mul[c] << 7; for (tree=1, col=width/2; col > 0; ) { if ((tree = radc_token(tree))) { col -= 2; if (tree == 8) FORYX buf[c][y][x] = (uchar) radc_token(18) * mul[c]; else FORYX buf[c][y][x] = radc_token(tree+10) * 16 + PREDICTOR; } else do { nreps = (col > 2) ? radc_token(9) + 1 : 1; for (rep=0; rep < 8 && rep < nreps && col > 0; rep++) { col -= 2; FORYX buf[c][y][x] = PREDICTOR; if (rep & 1) { step = radc_token(10) << 4; FORYX buf[c][y][x] += step; } } } while (nreps == 9); } for (y=0; y < 2; y++) for (x=0; x < width/2; x++) { val = (buf[c][y+1][x] << 4) / mul[c]; if (val < 0) val = 0; if (c) RAW(row+y*2+c-1,x*2+2-c) = val; else RAW(row+r*2+y,x*2+y) = val; } memcpy (buf[c][0]+!c, buf[c][2], sizeof buf[c][0]-2*!c); } } for (y=row; y < row+4; y++) for (x=0; x < width; x++) if ((x+y) & 1) { r = x ? x-1 : x+1; s = x+1 < width ? x+1 : x-1; val = (RAW(y,x)-2048)*2 + (RAW(y,r)+RAW(y,s))/2; if (val < 0) val = 0; RAW(y,x) = val; } } for (i=0; i < height*width; i++) raw_image[i] = curve[raw_image[i]]; maximum = 0x3fff; } #undef FORYX #undef PREDICTOR #ifdef NO_JPEG void CLASS kodak_jpeg_load_raw() {} void CLASS lossy_dng_load_raw() {} #else #ifndef LIBRAW_LIBRARY_BUILD METHODDEF(boolean) fill_input_buffer (j_decompress_ptr cinfo) { static uchar jpeg_buffer[4096]; size_t nbytes; nbytes = fread (jpeg_buffer, 1, 4096, ifp); swab (jpeg_buffer, jpeg_buffer, nbytes); cinfo->src->next_input_byte = jpeg_buffer; cinfo->src->bytes_in_buffer = nbytes; return TRUE; } void CLASS kodak_jpeg_load_raw() { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPARRAY buf; JSAMPLE (*pixel)[3]; int row, col; cinfo.err = jpeg_std_error (&jerr); jpeg_create_decompress (&cinfo); jpeg_stdio_src (&cinfo, ifp); cinfo.src->fill_input_buffer = fill_input_buffer; jpeg_read_header (&cinfo, TRUE); jpeg_start_decompress (&cinfo); if ((cinfo.output_width != width ) || (cinfo.output_height*2 != height ) || (cinfo.output_components != 3 )) { fprintf (stderr,_("%s: incorrect JPEG dimensions\n"), ifname); jpeg_destroy_decompress (&cinfo); longjmp (failure, 3); } buf = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, width*3, 1); while (cinfo.output_scanline < cinfo.output_height) { row = cinfo.output_scanline * 2; jpeg_read_scanlines (&cinfo, buf, 1); pixel = (JSAMPLE (*)[3]) buf[0]; for (col=0; col < width; col+=2) { RAW(row+0,col+0) = pixel[col+0][1] << 1; RAW(row+1,col+1) = pixel[col+1][1] << 1; RAW(row+0,col+1) = pixel[col][0] + pixel[col+1][0]; RAW(row+1,col+0) = pixel[col][2] + pixel[col+1][2]; } } jpeg_finish_decompress (&cinfo); jpeg_destroy_decompress (&cinfo); maximum = 0xff << 1; } #else struct jpegErrorManager { struct jpeg_error_mgr pub; }; static void jpegErrorExit (j_common_ptr cinfo) { jpegErrorManager* myerr = (jpegErrorManager*) cinfo->err; throw LIBRAW_EXCEPTION_DECODE_JPEG; } // LibRaw's Kodak_jpeg_load_raw void CLASS kodak_jpeg_load_raw() { if(data_size < 1) throw LIBRAW_EXCEPTION_DECODE_JPEG; int row, col; jpegErrorManager jerr; struct jpeg_decompress_struct cinfo; cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = jpegErrorExit; unsigned char *jpg_buf = (unsigned char *)malloc(data_size); merror(jpg_buf,"kodak_jpeg_load_raw"); unsigned char *pixel_buf = (unsigned char*) malloc(width*3); jpeg_create_decompress (&cinfo); merror(pixel_buf,"kodak_jpeg_load_raw"); fread(jpg_buf,data_size,1,ifp); swab ((char*)jpg_buf, (char*)jpg_buf, data_size); try { jpeg_mem_src(&cinfo, jpg_buf, data_size); int rc = jpeg_read_header(&cinfo, TRUE); if(rc!=1) throw LIBRAW_EXCEPTION_DECODE_JPEG; jpeg_start_decompress (&cinfo); if ((cinfo.output_width != width ) || (cinfo.output_height*2 != height ) || (cinfo.output_components != 3 )) { throw LIBRAW_EXCEPTION_DECODE_JPEG; } unsigned char *buf[1]; buf[0] = pixel_buf; while (cinfo.output_scanline < cinfo.output_height) { checkCancel(); row = cinfo.output_scanline * 2; jpeg_read_scanlines (&cinfo, buf, 1); unsigned char (*pixel)[3] = (unsigned char (*)[3]) buf[0]; for (col=0; col < width; col+=2) { RAW(row+0,col+0) = pixel[col+0][1] << 1; RAW(row+1,col+1) = pixel[col+1][1] << 1; RAW(row+0,col+1) = pixel[col][0] + pixel[col+1][0]; RAW(row+1,col+0) = pixel[col][2] + pixel[col+1][2]; } } } catch (...) { jpeg_finish_decompress (&cinfo); jpeg_destroy_decompress (&cinfo); free(jpg_buf); free(pixel_buf); throw; } jpeg_finish_decompress (&cinfo); jpeg_destroy_decompress (&cinfo); free(jpg_buf); free(pixel_buf); maximum = 0xff << 1; } #endif #ifndef LIBRAW_LIBRARY_BUILD void CLASS gamma_curve (double pwr, double ts, int mode, int imax); #endif void CLASS lossy_dng_load_raw() { #ifdef LIBRAW_LIBRARY_BUILD if(!image) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPARRAY buf; JSAMPLE (*pixel)[3]; unsigned sorder=order, ntags, opcode, deg, i, j, c; unsigned save=data_offset-4, trow=0, tcol=0, row, col; ushort cur[3][256]; double coeff[9], tot; if (meta_offset) { fseek (ifp, meta_offset, SEEK_SET); order = 0x4d4d; ntags = get4(); while (ntags--) { opcode = get4(); get4(); get4(); if (opcode != 8) { fseek (ifp, get4(), SEEK_CUR); continue; } fseek (ifp, 20, SEEK_CUR); if ((c = get4()) > 2) break; fseek (ifp, 12, SEEK_CUR); if ((deg = get4()) > 8) break; for (i=0; i <= deg && i < 9; i++) coeff[i] = getreal(12); for (i=0; i < 256; i++) { for (tot=j=0; j <= deg; j++) tot += coeff[j] * pow(i/255.0, (int)j); cur[c][i] = tot*0xffff; } } order = sorder; } else { gamma_curve (1/2.4, 12.92, 1, 255); FORC3 memcpy (cur[c], curve, sizeof cur[0]); } cinfo.err = jpeg_std_error (&jerr); jpeg_create_decompress (&cinfo); while (trow < raw_height) { fseek (ifp, save+=4, SEEK_SET); if (tile_length < INT_MAX) fseek (ifp, get4(), SEEK_SET); #ifdef LIBRAW_LIBRARY_BUILD if(libraw_internal_data.internal_data.input->jpeg_src(&cinfo) == -1) { jpeg_destroy_decompress(&cinfo); throw LIBRAW_EXCEPTION_DECODE_JPEG; } #else jpeg_stdio_src (&cinfo, ifp); #endif jpeg_read_header (&cinfo, TRUE); jpeg_start_decompress (&cinfo); buf = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, cinfo.output_width*3, 1); #ifdef LIBRAW_LIBRARY_BUILD try { #endif while (cinfo.output_scanline < cinfo.output_height && (row = trow + cinfo.output_scanline) < height) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif jpeg_read_scanlines (&cinfo, buf, 1); pixel = (JSAMPLE (*)[3]) buf[0]; for (col=0; col < cinfo.output_width && tcol+col < width; col++) { FORC3 image[row*width+tcol+col][c] = cur[c][pixel[col][c]]; } } #ifdef LIBRAW_LIBRARY_BUILD } catch(...) { jpeg_destroy_decompress (&cinfo); throw; } #endif jpeg_abort_decompress (&cinfo); if ((tcol += tile_width) >= raw_width) trow += tile_length + (tcol = 0); } jpeg_destroy_decompress (&cinfo); maximum = 0xffff; } #endif void CLASS kodak_dc120_load_raw() { static const int mul[4] = { 162, 192, 187, 92 }; static const int add[4] = { 0, 636, 424, 212 }; uchar pixel[848]; int row, shift, col; for (row=0; row < height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif if (fread (pixel, 1, 848, ifp) < 848) derror(); shift = row * mul[row & 3] + add[row & 3]; for (col=0; col < width; col++) RAW(row,col) = (ushort) pixel[(col + shift) % 848]; } maximum = 0xff; } void CLASS eight_bit_load_raw() { uchar *pixel; unsigned row, col; pixel = (uchar *) calloc (raw_width, sizeof *pixel); merror (pixel, "eight_bit_load_raw()"); #ifdef LIBRAW_LIBRARY_BUILD try { #endif for (row=0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif if (fread (pixel, 1, raw_width, ifp) < raw_width) derror(); for (col=0; col < raw_width; col++) RAW(row,col) = curve[pixel[col]]; } #ifdef LIBRAW_LIBRARY_BUILD } catch(...) { free (pixel); throw; } #endif free (pixel); maximum = curve[0xff]; } void CLASS kodak_c330_load_raw() { #ifdef LIBRAW_LIBRARY_BUILD if(!image) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif uchar *pixel; int row, col, y, cb, cr, rgb[3], c; pixel = (uchar *) calloc (raw_width, 2*sizeof *pixel); merror (pixel, "kodak_c330_load_raw()"); #ifdef LIBRAW_LIBRARY_BUILD try { #endif for (row=0; row < height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif if (fread (pixel, raw_width, 2, ifp) < 2) derror(); if (load_flags && (row & 31) == 31) fseek (ifp, raw_width*32, SEEK_CUR); for (col=0; col < width; col++) { y = pixel[col*2]; cb = pixel[(col*2 & -4) | 1] - 128; cr = pixel[(col*2 & -4) | 3] - 128; rgb[1] = y - ((cb + cr + 2) >> 2); rgb[2] = rgb[1] + cb; rgb[0] = rgb[1] + cr; FORC3 image[row*width+col][c] = curve[LIM(rgb[c],0,255)]; } } #ifdef LIBRAW_LIBRARY_BUILD } catch(...) { free (pixel); throw; } #endif free (pixel); maximum = curve[0xff]; } void CLASS kodak_c603_load_raw() { #ifdef LIBRAW_LIBRARY_BUILD if(!image) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif uchar *pixel; int row, col, y, cb, cr, rgb[3], c; pixel = (uchar *) calloc (raw_width, 3*sizeof *pixel); merror (pixel, "kodak_c603_load_raw()"); #ifdef LIBRAW_LIBRARY_BUILD try { #endif for (row=0; row < height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif if (~row & 1) if (fread (pixel, raw_width, 3, ifp) < 3) derror(); for (col=0; col < width; col++) { y = pixel[width*2*(row & 1) + col]; cb = pixel[width + (col & -2)] - 128; cr = pixel[width + (col & -2)+1] - 128; rgb[1] = y - ((cb + cr + 2) >> 2); rgb[2] = rgb[1] + cb; rgb[0] = rgb[1] + cr; FORC3 image[row*width+col][c] = curve[LIM(rgb[c],0,255)]; } } #ifdef LIBRAW_LIBRARY_BUILD } catch(...) { free (pixel); throw; } #endif free (pixel); maximum = curve[0xff]; } void CLASS kodak_262_load_raw() { static const uchar kodak_tree[2][26] = { { 0,1,5,1,1,2,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9 }, { 0,3,1,1,1,1,1,2,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9 } }; ushort *huff[2]; uchar *pixel; int *strip, ns, c, row, col, chess, pi=0, pi1, pi2, pred, val; FORC(2) huff[c] = make_decoder (kodak_tree[c]); ns = (raw_height+63) >> 5; pixel = (uchar *) malloc (raw_width*32 + ns*4); merror (pixel, "kodak_262_load_raw()"); strip = (int *) (pixel + raw_width*32); order = 0x4d4d; FORC(ns) strip[c] = get4(); #ifdef LIBRAW_LIBRARY_BUILD try { #endif for (row=0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif if ((row & 31) == 0) { fseek (ifp, strip[row >> 5], SEEK_SET); getbits(-1); pi = 0; } for (col=0; col < raw_width; col++) { chess = (row + col) & 1; pi1 = chess ? pi-2 : pi-raw_width-1; pi2 = chess ? pi-2*raw_width : pi-raw_width+1; if (col <= chess) pi1 = -1; if (pi1 < 0) pi1 = pi2; if (pi2 < 0) pi2 = pi1; if (pi1 < 0 && col > 1) pi1 = pi2 = pi-2; pred = (pi1 < 0) ? 0 : (pixel[pi1] + pixel[pi2]) >> 1; pixel[pi] = val = pred + ljpeg_diff (huff[chess]); if (val >> 8) derror(); val = curve[pixel[pi++]]; RAW(row,col) = val; } } #ifdef LIBRAW_LIBRARY_BUILD } catch(...) { free (pixel); throw; } #endif free (pixel); FORC(2) free (huff[c]); } int CLASS kodak_65000_decode (short *out, int bsize) { uchar c, blen[768]; ushort raw[6]; INT64 bitbuf=0; int save, bits=0, i, j, len, diff; save = ftell(ifp); bsize = (bsize + 3) & -4; for (i=0; i < bsize; i+=2) { c = fgetc(ifp); if ((blen[i ] = c & 15) > 12 || (blen[i+1] = c >> 4) > 12 ) { fseek (ifp, save, SEEK_SET); for (i=0; i < bsize; i+=8) { read_shorts (raw, 6); out[i ] = raw[0] >> 12 << 8 | raw[2] >> 12 << 4 | raw[4] >> 12; out[i+1] = raw[1] >> 12 << 8 | raw[3] >> 12 << 4 | raw[5] >> 12; for (j=0; j < 6; j++) out[i+2+j] = raw[j] & 0xfff; } return 1; } } if ((bsize & 7) == 4) { bitbuf = fgetc(ifp) << 8; bitbuf += fgetc(ifp); bits = 16; } for (i=0; i < bsize; i++) { len = blen[i]; if (bits < len) { for (j=0; j < 32; j+=8) bitbuf += (INT64) fgetc(ifp) << (bits+(j^8)); bits += 32; } diff = bitbuf & (0xffff >> (16-len)); bitbuf >>= len; bits -= len; if ((diff & (1 << (len-1))) == 0) diff -= (1 << len) - 1; out[i] = diff; } return 0; } void CLASS kodak_65000_load_raw() { short buf[272]; /* extra room for data stored w/o predictor */ int row, col, len, pred[2], ret, i; for (row=0; row < height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col=0; col < width; col+=256) { pred[0] = pred[1] = 0; len = MIN (256, width-col); ret = kodak_65000_decode (buf, len); for (i=0; i < len; i++) { int idx = ret ? buf[i] : (pred[i & 1] += buf[i]); if(idx >=0 && idx <= 0xffff) { if ((RAW(row,col+i) = curve[idx]) >> 12) derror(); } else derror(); } } } } void CLASS kodak_ycbcr_load_raw() { #ifdef LIBRAW_LIBRARY_BUILD if(!image) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif short buf[384], *bp; int row, col, len, c, i, j, k, y[2][2], cb, cr, rgb[3]; ushort *ip; if (!image) return; unsigned int bits = (load_flags && load_flags > 9 && load_flags < 17)?load_flags:10; for (row=0; row < height; row+=2) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col=0; col < width; col+=128) { len = MIN (128, width-col); kodak_65000_decode (buf, len*3); y[0][1] = y[1][1] = cb = cr = 0; for (bp=buf, i=0; i < len; i+=2, bp+=2) { cb += bp[4]; cr += bp[5]; rgb[1] = -((cb + cr + 2) >> 2); rgb[2] = rgb[1] + cb; rgb[0] = rgb[1] + cr; for (j=0; j < 2; j++) for (k=0; k < 2; k++) { if ((y[j][k] = y[j][k^1] + *bp++) >> bits) derror(); ip = image[(row+j)*width + col+i+k]; FORC3 ip[c] = curve[LIM(y[j][k]+rgb[c], 0, 0xfff)]; } } } } } void CLASS kodak_rgb_load_raw() { #ifdef LIBRAW_LIBRARY_BUILD if(!image) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif short buf[768], *bp; int row, col, len, c, i, rgb[3],ret; ushort *ip=image[0]; for (row=0; row < height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col=0; col < width; col+=256) { len = MIN (256, width-col); ret = kodak_65000_decode (buf, len*3); memset (rgb, 0, sizeof rgb); for (bp=buf, i=0; i < len; i++, ip+=4) #ifdef LIBRAW_LIBRARY_BUILD if(load_flags == 12) { FORC3 ip[c] = ret ? (*bp++) : (rgb[c] += *bp++); } else #endif FORC3 if ((ip[c] = ret ? (*bp++) : (rgb[c] += *bp++)) >> 12) derror(); } } } void CLASS kodak_thumb_load_raw() { #ifdef LIBRAW_LIBRARY_BUILD if(!image) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif int row, col; colors = thumb_misc >> 5; for (row=0; row < height; row++) for (col=0; col < width; col++) read_shorts (image[row*width+col], colors); maximum = (1 << (thumb_misc & 31)) - 1; } void CLASS sony_decrypt (unsigned *data, int len, int start, int key) { #ifndef LIBRAW_NOTHREADS #define pad tls->sony_decrypt.pad #define p tls->sony_decrypt.p #else static unsigned pad[128], p; #endif if (start) { for (p=0; p < 4; p++) pad[p] = key = key * 48828125 + 1; pad[3] = pad[3] << 1 | (pad[0]^pad[2]) >> 31; for (p=4; p < 127; p++) pad[p] = (pad[p-4]^pad[p-2]) << 1 | (pad[p-3]^pad[p-1]) >> 31; for (p=0; p < 127; p++) pad[p] = htonl(pad[p]); } while (len--) { *data++ ^= pad[p & 127] = pad[(p+1) & 127] ^ pad[(p+65) & 127]; p++; } #ifndef LIBRAW_NOTHREADS #undef pad #undef p #endif } void CLASS sony_load_raw() { uchar head[40]; ushort *pixel; unsigned i, key, row, col; fseek (ifp, 200896, SEEK_SET); fseek (ifp, (unsigned) fgetc(ifp)*4 - 1, SEEK_CUR); order = 0x4d4d; key = get4(); fseek (ifp, 164600, SEEK_SET); fread (head, 1, 40, ifp); sony_decrypt ((unsigned *) head, 10, 1, key); for (i=26; i-- > 22; ) key = key << 8 | head[i]; fseek (ifp, data_offset, SEEK_SET); for (row=0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif pixel = raw_image + row*raw_width; if (fread (pixel, 2, raw_width, ifp) < raw_width) derror(); sony_decrypt ((unsigned *) pixel, raw_width/2, !row, key); for (col=0; col < raw_width; col++) if ((pixel[col] = ntohs(pixel[col])) >> 14) derror(); } maximum = 0x3ff0; } void CLASS sony_arw_load_raw() { ushort huff[32770]; static const ushort tab[18] = { 0xf11,0xf10,0xe0f,0xd0e,0xc0d,0xb0c,0xa0b,0x90a,0x809, 0x708,0x607,0x506,0x405,0x304,0x303,0x300,0x202,0x201 }; int i, c, n, col, row, sum=0; huff[0] = 15; for (n=i=0; i < 18; i++) FORC(32768 >> (tab[i] >> 8)) huff[++n] = tab[i]; getbits(-1); for (col = raw_width; col--; ) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (row=0; row < raw_height+1; row+=2) { if (row == raw_height) row = 1; if ((sum += ljpeg_diff(huff)) >> 12) derror(); if (row < height) RAW(row,col) = sum; } } } void CLASS sony_arw2_load_raw() { uchar *data, *dp; ushort pix[16]; int row, col, val, max, min, imax, imin, sh, bit, i; data = (uchar *) malloc (raw_width+1); merror (data, "sony_arw2_load_raw()"); #ifdef LIBRAW_LIBRARY_BUILD try { #endif for (row=0; row < height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif fread (data, 1, raw_width, ifp); for (dp=data, col=0; col < raw_width-30; dp+=16) { max = 0x7ff & (val = sget4(dp)); min = 0x7ff & val >> 11; imax = 0x0f & val >> 22; imin = 0x0f & val >> 26; for (sh=0; sh < 4 && 0x80 << sh <= max-min; sh++); #ifdef LIBRAW_LIBRARY_BUILD /* flag checks if outside of loop */ if(! (imgdata.params.raw_processing_options & LIBRAW_PROCESSING_SONYARW2_ALLFLAGS) // no flag set || (imgdata.params.raw_processing_options & LIBRAW_PROCESSING_SONYARW2_DELTATOVALUE) ) { for (bit=30, i=0; i < 16; i++) if (i == imax) pix[i] = max; else if (i == imin) pix[i] = min; else { pix[i] = ((sget2(dp+(bit >> 3)) >> (bit & 7) & 0x7f) << sh) + min; if (pix[i] > 0x7ff) pix[i] = 0x7ff; bit += 7; } } else if(imgdata.params.raw_processing_options & LIBRAW_PROCESSING_SONYARW2_BASEONLY) { for (bit=30, i=0; i < 16; i++) if (i == imax) pix[i] = max; else if (i == imin) pix[i] = min; else pix[i]=0; } else if(imgdata.params.raw_processing_options & LIBRAW_PROCESSING_SONYARW2_DELTAONLY) { for (bit=30, i=0; i < 16; i++) if (i == imax) pix[i] = 0; else if (i == imin) pix[i] = 0; else { pix[i] = ((sget2(dp+(bit >> 3)) >> (bit & 7) & 0x7f) << sh) + min; if (pix[i] > 0x7ff) pix[i] = 0x7ff; bit += 7; } } else if(imgdata.params.raw_processing_options & LIBRAW_PROCESSING_SONYARW2_DELTAZEROBASE) { for (bit=30, i=0; i < 16; i++) if (i == imax) pix[i] = 0; else if (i == imin) pix[i] = 0; else { pix[i] = ((sget2(dp+(bit >> 3)) >> (bit & 7) & 0x7f) << sh); if (pix[i] > 0x7ff) pix[i] = 0x7ff; bit += 7; } } #else /* unaltered dcraw processing */ for (bit=30, i=0; i < 16; i++) if (i == imax) pix[i] = max; else if (i == imin) pix[i] = min; else { pix[i] = ((sget2(dp+(bit >> 3)) >> (bit & 7) & 0x7f) << sh) + min; if (pix[i] > 0x7ff) pix[i] = 0x7ff; bit += 7; } #endif #ifdef LIBRAW_LIBRARY_BUILD if(imgdata.params.raw_processing_options & LIBRAW_PROCESSING_SONYARW2_DELTATOVALUE) { for (i=0; i < 16; i++, col+=2) { unsigned slope = pix[i] < 1001? 2 : curve[pix[i]<<1]-curve[(pix[i]<<1)-2]; unsigned step = 1 << sh; RAW(row,col)=curve[pix[i]<<1]>black+imgdata.params.sony_arw2_posterization_thr? LIM(((slope*step*1000)/(curve[pix[i]<<1]-black)),0,10000):0; } } else { for (i=0; i < 16; i++, col+=2) RAW(row,col) = curve[pix[i] << 1]; } #else for (i=0; i < 16; i++, col+=2) RAW(row,col) = curve[pix[i] << 1] >> 2; #endif col -= col & 1 ? 1:31; } } #ifdef LIBRAW_LIBRARY_BUILD } catch(...) { free (data); throw; } if(imgdata.params.raw_processing_options & LIBRAW_PROCESSING_SONYARW2_DELTATOVALUE) maximum=10000; #endif free (data); } void CLASS samsung_load_raw() { int row, col, c, i, dir, op[4], len[4]; order = 0x4949; for (row=0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif fseek (ifp, strip_offset+row*4, SEEK_SET); fseek (ifp, data_offset+get4(), SEEK_SET); ph1_bits(-1); FORC4 len[c] = row < 2 ? 7:4; for (col=0; col < raw_width; col+=16) { dir = ph1_bits(1); FORC4 op[c] = ph1_bits(2); FORC4 switch (op[c]) { case 3: len[c] = ph1_bits(4); break; case 2: len[c]--; break; case 1: len[c]++; } for (c=0; c < 16; c+=2) { i = len[((c & 1) << 1) | (c >> 3)]; RAW(row,col+c) = ((signed) ph1_bits(i) << (32-i) >> (32-i)) + (dir ? RAW(row+(~c | -2),col+c) : col ? RAW(row,col+(c | -2)) : 128); if (c == 14) c = -1; } } } for (row=0; row < raw_height-1; row+=2) for (col=0; col < raw_width-1; col+=2) SWAP (RAW(row,col+1), RAW(row+1,col)); } void CLASS samsung2_load_raw() { static const ushort tab[14] = { 0x304,0x307,0x206,0x205,0x403,0x600,0x709, 0x80a,0x90b,0xa0c,0xa0d,0x501,0x408,0x402 }; ushort huff[1026], vpred[2][2] = {{0,0},{0,0}}, hpred[2]; int i, c, n, row, col, diff; huff[0] = 10; for (n=i=0; i < 14; i++) FORC(1024 >> (tab[i] >> 8)) huff[++n] = tab[i]; getbits(-1); for (row=0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col=0; col < raw_width; col++) { diff = ljpeg_diff (huff); if (col < 2) hpred[col] = vpred[row & 1][col] += diff; else hpred[col & 1] += diff; RAW(row,col) = hpred[col & 1]; if (hpred[col & 1] >> tiff_bps) derror(); } } } void CLASS samsung3_load_raw() { int opt, init, mag, pmode, row, tab, col, pred, diff, i, c; ushort lent[3][2], len[4], *prow[2]; order = 0x4949; fseek (ifp, 9, SEEK_CUR); opt = fgetc(ifp); init = (get2(),get2()); for (row=0; row < raw_height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif fseek (ifp, (data_offset-ftell(ifp)) & 15, SEEK_CUR); ph1_bits(-1); mag = 0; pmode = 7; FORC(6) ((ushort *)lent)[c] = row < 2 ? 7:4; prow[ row & 1] = &RAW(row-1,1-((row & 1) << 1)); // green prow[~row & 1] = &RAW(row-2,0); // red and blue for (tab=0; tab+15 < raw_width; tab+=16) { if (~opt & 4 && !(tab & 63)) { i = ph1_bits(2); mag = i < 3 ? mag-'2'+"204"[i] : ph1_bits(12); } if (opt & 2) pmode = 7 - 4*ph1_bits(1); else if (!ph1_bits(1)) pmode = ph1_bits(3); if (opt & 1 || !ph1_bits(1)) { FORC4 len[c] = ph1_bits(2); FORC4 { i = ((row & 1) << 1 | (c & 1)) % 3; len[c] = len[c] < 3 ? lent[i][0]-'1'+"120"[len[c]] : ph1_bits(4); lent[i][0] = lent[i][1]; lent[i][1] = len[c]; } } FORC(16) { col = tab + (((c & 7) << 1)^(c >> 3)^(row & 1)); pred = (pmode == 7 || row < 2) ? (tab ? RAW(row,tab-2+(col & 1)) : init) : (prow[col & 1][col-'4'+"0224468"[pmode]] + prow[col & 1][col-'4'+"0244668"[pmode]] + 1) >> 1; diff = ph1_bits (i = len[c >> 2]); if (diff >> (i-1)) diff -= 1 << i; diff = diff * (mag*2+1) + mag; RAW(row,col) = pred + diff; } } } } #define HOLE(row) ((holes >> (((row) - raw_height) & 7)) & 1) /* Kudos to Rich Taylor for figuring out SMaL's compression algorithm. */ void CLASS smal_decode_segment (unsigned seg[2][2], int holes) { uchar hist[3][13] = { { 7, 7, 0, 0, 63, 55, 47, 39, 31, 23, 15, 7, 0 }, { 7, 7, 0, 0, 63, 55, 47, 39, 31, 23, 15, 7, 0 }, { 3, 3, 0, 0, 63, 47, 31, 15, 0 } }; int low, high=0xff, carry=0, nbits=8; int pix, s, count, bin, next, i, sym[3]; uchar diff, pred[]={0,0}; ushort data=0, range=0; fseek (ifp, seg[0][1]+1, SEEK_SET); getbits(-1); if (seg[1][0] > raw_width*raw_height) seg[1][0] = raw_width*raw_height; for (pix=seg[0][0]; pix < seg[1][0]; pix++) { for (s=0; s < 3; s++) { data = data << nbits | getbits(nbits); if (carry < 0) carry = (nbits += carry+1) < 1 ? nbits-1 : 0; while (--nbits >= 0) if ((data >> nbits & 0xff) == 0xff) break; if (nbits > 0) data = ((data & ((1 << (nbits-1)) - 1)) << 1) | ((data + (((data & (1 << (nbits-1)))) << 1)) & ((~0u) << nbits)); if (nbits >= 0) { data += getbits(1); carry = nbits - 8; } count = ((((data-range+1) & 0xffff) << 2) - 1) / (high >> 4); for (bin=0; hist[s][bin+5] > count; bin++); low = hist[s][bin+5] * (high >> 4) >> 2; if (bin) high = hist[s][bin+4] * (high >> 4) >> 2; high -= low; for (nbits=0; high << nbits < 128; nbits++); range = (range+low) << nbits; high <<= nbits; next = hist[s][1]; if (++hist[s][2] > hist[s][3]) { next = (next+1) & hist[s][0]; hist[s][3] = (hist[s][next+4] - hist[s][next+5]) >> 2; hist[s][2] = 1; } if (hist[s][hist[s][1]+4] - hist[s][hist[s][1]+5] > 1) { if (bin < hist[s][1]) for (i=bin; i < hist[s][1]; i++) hist[s][i+5]--; else if (next <= bin) for (i=hist[s][1]; i < bin; i++) hist[s][i+5]++; } hist[s][1] = next; sym[s] = bin; } diff = sym[2] << 5 | sym[1] << 2 | (sym[0] & 3); if (sym[0] & 4) diff = diff ? -diff : 0x80; if (ftell(ifp) + 12 >= seg[1][1]) diff = 0; #ifdef LIBRAW_LIBRARY_BUILD if(pix>=raw_width*raw_height) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif raw_image[pix] = pred[pix & 1] += diff; if (!(pix & 1) && HOLE(pix / raw_width)) pix += 2; } maximum = 0xff; } void CLASS smal_v6_load_raw() { unsigned seg[2][2]; fseek (ifp, 16, SEEK_SET); seg[0][0] = 0; seg[0][1] = get2(); seg[1][0] = raw_width * raw_height; seg[1][1] = INT_MAX; smal_decode_segment (seg, 0); } int CLASS median4 (int *p) { int min, max, sum, i; min = max = sum = p[0]; for (i=1; i < 4; i++) { sum += p[i]; if (min > p[i]) min = p[i]; if (max < p[i]) max = p[i]; } return (sum - min - max) >> 1; } void CLASS fill_holes (int holes) { int row, col, val[4]; for (row=2; row < height-2; row++) { if (!HOLE(row)) continue; for (col=1; col < width-1; col+=4) { val[0] = RAW(row-1,col-1); val[1] = RAW(row-1,col+1); val[2] = RAW(row+1,col-1); val[3] = RAW(row+1,col+1); RAW(row,col) = median4(val); } for (col=2; col < width-2; col+=4) if (HOLE(row-2) || HOLE(row+2)) RAW(row,col) = (RAW(row,col-2) + RAW(row,col+2)) >> 1; else { val[0] = RAW(row,col-2); val[1] = RAW(row,col+2); val[2] = RAW(row-2,col); val[3] = RAW(row+2,col); RAW(row,col) = median4(val); } } } void CLASS smal_v9_load_raw() { unsigned seg[256][2], offset, nseg, holes, i; fseek (ifp, 67, SEEK_SET); offset = get4(); nseg = (uchar) fgetc(ifp); fseek (ifp, offset, SEEK_SET); for (i=0; i < nseg*2; i++) ((unsigned *)seg)[i] = get4() + data_offset*(i & 1); fseek (ifp, 78, SEEK_SET); holes = fgetc(ifp); fseek (ifp, 88, SEEK_SET); seg[nseg][0] = raw_height * raw_width; seg[nseg][1] = get4() + data_offset; for (i=0; i < nseg; i++) smal_decode_segment (seg+i, holes); if (holes) fill_holes (holes); } void CLASS redcine_load_raw() { #ifndef NO_JASPER int c, row, col; jas_stream_t *in; jas_image_t *jimg; jas_matrix_t *jmat; jas_seqent_t *data; ushort *img, *pix; jas_init(); #ifndef LIBRAW_LIBRARY_BUILD in = jas_stream_fopen (ifname, "rb"); #else in = (jas_stream_t*)ifp->make_jas_stream(); if(!in) throw LIBRAW_EXCEPTION_DECODE_JPEG2000; #endif jas_stream_seek (in, data_offset+20, SEEK_SET); jimg = jas_image_decode (in, -1, 0); #ifndef LIBRAW_LIBRARY_BUILD if (!jimg) longjmp (failure, 3); #else if(!jimg) { jas_stream_close (in); throw LIBRAW_EXCEPTION_DECODE_JPEG2000; } #endif jmat = jas_matrix_create (height/2, width/2); merror (jmat, "redcine_load_raw()"); img = (ushort *) calloc ((height+2), (width+2)*2); merror (img, "redcine_load_raw()"); #ifdef LIBRAW_LIBRARY_BUILD bool fastexitflag = false; try { #endif FORC4 { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif jas_image_readcmpt (jimg, c, 0, 0, width/2, height/2, jmat); data = jas_matrix_getref (jmat, 0, 0); for (row = c >> 1; row < height; row+=2) for (col = c & 1; col < width; col+=2) img[(row+1)*(width+2)+col+1] = data[(row/2)*(width/2)+col/2]; } for (col=1; col <= width; col++) { img[col] = img[2*(width+2)+col]; img[(height+1)*(width+2)+col] = img[(height-1)*(width+2)+col]; } for (row=0; row < height+2; row++) { img[row*(width+2)] = img[row*(width+2)+2]; img[(row+1)*(width+2)-1] = img[(row+1)*(width+2)-3]; } for (row=1; row <= height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif pix = img + row*(width+2) + (col = 1 + (FC(row,1) & 1)); for ( ; col <= width; col+=2, pix+=2) { c = (((pix[0] - 0x800) << 3) + pix[-(width+2)] + pix[width+2] + pix[-1] + pix[1]) >> 2; pix[0] = LIM(c,0,4095); } } for (row=0; row < height; row++) { #ifdef LIBRAW_LIBRARY_BUILD checkCancel(); #endif for (col=0; col < width; col++) RAW(row,col) = curve[img[(row+1)*(width+2)+col+1]]; } #ifdef LIBRAW_LIBRARY_BUILD } catch (...) { fastexitflag=true; } #endif free (img); jas_matrix_destroy (jmat); jas_image_destroy (jimg); jas_stream_close (in); #ifdef LIBRAW_LIBRARY_BUILD if(fastexitflag) throw LIBRAW_EXCEPTION_CANCELLED_BY_CALLBACK; #endif #endif } void CLASS crop_masked_pixels() { int row, col; unsigned #ifndef LIBRAW_LIBRARY_BUILD r, raw_pitch = raw_width*2, c, m, mblack[8], zero, val; #else c, m, zero, val; #define mblack imgdata.color.black_stat #endif #ifndef LIBRAW_LIBRARY_BUILD if (load_raw == &CLASS phase_one_load_raw || load_raw == &CLASS phase_one_load_raw_c) phase_one_correct(); if (fuji_width) { for (row=0; row < raw_height-top_margin*2; row++) { for (col=0; col < fuji_width << !fuji_layout; col++) { if (fuji_layout) { r = fuji_width - 1 - col + (row >> 1); c = col + ((row+1) >> 1); } else { r = fuji_width - 1 + row - (col >> 1); c = row + ((col+1) >> 1); } if (r < height && c < width) BAYER(r,c) = RAW(row+top_margin,col+left_margin); } } } else { for (row=0; row < height; row++) for (col=0; col < width; col++) BAYER2(row,col) = RAW(row+top_margin,col+left_margin); } #endif if (mask[0][3] > 0) goto mask_set; if (load_raw == &CLASS canon_load_raw || load_raw == &CLASS lossless_jpeg_load_raw) { mask[0][1] = mask[1][1] += 2; mask[0][3] -= 2; goto sides; } if (load_raw == &CLASS canon_600_load_raw || load_raw == &CLASS sony_load_raw || (load_raw == &CLASS eight_bit_load_raw && strncmp(model,"DC2",3)) || load_raw == &CLASS kodak_262_load_raw || (load_raw == &CLASS packed_load_raw && (load_flags & 32))) { sides: mask[0][0] = mask[1][0] = top_margin; mask[0][2] = mask[1][2] = top_margin+height; mask[0][3] += left_margin; mask[1][1] += left_margin+width; mask[1][3] += raw_width; } if (load_raw == &CLASS nokia_load_raw) { mask[0][2] = top_margin; mask[0][3] = width; } #ifdef LIBRAW_LIBRARY_BUILD if (load_raw == &CLASS broadcom_load_raw) { mask[0][2] = top_margin; mask[0][3] = width; } #endif mask_set: memset (mblack, 0, sizeof mblack); for (zero=m=0; m < 8; m++) for (row=MAX(mask[m][0],0); row < MIN(mask[m][2],raw_height); row++) for (col=MAX(mask[m][1],0); col < MIN(mask[m][3],raw_width); col++) { c = FC(row-top_margin,col-left_margin); mblack[c] += val = raw_image[(row)*raw_pitch/2+(col)]; mblack[4+c]++; zero += !val; } if (load_raw == &CLASS canon_600_load_raw && width < raw_width) { black = (mblack[0]+mblack[1]+mblack[2]+mblack[3]) / (mblack[4]+mblack[5]+mblack[6]+mblack[7]) - 4; #ifndef LIBRAW_LIBRARY_BUILD canon_600_correct(); #endif } else if (zero < mblack[4] && mblack[5] && mblack[6] && mblack[7]) { FORC4 cblack[c] = mblack[c] / mblack[4+c]; black = cblack[4] = cblack[5] = cblack[6] = 0; } } #ifdef LIBRAW_LIBRARY_BUILD #undef mblack #endif void CLASS remove_zeroes() { unsigned row, col, tot, n, r, c; #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_REMOVE_ZEROES,0,2); #endif for (row=0; row < height; row++) for (col=0; col < width; col++) if (BAYER(row,col) == 0) { tot = n = 0; for (r = row-2; r <= row+2; r++) for (c = col-2; c <= col+2; c++) if (r < height && c < width && FC(r,c) == FC(row,col) && BAYER(r,c)) tot += (n++,BAYER(r,c)); if (n) BAYER(row,col) = tot/n; } #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_REMOVE_ZEROES,1,2); #endif } static const uchar xlat[2][256] = { { 0xc1,0xbf,0x6d,0x0d,0x59,0xc5,0x13,0x9d,0x83,0x61,0x6b,0x4f,0xc7,0x7f,0x3d,0x3d, 0x53,0x59,0xe3,0xc7,0xe9,0x2f,0x95,0xa7,0x95,0x1f,0xdf,0x7f,0x2b,0x29,0xc7,0x0d, 0xdf,0x07,0xef,0x71,0x89,0x3d,0x13,0x3d,0x3b,0x13,0xfb,0x0d,0x89,0xc1,0x65,0x1f, 0xb3,0x0d,0x6b,0x29,0xe3,0xfb,0xef,0xa3,0x6b,0x47,0x7f,0x95,0x35,0xa7,0x47,0x4f, 0xc7,0xf1,0x59,0x95,0x35,0x11,0x29,0x61,0xf1,0x3d,0xb3,0x2b,0x0d,0x43,0x89,0xc1, 0x9d,0x9d,0x89,0x65,0xf1,0xe9,0xdf,0xbf,0x3d,0x7f,0x53,0x97,0xe5,0xe9,0x95,0x17, 0x1d,0x3d,0x8b,0xfb,0xc7,0xe3,0x67,0xa7,0x07,0xf1,0x71,0xa7,0x53,0xb5,0x29,0x89, 0xe5,0x2b,0xa7,0x17,0x29,0xe9,0x4f,0xc5,0x65,0x6d,0x6b,0xef,0x0d,0x89,0x49,0x2f, 0xb3,0x43,0x53,0x65,0x1d,0x49,0xa3,0x13,0x89,0x59,0xef,0x6b,0xef,0x65,0x1d,0x0b, 0x59,0x13,0xe3,0x4f,0x9d,0xb3,0x29,0x43,0x2b,0x07,0x1d,0x95,0x59,0x59,0x47,0xfb, 0xe5,0xe9,0x61,0x47,0x2f,0x35,0x7f,0x17,0x7f,0xef,0x7f,0x95,0x95,0x71,0xd3,0xa3, 0x0b,0x71,0xa3,0xad,0x0b,0x3b,0xb5,0xfb,0xa3,0xbf,0x4f,0x83,0x1d,0xad,0xe9,0x2f, 0x71,0x65,0xa3,0xe5,0x07,0x35,0x3d,0x0d,0xb5,0xe9,0xe5,0x47,0x3b,0x9d,0xef,0x35, 0xa3,0xbf,0xb3,0xdf,0x53,0xd3,0x97,0x53,0x49,0x71,0x07,0x35,0x61,0x71,0x2f,0x43, 0x2f,0x11,0xdf,0x17,0x97,0xfb,0x95,0x3b,0x7f,0x6b,0xd3,0x25,0xbf,0xad,0xc7,0xc5, 0xc5,0xb5,0x8b,0xef,0x2f,0xd3,0x07,0x6b,0x25,0x49,0x95,0x25,0x49,0x6d,0x71,0xc7 }, { 0xa7,0xbc,0xc9,0xad,0x91,0xdf,0x85,0xe5,0xd4,0x78,0xd5,0x17,0x46,0x7c,0x29,0x4c, 0x4d,0x03,0xe9,0x25,0x68,0x11,0x86,0xb3,0xbd,0xf7,0x6f,0x61,0x22,0xa2,0x26,0x34, 0x2a,0xbe,0x1e,0x46,0x14,0x68,0x9d,0x44,0x18,0xc2,0x40,0xf4,0x7e,0x5f,0x1b,0xad, 0x0b,0x94,0xb6,0x67,0xb4,0x0b,0xe1,0xea,0x95,0x9c,0x66,0xdc,0xe7,0x5d,0x6c,0x05, 0xda,0xd5,0xdf,0x7a,0xef,0xf6,0xdb,0x1f,0x82,0x4c,0xc0,0x68,0x47,0xa1,0xbd,0xee, 0x39,0x50,0x56,0x4a,0xdd,0xdf,0xa5,0xf8,0xc6,0xda,0xca,0x90,0xca,0x01,0x42,0x9d, 0x8b,0x0c,0x73,0x43,0x75,0x05,0x94,0xde,0x24,0xb3,0x80,0x34,0xe5,0x2c,0xdc,0x9b, 0x3f,0xca,0x33,0x45,0xd0,0xdb,0x5f,0xf5,0x52,0xc3,0x21,0xda,0xe2,0x22,0x72,0x6b, 0x3e,0xd0,0x5b,0xa8,0x87,0x8c,0x06,0x5d,0x0f,0xdd,0x09,0x19,0x93,0xd0,0xb9,0xfc, 0x8b,0x0f,0x84,0x60,0x33,0x1c,0x9b,0x45,0xf1,0xf0,0xa3,0x94,0x3a,0x12,0x77,0x33, 0x4d,0x44,0x78,0x28,0x3c,0x9e,0xfd,0x65,0x57,0x16,0x94,0x6b,0xfb,0x59,0xd0,0xc8, 0x22,0x36,0xdb,0xd2,0x63,0x98,0x43,0xa1,0x04,0x87,0x86,0xf7,0xa6,0x26,0xbb,0xd6, 0x59,0x4d,0xbf,0x6a,0x2e,0xaa,0x2b,0xef,0xe6,0x78,0xb6,0x4e,0xe0,0x2f,0xdc,0x7c, 0xbe,0x57,0x19,0x32,0x7e,0x2a,0xd0,0xb8,0xba,0x29,0x00,0x3c,0x52,0x7d,0xa8,0x49, 0x3b,0x2d,0xeb,0x25,0x49,0xfa,0xa3,0xaa,0x39,0xa7,0xc5,0xa7,0x50,0x11,0x36,0xfb, 0xc6,0x67,0x4a,0xf5,0xa5,0x12,0x65,0x7e,0xb0,0xdf,0xaf,0x4e,0xb3,0x61,0x7f,0x2f } }; void CLASS gamma_curve (double pwr, double ts, int mode, int imax) { int i; double g[6], bnd[2]={0,0}, r; g[0] = pwr; g[1] = ts; g[2] = g[3] = g[4] = 0; bnd[g[1] >= 1] = 1; if (g[1] && (g[1]-1)*(g[0]-1) <= 0) { for (i=0; i < 48; i++) { g[2] = (bnd[0] + bnd[1])/2; if (g[0]) bnd[(pow(g[2]/g[1],-g[0]) - 1)/g[0] - 1/g[2] > -1] = g[2]; else bnd[g[2]/exp(1-1/g[2]) < g[1]] = g[2]; } g[3] = g[2] / g[1]; if (g[0]) g[4] = g[2] * (1/g[0] - 1); } if (g[0]) g[5] = 1 / (g[1]*SQR(g[3])/2 - g[4]*(1 - g[3]) + (1 - pow(g[3],1+g[0]))*(1 + g[4])/(1 + g[0])) - 1; else g[5] = 1 / (g[1]*SQR(g[3])/2 + 1 - g[2] - g[3] - g[2]*g[3]*(log(g[3]) - 1)) - 1; if (!mode--) { memcpy (gamm, g, sizeof gamm); return; } for (i=0; i < 0x10000; i++) { curve[i] = 0xffff; if ((r = (double) i / imax) < 1) curve[i] = 0x10000 * ( mode ? (r < g[3] ? r*g[1] : (g[0] ? pow( r,g[0])*(1+g[4])-g[4] : log(r)*g[2]+1)) : (r < g[2] ? r/g[1] : (g[0] ? pow((r+g[4])/(1+g[4]),1/g[0]) : exp((r-1)/g[2])))); } } void CLASS pseudoinverse (double (*in)[3], double (*out)[3], int size) { double work[3][6], num; int i, j, k; for (i=0; i < 3; i++) { for (j=0; j < 6; j++) work[i][j] = j == i+3; for (j=0; j < 3; j++) for (k=0; k < size; k++) work[i][j] += in[k][i] * in[k][j]; } for (i=0; i < 3; i++) { num = work[i][i]; for (j=0; j < 6; j++) work[i][j] /= num; for (k=0; k < 3; k++) { if (k==i) continue; num = work[k][i]; for (j=0; j < 6; j++) work[k][j] -= work[i][j] * num; } } for (i=0; i < size; i++) for (j=0; j < 3; j++) for (out[i][j]=k=0; k < 3; k++) out[i][j] += work[j][k+3] * in[i][k]; } void CLASS cam_xyz_coeff (float _rgb_cam[3][4], double cam_xyz[4][3]) { double cam_rgb[4][3], inverse[4][3], num; int i, j, k; for (i=0; i < colors; i++) /* Multiply out XYZ colorspace */ for (j=0; j < 3; j++) for (cam_rgb[i][j] = k=0; k < 3; k++) cam_rgb[i][j] += cam_xyz[i][k] * xyz_rgb[k][j]; for (i=0; i < colors; i++) { /* Normalize cam_rgb so that */ for (num=j=0; j < 3; j++) /* cam_rgb * (1,1,1) is (1,1,1,1) */ num += cam_rgb[i][j]; if(num > 0.00001) { for (j=0; j < 3; j++) cam_rgb[i][j] /= num; pre_mul[i] = 1 / num; } else { for (j=0; j < 3; j++) cam_rgb[i][j] = 0.0; pre_mul[i] = 1.0; } } pseudoinverse (cam_rgb, inverse, colors); for (i=0; i < 3; i++) for (j=0; j < colors; j++) _rgb_cam[i][j] = inverse[j][i]; } #ifdef COLORCHECK void CLASS colorcheck() { #define NSQ 24 // Coordinates of the GretagMacbeth ColorChecker squares // width, height, 1st_column, 1st_row int cut[NSQ][4]; // you must set these // ColorChecker Chart under 6500-kelvin illumination static const double gmb_xyY[NSQ][3] = { { 0.400, 0.350, 10.1 }, // Dark Skin { 0.377, 0.345, 35.8 }, // Light Skin { 0.247, 0.251, 19.3 }, // Blue Sky { 0.337, 0.422, 13.3 }, // Foliage { 0.265, 0.240, 24.3 }, // Blue Flower { 0.261, 0.343, 43.1 }, // Bluish Green { 0.506, 0.407, 30.1 }, // Orange { 0.211, 0.175, 12.0 }, // Purplish Blue { 0.453, 0.306, 19.8 }, // Moderate Red { 0.285, 0.202, 6.6 }, // Purple { 0.380, 0.489, 44.3 }, // Yellow Green { 0.473, 0.438, 43.1 }, // Orange Yellow { 0.187, 0.129, 6.1 }, // Blue { 0.305, 0.478, 23.4 }, // Green { 0.539, 0.313, 12.0 }, // Red { 0.448, 0.470, 59.1 }, // Yellow { 0.364, 0.233, 19.8 }, // Magenta { 0.196, 0.252, 19.8 }, // Cyan { 0.310, 0.316, 90.0 }, // White { 0.310, 0.316, 59.1 }, // Neutral 8 { 0.310, 0.316, 36.2 }, // Neutral 6.5 { 0.310, 0.316, 19.8 }, // Neutral 5 { 0.310, 0.316, 9.0 }, // Neutral 3.5 { 0.310, 0.316, 3.1 } }; // Black double gmb_cam[NSQ][4], gmb_xyz[NSQ][3]; double inverse[NSQ][3], cam_xyz[4][3], balance[4], num; int c, i, j, k, sq, row, col, pass, count[4]; memset (gmb_cam, 0, sizeof gmb_cam); for (sq=0; sq < NSQ; sq++) { FORCC count[c] = 0; for (row=cut[sq][3]; row < cut[sq][3]+cut[sq][1]; row++) for (col=cut[sq][2]; col < cut[sq][2]+cut[sq][0]; col++) { c = FC(row,col); if (c >= colors) c -= 2; gmb_cam[sq][c] += BAYER2(row,col); BAYER2(row,col) = black + (BAYER2(row,col)-black)/2; count[c]++; } FORCC gmb_cam[sq][c] = gmb_cam[sq][c]/count[c] - black; gmb_xyz[sq][0] = gmb_xyY[sq][2] * gmb_xyY[sq][0] / gmb_xyY[sq][1]; gmb_xyz[sq][1] = gmb_xyY[sq][2]; gmb_xyz[sq][2] = gmb_xyY[sq][2] * (1 - gmb_xyY[sq][0] - gmb_xyY[sq][1]) / gmb_xyY[sq][1]; } pseudoinverse (gmb_xyz, inverse, NSQ); for (pass=0; pass < 2; pass++) { for (raw_color = i=0; i < colors; i++) for (j=0; j < 3; j++) for (cam_xyz[i][j] = k=0; k < NSQ; k++) cam_xyz[i][j] += gmb_cam[k][i] * inverse[k][j]; cam_xyz_coeff (rgb_cam, cam_xyz); FORCC balance[c] = pre_mul[c] * gmb_cam[20][c]; for (sq=0; sq < NSQ; sq++) FORCC gmb_cam[sq][c] *= balance[c]; } if (verbose) { printf (" { \"%s %s\", %d,\n\t{", make, model, black); num = 10000 / (cam_xyz[1][0] + cam_xyz[1][1] + cam_xyz[1][2]); FORCC for (j=0; j < 3; j++) printf ("%c%d", (c | j) ? ',':' ', (int) (cam_xyz[c][j] * num + 0.5)); puts (" } },"); } #undef NSQ } #endif void CLASS hat_transform (float *temp, float *base, int st, int size, int sc) { int i; for (i=0; i < sc; i++) temp[i] = 2*base[st*i] + base[st*(sc-i)] + base[st*(i+sc)]; for (; i+sc < size; i++) temp[i] = 2*base[st*i] + base[st*(i-sc)] + base[st*(i+sc)]; for (; i < size; i++) temp[i] = 2*base[st*i] + base[st*(i-sc)] + base[st*(2*size-2-(i+sc))]; } #if !defined(LIBRAW_USE_OPENMP) void CLASS wavelet_denoise() { float *fimg=0, *temp, thold, mul[2], avg, diff; int scale=1, size, lev, hpass, lpass, row, col, nc, c, i, wlast, blk[2]; ushort *window[4]; static const float noise[] = { 0.8002,0.2735,0.1202,0.0585,0.0291,0.0152,0.0080,0.0044 }; #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("Wavelet denoising...\n")); #endif while (maximum << scale < 0x10000) scale++; maximum <<= --scale; black <<= scale; FORC4 cblack[c] <<= scale; if ((size = iheight*iwidth) < 0x15550000) fimg = (float *) malloc ((size*3 + iheight + iwidth) * sizeof *fimg); merror (fimg, "wavelet_denoise()"); temp = fimg + size*3; if ((nc = colors) == 3 && filters) nc++; FORC(nc) { /* denoise R,G1,B,G3 individually */ for (i=0; i < size; i++) fimg[i] = 256 * sqrt((double)(image[i][c] << scale)); for (hpass=lev=0; lev < 5; lev++) { lpass = size*((lev & 1)+1); for (row=0; row < iheight; row++) { hat_transform (temp, fimg+hpass+row*iwidth, 1, iwidth, 1 << lev); for (col=0; col < iwidth; col++) fimg[lpass + row*iwidth + col] = temp[col] * 0.25; } for (col=0; col < iwidth; col++) { hat_transform (temp, fimg+lpass+col, iwidth, iheight, 1 << lev); for (row=0; row < iheight; row++) fimg[lpass + row*iwidth + col] = temp[row] * 0.25; } thold = threshold * noise[lev]; for (i=0; i < size; i++) { fimg[hpass+i] -= fimg[lpass+i]; if (fimg[hpass+i] < -thold) fimg[hpass+i] += thold; else if (fimg[hpass+i] > thold) fimg[hpass+i] -= thold; else fimg[hpass+i] = 0; if (hpass) fimg[i] += fimg[hpass+i]; } hpass = lpass; } for (i=0; i < size; i++) image[i][c] = CLIP(SQR(fimg[i]+fimg[lpass+i])/0x10000); } if (filters && colors == 3) { /* pull G1 and G3 closer together */ for (row=0; row < 2; row++) { mul[row] = 0.125 * pre_mul[FC(row+1,0) | 1] / pre_mul[FC(row,0) | 1]; blk[row] = cblack[FC(row,0) | 1]; } for (i=0; i < 4; i++) window[i] = (ushort *) fimg + width*i; for (wlast=-1, row=1; row < height-1; row++) { while (wlast < row+1) { for (wlast++, i=0; i < 4; i++) window[(i+3) & 3] = window[i]; for (col = FC(wlast,1) & 1; col < width; col+=2) window[2][col] = BAYER(wlast,col); } thold = threshold/512; for (col = (FC(row,0) & 1)+1; col < width-1; col+=2) { avg = ( window[0][col-1] + window[0][col+1] + window[2][col-1] + window[2][col+1] - blk[~row & 1]*4 ) * mul[row & 1] + (window[1][col] + blk[row & 1]) * 0.5; avg = avg < 0 ? 0 : sqrt(avg); diff = sqrt((double)BAYER(row,col)) - avg; if (diff < -thold) diff += thold; else if (diff > thold) diff -= thold; else diff = 0; BAYER(row,col) = CLIP(SQR(avg+diff) + 0.5); } } } free (fimg); } #else /* LIBRAW_USE_OPENMP */ void CLASS wavelet_denoise() { float *fimg=0, *temp, thold, mul[2], avg, diff; int scale=1, size, lev, hpass, lpass, row, col, nc, c, i, wlast, blk[2]; ushort *window[4]; static const float noise[] = { 0.8002,0.2735,0.1202,0.0585,0.0291,0.0152,0.0080,0.0044 }; #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("Wavelet denoising...\n")); #endif while (maximum << scale < 0x10000) scale++; maximum <<= --scale; black <<= scale; FORC4 cblack[c] <<= scale; if ((size = iheight*iwidth) < 0x15550000) fimg = (float *) malloc ((size*3 + iheight + iwidth) * sizeof *fimg); merror (fimg, "wavelet_denoise()"); temp = fimg + size*3; if ((nc = colors) == 3 && filters) nc++; #ifdef LIBRAW_LIBRARY_BUILD #pragma omp parallel default(shared) private(i,col,row,thold,lev,lpass,hpass,temp,c) firstprivate(scale,size) #endif { temp = (float*)malloc( (iheight + iwidth) * sizeof *fimg); FORC(nc) { /* denoise R,G1,B,G3 individually */ #ifdef LIBRAW_LIBRARY_BUILD #pragma omp for #endif for (i=0; i < size; i++) fimg[i] = 256 * sqrt((double)(image[i][c] << scale)); for (hpass=lev=0; lev < 5; lev++) { lpass = size*((lev & 1)+1); #ifdef LIBRAW_LIBRARY_BUILD #pragma omp for #endif for (row=0; row < iheight; row++) { hat_transform (temp, fimg+hpass+row*iwidth, 1, iwidth, 1 << lev); for (col=0; col < iwidth; col++) fimg[lpass + row*iwidth + col] = temp[col] * 0.25; } #ifdef LIBRAW_LIBRARY_BUILD #pragma omp for #endif for (col=0; col < iwidth; col++) { hat_transform (temp, fimg+lpass+col, iwidth, iheight, 1 << lev); for (row=0; row < iheight; row++) fimg[lpass + row*iwidth + col] = temp[row] * 0.25; } thold = threshold * noise[lev]; #ifdef LIBRAW_LIBRARY_BUILD #pragma omp for #endif for (i=0; i < size; i++) { fimg[hpass+i] -= fimg[lpass+i]; if (fimg[hpass+i] < -thold) fimg[hpass+i] += thold; else if (fimg[hpass+i] > thold) fimg[hpass+i] -= thold; else fimg[hpass+i] = 0; if (hpass) fimg[i] += fimg[hpass+i]; } hpass = lpass; } #ifdef LIBRAW_LIBRARY_BUILD #pragma omp for #endif for (i=0; i < size; i++) image[i][c] = CLIP(SQR(fimg[i]+fimg[lpass+i])/0x10000); } free(temp); } /* end omp parallel */ /* the following loops are hard to parallize, no idea yes, * problem is wlast which is carrying dependency * second part should be easyer, but did not yet get it right. */ if (filters && colors == 3) { /* pull G1 and G3 closer together */ for (row=0; row < 2; row++){ mul[row] = 0.125 * pre_mul[FC(row+1,0) | 1] / pre_mul[FC(row,0) | 1]; blk[row] = cblack[FC(row,0) | 1]; } for (i=0; i < 4; i++) window[i] = (ushort *) fimg + width*i; for (wlast=-1, row=1; row < height-1; row++) { while (wlast < row+1) { for (wlast++, i=0; i < 4; i++) window[(i+3) & 3] = window[i]; for (col = FC(wlast,1) & 1; col < width; col+=2) window[2][col] = BAYER(wlast,col); } thold = threshold/512; for (col = (FC(row,0) & 1)+1; col < width-1; col+=2) { avg = ( window[0][col-1] + window[0][col+1] + window[2][col-1] + window[2][col+1] - blk[~row & 1]*4 ) * mul[row & 1] + (window[1][col] + blk[row & 1]) * 0.5; avg = avg < 0 ? 0 : sqrt(avg); diff = sqrt((double)BAYER(row,col)) - avg; if (diff < -thold) diff += thold; else if (diff > thold) diff -= thold; else diff = 0; BAYER(row,col) = CLIP(SQR(avg+diff) + 0.5); } } } free (fimg); } #endif // green equilibration void CLASS green_matching() { int i,j; double m1,m2,c1,c2; int o1_1,o1_2,o1_3,o1_4; int o2_1,o2_2,o2_3,o2_4; ushort (*img)[4]; const int margin = 3; int oj = 2, oi = 2; float f; const float thr = 0.01f; if(half_size || shrink) return; if(FC(oj, oi) != 3) oj++; if(FC(oj, oi) != 3) oi++; if(FC(oj, oi) != 3) oj--; img = (ushort (*)[4]) calloc (height*width, sizeof *image); merror (img, "green_matching()"); memcpy(img,image,height*width*sizeof *image); for(j=oj;j0xffff?0xffff:f; } } free(img); } void CLASS scale_colors() { unsigned bottom, right, size, row, col, ur, uc, i, x, y, c, sum[8]; int val, dark, sat; double dsum[8], dmin, dmax; float scale_mul[4], fr, fc; ushort *img=0, *pix; #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_SCALE_COLORS,0,2); #endif if (user_mul[0]) memcpy (pre_mul, user_mul, sizeof pre_mul); if (use_auto_wb || (use_camera_wb && cam_mul[0] == -1)) { memset (dsum, 0, sizeof dsum); bottom = MIN (greybox[1]+greybox[3], height); right = MIN (greybox[0]+greybox[2], width); for (row=greybox[1]; row < bottom; row += 8) for (col=greybox[0]; col < right; col += 8) { memset (sum, 0, sizeof sum); for (y=row; y < row+8 && y < bottom; y++) for (x=col; x < col+8 && x < right; x++) FORC4 { if (filters) { c = fcol(y,x); val = BAYER2(y,x); } else val = image[y*width+x][c]; if (val > maximum-25) goto skip_block; if ((val -= cblack[c]) < 0) val = 0; sum[c] += val; sum[c+4]++; if (filters) break; } FORC(8) dsum[c] += sum[c]; skip_block: ; } FORC4 if (dsum[c]) pre_mul[c] = dsum[c+4] / dsum[c]; } if (use_camera_wb && cam_mul[0] != -1) { memset (sum, 0, sizeof sum); for (row=0; row < 8; row++) for (col=0; col < 8; col++) { c = FC(row,col); if ((val = white[row][col] - cblack[c]) > 0) sum[c] += val; sum[c+4]++; } #ifdef LIBRAW_LIBRARY_BUILD if(load_raw == &LibRaw::nikon_load_sraw) { // Nikon sRAW: camera WB already applied: pre_mul[0]=pre_mul[1]=pre_mul[2]=pre_mul[3]=1.0; } else #endif if (sum[0] && sum[1] && sum[2] && sum[3]) FORC4 pre_mul[c] = (float) sum[c+4] / sum[c]; else if (cam_mul[0] && cam_mul[2]) memcpy (pre_mul, cam_mul, sizeof pre_mul); else { #ifdef LIBRAW_LIBRARY_BUILD imgdata.process_warnings |= LIBRAW_WARN_BAD_CAMERA_WB; #endif #ifdef DCRAW_VERBOSE fprintf (stderr,_("%s: Cannot use camera white balance.\n"), ifname); #endif } } #ifdef LIBRAW_LIBRARY_BUILD // Nikon sRAW, daylight if (load_raw == &LibRaw::nikon_load_sraw && !use_camera_wb && !use_auto_wb && cam_mul[0] > 0.001f && cam_mul[1] > 0.001f && cam_mul[2] > 0.001f ) { for(c=0;c<3;c++) pre_mul[c]/=cam_mul[c]; } #endif if (pre_mul[1] == 0) pre_mul[1] = 1; if (pre_mul[3] == 0) pre_mul[3] = colors < 4 ? pre_mul[1] : 1; dark = black; sat = maximum; if (threshold) wavelet_denoise(); maximum -= black; for (dmin=DBL_MAX, dmax=c=0; c < 4; c++) { if (dmin > pre_mul[c]) dmin = pre_mul[c]; if (dmax < pre_mul[c]) dmax = pre_mul[c]; } if (!highlight) dmax = dmin; FORC4 scale_mul[c] = (pre_mul[c] /= dmax) * 65535.0 / maximum; #ifdef DCRAW_VERBOSE if (verbose) { fprintf (stderr, _("Scaling with darkness %d, saturation %d, and\nmultipliers"), dark, sat); FORC4 fprintf (stderr, " %f", pre_mul[c]); fputc ('\n', stderr); } #endif if (filters > 1000 && (cblack[4]+1)/2 == 1 && (cblack[5]+1)/2 == 1) { FORC4 cblack[FC(c/2,c%2)] += cblack[6 + c/2 % cblack[4] * cblack[5] + c%2 % cblack[5]]; cblack[4] = cblack[5] = 0; } size = iheight*iwidth; #ifdef LIBRAW_LIBRARY_BUILD scale_colors_loop(scale_mul); #else for (i=0; i < size*4; i++) { if (!(val = ((ushort *)image)[i])) continue; if (cblack[4] && cblack[5]) val -= cblack[6 + i/4 / iwidth % cblack[4] * cblack[5] + i/4 % iwidth % cblack[5]]; val -= cblack[i & 3]; val *= scale_mul[i & 3]; ((ushort *)image)[i] = CLIP(val); } #endif if ((aber[0] != 1 || aber[2] != 1) && colors == 3) { #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("Correcting chromatic aberration...\n")); #endif for (c=0; c < 4; c+=2) { if (aber[c] == 1) continue; img = (ushort *) malloc (size * sizeof *img); merror (img, "scale_colors()"); for (i=0; i < size; i++) img[i] = image[i][c]; for (row=0; row < iheight; row++) { ur = fr = (row - iheight*0.5) * aber[c] + iheight*0.5; if (ur > iheight-2) continue; fr -= ur; for (col=0; col < iwidth; col++) { uc = fc = (col - iwidth*0.5) * aber[c] + iwidth*0.5; if (uc > iwidth-2) continue; fc -= uc; pix = img + ur*iwidth + uc; image[row*iwidth+col][c] = (pix[ 0]*(1-fc) + pix[ 1]*fc) * (1-fr) + (pix[iwidth]*(1-fc) + pix[iwidth+1]*fc) * fr; } } free(img); } } #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_SCALE_COLORS,1,2); #endif } void CLASS pre_interpolate() { ushort (*img)[4]; int row, col, c; #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_PRE_INTERPOLATE,0,2); #endif if (shrink) { if (half_size) { height = iheight; width = iwidth; if (filters == 9) { for (row=0; row < 3; row++) for (col=1; col < 4; col++) if (!(image[row*width+col][0] | image[row*width+col][2])) goto break2; break2: for ( ; row < height; row+=3) for (col=(col-1)%3+1; col < width-1; col+=3) { img = image + row*width+col; for (c=0; c < 3; c+=2) img[0][c] = (img[-1][c] + img[1][c]) >> 1; } } } else { img = (ushort (*)[4]) calloc (height, width*sizeof *img); merror (img, "pre_interpolate()"); for (row=0; row < height; row++) for (col=0; col < width; col++) { c = fcol(row,col); img[row*width+col][c] = image[(row >> 1)*iwidth+(col >> 1)][c]; } free (image); image = img; shrink = 0; } } if (filters > 1000 && colors == 3) { mix_green = four_color_rgb ^ half_size; if (four_color_rgb | half_size) colors++; else { for (row = FC(1,0) >> 1; row < height; row+=2) for (col = FC(row,1) & 1; col < width; col+=2) image[row*width+col][1] = image[row*width+col][3]; filters &= ~((filters & 0x55555555) << 1); } } if (half_size) filters = 0; #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_PRE_INTERPOLATE,1,2); #endif } void CLASS border_interpolate (int border) { unsigned row, col, y, x, f, c, sum[8]; for (row=0; row < height; row++) for (col=0; col < width; col++) { if (col==border && row >= border && row < height-border) col = width-border; memset (sum, 0, sizeof sum); for (y=row-1; y != row+2; y++) for (x=col-1; x != col+2; x++) if (y < height && x < width) { f = fcol(y,x); sum[f] += image[y*width+x][f]; sum[f+4]++; } f = fcol(row,col); FORCC if (c != f && sum[c+4]) image[row*width+col][c] = sum[c] / sum[c+4]; } } void CLASS lin_interpolate_loop(int code[16][16][32],int size) { int row; for (row=1; row < height-1; row++) { int col,*ip; ushort *pix; for (col=1; col < width-1; col++) { int i; int sum[4]; pix = image[row*width+col]; ip = code[row % size][col % size]; memset (sum, 0, sizeof sum); for (i=*ip++; i--; ip+=3) sum[ip[2]] += pix[ip[0]] << ip[1]; for (i=colors; --i; ip+=2) pix[ip[0]] = sum[ip[0]] * ip[1] >> 8; } } } void CLASS lin_interpolate() { int code[16][16][32], size=16, *ip, sum[4]; int f, c, x, y, row, col, shift, color; #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("Bilinear interpolation...\n")); #endif #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE,0,3); #endif if (filters == 9) size = 6; border_interpolate(1); for (row=0; row < size; row++) for (col=0; col < size; col++) { ip = code[row][col]+1; f = fcol(row,col); memset (sum, 0, sizeof sum); for (y=-1; y <= 1; y++) for (x=-1; x <= 1; x++) { shift = (y==0) + (x==0); color = fcol(row+y,col+x); if (color == f) continue; *ip++ = (width*y + x)*4 + color; *ip++ = shift; *ip++ = color; sum[color] += 1 << shift; } code[row][col][0] = (ip - code[row][col]) / 3; FORCC if (c != f) { *ip++ = c; *ip++ = sum[c]>0?256 / sum[c]:0; } } #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE,1,3); #endif lin_interpolate_loop(code,size); #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE,2,3); #endif } /* This algorithm is officially called: "Interpolation using a Threshold-based variable number of gradients" described in http://scien.stanford.edu/pages/labsite/1999/psych221/projects/99/tingchen/algodep/vargra.html I've extended the basic idea to work with non-Bayer filter arrays. Gradients are numbered clockwise from NW=0 to W=7. */ void CLASS vng_interpolate() { static const signed char *cp, terms[] = { -2,-2,+0,-1,0,0x01, -2,-2,+0,+0,1,0x01, -2,-1,-1,+0,0,0x01, -2,-1,+0,-1,0,0x02, -2,-1,+0,+0,0,0x03, -2,-1,+0,+1,1,0x01, -2,+0,+0,-1,0,0x06, -2,+0,+0,+0,1,0x02, -2,+0,+0,+1,0,0x03, -2,+1,-1,+0,0,0x04, -2,+1,+0,-1,1,0x04, -2,+1,+0,+0,0,0x06, -2,+1,+0,+1,0,0x02, -2,+2,+0,+0,1,0x04, -2,+2,+0,+1,0,0x04, -1,-2,-1,+0,0,-128, -1,-2,+0,-1,0,0x01, -1,-2,+1,-1,0,0x01, -1,-2,+1,+0,1,0x01, -1,-1,-1,+1,0,-120, -1,-1,+1,-2,0,0x40, -1,-1,+1,-1,0,0x22, -1,-1,+1,+0,0,0x33, -1,-1,+1,+1,1,0x11, -1,+0,-1,+2,0,0x08, -1,+0,+0,-1,0,0x44, -1,+0,+0,+1,0,0x11, -1,+0,+1,-2,1,0x40, -1,+0,+1,-1,0,0x66, -1,+0,+1,+0,1,0x22, -1,+0,+1,+1,0,0x33, -1,+0,+1,+2,1,0x10, -1,+1,+1,-1,1,0x44, -1,+1,+1,+0,0,0x66, -1,+1,+1,+1,0,0x22, -1,+1,+1,+2,0,0x10, -1,+2,+0,+1,0,0x04, -1,+2,+1,+0,1,0x04, -1,+2,+1,+1,0,0x04, +0,-2,+0,+0,1,-128, +0,-1,+0,+1,1,-120, +0,-1,+1,-2,0,0x40, +0,-1,+1,+0,0,0x11, +0,-1,+2,-2,0,0x40, +0,-1,+2,-1,0,0x20, +0,-1,+2,+0,0,0x30, +0,-1,+2,+1,1,0x10, +0,+0,+0,+2,1,0x08, +0,+0,+2,-2,1,0x40, +0,+0,+2,-1,0,0x60, +0,+0,+2,+0,1,0x20, +0,+0,+2,+1,0,0x30, +0,+0,+2,+2,1,0x10, +0,+1,+1,+0,0,0x44, +0,+1,+1,+2,0,0x10, +0,+1,+2,-1,1,0x40, +0,+1,+2,+0,0,0x60, +0,+1,+2,+1,0,0x20, +0,+1,+2,+2,0,0x10, +1,-2,+1,+0,0,-128, +1,-1,+1,+1,0,-120, +1,+0,+1,+2,0,0x08, +1,+0,+2,-1,0,0x40, +1,+0,+2,+1,0,0x10 }, chood[] = { -1,-1, -1,0, -1,+1, 0,+1, +1,+1, +1,0, +1,-1, 0,-1 }; ushort (*brow[5])[4], *pix; int prow=8, pcol=2, *ip, *code[16][16], gval[8], gmin, gmax, sum[4]; int row, col, x, y, x1, x2, y1, y2, t, weight, grads, color, diag; int g, diff, thold, num, c; lin_interpolate(); #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("VNG interpolation...\n")); #endif if (filters == 1) prow = pcol = 16; if (filters == 9) prow = pcol = 6; ip = (int *) calloc (prow*pcol, 1280); merror (ip, "vng_interpolate()"); for (row=0; row < prow; row++) /* Precalculate for VNG */ for (col=0; col < pcol; col++) { code[row][col] = ip; for (cp=terms, t=0; t < 64; t++) { y1 = *cp++; x1 = *cp++; y2 = *cp++; x2 = *cp++; weight = *cp++; grads = *cp++; color = fcol(row+y1,col+x1); if (fcol(row+y2,col+x2) != color) continue; diag = (fcol(row,col+1) == color && fcol(row+1,col) == color) ? 2:1; if (abs(y1-y2) == diag && abs(x1-x2) == diag) continue; *ip++ = (y1*width + x1)*4 + color; *ip++ = (y2*width + x2)*4 + color; *ip++ = weight; for (g=0; g < 8; g++) if (grads & 1< gval[g]) gmin = gval[g]; if (gmax < gval[g]) gmax = gval[g]; } if (gmax == 0) { memcpy (brow[2][col], pix, sizeof *image); continue; } thold = gmin + (gmax >> 1); memset (sum, 0, sizeof sum); color = fcol(row,col); for (num=g=0; g < 8; g++,ip+=2) { /* Average the neighbors */ if (gval[g] <= thold) { FORCC if (c == color && ip[1]) sum[c] += (pix[c] + pix[ip[1]]) >> 1; else sum[c] += pix[ip[0] + c]; num++; } } FORCC { /* Save to buffer */ t = pix[color]; if (c != color) t += (sum[c] - sum[color]) / num; brow[2][col][c] = CLIP(t); } } if (row > 3) /* Write buffer to image */ memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image); for (g=0; g < 4; g++) brow[(g-1) & 3] = brow[g]; } memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image); memcpy (image[(row-1)*width+2], brow[1]+2, (width-4)*sizeof *image); free (brow[4]); free (code[0][0]); } /* Patterned Pixel Grouping Interpolation by Alain Desbiolles */ void CLASS ppg_interpolate() { int dir[5] = { 1, width, -1, -width, 1 }; int row, col, diff[2], guess[2], c, d, i; ushort (*pix)[4]; border_interpolate(3); #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("PPG interpolation...\n")); #endif /* Fill in the green layer with gradients and pattern recognition: */ #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE,0,3); #ifdef LIBRAW_USE_OPENMP #pragma omp parallel for default(shared) private(guess, diff, row, col, d, c, i, pix) schedule(static) #endif #endif for (row=3; row < height-3; row++) for (col=3+(FC(row,3) & 1), c=FC(row,col); col < width-3; col+=2) { pix = image + row*width+col; for (i=0; (d=dir[i]) > 0; i++) { guess[i] = (pix[-d][1] + pix[0][c] + pix[d][1]) * 2 - pix[-2*d][c] - pix[2*d][c]; diff[i] = ( ABS(pix[-2*d][c] - pix[ 0][c]) + ABS(pix[ 2*d][c] - pix[ 0][c]) + ABS(pix[ -d][1] - pix[ d][1]) ) * 3 + ( ABS(pix[ 3*d][1] - pix[ d][1]) + ABS(pix[-3*d][1] - pix[-d][1]) ) * 2; } d = dir[i = diff[0] > diff[1]]; pix[0][1] = ULIM(guess[i] >> 2, pix[d][1], pix[-d][1]); } /* Calculate red and blue for each green pixel: */ #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE,1,3); #ifdef LIBRAW_USE_OPENMP #pragma omp parallel for default(shared) private(guess, diff, row, col, d, c, i, pix) schedule(static) #endif #endif for (row=1; row < height-1; row++) for (col=1+(FC(row,2) & 1), c=FC(row,col+1); col < width-1; col+=2) { pix = image + row*width+col; for (i=0; (d=dir[i]) > 0; c=2-c, i++) pix[0][c] = CLIP((pix[-d][c] + pix[d][c] + 2*pix[0][1] - pix[-d][1] - pix[d][1]) >> 1); } /* Calculate blue for red pixels and vice versa: */ #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE,2,3); #ifdef LIBRAW_USE_OPENMP #pragma omp parallel for default(shared) private(guess, diff, row, col, d, c, i, pix) schedule(static) #endif #endif for (row=1; row < height-1; row++) for (col=1+(FC(row,1) & 1), c=2-FC(row,col); col < width-1; col+=2) { pix = image + row*width+col; for (i=0; (d=dir[i]+dir[i+1]) > 0; i++) { diff[i] = ABS(pix[-d][c] - pix[d][c]) + ABS(pix[-d][1] - pix[0][1]) + ABS(pix[ d][1] - pix[0][1]); guess[i] = pix[-d][c] + pix[d][c] + 2*pix[0][1] - pix[-d][1] - pix[d][1]; } if (diff[0] != diff[1]) pix[0][c] = CLIP(guess[diff[0] > diff[1]] >> 1); else pix[0][c] = CLIP((guess[0]+guess[1]) >> 2); } } void CLASS cielab (ushort rgb[3], short lab[3]) { int c, i, j, k; float r, xyz[3]; #ifdef LIBRAW_NOTHREADS static float cbrt[0x10000], xyz_cam[3][4]; #else #define cbrt tls->ahd_data.cbrt #define xyz_cam tls->ahd_data.xyz_cam #endif if (!rgb) { #ifndef LIBRAW_NOTHREADS if(cbrt[0] < -1.0f) #endif for (i=0; i < 0x10000; i++) { r = i / 65535.0; cbrt[i] = r > 0.008856 ? pow(r,1.f/3.0f) : 7.787f*r + 16.f/116.0f; } for (i=0; i < 3; i++) for (j=0; j < colors; j++) for (xyz_cam[i][j] = k=0; k < 3; k++) xyz_cam[i][j] += xyz_rgb[i][k] * rgb_cam[k][j] / d65_white[i]; return; } xyz[0] = xyz[1] = xyz[2] = 0.5; FORCC { xyz[0] += xyz_cam[0][c] * rgb[c]; xyz[1] += xyz_cam[1][c] * rgb[c]; xyz[2] += xyz_cam[2][c] * rgb[c]; } xyz[0] = cbrt[CLIP((int) xyz[0])]; xyz[1] = cbrt[CLIP((int) xyz[1])]; xyz[2] = cbrt[CLIP((int) xyz[2])]; lab[0] = 64 * (116 * xyz[1] - 16); lab[1] = 64 * 500 * (xyz[0] - xyz[1]); lab[2] = 64 * 200 * (xyz[1] - xyz[2]); #ifndef LIBRAW_NOTHREADS #undef cbrt #undef xyz_cam #endif } #define TS 512 /* Tile Size */ #define fcol(row,col) xtrans[(row+6) % 6][(col+6) % 6] /* Frank Markesteijn's algorithm for Fuji X-Trans sensors */ void CLASS xtrans_interpolate (int passes) { int c, d, f, g, h, i, v, ng, row, col, top, left, mrow, mcol; #ifdef LIBRAW_LIBRARY_BUILD int cstat[4]={0,0,0,0}; #endif int val, ndir, pass, hm[8], avg[4], color[3][8]; static const short orth[12] = { 1,0,0,1,-1,0,0,-1,1,0,0,1 }, patt[2][16] = { { 0,1,0,-1,2,0,-1,0,1,1,1,-1,0,0,0,0 }, { 0,1,0,-2,1,0,-2,0,1,1,-2,-2,1,-1,-1,1 } }, dir[4] = { 1,TS,TS+1,TS-1 }; short allhex[3][3][2][8], *hex; ushort min, max, sgrow, sgcol; ushort (*rgb)[TS][TS][3], (*rix)[3], (*pix)[4]; short (*lab) [TS][3], (*lix)[3]; float (*drv)[TS][TS], diff[6], tr; char (*homo)[TS][TS], *buffer; #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("%d-pass X-Trans interpolation...\n"), passes); #endif #ifdef LIBRAW_LIBRARY_BUILD if(width < TS || height < TS) throw LIBRAW_EXCEPTION_IO_CORRUPT; // too small image /* Check against right pattern */ for (row = 0; row < 6; row++) for (col = 0; col < 6; col++) cstat[fcol(row,col)]++; if(cstat[0] < 6 || cstat[0]>10 || cstat[1]< 16 || cstat[1]>24 || cstat[2]< 6 || cstat[2]>10 || cstat[3]) throw LIBRAW_EXCEPTION_IO_CORRUPT; // Init allhex table to unreasonable values for(int i = 0; i < 3; i++) for(int j = 0; j < 3; j++) for(int k = 0; k < 2; k++) for(int l = 0; l < 8; l++) allhex[i][j][k][l]=32700; #endif cielab (0,0); ndir = 4 << (passes > 1); buffer = (char *) malloc (TS*TS*(ndir*11+6)); merror (buffer, "xtrans_interpolate()"); rgb = (ushort(*)[TS][TS][3]) buffer; lab = (short (*) [TS][3])(buffer + TS*TS*(ndir*6)); drv = (float (*)[TS][TS]) (buffer + TS*TS*(ndir*6+6)); homo = (char (*)[TS][TS]) (buffer + TS*TS*(ndir*10+6)); int minv=0,maxv=0,minh=0,maxh=0; /* Map a green hexagon around each non-green pixel and vice versa: */ for (row=0; row < 3; row++) for (col=0; col < 3; col++) for (ng=d=0; d < 10; d+=2) { g = fcol(row,col) == 1; if (fcol(row+orth[d],col+orth[d+2]) == 1) ng=0; else ng++; if (ng == 4) { sgrow = row; sgcol = col; } if (ng == g+1) FORC(8) { v = orth[d ]*patt[g][c*2] + orth[d+1]*patt[g][c*2+1]; h = orth[d+2]*patt[g][c*2] + orth[d+3]*patt[g][c*2+1]; minv=MIN(v,minv); maxv=MAX(v,maxv); minh=MIN(v,minh); maxh=MAX(v,maxh); allhex[row][col][0][c^(g*2 & d)] = h + v*width; allhex[row][col][1][c^(g*2 & d)] = h + v*TS; } } #ifdef LIBRAW_LIBRARY_BUILD // Check allhex table initialization for(int i = 0; i < 3; i++) for(int j = 0; j < 3; j++) for(int k = 0; k < 2; k++) for(int l = 0; l < 8; l++) if(allhex[i][j][k][l]>maxh+maxv*width+1 || allhex[i][j][k][l] val) min = val; if (max < val) max = val; } pix[0][1] = min; pix[0][3] = max; switch ((row-sgrow) % 3) { case 1: if (row < height-3) { row++; col--; } break; case 2: if ((min = ~(max = 0)) && (col += 2) < width - 3 && row > 2) { row--; #ifdef LIBRAW_LIBRARY_BUILD if(retrycount++ > width*height) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif } } } for (top=3; top < height-19; top += TS-16) for (left=3; left < width-19; left += TS-16) { mrow = MIN (top+TS, height-3); mcol = MIN (left+TS, width-3); for (row=top; row < mrow; row++) for (col=left; col < mcol; col++) memcpy (rgb[0][row-top][col-left], image[row*width+col], 6); FORC3 memcpy (rgb[c+1], rgb[0], sizeof *rgb); /* Interpolate green horizontally, vertically, and along both diagonals: */ for (row=top; row < mrow; row++) for (col=left; col < mcol; col++) { if ((f = fcol(row,col)) == 1) continue; pix = image + row*width + col; hex = allhex[row % 3][col % 3][0]; color[1][0] = 174 * (pix[ hex[1]][1] + pix[ hex[0]][1]) - 46 * (pix[2*hex[1]][1] + pix[2*hex[0]][1]); color[1][1] = 223 * pix[ hex[3]][1] + pix[ hex[2]][1] * 33 + 92 * (pix[ 0 ][f] - pix[ -hex[2]][f]); FORC(2) color[1][2+c] = 164 * pix[hex[4+c]][1] + 92 * pix[-2*hex[4+c]][1] + 33 * (2*pix[0][f] - pix[3*hex[4+c]][f] - pix[-3*hex[4+c]][f]); FORC4 rgb[c^!((row-sgrow) % 3)][row-top][col-left][1] = LIM(color[1][c] >> 8,pix[0][1],pix[0][3]); } for (pass=0; pass < passes; pass++) { if (pass == 1) memcpy (rgb+=4, buffer, 4*sizeof *rgb); /* Recalculate green from interpolated values of closer pixels: */ if (pass) { for (row=top+2; row < mrow-2; row++) for (col=left+2; col < mcol-2; col++) { if ((f = fcol(row,col)) == 1) continue; pix = image + row*width + col; hex = allhex[row % 3][col % 3][1]; for (d=3; d < 6; d++) { rix = &rgb[(d-2)^!((row-sgrow) % 3)][row-top][col-left]; val = rix[-2*hex[d]][1] + 2*rix[hex[d]][1] - rix[-2*hex[d]][f] - 2*rix[hex[d]][f] + 3*rix[0][f]; rix[0][1] = LIM(val/3,pix[0][1],pix[0][3]); } } } /* Interpolate red and blue values for solitary green pixels: */ for (row=(top-sgrow+4)/3*3+sgrow; row < mrow-2; row+=3) for (col=(left-sgcol+4)/3*3+sgcol; col < mcol-2; col+=3) { rix = &rgb[0][row-top][col-left]; h = fcol(row,col+1); memset (diff, 0, sizeof diff); for (i=1, d=0; d < 6; d++, i^=TS^1, h^=2) { for (c=0; c < 2; c++, h^=2) { g = 2*rix[0][1] - rix[i< 1) diff[d] += SQR (rix[i< 1 && (d & 1)) if (diff[d-1] < diff[d]) FORC(2) color[c*2][d] = color[c*2][d-1]; if (d < 2 || (d & 1)) { FORC(2) rix[0][c*2] = CLIP(color[c*2][d]/2); rix += TS*TS; } } } /* Interpolate red for blue pixels and vice versa: */ for (row=top+3; row < mrow-3; row++) for (col=left+3; col < mcol-3; col++) { if ((f = 2-fcol(row,col)) == 1) continue; rix = &rgb[0][row-top][col-left]; c = (row-sgrow) % 3 ? TS:1; h = 3 * (c ^ TS ^ 1); for (d=0; d < 4; d++, rix += TS*TS) { i = d > 1 || ((d ^ c) & 1) || ((ABS(rix[0][1]-rix[c][1])+ABS(rix[0][1]-rix[-c][1])) < 2*(ABS(rix[0][1]-rix[h][1])+ABS(rix[0][1]-rix[-h][1]))) ? c:h; rix[0][f] = CLIP((rix[i][f] + rix[-i][f] + 2*rix[0][1] - rix[i][1] - rix[-i][1])/2); } } /* Fill in red and blue for 2x2 blocks of green: */ for (row=top+2; row < mrow-2; row++) if ((row-sgrow) % 3) for (col=left+2; col < mcol-2; col++) if ((col-sgcol) % 3) { rix = &rgb[0][row-top][col-left]; hex = allhex[row % 3][col % 3][1]; for (d=0; d < ndir; d+=2, rix += TS*TS) if (hex[d] + hex[d+1]) { g = 3*rix[0][1] - 2*rix[hex[d]][1] - rix[hex[d+1]][1]; for (c=0; c < 4; c+=2) rix[0][c] = CLIP((g + 2*rix[hex[d]][c] + rix[hex[d+1]][c])/3); } else { g = 2*rix[0][1] - rix[hex[d]][1] - rix[hex[d+1]][1]; for (c=0; c < 4; c+=2) rix[0][c] = CLIP((g + rix[hex[d]][c] + rix[hex[d+1]][c])/2); } } } rgb = (ushort(*)[TS][TS][3]) buffer; mrow -= top; mcol -= left; /* Convert to CIELab and differentiate in all directions: */ for (d=0; d < ndir; d++) { for (row=2; row < mrow-2; row++) for (col=2; col < mcol-2; col++) cielab (rgb[d][row][col], lab[row][col]); for (f=dir[d & 3],row=3; row < mrow-3; row++) for (col=3; col < mcol-3; col++) { lix = &lab[row][col]; g = 2*lix[0][0] - lix[f][0] - lix[-f][0]; drv[d][row][col] = SQR(g) + SQR((2*lix[0][1] - lix[f][1] - lix[-f][1] + g*500/232)) + SQR((2*lix[0][2] - lix[f][2] - lix[-f][2] - g*500/580)); } } /* Build homogeneity maps from the derivatives: */ memset(homo, 0, ndir*TS*TS); for (row=4; row < mrow-4; row++) for (col=4; col < mcol-4; col++) { for (tr=FLT_MAX, d=0; d < ndir; d++) if (tr > drv[d][row][col]) tr = drv[d][row][col]; tr *= 8; for (d=0; d < ndir; d++) for (v=-1; v <= 1; v++) for (h=-1; h <= 1; h++) if (drv[d][row+v][col+h] <= tr) homo[d][row][col]++; } /* Average the most homogenous pixels for the final result: */ if (height-top < TS+4) mrow = height-top+2; if (width-left < TS+4) mcol = width-left+2; for (row = MIN(top,8); row < mrow-8; row++) for (col = MIN(left,8); col < mcol-8; col++) { for (d=0; d < ndir; d++) for (hm[d]=0, v=-2; v <= 2; v++) for (h=-2; h <= 2; h++) hm[d] += homo[d][row+v][col+h]; for (d=0; d < ndir-4; d++) if (hm[d] < hm[d+4]) hm[d ] = 0; else if (hm[d] > hm[d+4]) hm[d+4] = 0; for (max=hm[0],d=1; d < ndir; d++) if (max < hm[d]) max = hm[d]; max -= max >> 3; memset (avg, 0, sizeof avg); for (d=0; d < ndir; d++) if (hm[d] >= max) { FORC3 avg[c] += rgb[d][row][col][c]; avg[3]++; } FORC3 image[(row+top)*width+col+left][c] = avg[c]/avg[3]; } } free(buffer); border_interpolate(8); } #undef fcol /* Adaptive Homogeneity-Directed interpolation is based on the work of Keigo Hirakawa, Thomas Parks, and Paul Lee. */ #ifdef LIBRAW_LIBRARY_BUILD void CLASS ahd_interpolate_green_h_and_v(int top, int left, ushort (*out_rgb)[TS][TS][3]) { int row, col; int c, val; ushort (*pix)[4]; const int rowlimit = MIN(top+TS, height-2); const int collimit = MIN(left+TS, width-2); for (row = top; row < rowlimit; row++) { col = left + (FC(row,left) & 1); for (c = FC(row,col); col < collimit; col+=2) { pix = image + row*width+col; val = ((pix[-1][1] + pix[0][c] + pix[1][1]) * 2 - pix[-2][c] - pix[2][c]) >> 2; out_rgb[0][row-top][col-left][1] = ULIM(val,pix[-1][1],pix[1][1]); val = ((pix[-width][1] + pix[0][c] + pix[width][1]) * 2 - pix[-2*width][c] - pix[2*width][c]) >> 2; out_rgb[1][row-top][col-left][1] = ULIM(val,pix[-width][1],pix[width][1]); } } } void CLASS ahd_interpolate_r_and_b_in_rgb_and_convert_to_cielab(int top, int left, ushort (*inout_rgb)[TS][3], short (*out_lab)[TS][3]) { unsigned row, col; int c, val; ushort (*pix)[4]; ushort (*rix)[3]; short (*lix)[3]; float xyz[3]; const unsigned num_pix_per_row = 4*width; const unsigned rowlimit = MIN(top+TS-1, height-3); const unsigned collimit = MIN(left+TS-1, width-3); ushort *pix_above; ushort *pix_below; int t1, t2; for (row = top+1; row < rowlimit; row++) { pix = image + row*width + left; rix = &inout_rgb[row-top][0]; lix = &out_lab[row-top][0]; for (col = left+1; col < collimit; col++) { pix++; pix_above = &pix[0][0] - num_pix_per_row; pix_below = &pix[0][0] + num_pix_per_row; rix++; lix++; c = 2 - FC(row, col); if (c == 1) { c = FC(row+1,col); t1 = 2-c; val = pix[0][1] + (( pix[-1][t1] + pix[1][t1] - rix[-1][1] - rix[1][1] ) >> 1); rix[0][t1] = CLIP(val); val = pix[0][1] + (( pix_above[c] + pix_below[c] - rix[-TS][1] - rix[TS][1] ) >> 1); } else { t1 = -4+c; /* -4+c: pixel of color c to the left */ t2 = 4+c; /* 4+c: pixel of color c to the right */ val = rix[0][1] + (( pix_above[t1] + pix_above[t2] + pix_below[t1] + pix_below[t2] - rix[-TS-1][1] - rix[-TS+1][1] - rix[+TS-1][1] - rix[+TS+1][1] + 1) >> 2); } rix[0][c] = CLIP(val); c = FC(row,col); rix[0][c] = pix[0][c]; cielab(rix[0],lix[0]); } } } void CLASS ahd_interpolate_r_and_b_and_convert_to_cielab(int top, int left, ushort (*inout_rgb)[TS][TS][3], short (*out_lab)[TS][TS][3]) { int direction; for (direction = 0; direction < 2; direction++) { ahd_interpolate_r_and_b_in_rgb_and_convert_to_cielab(top, left, inout_rgb[direction], out_lab[direction]); } } void CLASS ahd_interpolate_build_homogeneity_map(int top, int left, short (*lab)[TS][TS][3], char (*out_homogeneity_map)[TS][2]) { int row, col; int tr, tc; int direction; int i; short (*lix)[3]; short (*lixs[2])[3]; short *adjacent_lix; unsigned ldiff[2][4], abdiff[2][4], leps, abeps; static const int dir[4] = { -1, 1, -TS, TS }; const int rowlimit = MIN(top+TS-2, height-4); const int collimit = MIN(left+TS-2, width-4); int homogeneity; char (*homogeneity_map_p)[2]; memset (out_homogeneity_map, 0, 2*TS*TS); for (row=top+2; row < rowlimit; row++) { tr = row-top; homogeneity_map_p = &out_homogeneity_map[tr][1]; for (direction=0; direction < 2; direction++) { lixs[direction] = &lab[direction][tr][1]; } for (col=left+2; col < collimit; col++) { tc = col-left; homogeneity_map_p++; for (direction=0; direction < 2; direction++) { lix = ++lixs[direction]; for (i=0; i < 4; i++) { adjacent_lix = lix[dir[i]]; ldiff[direction][i] = ABS(lix[0][0]-adjacent_lix[0]); abdiff[direction][i] = SQR(lix[0][1]-adjacent_lix[1]) + SQR(lix[0][2]-adjacent_lix[2]); } } leps = MIN(MAX(ldiff[0][0],ldiff[0][1]), MAX(ldiff[1][2],ldiff[1][3])); abeps = MIN(MAX(abdiff[0][0],abdiff[0][1]), MAX(abdiff[1][2],abdiff[1][3])); for (direction=0; direction < 2; direction++) { homogeneity = 0; for (i=0; i < 4; i++) { if (ldiff[direction][i] <= leps && abdiff[direction][i] <= abeps) { homogeneity++; } } homogeneity_map_p[0][direction] = homogeneity; } } } } void CLASS ahd_interpolate_combine_homogeneous_pixels(int top, int left, ushort (*rgb)[TS][TS][3], char (*homogeneity_map)[TS][2]) { int row, col; int tr, tc; int i, j; int direction; int hm[2]; int c; const int rowlimit = MIN(top+TS-3, height-5); const int collimit = MIN(left+TS-3, width-5); ushort (*pix)[4]; ushort (*rix[2])[3]; for (row=top+3; row < rowlimit; row++) { tr = row-top; pix = &image[row*width+left+2]; for (direction = 0; direction < 2; direction++) { rix[direction] = &rgb[direction][tr][2]; } for (col=left+3; col < collimit; col++) { tc = col-left; pix++; for (direction = 0; direction < 2; direction++) { rix[direction]++; } for (direction=0; direction < 2; direction++) { hm[direction] = 0; for (i=tr-1; i <= tr+1; i++) { for (j=tc-1; j <= tc+1; j++) { hm[direction] += homogeneity_map[i][j][direction]; } } } if (hm[0] != hm[1]) { memcpy(pix[0], rix[hm[1] > hm[0]][0], 3 * sizeof(ushort)); } else { FORC3 { pix[0][c] = (rix[0][0][c] + rix[1][0][c]) >> 1; } } } } } void CLASS ahd_interpolate() { int i, j, k, top, left; float xyz_cam[3][4],r; char *buffer; ushort (*rgb)[TS][TS][3]; short (*lab)[TS][TS][3]; char (*homo)[TS][2]; int terminate_flag = 0; cielab(0,0); border_interpolate(5); #ifdef LIBRAW_LIBRARY_BUILD #ifdef LIBRAW_USE_OPENMP #pragma omp parallel private(buffer,rgb,lab,homo,top,left,i,j,k) shared(xyz_cam,terminate_flag) #endif #endif { buffer = (char *) malloc (26*TS*TS); /* 1664 kB */ merror (buffer, "ahd_interpolate()"); rgb = (ushort(*)[TS][TS][3]) buffer; lab = (short (*)[TS][TS][3])(buffer + 12*TS*TS); homo = (char (*)[TS][2]) (buffer + 24*TS*TS); #ifdef LIBRAW_LIBRARY_BUILD #ifdef LIBRAW_USE_OPENMP #pragma omp for schedule(dynamic) #endif #endif for (top=2; top < height-5; top += TS-6){ #ifdef LIBRAW_LIBRARY_BUILD #ifdef LIBRAW_USE_OPENMP if(0== omp_get_thread_num()) #endif if(callbacks.progress_cb) { int rr = (*callbacks.progress_cb)(callbacks.progresscb_data,LIBRAW_PROGRESS_INTERPOLATE,top-2,height-7); if(rr) terminate_flag = 1; } #endif for (left=2; !terminate_flag && (left < width-5); left += TS-6) { ahd_interpolate_green_h_and_v(top, left, rgb); ahd_interpolate_r_and_b_and_convert_to_cielab(top, left, rgb, lab); ahd_interpolate_build_homogeneity_map(top, left, lab, homo); ahd_interpolate_combine_homogeneous_pixels(top, left, rgb, homo); } } free (buffer); } #ifdef LIBRAW_LIBRARY_BUILD if(terminate_flag) throw LIBRAW_EXCEPTION_CANCELLED_BY_CALLBACK; #endif } #else void CLASS ahd_interpolate() { int i, j, top, left, row, col, tr, tc, c, d, val, hm[2]; static const int dir[4] = { -1, 1, -TS, TS }; unsigned ldiff[2][4], abdiff[2][4], leps, abeps; ushort (*rgb)[TS][TS][3], (*rix)[3], (*pix)[4]; short (*lab)[TS][TS][3], (*lix)[3]; char (*homo)[TS][TS], *buffer; #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("AHD interpolation...\n")); #endif cielab (0,0); border_interpolate(5); buffer = (char *) malloc (26*TS*TS); merror (buffer, "ahd_interpolate()"); rgb = (ushort(*)[TS][TS][3]) buffer; lab = (short (*)[TS][TS][3])(buffer + 12*TS*TS); homo = (char (*)[TS][TS]) (buffer + 24*TS*TS); for (top=2; top < height-5; top += TS-6) for (left=2; left < width-5; left += TS-6) { /* Interpolate green horizontally and vertically: */ for (row=top; row < top+TS && row < height-2; row++) { col = left + (FC(row,left) & 1); for (c = FC(row,col); col < left+TS && col < width-2; col+=2) { pix = image + row*width+col; val = ((pix[-1][1] + pix[0][c] + pix[1][1]) * 2 - pix[-2][c] - pix[2][c]) >> 2; rgb[0][row-top][col-left][1] = ULIM(val,pix[-1][1],pix[1][1]); val = ((pix[-width][1] + pix[0][c] + pix[width][1]) * 2 - pix[-2*width][c] - pix[2*width][c]) >> 2; rgb[1][row-top][col-left][1] = ULIM(val,pix[-width][1],pix[width][1]); } } /* Interpolate red and blue, and convert to CIELab: */ for (d=0; d < 2; d++) for (row=top+1; row < top+TS-1 && row < height-3; row++) for (col=left+1; col < left+TS-1 && col < width-3; col++) { pix = image + row*width+col; rix = &rgb[d][row-top][col-left]; lix = &lab[d][row-top][col-left]; if ((c = 2 - FC(row,col)) == 1) { c = FC(row+1,col); val = pix[0][1] + (( pix[-1][2-c] + pix[1][2-c] - rix[-1][1] - rix[1][1] ) >> 1); rix[0][2-c] = CLIP(val); val = pix[0][1] + (( pix[-width][c] + pix[width][c] - rix[-TS][1] - rix[TS][1] ) >> 1); } else val = rix[0][1] + (( pix[-width-1][c] + pix[-width+1][c] + pix[+width-1][c] + pix[+width+1][c] - rix[-TS-1][1] - rix[-TS+1][1] - rix[+TS-1][1] - rix[+TS+1][1] + 1) >> 2); rix[0][c] = CLIP(val); c = FC(row,col); rix[0][c] = pix[0][c]; cielab (rix[0],lix[0]); } /* Build homogeneity maps from the CIELab images: */ memset (homo, 0, 2*TS*TS); for (row=top+2; row < top+TS-2 && row < height-4; row++) { tr = row-top; for (col=left+2; col < left+TS-2 && col < width-4; col++) { tc = col-left; for (d=0; d < 2; d++) { lix = &lab[d][tr][tc]; for (i=0; i < 4; i++) { ldiff[d][i] = ABS(lix[0][0]-lix[dir[i]][0]); abdiff[d][i] = SQR(lix[0][1]-lix[dir[i]][1]) + SQR(lix[0][2]-lix[dir[i]][2]); } } leps = MIN(MAX(ldiff[0][0],ldiff[0][1]), MAX(ldiff[1][2],ldiff[1][3])); abeps = MIN(MAX(abdiff[0][0],abdiff[0][1]), MAX(abdiff[1][2],abdiff[1][3])); for (d=0; d < 2; d++) for (i=0; i < 4; i++) if (ldiff[d][i] <= leps && abdiff[d][i] <= abeps) homo[d][tr][tc]++; } } /* Combine the most homogenous pixels for the final result: */ for (row=top+3; row < top+TS-3 && row < height-5; row++) { tr = row-top; for (col=left+3; col < left+TS-3 && col < width-5; col++) { tc = col-left; for (d=0; d < 2; d++) for (hm[d]=0, i=tr-1; i <= tr+1; i++) for (j=tc-1; j <= tc+1; j++) hm[d] += homo[d][i][j]; if (hm[0] != hm[1]) FORC3 image[row*width+col][c] = rgb[hm[1] > hm[0]][tr][tc][c]; else FORC3 image[row*width+col][c] = (rgb[0][tr][tc][c] + rgb[1][tr][tc][c]) >> 1; } } } free (buffer); } #endif #undef TS void CLASS median_filter() { ushort (*pix)[4]; int pass, c, i, j, k, med[9]; static const uchar opt[] = /* Optimal 9-element median search */ { 1,2, 4,5, 7,8, 0,1, 3,4, 6,7, 1,2, 4,5, 7,8, 0,3, 5,8, 4,7, 3,6, 1,4, 2,5, 4,7, 4,2, 6,4, 4,2 }; for (pass=1; pass <= med_passes; pass++) { #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_MEDIAN_FILTER,pass-1,med_passes); #endif #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("Median filter pass %d...\n"), pass); #endif for (c=0; c < 3; c+=2) { for (pix = image; pix < image+width*height; pix++) pix[0][3] = pix[0][c]; for (pix = image+width; pix < image+width*(height-1); pix++) { if ((pix-image+1) % width < 2) continue; for (k=0, i = -width; i <= width; i += width) for (j = i-1; j <= i+1; j++) med[k++] = pix[j][3] - pix[j][1]; for (i=0; i < sizeof opt; i+=2) if (med[opt[i]] > med[opt[i+1]]) SWAP (med[opt[i]] , med[opt[i+1]]); pix[0][c] = CLIP(med[4] + pix[0][1]); } } } } void CLASS blend_highlights() { int clip=INT_MAX, row, col, c, i, j; static const float trans[2][4][4] = { { { 1,1,1 }, { 1.7320508,-1.7320508,0 }, { -1,-1,2 } }, { { 1,1,1,1 }, { 1,-1,1,-1 }, { 1,1,-1,-1 }, { 1,-1,-1,1 } } }; static const float itrans[2][4][4] = { { { 1,0.8660254,-0.5 }, { 1,-0.8660254,-0.5 }, { 1,0,1 } }, { { 1,1,1,1 }, { 1,-1,1,-1 }, { 1,1,-1,-1 }, { 1,-1,-1,1 } } }; float cam[2][4], lab[2][4], sum[2], chratio; if ((unsigned) (colors-3) > 1) return; #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("Blending highlights...\n")); #endif #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_HIGHLIGHTS,0,2); #endif FORCC if (clip > (i = 65535*pre_mul[c])) clip = i; for (row=0; row < height; row++) for (col=0; col < width; col++) { FORCC if (image[row*width+col][c] > clip) break; if (c == colors) continue; FORCC { cam[0][c] = image[row*width+col][c]; cam[1][c] = MIN(cam[0][c],clip); } for (i=0; i < 2; i++) { FORCC for (lab[i][c]=j=0; j < colors; j++) lab[i][c] += trans[colors-3][c][j] * cam[i][j]; for (sum[i]=0,c=1; c < colors; c++) sum[i] += SQR(lab[i][c]); } chratio = sqrt(sum[1]/sum[0]); for (c=1; c < colors; c++) lab[0][c] *= chratio; FORCC for (cam[0][c]=j=0; j < colors; j++) cam[0][c] += itrans[colors-3][c][j] * lab[0][j]; FORCC image[row*width+col][c] = cam[0][c] / colors; } #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_HIGHLIGHTS,1,2); #endif } #define SCALE (4 >> shrink) void CLASS recover_highlights() { float *map, sum, wgt, grow; int hsat[4], count, spread, change, val, i; unsigned high, wide, mrow, mcol, row, col, kc, c, d, y, x; ushort *pixel; static const signed char dir[8][2] = { {-1,-1}, {-1,0}, {-1,1}, {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1} }; #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("Rebuilding highlights...\n")); #endif grow = pow (2.0, 4-highlight); FORCC hsat[c] = 32000 * pre_mul[c]; for (kc=0, c=1; c < colors; c++) if (pre_mul[kc] < pre_mul[c]) kc = c; high = height / SCALE; wide = width / SCALE; map = (float *) calloc (high, wide*sizeof *map); merror (map, "recover_highlights()"); FORCC if (c != kc) { #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_HIGHLIGHTS,c-1,colors-1); #endif memset (map, 0, high*wide*sizeof *map); for (mrow=0; mrow < high; mrow++) for (mcol=0; mcol < wide; mcol++) { sum = wgt = count = 0; for (row = mrow*SCALE; row < (mrow+1)*SCALE; row++) for (col = mcol*SCALE; col < (mcol+1)*SCALE; col++) { pixel = image[row*width+col]; if (pixel[c] / hsat[c] == 1 && pixel[kc] > 24000) { sum += pixel[c]; wgt += pixel[kc]; count++; } } if (count == SCALE*SCALE) map[mrow*wide+mcol] = sum / wgt; } for (spread = 32/grow; spread--; ) { for (mrow=0; mrow < high; mrow++) for (mcol=0; mcol < wide; mcol++) { if (map[mrow*wide+mcol]) continue; sum = count = 0; for (d=0; d < 8; d++) { y = mrow + dir[d][0]; x = mcol + dir[d][1]; if (y < high && x < wide && map[y*wide+x] > 0) { sum += (1 + (d & 1)) * map[y*wide+x]; count += 1 + (d & 1); } } if (count > 3) map[mrow*wide+mcol] = - (sum+grow) / (count+grow); } for (change=i=0; i < high*wide; i++) if (map[i] < 0) { map[i] = -map[i]; change = 1; } if (!change) break; } for (i=0; i < high*wide; i++) if (map[i] == 0) map[i] = 1; for (mrow=0; mrow < high; mrow++) for (mcol=0; mcol < wide; mcol++) { for (row = mrow*SCALE; row < (mrow+1)*SCALE; row++) for (col = mcol*SCALE; col < (mcol+1)*SCALE; col++) { pixel = image[row*width+col]; if (pixel[c] / hsat[c] > 1) { val = pixel[kc] * map[mrow*wide+mcol]; if (pixel[c] < val) pixel[c] = CLIP(val); } } } } free (map); } #undef SCALE void CLASS tiff_get (unsigned base, unsigned *tag, unsigned *type, unsigned *len, unsigned *save) { *tag = get2(); *type = get2(); *len = get4(); *save = ftell(ifp) + 4; if (*len * ("11124811248484"[*type < 14 ? *type:0]-'0') > 4) fseek (ifp, get4()+base, SEEK_SET); } void CLASS parse_thumb_note (int base, unsigned toff, unsigned tlen) { unsigned entries, tag, type, len, save; entries = get2(); while (entries--) { tiff_get (base, &tag, &type, &len, &save); if (tag == toff) thumb_offset = get4()+base; if (tag == tlen) thumb_length = get4(); fseek (ifp, save, SEEK_SET); } } static float powf_lim(float a, float b, float limup) { return (b>limup || b < -limup)?0.f:powf(a,b); } static float libraw_powf64(float a, float b) { return powf_lim(a,b,64.f); } #ifdef LIBRAW_LIBRARY_BUILD static float my_roundf(float x) { float t; if (x >= 0.0) { t = ceilf(x); if (t - x > 0.5) t -= 1.0; return t; } else { t = ceilf(-x); if (t + x > 0.5) t -= 1.0; return -t; } } static float _CanonConvertAperture(ushort in) { if ((in == (ushort)0xffe0) || (in == (ushort)0x7fff)) return 0.0f; return libraw_powf64(2.0, in/64.0); } static float _CanonConvertEV (short in) { short EV, Sign, Frac; float Frac_f; EV = in; if (EV < 0) { EV = -EV; Sign = -1; } else { Sign = 1; } Frac = EV & 0x1f; EV -= Frac; // remove fraction if (Frac == 0x0c) { // convert 1/3 and 2/3 codes Frac_f = 32.0f / 3.0f; } else if (Frac == 0x14) { Frac_f = 64.0f / 3.0f; } else Frac_f = (float) Frac; return ((float)Sign * ((float)EV + Frac_f))/32.0f; } void CLASS setCanonBodyFeatures (unsigned id) { imgdata.lens.makernotes.CamID = id; if ( (id == 0x80000001) || // 1D (id == 0x80000174) || // 1D2 (id == 0x80000232) || // 1D2N (id == 0x80000169) || // 1D3 (id == 0x80000281) // 1D4 ) { imgdata.lens.makernotes.CameraFormat = LIBRAW_FORMAT_APSH; imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Canon_EF; } else if ( (id == 0x80000167) || // 1Ds (id == 0x80000188) || // 1Ds2 (id == 0x80000215) || // 1Ds3 (id == 0x80000269) || // 1DX (id == 0x80000328) || // 1DX2 (id == 0x80000324) || // 1DC (id == 0x80000213) || // 5D (id == 0x80000218) || // 5D2 (id == 0x80000285) || // 5D3 (id == 0x80000349) || // 5D4 (id == 0x80000382) || // 5DS (id == 0x80000401) || // 5DS R (id == 0x80000302) // 6D ) { imgdata.lens.makernotes.CameraFormat = LIBRAW_FORMAT_FF; imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Canon_EF; } else if ( (id == 0x80000331) || // M (id == 0x80000355) || // M2 (id == 0x80000374) || // M3 (id == 0x80000384) || // M10 (id == 0x80000394) // M5 ) { imgdata.lens.makernotes.CameraFormat = LIBRAW_FORMAT_APSC; imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Canon_EF_M; } else if ( (id == 0x01140000) || // D30 (id == 0x01668000) || // D60 (id > 0x80000000) ) { imgdata.lens.makernotes.CameraFormat = LIBRAW_FORMAT_APSC; imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Canon_EF; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Unknown; } else { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens; } return; } void CLASS processCanonCameraInfo (unsigned id, uchar *CameraInfo, unsigned maxlen) { ushort iCanonLensID = 0, iCanonMaxFocal = 0, iCanonMinFocal = 0, iCanonLens = 0, iCanonCurFocal = 0, iCanonFocalType = 0; if(maxlen<16) return; // too short, so broken CameraInfo[0] = 0; CameraInfo[1] = 0; switch (id) { case 0x80000001: // 1D case 0x80000167: // 1DS iCanonCurFocal = 10; iCanonLensID = 13; iCanonMinFocal = 14; iCanonMaxFocal = 16; if (!imgdata.lens.makernotes.CurFocal) imgdata.lens.makernotes.CurFocal = sget2(CameraInfo + iCanonCurFocal); if (!imgdata.lens.makernotes.MinFocal) imgdata.lens.makernotes.MinFocal = sget2(CameraInfo + iCanonMinFocal); if (!imgdata.lens.makernotes.MaxFocal) imgdata.lens.makernotes.MaxFocal = sget2(CameraInfo + iCanonMaxFocal); break; case 0x80000174: // 1DMkII case 0x80000188: // 1DsMkII iCanonCurFocal = 9; iCanonLensID = 12; iCanonMinFocal = 17; iCanonMaxFocal = 19; iCanonFocalType = 45; break; case 0x80000232: // 1DMkII N iCanonCurFocal = 9; iCanonLensID = 12; iCanonMinFocal = 17; iCanonMaxFocal = 19; break; case 0x80000169: // 1DMkIII case 0x80000215: // 1DsMkIII iCanonCurFocal = 29; iCanonLensID = 273; iCanonMinFocal = 275; iCanonMaxFocal = 277; break; case 0x80000281: // 1DMkIV iCanonCurFocal = 30; iCanonLensID = 335; iCanonMinFocal = 337; iCanonMaxFocal = 339; break; case 0x80000269: // 1D X iCanonCurFocal = 35; iCanonLensID = 423; iCanonMinFocal = 425; iCanonMaxFocal = 427; break; case 0x80000213: // 5D iCanonCurFocal = 40; if (!sget2Rev(CameraInfo + 12)) iCanonLensID = 151; else iCanonLensID = 12; iCanonMinFocal = 147; iCanonMaxFocal = 149; break; case 0x80000218: // 5DMkII iCanonCurFocal = 30; iCanonLensID = 230; iCanonMinFocal = 232; iCanonMaxFocal = 234; break; case 0x80000285: // 5DMkIII iCanonCurFocal = 35; iCanonLensID = 339; iCanonMinFocal = 341; iCanonMaxFocal = 343; break; case 0x80000302: // 6D iCanonCurFocal = 35; iCanonLensID = 353; iCanonMinFocal = 355; iCanonMaxFocal = 357; break; case 0x80000250: // 7D iCanonCurFocal = 30; iCanonLensID = 274; iCanonMinFocal = 276; iCanonMaxFocal = 278; break; case 0x80000190: // 40D iCanonCurFocal = 29; iCanonLensID = 214; iCanonMinFocal = 216; iCanonMaxFocal = 218; iCanonLens = 2347; break; case 0x80000261: // 50D iCanonCurFocal = 30; iCanonLensID = 234; iCanonMinFocal = 236; iCanonMaxFocal = 238; break; case 0x80000287: // 60D iCanonCurFocal = 30; iCanonLensID = 232; iCanonMinFocal = 234; iCanonMaxFocal = 236; break; case 0x80000325: // 70D iCanonCurFocal = 35; iCanonLensID = 358; iCanonMinFocal = 360; iCanonMaxFocal = 362; break; case 0x80000176: // 450D iCanonCurFocal = 29; iCanonLensID = 222; iCanonLens = 2355; break; case 0x80000252: // 500D iCanonCurFocal = 30; iCanonLensID = 246; iCanonMinFocal = 248; iCanonMaxFocal = 250; break; case 0x80000270: // 550D iCanonCurFocal = 30; iCanonLensID = 255; iCanonMinFocal = 257; iCanonMaxFocal = 259; break; case 0x80000286: // 600D case 0x80000288: // 1100D iCanonCurFocal = 30; iCanonLensID = 234; iCanonMinFocal = 236; iCanonMaxFocal = 238; break; case 0x80000301: // 650D case 0x80000326: // 700D iCanonCurFocal = 35; iCanonLensID = 295; iCanonMinFocal = 297; iCanonMaxFocal = 299; break; case 0x80000254: // 1000D iCanonCurFocal = 29; iCanonLensID = 226; iCanonMinFocal = 228; iCanonMaxFocal = 230; iCanonLens = 2359; break; } if (iCanonFocalType) { if(iCanonFocalType>=maxlen) return; // broken; imgdata.lens.makernotes.FocalType = CameraInfo[iCanonFocalType]; if (!imgdata.lens.makernotes.FocalType) // zero means 'fixed' here, replacing with standard '1' imgdata.lens.makernotes.FocalType = 1; } if (!imgdata.lens.makernotes.CurFocal) { if(iCanonCurFocal>=maxlen) return; // broken; imgdata.lens.makernotes.CurFocal = sget2Rev(CameraInfo + iCanonCurFocal); } if (!imgdata.lens.makernotes.LensID) { if(iCanonLensID>=maxlen) return; // broken; imgdata.lens.makernotes.LensID = sget2Rev(CameraInfo + iCanonLensID); } if (!imgdata.lens.makernotes.MinFocal) { if(iCanonMinFocal>=maxlen) return; // broken; imgdata.lens.makernotes.MinFocal = sget2Rev(CameraInfo + iCanonMinFocal); } if (!imgdata.lens.makernotes.MaxFocal) { if(iCanonMaxFocal>=maxlen) return; // broken; imgdata.lens.makernotes.MaxFocal = sget2Rev(CameraInfo + iCanonMaxFocal); } if (!imgdata.lens.makernotes.Lens[0] && iCanonLens) { if(iCanonLens+64>=maxlen) return; // broken; if (CameraInfo[iCanonLens] < 65) // non-Canon lens { memcpy(imgdata.lens.makernotes.Lens, CameraInfo + iCanonLens, 64); } else if (!strncmp((char *)CameraInfo + iCanonLens, "EF-S", 4)) { memcpy(imgdata.lens.makernotes.Lens, "EF-S ", 5); memcpy(imgdata.lens.makernotes.LensFeatures_pre, "EF-E", 4); imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Canon_EF_S; memcpy(imgdata.lens.makernotes.Lens + 5, CameraInfo + iCanonLens + 4, 60); } else if (!strncmp((char *)CameraInfo + iCanonLens, "TS-E", 4)) { memcpy(imgdata.lens.makernotes.Lens, "TS-E ", 5); memcpy(imgdata.lens.makernotes.LensFeatures_pre, "TS-E", 4); imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Canon_EF; memcpy(imgdata.lens.makernotes.Lens + 5, CameraInfo + iCanonLens + 4, 60); } else if (!strncmp((char *)CameraInfo + iCanonLens, "MP-E", 4)) { memcpy(imgdata.lens.makernotes.Lens, "MP-E ", 5); memcpy(imgdata.lens.makernotes.LensFeatures_pre, "MP-E", 4); imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Canon_EF; memcpy(imgdata.lens.makernotes.Lens + 5, CameraInfo + iCanonLens + 4, 60); } else if (!strncmp((char *)CameraInfo + iCanonLens, "EF-M", 4)) { memcpy(imgdata.lens.makernotes.Lens, "EF-M ", 5); memcpy(imgdata.lens.makernotes.LensFeatures_pre, "EF-M", 4); imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Canon_EF_M; memcpy(imgdata.lens.makernotes.Lens + 5, CameraInfo + iCanonLens + 4, 60); } else { memcpy(imgdata.lens.makernotes.Lens, CameraInfo + iCanonLens, 2); memcpy(imgdata.lens.makernotes.LensFeatures_pre, "EF", 2); imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Canon_EF; imgdata.lens.makernotes.Lens[2] = 32; memcpy(imgdata.lens.makernotes.Lens + 3, CameraInfo + iCanonLens + 2, 62); } } return; } void CLASS Canon_CameraSettings () { fseek(ifp, 10, SEEK_CUR); imgdata.shootinginfo.DriveMode = get2(); get2(); imgdata.shootinginfo.FocusMode = get2(); fseek(ifp, 18, SEEK_CUR); imgdata.shootinginfo.MeteringMode = get2(); get2(); imgdata.shootinginfo.AFPoint = get2(); imgdata.shootinginfo.ExposureMode = get2(); get2(); imgdata.lens.makernotes.LensID = get2(); imgdata.lens.makernotes.MaxFocal = get2(); imgdata.lens.makernotes.MinFocal = get2(); imgdata.lens.makernotes.CanonFocalUnits = get2(); if (imgdata.lens.makernotes.CanonFocalUnits > 1) { imgdata.lens.makernotes.MaxFocal /= (float)imgdata.lens.makernotes.CanonFocalUnits; imgdata.lens.makernotes.MinFocal /= (float)imgdata.lens.makernotes.CanonFocalUnits; } imgdata.lens.makernotes.MaxAp = _CanonConvertAperture(get2()); imgdata.lens.makernotes.MinAp = _CanonConvertAperture(get2()); fseek(ifp, 12, SEEK_CUR); imgdata.shootinginfo.ImageStabilization = get2(); } void CLASS Canon_WBpresets (int skip1, int skip2) { int c; FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][c ^ (c >> 1)] = get2(); if (skip1) fseek(ifp, skip1, SEEK_CUR); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][c ^ (c >> 1)] = get2(); if (skip1) fseek(ifp, skip1, SEEK_CUR); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][c ^ (c >> 1)] = get2(); if (skip1) fseek(ifp, skip1, SEEK_CUR); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][c ^ (c >> 1)] = get2(); if (skip1) fseek(ifp, skip1, SEEK_CUR); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][c ^ (c >> 1)] = get2(); if (skip2) fseek(ifp, skip2, SEEK_CUR); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][c ^ (c >> 1)] = get2(); return; } void CLASS Canon_WBCTpresets (short WBCTversion) { if (WBCTversion == 0) for (int i=0; i<15; i++)// tint, as shot R, as shot B, CСT { imgdata.color.WBCT_Coeffs[i][2] = imgdata.color.WBCT_Coeffs[i][4] = 1.0f; fseek (ifp, 2, SEEK_CUR); imgdata.color.WBCT_Coeffs[i][1] = 1024.0f /fMAX(get2(),1.f) ; imgdata.color.WBCT_Coeffs[i][3] = 1024.0f /fMAX(get2(),1.f); imgdata.color.WBCT_Coeffs[i][0] = get2(); } else if (WBCTversion == 1) for (int i=0; i<15; i++) // as shot R, as shot B, tint, CСT { imgdata.color.WBCT_Coeffs[i][2] = imgdata.color.WBCT_Coeffs[i][4] = 1.0f; imgdata.color.WBCT_Coeffs[i][1] = 1024.0f / fMAX(get2(),1.f); imgdata.color.WBCT_Coeffs[i][3] = 1024.0f / fMAX(get2(),1.f); fseek (ifp, 2, SEEK_CUR); imgdata.color.WBCT_Coeffs[i][0] = get2(); } else if ((WBCTversion == 2) && ((unique_id == 0x80000374) || // M3 (unique_id == 0x80000384) || // M10 (unique_id == 0x80000394) || // M5 (unique_id == 0x03970000))) // G7 X Mark II for (int i=0; i<15; i++) // tint, offset, as shot R, as shot B, CСT { fseek (ifp, 2, SEEK_CUR); fseek (ifp, 2, SEEK_CUR); imgdata.color.WBCT_Coeffs[i][2] = imgdata.color.WBCT_Coeffs[i][4] = 1.0f; imgdata.color.WBCT_Coeffs[i][1] = 1024.0f / fMAX(1.f,get2()); imgdata.color.WBCT_Coeffs[i][3] = 1024.0f / fMAX(1.f,get2()); imgdata.color.WBCT_Coeffs[i][0] = get2(); } else if ((WBCTversion == 2) && ((unique_id == 0x03950000) || (unique_id == 0x03930000))) // G5 X, G9 X for (int i=0; i<15; i++) // tint, offset, as shot R, as shot B, CСT { fseek (ifp, 2, SEEK_CUR); fseek (ifp, 2, SEEK_CUR); imgdata.color.WBCT_Coeffs[i][2] = imgdata.color.WBCT_Coeffs[i][4] = 1.0f; imgdata.color.WBCT_Coeffs[i][1] = (float)get2() / 512.0f; imgdata.color.WBCT_Coeffs[i][3] = (float)get2() / 512.0f; imgdata.color.WBCT_Coeffs[i][0] = get2(); } return; } void CLASS processNikonLensData (uchar *LensData, unsigned len) { ushort i; if (!(imgdata.lens.nikon.NikonLensType & 0x01)) { imgdata.lens.makernotes.LensFeatures_pre[0] = 'A'; imgdata.lens.makernotes.LensFeatures_pre[1] = 'F'; } else { imgdata.lens.makernotes.LensFeatures_pre[0] = 'M'; imgdata.lens.makernotes.LensFeatures_pre[1] = 'F'; } if (imgdata.lens.nikon.NikonLensType & 0x02) { if (imgdata.lens.nikon.NikonLensType & 0x04) imgdata.lens.makernotes.LensFeatures_suf[0] = 'G'; else imgdata.lens.makernotes.LensFeatures_suf[0] = 'D'; imgdata.lens.makernotes.LensFeatures_suf[1] = ' '; } if (imgdata.lens.nikon.NikonLensType & 0x08) { imgdata.lens.makernotes.LensFeatures_suf[2] = 'V'; imgdata.lens.makernotes.LensFeatures_suf[3] = 'R'; } if (imgdata.lens.nikon.NikonLensType & 0x10) { imgdata.lens.makernotes.LensMount = imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Nikon_CX; imgdata.lens.makernotes.CameraFormat = imgdata.lens.makernotes.LensFormat = LIBRAW_FORMAT_1INCH; } else imgdata.lens.makernotes.LensMount = imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Nikon_F; if (imgdata.lens.nikon.NikonLensType & 0x20) { strcpy(imgdata.lens.makernotes.Adapter, "FT-1"); imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Nikon_F; imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Nikon_CX; imgdata.lens.makernotes.CameraFormat = LIBRAW_FORMAT_1INCH; } imgdata.lens.nikon.NikonLensType = imgdata.lens.nikon.NikonLensType & 0xdf; if (len < 20) { switch (len) { case 9: i = 2; break; case 15: i = 7; break; case 16: i = 8; break; } imgdata.lens.nikon.NikonLensIDNumber = LensData[i]; imgdata.lens.nikon.NikonLensFStops = LensData[i + 1]; imgdata.lens.makernotes.LensFStops = (float)imgdata.lens.nikon.NikonLensFStops /12.0f; if (fabsf(imgdata.lens.makernotes.MinFocal) < 1.1f) { if ((imgdata.lens.nikon.NikonLensType ^ (uchar)0x01) || LensData[i + 2]) imgdata.lens.makernotes.MinFocal = 5.0f * libraw_powf64(2.0f, (float)LensData[i + 2] / 24.0f); if ((imgdata.lens.nikon.NikonLensType ^ (uchar)0x01) || LensData[i + 3]) imgdata.lens.makernotes.MaxFocal = 5.0f * libraw_powf64(2.0f, (float)LensData[i + 3] / 24.0f); if ((imgdata.lens.nikon.NikonLensType ^ (uchar)0x01) || LensData[i + 4]) imgdata.lens.makernotes.MaxAp4MinFocal = libraw_powf64(2.0f, (float)LensData[i + 4] / 24.0f); if ((imgdata.lens.nikon.NikonLensType ^ (uchar)0x01) || LensData[i + 5]) imgdata.lens.makernotes.MaxAp4MaxFocal = libraw_powf64(2.0f, (float)LensData[i + 5] / 24.0f); } imgdata.lens.nikon.NikonMCUVersion = LensData[i + 6]; if (i != 2) { if ((LensData[i - 1]) && (fabsf(imgdata.lens.makernotes.CurFocal) < 1.1f)) imgdata.lens.makernotes.CurFocal = 5.0f * libraw_powf64(2.0f, (float)LensData[i - 1] / 24.0f); if (LensData[i + 7]) imgdata.lens.nikon.NikonEffectiveMaxAp = libraw_powf64(2.0f, (float)LensData[i + 7] / 24.0f); } imgdata.lens.makernotes.LensID = (unsigned long long) LensData[i] << 56 | (unsigned long long) LensData[i + 1] << 48 | (unsigned long long) LensData[i + 2] << 40 | (unsigned long long) LensData[i + 3] << 32 | (unsigned long long) LensData[i + 4] << 24 | (unsigned long long) LensData[i + 5] << 16 | (unsigned long long) LensData[i + 6] << 8 | (unsigned long long) imgdata.lens.nikon.NikonLensType; } else if ((len == 459) || (len == 590)) { memcpy(imgdata.lens.makernotes.Lens, LensData + 390, 64); } else if (len == 509) { memcpy(imgdata.lens.makernotes.Lens, LensData + 391, 64); } else if (len == 879) { memcpy(imgdata.lens.makernotes.Lens, LensData + 680, 64); } return; } void CLASS setOlympusBodyFeatures (unsigned long long id) { imgdata.lens.makernotes.CamID = id; if ((id == 0x4434303430ULL) || // E-1 (id == 0x4434303431ULL) || // E-300 ((id & 0x00ffff0000ULL) == 0x0030300000ULL)) { imgdata.lens.makernotes.CameraFormat = LIBRAW_FORMAT_FT; if ((id == 0x4434303430ULL) || // E-1 (id == 0x4434303431ULL) || // E-330 ((id >= 0x5330303033ULL) && (id <= 0x5330303138ULL)) || // E-330 to E-520 (id == 0x5330303233ULL) || // E-620 (id == 0x5330303239ULL) || // E-450 (id == 0x5330303330ULL) || // E-600 (id == 0x5330303333ULL)) // E-5 { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FT; } else { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_mFT; } } else { imgdata.lens.makernotes.LensMount = imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens; } return; } void CLASS parseCanonMakernotes (unsigned tag, unsigned type, unsigned len) { if (tag == 0x0001) Canon_CameraSettings(); else if (tag == 0x0002) // focal length { imgdata.lens.makernotes.FocalType = get2(); imgdata.lens.makernotes.CurFocal = get2(); if (imgdata.lens.makernotes.CanonFocalUnits > 1) { imgdata.lens.makernotes.CurFocal /= (float)imgdata.lens.makernotes.CanonFocalUnits; } } else if (tag == 0x0004) // shot info { short tempAp; fseek(ifp, 30, SEEK_CUR); imgdata.other.FlashEC = _CanonConvertEV((signed short)get2()); fseek(ifp, 8-32, SEEK_CUR); if ((tempAp = get2()) != 0x7fff) imgdata.lens.makernotes.CurAp = _CanonConvertAperture(tempAp); if (imgdata.lens.makernotes.CurAp < 0.7f) { fseek(ifp, 32, SEEK_CUR); imgdata.lens.makernotes.CurAp = _CanonConvertAperture(get2()); } if (!aperture) aperture = imgdata.lens.makernotes.CurAp; } else if (tag == 0x0095 && // lens model tag !imgdata.lens.makernotes.Lens[0]) { fread(imgdata.lens.makernotes.Lens, 2, 1, ifp); imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Canon_EF; if (imgdata.lens.makernotes.Lens[0] < 65) // non-Canon lens fread(imgdata.lens.makernotes.Lens + 2, 62, 1, ifp); else { char efs[2]; imgdata.lens.makernotes.LensFeatures_pre[0] = imgdata.lens.makernotes.Lens[0]; imgdata.lens.makernotes.LensFeatures_pre[1] = imgdata.lens.makernotes.Lens[1]; fread(efs, 2, 1, ifp); if (efs[0] == 45 && (efs[1] == 83 || efs[1] == 69 || efs[1] == 77)) { // "EF-S, TS-E, MP-E, EF-M" lenses imgdata.lens.makernotes.Lens[2] = imgdata.lens.makernotes.LensFeatures_pre[2] = efs[0]; imgdata.lens.makernotes.Lens[3] = imgdata.lens.makernotes.LensFeatures_pre[3] = efs[1]; imgdata.lens.makernotes.Lens[4] = 32; if (efs[1] == 83) { imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Canon_EF_S; imgdata.lens.makernotes.LensFormat = LIBRAW_FORMAT_APSC; } else if (efs[1] == 77) { imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Canon_EF_M; } } else { // "EF" lenses imgdata.lens.makernotes.Lens[2] = 32; imgdata.lens.makernotes.Lens[3] = efs[0]; imgdata.lens.makernotes.Lens[4] = efs[1]; } fread(imgdata.lens.makernotes.Lens + 5, 58, 1, ifp); } } else if (tag == 0x00a9) { long int save1 = ftell(ifp); fseek (ifp, save1+(0x5<<1), SEEK_SET); Canon_WBpresets(0,0); fseek (ifp, save1, SEEK_SET); } else if (tag == 0x00e0) // sensor info { imgdata.makernotes.canon.SensorWidth = (get2(),get2()); imgdata.makernotes.canon.SensorHeight = get2(); imgdata.makernotes.canon.SensorLeftBorder = (get2(),get2(),get2()); imgdata.makernotes.canon.SensorTopBorder = get2(); imgdata.makernotes.canon.SensorRightBorder = get2(); imgdata.makernotes.canon.SensorBottomBorder = get2(); imgdata.makernotes.canon.BlackMaskLeftBorder = get2(); imgdata.makernotes.canon.BlackMaskTopBorder = get2(); imgdata.makernotes.canon.BlackMaskRightBorder = get2(); imgdata.makernotes.canon.BlackMaskBottomBorder = get2(); } else if (tag == 0x4001 && len > 500) { int c; long int save1 = ftell(ifp); switch (len) { case 582: imgdata.makernotes.canon.CanonColorDataVer = 1; // 20D / 350D { fseek (ifp, save1+(0x23<<1), SEEK_SET); Canon_WBpresets(2,2); fseek (ifp, save1+(0x4b<<1), SEEK_SET); Canon_WBCTpresets (1); // ABCT } break; case 653: imgdata.makernotes.canon.CanonColorDataVer = 2; // 1Dmk2 / 1DsMK2 { fseek (ifp, save1+(0x27<<1), SEEK_SET); Canon_WBpresets(2,12); fseek (ifp, save1+(0xa4<<1), SEEK_SET); Canon_WBCTpresets (1); // ABCT } break; case 796: imgdata.makernotes.canon.CanonColorDataVer = 3; // 1DmkIIN / 5D / 30D / 400D imgdata.makernotes.canon.CanonColorDataSubVer = get2(); { fseek (ifp, save1+(0x4e<<1), SEEK_SET); Canon_WBpresets(2,12); fseek (ifp, save1+(0x85<<1), SEEK_SET); Canon_WBCTpresets (0); // BCAT fseek (ifp, save1+(0x0c4<<1), SEEK_SET); // offset 196 short int bls=0; FORC4 bls+= (imgdata.makernotes.canon.ChannelBlackLevel[c]=get2()); imgdata.makernotes.canon.AverageBlackLevel = bls/4; } break; // 1DmkIII / 1DSmkIII / 1DmkIV / 5DmkII // 7D / 40D / 50D / 60D / 450D / 500D // 550D / 1000D / 1100D case 674: case 692: case 702: case 1227: case 1250: case 1251: case 1337: case 1338: case 1346: imgdata.makernotes.canon.CanonColorDataVer = 4; imgdata.makernotes.canon.CanonColorDataSubVer = get2(); { fseek (ifp, save1+(0x53<<1), SEEK_SET); Canon_WBpresets(2,12); fseek (ifp, save1+(0xa8<<1), SEEK_SET); Canon_WBCTpresets (0); // BCAT fseek (ifp, save1+(0x0e7<<1), SEEK_SET); // offset 231 short int bls=0; FORC4 bls+= (imgdata.makernotes.canon.ChannelBlackLevel[c]=get2()); imgdata.makernotes.canon.AverageBlackLevel = bls/4; } if ((imgdata.makernotes.canon.CanonColorDataSubVer == 4) || (imgdata.makernotes.canon.CanonColorDataSubVer == 5)) { fseek (ifp, save1+(0x2b9<<1), SEEK_SET); // offset 697 shorts imgdata.makernotes.canon.SpecularWhiteLevel = get2(); FORC4 imgdata.color.linear_max[c] = imgdata.makernotes.canon.SpecularWhiteLevel; } else if ((imgdata.makernotes.canon.CanonColorDataSubVer == 6) || (imgdata.makernotes.canon.CanonColorDataSubVer == 7)) { fseek (ifp, save1+(0x2d0<<1), SEEK_SET); // offset 720 shorts imgdata.makernotes.canon.SpecularWhiteLevel = get2(); FORC4 imgdata.color.linear_max[c] = imgdata.makernotes.canon.SpecularWhiteLevel; } else if (imgdata.makernotes.canon.CanonColorDataSubVer == 9) { fseek (ifp, save1+(0x2d4<<1), SEEK_SET); // offset 724 shorts imgdata.makernotes.canon.SpecularWhiteLevel = get2(); FORC4 imgdata.color.linear_max[c] = imgdata.makernotes.canon.SpecularWhiteLevel; } break; case 5120: imgdata.makernotes.canon.CanonColorDataVer = 5; // PowerSot G10, G12, G5 X, EOS M3, EOS M5 { fseek (ifp, save1+(0x56<<1), SEEK_SET); if ((unique_id == 0x03970000) || // G7 X Mark II (unique_id == 0x80000394)) // EOS M5 { fseek(ifp, 18, SEEK_CUR); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Other][c ^ (c >> 1)] = get2(); fseek(ifp, 8, SEEK_CUR); Canon_WBpresets(8,24); fseek(ifp, 168, SEEK_CUR); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_WW][c ^ (c >> 1)] = get2(); fseek(ifp, 24, SEEK_CUR); Canon_WBCTpresets (2); // BCADT fseek(ifp, 6, SEEK_CUR); } else { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Other][c ^ (c >> 1)] = get2(); get2(); Canon_WBpresets(2,12); fseek (ifp, save1+(0xba<<1), SEEK_SET); Canon_WBCTpresets (2); // BCADT fseek (ifp, save1+(0x108<<1), SEEK_SET); // offset 264 short } int bls=0; FORC4 bls+= (imgdata.makernotes.canon.ChannelBlackLevel[c]=get2()); imgdata.makernotes.canon.AverageBlackLevel = bls/4; } break; case 1273: case 1275: imgdata.makernotes.canon.CanonColorDataVer = 6; // 600D / 1200D imgdata.makernotes.canon.CanonColorDataSubVer = get2(); { fseek (ifp, save1+(0x67<<1), SEEK_SET); Canon_WBpresets(2,12); fseek (ifp, save1+(0xbc<<1), SEEK_SET); Canon_WBCTpresets (0); // BCAT fseek (ifp, save1+(0x0fb<<1), SEEK_SET); // offset 251 short int bls=0; FORC4 bls+= (imgdata.makernotes.canon.ChannelBlackLevel[c]=get2()); imgdata.makernotes.canon.AverageBlackLevel = bls/4; } fseek (ifp, save1+(0x1e4<<1), SEEK_SET); // offset 484 shorts imgdata.makernotes.canon.SpecularWhiteLevel = get2(); FORC4 imgdata.color.linear_max[c] = imgdata.makernotes.canon.SpecularWhiteLevel; break; // 1DX / 5DmkIII / 6D / 100D / 650D / 700D / EOS M / 7DmkII / 750D / 760D case 1312: case 1313: case 1316: case 1506: imgdata.makernotes.canon.CanonColorDataVer = 7; imgdata.makernotes.canon.CanonColorDataSubVer = get2(); { fseek (ifp, save1+(0x80<<1), SEEK_SET); Canon_WBpresets(2,12); fseek (ifp, save1+(0xd5<<1), SEEK_SET); Canon_WBCTpresets (0); // BCAT fseek (ifp, save1+(0x114<<1), SEEK_SET); // offset 276 shorts int bls=0; FORC4 bls+= (imgdata.makernotes.canon.ChannelBlackLevel[c]=get2()); imgdata.makernotes.canon.AverageBlackLevel = bls/4; } if (imgdata.makernotes.canon.CanonColorDataSubVer == 10) { fseek (ifp, save1+(0x1fd<<1), SEEK_SET); // offset 509 shorts imgdata.makernotes.canon.SpecularWhiteLevel = get2(); FORC4 imgdata.color.linear_max[c] = imgdata.makernotes.canon.SpecularWhiteLevel; } else if (imgdata.makernotes.canon.CanonColorDataSubVer == 11) { fseek (ifp, save1+(0x2dd<<1), SEEK_SET); // offset 733 shorts imgdata.makernotes.canon.SpecularWhiteLevel = get2(); FORC4 imgdata.color.linear_max[c] = imgdata.makernotes.canon.SpecularWhiteLevel; } break; // 5DS / 5DS R / 80D / 1300D / 5D4 case 1560: case 1592: case 1353: imgdata.makernotes.canon.CanonColorDataVer = 8; imgdata.makernotes.canon.CanonColorDataSubVer = get2(); { fseek (ifp, save1+(0x85<<1), SEEK_SET); Canon_WBpresets(2,12); fseek (ifp, save1+(0x107<<1), SEEK_SET); Canon_WBCTpresets (0); // BCAT fseek (ifp, save1+(0x146<<1), SEEK_SET); // offset 326 shorts int bls=0; FORC4 bls+= (imgdata.makernotes.canon.ChannelBlackLevel[c]=get2()); imgdata.makernotes.canon.AverageBlackLevel = bls/4; } if (imgdata.makernotes.canon.CanonColorDataSubVer == 14) // 1300D { fseek (ifp, save1+(0x231<<1), SEEK_SET); imgdata.makernotes.canon.SpecularWhiteLevel = get2(); FORC4 imgdata.color.linear_max[c] = imgdata.makernotes.canon.SpecularWhiteLevel; } else { fseek (ifp, save1+(0x30f<<1), SEEK_SET); // offset 783 shorts imgdata.makernotes.canon.SpecularWhiteLevel = get2(); FORC4 imgdata.color.linear_max[c] = imgdata.makernotes.canon.SpecularWhiteLevel; } break; } fseek (ifp, save1, SEEK_SET); } } void CLASS setPentaxBodyFeatures (unsigned id) { imgdata.lens.makernotes.CamID = id; switch (id) { case 0x12994: case 0x12aa2: case 0x12b1a: case 0x12b60: case 0x12b62: case 0x12b7e: case 0x12b80: case 0x12b9c: case 0x12b9d: case 0x12ba2: case 0x12c1e: case 0x12c20: case 0x12cd2: case 0x12cd4: case 0x12cfa: case 0x12d72: case 0x12d73: case 0x12db8: case 0x12dfe: case 0x12e6c: case 0x12e76: case 0x12ef8: case 0x12f52: case 0x12f70: case 0x12f71: case 0x12fb6: case 0x12fc0: case 0x12fca: case 0x1301a: case 0x13024: case 0x1309c: case 0x13222: imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Pentax_K; imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Pentax_K; imgdata.lens.makernotes.CameraFormat = LIBRAW_FORMAT_APSC; break; case 0x13092: imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Pentax_K; imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Pentax_K; imgdata.lens.makernotes.CameraFormat = LIBRAW_FORMAT_FF; break; case 0x12e08: case 0x13010: imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Pentax_645; imgdata.lens.makernotes.LensFormat = LIBRAW_FORMAT_MF; imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Pentax_645; imgdata.lens.makernotes.CameraFormat = LIBRAW_FORMAT_MF; break; case 0x12ee4: case 0x12f66: case 0x12f7a: case 0x1302e: imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Pentax_Q; imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Pentax_Q; break; default: imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens; imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens; } return; } void CLASS PentaxISO (ushort c) { int code [] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 50, 100, 200, 400, 800, 1600, 3200, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278}; double value [] = {50, 64, 80, 100, 125, 160, 200, 250, 320, 400, 500, 640, 800, 1000, 1250, 1600, 2000, 2500, 3200, 4000, 5000, 6400, 8000, 10000, 12800, 16000, 20000, 25600, 32000, 40000, 51200, 64000, 80000, 102400, 128000, 160000, 204800, 50, 100, 200, 400, 800, 1600, 3200, 50, 70, 100, 140, 200, 280, 400, 560, 800, 1100, 1600, 2200, 3200, 4500, 6400, 9000, 12800, 18000, 25600, 36000, 51200}; #define numel (sizeof(code)/sizeof(code[0])) int i; for (i = 0; i < numel; i++) { if (code[i] == c) { iso_speed = value[i]; return; } } if (i == numel) iso_speed = 65535.0f; } #undef numel void CLASS PentaxLensInfo (unsigned id, unsigned len) // tag 0x0207 { ushort iLensData = 0; uchar *table_buf; table_buf = (uchar*)malloc(MAX(len,128)); fread(table_buf, len, 1, ifp); if ((id < 0x12b9c) || (((id == 0x12b9c) || // K100D (id == 0x12b9d) || // K110D (id == 0x12ba2)) && // K100D Super ((!table_buf[20] || (table_buf[20] == 0xff))))) { iLensData = 3; if (imgdata.lens.makernotes.LensID == -1) imgdata.lens.makernotes.LensID = (((unsigned)table_buf[0]) << 8) + table_buf[1]; } else switch (len) { case 90: // LensInfo3 iLensData = 13; if (imgdata.lens.makernotes.LensID == -1) imgdata.lens.makernotes.LensID = ((unsigned)((table_buf[1] & 0x0f) + table_buf[3]) <<8) + table_buf[4]; break; case 91: // LensInfo4 iLensData = 12; if (imgdata.lens.makernotes.LensID == -1) imgdata.lens.makernotes.LensID = ((unsigned)((table_buf[1] & 0x0f) + table_buf[3]) <<8) + table_buf[4]; break; case 80: // LensInfo5 case 128: iLensData = 15; if (imgdata.lens.makernotes.LensID == -1) imgdata.lens.makernotes.LensID = ((unsigned)((table_buf[1] & 0x0f) + table_buf[4]) <<8) + table_buf[5]; break; default: if (id >= 0x12b9c) // LensInfo2 { iLensData = 4; if (imgdata.lens.makernotes.LensID == -1) imgdata.lens.makernotes.LensID = ((unsigned)((table_buf[0] & 0x0f) + table_buf[2]) <<8) + table_buf[3]; } } if (iLensData) { if (table_buf[iLensData+9] && (fabs(imgdata.lens.makernotes.CurFocal) < 0.1f)) imgdata.lens.makernotes.CurFocal = 10*(table_buf[iLensData+9]>>2) * libraw_powf64(4, (table_buf[iLensData+9] & 0x03)-2); if (table_buf[iLensData+10] & 0xf0) imgdata.lens.makernotes.MaxAp4CurFocal = libraw_powf64(2.0f, (float)((table_buf[iLensData+10] & 0xf0) >>4)/4.0f); if (table_buf[iLensData+10] & 0x0f) imgdata.lens.makernotes.MinAp4CurFocal = libraw_powf64(2.0f, (float)((table_buf[iLensData+10] & 0x0f) + 10)/4.0f); if (iLensData != 12) { switch (table_buf[iLensData] & 0x06) { case 0: imgdata.lens.makernotes.MinAp4MinFocal = 22.0f; break; case 2: imgdata.lens.makernotes.MinAp4MinFocal = 32.0f; break; case 4: imgdata.lens.makernotes.MinAp4MinFocal = 45.0f; break; case 6: imgdata.lens.makernotes.MinAp4MinFocal = 16.0f; break; } if (table_buf[iLensData] & 0x70) imgdata.lens.makernotes.LensFStops = ((float)(((table_buf[iLensData] & 0x70) >> 4) ^ 0x07)) / 2.0f + 5.0f; imgdata.lens.makernotes.MinFocusDistance = (float)(table_buf[iLensData+3] & 0xf8); imgdata.lens.makernotes.FocusRangeIndex = (float)(table_buf[iLensData+3] & 0x07); if ((table_buf[iLensData+14] > 1) && (fabs(imgdata.lens.makernotes.MaxAp4CurFocal) < 0.7f)) imgdata.lens.makernotes.MaxAp4CurFocal = libraw_powf64(2.0f, (float)((table_buf[iLensData+14] & 0x7f) -1)/32.0f); } else if ((id != 0x12e76) && // K-5 (table_buf[iLensData+15] > 1) && (fabs(imgdata.lens.makernotes.MaxAp4CurFocal) < 0.7f)) { imgdata.lens.makernotes.MaxAp4CurFocal = libraw_powf64(2.0f, (float)((table_buf[iLensData+15] & 0x7f) -1)/32.0f); } } free(table_buf); return; } void CLASS setPhaseOneFeatures (unsigned id) { ushort i; static const struct { ushort id; char t_model[32]; } p1_unique[] = { // Phase One section: {1, "Hasselblad V"}, {10, "PhaseOne/Mamiya"}, {12, "Contax 645"}, {16, "Hasselblad V"}, {17, "Hasselblad V"}, {18, "Contax 645"}, {19, "PhaseOne/Mamiya"}, {20, "Hasselblad V"}, {21, "Contax 645"}, {22, "PhaseOne/Mamiya"}, {23, "Hasselblad V"}, {24, "Hasselblad H"}, {25, "PhaseOne/Mamiya"}, {32, "Contax 645"}, {34, "Hasselblad V"}, {35, "Hasselblad V"}, {36, "Hasselblad H"}, {37, "Contax 645"}, {38, "PhaseOne/Mamiya"}, {39, "Hasselblad V"}, {40, "Hasselblad H"}, {41, "Contax 645"}, {42, "PhaseOne/Mamiya"}, {44, "Hasselblad V"}, {45, "Hasselblad H"}, {46, "Contax 645"}, {47, "PhaseOne/Mamiya"}, {48, "Hasselblad V"}, {49, "Hasselblad H"}, {50, "Contax 645"}, {51, "PhaseOne/Mamiya"}, {52, "Hasselblad V"}, {53, "Hasselblad H"}, {54, "Contax 645"}, {55, "PhaseOne/Mamiya"}, {67, "Hasselblad V"}, {68, "Hasselblad H"}, {69, "Contax 645"}, {70, "PhaseOne/Mamiya"}, {71, "Hasselblad V"}, {72, "Hasselblad H"}, {73, "Contax 645"}, {74, "PhaseOne/Mamiya"}, {76, "Hasselblad V"}, {77, "Hasselblad H"}, {78, "Contax 645"}, {79, "PhaseOne/Mamiya"}, {80, "Hasselblad V"}, {81, "Hasselblad H"}, {82, "Contax 645"}, {83, "PhaseOne/Mamiya"}, {84, "Hasselblad V"}, {85, "Hasselblad H"}, {86, "Contax 645"}, {87, "PhaseOne/Mamiya"}, {99, "Hasselblad V"}, {100, "Hasselblad H"}, {101, "Contax 645"}, {102, "PhaseOne/Mamiya"}, {103, "Hasselblad V"}, {104, "Hasselblad H"}, {105, "PhaseOne/Mamiya"}, {106, "Contax 645"}, {112, "Hasselblad V"}, {113, "Hasselblad H"}, {114, "Contax 645"}, {115, "PhaseOne/Mamiya"}, {131, "Hasselblad V"}, {132, "Hasselblad H"}, {133, "Contax 645"}, {134, "PhaseOne/Mamiya"}, {135, "Hasselblad V"}, {136, "Hasselblad H"}, {137, "Contax 645"}, {138, "PhaseOne/Mamiya"}, {140, "Hasselblad V"}, {141, "Hasselblad H"}, {142, "Contax 645"}, {143, "PhaseOne/Mamiya"}, {148, "Hasselblad V"}, {149, "Hasselblad H"}, {150, "Contax 645"}, {151, "PhaseOne/Mamiya"}, {160, "A-250"}, {161, "A-260"}, {162, "A-280"}, {167, "Hasselblad V"}, {168, "Hasselblad H"}, {169, "Contax 645"}, {170, "PhaseOne/Mamiya"}, {172, "Hasselblad V"}, {173, "Hasselblad H"}, {174, "Contax 645"}, {175, "PhaseOne/Mamiya"}, {176, "Hasselblad V"}, {177, "Hasselblad H"}, {178, "Contax 645"}, {179, "PhaseOne/Mamiya"}, {180, "Hasselblad V"}, {181, "Hasselblad H"}, {182, "Contax 645"}, {183, "PhaseOne/Mamiya"}, {208, "Hasselblad V"}, {211, "PhaseOne/Mamiya"}, {448, "Phase One 645AF"}, {457, "Phase One 645DF"}, {471, "Phase One 645DF+"}, {704, "Phase One iXA"}, {705, "Phase One iXA - R"}, {706, "Phase One iXU 150"}, {707, "Phase One iXU 150 - NIR"}, {708, "Phase One iXU 180"}, {721, "Phase One iXR"}, // Leaf section: {333,"Mamiya"}, {329,"Universal"}, {330,"Hasselblad H1/H2"}, {332,"Contax"}, {336,"AFi"}, {327,"Mamiya"}, {324,"Universal"}, {325,"Hasselblad H1/H2"}, {326,"Contax"}, {335,"AFi"}, {340,"Mamiya"}, {337,"Universal"}, {338,"Hasselblad H1/H2"}, {339,"Contax"}, {323,"Mamiya"}, {320,"Universal"}, {322,"Hasselblad H1/H2"}, {321,"Contax"}, {334,"AFi"}, {369,"Universal"}, {370,"Mamiya"}, {371,"Hasselblad H1/H2"}, {372,"Contax"}, {373,"Afi"}, }; imgdata.lens.makernotes.CamID = id; if (id && !imgdata.lens.makernotes.body[0]) { for (i=0; i < sizeof p1_unique / sizeof *p1_unique; i++) if (id == p1_unique[i].id) { strcpy(imgdata.lens.makernotes.body,p1_unique[i].t_model); } } return; } void CLASS parseFujiMakernotes (unsigned tag, unsigned type) { switch (tag) { case 0x1002: imgdata.makernotes.fuji.WB_Preset = get2(); break; case 0x1011: imgdata.other.FlashEC = getreal(type); break; case 0x1020: imgdata.makernotes.fuji.Macro = get2(); break; case 0x1021: imgdata.makernotes.fuji.FocusMode = get2(); break; case 0x1022: imgdata.makernotes.fuji.AFMode = get2(); break; case 0x1023: imgdata.makernotes.fuji.FocusPixel[0] = get2(); imgdata.makernotes.fuji.FocusPixel[1] = get2(); break; case 0x1034: imgdata.makernotes.fuji.ExrMode = get2(); break; case 0x1050: imgdata.makernotes.fuji.ShutterType = get2(); break; case 0x1400: imgdata.makernotes.fuji.FujiDynamicRange = get2(); break; case 0x1401: imgdata.makernotes.fuji.FujiFilmMode = get2(); break; case 0x1402: imgdata.makernotes.fuji.FujiDynamicRangeSetting = get2(); break; case 0x1403: imgdata.makernotes.fuji.FujiDevelopmentDynamicRange = get2(); break; case 0x140b: imgdata.makernotes.fuji.FujiAutoDynamicRange = get2(); break; case 0x1404: imgdata.lens.makernotes.MinFocal = getreal(type); break; case 0x1405: imgdata.lens.makernotes.MaxFocal = getreal(type); break; case 0x1406: imgdata.lens.makernotes.MaxAp4MinFocal = getreal(type); break; case 0x1407: imgdata.lens.makernotes.MaxAp4MaxFocal = getreal(type); break; case 0x1422: imgdata.makernotes.fuji.ImageStabilization[0] = get2(); imgdata.makernotes.fuji.ImageStabilization[1] = get2(); imgdata.makernotes.fuji.ImageStabilization[2] = get2(); imgdata.shootinginfo.ImageStabilization = (imgdata.makernotes.fuji.ImageStabilization[0]<<9) + imgdata.makernotes.fuji.ImageStabilization[1]; break; case 0x1431: imgdata.makernotes.fuji.Rating = get4(); break; case 0x3820: imgdata.makernotes.fuji.FrameRate = get2(); break; case 0x3821: imgdata.makernotes.fuji.FrameWidth = get2(); break; case 0x3822: imgdata.makernotes.fuji.FrameHeight = get2(); break; } return; } void CLASS setSonyBodyFeatures (unsigned id) { imgdata.lens.makernotes.CamID = id; if ( // FF cameras (id == 257) || // a900 (id == 269) || // a850 (id == 340) || // ILCE-7M2 (id == 318) || // ILCE-7S (id == 350) || // ILCE-7SM2 (id == 311) || // ILCE-7R (id == 347) || // ILCE-7RM2 (id == 306) || // ILCE-7 (id == 298) || // DSC-RX1 (id == 299) || // NEX-VG900 (id == 310) || // DSC-RX1R (id == 344) || // DSC-RX1RM2 (id == 354) || // ILCA-99M2 (id == 294) // SLT-99, Hasselblad HV ) { imgdata.lens.makernotes.CameraFormat = LIBRAW_FORMAT_FF; } else if ((id == 297) || // DSC-RX100 (id == 308) || // DSC-RX100M2 (id == 309) || // DSC-RX10 (id == 317) || // DSC-RX100M3 (id == 341) || // DSC-RX100M4 (id == 342) || // DSC-RX10M2 (id == 355) || // DSC-RX10M3 (id == 356) // DSC-RX100M5 ) { imgdata.lens.makernotes.CameraFormat = LIBRAW_FORMAT_1INCH; } else if (id != 002) // DSC-R1 { imgdata.lens.makernotes.CameraFormat = LIBRAW_FORMAT_APSC; } if ( // E-mount cameras, ILCE series (id == 302) || (id == 306) || (id == 311) || (id == 312) || (id == 313) || (id == 318) || (id == 339) || (id == 340) || (id == 346) || (id == 347) || (id == 350) || (id == 360) ) { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Sony_E; imgdata.makernotes.sony.SonyCameraType = LIBRAW_SONY_ILCE; } else if ( // E-mount cameras, NEX series (id == 278) || (id == 279) || (id == 284) || (id == 288) || (id == 289) || (id == 290) || (id == 293) || (id == 295) || (id == 296) || (id == 299) || (id == 300) || (id == 305) || (id == 307) ) { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Sony_E; imgdata.makernotes.sony.SonyCameraType = LIBRAW_SONY_NEX; } else if ( // A-mount cameras, DSLR series (id == 256) || (id == 257) || (id == 258) || (id == 259) || (id == 260) || (id == 261) || (id == 262) || (id == 263) || (id == 264) || (id == 265) || (id == 266) || (id == 269) || (id == 270) || (id == 273) || (id == 274) || (id == 275) || (id == 282) || (id == 283) ) { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Minolta_A; imgdata.makernotes.sony.SonyCameraType = LIBRAW_SONY_DSLR; } else if ( // A-mount cameras, SLT series (id == 280) || (id == 281) || (id == 285) || (id == 286) || (id == 287) || (id == 291) || (id == 292) || (id == 294) || (id == 303) ) { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Minolta_A; imgdata.makernotes.sony.SonyCameraType = LIBRAW_SONY_SLT; } else if ( // A-mount cameras, ILCA series (id == 319) || (id == 353) || (id == 354) ) { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Minolta_A; imgdata.makernotes.sony.SonyCameraType = LIBRAW_SONY_ILCA; } else if ( // DSC (id == 002) || // DSC-R1 (id == 297) || // DSC-RX100 (id == 298) || // DSC-RX1 (id == 308) || // DSC-RX100M2 (id == 309) || // DSC-RX10 (id == 310) || // DSC-RX1R (id == 344) || // DSC-RX1RM2 (id == 317) || // DSC-RX100M3 (id == 341) || // DSC-RX100M4 (id == 342) || // DSC-RX10M2 (id == 355) || // DSC-RX10M3 (id == 356) // DSC-RX100M5 ) { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens; imgdata.makernotes.sony.SonyCameraType = LIBRAW_SONY_DSC; } return; } void CLASS parseSonyLensType2 (uchar a, uchar b) { ushort lid2; lid2 = (((ushort)a)<<8) | ((ushort)b); if (!lid2) return; if (lid2 < 0x100) { if ((imgdata.lens.makernotes.AdapterID != 0x4900) && (imgdata.lens.makernotes.AdapterID != 0xEF00)) { imgdata.lens.makernotes.AdapterID = lid2; switch (lid2) { case 1: case 2: case 3: case 6: imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Minolta_A; break; case 44: case 78: case 239: imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Canon_EF; break; } } } else imgdata.lens.makernotes.LensID = lid2; if ((lid2 >= 50481) && (lid2 < 50500)) { strcpy(imgdata.lens.makernotes.Adapter, "MC-11"); imgdata.lens.makernotes.AdapterID = 0x4900; } return; } #define strnXcat(buf,string) strncat(buf,string,LIM(sizeof(buf)-strbuflen(buf)-1,0,sizeof(buf))) void CLASS parseSonyLensFeatures (uchar a, uchar b) { ushort features; features = (((ushort)a)<<8) | ((ushort)b); if ((imgdata.lens.makernotes.LensMount == LIBRAW_MOUNT_Canon_EF) || (imgdata.lens.makernotes.LensMount != LIBRAW_MOUNT_Sigma_X3F) || !features) return; imgdata.lens.makernotes.LensFeatures_pre[0] = 0; imgdata.lens.makernotes.LensFeatures_suf[0] = 0; if ((features & 0x0200) && (features & 0x0100)) strcpy(imgdata.lens.makernotes.LensFeatures_pre, "E"); else if (features & 0x0200) strcpy(imgdata.lens.makernotes.LensFeatures_pre, "FE"); else if (features & 0x0100) strcpy(imgdata.lens.makernotes.LensFeatures_pre, "DT"); if (!imgdata.lens.makernotes.LensFormat && !imgdata.lens.makernotes.LensMount) { imgdata.lens.makernotes.LensFormat = LIBRAW_FORMAT_FF; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Minolta_A; if ((features & 0x0200) && (features & 0x0100)) { imgdata.lens.makernotes.LensFormat = LIBRAW_FORMAT_APSC; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Sony_E; } else if (features & 0x0200) { imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Sony_E; } else if (features & 0x0100) { imgdata.lens.makernotes.LensFormat = LIBRAW_FORMAT_APSC; } } if (features & 0x4000) strnXcat(imgdata.lens.makernotes.LensFeatures_pre, " PZ"); if (features & 0x0008) strnXcat(imgdata.lens.makernotes.LensFeatures_suf, " G"); else if (features & 0x0004) strnXcat(imgdata.lens.makernotes.LensFeatures_suf, " ZA" ); if ((features & 0x0020) && (features & 0x0040)) strnXcat(imgdata.lens.makernotes.LensFeatures_suf, " Macro"); else if (features & 0x0020) strnXcat(imgdata.lens.makernotes.LensFeatures_suf, " STF"); else if (features & 0x0040) strnXcat(imgdata.lens.makernotes.LensFeatures_suf, " Reflex"); else if (features & 0x0080) strnXcat(imgdata.lens.makernotes.LensFeatures_suf, " Fisheye"); if (features & 0x0001) strnXcat(imgdata.lens.makernotes.LensFeatures_suf, " SSM"); else if (features & 0x0002) strnXcat(imgdata.lens.makernotes.LensFeatures_suf, " SAM"); if (features & 0x8000) strnXcat(imgdata.lens.makernotes.LensFeatures_suf, " OSS"); if (features & 0x2000) strnXcat(imgdata.lens.makernotes.LensFeatures_suf, " LE"); if (features & 0x0800) strnXcat(imgdata.lens.makernotes.LensFeatures_suf, " II"); if (imgdata.lens.makernotes.LensFeatures_suf[0] == ' ') memmove(imgdata.lens.makernotes.LensFeatures_suf, imgdata.lens.makernotes.LensFeatures_suf+1, strbuflen(imgdata.lens.makernotes.LensFeatures_suf)-1); return; } #undef strnXcat void CLASS process_Sony_0x940c (uchar * buf) { ushort lid2; if ((imgdata.lens.makernotes.LensMount != LIBRAW_MOUNT_Canon_EF) && (imgdata.lens.makernotes.LensMount != LIBRAW_MOUNT_Sigma_X3F)) { switch (SonySubstitution[buf[0x0008]]) { case 1: case 5: imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Minolta_A; break; case 4: imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Sony_E; break; } } lid2 = (((ushort)SonySubstitution[buf[0x000a]])<<8) | ((ushort)SonySubstitution[buf[0x0009]]); if ((lid2 > 0) && (lid2 < 32784)) parseSonyLensType2 (SonySubstitution[buf[0x000a]], // LensType2 - Sony lens ids SonySubstitution[buf[0x0009]]); return; } void CLASS process_Sony_0x9050 (uchar * buf, unsigned id) { ushort lid; if ((imgdata.lens.makernotes.CameraMount != LIBRAW_MOUNT_Sony_E) && (imgdata.lens.makernotes.CameraMount != LIBRAW_MOUNT_FixedLens)) { if (buf[0]) imgdata.lens.makernotes.MaxAp4CurFocal = my_roundf(libraw_powf64(2.0f, ((float)SonySubstitution[buf[0]] / 8.0 - 1.06f) / 2.0f)*10.0f) / 10.0f; if (buf[1]) imgdata.lens.makernotes.MinAp4CurFocal = my_roundf(libraw_powf64(2.0f, ((float)SonySubstitution[buf[1]] / 8.0 - 1.06f) / 2.0f)*10.0f) / 10.0f; } if (imgdata.lens.makernotes.CameraMount != LIBRAW_MOUNT_FixedLens) { if (buf[0x3d] | buf[0x3c]) { lid = SonySubstitution[buf[0x3d]] << 8 | SonySubstitution[buf[0x3c]]; imgdata.lens.makernotes.CurAp = libraw_powf64(2.0f, ((float)lid/256.0f - 16.0f) / 2.0f); } if (buf[0x105] && (imgdata.lens.makernotes.LensMount != LIBRAW_MOUNT_Canon_EF) && (imgdata.lens.makernotes.LensMount != LIBRAW_MOUNT_Sigma_X3F)) imgdata.lens.makernotes.LensMount = SonySubstitution[buf[0x105]]; if (buf[0x106]) imgdata.lens.makernotes.LensFormat = SonySubstitution[buf[0x106]]; } if (imgdata.lens.makernotes.CameraMount == LIBRAW_MOUNT_Sony_E) { parseSonyLensType2 (SonySubstitution[buf[0x0108]], // LensType2 - Sony lens ids SonySubstitution[buf[0x0107]]); } if ((imgdata.lens.makernotes.LensID == -1) && (imgdata.lens.makernotes.CameraMount == LIBRAW_MOUNT_Minolta_A) && (buf[0x010a] | buf[0x0109])) { imgdata.lens.makernotes.LensID = // LensType - Minolta/Sony lens ids SonySubstitution[buf[0x010a]] << 8 | SonySubstitution[buf[0x0109]]; if ((imgdata.lens.makernotes.LensID > 0x4900) && (imgdata.lens.makernotes.LensID <= 0x5900)) { imgdata.lens.makernotes.AdapterID = 0x4900; imgdata.lens.makernotes.LensID -= imgdata.lens.makernotes.AdapterID; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Sigma_X3F; strcpy(imgdata.lens.makernotes.Adapter, "MC-11"); } else if ((imgdata.lens.makernotes.LensID > 0xEF00) && (imgdata.lens.makernotes.LensID < 0xFFFF) && (imgdata.lens.makernotes.LensID != 0xFF00)) { imgdata.lens.makernotes.AdapterID = 0xEF00; imgdata.lens.makernotes.LensID -= imgdata.lens.makernotes.AdapterID; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Canon_EF; } } if ((id >= 286) && (id <= 293)) // "SLT-A65", "SLT-A77", "NEX-7", "NEX-VG20E", // "SLT-A37", "SLT-A57", "NEX-F3", "Lunar" parseSonyLensFeatures (SonySubstitution[buf[0x115]], SonySubstitution[buf[0x116]]); else if (imgdata.lens.makernotes.CameraMount != LIBRAW_MOUNT_FixedLens) parseSonyLensFeatures(SonySubstitution[buf[0x116]], SonySubstitution[buf[0x117]]); if ((id == 347) || (id == 350) || (id == 357)) { unsigned long long b88 = SonySubstitution[buf[0x88]]; unsigned long long b89 = SonySubstitution[buf[0x89]]; unsigned long long b8a = SonySubstitution[buf[0x8a]]; unsigned long long b8b = SonySubstitution[buf[0x8b]]; unsigned long long b8c = SonySubstitution[buf[0x8c]]; unsigned long long b8d = SonySubstitution[buf[0x8d]]; sprintf(imgdata.shootinginfo.InternalBodySerial, "%06llx", (b88 << 40) + (b89 << 32) + (b8a << 24) + (b8b << 16) + (b8c << 8) + b8d); } else if ((imgdata.lens.makernotes.CameraMount == LIBRAW_MOUNT_Minolta_A) && (id > 279) && (id != 282) && (id != 283)) { unsigned long long bf0 = SonySubstitution[buf[0xf0]]; unsigned long long bf1 = SonySubstitution[buf[0xf1]]; unsigned long long bf2 = SonySubstitution[buf[0xf2]]; unsigned long long bf3 = SonySubstitution[buf[0xf3]]; unsigned long long bf4 = SonySubstitution[buf[0xf4]]; sprintf(imgdata.shootinginfo.InternalBodySerial, "%05llx", (bf0 << 32) + (bf1 << 24) + (bf2 << 16) + (bf3 << 8) + bf4); } else if ((imgdata.lens.makernotes.CameraMount == LIBRAW_MOUNT_Sony_E) && (id != 288) && (id != 289) && (id != 290)) { unsigned b7c = SonySubstitution[buf[0x7c]]; unsigned b7d = SonySubstitution[buf[0x7d]]; unsigned b7e = SonySubstitution[buf[0x7e]]; unsigned b7f = SonySubstitution[buf[0x7f]]; sprintf(imgdata.shootinginfo.InternalBodySerial, "%04x", (b7c << 24) + (b7d << 16) + (b7e << 8) + b7f); } return; } void CLASS parse_makernote_0xc634(int base, int uptag, unsigned dng_writer) { unsigned ver97 = 0, offset = 0, entries, tag, type, len, save, c; unsigned i; uchar NikonKey, ci, cj, ck; unsigned serial = 0; unsigned custom_serial = 0; unsigned NikonLensDataVersion = 0; unsigned lenNikonLensData = 0; unsigned NikonFlashInfoVersion = 0; uchar *CanonCameraInfo; unsigned lenCanonCameraInfo = 0; uchar *table_buf; uchar *table_buf_0x9050; ushort table_buf_0x9050_present = 0; uchar *table_buf_0x940c; ushort table_buf_0x940c_present = 0; short morder, sorder = order; char buf[10]; INT64 fsize = ifp->size(); fread(buf, 1, 10, ifp); if (!strcmp(buf, "Nikon")) { base = ftell(ifp); order = get2(); if (get2() != 42) goto quit; offset = get4(); fseek(ifp, offset - 8, SEEK_CUR); } else if (!strcmp(buf, "OLYMPUS") || !strcmp(buf, "PENTAX ") || (!strncmp(make, "SAMSUNG", 7) && (dng_writer == CameraDNG))) { base = ftell(ifp) - 10; fseek(ifp, -2, SEEK_CUR); order = get2(); if (buf[0] == 'O') get2(); } else if (!strncmp(buf, "SONY", 4) || !strcmp(buf, "Panasonic")) { goto nf; } else if (!strncmp(buf, "FUJIFILM", 8)) { base = ftell(ifp) - 10; nf: order = 0x4949; fseek(ifp, 2, SEEK_CUR); } else if (!strcmp(buf, "OLYMP") || !strcmp(buf, "LEICA") || !strcmp(buf, "Ricoh") || !strcmp(buf, "EPSON")) fseek(ifp, -2, SEEK_CUR); else if (!strcmp(buf, "AOC") || !strcmp(buf, "QVC")) fseek(ifp, -4, SEEK_CUR); else { fseek(ifp, -10, SEEK_CUR); if ((!strncmp(make, "SAMSUNG", 7) && (dng_writer == AdobeDNG))) base = ftell(ifp); } entries = get2(); if (entries > 1000) return; morder = order; while (entries--) { order = morder; tiff_get(base, &tag, &type, &len, &save); INT64 pos = ifp->tell(); if(len > 8 && pos+len > 2* fsize) continue; tag |= uptag << 16; if(len > 100*1024*1024) goto next; // 100Mb tag? No! if (!strncmp(make, "Canon",5)) { if (tag == 0x000d && len < 256000) // camera info { CanonCameraInfo = (uchar*)malloc(MAX(16,len)); fread(CanonCameraInfo, len, 1, ifp); lenCanonCameraInfo = len; } else if (tag == 0x10) // Canon ModelID { unique_id = get4(); if (unique_id == 0x03740000) unique_id = 0x80000374; // M3 if (unique_id == 0x03840000) unique_id = 0x80000384; // M10 if (unique_id == 0x03940000) unique_id = 0x80000394; // M5 setCanonBodyFeatures(unique_id); if (lenCanonCameraInfo) { processCanonCameraInfo(unique_id, CanonCameraInfo,lenCanonCameraInfo); free(CanonCameraInfo); CanonCameraInfo = 0; lenCanonCameraInfo = 0; } } else parseCanonMakernotes (tag, type, len); } else if (!strncmp(make, "FUJI", 4)) parseFujiMakernotes (tag, type); else if (!strncasecmp(make, "LEICA", 5)) { if (((tag == 0x035e) || (tag == 0x035f)) && (type == 10) && (len == 9)) { int ind = tag == 0x035e?0:1; for (int j=0; j < 3; j++) FORCC imgdata.color.dng_color[ind].forwardmatrix[j][c]= getreal(type); } if ((tag == 0x0303) && (type != 4)) { stmread(imgdata.lens.makernotes.Lens, len,ifp); } if ((tag == 0x3405) || (tag == 0x0310) || (tag == 0x34003405)) { imgdata.lens.makernotes.LensID = get4(); imgdata.lens.makernotes.LensID = ((imgdata.lens.makernotes.LensID>>2)<<8) | (imgdata.lens.makernotes.LensID & 0x3); if (imgdata.lens.makernotes.LensID != -1) { if ((model[0] == 'M') || !strncasecmp (model, "LEICA M", 7)) { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Leica_M; if (imgdata.lens.makernotes.LensID) imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Leica_M; } else if ((model[0] == 'S') || !strncasecmp (model, "LEICA S", 7)) { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Leica_S; if (imgdata.lens.makernotes.Lens[0]) imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Leica_S; } } } else if ( ((tag == 0x0313) || (tag == 0x34003406)) && (fabs(imgdata.lens.makernotes.CurAp) < 0.17f) && ((type == 10) || (type == 5)) ) { imgdata.lens.makernotes.CurAp = getreal(type); if (imgdata.lens.makernotes.CurAp > 126.3) imgdata.lens.makernotes.CurAp = 0.0f; } else if (tag == 0x3400) { parse_makernote (base, 0x3400); } } else if (!strncmp(make, "NIKON", 5)) { if (tag == 0x1d) // serial number while ((c = fgetc(ifp)) && c != EOF) { if ((!custom_serial) && (!isdigit(c))) { if ((strbuflen(model) == 3) && (!strcmp(model,"D50"))) { custom_serial = 34; } else { custom_serial = 96; } } serial = serial*10 + (isdigit(c) ? c - '0' : c % 10); } else if (tag == 0x000a) { imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens; imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens; } else if (tag == 0x0082) // lens attachment { stmread(imgdata.lens.makernotes.Attachment, len, ifp); } else if (tag == 0x0083) // lens type { imgdata.lens.nikon.NikonLensType = fgetc(ifp); } else if (tag == 0x0084) // lens { imgdata.lens.makernotes.MinFocal = getreal(type); imgdata.lens.makernotes.MaxFocal = getreal(type); imgdata.lens.makernotes.MaxAp4MinFocal = getreal(type); imgdata.lens.makernotes.MaxAp4MaxFocal = getreal(type); } else if (tag == 0x008b) // lens f-stops { uchar a, b, c; a = fgetc(ifp); b = fgetc(ifp); c = fgetc(ifp); if (c) { imgdata.lens.nikon.NikonLensFStops = a*b*(12/c); imgdata.lens.makernotes.LensFStops = (float)imgdata.lens.nikon.NikonLensFStops /12.0f; } } else if (tag == 0x0093) { i = get2(); if ((i == 7) || (i == 9)) { imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens; imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens; } } else if (tag == 0x0097) { for (i=0; i < 4; i++) ver97 = ver97 * 10 + fgetc(ifp)-'0'; if (ver97 == 601) // Coolpix A { imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens; imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens; } } else if (tag == 0x0098) // contains lens data { for (i = 0; i < 4; i++) { NikonLensDataVersion = NikonLensDataVersion * 10 + fgetc(ifp) - '0'; } switch (NikonLensDataVersion) { case 100: lenNikonLensData = 9; break; case 101: case 201: // encrypted, starting from v.201 case 202: case 203: lenNikonLensData = 15; break; case 204: lenNikonLensData = 16; break; case 400: lenNikonLensData = 459; break; case 401: lenNikonLensData = 590; break; case 402: lenNikonLensData = 509; break; case 403: lenNikonLensData = 879; break; } if(lenNikonLensData) { table_buf = (uchar*)malloc(lenNikonLensData); fread(table_buf, lenNikonLensData, 1, ifp); if ((NikonLensDataVersion < 201) && lenNikonLensData) { processNikonLensData(table_buf, lenNikonLensData); free(table_buf); lenNikonLensData = 0; } } } else if (tag == 0xa7) // shutter count { NikonKey = fgetc(ifp) ^ fgetc(ifp) ^ fgetc(ifp) ^ fgetc(ifp); if ((NikonLensDataVersion > 200) && lenNikonLensData) { if (custom_serial) { ci = xlat[0][custom_serial]; } else { ci = xlat[0][serial & 0xff]; } cj = xlat[1][NikonKey]; ck = 0x60; for (i = 0; i < lenNikonLensData; i++) table_buf[i] ^= (cj += ci * ck++); processNikonLensData(table_buf, lenNikonLensData); lenNikonLensData = 0; free(table_buf); } } else if (tag == 0x00a8) // contains flash data { for (i = 0; i < 4; i++) { NikonFlashInfoVersion = NikonFlashInfoVersion * 10 + fgetc(ifp) - '0'; } } else if (tag == 37 && (!iso_speed || iso_speed == 65535)) { unsigned char cc; fread(&cc, 1, 1, ifp); iso_speed = (int)(100.0 * libraw_powf64(2.0, (double)(cc) / 12.0 - 5.0)); break; } } else if (!strncmp(make, "OLYMPUS", 7)) { int SubDirOffsetValid = strncmp (model, "E-300", 5) && strncmp (model, "E-330", 5) && strncmp (model, "E-400", 5) && strncmp (model, "E-500", 5) && strncmp (model, "E-1", 3); if ((tag == 0x2010) || (tag == 0x2020)) { fseek(ifp, save - 4, SEEK_SET); fseek(ifp, base + get4(), SEEK_SET); parse_makernote_0xc634(base, tag, dng_writer); } if (!SubDirOffsetValid && ((len > 4) || ( ((type == 3) || (type == 8)) && (len > 2)) || ( ((type == 4) || (type == 9)) && (len > 1)) || (type == 5) || (type > 9))) goto skip_Oly_broken_tags; switch (tag) { case 0x0207: case 0x20100100: { uchar sOlyID[8]; unsigned long long OlyID; fread (sOlyID, MIN(len,7), 1, ifp); sOlyID[7] = 0; OlyID = sOlyID[0]; i = 1; while (i < 7 && sOlyID[i]) { OlyID = OlyID << 8 | sOlyID[i]; i++; } setOlympusBodyFeatures(OlyID); } break; case 0x1002: imgdata.lens.makernotes.CurAp = libraw_powf64(2.0f, getreal(type)/2); break; case 0x20100102: stmread(imgdata.shootinginfo.InternalBodySerial, len, ifp); break; case 0x20100201: imgdata.lens.makernotes.LensID = (unsigned long long)fgetc(ifp)<<16 | (unsigned long long)(fgetc(ifp), fgetc(ifp))<<8 | (unsigned long long)fgetc(ifp); imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FT; imgdata.lens.makernotes.LensFormat = LIBRAW_FORMAT_FT; if (((imgdata.lens.makernotes.LensID < 0x20000) || (imgdata.lens.makernotes.LensID > 0x4ffff)) && (imgdata.lens.makernotes.LensID & 0x10)) { imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_mFT; } break; case 0x20100202: if ((!imgdata.lens.LensSerial[0])) stmread(imgdata.lens.LensSerial, len, ifp); break; case 0x20100203: stmread(imgdata.lens.makernotes.Lens,len, ifp); break; case 0x20100205: imgdata.lens.makernotes.MaxAp4MinFocal = libraw_powf64(sqrt(2.0f), get2() / 256.0f); break; case 0x20100206: imgdata.lens.makernotes.MaxAp4MaxFocal = libraw_powf64(sqrt(2.0f), get2() / 256.0f); break; case 0x20100207: imgdata.lens.makernotes.MinFocal = (float)get2(); break; case 0x20100208: imgdata.lens.makernotes.MaxFocal = (float)get2(); if (imgdata.lens.makernotes.MaxFocal > 1000.0f) imgdata.lens.makernotes.MaxFocal = imgdata.lens.makernotes.MinFocal; break; case 0x2010020a: imgdata.lens.makernotes.MaxAp4CurFocal = libraw_powf64(sqrt(2.0f), get2() / 256.0f); break; case 0x20100301: imgdata.lens.makernotes.TeleconverterID = fgetc(ifp) << 8; fgetc(ifp); imgdata.lens.makernotes.TeleconverterID = imgdata.lens.makernotes.TeleconverterID | fgetc(ifp); break; case 0x20100303: stmread(imgdata.lens.makernotes.Teleconverter, len, ifp); break; case 0x20100403: stmread(imgdata.lens.makernotes.Attachment,len, ifp); break; case 0x20200401: imgdata.other.FlashEC = getreal(type); break; } skip_Oly_broken_tags:; } else if (!strncmp(make, "PENTAX", 6) || !strncmp(model, "PENTAX", 6) || (!strncmp(make, "SAMSUNG", 7) && (dng_writer == CameraDNG))) { if (tag == 0x0005) { unique_id = get4(); setPentaxBodyFeatures(unique_id); } else if (tag == 0x0013) { imgdata.lens.makernotes.CurAp = (float)get2()/10.0f; } else if (tag == 0x0014) { PentaxISO(get2()); } else if (tag == 0x001d) { imgdata.lens.makernotes.CurFocal = (float)get4()/100.0f; } else if (tag == 0x003f) { imgdata.lens.makernotes.LensID = fgetc(ifp) << 8 | fgetc(ifp); } else if (tag == 0x004d) { if (type == 9) imgdata.other.FlashEC = getreal(type) / 256.0f; else imgdata.other.FlashEC = (float) ((signed short) fgetc(ifp)) / 6.0f; } else if (tag == 0x007e) { imgdata.color.linear_max[0] = imgdata.color.linear_max[1] = imgdata.color.linear_max[2] = imgdata.color.linear_max[3] = (long)(-1) * get4(); } else if (tag == 0x0207) { if(len < 65535) // Safety belt PentaxLensInfo(imgdata.lens.makernotes.CamID, len); } else if (tag == 0x020d) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][c ^ (c >> 1)] = get2(); } else if (tag == 0x020e) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][c ^ (c >> 1)] = get2(); } else if (tag == 0x020f) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][c ^ (c >> 1)] = get2(); } else if (tag == 0x0210) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][c ^ (c >> 1)] = get2(); } else if (tag == 0x0211) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][c ^ (c >> 1)] = get2(); } else if (tag == 0x0212) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][c ^ (c >> 1)] = get2(); } else if (tag == 0x0213) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][c ^ (c >> 1)] = get2(); } else if (tag == 0x0214) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][c ^ (c >> 1)] = get2(); } else if (tag == 0x0221) { int nWB = get2(); if(nWB<=sizeof(imgdata.color.WBCT_Coeffs)/sizeof(imgdata.color.WBCT_Coeffs[0])) for (int i = 0; i < nWB; i++) { imgdata.color.WBCT_Coeffs[i][0] = (unsigned)0xcfc6 - get2(); fseek(ifp, 2, SEEK_CUR); imgdata.color.WBCT_Coeffs[i][1] = get2(); imgdata.color.WBCT_Coeffs[i][2] = imgdata.color.WBCT_Coeffs[i][4] = 0x2000; imgdata.color.WBCT_Coeffs[i][3] = get2(); } } else if (tag == 0x0215) { fseek (ifp, 16, SEEK_CUR); sprintf(imgdata.shootinginfo.InternalBodySerial, "%d", get4()); } else if (tag == 0x0229) { stmread(imgdata.shootinginfo.BodySerial, len, ifp); } else if (tag == 0x022d) { fseek (ifp,2,SEEK_CUR); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][c ^ (c >> 1)] = get2(); getc(ifp); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][c ^ (c >> 1)] = get2(); getc(ifp); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][c ^ (c >> 1)] = get2(); getc(ifp); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][c ^ (c >> 1)] = get2(); getc(ifp); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][c ^ (c >> 1)] = get2(); getc(ifp); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][c ^ (c >> 1)] = get2(); getc(ifp); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][c ^ (c >> 1)] = get2(); getc(ifp); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][c ^ (c >> 1)] = get2(); getc(ifp); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_L][c ^ (c >> 1)] = get2(); } else if (tag == 0x0239) // Q-series lens info (LensInfoQ) { char LensInfo [20]; fseek (ifp, 12, SEEK_CUR); stread(imgdata.lens.makernotes.Lens, 30, ifp); strcat(imgdata.lens.makernotes.Lens, " "); stread(LensInfo, 20, ifp); strcat(imgdata.lens.makernotes.Lens, LensInfo); } } else if (!strncmp(make, "SAMSUNG", 7) && (dng_writer == AdobeDNG)) { if (tag == 0x0002) { if(get4() == 0x2000) { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Samsung_NX; } else if (!strncmp(model, "NX mini", 7)) { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Samsung_NX_M; } else { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens; } } else if (tag == 0x0003) { imgdata.lens.makernotes.CamID = unique_id = get4(); } else if (tag == 0xa003) { imgdata.lens.makernotes.LensID = get2(); if (imgdata.lens.makernotes.LensID) imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Samsung_NX; } else if (tag == 0xa005) { stmread(imgdata.lens.InternalLensSerial, len, ifp); } else if (tag == 0xa019) { imgdata.lens.makernotes.CurAp = getreal(type); } else if (tag == 0xa01a) { imgdata.lens.makernotes.FocalLengthIn35mmFormat = get4() / 10.0f; if (imgdata.lens.makernotes.FocalLengthIn35mmFormat < 10.0f) imgdata.lens.makernotes.FocalLengthIn35mmFormat *= 10.0f; } } else if (!strncasecmp(make, "SONY", 4) || !strncasecmp(make, "Konica", 6) || !strncasecmp(make, "Minolta", 7) || (!strncasecmp(make, "Hasselblad", 10) && (!strncasecmp(model, "Stellar", 7) || !strncasecmp(model, "Lunar", 5) || !strncasecmp(model, "Lusso", 5) || !strncasecmp(model, "HV",2)))) { ushort lid; if (tag == 0xb001) // Sony ModelID { unique_id = get2(); setSonyBodyFeatures(unique_id); if (table_buf_0x9050_present) { process_Sony_0x9050(table_buf_0x9050, unique_id); free (table_buf_0x9050); table_buf_0x9050_present = 0; } if (table_buf_0x940c_present) { if (imgdata.lens.makernotes.CameraMount == LIBRAW_MOUNT_Sony_E) { process_Sony_0x940c(table_buf_0x940c); } free (table_buf_0x940c); table_buf_0x940c_present = 0; } } else if ((tag == 0x0010) && // CameraInfo strncasecmp(model, "DSLR-A100", 9) && strncasecmp(model, "NEX-5C", 6) && !strncasecmp(make, "SONY", 4) && ((len == 368) || // a700 (len == 5478) || // a850, a900 (len == 5506) || // a200, a300, a350 (len == 6118) || // a230, a290, a330, a380, a390 // a450, a500, a550, a560, a580 // a33, a35, a55 // NEX3, NEX5, NEX5C, NEXC3, VG10E (len == 15360)) ) { table_buf = (uchar*)malloc(len); fread(table_buf, len, 1, ifp); if (memcmp(table_buf, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) && memcmp(table_buf, "\x00\x00\x00\x00\x00\x00\x00\x00", 8)) { switch (len) { case 368: case 5478: // a700, a850, a900: CameraInfo if (saneSonyCameraInfo(table_buf[0], table_buf[3], table_buf[2], table_buf[5], table_buf[4], table_buf[7])) { if (table_buf[0] | table_buf[3]) imgdata.lens.makernotes.MinFocal = bcd2dec(table_buf[0]) * 100 + bcd2dec(table_buf[3]); if (table_buf[2] | table_buf[5]) imgdata.lens.makernotes.MaxFocal = bcd2dec(table_buf[2]) * 100 + bcd2dec(table_buf[5]); if (table_buf[4]) imgdata.lens.makernotes.MaxAp4MinFocal = bcd2dec(table_buf[4]) / 10.0f; if (table_buf[4]) imgdata.lens.makernotes.MaxAp4MaxFocal = bcd2dec(table_buf[7]) / 10.0f; parseSonyLensFeatures(table_buf[1], table_buf[6]); } break; default: // CameraInfo2 & 3 if (saneSonyCameraInfo(table_buf[1], table_buf[2], table_buf[3], table_buf[4], table_buf[5], table_buf[6])) { if (table_buf[1] | table_buf[2]) imgdata.lens.makernotes.MinFocal = bcd2dec(table_buf[1]) * 100 + bcd2dec(table_buf[2]); if (table_buf[3] | table_buf[4]) imgdata.lens.makernotes.MaxFocal = bcd2dec(table_buf[3]) * 100 + bcd2dec(table_buf[4]); if (table_buf[5]) imgdata.lens.makernotes.MaxAp4MinFocal = bcd2dec(table_buf[5]) / 10.0f; if (table_buf[6]) imgdata.lens.makernotes.MaxAp4MaxFocal = bcd2dec(table_buf[6]) / 10.0f; parseSonyLensFeatures(table_buf[0], table_buf[7]); } } } free(table_buf); } else if (tag == 0x0104) { imgdata.other.FlashEC = getreal(type); } else if (tag == 0x0105) // Teleconverter { imgdata.lens.makernotes.TeleconverterID = get2(); } else if (tag == 0x0114 && len < 65535) // CameraSettings { table_buf = (uchar*)malloc(len); fread(table_buf, len, 1, ifp); switch (len) { case 280: case 364: case 332: // CameraSettings and CameraSettings2 are big endian if (table_buf[2] | table_buf[3]) { lid = (((ushort)table_buf[2])<<8) | ((ushort)table_buf[3]); imgdata.lens.makernotes.CurAp = libraw_powf64(2.0f, ((float)lid/8.0f-1.0f)/2.0f); } break; case 1536: case 2048: // CameraSettings3 are little endian parseSonyLensType2(table_buf[1016], table_buf[1015]); if (imgdata.lens.makernotes.LensMount != LIBRAW_MOUNT_Canon_EF) { switch (table_buf[153]) { case 16: imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Minolta_A; break; case 17: imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Sony_E; break; } } break; } free(table_buf); } else if (tag == 0x9050 && len < 256000) // little endian { table_buf_0x9050 = (uchar*)malloc(len); table_buf_0x9050_present = 1; fread(table_buf_0x9050, len, 1, ifp); if (imgdata.lens.makernotes.CamID) { process_Sony_0x9050(table_buf_0x9050, imgdata.lens.makernotes.CamID); free (table_buf_0x9050); table_buf_0x9050_present = 0; } } else if (tag == 0x940c && len < 256000) { table_buf_0x940c = (uchar*)malloc(len); table_buf_0x940c_present = 1; fread(table_buf_0x940c, len, 1, ifp); if ((imgdata.lens.makernotes.CamID) && (imgdata.lens.makernotes.CameraMount == LIBRAW_MOUNT_Sony_E)) { process_Sony_0x940c(table_buf_0x940c); free(table_buf_0x940c); table_buf_0x940c_present = 0; } } else if (((tag == 0xb027) || (tag == 0x010c)) && (imgdata.lens.makernotes.LensID == -1)) { imgdata.lens.makernotes.LensID = get4(); if ((imgdata.lens.makernotes.LensID > 0x4900) && (imgdata.lens.makernotes.LensID <= 0x5900)) { imgdata.lens.makernotes.AdapterID = 0x4900; imgdata.lens.makernotes.LensID -= imgdata.lens.makernotes.AdapterID; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Sigma_X3F; strcpy(imgdata.lens.makernotes.Adapter, "MC-11"); } else if ((imgdata.lens.makernotes.LensID > 0xEF00) && (imgdata.lens.makernotes.LensID < 0xFFFF) && (imgdata.lens.makernotes.LensID != 0xFF00)) { imgdata.lens.makernotes.AdapterID = 0xEF00; imgdata.lens.makernotes.LensID -= imgdata.lens.makernotes.AdapterID; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Canon_EF; } if (tag == 0x010c) imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Minolta_A; } else if (tag == 0xb02a && len < 256000) // Sony LensSpec { table_buf = (uchar*)malloc(len); fread(table_buf, len, 1, ifp); if (saneSonyCameraInfo(table_buf[1], table_buf[2], table_buf[3], table_buf[4], table_buf[5], table_buf[6])) { if (table_buf[1] | table_buf[2]) imgdata.lens.makernotes.MinFocal = bcd2dec(table_buf[1]) * 100 + bcd2dec(table_buf[2]); if (table_buf[3] | table_buf[4]) imgdata.lens.makernotes.MaxFocal = bcd2dec(table_buf[3]) * 100 + bcd2dec(table_buf[4]); if (table_buf[5]) imgdata.lens.makernotes.MaxAp4MinFocal = bcd2dec(table_buf[5]) / 10.0f; if (table_buf[6]) imgdata.lens.makernotes.MaxAp4MaxFocal = bcd2dec(table_buf[6]) / 10.0f; parseSonyLensFeatures(table_buf[0], table_buf[7]); } free(table_buf); } } next: fseek (ifp, save, SEEK_SET); } quit: order = sorder; } #else void CLASS parse_makernote_0xc634(int base, int uptag, unsigned dng_writer) { /*placeholder */ } #endif void CLASS parse_makernote (int base, int uptag) { unsigned offset=0, entries, tag, type, len, save, c; unsigned ver97=0, serial=0, i, wbi=0, wb[4]={0,0,0,0}; uchar buf97[324], ci, cj, ck; short morder, sorder=order; char buf[10]; unsigned SamsungKey[11]; uchar NikonKey; #ifdef LIBRAW_LIBRARY_BUILD unsigned custom_serial = 0; unsigned NikonLensDataVersion = 0; unsigned lenNikonLensData = 0; unsigned NikonFlashInfoVersion = 0; uchar *CanonCameraInfo; unsigned lenCanonCameraInfo = 0; uchar *table_buf; uchar *table_buf_0x9050; ushort table_buf_0x9050_present = 0; uchar *table_buf_0x940c; ushort table_buf_0x940c_present = 0; INT64 fsize = ifp->size(); #endif /* The MakerNote might have its own TIFF header (possibly with its own byte-order!), or it might just be a table. */ if (!strncmp(make,"Nokia",5)) return; fread (buf, 1, 10, ifp); if (!strncmp (buf,"KDK" ,3) || /* these aren't TIFF tables */ !strncmp (buf,"VER" ,3) || !strncmp (buf,"IIII",4) || !strncmp (buf,"MMMM",4)) return; if (!strncmp (buf,"KC" ,2) || /* Konica KD-400Z, KD-510Z */ !strncmp (buf,"MLY" ,3)) { /* Minolta DiMAGE G series */ order = 0x4d4d; while ((i=ftell(ifp)) < data_offset && i < 16384) { wb[0] = wb[2]; wb[2] = wb[1]; wb[1] = wb[3]; wb[3] = get2(); if (wb[1] == 256 && wb[3] == 256 && wb[0] > 256 && wb[0] < 640 && wb[2] > 256 && wb[2] < 640) FORC4 cam_mul[c] = wb[c]; } goto quit; } if (!strcmp (buf,"Nikon")) { base = ftell(ifp); order = get2(); if (get2() != 42) goto quit; offset = get4(); fseek (ifp, offset-8, SEEK_CUR); } else if (!strcmp (buf,"OLYMPUS") || !strcmp (buf,"PENTAX ")) { base = ftell(ifp)-10; fseek (ifp, -2, SEEK_CUR); order = get2(); if (buf[0] == 'O') get2(); } else if (!strncmp (buf,"SONY",4) || !strcmp (buf,"Panasonic")) { goto nf; } else if (!strncmp (buf,"FUJIFILM",8)) { base = ftell(ifp)-10; nf: order = 0x4949; fseek (ifp, 2, SEEK_CUR); } else if (!strcmp (buf,"OLYMP") || !strcmp (buf,"LEICA") || !strcmp (buf,"Ricoh") || !strcmp (buf,"EPSON")) fseek (ifp, -2, SEEK_CUR); else if (!strcmp (buf,"AOC") || !strcmp (buf,"QVC")) fseek (ifp, -4, SEEK_CUR); else { fseek (ifp, -10, SEEK_CUR); if (!strncmp(make,"SAMSUNG",7)) base = ftell(ifp); } // adjust pos & base for Leica M8/M9/M Mono tags and dir in tag 0x3400 if (!strncasecmp(make, "LEICA", 5)) { if (!strncmp(model, "M8", 2) || !strncasecmp(model, "Leica M8", 8) || !strncasecmp(model, "LEICA X", 7)) { base = ftell(ifp)-8; } else if (!strncasecmp(model, "LEICA M (Typ 240)", 17)) { base = 0; } else if (!strncmp(model, "M9", 2) || !strncasecmp(model, "Leica M9", 8) || !strncasecmp(model, "M Monochrom", 11) || !strncasecmp(model, "Leica M Monochrom", 11)) { if (!uptag) { base = ftell(ifp) - 10; fseek (ifp, 8, SEEK_CUR); } else if (uptag == 0x3400) { fseek (ifp, 10, SEEK_CUR); base += 10; } } else if (!strncasecmp(model, "LEICA T", 7)) { base = ftell(ifp)-8; #ifdef LIBRAW_LIBRARY_BUILD imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Leica_T; #endif } #ifdef LIBRAW_LIBRARY_BUILD else if (!strncasecmp(model, "LEICA SL", 8)) { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Leica_SL; imgdata.lens.makernotes.CameraFormat = LIBRAW_FORMAT_FF; } #endif } entries = get2(); if (entries > 1000) return; morder = order; while (entries--) { order = morder; tiff_get (base, &tag, &type, &len, &save); tag |= uptag << 16; #ifdef LIBRAW_LIBRARY_BUILD INT64 _pos = ftell(ifp); if(len > 8 && _pos+len > 2* fsize) continue; if (!strncmp(make, "Canon",5)) { if (tag == 0x000d && len < 256000) // camera info { CanonCameraInfo = (uchar*)malloc(MAX(16,len)); fread(CanonCameraInfo, len, 1, ifp); lenCanonCameraInfo = len; } else if (tag == 0x10) // Canon ModelID { unique_id = get4(); if (unique_id == 0x03740000) unique_id = 0x80000374; // M3 if (unique_id == 0x03840000) unique_id = 0x80000384; // M10 if (unique_id == 0x03940000) unique_id = 0x80000394; // M5 setCanonBodyFeatures(unique_id); if (lenCanonCameraInfo) { processCanonCameraInfo(unique_id, CanonCameraInfo,lenCanonCameraInfo); free(CanonCameraInfo); CanonCameraInfo = 0; lenCanonCameraInfo = 0; } } else parseCanonMakernotes (tag, type, len); } else if (!strncmp(make, "FUJI", 4)) { if (tag == 0x0010) { char FujiSerial[sizeof(imgdata.shootinginfo.InternalBodySerial)]; char *words[4]; char yy[2], mm[3], dd[3], ystr[16], ynum[16]; int year, nwords, ynum_len; unsigned c; stmread(FujiSerial, len, ifp); nwords = getwords(FujiSerial, words, 4,sizeof(imgdata.shootinginfo.InternalBodySerial)); for (int i = 0; i < nwords; i++) { mm[2] = dd[2] = 0; if (strnlen(words[i],sizeof(imgdata.shootinginfo.InternalBodySerial)-1) < 18) if (i == 0) strncpy (imgdata.shootinginfo.InternalBodySerial, words[0], sizeof(imgdata.shootinginfo.InternalBodySerial)-1); else { char tbuf[sizeof(imgdata.shootinginfo.InternalBodySerial)]; snprintf (tbuf, sizeof(tbuf), "%s %s", imgdata.shootinginfo.InternalBodySerial, words[i]); strncpy(imgdata.shootinginfo.InternalBodySerial,tbuf, sizeof(imgdata.shootinginfo.InternalBodySerial)-1); } else { strncpy (dd, words[i]+strnlen(words[i],sizeof(imgdata.shootinginfo.InternalBodySerial)-1)-14, 2); strncpy (mm, words[i]+strnlen(words[i],sizeof(imgdata.shootinginfo.InternalBodySerial)-1)-16, 2); strncpy (yy, words[i]+strnlen(words[i],sizeof(imgdata.shootinginfo.InternalBodySerial)-1)-18, 2); year = (yy[0]-'0')*10 + (yy[1]-'0'); if (year <70) year += 2000; else year += 1900; ynum_len = (int)strnlen(words[i],sizeof(imgdata.shootinginfo.InternalBodySerial)-1)-18; strncpy(ynum, words[i], ynum_len); ynum[ynum_len] = 0; for ( int j = 0; ynum[j] && ynum[j+1] && sscanf(ynum+j, "%2x", &c); j += 2) ystr[j/2] = c; ystr[ynum_len / 2 + 1] = 0; strcpy (model2, ystr); if (i == 0) { char tbuf[sizeof(imgdata.shootinginfo.InternalBodySerial)]; if (nwords == 1) snprintf (tbuf,sizeof(tbuf), "%s %s %d:%s:%s", words[0]+strnlen(words[0],sizeof(imgdata.shootinginfo.InternalBodySerial)-1)-12, ystr, year, mm, dd); else snprintf (tbuf,sizeof(tbuf), "%s %d:%s:%s %s", ystr, year, mm, dd, words[0]+strnlen(words[0],sizeof(imgdata.shootinginfo.InternalBodySerial)-1)-12); strncpy(imgdata.shootinginfo.InternalBodySerial,tbuf, sizeof(imgdata.shootinginfo.InternalBodySerial)-1); } else { char tbuf[sizeof(imgdata.shootinginfo.InternalBodySerial)]; snprintf (tbuf, sizeof(tbuf), "%s %s %d:%s:%s %s", imgdata.shootinginfo.InternalBodySerial, ystr, year, mm, dd, words[i]+strnlen(words[i],sizeof(imgdata.shootinginfo.InternalBodySerial)-1)-12); strncpy(imgdata.shootinginfo.InternalBodySerial,tbuf, sizeof(imgdata.shootinginfo.InternalBodySerial)-1); } } } } else parseFujiMakernotes (tag, type); } else if (!strncasecmp(make, "LEICA", 5)) { if (((tag == 0x035e) || (tag == 0x035f)) && (type == 10) && (len == 9)) { int ind = tag == 0x035e?0:1; for (int j=0; j < 3; j++) FORCC imgdata.color.dng_color[ind].forwardmatrix[j][c]= getreal(type); } if ((tag == 0x0303) && (type != 4)) { stmread(imgdata.lens.makernotes.Lens, len, ifp); } if ((tag == 0x3405) || (tag == 0x0310) || (tag == 0x34003405)) { imgdata.lens.makernotes.LensID = get4(); imgdata.lens.makernotes.LensID = ((imgdata.lens.makernotes.LensID>>2)<<8) | (imgdata.lens.makernotes.LensID & 0x3); if (imgdata.lens.makernotes.LensID != -1) { if ((model[0] == 'M') || !strncasecmp (model, "LEICA M", 7)) { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Leica_M; if (imgdata.lens.makernotes.LensID) imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Leica_M; } else if ((model[0] == 'S') || !strncasecmp (model, "LEICA S", 7)) { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Leica_S; if (imgdata.lens.makernotes.Lens[0]) imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Leica_S; } } } else if ( ((tag == 0x0313) || (tag == 0x34003406)) && (fabs(imgdata.lens.makernotes.CurAp) < 0.17f) && ((type == 10) || (type == 5)) ) { imgdata.lens.makernotes.CurAp = getreal(type); if (imgdata.lens.makernotes.CurAp > 126.3) imgdata.lens.makernotes.CurAp = 0.0f; } else if (tag == 0x3400) { parse_makernote (base, 0x3400); } } else if (!strncmp(make, "NIKON",5)) { if (tag == 0x000a) { imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens; imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens; } else if (tag == 0x0012) { char a, b, c; a = fgetc(ifp); b = fgetc(ifp); c = fgetc(ifp); if (c) imgdata.other.FlashEC = (float)(a*b)/(float)c; } else if (tag == 0x0082) // lens attachment { stmread(imgdata.lens.makernotes.Attachment, len, ifp); } else if (tag == 0x0083) // lens type { imgdata.lens.nikon.NikonLensType = fgetc(ifp); } else if (tag == 0x0084) // lens { imgdata.lens.makernotes.MinFocal = getreal(type); imgdata.lens.makernotes.MaxFocal = getreal(type); imgdata.lens.makernotes.MaxAp4MinFocal = getreal(type); imgdata.lens.makernotes.MaxAp4MaxFocal = getreal(type); } else if (tag == 0x008b) // lens f-stops { uchar a, b, c; a = fgetc(ifp); b = fgetc(ifp); c = fgetc(ifp); if (c) { imgdata.lens.nikon.NikonLensFStops = a*b*(12/c); imgdata.lens.makernotes.LensFStops = (float)imgdata.lens.nikon.NikonLensFStops /12.0f; } } else if (tag == 0x0093) { i = get2(); if ((i == 7) || (i == 9)) { imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens; imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens; } } else if (tag == 0x0098) // contains lens data { for (i = 0; i < 4; i++) { NikonLensDataVersion = NikonLensDataVersion * 10 + fgetc(ifp) - '0'; } switch (NikonLensDataVersion) { case 100: lenNikonLensData = 9; break; case 101: case 201: // encrypted, starting from v.201 case 202: case 203: lenNikonLensData = 15; break; case 204: lenNikonLensData = 16; break; case 400: lenNikonLensData = 459; break; case 401: lenNikonLensData = 590; break; case 402: lenNikonLensData = 509; break; case 403: lenNikonLensData = 879; break; } if(lenNikonLensData>0) { table_buf = (uchar*)malloc(lenNikonLensData); fread(table_buf, lenNikonLensData, 1, ifp); if ((NikonLensDataVersion < 201) && lenNikonLensData) { processNikonLensData(table_buf, lenNikonLensData); free(table_buf); lenNikonLensData = 0; } } } else if (tag == 0x00a0) { stmread(imgdata.shootinginfo.BodySerial, len, ifp); } else if (tag == 0x00a8) // contains flash data { for (i = 0; i < 4; i++) { NikonFlashInfoVersion = NikonFlashInfoVersion * 10 + fgetc(ifp) - '0'; } } } else if (!strncmp(make, "OLYMPUS", 7)) { switch (tag) { case 0x0404: case 0x101a: case 0x20100101: if (!imgdata.shootinginfo.BodySerial[0]) stmread(imgdata.shootinginfo.BodySerial, len, ifp); break; case 0x20100102: if (!imgdata.shootinginfo.InternalBodySerial[0]) stmread(imgdata.shootinginfo.InternalBodySerial, len, ifp); break; case 0x0207: case 0x20100100: { uchar sOlyID[8]; unsigned long long OlyID; fread (sOlyID, MIN(len,7), 1, ifp); sOlyID[7] = 0; OlyID = sOlyID[0]; i = 1; while (i < 7 && sOlyID[i]) { OlyID = OlyID << 8 | sOlyID[i]; i++; } setOlympusBodyFeatures(OlyID); } break; case 0x1002: imgdata.lens.makernotes.CurAp = libraw_powf64(2.0f, getreal(type)/2); break; case 0x20401112: imgdata.makernotes.olympus.OlympusCropID = get2(); break; case 0x20401113: FORC4 imgdata.makernotes.olympus.OlympusFrame[c] = get2(); break; case 0x20100201: { unsigned long long oly_lensid [3]; oly_lensid[0] = fgetc(ifp); fgetc(ifp); oly_lensid[1] = fgetc(ifp); oly_lensid[2] = fgetc(ifp); imgdata.lens.makernotes.LensID = (oly_lensid[0] << 16) | (oly_lensid[1] << 8) | oly_lensid[2]; } imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FT; imgdata.lens.makernotes.LensFormat = LIBRAW_FORMAT_FT; if (((imgdata.lens.makernotes.LensID < 0x20000) || (imgdata.lens.makernotes.LensID > 0x4ffff)) && (imgdata.lens.makernotes.LensID & 0x10)) { imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_mFT; } break; case 0x20100202: stmread(imgdata.lens.LensSerial, len, ifp); break; case 0x20100203: stmread(imgdata.lens.makernotes.Lens, len, ifp); break; case 0x20100205: imgdata.lens.makernotes.MaxAp4MinFocal = libraw_powf64(sqrt(2.0f), get2() / 256.0f); break; case 0x20100206: imgdata.lens.makernotes.MaxAp4MaxFocal = libraw_powf64(sqrt(2.0f), get2() / 256.0f); break; case 0x20100207: imgdata.lens.makernotes.MinFocal = (float)get2(); break; case 0x20100208: imgdata.lens.makernotes.MaxFocal = (float)get2(); if (imgdata.lens.makernotes.MaxFocal > 1000.0f) imgdata.lens.makernotes.MaxFocal = imgdata.lens.makernotes.MinFocal; break; case 0x2010020a: imgdata.lens.makernotes.MaxAp4CurFocal = libraw_powf64(sqrt(2.0f), get2() / 256.0f); break; case 0x20100301: imgdata.lens.makernotes.TeleconverterID = fgetc(ifp) << 8; fgetc(ifp); imgdata.lens.makernotes.TeleconverterID = imgdata.lens.makernotes.TeleconverterID | fgetc(ifp); break; case 0x20100303: stmread(imgdata.lens.makernotes.Teleconverter, len, ifp); break; case 0x20100403: stmread(imgdata.lens.makernotes.Attachment, len, ifp); break; } } else if ((!strncmp(make, "PENTAX", 6) || !strncmp(make, "RICOH", 5)) && !strncmp(model, "GR", 2)) { if (tag == 0x0005) { char buffer[17]; int count=0; fread(buffer, 16, 1, ifp); buffer[16] = 0; for (int i=0; i<16; i++) { // sprintf(imgdata.shootinginfo.InternalBodySerial+2*i, "%02x", buffer[i]); if ((isspace(buffer[i])) || (buffer[i] == 0x2D) || (isalnum(buffer[i]))) count++; } if (count == 16) { sprintf (imgdata.shootinginfo.BodySerial, "%8s", buffer+8); buffer[8] = 0; sprintf (imgdata.shootinginfo.InternalBodySerial, "%8s", buffer); } else { sprintf (imgdata.shootinginfo.BodySerial, "%02x%02x%02x%02x", buffer[4], buffer[5], buffer[6], buffer[7]); sprintf (imgdata.shootinginfo.InternalBodySerial, "%02x%02x%02x%02x", buffer[8], buffer[9], buffer[10], buffer[11]); } } else if ((tag == 0x1001) && (type == 3)) { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens; imgdata.lens.makernotes.CameraFormat = LIBRAW_FORMAT_APSC; imgdata.lens.makernotes.LensID = -1; imgdata.lens.makernotes.FocalType = 1; } else if ((tag == 0x100b) && (type == 10)) { imgdata.other.FlashEC = getreal(type); } else if ((tag == 0x1017) && (get2() == 2)) { strcpy(imgdata.lens.makernotes.Attachment, "Wide-Angle Adapter"); } else if (tag == 0x1500) { imgdata.lens.makernotes.CurFocal = getreal(type); } } else if (!strncmp(make, "RICOH", 5) && strncmp(model, "PENTAX", 6)) { if ((tag == 0x0005) && !strncmp(model, "GXR", 3)) { char buffer[9]; buffer[8] = 0; fread(buffer, 8, 1, ifp); sprintf (imgdata.shootinginfo.InternalBodySerial, "%8s", buffer); } else if ((tag == 0x100b) && (type == 10)) { imgdata.other.FlashEC = getreal(type); } else if ((tag == 0x1017) && (get2() == 2)) { strcpy(imgdata.lens.makernotes.Attachment, "Wide-Angle Adapter"); } else if (tag == 0x1500) { imgdata.lens.makernotes.CurFocal = getreal(type); } else if ((tag == 0x2001) && !strncmp(model, "GXR", 3)) { short ntags, cur_tag; fseek(ifp, 20, SEEK_CUR); ntags = get2(); cur_tag = get2(); while (cur_tag != 0x002c) { fseek(ifp, 10, SEEK_CUR); cur_tag = get2(); } fseek(ifp, 6, SEEK_CUR); fseek(ifp, get4()+20, SEEK_SET); stread(imgdata.shootinginfo.BodySerial, 12, ifp); get2(); imgdata.lens.makernotes.LensID = getc(ifp) - '0'; switch(imgdata.lens.makernotes.LensID) { case 1: case 2: case 3: case 5: case 6: imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_RicohModule; break; case 8: imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Leica_M; imgdata.lens.makernotes.CameraFormat = LIBRAW_FORMAT_APSC; imgdata.lens.makernotes.LensID = -1; break; default: imgdata.lens.makernotes.LensID = -1; } fseek(ifp, 17, SEEK_CUR); stread(imgdata.lens.LensSerial, 12, ifp); } } else if ((!strncmp(make, "PENTAX", 6) || !strncmp(model, "PENTAX", 6) || (!strncmp(make, "SAMSUNG", 7) && dng_version)) && strncmp(model, "GR", 2)) { if (tag == 0x0005) { unique_id = get4(); setPentaxBodyFeatures(unique_id); } else if (tag == 0x0013) { imgdata.lens.makernotes.CurAp = (float)get2()/10.0f; } else if (tag == 0x0014) { PentaxISO(get2()); } else if (tag == 0x001d) { imgdata.lens.makernotes.CurFocal = (float)get4()/100.0f; } else if (tag == 0x003f) { imgdata.lens.makernotes.LensID = fgetc(ifp) << 8 | fgetc(ifp); } else if (tag == 0x004d) { if (type == 9) imgdata.other.FlashEC = getreal(type) / 256.0f; else imgdata.other.FlashEC = (float) ((signed short) fgetc(ifp)) / 6.0f; } else if (tag == 0x007e) { imgdata.color.linear_max[0] = imgdata.color.linear_max[1] = imgdata.color.linear_max[2] = imgdata.color.linear_max[3] = (long)(-1) * get4(); } else if (tag == 0x0207) { if(len < 65535) // Safety belt PentaxLensInfo(imgdata.lens.makernotes.CamID, len); } else if (tag == 0x020d) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][c ^ (c >> 1)] = get2(); } else if (tag == 0x020e) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][c ^ (c >> 1)] = get2(); } else if (tag == 0x020f) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][c ^ (c >> 1)] = get2(); } else if (tag == 0x0210) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][c ^ (c >> 1)] = get2(); } else if (tag == 0x0211) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][c ^ (c >> 1)] = get2(); } else if (tag == 0x0212) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][c ^ (c >> 1)] = get2(); } else if (tag == 0x0213) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][c ^ (c >> 1)] = get2(); } else if (tag == 0x0214) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][c ^ (c >> 1)] = get2(); } else if (tag == 0x0221) { int nWB = get2(); if(nWB<=sizeof(imgdata.color.WBCT_Coeffs)/sizeof(imgdata.color.WBCT_Coeffs[0])) for (int i = 0; i < nWB; i++) { imgdata.color.WBCT_Coeffs[i][0] = (unsigned)0xcfc6 - get2(); fseek(ifp, 2, SEEK_CUR); imgdata.color.WBCT_Coeffs[i][1] = get2(); imgdata.color.WBCT_Coeffs[i][2] = imgdata.color.WBCT_Coeffs[i][4] = 0x2000; imgdata.color.WBCT_Coeffs[i][3] = get2(); } } else if (tag == 0x0215) { fseek (ifp, 16, SEEK_CUR); sprintf(imgdata.shootinginfo.InternalBodySerial, "%d", get4()); } else if (tag == 0x0229) { stmread(imgdata.shootinginfo.BodySerial, len, ifp); } else if (tag == 0x022d) { fseek (ifp,2,SEEK_CUR); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][c ^ (c >> 1)] = get2(); getc(ifp); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][c ^ (c >> 1)] = get2(); getc(ifp); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][c ^ (c >> 1)] = get2(); getc(ifp); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][c ^ (c >> 1)] = get2(); getc(ifp); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][c ^ (c >> 1)] = get2(); getc(ifp); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][c ^ (c >> 1)] = get2(); getc(ifp); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][c ^ (c >> 1)] = get2(); getc(ifp); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][c ^ (c >> 1)] = get2(); getc(ifp); FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_L][c ^ (c >> 1)] = get2(); } else if (tag == 0x0239) // Q-series lens info (LensInfoQ) { char LensInfo [20]; fseek (ifp, 2, SEEK_CUR); stread(imgdata.lens.makernotes.Lens, 30, ifp); strcat(imgdata.lens.makernotes.Lens, " "); stread(LensInfo, 20, ifp); strcat(imgdata.lens.makernotes.Lens, LensInfo); } } else if (!strncmp(make, "SAMSUNG", 7)) { if (tag == 0x0002) { if(get4() == 0x2000) { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Samsung_NX; } else if (!strncmp(model, "NX mini", 7)) { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Samsung_NX_M; } else { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens; } } else if (tag == 0x0003) { unique_id = imgdata.lens.makernotes.CamID = get4(); } else if (tag == 0xa002) { stmread(imgdata.shootinginfo.BodySerial, len, ifp); } else if (tag == 0xa003) { imgdata.lens.makernotes.LensID = get2(); if (imgdata.lens.makernotes.LensID) imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Samsung_NX; } else if (tag == 0xa005) { stmread(imgdata.lens.InternalLensSerial, len, ifp); } else if (tag == 0xa019) { imgdata.lens.makernotes.CurAp = getreal(type); } else if (tag == 0xa01a) { imgdata.lens.makernotes.FocalLengthIn35mmFormat = get4() / 10.0f; if (imgdata.lens.makernotes.FocalLengthIn35mmFormat < 10.0f) imgdata.lens.makernotes.FocalLengthIn35mmFormat *= 10.0f; } } else if (!strncasecmp(make, "SONY", 4) || !strncasecmp(make, "Konica", 6) || !strncasecmp(make, "Minolta", 7) || (!strncasecmp(make, "Hasselblad", 10) && (!strncasecmp(model, "Stellar", 7) || !strncasecmp(model, "Lunar", 5) || !strncasecmp(model, "Lusso", 5) || !strncasecmp(model, "HV",2)))) { ushort lid; if (tag == 0xb001) // Sony ModelID { unique_id = get2(); setSonyBodyFeatures(unique_id); if (table_buf_0x9050_present) { process_Sony_0x9050(table_buf_0x9050, unique_id); free (table_buf_0x9050); table_buf_0x9050_present = 0; } if (table_buf_0x940c_present) { if (imgdata.lens.makernotes.CameraMount == LIBRAW_MOUNT_Sony_E) { process_Sony_0x940c(table_buf_0x940c); } free (table_buf_0x940c); table_buf_0x940c_present = 0; } } else if ((tag == 0x0010) && // CameraInfo strncasecmp(model, "DSLR-A100", 9) && strncasecmp(model, "NEX-5C", 6) && !strncasecmp(make, "SONY", 4) && ((len == 368) || // a700 (len == 5478) || // a850, a900 (len == 5506) || // a200, a300, a350 (len == 6118) || // a230, a290, a330, a380, a390 // a450, a500, a550, a560, a580 // a33, a35, a55 // NEX3, NEX5, NEX5C, NEXC3, VG10E (len == 15360)) ) { table_buf = (uchar*)malloc(len); fread(table_buf, len, 1, ifp); if (memcmp(table_buf, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) && memcmp(table_buf, "\x00\x00\x00\x00\x00\x00\x00\x00", 8)) { switch (len) { case 368: case 5478: // a700, a850, a900: CameraInfo if (table_buf[0] | table_buf[3]) imgdata.lens.makernotes.MinFocal = bcd2dec(table_buf[0]) * 100 + bcd2dec(table_buf[3]); if (table_buf[2] | table_buf[5]) imgdata.lens.makernotes.MaxFocal = bcd2dec(table_buf[2]) * 100 + bcd2dec(table_buf[5]); if (table_buf[4]) imgdata.lens.makernotes.MaxAp4MinFocal = bcd2dec(table_buf[4]) / 10.0f; if (table_buf[4]) imgdata.lens.makernotes.MaxAp4MaxFocal = bcd2dec(table_buf[7]) / 10.0f; parseSonyLensFeatures(table_buf[1], table_buf[6]); break; default: // CameraInfo2 & 3 if (table_buf[1] | table_buf[2]) imgdata.lens.makernotes.MinFocal = bcd2dec(table_buf[1]) * 100 + bcd2dec(table_buf[2]); if (table_buf[3] | table_buf[4]) imgdata.lens.makernotes.MaxFocal = bcd2dec(table_buf[3]) * 100 + bcd2dec(table_buf[4]); if (table_buf[5]) imgdata.lens.makernotes.MaxAp4MinFocal = bcd2dec(table_buf[5]) / 10.0f; if (table_buf[6]) imgdata.lens.makernotes.MaxAp4MaxFocal = bcd2dec(table_buf[6]) / 10.0f; parseSonyLensFeatures(table_buf[0], table_buf[7]); } } free(table_buf); } else if ((tag == 0x0020) && // WBInfoA100, needs 0xb028 processing !strncasecmp(model, "DSLR-A100", 9)) { fseek(ifp,0x49dc,SEEK_CUR); stmread(imgdata.shootinginfo.InternalBodySerial, 12, ifp); } else if (tag == 0x0104) { imgdata.other.FlashEC = getreal(type); } else if (tag == 0x0105) // Teleconverter { imgdata.lens.makernotes.TeleconverterID = get2(); } else if (tag == 0x0114 && len < 256000) // CameraSettings { table_buf = (uchar*)malloc(len); fread(table_buf, len, 1, ifp); switch (len) { case 280: case 364: case 332: // CameraSettings and CameraSettings2 are big endian if (table_buf[2] | table_buf[3]) { lid = (((ushort)table_buf[2])<<8) | ((ushort)table_buf[3]); imgdata.lens.makernotes.CurAp = libraw_powf64(2.0f, ((float)lid/8.0f-1.0f)/2.0f); } break; case 1536: case 2048: // CameraSettings3 are little endian parseSonyLensType2(table_buf[1016], table_buf[1015]); if (imgdata.lens.makernotes.LensMount != LIBRAW_MOUNT_Canon_EF) { switch (table_buf[153]) { case 16: imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Minolta_A; break; case 17: imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Sony_E; break; } } break; } free(table_buf); } else if (tag == 0x9050 && len < 256000) // little endian { table_buf_0x9050 = (uchar*)malloc(len); table_buf_0x9050_present = 1; fread(table_buf_0x9050, len, 1, ifp); if (imgdata.lens.makernotes.CamID) { process_Sony_0x9050(table_buf_0x9050, imgdata.lens.makernotes.CamID); free (table_buf_0x9050); table_buf_0x9050_present = 0; } } else if (tag == 0x940c && len <256000) { table_buf_0x940c = (uchar*)malloc(len); table_buf_0x940c_present = 1; fread(table_buf_0x940c, len, 1, ifp); if ((imgdata.lens.makernotes.CamID) && (imgdata.lens.makernotes.CameraMount == LIBRAW_MOUNT_Sony_E)) { process_Sony_0x940c(table_buf_0x940c); free(table_buf_0x940c); table_buf_0x940c_present = 0; } } else if (((tag == 0xb027) || (tag == 0x010c)) && (imgdata.lens.makernotes.LensID == -1)) { imgdata.lens.makernotes.LensID = get4(); if ((imgdata.lens.makernotes.LensID > 0x4900) && (imgdata.lens.makernotes.LensID <= 0x5900)) { imgdata.lens.makernotes.AdapterID = 0x4900; imgdata.lens.makernotes.LensID -= imgdata.lens.makernotes.AdapterID; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Sigma_X3F; strcpy(imgdata.lens.makernotes.Adapter, "MC-11"); } else if ((imgdata.lens.makernotes.LensID > 0xEF00) && (imgdata.lens.makernotes.LensID < 0xFFFF) && (imgdata.lens.makernotes.LensID != 0xFF00)) { imgdata.lens.makernotes.AdapterID = 0xEF00; imgdata.lens.makernotes.LensID -= imgdata.lens.makernotes.AdapterID; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Canon_EF; } if (tag == 0x010c) imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Minolta_A; } else if (tag == 0xb02a && len < 256000) // Sony LensSpec { table_buf = (uchar*)malloc(len); fread(table_buf, len, 1, ifp); if (table_buf[1] | table_buf[2]) imgdata.lens.makernotes.MinFocal = bcd2dec(table_buf[1]) * 100 + bcd2dec(table_buf[2]); if (table_buf[3] | table_buf[4]) imgdata.lens.makernotes.MaxFocal = bcd2dec(table_buf[3]) * 100 + bcd2dec(table_buf[4]); if (table_buf[5]) imgdata.lens.makernotes.MaxAp4MinFocal = bcd2dec(table_buf[5]) / 10.0f; if (table_buf[6]) imgdata.lens.makernotes.MaxAp4MaxFocal = bcd2dec(table_buf[6]) / 10.0f; parseSonyLensFeatures(table_buf[0], table_buf[7]); free(table_buf); } } fseek(ifp,_pos,SEEK_SET); #endif if (tag == 2 && strstr(make,"NIKON") && !iso_speed) iso_speed = (get2(),get2()); if (tag == 37 && strstr(make,"NIKON") && (!iso_speed || iso_speed == 65535)) { unsigned char cc; fread(&cc,1,1,ifp); iso_speed = int(100.0 * libraw_powf64(2.0f,float(cc)/12.0-5.0)); } if (tag == 4 && len > 26 && len < 35) { if ((i=(get4(),get2())) != 0x7fff && (!iso_speed || iso_speed == 65535)) iso_speed = 50 * libraw_powf64(2.0, i/32.0 - 4); #ifdef LIBRAW_LIBRARY_BUILD get4(); #else if ((i=(get2(),get2())) != 0x7fff && !aperture) aperture = libraw_powf64(2.0, i/64.0); #endif if ((i=get2()) != 0xffff && !shutter) shutter = libraw_powf64(2.0, (short) i/-32.0); wbi = (get2(),get2()); shot_order = (get2(),get2()); } if ((tag == 4 || tag == 0x114) && !strncmp(make,"KONICA",6)) { fseek (ifp, tag == 4 ? 140:160, SEEK_CUR); switch (get2()) { case 72: flip = 0; break; case 76: flip = 6; break; case 82: flip = 5; break; } } if (tag == 7 && type == 2 && len > 20) fgets (model2, 64, ifp); if (tag == 8 && type == 4) shot_order = get4(); if (tag == 9 && !strncmp(make,"Canon",5)) fread (artist, 64, 1, ifp); if (tag == 0xc && len == 4) FORC3 cam_mul[(c << 1 | c >> 1) & 3] = getreal(type); if (tag == 0xd && type == 7 && get2() == 0xaaaa) { for (c=i=2; (ushort) c != 0xbbbb && i < len; i++) c = c << 8 | fgetc(ifp); while ((i+=4) < len-5) if (get4() == 257 && (i=len) && (c = (get4(),fgetc(ifp))) < 3) flip = "065"[c]-'0'; } #ifndef LIBRAW_LIBRARY_BUILD if (tag == 0x10 && type == 4) unique_id = get4(); #endif #ifdef LIBRAW_LIBRARY_BUILD INT64 _pos2 = ftell(ifp); if (!strncasecmp(make,"Olympus",7)) { short nWB, tWB; if ((tag == 0x20300108) || (tag == 0x20310109)) imgdata.makernotes.olympus.ColorSpace = get2(); if ((tag == 0x20400102) && (len == 2) && (!strncasecmp(model, "E-410", 5) || !strncasecmp(model, "E-510", 5))) { int i; for (i=0; i<64; i++) imgdata.color.WBCT_Coeffs[i][2] = imgdata.color.WBCT_Coeffs[i][4] = imgdata.color.WB_Coeffs[i][1] = imgdata.color.WB_Coeffs[i][3] = 0x100; for (i=64; i<256; i++) imgdata.color.WB_Coeffs[i][1] = imgdata.color.WB_Coeffs[i][3] = 0x100; } if ((tag >= 0x20400102) && (tag <= 0x2040010d)) { ushort CT; nWB = tag-0x20400102; switch (nWB) { case 0 : CT = 3000; tWB = LIBRAW_WBI_Tungsten; break; case 1 : CT = 3300; tWB = 0x100; break; case 2 : CT = 3600; tWB = 0x100; break; case 3 : CT = 3900; tWB = 0x100; break; case 4 : CT = 4000; tWB = LIBRAW_WBI_FL_W; break; case 5 : CT = 4300; tWB = 0x100; break; case 6 : CT = 4500; tWB = LIBRAW_WBI_FL_D; break; case 7 : CT = 4800; tWB = 0x100; break; case 8 : CT = 5300; tWB = LIBRAW_WBI_FineWeather; break; case 9 : CT = 6000; tWB = LIBRAW_WBI_Cloudy; break; case 10: CT = 6600; tWB = LIBRAW_WBI_FL_N; break; case 11: CT = 7500; tWB = LIBRAW_WBI_Shade; break; default: CT = 0; tWB = 0x100; } if (CT) { imgdata.color.WBCT_Coeffs[nWB][0] = CT; imgdata.color.WBCT_Coeffs[nWB][1] = get2(); imgdata.color.WBCT_Coeffs[nWB][3] = get2(); if (len == 4) { imgdata.color.WBCT_Coeffs[nWB][2] = get2(); imgdata.color.WBCT_Coeffs[nWB][4] = get2(); } } if (tWB != 0x100) FORC4 imgdata.color.WB_Coeffs[tWB][c] = imgdata.color.WBCT_Coeffs[nWB][c+1]; } if ((tag >= 0x20400113) && (tag <= 0x2040011e)) { nWB = tag-0x20400113; imgdata.color.WBCT_Coeffs[nWB][2] = imgdata.color.WBCT_Coeffs[nWB][4] = get2(); switch (nWB) { case 0: tWB = LIBRAW_WBI_Tungsten; break; case 4: tWB = LIBRAW_WBI_FL_W; break; case 6: tWB = LIBRAW_WBI_FL_D; break; case 8: tWB = LIBRAW_WBI_FineWeather; break; case 9: tWB = LIBRAW_WBI_Cloudy; break; case 10: tWB = LIBRAW_WBI_FL_N; break; case 11: tWB = LIBRAW_WBI_Shade; break; default: tWB = 0x100; } if (tWB != 0x100) imgdata.color.WB_Coeffs[tWB][1] = imgdata.color.WB_Coeffs[tWB][3] = imgdata.color.WBCT_Coeffs[nWB][2]; } if (tag == 0x20400121) { imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][2] = get2(); if (len == 4) { imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][1] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][3] = get2(); } } if (tag == 0x2040011f) { imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][3] = get2(); } if (tag == 0x30000120) { imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][2] = get2(); if (len == 2) { for (int i=0; i<256; i++) imgdata.color.WB_Coeffs[i][1] = imgdata.color.WB_Coeffs[i][3] = 0x100; } } if (tag == 0x30000121) { imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][2] = get2(); } if (tag == 0x30000122) { imgdata.color.WB_Coeffs[LIBRAW_WBI_FineWeather][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_FineWeather][2] = get2(); } if (tag == 0x30000123) { imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][2] = get2(); } if (tag == 0x30000124) { imgdata.color.WB_Coeffs[LIBRAW_WBI_Sunset][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Sunset][2] = get2(); } if (tag == 0x30000130) { imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][2] = get2(); } if (tag == 0x30000131) { imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][2] = get2(); } if (tag == 0x30000132) { imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][2] = get2(); } if (tag == 0x30000133) { imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_WW][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_WW][2] = get2(); } if((tag == 0x20400805) && (len == 2)) { imgdata.makernotes.olympus.OlympusSensorCalibration[0]=getreal(type); imgdata.makernotes.olympus.OlympusSensorCalibration[1]=getreal(type); FORC4 imgdata.color.linear_max[c] = imgdata.makernotes.olympus.OlympusSensorCalibration[0]; } if (tag == 0x20200401) { imgdata.other.FlashEC = getreal(type); } } fseek(ifp,_pos2,SEEK_SET); #endif if (tag == 0x11 && is_raw && !strncmp(make,"NIKON",5)) { fseek (ifp, get4()+base, SEEK_SET); parse_tiff_ifd (base); } if (tag == 0x14 && type == 7) { if (len == 2560) { fseek (ifp, 1248, SEEK_CUR); goto get2_256; } fread (buf, 1, 10, ifp); if (!strncmp(buf,"NRW ",4)) { fseek (ifp, strcmp(buf+4,"0100") ? 46:1546, SEEK_CUR); cam_mul[0] = get4() << 2; cam_mul[1] = get4() + get4(); cam_mul[2] = get4() << 2; } } if (tag == 0x15 && type == 2 && is_raw) fread (model, 64, 1, ifp); if (strstr(make,"PENTAX")) { if (tag == 0x1b) tag = 0x1018; if (tag == 0x1c) tag = 0x1017; } if (tag == 0x1d) { while ((c = fgetc(ifp)) && c != EOF) #ifdef LIBRAW_LIBRARY_BUILD { if ((!custom_serial) && (!isdigit(c))) { if ((strbuflen(model) == 3) && (!strcmp(model,"D50"))) { custom_serial = 34; } else { custom_serial = 96; } } #endif serial = serial*10 + (isdigit(c) ? c - '0' : c % 10); #ifdef LIBRAW_LIBRARY_BUILD } if (!imgdata.shootinginfo.BodySerial[0]) sprintf(imgdata.shootinginfo.BodySerial, "%d", serial); #endif } if (tag == 0x29 && type == 1) { // Canon PowerShot G9 c = wbi < 18 ? "012347800000005896"[wbi]-'0' : 0; fseek (ifp, 8 + c*32, SEEK_CUR); FORC4 cam_mul[c ^ (c >> 1) ^ 1] = get4(); } #ifndef LIBRAW_LIBRARY_BUILD if (tag == 0x3d && type == 3 && len == 4) FORC4 cblack[c ^ c >> 1] = get2() >> (14-tiff_bps); #endif if (tag == 0x81 && type == 4) { data_offset = get4(); fseek (ifp, data_offset + 41, SEEK_SET); raw_height = get2() * 2; raw_width = get2(); filters = 0x61616161; } if ((tag == 0x81 && type == 7) || (tag == 0x100 && type == 7) || (tag == 0x280 && type == 1)) { thumb_offset = ftell(ifp); thumb_length = len; } if (tag == 0x88 && type == 4 && (thumb_offset = get4())) thumb_offset += base; if (tag == 0x89 && type == 4) thumb_length = get4(); if (tag == 0x8c || tag == 0x96) meta_offset = ftell(ifp); if (tag == 0x97) { for (i=0; i < 4; i++) ver97 = ver97 * 10 + fgetc(ifp)-'0'; switch (ver97) { case 100: fseek (ifp, 68, SEEK_CUR); FORC4 cam_mul[(c >> 1) | ((c & 1) << 1)] = get2(); break; case 102: fseek (ifp, 6, SEEK_CUR); FORC4 cam_mul[c ^ (c >> 1)] = get2(); break; case 103: fseek (ifp, 16, SEEK_CUR); FORC4 cam_mul[c] = get2(); } if (ver97 >= 200) { if (ver97 != 205) fseek (ifp, 280, SEEK_CUR); fread (buf97, 324, 1, ifp); } } if (tag == 0xa1 && type == 7) { order = 0x4949; fseek (ifp, 140, SEEK_CUR); FORC3 cam_mul[c] = get4(); } if (tag == 0xa4 && type == 3) { fseek (ifp, wbi*48, SEEK_CUR); FORC3 cam_mul[c] = get2(); } if (tag == 0xa7) { // shutter count NikonKey = fgetc(ifp)^fgetc(ifp)^fgetc(ifp)^fgetc(ifp); if ( (unsigned) (ver97-200) < 17) { ci = xlat[0][serial & 0xff]; cj = xlat[1][NikonKey]; ck = 0x60; for (i=0; i < 324; i++) buf97[i] ^= (cj += ci * ck++); i = "66666>666;6A;:;55"[ver97-200] - '0'; FORC4 cam_mul[c ^ (c >> 1) ^ (i & 1)] = sget2 (buf97 + (i & -2) + c*2); } #ifdef LIBRAW_LIBRARY_BUILD if ((NikonLensDataVersion > 200) && lenNikonLensData) { if (custom_serial) { ci = xlat[0][custom_serial]; } else { ci = xlat[0][serial & 0xff]; } cj = xlat[1][NikonKey]; ck = 0x60; for (i = 0; i < lenNikonLensData; i++) table_buf[i] ^= (cj += ci * ck++); processNikonLensData(table_buf, lenNikonLensData); lenNikonLensData = 0; free(table_buf); } if (ver97 == 601) // Coolpix A { imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens; imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens; } #endif } if(tag == 0xb001 && type == 3) // Sony ModelID { unique_id = get2(); } if (tag == 0x200 && len == 3) shot_order = (get4(),get4()); if (tag == 0x200 && len == 4) FORC4 cblack[c ^ c >> 1] = get2(); if (tag == 0x201 && len == 4) FORC4 cam_mul[c ^ (c >> 1)] = get2(); if (tag == 0x220 && type == 7) meta_offset = ftell(ifp); if (tag == 0x401 && type == 4 && len == 4) FORC4 cblack[c ^ c >> 1] = get4(); #ifdef LIBRAW_LIBRARY_BUILD // not corrected for file bitcount, to be patched in open_datastream if (tag == 0x03d && strstr(make,"NIKON") && len == 4) { FORC4 cblack[c ^ c >> 1] = get2(); i = cblack[3]; FORC3 if(i>cblack[c]) i = cblack[c]; FORC4 cblack[c]-=i; black += i; } #endif if (tag == 0xe01) { /* Nikon Capture Note */ #ifdef LIBRAW_LIBRARY_BUILD int loopc = 0; #endif order = 0x4949; fseek (ifp, 22, SEEK_CUR); for (offset=22; offset+22 < len; offset += 22+i) { #ifdef LIBRAW_LIBRARY_BUILD if(loopc++>1024) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif tag = get4(); fseek (ifp, 14, SEEK_CUR); i = get4()-4; if (tag == 0x76a43207) flip = get2(); else fseek (ifp, i, SEEK_CUR); } } if (tag == 0xe80 && len == 256 && type == 7) { fseek (ifp, 48, SEEK_CUR); cam_mul[0] = get2() * 508 * 1.078 / 0x10000; cam_mul[2] = get2() * 382 * 1.173 / 0x10000; } if (tag == 0xf00 && type == 7) { if (len == 614) fseek (ifp, 176, SEEK_CUR); else if (len == 734 || len == 1502) fseek (ifp, 148, SEEK_CUR); else goto next; goto get2_256; } if ((tag == 0x1011 && len == 9) || tag == 0x20400200) for (i=0; i < 3; i++) { #ifdef LIBRAW_LIBRARY_BUILD if (!imgdata.makernotes.olympus.ColorSpace) { FORC3 cmatrix[i][c] = ((short) get2()) / 256.0; } else { FORC3 imgdata.color.ccm[i][c] = ((short) get2()) / 256.0; } #else FORC3 cmatrix[i][c] = ((short) get2()) / 256.0; #endif } if ((tag == 0x1012 || tag == 0x20400600) && len == 4) FORC4 cblack[c ^ c >> 1] = get2(); if (tag == 0x1017 || tag == 0x20400100) cam_mul[0] = get2() / 256.0; if (tag == 0x1018 || tag == 0x20400100) cam_mul[2] = get2() / 256.0; if (tag == 0x2011 && len == 2) { get2_256: order = 0x4d4d; cam_mul[0] = get2() / 256.0; cam_mul[2] = get2() / 256.0; } if ((tag | 0x70) == 0x2070 && (type == 4 || type == 13)) fseek (ifp, get4()+base, SEEK_SET); #ifdef LIBRAW_LIBRARY_BUILD // IB start if (tag == 0x2010) { INT64 _pos3 = ftell(ifp); parse_makernote(base, 0x2010); fseek(ifp,_pos3,SEEK_SET); } if ( ((tag == 0x2020) || (tag == 0x3000) || (tag == 0x2030) || (tag == 0x2031)) && ((type == 7) || (type == 13)) && !strncasecmp(make,"Olympus",7) ) { INT64 _pos3 = ftell(ifp); parse_makernote(base, tag); fseek(ifp,_pos3,SEEK_SET); } // IB end #endif if ((tag == 0x2020) && ((type == 7) || (type == 13)) && !strncmp(buf,"OLYMP",5)) parse_thumb_note (base, 257, 258); if (tag == 0x2040) parse_makernote (base, 0x2040); if (tag == 0xb028) { fseek (ifp, get4()+base, SEEK_SET); parse_thumb_note (base, 136, 137); } if (tag == 0x4001 && len > 500 && len < 100000) { i = len == 582 ? 50 : len == 653 ? 68 : len == 5120 ? 142 : 126; fseek (ifp, i, SEEK_CUR); FORC4 cam_mul[c ^ (c >> 1)] = get2(); for (i+=18; i <= len; i+=10) { get2(); FORC4 sraw_mul[c ^ (c >> 1)] = get2(); if (sraw_mul[1] == 1170) break; } } if(!strncasecmp(make,"Samsung",7)) { if (tag == 0xa020) // get the full Samsung encryption key for (i=0; i<11; i++) SamsungKey[i] = get4(); if (tag == 0xa021) // get and decode Samsung cam_mul array FORC4 cam_mul[c ^ (c >> 1)] = get4() - SamsungKey[c]; #ifdef LIBRAW_LIBRARY_BUILD if (tag == 0xa023) { imgdata.color.WB_Coeffs[LIBRAW_WBI_Ill_A][0] = get4() - SamsungKey[8]; imgdata.color.WB_Coeffs[LIBRAW_WBI_Ill_A][1] = get4() - SamsungKey[9]; imgdata.color.WB_Coeffs[LIBRAW_WBI_Ill_A][3] = get4() - SamsungKey[10]; imgdata.color.WB_Coeffs[LIBRAW_WBI_Ill_A][2] = get4() - SamsungKey[0]; if (imgdata.color.WB_Coeffs[LIBRAW_WBI_Ill_A][0] < (imgdata.color.WB_Coeffs[LIBRAW_WBI_Ill_A][1]>>1)) { imgdata.color.WB_Coeffs[LIBRAW_WBI_Ill_A][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Ill_A][1] >> 4; imgdata.color.WB_Coeffs[LIBRAW_WBI_Ill_A][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Ill_A][3] >> 4; } } if (tag == 0xa024) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_D65][c ^ (c >> 1)] = get4() - SamsungKey[c+1]; if (imgdata.color.WB_Coeffs[LIBRAW_WBI_D65][0] < (imgdata.color.WB_Coeffs[LIBRAW_WBI_D65][1]>>1)) { imgdata.color.WB_Coeffs[LIBRAW_WBI_D65][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_D65][1] >> 4; imgdata.color.WB_Coeffs[LIBRAW_WBI_D65][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_D65][3] >> 4; } } if (tag == 0xa025) imgdata.color.linear_max[0]= imgdata.color.linear_max[1]= imgdata.color.linear_max[2]= imgdata.color.linear_max[3]= get4() - SamsungKey[0]; if (tag == 0xa030 && len == 9) for (i=0; i < 3; i++) FORC3 imgdata.color.ccm[i][c] = (float)((short)((get4() + SamsungKey[i*3+c])))/256.0; #endif if (tag == 0xa031 && len == 9) // get and decode Samsung color matrix for (i=0; i < 3; i++) FORC3 cmatrix[i][c] = (float)((short)((get4() + SamsungKey[i*3+c])))/256.0; if (tag == 0xa028) FORC4 cblack[c ^ (c >> 1)] = get4() - SamsungKey[c]; } else { // Somebody else use 0xa021 and 0xa028? if (tag == 0xa021) FORC4 cam_mul[c ^ (c >> 1)] = get4(); if (tag == 0xa028) FORC4 cam_mul[c ^ (c >> 1)] -= get4(); } if (tag == 0x4021 && get4() && get4()) FORC4 cam_mul[c] = 1024; next: fseek (ifp, save, SEEK_SET); } quit: order = sorder; } /* Since the TIFF DateTime string has no timezone information, assume that the camera's clock was set to Universal Time. */ void CLASS get_timestamp (int reversed) { struct tm t; char str[20]; int i; str[19] = 0; if (reversed) for (i=19; i--; ) str[i] = fgetc(ifp); else fread (str, 19, 1, ifp); memset (&t, 0, sizeof t); if (sscanf (str, "%d:%d:%d %d:%d:%d", &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec) != 6) return; t.tm_year -= 1900; t.tm_mon -= 1; t.tm_isdst = -1; if (mktime(&t) > 0) timestamp = mktime(&t); } void CLASS parse_exif (int base) { unsigned kodak, entries, tag, type, len, save, c; double expo,ape; kodak = !strncmp(make,"EASTMAN",7) && tiff_nifds < 3; entries = get2(); if(!strncmp(make,"Hasselblad",10) && (tiff_nifds > 3) && (entries > 512)) return; #ifdef LIBRAW_LIBRARY_BUILD INT64 fsize = ifp->size(); #endif while (entries--) { tiff_get (base, &tag, &type, &len, &save); #ifdef LIBRAW_LIBRARY_BUILD INT64 savepos = ftell(ifp); if(len > 8 && savepos + len > fsize*2) continue; if(callbacks.exif_cb) { callbacks.exif_cb(callbacks.exifparser_data,tag,type,len,order,ifp); fseek(ifp,savepos,SEEK_SET); } #endif switch (tag) { #ifdef LIBRAW_LIBRARY_BUILD case 0xa405: // FocalLengthIn35mmFormat imgdata.lens.FocalLengthIn35mmFormat = get2(); break; case 0xa431: // BodySerialNumber stmread(imgdata.shootinginfo.BodySerial, len, ifp); break; case 0xa432: // LensInfo, 42034dec, Lens Specification per EXIF standard imgdata.lens.MinFocal = getreal(type); imgdata.lens.MaxFocal = getreal(type); imgdata.lens.MaxAp4MinFocal = getreal(type); imgdata.lens.MaxAp4MaxFocal = getreal(type); break; case 0xa435: // LensSerialNumber stmread(imgdata.lens.LensSerial, len, ifp); break; case 0xc630: // DNG LensInfo, Lens Specification per EXIF standard imgdata.lens.dng.MinFocal = getreal(type); imgdata.lens.dng.MaxFocal = getreal(type); imgdata.lens.dng.MaxAp4MinFocal = getreal(type); imgdata.lens.dng.MaxAp4MaxFocal = getreal(type); break; case 0xa433: // LensMake stmread(imgdata.lens.LensMake, len, ifp); break; case 0xa434: // LensModel stmread(imgdata.lens.Lens, len, ifp); if (!strncmp(imgdata.lens.Lens, "----", 4)) imgdata.lens.Lens[0] = 0; break; case 0x9205: imgdata.lens.EXIF_MaxAp = libraw_powf64(2.0f, (getreal(type) / 2.0f)); break; #endif case 33434: tiff_ifd[tiff_nifds-1].t_shutter = shutter = getreal(type); break; case 33437: aperture = getreal(type); break; // 0x829d FNumber case 34855: iso_speed = get2(); break; case 34866: if (iso_speed == 0xffff && (!strncasecmp(make, "SONY",4) || !strncasecmp(make, "CANON",5))) iso_speed = getreal(type); break; case 36867: case 36868: get_timestamp(0); break; case 37377: if ((expo = -getreal(type)) < 128 && shutter == 0.) tiff_ifd[tiff_nifds-1].t_shutter = shutter = libraw_powf64(2.0, expo); break; case 37378: // 0x9202 ApertureValue if ((fabs(ape = getreal(type))<256.0) && (!aperture)) aperture = libraw_powf64(2.0, ape/2); break; case 37385: flash_used = getreal(type); break; case 37386: focal_len = getreal(type); break; case 37500: // tag 0x927c #ifdef LIBRAW_LIBRARY_BUILD if (((make[0] == '\0') && (!strncmp(model, "ov5647",6))) || ((!strncmp(make, "RaspberryPi",11)) && (!strncmp(model, "RP_OV5647",9))) || ((!strncmp(make, "RaspberryPi",11)) && (!strncmp(model, "RP_imx219",9)))) { char mn_text[512]; char* pos; char ccms[512]; ushort l; float num; fgets(mn_text, len, ifp); pos = strstr(mn_text, "gain_r="); if (pos) cam_mul[0] = atof(pos+7); pos = strstr(mn_text, "gain_b="); if (pos) cam_mul[2] = atof(pos+7); if ((cam_mul[0] > 0.001f) && (cam_mul[2] > 0.001f)) cam_mul[1] = cam_mul[3] = 1.0f; else cam_mul[0] = cam_mul[2] = 0.0f; pos = strstr(mn_text, "ccm=") + 4; l = strstr(pos, " ") - pos; memcpy (ccms, pos, l); ccms[l] = '\0'; pos = strtok (ccms, ","); for (l=0; l<4; l++) { num = 0.0; for (c=0; c<3; c++) { imgdata.color.ccm[l][c] = (float)atoi(pos); num += imgdata.color.ccm[l][c]; pos = strtok (NULL, ","); } if (num > 0.01) FORC3 imgdata.color.ccm[l][c] = imgdata.color.ccm[l][c] / num; } } else #endif parse_makernote (base, 0); break; case 40962: if (kodak) raw_width = get4(); break; case 40963: if (kodak) raw_height = get4(); break; case 41730: if (get4() == 0x20002) for (exif_cfa=c=0; c < 8; c+=2) exif_cfa |= fgetc(ifp) * 0x01010101 << c; } fseek (ifp, save, SEEK_SET); } } #ifdef LIBRAW_LIBRARY_BUILD void CLASS parse_gps_libraw(int base) { unsigned entries, tag, type, len, save, c; entries = get2(); if (entries > 200) return; if (entries > 0) imgdata.other.parsed_gps.gpsparsed = 1; while (entries--) { tiff_get(base, &tag, &type, &len, &save); if(len > 1024) continue; // no GPS tags are 1k or larger switch (tag) { case 1: imgdata.other.parsed_gps.latref = getc(ifp); break; case 3: imgdata.other.parsed_gps.longref = getc(ifp); break; case 5: imgdata.other.parsed_gps.altref = getc(ifp); break; case 2: if (len == 3) FORC(3) imgdata.other.parsed_gps.latitude[c] = getreal(type); break; case 4: if (len == 3) FORC(3) imgdata.other.parsed_gps.longtitude[c] = getreal(type); break; case 7: if (len == 3) FORC(3) imgdata.other.parsed_gps.gpstimestamp[c] = getreal(type); break; case 6: imgdata.other.parsed_gps.altitude = getreal(type); break; case 9: imgdata.other.parsed_gps.gpsstatus = getc(ifp); break; } fseek(ifp, save, SEEK_SET); } } #endif void CLASS parse_gps (int base) { unsigned entries, tag, type, len, save, c; entries = get2(); while (entries--) { tiff_get (base, &tag, &type, &len, &save); if(len > 1024) continue; // no GPS tags are 1k or larger switch (tag) { case 1: case 3: case 5: gpsdata[29+tag/2] = getc(ifp); break; case 2: case 4: case 7: FORC(6) gpsdata[tag/3*6+c] = get4(); break; case 6: FORC(2) gpsdata[18+c] = get4(); break; case 18: case 29: fgets ((char *) (gpsdata+14+tag/3), MIN(len,12), ifp); } fseek (ifp, save, SEEK_SET); } } void CLASS romm_coeff (float romm_cam[3][3]) { static const float rgb_romm[3][3] = /* ROMM == Kodak ProPhoto */ { { 2.034193, -0.727420, -0.306766 }, { -0.228811, 1.231729, -0.002922 }, { -0.008565, -0.153273, 1.161839 } }; int i, j, k; for (i=0; i < 3; i++) for (j=0; j < 3; j++) for (cmatrix[i][j] = k=0; k < 3; k++) cmatrix[i][j] += rgb_romm[i][k] * romm_cam[k][j]; } void CLASS parse_mos (int offset) { char data[40]; int skip, from, i, c, neut[4], planes=0, frot=0; static const char *mod[] = { "","DCB2","Volare","Cantare","CMost","Valeo 6","Valeo 11","Valeo 22", "Valeo 11p","Valeo 17","","Aptus 17","Aptus 22","Aptus 75","Aptus 65", "Aptus 54S","Aptus 65S","Aptus 75S","AFi 5","AFi 6","AFi 7", "AFi-II 7","Aptus-II 7","","Aptus-II 6","","","Aptus-II 10","Aptus-II 5", "","","","","Aptus-II 10R","Aptus-II 8","","Aptus-II 12","","AFi-II 12" }; float romm_cam[3][3]; fseek (ifp, offset, SEEK_SET); while (1) { if (get4() != 0x504b5453) break; get4(); fread (data, 1, 40, ifp); skip = get4(); from = ftell(ifp); // IB start #ifdef LIBRAW_LIBRARY_BUILD if (!strcmp(data,"CameraObj_camera_type")) { stmread(imgdata.lens.makernotes.body, skip, ifp); } if (!strcmp(data,"back_serial_number")) { char buffer [sizeof(imgdata.shootinginfo.BodySerial)]; char *words[4]; int nwords; stmread(buffer, skip, ifp); nwords = getwords(buffer, words, 4,sizeof(imgdata.shootinginfo.BodySerial)); strcpy (imgdata.shootinginfo.BodySerial, words[0]); } if (!strcmp(data,"CaptProf_serial_number")) { char buffer [sizeof(imgdata.shootinginfo.InternalBodySerial)]; char *words[4]; int nwords; stmread(buffer, skip, ifp); nwords = getwords(buffer, words, 4,sizeof(imgdata.shootinginfo.InternalBodySerial)); strcpy (imgdata.shootinginfo.InternalBodySerial, words[0]); } #endif // IB end if (!strcmp(data,"JPEG_preview_data")) { thumb_offset = from; thumb_length = skip; } if (!strcmp(data,"icc_camera_profile")) { profile_offset = from; profile_length = skip; } if (!strcmp(data,"ShootObj_back_type")) { fscanf (ifp, "%d", &i); if ((unsigned) i < sizeof mod / sizeof (*mod)) strcpy (model, mod[i]); } if (!strcmp(data,"icc_camera_to_tone_matrix")) { for (i=0; i < 9; i++) ((float *)romm_cam)[i] = int_to_float(get4()); romm_coeff (romm_cam); } if (!strcmp(data,"CaptProf_color_matrix")) { for (i=0; i < 9; i++) fscanf (ifp, "%f", (float *)romm_cam + i); romm_coeff (romm_cam); } if (!strcmp(data,"CaptProf_number_of_planes")) fscanf (ifp, "%d", &planes); if (!strcmp(data,"CaptProf_raw_data_rotation")) fscanf (ifp, "%d", &flip); if (!strcmp(data,"CaptProf_mosaic_pattern")) FORC4 { fscanf (ifp, "%d", &i); if (i == 1) frot = c ^ (c >> 1); } if (!strcmp(data,"ImgProf_rotation_angle")) { fscanf (ifp, "%d", &i); flip = i - flip; } if (!strcmp(data,"NeutObj_neutrals") && !cam_mul[0]) { FORC4 fscanf (ifp, "%d", neut+c); FORC3 cam_mul[c] = (float) neut[0] / neut[c+1]; } if (!strcmp(data,"Rows_data")) load_flags = get4(); parse_mos (from); fseek (ifp, skip+from, SEEK_SET); } if (planes) filters = (planes == 1) * 0x01010101 * (uchar) "\x94\x61\x16\x49"[(flip/90 + frot) & 3]; } void CLASS linear_table (unsigned len) { int i; if (len > 0x10000) len = 0x10000; read_shorts (curve, len); for (i=len; i < 0x10000; i++) curve[i] = curve[i-1]; maximum = curve[len<0x1000?0xfff:len-1]; } #ifdef LIBRAW_LIBRARY_BUILD void CLASS Kodak_WB_0x08tags (int wb, unsigned type) { float mul[3]={1,1,1}, num, mul2; int c; FORC3 mul[c] = (num=getreal(type))==0 ? 1 : num; imgdata.color.WB_Coeffs[wb][1] = imgdata.color.WB_Coeffs[wb][3] = mul[1]; mul2 = mul[1] * mul[1]; imgdata.color.WB_Coeffs[wb][0] = mul2 / mul[0]; imgdata.color.WB_Coeffs[wb][2] = mul2 / mul[2]; return; } /* Thanks to Alexey Danilchenko for wb as-shot parsing code */ void CLASS parse_kodak_ifd (int base) { unsigned entries, tag, type, len, save; int i, c, wbi=-2; float mul[3]={1,1,1}, num; static const int wbtag[] = { 64037,64040,64039,64041,-1,-1,64042 }; entries = get2(); if (entries > 1024) return; INT64 fsize = ifp->size(); while (entries--) { tiff_get (base, &tag, &type, &len, &save); INT64 savepos = ftell(ifp); if(len > 8 && len + savepos > 2*fsize) continue; if(callbacks.exif_cb) { callbacks.exif_cb(callbacks.exifparser_data,tag | 0x20000,type,len,order,ifp); fseek(ifp,savepos,SEEK_SET); } if (tag == 1011) imgdata.other.FlashEC = getreal(type); if (tag == 1020) wbi = getint(type); if (tag == 1021 && len == 72) { /* WB set in software */ fseek (ifp, 40, SEEK_CUR); FORC3 cam_mul[c] = 2048.0 / fMAX(1.0f,get2()); wbi = -2; } if (tag == 0x0848) Kodak_WB_0x08tags(LIBRAW_WBI_Daylight, type); if (tag == 0x0849) Kodak_WB_0x08tags(LIBRAW_WBI_Tungsten, type); if (tag == 0x084a) Kodak_WB_0x08tags(LIBRAW_WBI_Fluorescent, type); if (tag == 0x084b) Kodak_WB_0x08tags(LIBRAW_WBI_Flash, type); if (tag == 0x0e93) imgdata.color.linear_max[0] = imgdata.color.linear_max[1] = imgdata.color.linear_max[2] = imgdata.color.linear_max[3] = get2(); if (tag == 0x09ce) stmread(imgdata.shootinginfo.InternalBodySerial,len, ifp); if (tag == 0xfa00) stmread(imgdata.shootinginfo.BodySerial, len, ifp); if (tag == 0xfa27) { FORC3 imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][c] = get4(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][1]; } if (tag == 0xfa28) { FORC3 imgdata.color.WB_Coeffs[LIBRAW_WBI_Fluorescent][c] = get4(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Fluorescent][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Fluorescent][1]; } if (tag == 0xfa29) { FORC3 imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][c] = get4(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][1]; } if (tag == 0xfa2a) { FORC3 imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][c] = get4(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][1]; } if (tag == 2120 + wbi || (wbi<0 && tag == 2125)) /* use Auto WB if illuminant index is not set */ { FORC3 mul[c] = (num=getreal(type))==0 ? 1 : num; FORC3 cam_mul[c] = mul[1] / mul[c]; /* normalise against green */ } if (tag == 2317) linear_table (len); if (tag == 0x903) iso_speed = getreal(type); //if (tag == 6020) iso_speed = getint(type); if (tag == 64013) wbi = fgetc(ifp); if ((unsigned) wbi < 7 && tag == wbtag[wbi]) FORC3 cam_mul[c] = get4(); if (tag == 64019) width = getint(type); if (tag == 64020) height = (getint(type)+1) & -2; fseek (ifp, save, SEEK_SET); } } #else void CLASS parse_kodak_ifd (int base) { unsigned entries, tag, type, len, save; int i, c, wbi=-2, wbtemp=6500; float mul[3]={1,1,1}, num; static const int wbtag[] = { 64037,64040,64039,64041,-1,-1,64042 }; entries = get2(); if (entries > 1024) return; while (entries--) { tiff_get (base, &tag, &type, &len, &save); if (tag == 1020) wbi = getint(type); if (tag == 1021 && len == 72) { /* WB set in software */ fseek (ifp, 40, SEEK_CUR); FORC3 cam_mul[c] = 2048.0 / fMAX(1.0,get2()); wbi = -2; } if (tag == 2118) wbtemp = getint(type); if (tag == 2120 + wbi && wbi >= 0) FORC3 cam_mul[c] = 2048.0 / fMAX(1.0,getreal(type)); if (tag == 2130 + wbi) FORC3 mul[c] = getreal(type); if (tag == 2140 + wbi && wbi >= 0) FORC3 { for (num=i=0; i < 4; i++) num += getreal(type) * pow (wbtemp/100.0, i); cam_mul[c] = 2048 / fMAX(1.0,(num * mul[c])); } if (tag == 2317) linear_table (len); if (tag == 6020) iso_speed = getint(type); if (tag == 64013) wbi = fgetc(ifp); if ((unsigned) wbi < 7 && tag == wbtag[wbi]) FORC3 cam_mul[c] = get4(); if (tag == 64019) width = getint(type); if (tag == 64020) height = (getint(type)+1) & -2; fseek (ifp, save, SEEK_SET); } } #endif int CLASS parse_tiff_ifd (int base) { unsigned entries, tag, type, len, plen=16, save; int ifd, use_cm=0, cfa, i, j, c, ima_len=0; char *cbuf, *cp; uchar cfa_pat[16], cfa_pc[] = { 0,1,2,3 }, tab[256]; double fm[3][4], cc[4][4], cm[4][3], cam_xyz[4][3], num; double ab[]={ 1,1,1,1 }, asn[] = { 0,0,0,0 }, xyz[] = { 1,1,1 }; unsigned sony_curve[] = { 0,0,0,0,0,4095 }; unsigned *buf, sony_offset=0, sony_length=0, sony_key=0; struct jhead jh; int pana_raw = 0; #ifndef LIBRAW_LIBRARY_BUILD FILE *sfp; #endif if (tiff_nifds >= sizeof tiff_ifd / sizeof tiff_ifd[0]) return 1; ifd = tiff_nifds++; for (j=0; j < 4; j++) for (i=0; i < 4; i++) cc[j][i] = i == j; entries = get2(); if (entries > 512) return 1; #ifdef LIBRAW_LIBRARY_BUILD INT64 fsize = ifp->size(); #endif while (entries--) { tiff_get (base, &tag, &type, &len, &save); #ifdef LIBRAW_LIBRARY_BUILD INT64 savepos = ftell(ifp); if(len > 8 && len + savepos > fsize*2) continue; // skip tag pointing out of 2xfile if(callbacks.exif_cb) { callbacks.exif_cb(callbacks.exifparser_data,tag|(pana_raw?0x30000:0),type,len,order,ifp); fseek(ifp,savepos,SEEK_SET); } #endif #ifdef LIBRAW_LIBRARY_BUILD if (!strncasecmp(make, "SONY", 4) || (!strncasecmp(make, "Hasselblad", 10) && (!strncasecmp(model, "Stellar", 7) || !strncasecmp(model, "Lunar", 5) || !strncasecmp(model, "HV",2)))) { switch (tag) { case 0x7300: // SR2 black level for (int i = 0; i < 4 && i < len; i++) cblack[i] = get2(); break; case 0x7480: case 0x7820: FORC3 imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][c] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][1]; break; case 0x7481: case 0x7821: FORC3 imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][c] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][1]; break; case 0x7482: case 0x7822: FORC3 imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][c] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][1]; break; case 0x7483: case 0x7823: FORC3 imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][c] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][1]; break; case 0x7484: case 0x7824: imgdata.color.WBCT_Coeffs[0][0] = 4500; FORC3 imgdata.color.WBCT_Coeffs[0][c+1] = get2(); imgdata.color.WBCT_Coeffs[0][4] = imgdata.color.WBCT_Coeffs[0][2]; break; case 0x7486: FORC3 imgdata.color.WB_Coeffs[LIBRAW_WBI_Fluorescent][c] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Fluorescent][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Fluorescent][1]; break; case 0x7825: FORC3 imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][c] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][1]; break; case 0x7826: FORC3 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][c] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][1]; break; case 0x7827: FORC3 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][c] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][1]; break; case 0x7828: FORC3 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][c] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][1]; break; case 0x7829: FORC3 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_L][c] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_L][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_L][1]; break; case 0x782a: imgdata.color.WBCT_Coeffs[1][0] = 8500; FORC3 imgdata.color.WBCT_Coeffs[1][c+1] = get2(); imgdata.color.WBCT_Coeffs[1][4] = imgdata.color.WBCT_Coeffs[1][2]; break; case 0x782b: imgdata.color.WBCT_Coeffs[2][0] = 6000; FORC3 imgdata.color.WBCT_Coeffs[2][c+1] = get2(); imgdata.color.WBCT_Coeffs[2][4] = imgdata.color.WBCT_Coeffs[2][2]; break; case 0x782c: imgdata.color.WBCT_Coeffs[3][0] = 3200; FORC3 imgdata.color.WB_Coeffs[LIBRAW_WBI_StudioTungsten][c] = imgdata.color.WBCT_Coeffs[3][c+1] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_StudioTungsten][3] = imgdata.color.WBCT_Coeffs[3][4] = imgdata.color.WB_Coeffs[LIBRAW_WBI_StudioTungsten][1]; break; case 0x782d: imgdata.color.WBCT_Coeffs[4][0] = 2500; FORC3 imgdata.color.WBCT_Coeffs[4][c+1] = get2(); imgdata.color.WBCT_Coeffs[4][4] = imgdata.color.WBCT_Coeffs[4][2]; break; case 0x787f: FORC3 imgdata.color.linear_max[c] = get2(); imgdata.color.linear_max[3] = imgdata.color.linear_max[1]; break; } } #endif switch (tag) { case 1: if(len==4) pana_raw = get4(); break; case 5: width = get2(); break; case 6: height = get2(); break; case 7: width += get2(); break; case 9: if ((i = get2())) filters = i; #ifdef LIBRAW_LIBRARY_BUILD if(pana_raw && len == 1 && type ==3) pana_black[3]+=i; #endif break; case 8: case 10: #ifdef LIBRAW_LIBRARY_BUILD if(pana_raw && len == 1 && type ==3) pana_black[3]+=get2(); #endif break; case 14: case 15: case 16: #ifdef LIBRAW_LIBRARY_BUILD if(pana_raw) { imgdata.color.linear_max[tag-14] = get2(); if (tag == 15 ) imgdata.color.linear_max[3] = imgdata.color.linear_max[1]; } #endif break; case 17: case 18: if (type == 3 && len == 1) cam_mul[(tag-17)*2] = get2() / 256.0; break; #ifdef LIBRAW_LIBRARY_BUILD case 19: if(pana_raw) { ushort nWB, cnt, tWB; nWB = get2(); if (nWB > 0x100) break; for (cnt=0; cnt 0x100) break; for (cnt=0; cnt 12) break; load_raw = &CLASS packed_load_raw; load_flags = get4() ? 24:80; break; case 259: /* Compression */ tiff_ifd[ifd].comp = getint(type); break; case 262: /* PhotometricInterpretation */ tiff_ifd[ifd].phint = get2(); break; case 270: /* ImageDescription */ fread (desc, 512, 1, ifp); break; case 271: /* Make */ fgets (make, 64, ifp); break; case 272: /* Model */ fgets (model, 64, ifp); break; #ifdef LIBRAW_LIBRARY_BUILD case 278: tiff_ifd[ifd].rows_per_strip = getint(type); break; #endif case 280: /* Panasonic RW2 offset */ if (type != 4) break; load_raw = &CLASS panasonic_load_raw; load_flags = 0x2008; case 273: /* StripOffset */ #ifdef LIBRAW_LIBRARY_BUILD if(len > 1 && len < 16384) { off_t sav = ftell(ifp); tiff_ifd[ifd].strip_offsets = (int*)calloc(len,sizeof(int)); tiff_ifd[ifd].strip_offsets_count = len; for(int i=0; i< len; i++) tiff_ifd[ifd].strip_offsets[i]=get4()+base; fseek(ifp,sav,SEEK_SET); // restore position } /* fallback */ #endif case 513: /* JpegIFOffset */ case 61447: tiff_ifd[ifd].offset = get4()+base; if (!tiff_ifd[ifd].bps && tiff_ifd[ifd].offset > 0) { fseek (ifp, tiff_ifd[ifd].offset, SEEK_SET); if (ljpeg_start (&jh, 1)) { tiff_ifd[ifd].comp = 6; tiff_ifd[ifd].t_width = jh.wide; tiff_ifd[ifd].t_height = jh.high; tiff_ifd[ifd].bps = jh.bits; tiff_ifd[ifd].samples = jh.clrs; if (!(jh.sraw || (jh.clrs & 1))) tiff_ifd[ifd].t_width *= jh.clrs; if ((tiff_ifd[ifd].t_width > 4*tiff_ifd[ifd].t_height) & ~jh.clrs) { tiff_ifd[ifd].t_width /= 2; tiff_ifd[ifd].t_height *= 2; } i = order; parse_tiff (tiff_ifd[ifd].offset + 12); order = i; } } break; case 274: /* Orientation */ tiff_ifd[ifd].t_flip = "50132467"[get2() & 7]-'0'; break; case 277: /* SamplesPerPixel */ tiff_ifd[ifd].samples = getint(type) & 7; break; case 279: /* StripByteCounts */ #ifdef LIBRAW_LIBRARY_BUILD if(len > 1 && len < 16384) { off_t sav = ftell(ifp); tiff_ifd[ifd].strip_byte_counts = (int*)calloc(len,sizeof(int)); tiff_ifd[ifd].strip_byte_counts_count = len; for(int i=0; i< len; i++) tiff_ifd[ifd].strip_byte_counts[i]=get4(); fseek(ifp,sav,SEEK_SET); // restore position } /* fallback */ #endif case 514: case 61448: tiff_ifd[ifd].bytes = get4(); break; case 61454: FORC3 cam_mul[(4-c) % 3] = getint(type); break; case 305: case 11: /* Software */ fgets (software, 64, ifp); if (!strncmp(software,"Adobe",5) || !strncmp(software,"dcraw",5) || !strncmp(software,"UFRaw",5) || !strncmp(software,"Bibble",6) || !strcmp (software,"Digital Photo Professional")) is_raw = 0; break; case 306: /* DateTime */ get_timestamp(0); break; case 315: /* Artist */ fread (artist, 64, 1, ifp); break; case 317: tiff_ifd[ifd].predictor = getint(type); break; case 322: /* TileWidth */ tiff_ifd[ifd].t_tile_width = getint(type); break; case 323: /* TileLength */ tiff_ifd[ifd].t_tile_length = getint(type); break; case 324: /* TileOffsets */ tiff_ifd[ifd].offset = len > 1 ? ftell(ifp) : get4(); if (len == 1) tiff_ifd[ifd].t_tile_width = tiff_ifd[ifd].t_tile_length = 0; if (len == 4) { load_raw = &CLASS sinar_4shot_load_raw; is_raw = 5; } break; case 325: tiff_ifd[ifd].bytes = len > 1 ? ftell(ifp): get4(); break; case 330: /* SubIFDs */ if (!strcmp(model,"DSLR-A100") && tiff_ifd[ifd].t_width == 3872) { load_raw = &CLASS sony_arw_load_raw; data_offset = get4()+base; ifd++; #ifdef LIBRAW_LIBRARY_BUILD if (ifd >= sizeof tiff_ifd / sizeof tiff_ifd[0]) throw LIBRAW_EXCEPTION_IO_CORRUPT; #endif break; } #ifdef LIBRAW_LIBRARY_BUILD if (!strncmp(make,"Hasselblad",10) && libraw_internal_data.unpacker_data.hasselblad_parser_flag) { fseek (ifp, ftell(ifp)+4, SEEK_SET); fseek (ifp, get4()+base, SEEK_SET); parse_tiff_ifd (base); break; } #endif if(len > 1000) len=1000; /* 1000 SubIFDs is enough */ while (len--) { i = ftell(ifp); fseek (ifp, get4()+base, SEEK_SET); if (parse_tiff_ifd (base)) break; fseek (ifp, i+4, SEEK_SET); } break; case 339: tiff_ifd[ifd].sample_format = getint(type); break; case 400: strcpy (make, "Sarnoff"); maximum = 0xfff; break; #ifdef LIBRAW_LIBRARY_BUILD case 700: if((type == 1 || type == 2 || type == 6 || type == 7) && len > 1 && len < 5100000) { xmpdata = (char*)malloc(xmplen = len+1); fread(xmpdata,len,1,ifp); xmpdata[len]=0; } break; #endif case 28688: FORC4 sony_curve[c+1] = get2() >> 2 & 0xfff; for (i=0; i < 5; i++) for (j = sony_curve[i]+1; j <= sony_curve[i+1]; j++) curve[j] = curve[j-1] + (1 << i); break; case 29184: sony_offset = get4(); break; case 29185: sony_length = get4(); break; case 29217: sony_key = get4(); break; case 29264: parse_minolta (ftell(ifp)); raw_width = 0; break; case 29443: FORC4 cam_mul[c ^ (c < 2)] = get2(); break; case 29459: FORC4 cam_mul[c] = get2(); i = (cam_mul[1] == 1024 && cam_mul[2] == 1024) << 1; SWAP (cam_mul[i],cam_mul[i+1]) break; #ifdef LIBRAW_LIBRARY_BUILD case 30720: // Sony matrix, Sony_SR2SubIFD_0x7800 for (i=0; i < 3; i++) { float num = 0.0; for (c=0; c<3; c++) { imgdata.color.ccm[i][c] = (float) ((short)get2()); num += imgdata.color.ccm[i][c]; } if (num > 0.01) FORC3 imgdata.color.ccm[i][c] = imgdata.color.ccm[i][c] / num; } break; #endif case 29456: // Sony black level, Sony_SR2SubIFD_0x7310, no more needs to be divided by 4 FORC4 cblack[c ^ c >> 1] = get2(); i = cblack[3]; FORC3 if(i>cblack[c]) i = cblack[c]; FORC4 cblack[c]-=i; black = i; #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr, _("...Sony black: %u cblack: %u %u %u %u\n"),black, cblack[0],cblack[1],cblack[2], cblack[3]); #endif break; case 33405: /* Model2 */ fgets (model2, 64, ifp); break; case 33421: /* CFARepeatPatternDim */ if (get2() == 6 && get2() == 6) filters = 9; break; case 33422: /* CFAPattern */ if (filters == 9) { FORC(36) ((char *)xtrans)[c] = fgetc(ifp) & 3; break; } case 64777: /* Kodak P-series */ if(len == 36) { filters = 9; colors = 3; FORC(36) xtrans[0][c] = fgetc(ifp) & 3; } else if(len > 0) { if ((plen=len) > 16) plen = 16; fread (cfa_pat, 1, plen, ifp); for (colors=cfa=i=0; i < plen && colors < 4; i++) { colors += !(cfa & (1 << cfa_pat[i])); cfa |= 1 << cfa_pat[i]; } if (cfa == 070) memcpy (cfa_pc,"\003\004\005",3); /* CMY */ if (cfa == 072) memcpy (cfa_pc,"\005\003\004\001",4); /* GMCY */ goto guess_cfa_pc; } break; case 33424: case 65024: fseek (ifp, get4()+base, SEEK_SET); parse_kodak_ifd (base); break; case 33434: /* ExposureTime */ tiff_ifd[ifd].t_shutter = shutter = getreal(type); break; case 33437: /* FNumber */ aperture = getreal(type); break; #ifdef LIBRAW_LIBRARY_BUILD // IB start case 0xa405: // FocalLengthIn35mmFormat imgdata.lens.FocalLengthIn35mmFormat = get2(); break; case 0xa431: // BodySerialNumber case 0xc62f: stmread(imgdata.shootinginfo.BodySerial, len, ifp); break; case 0xa432: // LensInfo, 42034dec, Lens Specification per EXIF standard imgdata.lens.MinFocal = getreal(type); imgdata.lens.MaxFocal = getreal(type); imgdata.lens.MaxAp4MinFocal = getreal(type); imgdata.lens.MaxAp4MaxFocal = getreal(type); break; case 0xa435: // LensSerialNumber stmread(imgdata.lens.LensSerial, len, ifp); break; case 0xc630: // DNG LensInfo, Lens Specification per EXIF standard imgdata.lens.MinFocal = getreal(type); imgdata.lens.MaxFocal = getreal(type); imgdata.lens.MaxAp4MinFocal = getreal(type); imgdata.lens.MaxAp4MaxFocal = getreal(type); break; case 0xa433: // LensMake stmread(imgdata.lens.LensMake, len, ifp); break; case 0xa434: // LensModel stmread(imgdata.lens.Lens, len, ifp); if (!strncmp(imgdata.lens.Lens, "----", 4)) imgdata.lens.Lens[0] = 0; break; case 0x9205: imgdata.lens.EXIF_MaxAp = libraw_powf64(2.0f, (getreal(type) / 2.0f)); break; // IB end #endif case 34306: /* Leaf white balance */ FORC4 cam_mul[c ^ 1] = 4096.0 / get2(); break; case 34307: /* Leaf CatchLight color matrix */ fread (software, 1, 7, ifp); if (strncmp(software,"MATRIX",6)) break; colors = 4; for (raw_color = i=0; i < 3; i++) { FORC4 fscanf (ifp, "%f", &rgb_cam[i][c^1]); if (!use_camera_wb) continue; num = 0; FORC4 num += rgb_cam[i][c]; FORC4 rgb_cam[i][c] /= MAX(1,num); } break; case 34310: /* Leaf metadata */ parse_mos (ftell(ifp)); case 34303: strcpy (make, "Leaf"); break; case 34665: /* EXIF tag */ fseek (ifp, get4()+base, SEEK_SET); parse_exif (base); break; case 34853: /* GPSInfo tag */ { unsigned pos; fseek(ifp, pos = (get4() + base), SEEK_SET); parse_gps(base); #ifdef LIBRAW_LIBRARY_BUILD fseek(ifp, pos, SEEK_SET); parse_gps_libraw(base); #endif } break; case 34675: /* InterColorProfile */ case 50831: /* AsShotICCProfile */ profile_offset = ftell(ifp); profile_length = len; break; case 37122: /* CompressedBitsPerPixel */ kodak_cbpp = get4(); break; case 37386: /* FocalLength */ focal_len = getreal(type); break; case 37393: /* ImageNumber */ shot_order = getint(type); break; case 37400: /* old Kodak KDC tag */ for (raw_color = i=0; i < 3; i++) { getreal(type); FORC3 rgb_cam[i][c] = getreal(type); } break; case 40976: strip_offset = get4(); switch (tiff_ifd[ifd].comp) { case 32770: load_raw = &CLASS samsung_load_raw; break; case 32772: load_raw = &CLASS samsung2_load_raw; break; case 32773: load_raw = &CLASS samsung3_load_raw; break; } break; case 46275: /* Imacon tags */ strcpy (make, "Imacon"); data_offset = ftell(ifp); ima_len = len; break; case 46279: if (!ima_len) break; fseek (ifp, 38, SEEK_CUR); case 46274: fseek (ifp, 40, SEEK_CUR); raw_width = get4(); raw_height = get4(); left_margin = get4() & 7; width = raw_width - left_margin - (get4() & 7); top_margin = get4() & 7; height = raw_height - top_margin - (get4() & 7); if (raw_width == 7262 && ima_len == 234317952 ) { height = 5412; width = 7216; left_margin = 7; filters=0; } else if (raw_width == 7262) { height = 5444; width = 7244; left_margin = 7; } fseek (ifp, 52, SEEK_CUR); FORC3 cam_mul[c] = getreal(11); fseek (ifp, 114, SEEK_CUR); flip = (get2() >> 7) * 90; if (width * height * 6 == ima_len) { if (flip % 180 == 90) SWAP(width,height); raw_width = width; raw_height = height; left_margin = top_margin = filters = flip = 0; } sprintf (model, "Ixpress %d-Mp", height*width/1000000); load_raw = &CLASS imacon_full_load_raw; if (filters) { if (left_margin & 1) filters = 0x61616161; load_raw = &CLASS unpacked_load_raw; } maximum = 0xffff; break; case 50454: /* Sinar tag */ case 50455: if (len < 1 || len > 2560000 || !(cbuf = (char *) malloc(len))) break; #ifndef LIBRAW_LIBRARY_BUILD fread (cbuf, 1, len, ifp); #else if(fread (cbuf, 1, len, ifp) != len) throw LIBRAW_EXCEPTION_IO_CORRUPT; // cbuf to be free'ed in recycle #endif cbuf[len-1] = 0; for (cp = cbuf-1; cp && cp < cbuf+len; cp = strchr(cp,'\n')) if (!strncmp (++cp,"Neutral ",8)) sscanf (cp+8, "%f %f %f", cam_mul, cam_mul+1, cam_mul+2); free (cbuf); break; case 50458: if (!make[0]) strcpy (make, "Hasselblad"); break; case 50459: /* Hasselblad tag */ #ifdef LIBRAW_LIBRARY_BUILD libraw_internal_data.unpacker_data.hasselblad_parser_flag=1; #endif i = order; j = ftell(ifp); c = tiff_nifds; order = get2(); fseek (ifp, j+(get2(),get4()), SEEK_SET); parse_tiff_ifd (j); maximum = 0xffff; tiff_nifds = c; order = i; break; case 50706: /* DNGVersion */ FORC4 dng_version = (dng_version << 8) + fgetc(ifp); if (!make[0]) strcpy (make, "DNG"); is_raw = 1; break; case 50708: /* UniqueCameraModel */ #ifdef LIBRAW_LIBRARY_BUILD stmread(imgdata.color.UniqueCameraModel, len, ifp); imgdata.color.UniqueCameraModel[sizeof(imgdata.color.UniqueCameraModel)-1] = 0; #endif if (model[0]) break; #ifndef LIBRAW_LIBRARY_BUILD fgets (make, 64, ifp); #else strncpy (make, imgdata.color.UniqueCameraModel, MIN(len, sizeof(imgdata.color.UniqueCameraModel))); #endif if ((cp = strchr(make,' '))) { strcpy(model,cp+1); *cp = 0; } break; case 50710: /* CFAPlaneColor */ if (filters == 9) break; if (len > 4) len = 4; colors = len; fread (cfa_pc, 1, colors, ifp); guess_cfa_pc: FORCC tab[cfa_pc[c]] = c; cdesc[c] = 0; for (i=16; i--; ) filters = filters << 2 | tab[cfa_pat[i % plen]]; filters -= !filters; break; case 50711: /* CFALayout */ if (get2() == 2) fuji_width = 1; break; case 291: case 50712: /* LinearizationTable */ linear_table (len); break; case 50713: /* BlackLevelRepeatDim */ #ifdef LIBRAW_LIBRARY_BUILD imgdata.color.dng_levels.dng_cblack[4] = #endif cblack[4] = get2(); #ifdef LIBRAW_LIBRARY_BUILD imgdata.color.dng_levels.dng_cblack[5] = #endif cblack[5] = get2(); if (cblack[4] * cblack[5] > (sizeof(cblack) / sizeof (cblack[0]) - 6)) #ifdef LIBRAW_LIBRARY_BUILD imgdata.color.dng_levels.dng_cblack[4]= imgdata.color.dng_levels.dng_cblack[5]= #endif cblack[4] = cblack[5] = 1; break; #ifdef LIBRAW_LIBRARY_BUILD case 0xf00c: { unsigned fwb[4]; FORC4 fwb[c] = get4(); if (fwb[3] < 0x100) { imgdata.color.WB_Coeffs[fwb[3]][0] = fwb[1]; imgdata.color.WB_Coeffs[fwb[3]][1] = imgdata.color.WB_Coeffs[fwb[3]][3] = fwb[0]; imgdata.color.WB_Coeffs[fwb[3]][2] = fwb[2]; if ((fwb[3] == 17) && libraw_internal_data.unpacker_data.lenRAFData>3 && libraw_internal_data.unpacker_data.lenRAFData < 10240000) { long long f_save = ftell(ifp); int fj, found = 0; ushort *rafdata = (ushort*) malloc (sizeof(ushort)*libraw_internal_data.unpacker_data.lenRAFData); fseek (ifp, libraw_internal_data.unpacker_data.posRAFData, SEEK_SET); fread (rafdata, sizeof(ushort), libraw_internal_data.unpacker_data.lenRAFData, ifp); fseek(ifp, f_save, SEEK_SET); for (int fi=0; fi<(libraw_internal_data.unpacker_data.lenRAFData-3); fi++) { if ((fwb[0]==rafdata[fi]) && (fwb[1]==rafdata[fi+1]) && (fwb[2]==rafdata[fi+2])) { if (rafdata[fi-15] != fwb[0]) continue; fi = fi - 15; imgdata.color.WB_Coeffs[LIBRAW_WBI_FineWeather][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_FineWeather][3] = rafdata[fi]; imgdata.color.WB_Coeffs[LIBRAW_WBI_FineWeather][0] = rafdata[fi+1]; imgdata.color.WB_Coeffs[LIBRAW_WBI_FineWeather][2] = rafdata[fi+2]; imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][3] = rafdata[fi+3]; imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][0] = rafdata[fi+4]; imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][2] = rafdata[fi+5]; imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][3] = rafdata[fi+6]; imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][0] = rafdata[fi+7]; imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][2] = rafdata[fi+8]; imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_L][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_L][3] = rafdata[fi+9]; imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_L][0] = rafdata[fi+10]; imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_L][2] = rafdata[fi+11]; imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][3] = rafdata[fi+12]; imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][0] = rafdata[fi+13]; imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][2] = rafdata[fi+14]; imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][3] = rafdata[fi+15]; imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][0] = rafdata[fi+16]; imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][2] = rafdata[fi+17]; fi += 111; for (fj = fi; fj<(fi+15); fj+=3) if (rafdata[fj] != rafdata[fi]) { found = 1; break; } if (found) { int FujiCCT_K [31] = {2500,2550,2650,2700,2800,2850,2950,3000,3100,3200,3300,3400,3600,3700,3800,4000,4200,4300,4500,4800,5000,5300,5600,5900,6300,6700,7100,7700,8300,9100,10000}; fj = fj - 93; for (int iCCT=0; iCCT < 31; iCCT++) { imgdata.color.WBCT_Coeffs[iCCT][0] = FujiCCT_K[iCCT]; imgdata.color.WBCT_Coeffs[iCCT][1] = rafdata[iCCT*3+1+fj]; imgdata.color.WBCT_Coeffs[iCCT][2] = imgdata.color.WBCT_Coeffs[iCCT][4] = rafdata[iCCT*3+fj]; imgdata.color.WBCT_Coeffs[iCCT][3] = rafdata[iCCT*3+2+fj]; } } free (rafdata); break; } } } } FORC4 fwb[c] = get4(); if (fwb[3] < 0x100) { imgdata.color.WB_Coeffs[fwb[3]][0] = fwb[1]; imgdata.color.WB_Coeffs[fwb[3]][1] = imgdata.color.WB_Coeffs[fwb[3]][3] = fwb[0]; imgdata.color.WB_Coeffs[fwb[3]][2] = fwb[2]; } } break; #endif #ifdef LIBRAW_LIBRARY_BUILD case 50709: stmread(imgdata.color.LocalizedCameraModel,len, ifp); break; #endif case 61450: cblack[4] = cblack[5] = MIN(sqrt((double)len),64); case 50714: /* BlackLevel */ #ifdef LIBRAW_LIBRARY_BUILD if(tiff_ifd[ifd].samples > 1 && tiff_ifd[ifd].samples == len) // LinearDNG, per-channel black { for(i=0; i < colors && i < 4 && i < len; i++) imgdata.color.dng_levels.dng_cblack[i]= cblack[i]= getreal(type)+0.5; imgdata.color.dng_levels.dng_black= black = 0; } else #endif if((cblack[4] * cblack[5] < 2) && len == 1) { #ifdef LIBRAW_LIBRARY_BUILD imgdata.color.dng_levels.dng_black= #endif black = getreal(type); } else if(cblack[4] * cblack[5] <= len) { FORC (cblack[4] * cblack[5]) cblack[6+c] = getreal(type); black = 0; FORC4 cblack[c] = 0; #ifdef LIBRAW_LIBRARY_BUILD if(tag == 50714) { FORC (cblack[4] * cblack[5]) imgdata.color.dng_levels.dng_cblack[6+c]= cblack[6+c]; imgdata.color.dng_levels.dng_black=0; FORC4 imgdata.color.dng_levels.dng_cblack[c]= 0; } #endif } break; case 50715: /* BlackLevelDeltaH */ case 50716: /* BlackLevelDeltaV */ for (num=i=0; i < len && i < 65536; i++) num += getreal(type); black += num/len + 0.5; #ifdef LIBRAW_LIBRARY_BUILD imgdata.color.dng_levels.dng_black += num/len + 0.5; #endif break; case 50717: /* WhiteLevel */ #ifdef LIBRAW_LIBRARY_BUILD imgdata.color.dng_levels.dng_whitelevel[0]= #endif maximum = getint(type); #ifdef LIBRAW_LIBRARY_BUILD if(tiff_ifd[ifd].samples > 1 ) // Linear DNG case for(i=1; i < colors && i < 4 && i < len; i++) imgdata.color.dng_levels.dng_whitelevel[i]=getint(type); #endif break; case 50718: /* DefaultScale */ pixel_aspect = getreal(type); pixel_aspect /= getreal(type); if(pixel_aspect > 0.995 && pixel_aspect < 1.005) pixel_aspect = 1.0; break; #ifdef LIBRAW_LIBRARY_BUILD case 50778: imgdata.color.dng_color[0].illuminant = get2(); break; case 50779: imgdata.color.dng_color[1].illuminant = get2(); break; #endif case 50721: /* ColorMatrix1 */ case 50722: /* ColorMatrix2 */ #ifdef LIBRAW_LIBRARY_BUILD i = tag == 50721?0:1; #endif FORCC for (j=0; j < 3; j++) { #ifdef LIBRAW_LIBRARY_BUILD imgdata.color.dng_color[i].colormatrix[c][j]= #endif cm[c][j] = getreal(type); } use_cm = 1; break; case 0xc714: /* ForwardMatrix1 */ case 0xc715: /* ForwardMatrix2 */ #ifdef LIBRAW_LIBRARY_BUILD i = tag == 0xc714?0:1; #endif for (j=0; j < 3; j++) FORCC { #ifdef LIBRAW_LIBRARY_BUILD imgdata.color.dng_color[i].forwardmatrix[j][c]= #endif fm[j][c] = getreal(type); } break; case 50723: /* CameraCalibration1 */ case 50724: /* CameraCalibration2 */ #ifdef LIBRAW_LIBRARY_BUILD j = tag == 50723?0:1; #endif for (i=0; i < colors; i++) FORCC { #ifdef LIBRAW_LIBRARY_BUILD imgdata.color.dng_color[j].calibration[i][c]= #endif cc[i][c] = getreal(type); } break; case 50727: /* AnalogBalance */ FORCC{ #ifdef LIBRAW_LIBRARY_BUILD imgdata.color.dng_levels.analogbalance[c]= #endif ab[c] = getreal(type); } break; case 50728: /* AsShotNeutral */ FORCC asn[c] = getreal(type); break; case 50729: /* AsShotWhiteXY */ xyz[0] = getreal(type); xyz[1] = getreal(type); xyz[2] = 1 - xyz[0] - xyz[1]; FORC3 xyz[c] /= d65_white[c]; break; #ifdef LIBRAW_LIBRARY_BUILD case 50730: /* DNG: Baseline Exposure */ baseline_exposure = getreal(type); break; #endif // IB start case 50740: /* tag 0xc634 : DNG Adobe, DNG Pentax, Sony SR2, DNG Private */ #ifdef LIBRAW_LIBRARY_BUILD { char mbuf[64]; unsigned short makernote_found = 0; INT64 curr_pos, start_pos = ftell(ifp); unsigned MakN_order, m_sorder = order; unsigned MakN_length; unsigned pos_in_original_raw; fread(mbuf, 1, 6, ifp); if (!strcmp(mbuf, "Adobe")) { order = 0x4d4d; // Adobe header is always in "MM" / big endian curr_pos = start_pos + 6; while (curr_pos + 8 - start_pos <= len) { fread(mbuf, 1, 4, ifp); curr_pos += 8; if (!strncmp(mbuf, "MakN", 4)) { makernote_found = 1; MakN_length = get4(); MakN_order = get2(); pos_in_original_raw = get4(); order = MakN_order; parse_makernote_0xc634(curr_pos + 6 - pos_in_original_raw, 0, AdobeDNG); break; } } } else { fread(mbuf + 6, 1, 2, ifp); if (!strcmp(mbuf, "PENTAX ") || !strcmp(mbuf, "SAMSUNG")) { makernote_found = 1; fseek(ifp, start_pos, SEEK_SET); parse_makernote_0xc634(base, 0, CameraDNG); } } fseek(ifp, start_pos, SEEK_SET); order = m_sorder; } // IB end #endif if (dng_version) break; parse_minolta (j = get4()+base); fseek (ifp, j, SEEK_SET); parse_tiff_ifd (base); break; case 50752: read_shorts (cr2_slice, 3); break; case 50829: /* ActiveArea */ top_margin = getint(type); left_margin = getint(type); height = getint(type) - top_margin; width = getint(type) - left_margin; break; case 50830: /* MaskedAreas */ for (i=0; i < len && i < 32; i++) ((int*)mask)[i] = getint(type); black = 0; break; case 51009: /* OpcodeList2 */ meta_offset = ftell(ifp); break; case 64772: /* Kodak P-series */ if (len < 13) break; fseek (ifp, 16, SEEK_CUR); data_offset = get4(); fseek (ifp, 28, SEEK_CUR); data_offset += get4(); load_raw = &CLASS packed_load_raw; break; case 65026: if (type == 2) fgets (model2, 64, ifp); } fseek (ifp, save, SEEK_SET); } if (sony_length && sony_length < 10240000 && (buf = (unsigned *) malloc(sony_length))) { fseek (ifp, sony_offset, SEEK_SET); fread (buf, sony_length, 1, ifp); sony_decrypt (buf, sony_length/4, 1, sony_key); #ifndef LIBRAW_LIBRARY_BUILD sfp = ifp; if ((ifp = tmpfile())) { fwrite (buf, sony_length, 1, ifp); fseek (ifp, 0, SEEK_SET); parse_tiff_ifd (-sony_offset); fclose (ifp); } ifp = sfp; #else if( !ifp->tempbuffer_open(buf,sony_length)) { parse_tiff_ifd(-sony_offset); ifp->tempbuffer_close(); } #endif free (buf); } for (i=0; i < colors; i++) FORCC cc[i][c] *= ab[i]; if (use_cm) { FORCC for (i=0; i < 3; i++) for (cam_xyz[c][i]=j=0; j < colors; j++) cam_xyz[c][i] += cc[c][j] * cm[j][i] * xyz[i]; cam_xyz_coeff (cmatrix, cam_xyz); } if (asn[0]) { cam_mul[3] = 0; FORCC cam_mul[c] = 1 / asn[c]; } if (!use_cm) FORCC pre_mul[c] /= cc[c][c]; return 0; } int CLASS parse_tiff (int base) { int doff; fseek (ifp, base, SEEK_SET); order = get2(); if (order != 0x4949 && order != 0x4d4d) return 0; get2(); while ((doff = get4())) { fseek (ifp, doff+base, SEEK_SET); if (parse_tiff_ifd (base)) break; } return 1; } void CLASS apply_tiff() { int max_samp=0, ties=0, os, ns, raw=-1, thm=-1, i; struct jhead jh; thumb_misc = 16; if (thumb_offset) { fseek (ifp, thumb_offset, SEEK_SET); if (ljpeg_start (&jh, 1)) { if((unsigned)jh.bits<17 && (unsigned)jh.wide < 0x10000 && (unsigned)jh.high < 0x10000) { thumb_misc = jh.bits; thumb_width = jh.wide; thumb_height = jh.high; } } } for (i=tiff_nifds; i--; ) { if (tiff_ifd[i].t_shutter) shutter = tiff_ifd[i].t_shutter; tiff_ifd[i].t_shutter = shutter; } for (i=0; i < tiff_nifds; i++) { if (max_samp < tiff_ifd[i].samples) max_samp = tiff_ifd[i].samples; if (max_samp > 3) max_samp = 3; os = raw_width*raw_height; ns = tiff_ifd[i].t_width*tiff_ifd[i].t_height; if (tiff_bps) { os *= tiff_bps; ns *= tiff_ifd[i].bps; } if ((tiff_ifd[i].comp != 6 || tiff_ifd[i].samples != 3) && unsigned(tiff_ifd[i].t_width | tiff_ifd[i].t_height) < 0x10000 && (unsigned)tiff_ifd[i].bps < 33 && (unsigned)tiff_ifd[i].samples < 13 && ns && ((ns > os && (ties = 1)) || (ns == os && shot_select == ties++))) { raw_width = tiff_ifd[i].t_width; raw_height = tiff_ifd[i].t_height; tiff_bps = tiff_ifd[i].bps; tiff_compress = tiff_ifd[i].comp; data_offset = tiff_ifd[i].offset; #ifdef LIBRAW_LIBRARY_BUILD data_size = tiff_ifd[i].bytes; #endif tiff_flip = tiff_ifd[i].t_flip; tiff_samples = tiff_ifd[i].samples; tile_width = tiff_ifd[i].t_tile_width; tile_length = tiff_ifd[i].t_tile_length; shutter = tiff_ifd[i].t_shutter; raw = i; } } if (is_raw == 1 && ties) is_raw = ties; if (!tile_width ) tile_width = INT_MAX; if (!tile_length) tile_length = INT_MAX; for (i=tiff_nifds; i--; ) if (tiff_ifd[i].t_flip) tiff_flip = tiff_ifd[i].t_flip; if (raw >= 0 && !load_raw) switch (tiff_compress) { case 32767: if (tiff_ifd[raw].bytes == raw_width*raw_height) { tiff_bps = 12; load_raw = &CLASS sony_arw2_load_raw; break; } if (!strncasecmp(make,"Sony",4) && tiff_ifd[raw].bytes == raw_width*raw_height*2) { tiff_bps = 14; load_raw = &CLASS unpacked_load_raw; break; } if (tiff_ifd[raw].bytes*8 != raw_width*raw_height*tiff_bps) { raw_height += 8; load_raw = &CLASS sony_arw_load_raw; break; } load_flags = 79; case 32769: load_flags++; case 32770: case 32773: goto slr; case 0: case 1: #ifdef LIBRAW_LIBRARY_BUILD // Sony 14-bit uncompressed if(!strncasecmp(make,"Sony",4) && tiff_ifd[raw].bytes == raw_width*raw_height*2) { tiff_bps = 14; load_raw = &CLASS unpacked_load_raw; break; } if(!strncasecmp(make,"Nikon",5) && !strncmp(software,"Nikon Scan",10)) { load_raw = &CLASS nikon_coolscan_load_raw; raw_color = 1; filters = 0; break; } #endif if (!strncmp(make,"OLYMPUS",7) && tiff_ifd[raw].bytes*2 == raw_width*raw_height*3) load_flags = 24; if (tiff_ifd[raw].bytes*5 == raw_width*raw_height*8) { load_flags = 81; tiff_bps = 12; } slr: switch (tiff_bps) { case 8: load_raw = &CLASS eight_bit_load_raw; break; case 12: if (tiff_ifd[raw].phint == 2) load_flags = 6; load_raw = &CLASS packed_load_raw; break; case 14: load_flags = 0; case 16: load_raw = &CLASS unpacked_load_raw; if (!strncmp(make,"OLYMPUS",7) && tiff_ifd[raw].bytes*7 > raw_width*raw_height) load_raw = &CLASS olympus_load_raw; } break; case 6: case 7: case 99: load_raw = &CLASS lossless_jpeg_load_raw; break; case 262: load_raw = &CLASS kodak_262_load_raw; break; case 34713: if ((raw_width+9)/10*16*raw_height == tiff_ifd[raw].bytes) { load_raw = &CLASS packed_load_raw; load_flags = 1; } else if (raw_width*raw_height*3 == tiff_ifd[raw].bytes*2) { load_raw = &CLASS packed_load_raw; if (model[0] == 'N') load_flags = 80; } else if (raw_width*raw_height*3 == tiff_ifd[raw].bytes) { load_raw = &CLASS nikon_yuv_load_raw; gamma_curve (1/2.4, 12.92, 1, 4095); memset (cblack, 0, sizeof cblack); filters = 0; } else if (raw_width*raw_height*2 == tiff_ifd[raw].bytes) { load_raw = &CLASS unpacked_load_raw; load_flags = 4; order = 0x4d4d; } else #ifdef LIBRAW_LIBRARY_BUILD if(raw_width*raw_height*3 == tiff_ifd[raw].bytes*2) { load_raw = &CLASS packed_load_raw; load_flags=80; } else if(tiff_ifd[raw].rows_per_strip && tiff_ifd[raw].strip_offsets_count && tiff_ifd[raw].strip_offsets_count == tiff_ifd[raw].strip_byte_counts_count) { int fit = 1; for(int i = 0; i < tiff_ifd[raw].strip_byte_counts_count-1; i++) // all but last if(tiff_ifd[raw].strip_byte_counts[i]*2 != tiff_ifd[raw].rows_per_strip*raw_width*3) { fit = 0; break; } if(fit) load_raw = &CLASS nikon_load_striped_packed_raw; else load_raw = &CLASS nikon_load_raw; // fallback } else #endif load_raw = &CLASS nikon_load_raw; break; case 65535: load_raw = &CLASS pentax_load_raw; break; case 65000: switch (tiff_ifd[raw].phint) { case 2: load_raw = &CLASS kodak_rgb_load_raw; filters = 0; break; case 6: load_raw = &CLASS kodak_ycbcr_load_raw; filters = 0; break; case 32803: load_raw = &CLASS kodak_65000_load_raw; } case 32867: case 34892: break; #ifdef LIBRAW_LIBRARY_BUILD case 8: break; #endif default: is_raw = 0; } if (!dng_version) if ( ((tiff_samples == 3 && tiff_ifd[raw].bytes && tiff_bps != 14 && (tiff_compress & -16) != 32768) || (tiff_bps == 8 && strncmp(make,"Phase",5) && !strcasestr(make,"Kodak") && !strstr(model2,"DEBUG RAW"))) && strncmp(software,"Nikon Scan",10)) is_raw = 0; for (i=0; i < tiff_nifds; i++) if (i != raw && (tiff_ifd[i].samples == max_samp || (tiff_ifd[i].comp == 7 && tiff_ifd[i].samples == 1)) /* Allow 1-bps JPEGs */ && tiff_ifd[i].bps>0 && tiff_ifd[i].bps < 33 && tiff_ifd[i].phint != 32803 && tiff_ifd[i].phint != 34892 && unsigned(tiff_ifd[i].t_width | tiff_ifd[i].t_height) < 0x10000 && tiff_ifd[i].t_width * tiff_ifd[i].t_height / (SQR(tiff_ifd[i].bps)+1) > thumb_width * thumb_height / (SQR(thumb_misc)+1) && tiff_ifd[i].comp != 34892) { thumb_width = tiff_ifd[i].t_width; thumb_height = tiff_ifd[i].t_height; thumb_offset = tiff_ifd[i].offset; thumb_length = tiff_ifd[i].bytes; thumb_misc = tiff_ifd[i].bps; thm = i; } if (thm >= 0) { thumb_misc |= tiff_ifd[thm].samples << 5; switch (tiff_ifd[thm].comp) { case 0: write_thumb = &CLASS layer_thumb; break; case 1: if (tiff_ifd[thm].bps <= 8) write_thumb = &CLASS ppm_thumb; else if (!strncmp(make,"Imacon",6)) write_thumb = &CLASS ppm16_thumb; else thumb_load_raw = &CLASS kodak_thumb_load_raw; break; case 65000: thumb_load_raw = tiff_ifd[thm].phint == 6 ? &CLASS kodak_ycbcr_load_raw : &CLASS kodak_rgb_load_raw; } } } void CLASS parse_minolta (int base) { int save, tag, len, offset, high=0, wide=0, i, c; short sorder=order; fseek (ifp, base, SEEK_SET); if (fgetc(ifp) || fgetc(ifp)-'M' || fgetc(ifp)-'R') return; order = fgetc(ifp) * 0x101; offset = base + get4() + 8; while ((save=ftell(ifp)) < offset) { for (tag=i=0; i < 4; i++) tag = tag << 8 | fgetc(ifp); len = get4(); switch (tag) { case 0x505244: /* PRD */ fseek (ifp, 8, SEEK_CUR); high = get2(); wide = get2(); break; #ifdef LIBRAW_LIBRARY_BUILD case 0x524946: /* RIF */ if (!strncasecmp(model,"DSLR-A100", 9)) { fseek(ifp, 8, SEEK_CUR); imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][2] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][2] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][2] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][2] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][2] = get2(); get4(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][2] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][2] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][2] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_WW][0] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_WW][2] = get2(); imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_WW][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_WW][3] = 0x100; } break; #endif case 0x574247: /* WBG */ get4(); i = strcmp(model,"DiMAGE A200") ? 0:3; FORC4 cam_mul[c ^ (c >> 1) ^ i] = get2(); break; case 0x545457: /* TTW */ parse_tiff (ftell(ifp)); data_offset = offset; } fseek (ifp, save+len+8, SEEK_SET); } raw_height = high; raw_width = wide; order = sorder; } /* Many cameras have a "debug mode" that writes JPEG and raw at the same time. The raw file has no header, so try to to open the matching JPEG file and read its metadata. */ void CLASS parse_external_jpeg() { const char *file, *ext; char *jname, *jfile, *jext; #ifndef LIBRAW_LIBRARY_BUILD FILE *save=ifp; #else #if defined(_WIN32) && !defined(__MINGW32__) && defined(_MSC_VER) && (_MSC_VER > 1310) if(ifp->wfname()) { std::wstring rawfile(ifp->wfname()); rawfile.replace(rawfile.length()-3,3,L"JPG"); if(!ifp->subfile_open(rawfile.c_str())) { parse_tiff (12); thumb_offset = 0; is_raw = 1; ifp->subfile_close(); } else imgdata.process_warnings |= LIBRAW_WARN_NO_METADATA ; return; } #endif if(!ifp->fname()) { imgdata.process_warnings |= LIBRAW_WARN_NO_METADATA ; return; } #endif ext = strrchr (ifname, '.'); file = strrchr (ifname, '/'); if (!file) file = strrchr (ifname, '\\'); #ifndef LIBRAW_LIBRARY_BUILD if (!file) file = ifname-1; #else if (!file) file = (char*)ifname-1; #endif file++; if (!ext || strlen(ext) != 4 || ext-file != 8) return; jname = (char *) malloc (strlen(ifname) + 1); merror (jname, "parse_external_jpeg()"); strcpy (jname, ifname); jfile = file - ifname + jname; jext = ext - ifname + jname; if (strcasecmp (ext, ".jpg")) { strcpy (jext, isupper(ext[1]) ? ".JPG":".jpg"); if (isdigit(*file)) { memcpy (jfile, file+4, 4); memcpy (jfile+4, file, 4); } } else while (isdigit(*--jext)) { if (*jext != '9') { (*jext)++; break; } *jext = '0'; } #ifndef LIBRAW_LIBRARY_BUILD if (strcmp (jname, ifname)) { if ((ifp = fopen (jname, "rb"))) { #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("Reading metadata from %s ...\n"), jname); #endif parse_tiff (12); thumb_offset = 0; is_raw = 1; fclose (ifp); } } #else if (strcmp (jname, ifname)) { if(!ifp->subfile_open(jname)) { parse_tiff (12); thumb_offset = 0; is_raw = 1; ifp->subfile_close(); } else imgdata.process_warnings |= LIBRAW_WARN_NO_METADATA ; } #endif if (!timestamp) { #ifdef LIBRAW_LIBRARY_BUILD imgdata.process_warnings |= LIBRAW_WARN_NO_METADATA ; #endif #ifdef DCRAW_VERBOSE fprintf (stderr,_("Failed to read metadata from %s\n"), jname); #endif } free (jname); #ifndef LIBRAW_LIBRARY_BUILD ifp = save; #endif } /* CIFF block 0x1030 contains an 8x8 white sample. Load this into white[][] for use in scale_colors(). */ void CLASS ciff_block_1030() { static const ushort key[] = { 0x410, 0x45f3 }; int i, bpp, row, col, vbits=0; unsigned long bitbuf=0; if ((get2(),get4()) != 0x80008 || !get4()) return; bpp = get2(); if (bpp != 10 && bpp != 12) return; for (i=row=0; row < 8; row++) for (col=0; col < 8; col++) { if (vbits < bpp) { bitbuf = bitbuf << 16 | (get2() ^ key[i++ & 1]); vbits += 16; } white[row][col] = bitbuf >> (vbits -= bpp) & ~(-1 << bpp); } } /* Parse a CIFF file, better known as Canon CRW format. */ void CLASS parse_ciff (int offset, int length, int depth) { int tboff, nrecs, c, type, len, save, wbi=-1; ushort key[] = { 0x410, 0x45f3 }; fseek (ifp, offset+length-4, SEEK_SET); tboff = get4() + offset; fseek (ifp, tboff, SEEK_SET); nrecs = get2(); if ((nrecs | depth) > 127) return; while (nrecs--) { type = get2(); len = get4(); save = ftell(ifp) + 4; fseek (ifp, offset+get4(), SEEK_SET); if ((((type >> 8) + 8) | 8) == 0x38) { parse_ciff (ftell(ifp), len, depth+1); /* Parse a sub-table */ } #ifdef LIBRAW_LIBRARY_BUILD if (type == 0x3004) parse_ciff (ftell(ifp), len, depth+1); #endif if (type == 0x0810) fread (artist, 64, 1, ifp); if (type == 0x080a) { fread (make, 64, 1, ifp); fseek (ifp, strbuflen(make) - 63, SEEK_CUR); fread (model, 64, 1, ifp); } if (type == 0x1810) { width = get4(); height = get4(); pixel_aspect = int_to_float(get4()); flip = get4(); } if (type == 0x1835) /* Get the decoder table */ tiff_compress = get4(); if (type == 0x2007) { thumb_offset = ftell(ifp); thumb_length = len; } if (type == 0x1818) { shutter = libraw_powf64(2.0f, -int_to_float((get4(),get4()))); aperture = libraw_powf64(2.0f, int_to_float(get4())/2); #ifdef LIBRAW_LIBRARY_BUILD imgdata.lens.makernotes.CurAp = aperture; #endif } if (type == 0x102a) { // iso_speed = pow (2.0, (get4(),get2())/32.0 - 4) * 50; iso_speed = libraw_powf64(2.0f, ((get2(),get2()) + get2())/32.0f - 5.0f) * 100.0f; #ifdef LIBRAW_LIBRARY_BUILD aperture = _CanonConvertAperture((get2(),get2())); imgdata.lens.makernotes.CurAp = aperture; #else aperture = libraw_powf64(2.0, (get2(),(short)get2())/64.0); #endif shutter = libraw_powf64(2.0,-((short)get2())/32.0); wbi = (get2(),get2()); if (wbi > 17) wbi = 0; fseek (ifp, 32, SEEK_CUR); if (shutter > 1e6) shutter = get2()/10.0; } if (type == 0x102c) { if (get2() > 512) { /* Pro90, G1 */ fseek (ifp, 118, SEEK_CUR); FORC4 cam_mul[c ^ 2] = get2(); } else { /* G2, S30, S40 */ fseek (ifp, 98, SEEK_CUR); FORC4 cam_mul[c ^ (c >> 1) ^ 1] = get2(); } } #ifdef LIBRAW_LIBRARY_BUILD if (type == 0x10a9) { INT64 o = ftell(ifp); fseek (ifp, (0x5<<1), SEEK_CUR); Canon_WBpresets(0,0); fseek(ifp,o,SEEK_SET); } if (type == 0x102d) { INT64 o = ftell(ifp); Canon_CameraSettings(); fseek(ifp,o,SEEK_SET); } if (type == 0x580b) { if (strcmp(model,"Canon EOS D30")) sprintf(imgdata.shootinginfo.BodySerial, "%d", len); else sprintf(imgdata.shootinginfo.BodySerial, "%0x-%05d", len>>16, len&0xffff); } #endif if (type == 0x0032) { if (len == 768) { /* EOS D30 */ fseek (ifp, 72, SEEK_CUR); FORC4 cam_mul[c ^ (c >> 1)] = 1024.0 / get2(); if (!wbi) cam_mul[0] = -1; /* use my auto white balance */ } else if (!cam_mul[0]) { if (get2() == key[0]) /* Pro1, G6, S60, S70 */ c = (strstr(model,"Pro1") ? "012346000000000000":"01345:000000006008")[LIM(0,wbi,17)]-'0'+ 2; else { /* G3, G5, S45, S50 */ c = "023457000000006000"[LIM(0,wbi,17)]-'0'; key[0] = key[1] = 0; } fseek (ifp, 78 + c*8, SEEK_CUR); FORC4 cam_mul[c ^ (c >> 1) ^ 1] = get2() ^ key[c & 1]; if (!wbi) cam_mul[0] = -1; } } if (type == 0x10a9) { /* D60, 10D, 300D, and clones */ if (len > 66) wbi = "0134567028"[LIM(0,wbi,9)]-'0'; fseek (ifp, 2 + wbi*8, SEEK_CUR); FORC4 cam_mul[c ^ (c >> 1)] = get2(); } if (type == 0x1030 && wbi>=0 && (0x18040 >> wbi & 1)) ciff_block_1030(); /* all that don't have 0x10a9 */ if (type == 0x1031) { raw_width = (get2(),get2()); raw_height = get2(); } if (type == 0x501c) { iso_speed = len & 0xffff; } if (type == 0x5029) { #ifdef LIBRAW_LIBRARY_BUILD imgdata.lens.makernotes.CurFocal = len >> 16; imgdata.lens.makernotes.FocalType = len & 0xffff; if (imgdata.lens.makernotes.FocalType == 2) { imgdata.lens.makernotes.CanonFocalUnits = 32; if(imgdata.lens.makernotes.CanonFocalUnits>1) imgdata.lens.makernotes.CurFocal /= (float)imgdata.lens.makernotes.CanonFocalUnits; } focal_len = imgdata.lens.makernotes.CurFocal; #else focal_len = len >> 16; if ((len & 0xffff) == 2) focal_len /= 32; #endif } if (type == 0x5813) flash_used = int_to_float(len); if (type == 0x5814) canon_ev = int_to_float(len); if (type == 0x5817) shot_order = len; if (type == 0x5834) { unique_id = len; #ifdef LIBRAW_LIBRARY_BUILD setCanonBodyFeatures(unique_id); #endif } if (type == 0x580e) timestamp = len; if (type == 0x180e) timestamp = get4(); #ifdef LOCALTIME if ((type | 0x4000) == 0x580e) timestamp = mktime (gmtime (×tamp)); #endif fseek (ifp, save, SEEK_SET); } } void CLASS parse_rollei() { char line[128], *val; struct tm t; fseek (ifp, 0, SEEK_SET); memset (&t, 0, sizeof t); do { fgets (line, 128, ifp); if ((val = strchr(line,'='))) *val++ = 0; else val = line + strbuflen(line); if (!strcmp(line,"DAT")) sscanf (val, "%d.%d.%d", &t.tm_mday, &t.tm_mon, &t.tm_year); if (!strcmp(line,"TIM")) sscanf (val, "%d:%d:%d", &t.tm_hour, &t.tm_min, &t.tm_sec); if (!strcmp(line,"HDR")) thumb_offset = atoi(val); if (!strcmp(line,"X ")) raw_width = atoi(val); if (!strcmp(line,"Y ")) raw_height = atoi(val); if (!strcmp(line,"TX ")) thumb_width = atoi(val); if (!strcmp(line,"TY ")) thumb_height = atoi(val); } while (strncmp(line,"EOHD",4)); data_offset = thumb_offset + thumb_width * thumb_height * 2; t.tm_year -= 1900; t.tm_mon -= 1; if (mktime(&t) > 0) timestamp = mktime(&t); strcpy (make, "Rollei"); strcpy (model,"d530flex"); write_thumb = &CLASS rollei_thumb; } void CLASS parse_sinar_ia() { int entries, off; char str[8], *cp; order = 0x4949; fseek (ifp, 4, SEEK_SET); entries = get4(); fseek (ifp, get4(), SEEK_SET); while (entries--) { off = get4(); get4(); fread (str, 8, 1, ifp); if (!strcmp(str,"META")) meta_offset = off; if (!strcmp(str,"THUMB")) thumb_offset = off; if (!strcmp(str,"RAW0")) data_offset = off; } fseek (ifp, meta_offset+20, SEEK_SET); fread (make, 64, 1, ifp); make[63] = 0; if ((cp = strchr(make,' '))) { strcpy (model, cp+1); *cp = 0; } raw_width = get2(); raw_height = get2(); load_raw = &CLASS unpacked_load_raw; thumb_width = (get4(),get2()); thumb_height = get2(); write_thumb = &CLASS ppm_thumb; maximum = 0x3fff; } void CLASS parse_phase_one (int base) { unsigned entries, tag, type, len, data, save, i, c; float romm_cam[3][3]; char *cp; memset (&ph1, 0, sizeof ph1); fseek (ifp, base, SEEK_SET); order = get4() & 0xffff; if (get4() >> 8 != 0x526177) return; /* "Raw" */ fseek (ifp, get4()+base, SEEK_SET); entries = get4(); get4(); while (entries--) { tag = get4(); type = get4(); len = get4(); data = get4(); save = ftell(ifp); fseek (ifp, base+data, SEEK_SET); switch (tag) { #ifdef LIBRAW_LIBRARY_BUILD case 0x0102: stmread(imgdata.shootinginfo.BodySerial, len, ifp); if ((imgdata.shootinginfo.BodySerial[0] == 0x4c) && (imgdata.shootinginfo.BodySerial[1] == 0x49)) { unique_id = (((imgdata.shootinginfo.BodySerial[0] & 0x3f) << 5) | (imgdata.shootinginfo.BodySerial[2] & 0x3f)) - 0x41; } else { unique_id = (((imgdata.shootinginfo.BodySerial[0] & 0x3f) << 5) | (imgdata.shootinginfo.BodySerial[1] & 0x3f)) - 0x41; } setPhaseOneFeatures(unique_id); break; case 0x0401: if (type == 4) imgdata.lens.makernotes.CurAp = libraw_powf64(2.0f, (int_to_float(data)/2.0f)); else imgdata.lens.makernotes.CurAp = libraw_powf64(2.0f, (getreal(type)/2.0f)); break; case 0x0403: if (type == 4) imgdata.lens.makernotes.CurFocal = int_to_float(data); else imgdata.lens.makernotes.CurFocal = getreal(type); break; case 0x0410: stmread(imgdata.lens.makernotes.body, len, ifp); break; case 0x0412: stmread(imgdata.lens.makernotes.Lens, len, ifp); break; case 0x0414: if (type == 4) { imgdata.lens.makernotes.MaxAp4CurFocal = libraw_powf64(2.0f, (int_to_float(data)/2.0f)); } else { imgdata.lens.makernotes.MaxAp4CurFocal = libraw_powf64(2.0f, (getreal(type) / 2.0f)); } break; case 0x0415: if (type == 4) { imgdata.lens.makernotes.MinAp4CurFocal = libraw_powf64(2.0f, (int_to_float(data)/2.0f)); } else { imgdata.lens.makernotes.MinAp4CurFocal = libraw_powf64(2.0f, (getreal(type) / 2.0f)); } break; case 0x0416: if (type == 4) { imgdata.lens.makernotes.MinFocal = int_to_float(data); } else { imgdata.lens.makernotes.MinFocal = getreal(type); } if (imgdata.lens.makernotes.MinFocal > 1000.0f) { imgdata.lens.makernotes.MinFocal = 0.0f; } break; case 0x0417: if (type == 4) { imgdata.lens.makernotes.MaxFocal = int_to_float(data); } else { imgdata.lens.makernotes.MaxFocal = getreal(type); } break; #endif case 0x100: flip = "0653"[data & 3]-'0'; break; case 0x106: for (i=0; i < 9; i++) #ifdef LIBRAW_LIBRARY_BUILD imgdata.color.P1_color[0].romm_cam[i]= #endif ((float *)romm_cam)[i] = getreal(11); romm_coeff (romm_cam); break; case 0x107: FORC3 cam_mul[c] = getreal(11); break; case 0x108: raw_width = data; break; case 0x109: raw_height = data; break; case 0x10a: left_margin = data; break; case 0x10b: top_margin = data; break; case 0x10c: width = data; break; case 0x10d: height = data; break; case 0x10e: ph1.format = data; break; case 0x10f: data_offset = data+base; break; case 0x110: meta_offset = data+base; meta_length = len; break; case 0x112: ph1.key_off = save - 4; break; case 0x210: ph1.tag_210 = int_to_float(data); break; case 0x21a: ph1.tag_21a = data; break; case 0x21c: strip_offset = data+base; break; case 0x21d: ph1.t_black = data; break; case 0x222: ph1.split_col = data; break; case 0x223: ph1.black_col = data+base; break; case 0x224: ph1.split_row = data; break; case 0x225: ph1.black_row = data+base; break; #ifdef LIBRAW_LIBRARY_BUILD case 0x226: for (i=0; i < 9; i++) imgdata.color.P1_color[1].romm_cam[i] = getreal(11); break; #endif case 0x301: model[63] = 0; fread (model, 1, 63, ifp); if ((cp = strstr(model," camera"))) *cp = 0; } fseek (ifp, save, SEEK_SET); } #ifdef LIBRAW_LIBRARY_BUILD if (!imgdata.lens.makernotes.body[0] && !imgdata.shootinginfo.BodySerial[0]) { fseek (ifp, meta_offset, SEEK_SET); order = get2(); fseek (ifp, 6, SEEK_CUR); fseek (ifp, meta_offset+get4(), SEEK_SET); entries = get4(); get4(); while (entries--) { tag = get4(); len = get4(); data = get4(); save = ftell(ifp); fseek (ifp, meta_offset+data, SEEK_SET); if (tag == 0x0407) { stmread(imgdata.shootinginfo.BodySerial, len, ifp); if ((imgdata.shootinginfo.BodySerial[0] == 0x4c) && (imgdata.shootinginfo.BodySerial[1] == 0x49)) { unique_id = (((imgdata.shootinginfo.BodySerial[0] & 0x3f) << 5) | (imgdata.shootinginfo.BodySerial[2] & 0x3f)) - 0x41; } else { unique_id = (((imgdata.shootinginfo.BodySerial[0] & 0x3f) << 5) | (imgdata.shootinginfo.BodySerial[1] & 0x3f)) - 0x41; } setPhaseOneFeatures(unique_id); } fseek (ifp, save, SEEK_SET); } } #endif load_raw = ph1.format < 3 ? &CLASS phase_one_load_raw : &CLASS phase_one_load_raw_c; maximum = 0xffff; strcpy (make, "Phase One"); if (model[0]) return; switch (raw_height) { case 2060: strcpy (model,"LightPhase"); break; case 2682: strcpy (model,"H 10"); break; case 4128: strcpy (model,"H 20"); break; case 5488: strcpy (model,"H 25"); break; } } void CLASS parse_fuji (int offset) { unsigned entries, tag, len, save, c; fseek (ifp, offset, SEEK_SET); entries = get4(); if (entries > 255) return; #ifdef LIBRAW_LIBRARY_BUILD imgdata.process_warnings |= LIBRAW_WARN_PARSEFUJI_PROCESSED; #endif while (entries--) { tag = get2(); len = get2(); save = ftell(ifp); if (tag == 0x100) { raw_height = get2(); raw_width = get2(); } else if (tag == 0x121) { height = get2(); if ((width = get2()) == 4284) width += 3; } else if (tag == 0x130) { fuji_layout = fgetc(ifp) >> 7; fuji_width = !(fgetc(ifp) & 8); } else if (tag == 0x131) { filters = 9; FORC(36) { int q = fgetc(ifp); xtrans_abs[0][35 - c] = MAX(0,MIN(q,2)); /* & 3;*/ } } else if (tag == 0x2ff0) { FORC4 cam_mul[c ^ 1] = get2(); } // IB start #ifdef LIBRAW_LIBRARY_BUILD else if (tag == 0x9650) { short a = (short)get2(); float b =fMAX(1.0f, get2()); imgdata.makernotes.fuji.FujiExpoMidPointShift = a / b; } else if (tag == 0x2100) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][c ^ 1] = get2(); } else if (tag == 0x2200) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][c ^ 1] = get2(); } else if (tag == 0x2300) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][c ^ 1] = get2(); } else if (tag == 0x2301) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][c ^ 1] = get2(); } else if (tag == 0x2302) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_WW][c ^ 1] = get2(); } else if (tag == 0x2310) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_L][c ^ 1] = get2(); } else if (tag == 0x2400) { FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][c ^ 1] = get2(); } #endif // IB end else if (tag == 0xc000) { c = order; order = 0x4949; if ((tag = get4()) > 10000) tag = get4(); if (tag > 10000) tag = get4(); width = tag; height = get4(); #ifdef LIBRAW_LIBRARY_BUILD libraw_internal_data.unpacker_data.posRAFData = save; libraw_internal_data.unpacker_data.lenRAFData = (len>>1); #endif order = c; } fseek (ifp, save+len, SEEK_SET); } height <<= fuji_layout; width >>= fuji_layout; } int CLASS parse_jpeg (int offset) { int len, save, hlen, mark; fseek (ifp, offset, SEEK_SET); if (fgetc(ifp) != 0xff || fgetc(ifp) != 0xd8) return 0; while (fgetc(ifp) == 0xff && (mark = fgetc(ifp)) != 0xda) { order = 0x4d4d; len = get2() - 2; save = ftell(ifp); if (mark == 0xc0 || mark == 0xc3 || mark == 0xc9) { fgetc(ifp); raw_height = get2(); raw_width = get2(); } order = get2(); hlen = get4(); if (get4() == 0x48454150 #ifdef LIBRAW_LIBRARY_BUILD && (save+hlen) >= 0 && (save+hlen)<=ifp->size() #endif ) /* "HEAP" */ { #ifdef LIBRAW_LIBRARY_BUILD imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens; #endif parse_ciff (save+hlen, len-hlen, 0); } if (parse_tiff (save+6)) apply_tiff(); fseek (ifp, save+len, SEEK_SET); } return 1; } void CLASS parse_riff() { unsigned i, size, end; char tag[4], date[64], month[64]; static const char mon[12][4] = { "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" }; struct tm t; order = 0x4949; fread (tag, 4, 1, ifp); size = get4(); end = ftell(ifp) + size; if (!memcmp(tag,"RIFF",4) || !memcmp(tag,"LIST",4)) { int maxloop = 1000; get4(); while (ftell(ifp)+7 < end && !feof(ifp) && maxloop--) parse_riff(); } else if (!memcmp(tag,"nctg",4)) { while (ftell(ifp)+7 < end) { i = get2(); size = get2(); if ((i+1) >> 1 == 10 && size == 20) get_timestamp(0); else fseek (ifp, size, SEEK_CUR); } } else if (!memcmp(tag,"IDIT",4) && size < 64) { fread (date, 64, 1, ifp); date[size] = 0; memset (&t, 0, sizeof t); if (sscanf (date, "%*s %s %d %d:%d:%d %d", month, &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec, &t.tm_year) == 6) { for (i=0; i < 12 && strcasecmp(mon[i],month); i++); t.tm_mon = i; t.tm_year -= 1900; if (mktime(&t) > 0) timestamp = mktime(&t); } } else fseek (ifp, size, SEEK_CUR); } void CLASS parse_qt (int end) { unsigned save, size; char tag[4]; order = 0x4d4d; while (ftell(ifp)+7 < end) { save = ftell(ifp); if ((size = get4()) < 8) return; fread (tag, 4, 1, ifp); if (!memcmp(tag,"moov",4) || !memcmp(tag,"udta",4) || !memcmp(tag,"CNTH",4)) parse_qt (save+size); if (!memcmp(tag,"CNDA",4)) parse_jpeg (ftell(ifp)); fseek (ifp, save+size, SEEK_SET); } } void CLASS parse_smal (int offset, int fsize) { int ver; fseek (ifp, offset+2, SEEK_SET); order = 0x4949; ver = fgetc(ifp); if (ver == 6) fseek (ifp, 5, SEEK_CUR); if (get4() != fsize) return; if (ver > 6) data_offset = get4(); raw_height = height = get2(); raw_width = width = get2(); strcpy (make, "SMaL"); sprintf (model, "v%d %dx%d", ver, width, height); if (ver == 6) load_raw = &CLASS smal_v6_load_raw; if (ver == 9) load_raw = &CLASS smal_v9_load_raw; } void CLASS parse_cine() { unsigned off_head, off_setup, off_image, i; order = 0x4949; fseek (ifp, 4, SEEK_SET); is_raw = get2() == 2; fseek (ifp, 14, SEEK_CUR); is_raw *= get4(); off_head = get4(); off_setup = get4(); off_image = get4(); timestamp = get4(); if ((i = get4())) timestamp = i; fseek (ifp, off_head+4, SEEK_SET); raw_width = get4(); raw_height = get4(); switch (get2(),get2()) { case 8: load_raw = &CLASS eight_bit_load_raw; break; case 16: load_raw = &CLASS unpacked_load_raw; } fseek (ifp, off_setup+792, SEEK_SET); strcpy (make, "CINE"); sprintf (model, "%d", get4()); fseek (ifp, 12, SEEK_CUR); switch ((i=get4()) & 0xffffff) { case 3: filters = 0x94949494; break; case 4: filters = 0x49494949; break; default: is_raw = 0; } fseek (ifp, 72, SEEK_CUR); switch ((get4()+3600) % 360) { case 270: flip = 4; break; case 180: flip = 1; break; case 90: flip = 7; break; case 0: flip = 2; } cam_mul[0] = getreal(11); cam_mul[2] = getreal(11); maximum = ~((~0u) << get4()); fseek (ifp, 668, SEEK_CUR); shutter = get4()/1000000000.0; fseek (ifp, off_image, SEEK_SET); if (shot_select < is_raw) fseek (ifp, shot_select*8, SEEK_CUR); data_offset = (INT64) get4() + 8; data_offset += (INT64) get4() << 32; } void CLASS parse_redcine() { unsigned i, len, rdvo; order = 0x4d4d; is_raw = 0; fseek (ifp, 52, SEEK_SET); width = get4(); height = get4(); fseek (ifp, 0, SEEK_END); fseek (ifp, -(i = ftello(ifp) & 511), SEEK_CUR); if (get4() != i || get4() != 0x52454f42) { #ifdef DCRAW_VERBOSE fprintf (stderr,_("%s: Tail is missing, parsing from head...\n"), ifname); #endif fseek (ifp, 0, SEEK_SET); while ((len = get4()) != EOF) { if (get4() == 0x52454456) if (is_raw++ == shot_select) data_offset = ftello(ifp) - 8; fseek (ifp, len-8, SEEK_CUR); } } else { rdvo = get4(); fseek (ifp, 12, SEEK_CUR); is_raw = get4(); fseeko (ifp, rdvo+8 + shot_select*4, SEEK_SET); data_offset = get4(); } } /* All matrices are from Adobe DNG Converter unless otherwise noted. */ void CLASS adobe_coeff (const char *t_make, const char *t_model #ifdef LIBRAW_LIBRARY_BUILD ,int internal_only #endif ) { static const struct { const char *prefix; int t_black, t_maximum, trans[12]; } table[] = { { "AgfaPhoto DC-833m", 0, 0, /* DJC */ { 11438,-3762,-1115,-2409,9914,2497,-1227,2295,5300 } }, { "Apple QuickTake", 0, 0, /* DJC */ { 21392,-5653,-3353,2406,8010,-415,7166,1427,2078 } }, {"Broadcom RPi IMX219", 66, 0x3ff, { 5302,1083,-728,-5320,14112,1699,-863,2371,5136 } }, /* LibRaw */ { "Broadcom RPi OV5647", 16, 0x3ff, { 12782,-4059,-379,-478,9066,1413,1340,1513,5176 } }, /* DJC */ { "Canon EOS D2000", 0, 0, { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } }, { "Canon EOS D6000", 0, 0, { 20482,-7172,-3125,-1033,10410,-285,2542,226,3136 } }, { "Canon EOS D30", 0, 0, { 9805,-2689,-1312,-5803,13064,3068,-2438,3075,8775 } }, { "Canon EOS D60", 0, 0xfa0, { 6188,-1341,-890,-7168,14489,2937,-2640,3228,8483 } }, { "Canon EOS 5DS", 0, 0x3c96, { 6250,-711,-808,-5153,12794,2636,-1249,2198,5610 } }, { "Canon EOS 5D Mark IV", 0, 0, { 6446, -366, -864, -4436, 12204, 2513, -952, 2496, 6348 }}, { "Canon EOS 5D Mark III", 0, 0x3c80, { 6722,-635,-963,-4287,12460,2028,-908,2162,5668 } }, { "Canon EOS 5D Mark II", 0, 0x3cf0, { 4716,603,-830,-7798,15474,2480,-1496,1937,6651 } }, { "Canon EOS 5D", 0, 0xe6c, { 6347,-479,-972,-8297,15954,2480,-1968,2131,7649 } }, { "Canon EOS 6D", 0, 0x3c82, { 8621,-2197,-787,-3150,11358,912,-1161,2400,4836 } }, { "Canon EOS 7D Mark II", 0, 0x3510, { 7268,-1082,-969,-4186,11839,2663,-825,2029,5839 } }, { "Canon EOS 7D", 0, 0x3510, { 6844,-996,-856,-3876,11761,2396,-593,1772,6198 } }, { "Canon EOS 80D", 0, 0, { 7457,-671,-937,-4849,12495,2643,-1213,2354,5492 } }, { "Canon EOS 10D", 0, 0xfa0, { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } }, { "Canon EOS 20Da", 0, 0, { 14155,-5065,-1382,-6550,14633,2039,-1623,1824,6561 } }, { "Canon EOS 20D", 0, 0xfff, { 6599,-537,-891,-8071,15783,2424,-1983,2234,7462 } }, { "Canon EOS 30D", 0, 0, { 6257,-303,-1000,-7880,15621,2396,-1714,1904,7046 } }, { "Canon EOS 40D", 0, 0x3f60, { 6071,-747,-856,-7653,15365,2441,-2025,2553,7315 } }, { "Canon EOS 50D", 0, 0x3d93, { 4920,616,-593,-6493,13964,2784,-1774,3178,7005 } }, { "Canon EOS 60D", 0, 0x2ff7, { 6719,-994,-925,-4408,12426,2211,-887,2129,6051 } }, { "Canon EOS 70D", 0, 0x3bc7, { 7034,-804,-1014,-4420,12564,2058,-851,1994,5758 } }, { "Canon EOS 100D", 0, 0x350f, { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } }, { "Canon EOS 300D", 0, 0xfa0, { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } }, { "Canon EOS 350D", 0, 0xfff, { 6018,-617,-965,-8645,15881,2975,-1530,1719,7642 } }, { "Canon EOS 400D", 0, 0xe8e, { 7054,-1501,-990,-8156,15544,2812,-1278,1414,7796 } }, { "Canon EOS 450D", 0, 0x390d, { 5784,-262,-821,-7539,15064,2672,-1982,2681,7427 } }, { "Canon EOS 500D", 0, 0x3479, { 4763,712,-646,-6821,14399,2640,-1921,3276,6561 } }, { "Canon EOS 550D", 0, 0x3dd7, { 6941,-1164,-857,-3825,11597,2534,-416,1540,6039 } }, { "Canon EOS 600D", 0, 0x3510, { 6461,-907,-882,-4300,12184,2378,-819,1944,5931 } }, { "Canon EOS 650D", 0, 0x354d, { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } }, { "Canon EOS 750D", 0, 0x3c00, { 6362,-823,-847,-4426,12109,2616,-743,1857,5635 } }, { "Canon EOS 760D", 0, 0x3c00, { 6362,-823,-847,-4426,12109,2616,-743,1857,5635 } }, { "Canon EOS 700D", 0, 0x3c00, { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } }, { "Canon EOS 1000D", 0, 0xe43, { 6771,-1139,-977,-7818,15123,2928,-1244,1437,7533 } }, { "Canon EOS 1100D", 0, 0x3510, { 6444,-904,-893,-4563,12308,2535,-903,2016,6728 } }, { "Canon EOS 1200D", 0, 0x37c2, { 6461,-907,-882,-4300,12184,2378,-819,1944,5931 } }, { "Canon EOS 1300D", 0, 0x37c2, { 6939, -1016, -866, -4428, 12473, 2177, -1175, 2178, 6162 } }, { "Canon EOS M3", 0, 0, { 6362,-823,-847,-4426,12109,2616,-743,1857,5635 } }, { "Canon EOS M5", 0, 0, /* Adobe */ { 8532, -701, -1167, -4095, 11879, 2508, -797, 2424, 7010 }}, { "Canon EOS M10", 0, 0, { 6400,-480,-888,-5294,13416,2047,-1296,2203,6137 } }, { "Canon EOS M", 0, 0, { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } }, { "Canon EOS-1Ds Mark III", 0, 0x3bb0, { 5859,-211,-930,-8255,16017,2353,-1732,1887,7448 } }, { "Canon EOS-1Ds Mark II", 0, 0xe80, { 6517,-602,-867,-8180,15926,2378,-1618,1771,7633 } }, { "Canon EOS-1D Mark IV", 0, 0x3bb0, { 6014,-220,-795,-4109,12014,2361,-561,1824,5787 } }, { "Canon EOS-1D Mark III", 0, 0x3bb0, { 6291,-540,-976,-8350,16145,2311,-1714,1858,7326 } }, { "Canon EOS-1D Mark II N", 0, 0xe80, { 6240,-466,-822,-8180,15825,2500,-1801,1938,8042 } }, { "Canon EOS-1D Mark II", 0, 0xe80, { 6264,-582,-724,-8312,15948,2504,-1744,1919,8664 } }, { "Canon EOS-1DS", 0, 0xe20, { 4374,3631,-1743,-7520,15212,2472,-2892,3632,8161 } }, { "Canon EOS-1D C", 0, 0x3c4e, { 6847,-614,-1014,-4669,12737,2139,-1197,2488,6846 } }, { "Canon EOS-1D X Mark II", 0, 0x3c4e, { 7596,-978,967,-4808,12571,2503,-1398,2567,5752 } }, { "Canon EOS-1D X", 0, 0x3c4e, { 6847,-614,-1014,-4669,12737,2139,-1197,2488,6846 } }, { "Canon EOS-1D", 0, 0xe20, { 6806,-179,-1020,-8097,16415,1687,-3267,4236,7690 } }, { "Canon EOS C500", 853, 0, /* DJC */ { 17851,-10604,922,-7425,16662,763,-3660,3636,22278 } }, { "Canon PowerShot A530", 0, 0, { 0 } }, /* don't want the A5 matrix */ { "Canon PowerShot A50", 0, 0, { -5300,9846,1776,3436,684,3939,-5540,9879,6200,-1404,11175,217 } }, { "Canon PowerShot A5", 0, 0, { -4801,9475,1952,2926,1611,4094,-5259,10164,5947,-1554,10883,547 } }, { "Canon PowerShot G10", 0, 0, { 11093,-3906,-1028,-5047,12492,2879,-1003,1750,5561 } }, { "Canon PowerShot G11", 0, 0, { 12177,-4817,-1069,-1612,9864,2049,-98,850,4471 } }, { "Canon PowerShot G12", 0, 0, { 13244,-5501,-1248,-1508,9858,1935,-270,1083,4366 } }, { "Canon PowerShot G15", 0, 0, { 7474,-2301,-567,-4056,11456,2975,-222,716,4181 } }, { "Canon PowerShot G16", 0, 0, { 14130,-8071,127,2199,6528,1551,3402,-1721,4960 } }, { "Canon PowerShot G1 X Mark II", 0, 0, { 7378,-1255,-1043,-4088,12251,2048,-876,1946,5805 } }, { "Canon PowerShot G1 X", 0, 0, { 7378,-1255,-1043,-4088,12251,2048,-876,1946,5805 } }, { "Canon PowerShot G1", 0, 0, { -4778,9467,2172,4743,-1141,4344,-5146,9908,6077,-1566,11051,557 } }, { "Canon PowerShot G2", 0, 0, { 9087,-2693,-1049,-6715,14382,2537,-2291,2819,7790 } }, { "Canon PowerShot G3 X", 0, 0, { 9701,-3857,-921,-3149,11537,1817,-786,1817,5147 } }, { "Canon PowerShot G3", 0, 0, { 9212,-2781,-1073,-6573,14189,2605,-2300,2844,7664 } }, { "Canon PowerShot G5 X",0, 0, { 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 } }, { "Canon PowerShot G5", 0, 0, { 9757,-2872,-933,-5972,13861,2301,-1622,2328,7212 } }, { "Canon PowerShot G6", 0, 0, { 9877,-3775,-871,-7613,14807,3072,-1448,1305,7485 } }, { "Canon PowerShot G7 X Mark II", 0, 0, { 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 } }, { "Canon PowerShot G7 X", 0, 0, { 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 } }, { "Canon PowerShot G9 X",0, 0, { 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 } }, { "Canon PowerShot G9", 0, 0, { 7368,-2141,-598,-5621,13254,2625,-1418,1696,5743 } }, { "Canon PowerShot Pro1", 0, 0, { 10062,-3522,-999,-7643,15117,2730,-765,817,7323 } }, { "Canon PowerShot Pro70", 34, 0, { -4155,9818,1529,3939,-25,4522,-5521,9870,6610,-2238,10873,1342 } }, { "Canon PowerShot Pro90", 0, 0, { -4963,9896,2235,4642,-987,4294,-5162,10011,5859,-1770,11230,577 } }, { "Canon PowerShot S30", 0, 0, { 10566,-3652,-1129,-6552,14662,2006,-2197,2581,7670 } }, { "Canon PowerShot S40", 0, 0, { 8510,-2487,-940,-6869,14231,2900,-2318,2829,9013 } }, { "Canon PowerShot S45", 0, 0, { 8163,-2333,-955,-6682,14174,2751,-2077,2597,8041 } }, { "Canon PowerShot S50", 0, 0, { 8882,-2571,-863,-6348,14234,2288,-1516,2172,6569 } }, { "Canon PowerShot S60", 0, 0, { 8795,-2482,-797,-7804,15403,2573,-1422,1996,7082 } }, { "Canon PowerShot S70", 0, 0, { 9976,-3810,-832,-7115,14463,2906,-901,989,7889 } }, { "Canon PowerShot S90", 0, 0, { 12374,-5016,-1049,-1677,9902,2078,-83,852,4683 } }, { "Canon PowerShot S95", 0, 0, { 13440,-5896,-1279,-1236,9598,1931,-180,1001,4651 } }, { "Canon PowerShot S120", 0, 0, { 6961,-1685,-695,-4625,12945,1836,-1114,2152,5518 } }, { "Canon PowerShot S110", 0, 0, { 8039,-2643,-654,-3783,11230,2930,-206,690,4194 } }, { "Canon PowerShot S100", 0, 0, { 7968,-2565,-636,-2873,10697,2513,180,667,4211 } }, { "Canon PowerShot SX1 IS", 0, 0, { 6578,-259,-502,-5974,13030,3309,-308,1058,4970 } }, { "Canon PowerShot SX50 HS", 0, 0, { 12432,-4753,-1247,-2110,10691,1629,-412,1623,4926 } }, { "Canon PowerShot SX60 HS", 0, 0, { 13161,-5451,-1344,-1989,10654,1531,-47,1271,4955 } }, { "Canon PowerShot A3300", 0, 0, /* DJC */ { 10826,-3654,-1023,-3215,11310,1906,0,999,4960 } }, { "Canon PowerShot A470", 0, 0, /* DJC */ { 12513,-4407,-1242,-2680,10276,2405,-878,2215,4734 } }, { "Canon PowerShot A610", 0, 0, /* DJC */ { 15591,-6402,-1592,-5365,13198,2168,-1300,1824,5075 } }, { "Canon PowerShot A620", 0, 0, /* DJC */ { 15265,-6193,-1558,-4125,12116,2010,-888,1639,5220 } }, { "Canon PowerShot A630", 0, 0, /* DJC */ { 14201,-5308,-1757,-6087,14472,1617,-2191,3105,5348 } }, { "Canon PowerShot A640", 0, 0, /* DJC */ { 13124,-5329,-1390,-3602,11658,1944,-1612,2863,4885 } }, { "Canon PowerShot A650", 0, 0, /* DJC */ { 9427,-3036,-959,-2581,10671,1911,-1039,1982,4430 } }, { "Canon PowerShot A720", 0, 0, /* DJC */ { 14573,-5482,-1546,-1266,9799,1468,-1040,1912,3810 } }, { "Canon PowerShot S3 IS", 0, 0, /* DJC */ { 14062,-5199,-1446,-4712,12470,2243,-1286,2028,4836 } }, { "Canon PowerShot SX110 IS", 0, 0, /* DJC */ { 14134,-5576,-1527,-1991,10719,1273,-1158,1929,3581 } }, { "Canon PowerShot SX220", 0, 0, /* DJC */ { 13898,-5076,-1447,-1405,10109,1297,-244,1860,3687 } }, { "Canon IXUS 160", 0, 0, /* DJC */ { 11657,-3781,-1136,-3544,11262,2283,-160,1219,4700 } }, { "Casio EX-S20", 0, 0, /* DJC */ { 11634,-3924,-1128,-4968,12954,2015,-1588,2648,7206 } }, { "Casio EX-Z750", 0, 0, /* DJC */ { 10819,-3873,-1099,-4903,13730,1175,-1755,3751,4632 } }, { "Casio EX-Z10", 128, 0xfff, /* DJC */ { 9790,-3338,-603,-2321,10222,2099,-344,1273,4799 } }, { "CINE 650", 0, 0, { 3390,480,-500,-800,3610,340,-550,2336,1192 } }, { "CINE 660", 0, 0, { 3390,480,-500,-800,3610,340,-550,2336,1192 } }, { "CINE", 0, 0, { 20183,-4295,-423,-3940,15330,3985,-280,4870,9800 } }, { "Contax N Digital", 0, 0xf1e, { 7777,1285,-1053,-9280,16543,2916,-3677,5679,7060 } }, { "DXO ONE", 0, 0, { 6596,-2079,-562,-4782,13016,1933,-970,1581,5181 } }, { "Epson R-D1", 0, 0, { 6827,-1878,-732,-8429,16012,2564,-704,592,7145 } }, { "Fujifilm E550", 0, 0, { 11044,-3888,-1120,-7248,15168,2208,-1531,2277,8069 } }, { "Fujifilm E900", 0, 0, { 9183,-2526,-1078,-7461,15071,2574,-2022,2440,8639 } }, { "Fujifilm F5", 0, 0, { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, { "Fujifilm F6", 0, 0, { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, { "Fujifilm F77", 0, 0xfe9, { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, { "Fujifilm F7", 0, 0, { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } }, { "Fujifilm F8", 0, 0, { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, { "Fujifilm S100FS", 514, 0, { 11521,-4355,-1065,-6524,13767,3058,-1466,1984,6045 } }, { "Fujifilm S1", 0, 0, { 12297,-4882,-1202,-2106,10691,1623,-88,1312,4790 } }, { "Fujifilm S20Pro", 0, 0, { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } }, { "Fujifilm S20", 512, 0x3fff, { 11401,-4498,-1312,-5088,12751,2613,-838,1568,5941 } }, { "Fujifilm S2Pro", 128, 0, { 12492,-4690,-1402,-7033,15423,1647,-1507,2111,7697 } }, { "Fujifilm S3Pro", 0, 0, { 11807,-4612,-1294,-8927,16968,1988,-2120,2741,8006 } }, { "Fujifilm S5Pro", 0, 0, { 12300,-5110,-1304,-9117,17143,1998,-1947,2448,8100 } }, { "Fujifilm S5000", 0, 0, { 8754,-2732,-1019,-7204,15069,2276,-1702,2334,6982 } }, { "Fujifilm S5100", 0, 0, { 11940,-4431,-1255,-6766,14428,2542,-993,1165,7421 } }, { "Fujifilm S5500", 0, 0, { 11940,-4431,-1255,-6766,14428,2542,-993,1165,7421 } }, { "Fujifilm S5200", 0, 0, { 9636,-2804,-988,-7442,15040,2589,-1803,2311,8621 } }, { "Fujifilm S5600", 0, 0, { 9636,-2804,-988,-7442,15040,2589,-1803,2311,8621 } }, { "Fujifilm S6", 0, 0, { 12628,-4887,-1401,-6861,14996,1962,-2198,2782,7091 } }, { "Fujifilm S7000", 0, 0, { 10190,-3506,-1312,-7153,15051,2238,-2003,2399,7505 } }, { "Fujifilm S9000", 0, 0, { 10491,-3423,-1145,-7385,15027,2538,-1809,2275,8692 } }, { "Fujifilm S9500", 0, 0, { 10491,-3423,-1145,-7385,15027,2538,-1809,2275,8692 } }, { "Fujifilm S9100", 0, 0, { 12343,-4515,-1285,-7165,14899,2435,-1895,2496,8800 } }, { "Fujifilm S9600", 0, 0, { 12343,-4515,-1285,-7165,14899,2435,-1895,2496,8800 } }, { "Fujifilm SL1000", 0, 0, { 11705,-4262,-1107,-2282,10791,1709,-555,1713,4945 } }, { "Fujifilm IS-1", 0, 0, { 21461,-10807,-1441,-2332,10599,1999,289,875,7703 } }, { "Fujifilm IS Pro", 0, 0, { 12300,-5110,-1304,-9117,17143,1998,-1947,2448,8100 } }, { "Fujifilm HS10 HS11", 0, 0xf68, { 12440,-3954,-1183,-1123,9674,1708,-83,1614,4086 } }, { "Fujifilm HS2", 0, 0, { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, { "Fujifilm HS3", 0, 0, { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, { "Fujifilm HS50EXR", 0, 0, { 12085,-4727,-953,-3257,11489,2002,-511,2046,4592 } }, { "Fujifilm F900EXR", 0, 0, { 12085,-4727,-953,-3257,11489,2002,-511,2046,4592 } }, { "Fujifilm X100S", 0, 0, { 10592,-4262,-1008,-3514,11355,2465,-870,2025,6386 } }, { "Fujifilm X100T", 0, 0, { 10592,-4262,-1008,-3514,11355,2465,-870,2025,6386 } }, { "Fujifilm X100", 0, 0, { 12161,-4457,-1069,-5034,12874,2400,-795,1724,6904 } }, { "Fujifilm X10", 0, 0, { 13509,-6199,-1254,-4430,12733,1865,-331,1441,5022 } }, { "Fujifilm X20", 0, 0, { 11768,-4971,-1133,-4904,12927,2183,-480,1723,4605 } }, { "Fujifilm X30", 0, 0, { 12328,-5256,-1144,-4469,12927,1675,-87,1291,4351 } }, { "Fujifilm X70", 0, 0, { 10450,-4329,-878,-3217,11105,2421,-752,1758,6519 } }, { "Fujifilm X-Pro1", 0, 0, { 10413,-3996,-993,-3721,11640,2361,-733,1540,6011 } }, { "Fujifilm X-Pro2", 0, 0, { 11434,-4948,-1210,-3746,12042,1903,-666,1479,5235 } }, { "Fujifilm X-A1", 0, 0, { 11086,-4555,-839,-3512,11310,2517,-815,1341,5940 } }, { "Fujifilm X-A2", 0, 0, { 10763,-4560,-917,-3346,11311,2322,-475,1135,5843 } }, { "Fujifilm X-E1", 0, 0, { 10413,-3996,-993,-3721,11640,2361,-733,1540,6011 } }, { "Fujifilm X-E2S", 0, 0, { 11562,-5118,-961,-3022,11007,2311,-525,1569,6097 } }, { "Fujifilm X-E2", 0, 0, { 12066,-5927,-367,-1969,9878,1503,-721,2034,5453 } }, { "Fujifilm XF1", 0, 0, { 13509,-6199,-1254,-4430,12733,1865,-331,1441,5022 } }, { "Fujifilm X-M1", 0, 0, { 13193,-6685,-425,-2229,10458,1534,-878,1763,5217 } }, { "Fujifilm X-S1", 0, 0, { 13509,-6199,-1254,-4430,12733,1865,-331,1441,5022 } }, { "Fujifilm X-T10", 0, 0, { 10763,-4560,-917,-3346,11311,2322,-475,1135,5843 } }, { "Fujifilm X-T1", 0, 0, { 8458,-2451,-855,-4597,12447,2407,-1475,2482,6526 } }, { "Fujifilm X-T2", 0, 0, { 11434,-4948,-1210,-3746,12042,1903,-666,1479,5235 } }, { "Fujifilm XQ1", 0, 0, { 9252,-2704,-1064,-5893,14265,1717,-1101,2341,4349 } }, { "Fujifilm XQ2", 0, 0, { 9252,-2704,-1064,-5893,14265,1717,-1101,2341,4349 } }, { "GITUP GIT2", 3200, 0, {8489, -2583,-1036,-8051,15583,2643,-1307,1407,7354}}, { "Hasselblad Lunar", 0, 0, { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } }, { "Hasselblad Stellar", -800, 0, { 8651,-2754,-1057,-3464,12207,1373,-568,1398,4434 } }, { "Hasselblad CFV", 0, 0, /* Adobe */ { 8519, -3260, -280, -5081, 13459, 1738, -1449, 2960, 7809, } }, { "Hasselblad H-16MP", 0, 0, /* LibRaw */ { 17765,-5322,-1734,-6168,13354,2135,-264,2524,7440 } }, { "Hasselblad H-22MP", 0, 0, /* LibRaw */ { 17765,-5322,-1734,-6168,13354,2135,-264,2524,7440 } }, { "Hasselblad H-31MP",0, 0, /* LibRaw */ { 14480,-5448,-1686,-3534,13123,2260,384,2952,7232 } }, { "Hasselblad H-39MP",0, 0, /* Adobe */ { 3857,452, -46, -6008, 14477, 1596, -2627, 4481, 5718 } }, { "Hasselblad H3D-50", 0, 0, /* Adobe */ { 3857,452, -46, -6008, 14477, 1596, -2627, 4481, 5718 } }, { "Hasselblad H4D-40",0, 0, /* LibRaw */ { 6325,-860,-957,-6559,15945,266,167,770,5936 } }, { "Hasselblad H4D-50",0, 0, /* LibRaw */ { 15283,-6272,-465,-2030,16031,478,-2379,390,7965 } }, { "Hasselblad H4D-60",0, 0, /* Adobe */ { 9662, -684, -279, -4903, 12293, 2950, -344, 1669, 6024 } }, { "Hasselblad H5D-50c",0, 0, /* Adobe */ { 4932, -835, 141, -4878, 11868, 3437, -1138, 1961, 7067 } }, { "Hasselblad H5D-50",0, 0, /* Adobe */ { 5656, -659, -346, -3923, 12306, 1791, -1602, 3509, 5442 } }, { "Hasselblad X1D",0, 0, /* Adobe */ {4932, -835, 141, -4878, 11868, 3437, -1138, 1961, 7067 }}, { "HTC One A9", 64, 1023, /* this is CM1 transposed */ { 101, -20, -2, -11, 145, 41, -24, 1, 56 } }, { "Imacon Ixpress", 0, 0, /* DJC */ { 7025,-1415,-704,-5188,13765,1424,-1248,2742,6038 } }, { "Kodak NC2000", 0, 0, { 13891,-6055,-803,-465,9919,642,2121,82,1291 } }, { "Kodak DCS315C", -8, 0, { 17523,-4827,-2510,756,8546,-137,6113,1649,2250 } }, { "Kodak DCS330C", -8, 0, { 20620,-7572,-2801,-103,10073,-396,3551,-233,2220 } }, { "Kodak DCS420", 0, 0, { 10868,-1852,-644,-1537,11083,484,2343,628,2216 } }, { "Kodak DCS460", 0, 0, { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } }, { "Kodak EOSDCS1", 0, 0, { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } }, { "Kodak EOSDCS3B", 0, 0, { 9898,-2700,-940,-2478,12219,206,1985,634,1031 } }, { "Kodak DCS520C", -178, 0, { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } }, { "Kodak DCS560C", -177, 0, { 20482,-7172,-3125,-1033,10410,-285,2542,226,3136 } }, { "Kodak DCS620C", -177, 0, { 23617,-10175,-3149,-2054,11749,-272,2586,-489,3453 } }, { "Kodak DCS620X", -176, 0, { 13095,-6231,154,12221,-21,-2137,895,4602,2258 } }, { "Kodak DCS660C", -173, 0, { 18244,-6351,-2739,-791,11193,-521,3711,-129,2802 } }, { "Kodak DCS720X", 0, 0, { 11775,-5884,950,9556,1846,-1286,-1019,6221,2728 } }, { "Kodak DCS760C", 0, 0, { 16623,-6309,-1411,-4344,13923,323,2285,274,2926 } }, { "Kodak DCS Pro SLR", 0, 0, { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } }, { "Kodak DCS Pro 14nx", 0, 0, { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } }, { "Kodak DCS Pro 14", 0, 0, { 7791,3128,-776,-8588,16458,2039,-2455,4006,6198 } }, { "Kodak ProBack645", 0, 0, { 16414,-6060,-1470,-3555,13037,473,2545,122,4948 } }, { "Kodak ProBack", 0, 0, { 21179,-8316,-2918,-915,11019,-165,3477,-180,4210 } }, { "Kodak P712", 0, 0, { 9658,-3314,-823,-5163,12695,2768,-1342,1843,6044 } }, { "Kodak P850", 0, 0xf7c, { 10511,-3836,-1102,-6946,14587,2558,-1481,1792,6246 } }, { "Kodak P880", 0, 0xfff, { 12805,-4662,-1376,-7480,15267,2360,-1626,2194,7904 } }, { "Kodak EasyShare Z980", 0, 0, { 11313,-3559,-1101,-3893,11891,2257,-1214,2398,4908 } }, { "Kodak EasyShare Z981", 0, 0, { 12729,-4717,-1188,-1367,9187,2582,274,860,4411 } }, { "Kodak EasyShare Z990", 0, 0xfed, { 11749,-4048,-1309,-1867,10572,1489,-138,1449,4522 } }, { "Kodak EASYSHARE Z1015", 0, 0xef1, { 11265,-4286,-992,-4694,12343,2647,-1090,1523,5447 } }, { "Leaf CMost", 0, 0, { 3952,2189,449,-6701,14585,2275,-4536,7349,6536 } }, { "Leaf Valeo 6", 0, 0, { 3952,2189,449,-6701,14585,2275,-4536,7349,6536 } }, { "Leaf Aptus 54S", 0, 0, { 8236,1746,-1314,-8251,15953,2428,-3673,5786,5771 } }, { "Leaf Aptus 65", 0, 0, { 7914,1414,-1190,-8777,16582,2280,-2811,4605,5562 } }, { "Leaf Aptus 75", 0, 0, { 7914,1414,-1190,-8777,16582,2280,-2811,4605,5562 } }, { "Leaf Credo 40", 0, 0, { 8035, 435, -962, -6001, 13872, 2320, -1159, 3065, 5434 } }, { "Leaf Credo 50", 0, 0, { 3984, 0, 0, 0, 10000, 0, 0, 0, 7666 } }, { "Leaf Credo 60", 0, 0, { 8035, 435, -962, -6001, 13872,2320,-1159,3065,5434 } }, { "Leaf Credo 80", 0, 0, { 6294, 686, -712, -5435, 13417, 2211, -1006, 2435, 5042 } }, { "Leaf", 0, 0, { 8236,1746,-1314,-8251,15953,2428,-3673,5786,5771 } }, { "Mamiya ZD", 0, 0, { 7645,2579,-1363,-8689,16717,2015,-3712,5941,5961 } }, { "Micron 2010", 110, 0, /* DJC */ { 16695,-3761,-2151,155,9682,163,3433,951,4904 } }, { "Minolta DiMAGE 5", 0, 0xf7d, { 8983,-2942,-963,-6556,14476,2237,-2426,2887,8014 } }, { "Minolta DiMAGE 7Hi", 0, 0xf7d, { 11368,-3894,-1242,-6521,14358,2339,-2475,3056,7285 } }, { "Minolta DiMAGE 7", 0, 0xf7d, { 9144,-2777,-998,-6676,14556,2281,-2470,3019,7744 } }, { "Minolta DiMAGE A1", 0, 0xf8b, { 9274,-2547,-1167,-8220,16323,1943,-2273,2720,8340 } }, { "Minolta DiMAGE A200", 0, 0, { 8560,-2487,-986,-8112,15535,2771,-1209,1324,7743 } }, { "Minolta DiMAGE A2", 0, 0xf8f, { 9097,-2726,-1053,-8073,15506,2762,-966,981,7763 } }, { "Minolta DiMAGE Z2", 0, 0, /* DJC */ { 11280,-3564,-1370,-4655,12374,2282,-1423,2168,5396 } }, { "Minolta DYNAX 5", 0, 0xffb, { 10284,-3283,-1086,-7957,15762,2316,-829,882,6644 } }, { "Minolta DYNAX 7", 0, 0xffb, { 10239,-3104,-1099,-8037,15727,2451,-927,925,6871 } }, { "Motorola PIXL", 0, 0, /* DJC */ { 8898,-989,-1033,-3292,11619,1674,-661,3178,5216 } }, { "Nikon D100", 0, 0, { 5902,-933,-782,-8983,16719,2354,-1402,1455,6464 } }, { "Nikon D1H", 0, 0, { 7577,-2166,-926,-7454,15592,1934,-2377,2808,8606 } }, { "Nikon D1X", 0, 0, { 7702,-2245,-975,-9114,17242,1875,-2679,3055,8521 } }, { "Nikon D1", 0, 0, /* multiplied by 2.218750, 1.0, 1.148438 */ { 16772,-4726,-2141,-7611,15713,1972,-2846,3494,9521 } }, { "Nikon D200", 0, 0xfbc, { 8367,-2248,-763,-8758,16447,2422,-1527,1550,8053 } }, { "Nikon D2H", 0, 0, { 5710,-901,-615,-8594,16617,2024,-2975,4120,6830 } }, { "Nikon D2X", 0, 0, { 10231,-2769,-1255,-8301,15900,2552,-797,680,7148 } }, { "Nikon D3000", 0, 0, { 8736,-2458,-935,-9075,16894,2251,-1354,1242,8263 } }, { "Nikon D3100", 0, 0, { 7911,-2167,-813,-5327,13150,2408,-1288,2483,7968 } }, { "Nikon D3200", 0, 0xfb9, { 7013,-1408,-635,-5268,12902,2640,-1470,2801,7379 } }, { "Nikon D3300", 0, 0, { 6988,-1384,-714,-5631,13410,2447,-1485,2204,7318 } }, { "Nikon D3400", 0, 0, { 6988,-1384,-714,-5631,13410,2447,-1485,2204,7318 } }, { "Nikon D300", 0, 0, { 9030,-1992,-715,-8465,16302,2255,-2689,3217,8069 } }, { "Nikon D3X", 0, 0, { 7171,-1986,-648,-8085,15555,2718,-2170,2512,7457 } }, { "Nikon D3S", 0, 0, { 8828,-2406,-694,-4874,12603,2541,-660,1509,7587 } }, { "Nikon D3", 0, 0, { 8139,-2171,-663,-8747,16541,2295,-1925,2008,8093 } }, { "Nikon D40X", 0, 0, { 8819,-2543,-911,-9025,16928,2151,-1329,1213,8449 } }, { "Nikon D40", 0, 0, { 6992,-1668,-806,-8138,15748,2543,-874,850,7897 } }, { "Nikon D4S", 0, 0, { 8598,-2848,-857,-5618,13606,2195,-1002,1773,7137 } }, { "Nikon D4", 0, 0, { 8598,-2848,-857,-5618,13606,2195,-1002,1773,7137 } }, { "Nikon Df", 0, 0, { 8598,-2848,-857,-5618,13606,2195,-1002,1773,7137 } }, { "Nikon D5000", 0, 0xf00, { 7309,-1403,-519,-8474,16008,2622,-2433,2826,8064 } }, { "Nikon D5100", 0, 0x3de6, { 8198,-2239,-724,-4871,12389,2798,-1043,2050,7181 } }, { "Nikon D5200", 0, 0, { 8322,-3112,-1047,-6367,14342,2179,-988,1638,6394 } }, { "Nikon D5300", 0, 0, { 6988,-1384,-714,-5631,13410,2447,-1485,2204,7318 } }, { "Nikon D5500", 0, 0, { 8821,-2938,-785,-4178,12142,2287,-824,1651,6860 } }, { "Nikon D500", 0, 0, { 8813,-3210,-1036,-4703,12868,2021,-1054,1940,6129 } }, { "Nikon D50", 0, 0, { 7732,-2422,-789,-8238,15884,2498,-859,783,7330 } }, { "Nikon D5", 0, 0, { 9200,-3522,-992,-5755,13803,2117,-753,1486,6338 } }, { "Nikon D600", 0, 0x3e07, { 8178,-2245,-609,-4857,12394,2776,-1207,2086,7298 } }, { "Nikon D610",0, 0, { 10426,-4005,-444,-3565,11764,1403,-1206,2266,6549 } }, { "Nikon D60", 0, 0, { 8736,-2458,-935,-9075,16894,2251,-1354,1242,8263 } }, { "Nikon D7000", 0, 0, { 8198,-2239,-724,-4871,12389,2798,-1043,2050,7181 } }, { "Nikon D7100", 0, 0, { 8322,-3112,-1047,-6367,14342,2179,-988,1638,6394 } }, { "Nikon D7200", 0, 0, { 8322,-3112,-1047,-6367,14342,2179,-988,1638,6394 } }, { "Nikon D750", -600, 0, { 9020,-2890,-715,-4535,12436,2348,-934,1919,7086 } }, { "Nikon D700", 0, 0, { 8139,-2171,-663,-8747,16541,2295,-1925,2008,8093 } }, { "Nikon D70", 0, 0, { 7732,-2422,-789,-8238,15884,2498,-859,783,7330 } }, { "Nikon D810A", 0, 0, { 11973, -5685, -888, -1965, 10326, 1901, -115, 1123, 7169 } }, { "Nikon D810", 0, 0, { 9369,-3195,-791,-4488,12430,2301,-893,1796,6872 } }, { "Nikon D800", 0, 0, { 7866,-2108,-555,-4869,12483,2681,-1176,2069,7501 } }, { "Nikon D80", 0, 0, { 8629,-2410,-883,-9055,16940,2171,-1490,1363,8520 } }, { "Nikon D90", 0, 0xf00, { 7309,-1403,-519,-8474,16008,2622,-2434,2826,8064 } }, { "Nikon E700", 0, 0x3dd, /* DJC */ { -3746,10611,1665,9621,-1734,2114,-2389,7082,3064,3406,6116,-244 } }, { "Nikon E800", 0, 0x3dd, /* DJC */ { -3746,10611,1665,9621,-1734,2114,-2389,7082,3064,3406,6116,-244 } }, { "Nikon E950", 0, 0x3dd, /* DJC */ { -3746,10611,1665,9621,-1734,2114,-2389,7082,3064,3406,6116,-244 } }, { "Nikon E995", 0, 0, /* copied from E5000 */ { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, { "Nikon E2100", 0, 0, /* copied from Z2, new white balance */ { 13142,-4152,-1596,-4655,12374,2282,-1769,2696,6711 } }, { "Nikon E2500", 0, 0, { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, { "Nikon E3200", 0, 0, /* DJC */ { 9846,-2085,-1019,-3278,11109,2170,-774,2134,5745 } }, { "Nikon E4300", 0, 0, /* copied from Minolta DiMAGE Z2 */ { 11280,-3564,-1370,-4655,12374,2282,-1423,2168,5396 } }, { "Nikon E4500", 0, 0, { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, { "Nikon E5000", 0, 0, { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, { "Nikon E5400", 0, 0, { 9349,-2987,-1001,-7919,15766,2266,-2098,2680,6839 } }, { "Nikon E5700", 0, 0, { -5368,11478,2368,5537,-113,3148,-4969,10021,5782,778,9028,211 } }, { "Nikon E8400", 0, 0, { 7842,-2320,-992,-8154,15718,2599,-1098,1342,7560 } }, { "Nikon E8700", 0, 0, { 8489,-2583,-1036,-8051,15583,2643,-1307,1407,7354 } }, { "Nikon E8800", 0, 0, { 7971,-2314,-913,-8451,15762,2894,-1442,1520,7610 } }, { "Nikon COOLPIX A", 0, 0, { 8198,-2239,-724,-4871,12389,2798,-1043,2050,7181 } }, { "Nikon COOLPIX B700", 0, 0, { 14387,-6014,-1299,-1357,9975,1616,467,1047,4744 } }, { "Nikon COOLPIX P330", -200, 0, { 10321,-3920,-931,-2750,11146,1824,-442,1545,5539 } }, { "Nikon COOLPIX P340", -200, 0, { 10321,-3920,-931,-2750,11146,1824,-442,1545,5539 } }, { "Nikon COOLPIX P6000", 0, 0, { 9698,-3367,-914,-4706,12584,2368,-837,968,5801 } }, { "Nikon COOLPIX P7000", 0, 0, { 11432,-3679,-1111,-3169,11239,2202,-791,1380,4455 } }, { "Nikon COOLPIX P7100", 0, 0, { 11053,-4269,-1024,-1976,10182,2088,-526,1263,4469 } }, { "Nikon COOLPIX P7700", -3200, 0, { 10321,-3920,-931,-2750,11146,1824,-442,1545,5539 } }, { "Nikon COOLPIX P7800", -3200, 0, { 10321,-3920,-931,-2750,11146,1824,-442,1545,5539 } }, { "Nikon 1 V3", -200, 0, { 5958,-1559,-571,-4021,11453,2939,-634,1548,5087 } }, { "Nikon 1 J4", 0, 0, { 5958,-1559,-571,-4021,11453,2939,-634,1548,5087 } }, { "Nikon 1 J5", 0, 0, { 7520,-2518,-645,-3844,12102,1945,-913,2249,6835} }, { "Nikon 1 S2", -200, 0, { 6612,-1342,-618,-3338,11055,2623,-174,1792,5075 } }, { "Nikon 1 V2", 0, 0, { 6588,-1305,-693,-3277,10987,2634,-355,2016,5106 } }, { "Nikon 1 J3", 0, 0, { 8144,-2671,-473,-1740,9834,1601,-58,1971,4296 } }, { "Nikon 1 AW1", 0, 0, { 6588,-1305,-693,-3277,10987,2634,-355,2016,5106 } }, { "Nikon 1 ", 0, 0, /* J1, J2, S1, V1 */ { 8994,-2667,-865,-4594,12324,2552,-699,1786,6260 } }, { "Olympus AIR-A01", 0, 0xfe1, { 8992,-3093,-639,-2563,10721,2122,-437,1270,5473 } }, { "Olympus C5050", 0, 0, { 10508,-3124,-1273,-6079,14294,1901,-1653,2306,6237 } }, { "Olympus C5060", 0, 0, { 10445,-3362,-1307,-7662,15690,2058,-1135,1176,7602 } }, { "Olympus C7070", 0, 0, { 10252,-3531,-1095,-7114,14850,2436,-1451,1723,6365 } }, { "Olympus C70", 0, 0, { 10793,-3791,-1146,-7498,15177,2488,-1390,1577,7321 } }, { "Olympus C80", 0, 0, { 8606,-2509,-1014,-8238,15714,2703,-942,979,7760 } }, { "Olympus E-10", 0, 0xffc, { 12745,-4500,-1416,-6062,14542,1580,-1934,2256,6603 } }, { "Olympus E-1", 0, 0, { 11846,-4767,-945,-7027,15878,1089,-2699,4122,8311 } }, { "Olympus E-20", 0, 0xffc, { 13173,-4732,-1499,-5807,14036,1895,-2045,2452,7142 } }, { "Olympus E-300", 0, 0, { 7828,-1761,-348,-5788,14071,1830,-2853,4518,6557 } }, { "Olympus E-330", 0, 0, { 8961,-2473,-1084,-7979,15990,2067,-2319,3035,8249 } }, { "Olympus E-30", 0, 0xfbc, { 8144,-1861,-1111,-7763,15894,1929,-1865,2542,7607 } }, { "Olympus E-3", 0, 0xf99, { 9487,-2875,-1115,-7533,15606,2010,-1618,2100,7389 } }, { "Olympus E-400", 0, 0, { 6169,-1483,-21,-7107,14761,2536,-2904,3580,8568 } }, { "Olympus E-410", 0, 0xf6a, { 8856,-2582,-1026,-7761,15766,2082,-2009,2575,7469 } }, { "Olympus E-420", 0, 0xfd7, { 8746,-2425,-1095,-7594,15612,2073,-1780,2309,7416 } }, { "Olympus E-450", 0, 0xfd2, { 8745,-2425,-1095,-7594,15613,2073,-1780,2309,7416 } }, { "Olympus E-500", 0, 0, { 8136,-1968,-299,-5481,13742,1871,-2556,4205,6630 } }, { "Olympus E-510", 0, 0xf6a, { 8785,-2529,-1033,-7639,15624,2112,-1783,2300,7817 } }, { "Olympus E-520", 0, 0xfd2, { 8344,-2322,-1020,-7596,15635,2048,-1748,2269,7287 } }, { "Olympus E-5", 0, 0xeec, { 11200,-3783,-1325,-4576,12593,2206,-695,1742,7504 } }, { "Olympus E-600", 0, 0xfaf, { 8453,-2198,-1092,-7609,15681,2008,-1725,2337,7824 } }, { "Olympus E-620", 0, 0xfaf, { 8453,-2198,-1092,-7609,15681,2008,-1725,2337,7824 } }, { "Olympus E-P1", 0, 0xffd, { 8343,-2050,-1021,-7715,15705,2103,-1831,2380,8235 } }, { "Olympus E-P2", 0, 0xffd, { 8343,-2050,-1021,-7715,15705,2103,-1831,2380,8235 } }, { "Olympus E-P3", 0, 0, { 7575,-2159,-571,-3722,11341,2725,-1434,2819,6271 } }, { "Olympus E-P5", 0, 0, { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, { "Olympus E-PL1s", 0, 0, { 11409,-3872,-1393,-4572,12757,2003,-709,1810,7415 } }, { "Olympus E-PL1", 0, 0, { 11408,-4289,-1215,-4286,12385,2118,-387,1467,7787 } }, { "Olympus E-PL2", 0, 0xcf3, { 15030,-5552,-1806,-3987,12387,1767,-592,1670,7023 } }, { "Olympus E-PL3", 0, 0, { 7575,-2159,-571,-3722,11341,2725,-1434,2819,6271 } }, { "Olympus E-PL5", 0, 0xfcb, { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, { "Olympus E-PL6", 0, 0, { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, { "Olympus E-PL7", 0, 0, { 9197,-3190,-659,-2606,10830,2039,-458,1250,5458 } }, { "Olympus E-PL8", 0, 0, { 9197,-3190,-659,-2606,10830,2039,-458,1250,5458 } }, { "Olympus E-PM1", 0, 0, { 7575,-2159,-571,-3722,11341,2725,-1434,2819,6271 } }, { "Olympus E-PM2", 0, 0, { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, { "Olympus E-M10", 0, 0, /* Same for E-M10MarkII */ { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, { "Olympus E-M1MarkII", 0, 0, /* Adobe */ { 8380, -2630, -639, -2887, 10725, 2496, -627, 1427, 5438 }}, { "Olympus E-M1", 0, 0, { 7687,-1984,-606,-4327,11928,2721,-1381,2339,6452 } }, { "Olympus E-M5MarkII", 0, 0, { 9422,-3258,-711,-2655,10898,2015,-512,1354,5512 } }, { "Olympus E-M5", 0, 0xfe1, { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, { "Olympus PEN-F",0, 0, { 9476,-3182,-765,-2613,10958,1893,-449,1315,5268 } }, { "Olympus SP350", 0, 0, { 12078,-4836,-1069,-6671,14306,2578,-786,939,7418 } }, { "Olympus SP3", 0, 0, { 11766,-4445,-1067,-6901,14421,2707,-1029,1217,7572 } }, { "Olympus SP500UZ", 0, 0xfff, { 9493,-3415,-666,-5211,12334,3260,-1548,2262,6482 } }, { "Olympus SP510UZ", 0, 0xffe, { 10593,-3607,-1010,-5881,13127,3084,-1200,1805,6721 } }, { "Olympus SP550UZ", 0, 0xffe, { 11597,-4006,-1049,-5432,12799,2957,-1029,1750,6516 } }, { "Olympus SP560UZ", 0, 0xff9, { 10915,-3677,-982,-5587,12986,2911,-1168,1968,6223 } }, { "Olympus SP570UZ", 0, 0, { 11522,-4044,-1146,-4736,12172,2904,-988,1829,6039 } }, { "Olympus SH-2", 0, 0, { 10156,-3425,-1077,-2611,11177,1624,-385,1592,5080 } }, { "Olympus SH-3", 0, 0, /* Alias of SH-2 */ { 10156,-3425,-1077,-2611,11177,1624,-385,1592,5080 } }, { "Olympus STYLUS1",0, 0, { 11976,-5518,-545,-1419,10472,846,-475,1766,4524 } }, { "Olympus TG-4", 0, 0, { 11426,-4159,-1126,-2066,10678,1593,-120,1327,4998 } }, { "Olympus XZ-10", 0, 0, { 9777,-3483,-925,-2886,11297,1800,-602,1663,5134 } }, { "Olympus XZ-1", 0, 0, { 10901,-4095,-1074,-1141,9208,2293,-62,1417,5158 } }, { "Olympus XZ-2", 0, 0, { 9777,-3483,-925,-2886,11297,1800,-602,1663,5134 } }, { "OmniVision", 16, 0x3ff, { 12782,-4059,-379,-478,9066,1413,1340,1513,5176 } }, /* DJC */ { "Pentax *ist DL2", 0, 0, { 10504,-2438,-1189,-8603,16207,2531,-1022,863,12242 } }, { "Pentax *ist DL", 0, 0, { 10829,-2838,-1115,-8339,15817,2696,-837,680,11939 } }, { "Pentax *ist DS2", 0, 0, { 10504,-2438,-1189,-8603,16207,2531,-1022,863,12242 } }, { "Pentax *ist DS", 0, 0, { 10371,-2333,-1206,-8688,16231,2602,-1230,1116,11282 } }, { "Pentax *ist D", 0, 0, { 9651,-2059,-1189,-8881,16512,2487,-1460,1345,10687 } }, { "Pentax K10D", 0, 0, { 9566,-2863,-803,-7170,15172,2112,-818,803,9705 } }, { "Pentax K1", 0, 0, { 11095,-3157,-1324,-8377,15834,2720,-1108,947,11688 } }, { "Pentax K20D", 0, 0, { 9427,-2714,-868,-7493,16092,1373,-2199,3264,7180 } }, { "Pentax K200D", 0, 0, { 9186,-2678,-907,-8693,16517,2260,-1129,1094,8524 } }, { "Pentax K2000", 0, 0, { 11057,-3604,-1155,-5152,13046,2329,-282,375,8104 } }, { "Pentax K-m", 0, 0, { 11057,-3604,-1155,-5152,13046,2329,-282,375,8104 } }, { "Pentax K-x", 0, 0, { 8843,-2837,-625,-5025,12644,2668,-411,1234,7410 } }, { "Pentax K-r", 0, 0, { 9895,-3077,-850,-5304,13035,2521,-883,1768,6936 } }, { "Pentax K-1", 0, 0, { 8566,-2746,-1201,-3612,12204,1550,-893,1680,6264 } }, { "Pentax K-30", 0, 0, { 8710,-2632,-1167,-3995,12301,1881,-981,1719,6535 } }, { "Pentax K-3 II", 0, 0, { 8626,-2607,-1155,-3995,12301,1881,-1039,1822,6925 } }, { "Pentax K-3", 0, 0, { 7415,-2052,-721,-5186,12788,2682,-1446,2157,6773 } }, { "Pentax K-5 II", 0, 0, { 8170,-2725,-639,-4440,12017,2744,-771,1465,6599 } }, { "Pentax K-5", 0, 0, { 8713,-2833,-743,-4342,11900,2772,-722,1543,6247 } }, { "Pentax K-70", 0, 0, {8766, -3149, -747, -3976, 11943, 2292, -517, 1259, 5552 }}, { "Pentax K-7", 0, 0, { 9142,-2947,-678,-8648,16967,1663,-2224,2898,8615 } }, { "Pentax K-S1", 0, 0, { 8512,-3211,-787,-4167,11966,2487,-638,1288,6054 } }, { "Pentax K-S2", 0, 0, { 8662,-3280,-798,-3928,11771,2444,-586,1232,6054 } }, { "Pentax Q-S1", 0, 0, { 12995,-5593,-1107,-1879,10139,2027,-64,1233,4919 } }, { "Pentax MX-1", 0, 0, { 8804,-2523,-1238,-2423,11627,860,-682,1774,4753 } }, { "Pentax Q10", 0, 0, { 12995,-5593,-1107,-1879,10139,2027,-64,1233,4919 } }, { "Pentax 645D", 0, 0x3e00, { 10646,-3593,-1158,-3329,11699,1831,-667,2874,6287 } }, { "Pentax 645Z", 0, 0, /* Adobe */ { 9702, -3060, -1254, -3685, 12133, 1721, -1086, 2010, 6971}}, { "Panasonic DMC-CM10", -15, 0, { 8770, -3194,-820,-2871,11281,1803,-513,1552,4434 } }, { "Panasonic DMC-CM1", -15, 0, { 8770, -3194,-820,-2871,11281,1803,-513,1552,4434 } }, { "Panasonic DMC-FZ8", 0, 0xf7f, { 8986,-2755,-802,-6341,13575,3077,-1476,2144,6379 } }, { "Panasonic DMC-FZ18", 0, 0, { 9932,-3060,-935,-5809,13331,2753,-1267,2155,5575 } }, { "Panasonic DMC-FZ28", -15, 0xf96, { 10109,-3488,-993,-5412,12812,2916,-1305,2140,5543 } }, { "Panasonic DMC-FZ300", -15, 0xfff, { 8378,-2798,-769,-3068,11410,1877,-538,1792,4623 } }, { "Panasonic DMC-FZ330", -15, 0xfff, // same as FZ300 { 8378,-2798,-769,-3068,11410,1877,-538,1792,4623 } }, { "Panasonic DMC-FZ30", 0, 0xf94, { 10976,-4029,-1141,-7918,15491,2600,-1670,2071,8246 } }, { "Panasonic DMC-FZ3", -15, 0, { 9938,-2780,-890,-4604,12393,2480,-1117,2304,4620 } }, { "Panasonic DMC-FZ4", -15, 0, { 13639,-5535,-1371,-1698,9633,2430,316,1152,4108 } }, { "Panasonic DMC-FZ50", 0, 0, { 7906,-2709,-594,-6231,13351,3220,-1922,2631,6537 } }, { "Panasonic DMC-FZ7", -15, 0, { 11532,-4324,-1066,-2375,10847,1749,-564,1699,4351 } }, { "Leica V-LUX1", 0, 0, { 7906,-2709,-594,-6231,13351,3220,-1922,2631,6537 } }, { "Panasonic DMC-L10", -15, 0xf96, { 8025,-1942,-1050,-7920,15904,2100,-2456,3005,7039 } }, { "Panasonic DMC-L1", 0, 0xf7f, { 8054,-1885,-1025,-8349,16367,2040,-2805,3542,7629 } }, { "Leica DIGILUX 3", 0, 0xf7f, { 8054,-1885,-1025,-8349,16367,2040,-2805,3542,7629 } }, { "Panasonic DMC-LC1", 0, 0, { 11340,-4069,-1275,-7555,15266,2448,-2960,3426,7685 } }, { "Leica DIGILUX 2", 0, 0, { 11340,-4069,-1275,-7555,15266,2448,-2960,3426,7685 } }, { "Panasonic DMC-LX100", -15, 0, { 8844,-3538,-768,-3709,11762,2200,-698,1792,5220 } }, { "Leica D-LUX (Typ 109)", -15, 0, { 8844,-3538,-768,-3709,11762,2200,-698,1792,5220 } }, { "Panasonic DMC-LF1", -15, 0, { 9379,-3267,-816,-3227,11560,1881,-926,1928,5340 } }, { "Leica C (Typ 112)", -15, 0, { 9379,-3267,-816,-3227,11560,1881,-926,1928,5340 } }, { "Panasonic DMC-LX9", -15, 0, /* markets: LX9 LX10 LX15 */ { 7790, -2736, -755, -3452, 11870, 1769, -628, 1647, 4898 }}, /* Adobe*/ { "Panasonic DMC-LX10", -15, 0, /* markets: LX9 LX10 LX15 */ { 7790, -2736, -755, -3452, 11870, 1769, -628, 1647, 4898 }}, /* Adobe*/ { "Panasonic DMC-LX15", -15, 0, /* markets: LX9 LX10 LX15 */ { 7790, -2736, -755, -3452, 11870, 1769, -628, 1647, 4898 }}, /* Adobe*/ { "Panasonic DMC-LX1", 0, 0xf7f, { 10704,-4187,-1230,-8314,15952,2501,-920,945,8927 } }, { "Leica D-Lux (Typ 109)", 0, 0xf7f, { 8844,-3538,-768,-3709,11762,2200,-698,1792,5220 } }, { "Leica D-LUX2", 0, 0xf7f, { 10704,-4187,-1230,-8314,15952,2501,-920,945,8927 } }, { "Panasonic DMC-LX2", 0, 0, { 8048,-2810,-623,-6450,13519,3272,-1700,2146,7049 } }, { "Leica D-LUX3", 0, 0, { 8048,-2810,-623,-6450,13519,3272,-1700,2146,7049 } }, { "Panasonic DMC-LX3", -15, 0, { 8128,-2668,-655,-6134,13307,3161,-1782,2568,6083 } }, { "Leica D-LUX 4", -15, 0, { 8128,-2668,-655,-6134,13307,3161,-1782,2568,6083 } }, { "Panasonic DMC-LX5", -15, 0, { 10909,-4295,-948,-1333,9306,2399,22,1738,4582 } }, { "Leica D-LUX 5", -15, 0, { 10909,-4295,-948,-1333,9306,2399,22,1738,4582 } }, { "Panasonic DMC-LX7", -15, 0, { 10148,-3743,-991,-2837,11366,1659,-701,1893,4899 } }, { "Leica D-LUX 6", -15, 0, { 10148,-3743,-991,-2837,11366,1659,-701,1893,4899 } }, { "Panasonic DMC-FZ1000", -15, 0, { 7830,-2696,-763,-3325,11667,1866,-641,1712,4824 } }, { "Leica V-LUX (Typ 114)", 15, 0, { 7830,-2696,-763,-3325,11667,1866,-641,1712,4824 } }, { "Panasonic DMC-FZ100", -15, 0xfff, { 16197,-6146,-1761,-2393,10765,1869,366,2238,5248 } }, { "Leica V-LUX 2", -15, 0xfff, { 16197,-6146,-1761,-2393,10765,1869,366,2238,5248 } }, { "Panasonic DMC-FZ150", -15, 0xfff, { 11904,-4541,-1189,-2355,10899,1662,-296,1586,4289 } }, { "Leica V-LUX 3", -15, 0xfff, { 11904,-4541,-1189,-2355,10899,1662,-296,1586,4289 } }, { "Panasonic DMC-FZ2000", -15, 0, /* markets: DMC-FZ2000,DMC-FZ2500,FZH1 */ { 7386, -2443, -743, -3437, 11864, 1757, -608, 1660, 4766 }}, { "Panasonic DMC-FZ2500", -15, 0, { 7386, -2443, -743, -3437, 11864, 1757, -608, 1660, 4766 }}, { "Panasonic DMC-FZH1", -15, 0, { 7386, -2443, -743, -3437, 11864, 1757, -608, 1660, 4766 }}, { "Panasonic DMC-FZ200", -15, 0xfff, { 8112,-2563,-740,-3730,11784,2197,-941,2075,4933 } }, { "Leica V-LUX 4", -15, 0xfff, { 8112,-2563,-740,-3730,11784,2197,-941,2075,4933 } }, { "Panasonic DMC-FX150", -15, 0xfff, { 9082,-2907,-925,-6119,13377,3058,-1797,2641,5609 } }, { "Panasonic DMC-G10", 0, 0, { 10113,-3400,-1114,-4765,12683,2317,-377,1437,6710 } }, { "Panasonic DMC-G1", -15, 0xf94, { 8199,-2065,-1056,-8124,16156,2033,-2458,3022,7220 } }, { "Panasonic DMC-G2", -15, 0xf3c, { 10113,-3400,-1114,-4765,12683,2317,-377,1437,6710 } }, { "Panasonic DMC-G3", -15, 0xfff, { 6763,-1919,-863,-3868,11515,2684,-1216,2387,5879 } }, { "Panasonic DMC-G5", -15, 0xfff, { 7798,-2562,-740,-3879,11584,2613,-1055,2248,5434 } }, { "Panasonic DMC-G6", -15, 0xfff, { 8294,-2891,-651,-3869,11590,2595,-1183,2267,5352 } }, { "Panasonic DMC-G7", -15, 0xfff, { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, { "Panasonic DMC-G8", -15, 0xfff, /* markets: DMC-G8, DMC-G80, DMC-G81, DMC-G85 */ { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, { "Panasonic DMC-GF1", -15, 0xf92, { 7888,-1902,-1011,-8106,16085,2099,-2353,2866,7330 } }, { "Panasonic DMC-GF2", -15, 0xfff, { 7888,-1902,-1011,-8106,16085,2099,-2353,2866,7330 } }, { "Panasonic DMC-GF3", -15, 0xfff, { 9051,-2468,-1204,-5212,13276,2121,-1197,2510,6890 } }, { "Panasonic DMC-GF5", -15, 0xfff, { 8228,-2945,-660,-3938,11792,2430,-1094,2278,5793 } }, { "Panasonic DMC-GF6", -15, 0, { 8130,-2801,-946,-3520,11289,2552,-1314,2511,5791 } }, { "Panasonic DMC-GF7", -15, 0, { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, { "Panasonic DMC-GF8", -15, 0, { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, { "Panasonic DMC-GH1", -15, 0xf92, { 6299,-1466,-532,-6535,13852,2969,-2331,3112,5984 } }, { "Panasonic DMC-GH2", -15, 0xf95, { 7780,-2410,-806,-3913,11724,2484,-1018,2390,5298 } }, { "Panasonic DMC-GH3", -15, 0, { 6559,-1752,-491,-3672,11407,2586,-962,1875,5130 } }, { "Panasonic DMC-GH4", -15, 0, { 7122,-2108,-512,-3155,11201,2231,-541,1423,5045 } }, { "Yuneec CGO4", -15, 0, { 7122,-2108,-512,-3155,11201,2231,-541,1423,5045 } }, { "Panasonic DMC-GM1", -15, 0, { 6770,-1895,-744,-5232,13145,2303,-1664,2691,5703 } }, { "Panasonic DMC-GM5", -15, 0, { 8238,-3244,-679,-3921,11814,2384,-836,2022,5852 } }, { "Panasonic DMC-GX1", -15, 0, { 6763,-1919,-863,-3868,11515,2684,-1216,2387,5879 } }, { "Panasonic DMC-GX85", -15, 0, /* markets: GX85 GX80 GX7MK2 */ { 7771,-3020,-629,4029,11950,2345,-821,1977,6119 } }, { "Panasonic DMC-GX80", -15, 0, /* markets: GX85 GX80 GX7MK2 */ { 7771,-3020,-629,4029,11950,2345,-821,1977,6119 } }, { "Panasonic DMC-GX7MK2", -15, 0, /* markets: GX85 GX80 GX7MK2 */ { 7771,-3020,-629,4029,11950,2345,-821,1977,6119 } }, { "Panasonic DMC-GX7", -15,0, { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, { "Panasonic DMC-GX8", -15,0, { 7564,-2263,-606,-3148,11239,2177,-540,1435,4853 } }, { "Panasonic DMC-TZ6", -15, 0, /* markets: ZS40 TZ60 TZ61 */ { 8607,-2822,-808,-3755,11930,2049,-820,2060,5224 } }, { "Panasonic DMC-TZ8", -15, 0, /* markets: ZS60 TZ80 TZ81 TZ85 */ { 8550,-2908,-842,-3195,11529,1881,-338,1603,4631 } }, { "Panasonic DMC-ZS4", -15, 0, /* markets: ZS40 TZ60 TZ61 */ { 8607,-2822,-808,-3755,11930,2049,-820,2060,5224 } }, { "Panasonic DMC-TZ7", -15, 0, /* markets: ZS50 TZ70 TZ71 */ { 8802,-3135,-789,-3151,11468,1904,-550,1745,4810 } }, { "Panasonic DMC-ZS5", -15, 0, /* markets: ZS50 TZ70 TZ71 */ { 8802,-3135,-789,-3151,11468,1904,-550,1745,4810 } }, { "Panasonic DMC-ZS6", -15, 0, /* markets: ZS60 TZ80 TZ81 TZ85 */ { 8550,-2908,-842,-3195,11529,1881,-338,1603,4631 } }, { "Panasonic DMC-ZS100", -15, 0, /* markets: ZS100 ZS110 TZ100 TZ101 TZ110 TX1 */ { 7790,-2736,-755,-3452,11870,1769,-628,1647,4898 } }, { "Panasonic DMC-ZS110", -15, 0, /* markets: ZS100 ZS110 TZ100 TZ101 TZ110 TX1 */ { 7790,-2736,-755,-3452,11870,1769,-628,1647,4898 } }, { "Panasonic DMC-TZ100", -15, 0, /* markets: ZS100 ZS110 TZ100 TZ101 TZ110 TX1 */ { 7790,-2736,-755,-3452,11870,1769,-628,1647,4898 } }, { "Panasonic DMC-TZ101", -15, 0, /* markets: ZS100 ZS110 TZ100 TZ101 TZ110 TX1 */ { 7790,-2736,-755,-3452,11870,1769,-628,1647,4898 } }, { "Panasonic DMC-TZ110", -15, 0, /* markets: ZS100 ZS110 TZ100 TZ101 TZ110 TX1 */ { 7790,-2736,-755,-3452,11870,1769,-628,1647,4898 } }, { "Panasonic DMC-TX1", -15, 0, /* markets: ZS100 ZS110 TZ100 TZ101 TZ110 TX1 */ { 7790,-2736,-755,-3452,11870,1769,-628,1647,4898 } }, { "Leica S (Typ 007)", 0, 0, { 6063,-2234,-231,-5210,13787,1500,-1043,2866,6997 } }, { "Leica X", 0, 0, /* X and X-U, both (Typ 113) */ { 7712,-2059,-653,-3882,11494,2726,-710,1332,5958 } }, { "Leica Q (Typ 116)", 0, 0, { 11865,-4523,-1441,-5423,14458,935,-1587,2687,4830 } }, { "Leica M (Typ 262)", 0, 0, { 6653,-1486,-611,-4221,13303,929,-881,2416,7226 } }, { "Leica SL (Typ 601)", 0, 0, { 11865,-4523,-1441,-5423,14458,935,-1587,2687,4830} }, { "Phase One H 20", 0, 0, /* DJC */ { 1313,1855,-109,-6715,15908,808,-327,1840,6020 } }, { "Phase One H 25", 0, 0, { 2905,732,-237,-8134,16626,1476,-3038,4253,7517 } }, { "Phase One IQ250",0, 0, { 4396,-153,-249,-5267,12249,2657,-1397,2323,6014 } }, { "Phase One P 2", 0, 0, { 2905,732,-237,-8134,16626,1476,-3038,4253,7517 } }, { "Phase One P 30", 0, 0, { 4516,-245,-37,-7020,14976,2173,-3206,4671,7087 } }, { "Phase One P 45", 0, 0, { 5053,-24,-117,-5684,14076,1702,-2619,4492,5849 } }, { "Phase One P40", 0, 0, { 8035,435,-962,-6001,13872,2320,-1159,3065,5434 } }, { "Phase One P65", 0, 0, { 8035,435,-962,-6001,13872,2320,-1159,3065,5434 } }, { "Photron BC2-HD", 0, 0, /* DJC */ { 14603,-4122,-528,-1810,9794,2017,-297,2763,5936 } }, { "Red One", 704, 0xffff, /* DJC */ { 21014,-7891,-2613,-3056,12201,856,-2203,5125,8042 } }, { "Ricoh GR II", 0, 0, { 4630,-834,-423,-4977,12805,2417,-638,1467,6115 } }, { "Ricoh GR", 0, 0, { 3708,-543,-160,-5381,12254,3556,-1471,1929,8234 } }, { "Samsung EK-GN120", 0, 0, /* Adobe; Galaxy NX */ { 7557,-2522,-739,-4679,12949,1894,-840,1777,5311 } }, { "Samsung EX1", 0, 0x3e00, { 8898,-2498,-994,-3144,11328,2066,-760,1381,4576 } }, { "Samsung EX2F", 0, 0x7ff, { 10648,-3897,-1055,-2022,10573,1668,-492,1611,4742 } }, { "Samsung NX mini", 0, 0, { 5222,-1196,-550,-6540,14649,2009,-1666,2819,5657 } }, { "Samsung NX3300", 0, 0, /* same as NX3000 */ { 8060,-2933,-761,-4504,12890,1762,-630,1489,5227 } }, { "Samsung NX3000", 0, 0, { 8060,-2933,-761,-4504,12890,1762,-630,1489,5227 } }, { "Samsung NX30", 0, 0, /* NX30, NX300, NX300M */ { 7557,-2522,-739,-4679,12949,1894,-840,1777,5311 } }, { "Samsung NX2000", 0, 0, { 7557,-2522,-739,-4679,12949,1894,-840,1777,5311 } }, { "Samsung NX2", 0, 0xfff, /* NX20, NX200, NX210 */ { 6933,-2268,-753,-4921,13387,1647,-803,1641,6096 } }, { "Samsung NX1000", 0, 0, { 6933,-2268,-753,-4921,13387,1647,-803,1641,6096 } }, { "Samsung NX1100", 0, 0, { 6933,-2268,-753,-4921,13387,1647,-803,1641,6096 } }, { "Samsung NX11", 0, 0, { 10332,-3234,-1168,-6111,14639,1520,-1352,2647,8331 } }, { "Samsung NX10", 0, 0, /* also NX100 */ { 10332,-3234,-1168,-6111,14639,1520,-1352,2647,8331 } }, { "Samsung NX500", 0, 0, { 10686,-4042,-1052,-3595,13238,276,-464,1259,5931 } }, { "Samsung NX5", 0, 0, { 10332,-3234,-1168,-6111,14639,1520,-1352,2647,8331 } }, { "Samsung NX1", 0, 0, { 10686,-4042,-1052,-3595,13238,276,-464,1259,5931 } }, { "Samsung WB2000", 0, 0xfff, { 12093,-3557,-1155,-1000,9534,1733,-22,1787,4576 } }, { "Samsung GX-1", 0, 0, { 10504,-2438,-1189,-8603,16207,2531,-1022,863,12242 } }, { "Samsung GX20", 0, 0, /* copied from Pentax K20D */ { 9427,-2714,-868,-7493,16092,1373,-2199,3264,7180 } }, { "Samsung S85", 0, 0, /* DJC */ { 11885,-3968,-1473,-4214,12299,1916,-835,1655,5549 } }, // Foveon: LibRaw color data { "Sigma dp0 Quattro", 2047, 0, { 13801,-3390,-1016,5535,3802,877,1848,4245,3730 } }, { "Sigma dp1 Quattro", 2047, 0, { 13801,-3390,-1016,5535,3802,877,1848,4245,3730 } }, { "Sigma dp2 Quattro", 2047, 0, { 13801,-3390,-1016,5535,3802,877,1848,4245,3730 } }, { "Sigma dp3 Quattro", 2047, 0, { 13801,-3390,-1016,5535,3802,877,1848,4245,3730 } }, { "Sigma sd Quattro H", 256, 0, {1295,108,-311, 256,828,-65,-28,750,254}}, /* temp, same as sd Quattro */ { "Sigma sd Quattro", 2047, 0, {1295,108,-311, 256,828,-65,-28,750,254}}, /* temp */ { "Sigma SD9", 15, 4095, /* LibRaw */ { 14082,-2201,-1056,-5243,14788,167,-121,196,8881 } }, { "Sigma SD10", 15, 16383, /* LibRaw */ { 14082,-2201,-1056,-5243,14788,167,-121,196,8881 } }, { "Sigma SD14", 15, 16383, /* LibRaw */ { 14082,-2201,-1056,-5243,14788,167,-121,196,8881 } }, { "Sigma SD15", 15, 4095, /* LibRaw */ { 14082,-2201,-1056,-5243,14788,167,-121,196,8881 } }, // Merills + SD1 { "Sigma SD1", 31, 4095, /* LibRaw */ { 5133,-1895,-353,4978,744,144,3837,3069,2777 } }, { "Sigma DP1 Merrill", 31, 4095, /* LibRaw */ { 5133,-1895,-353,4978,744,144,3837,3069,2777 } }, { "Sigma DP2 Merrill", 31, 4095, /* LibRaw */ { 5133,-1895,-353,4978,744,144,3837,3069,2777 } }, { "Sigma DP3 Merrill", 31, 4095, /* LibRaw */ { 5133,-1895,-353,4978,744,144,3837,3069,2777 } }, // Sigma DP (non-Merill Versions) { "Sigma DP", 0, 4095, /* LibRaw */ // { 7401,-1169,-567,2059,3769,1510,664,3367,5328 } }, { 13100,-3638,-847,6855,2369,580,2723,3218,3251 } }, { "Sinar", 0, 0, /* DJC */ { 16442,-2956,-2422,-2877,12128,750,-1136,6066,4559 } }, { "Sony DSC-F828", 0, 0, { 7924,-1910,-777,-8226,15459,2998,-1517,2199,6818,-7242,11401,3481 } }, { "Sony DSC-R1", 0, 0, { 8512,-2641,-694,-8042,15670,2526,-1821,2117,7414 } }, { "Sony DSC-V3", 0, 0, { 7511,-2571,-692,-7894,15088,3060,-948,1111,8128 } }, {"Sony DSC-RX100M5", -800, 0, /* Adobe */ {6596, -2079, -562, -4782, 13016, 1933, -970, 1581, 5181 }}, { "Sony DSC-RX100M", -800, 0, /* M2 and M3 and M4 */ { 6596,-2079,-562,-4782,13016,1933,-970,1581,5181 } }, { "Sony DSC-RX100", 0, 0, { 8651,-2754,-1057,-3464,12207,1373,-568,1398,4434 } }, { "Sony DSC-RX10",0, 0, /* And M2/M3 too */ { 6679,-1825,-745,-5047,13256,1953,-1580,2422,5183 } }, { "Sony DSC-RX1RM2", 0, 0, { 6629,-1900,-483,-4618,12349,2550,-622,1381,6514 } }, { "Sony DSC-RX1R", 0, 0, { 8195,-2800,-422,-4261,12273,1709,-1505,2400,5624 } }, { "Sony DSC-RX1", 0, 0, { 6344,-1612,-462,-4863,12477,2681,-865,1786,6899 } }, { "Sony DSLR-A100", 0, 0xfeb, { 9437,-2811,-774,-8405,16215,2290,-710,596,7181 } }, { "Sony DSLR-A290", 0, 0, { 6038,-1484,-579,-9145,16746,2512,-875,746,7218 } }, { "Sony DSLR-A2", 0, 0, { 9847,-3091,-928,-8485,16345,2225,-715,595,7103 } }, { "Sony DSLR-A300", 0, 0, { 9847,-3091,-928,-8485,16345,2225,-715,595,7103 } }, { "Sony DSLR-A330", 0, 0, { 9847,-3091,-929,-8485,16346,2225,-714,595,7103 } }, { "Sony DSLR-A350", 0, 0xffc, { 6038,-1484,-578,-9146,16746,2513,-875,746,7217 } }, { "Sony DSLR-A380", 0, 0, { 6038,-1484,-579,-9145,16746,2512,-875,746,7218 } }, { "Sony DSLR-A390", 0, 0, { 6038,-1484,-579,-9145,16746,2512,-875,746,7218 } }, { "Sony DSLR-A450", 0, 0xfeb, { 4950,-580,-103,-5228,12542,3029,-709,1435,7371 } }, { "Sony DSLR-A580", 0, 0xfeb, { 5932,-1492,-411,-4813,12285,2856,-741,1524,6739 } }, { "Sony DSLR-A500", 0, 0xfeb, { 6046,-1127,-278,-5574,13076,2786,-691,1419,7625 } }, { "Sony DSLR-A5", 0, 0xfeb, { 4950,-580,-103,-5228,12542,3029,-709,1435,7371 } }, { "Sony DSLR-A700", 0, 0, { 5775,-805,-359,-8574,16295,2391,-1943,2341,7249 } }, { "Sony DSLR-A850", 0, 0, { 5413,-1162,-365,-5665,13098,2866,-608,1179,8440 } }, { "Sony DSLR-A900", 0, 0, { 5209,-1072,-397,-8845,16120,2919,-1618,1803,8654 } }, { "Sony ILCA-68", 0, 0, { 6435,-1903,-536,-4722,12449,2550,-663,1363,6517 } }, { "Sony ILCA-77M2", 0, 0, { 5991,-1732,-443,-4100,11989,2381,-704,1467,5992 } }, { "Sony ILCA-99M2", 0, 0, /* Adobe */ { 6660, -1918, -471, -4613, 12398, 2485, -649, 1433, 6447}}, { "Sony ILCE-7M2", 0, 0, { 5271,-712,-347,-6153,13653,2763,-1601,2366,7242 } }, { "Sony ILCE-7SM2", 0, 0, { 5838,-1430,-246,-3497,11477,2297,-748,1885,5778 } }, { "Sony ILCE-7S", 0, 0, { 5838,-1430,-246,-3497,11477,2297,-748,1885,5778 } }, { "Sony ILCE-7RM2", 0, 0, { 6629,-1900,-483,-4618,12349,2550,-622,1381,6514 } }, { "Sony ILCE-7R", 0, 0, { 4913,-541,-202,-6130,13513,2906,-1564,2151,7183 } }, { "Sony ILCE-7", 0, 0, { 5271,-712,-347,-6153,13653,2763,-1601,2366,7242 } }, { "Sony ILCE-6300", 0, 0, { 5973,-1695,-419,-3826,11797,2293,-639,1398,5789 } }, { "Sony ILCE-6500", 0, 0, /* Adobe */ { 5973,-1695,-419,-3826,11797,2293,-639,1398,5789 } }, { "Sony ILCE", 0, 0, /* 3000, 5000, 5100, 6000, and QX1 */ { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, { "Sony NEX-5N", 0, 0, { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, { "Sony NEX-5R", 0, 0, { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, { "Sony NEX-5T", 0, 0, { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, { "Sony NEX-3N", 0, 0, { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, { "Sony NEX-3", 0, 0, /* Adobe */ { 6549,-1550,-436,-4880,12435,2753,-854,1868,6976 } }, { "Sony NEX-5", 0, 0, /* Adobe */ { 6549,-1550,-436,-4880,12435,2753,-854,1868,6976 } }, { "Sony NEX-6", 0, 0, { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, { "Sony NEX-7", 0, 0, { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } }, { "Sony NEX", 0, 0, /* NEX-C3, NEX-F3 */ { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, { "Sony SLT-A33", 0, 0, { 6069,-1221,-366,-5221,12779,2734,-1024,2066,6834 } }, { "Sony SLT-A35", 0, 0, { 5986,-1618,-415,-4557,11820,3120,-681,1404,6971 } }, { "Sony SLT-A37", 0, 0, { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, { "Sony SLT-A55", 0, 0, { 5932,-1492,-411,-4813,12285,2856,-741,1524,6739 } }, { "Sony SLT-A57", 0, 0, { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, { "Sony SLT-A58", 0, 0, { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, { "Sony SLT-A65", 0, 0, { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } }, { "Sony SLT-A77", 0, 0, { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } }, { "Sony SLT-A99", 0, 0, { 6344,-1612,-462,-4863,12477,2681,-865,1786,6899 } }, }; double cam_xyz[4][3]; char name[130]; int i, j; if(colors>4 || colors < 1) return; int bl4=(cblack[0]+cblack[1]+cblack[2]+cblack[3])/4,bl64=0; if(cblack[4]*cblack[5]>0) { for (unsigned c = 0; c < 4096 && c < cblack[4]*cblack[5]; c++) bl64+=cblack[c+6]; bl64 /= cblack[4]*cblack[5]; } int rblack = black+bl4+bl64; sprintf (name, "%s %s", t_make, t_model); for (i=0; i < sizeof table / sizeof *table; i++) if (!strncasecmp(name, table[i].prefix, strlen(table[i].prefix))) { if(!dng_version) { if (table[i].t_black>0) { black = (ushort) table[i].t_black; memset(cblack,0,sizeof(cblack)); } else if(table[i].t_black <0 && rblack == 0 ) { black = (ushort) (-table[i].t_black); memset(cblack,0,sizeof(cblack)); } if (table[i].t_maximum) maximum = (ushort) table[i].t_maximum; } if (table[i].trans[0]) { for (raw_color = j=0; j < 12; j++) #ifdef LIBRAW_LIBRARY_BUILD if(internal_only) imgdata.color.cam_xyz[0][j] = table[i].trans[j] / 10000.0; else imgdata.color.cam_xyz[0][j] = #endif ((double*)cam_xyz)[j] = table[i].trans[j] / 10000.0; #ifdef LIBRAW_LIBRARY_BUILD if(!internal_only) #endif cam_xyz_coeff (rgb_cam, cam_xyz); } break; } } void CLASS simple_coeff (int index) { static const float table[][12] = { /* index 0 -- all Foveon cameras */ { 1.4032,-0.2231,-0.1016,-0.5263,1.4816,0.017,-0.0112,0.0183,0.9113 }, /* index 1 -- Kodak DC20 and DC25 */ { 2.25,0.75,-1.75,-0.25,-0.25,0.75,0.75,-0.25,-0.25,-1.75,0.75,2.25 }, /* index 2 -- Logitech Fotoman Pixtura */ { 1.893,-0.418,-0.476,-0.495,1.773,-0.278,-1.017,-0.655,2.672 }, /* index 3 -- Nikon E880, E900, and E990 */ { -1.936280, 1.800443, -1.448486, 2.584324, 1.405365, -0.524955, -0.289090, 0.408680, -1.204965, 1.082304, 2.941367, -1.818705 } }; int i, c; for (raw_color = i=0; i < 3; i++) FORCC rgb_cam[i][c] = table[index][i*colors+c]; } short CLASS guess_byte_order (int words) { uchar test[4][2]; int t=2, msb; double diff, sum[2] = {0,0}; fread (test[0], 2, 2, ifp); for (words-=2; words--; ) { fread (test[t], 2, 1, ifp); for (msb=0; msb < 2; msb++) { diff = (test[t^2][msb] << 8 | test[t^2][!msb]) - (test[t ][msb] << 8 | test[t ][!msb]); sum[msb] += diff*diff; } t = (t+1) & 3; } return sum[0] < sum[1] ? 0x4d4d : 0x4949; } float CLASS find_green (int bps, int bite, int off0, int off1) { UINT64 bitbuf=0; int vbits, col, i, c; ushort img[2][2064]; double sum[]={0,0}; FORC(2) { fseek (ifp, c ? off1:off0, SEEK_SET); for (vbits=col=0; col < width; col++) { for (vbits -= bps; vbits < 0; vbits += bite) { bitbuf <<= bite; for (i=0; i < bite; i+=8) bitbuf |= (unsigned) (fgetc(ifp) << i); } img[c][col] = bitbuf << (64-bps-vbits) >> (64-bps); } } FORC(width-1) { sum[ c & 1] += ABS(img[0][c]-img[1][c+1]); sum[~c & 1] += ABS(img[1][c]-img[0][c+1]); } return 100 * log(sum[0]/sum[1]); } #ifdef LIBRAW_LIBRARY_BUILD static void remove_trailing_spaces(char *string, size_t len) { if(len<1) return; // not needed, b/c sizeof of make/model is 64 string[len-1]=0; if(len<3) return; // also not needed len = strnlen(string,len-1); for(int i=len-1; i>=0; i--) { if(isspace(string[i])) string[i]=0; else break; } } #endif /* Identify which camera created this file, and set global variables accordingly. */ void CLASS identify() { static const short pana[][6] = { { 3130, 1743, 4, 0, -6, 0 }, { 3130, 2055, 4, 0, -6, 0 }, { 3130, 2319, 4, 0, -6, 0 }, { 3170, 2103, 18, 0,-42, 20 }, { 3170, 2367, 18, 13,-42,-21 }, { 3177, 2367, 0, 0, -1, 0 }, { 3304, 2458, 0, 0, -1, 0 }, { 3330, 2463, 9, 0, -5, 0 }, { 3330, 2479, 9, 0,-17, 4 }, { 3370, 1899, 15, 0,-44, 20 }, { 3370, 2235, 15, 0,-44, 20 }, { 3370, 2511, 15, 10,-44,-21 }, { 3690, 2751, 3, 0, -8, -3 }, { 3710, 2751, 0, 0, -3, 0 }, { 3724, 2450, 0, 0, 0, -2 }, { 3770, 2487, 17, 0,-44, 19 }, { 3770, 2799, 17, 15,-44,-19 }, { 3880, 2170, 6, 0, -6, 0 }, { 4060, 3018, 0, 0, 0, -2 }, { 4290, 2391, 3, 0, -8, -1 }, { 4330, 2439, 17, 15,-44,-19 }, { 4508, 2962, 0, 0, -3, -4 }, { 4508, 3330, 0, 0, -3, -6 }, }; static const ushort canon[][11] = { { 1944, 1416, 0, 0, 48, 0 }, { 2144, 1560, 4, 8, 52, 2, 0, 0, 0, 25 }, { 2224, 1456, 48, 6, 0, 2 }, { 2376, 1728, 12, 6, 52, 2 }, { 2672, 1968, 12, 6, 44, 2 }, { 3152, 2068, 64, 12, 0, 0, 16 }, { 3160, 2344, 44, 12, 4, 4 }, { 3344, 2484, 4, 6, 52, 6 }, { 3516, 2328, 42, 14, 0, 0 }, { 3596, 2360, 74, 12, 0, 0 }, { 3744, 2784, 52, 12, 8, 12 }, { 3944, 2622, 30, 18, 6, 2 }, { 3948, 2622, 42, 18, 0, 2 }, { 3984, 2622, 76, 20, 0, 2, 14 }, { 4104, 3048, 48, 12, 24, 12 }, { 4116, 2178, 4, 2, 0, 0 }, { 4152, 2772, 192, 12, 0, 0 }, { 4160, 3124, 104, 11, 8, 65 }, { 4176, 3062, 96, 17, 8, 0, 0, 16, 0, 7, 0x49 }, { 4192, 3062, 96, 17, 24, 0, 0, 16, 0, 0, 0x49 }, { 4312, 2876, 22, 18, 0, 2 }, { 4352, 2874, 62, 18, 0, 0 }, { 4476, 2954, 90, 34, 0, 0 }, { 4480, 3348, 12, 10, 36, 12, 0, 0, 0, 18, 0x49 }, { 4480, 3366, 80, 50, 0, 0 }, { 4496, 3366, 80, 50, 12, 0 }, { 4768, 3516, 96, 16, 0, 0, 0, 16 }, { 4832, 3204, 62, 26, 0, 0 }, { 4832, 3228, 62, 51, 0, 0 }, { 5108, 3349, 98, 13, 0, 0 }, { 5120, 3318, 142, 45, 62, 0 }, { 5280, 3528, 72, 52, 0, 0 }, /* EOS M */ { 5344, 3516, 142, 51, 0, 0 }, { 5344, 3584, 126,100, 0, 2 }, { 5360, 3516, 158, 51, 0, 0 }, { 5568, 3708, 72, 38, 0, 0 }, { 5632, 3710, 96, 17, 0, 0, 0, 16, 0, 0, 0x49 }, { 5712, 3774, 62, 20, 10, 2 }, { 5792, 3804, 158, 51, 0, 0 }, { 5920, 3950, 122, 80, 2, 0 }, { 6096, 4056, 72, 34, 0, 0 }, /* EOS M3 */ { 6288, 4056, 266, 36, 0, 0 }, /* EOS 80D */ { 6880, 4544, 136, 42, 0, 0 }, /* EOS 5D4 */ { 8896, 5920, 160, 64, 0, 0 }, }; static const struct { ushort id; char t_model[20]; } unique[] = { { 0x001, "EOS-1D" }, { 0x167, "EOS-1DS" }, { 0x168, "EOS 10D" }, { 0x169, "EOS-1D Mark III" }, { 0x170, "EOS 300D" }, { 0x174, "EOS-1D Mark II" }, { 0x175, "EOS 20D" }, { 0x176, "EOS 450D" }, { 0x188, "EOS-1Ds Mark II" }, { 0x189, "EOS 350D" }, { 0x190, "EOS 40D" }, { 0x213, "EOS 5D" }, { 0x215, "EOS-1Ds Mark III" }, { 0x218, "EOS 5D Mark II" }, { 0x232, "EOS-1D Mark II N" }, { 0x234, "EOS 30D" }, { 0x236, "EOS 400D" }, { 0x250, "EOS 7D" }, { 0x252, "EOS 500D" }, { 0x254, "EOS 1000D" }, { 0x261, "EOS 50D" }, { 0x269, "EOS-1D X" }, { 0x270, "EOS 550D" }, { 0x281, "EOS-1D Mark IV" }, { 0x285, "EOS 5D Mark III" }, { 0x286, "EOS 600D" }, { 0x287, "EOS 60D" }, { 0x288, "EOS 1100D" }, { 0x289, "EOS 7D Mark II" }, { 0x301, "EOS 650D" }, { 0x302, "EOS 6D" }, { 0x324, "EOS-1D C" }, { 0x325, "EOS 70D" }, { 0x326, "EOS 700D" }, { 0x327, "EOS 1200D" }, { 0x328, "EOS-1D X Mark II" }, { 0x331, "EOS M" }, { 0x335, "EOS M2" }, { 0x374, "EOS M3"}, /* temp */ { 0x384, "EOS M10"}, /* temp */ { 0x394, "EOS M5"}, /* temp */ { 0x346, "EOS 100D" }, { 0x347, "EOS 760D" }, { 0x349, "EOS 5D Mark IV" }, { 0x350, "EOS 80D"}, { 0x382, "EOS 5DS" }, { 0x393, "EOS 750D" }, { 0x401, "EOS 5DS R" }, { 0x404, "EOS 1300D" }, }, sonique[] = { { 0x002, "DSC-R1" }, { 0x100, "DSLR-A100" }, { 0x101, "DSLR-A900" }, { 0x102, "DSLR-A700" }, { 0x103, "DSLR-A200" }, { 0x104, "DSLR-A350" }, { 0x105, "DSLR-A300" }, { 0x106, "DSLR-A900" }, { 0x107, "DSLR-A380" }, { 0x108, "DSLR-A330" }, { 0x109, "DSLR-A230" }, { 0x10a, "DSLR-A290" }, { 0x10d, "DSLR-A850" }, { 0x10e, "DSLR-A850" }, { 0x111, "DSLR-A550" }, { 0x112, "DSLR-A500" }, { 0x113, "DSLR-A450" }, { 0x116, "NEX-5" }, { 0x117, "NEX-3" }, { 0x118, "SLT-A33" }, { 0x119, "SLT-A55V" }, { 0x11a, "DSLR-A560" }, { 0x11b, "DSLR-A580" }, { 0x11c, "NEX-C3" }, { 0x11d, "SLT-A35" }, { 0x11e, "SLT-A65V" }, { 0x11f, "SLT-A77V" }, { 0x120, "NEX-5N" }, { 0x121, "NEX-7" }, { 0x122, "NEX-VG20E"}, { 0x123, "SLT-A37" }, { 0x124, "SLT-A57" }, { 0x125, "NEX-F3" }, { 0x126, "SLT-A99V" }, { 0x127, "NEX-6" }, { 0x128, "NEX-5R" }, { 0x129, "DSC-RX100" }, { 0x12a, "DSC-RX1" }, { 0x12b, "NEX-VG900" }, { 0x12c, "NEX-VG30E" }, { 0x12e, "ILCE-3000" }, { 0x12f, "SLT-A58" }, { 0x131, "NEX-3N" }, { 0x132, "ILCE-7" }, { 0x133, "NEX-5T" }, { 0x134, "DSC-RX100M2" }, { 0x135, "DSC-RX10" }, { 0x136, "DSC-RX1R" }, { 0x137, "ILCE-7R" }, { 0x138, "ILCE-6000" }, { 0x139, "ILCE-5000" }, { 0x13d, "DSC-RX100M3" }, { 0x13e, "ILCE-7S" }, { 0x13f, "ILCA-77M2" }, { 0x153, "ILCE-5100" }, { 0x154, "ILCE-7M2" }, { 0x155, "DSC-RX100M4" }, { 0x156, "DSC-RX10M2" }, { 0x158, "DSC-RX1RM2" }, { 0x15a, "ILCE-QX1" }, { 0x15b, "ILCE-7RM2" }, { 0x15e, "ILCE-7SM2" }, { 0x161, "ILCA-68" }, { 0x162, "ILCA-99M2" }, { 0x163, "DSC-RX10M3" }, { 0x164, "DSC-RX100M5"}, { 0x165, "ILCE-6300" }, { 0x168, "ILCE-6500"}, }; #ifdef LIBRAW_LIBRARY_BUILD static const libraw_custom_camera_t const_table[] #else static const struct { unsigned fsize; ushort rw, rh; uchar lm, tm, rm, bm, lf, cf, max, flags; char t_make[10], t_model[20]; ushort offset; } table[] #endif = { { 786432,1024, 768, 0, 0, 0, 0, 0,0x94,0,0,"AVT","F-080C" }, { 1447680,1392,1040, 0, 0, 0, 0, 0,0x94,0,0,"AVT","F-145C" }, { 1920000,1600,1200, 0, 0, 0, 0, 0,0x94,0,0,"AVT","F-201C" }, { 5067304,2588,1958, 0, 0, 0, 0, 0,0x94,0,0,"AVT","F-510C" }, { 5067316,2588,1958, 0, 0, 0, 0, 0,0x94,0,0,"AVT","F-510C",12 }, { 10134608,2588,1958, 0, 0, 0, 0, 9,0x94,0,0,"AVT","F-510C" }, { 10134620,2588,1958, 0, 0, 0, 0, 9,0x94,0,0,"AVT","F-510C",12 }, { 16157136,3272,2469, 0, 0, 0, 0, 9,0x94,0,0,"AVT","F-810C" }, { 15980544,3264,2448, 0, 0, 0, 0, 8,0x61,0,1,"AgfaPhoto","DC-833m" }, { 9631728,2532,1902, 0, 0, 0, 0,96,0x61,0,0,"Alcatel","5035D" }, { 31850496,4608,3456, 0, 0, 0, 0,0,0x94,0,0,"GITUP","GIT2 4:3" }, { 23887872,4608,2592, 0, 0, 0, 0,0,0x94,0,0,"GITUP","GIT2 16:9" }, // Android Raw dumps id start // File Size in bytes Horizontal Res Vertical Flag then bayer order eg 0x16 bbgr 0x94 rggb { 1540857,2688,1520, 0, 0, 0, 0, 1,0x61,0,0,"Samsung","S3" }, { 2658304,1212,1096, 0, 0, 0, 0, 1 ,0x16,0,0,"LG","G3FrontMipi" }, { 2842624,1296,1096, 0, 0, 0, 0, 1 ,0x16,0,0,"LG","G3FrontQCOM" }, { 2969600,1976,1200, 0, 0, 0, 0, 1 ,0x16,0,0,"Xiaomi","MI3wMipi" }, { 3170304,1976,1200, 0, 0, 0, 0, 1 ,0x16,0,0,"Xiaomi","MI3wQCOM" }, { 3763584,1584,1184, 0, 0, 0, 0, 96,0x61,0,0,"I_Mobile","I_StyleQ6" }, { 5107712,2688,1520, 0, 0, 0, 0, 1 ,0x61,0,0,"OmniVisi","UltraPixel1" }, { 5382640,2688,1520, 0, 0, 0, 0, 1 ,0x61,0,0,"OmniVisi","UltraPixel2" }, { 5664912,2688,1520, 0, 0, 0, 0, 1 ,0x61,0,0,"OmniVisi","4688" }, { 5664912,2688,1520, 0, 0, 0, 0, 1 ,0x61,0,0,"OmniVisi","4688" }, { 5364240,2688,1520, 0, 0, 0, 0, 1 ,0x61,0,0,"OmniVisi","4688" }, { 6299648,2592,1944, 0, 0, 0, 0, 1 ,0x16,0,0,"OmniVisi","OV5648" }, { 6721536,2592,1944, 0, 0, 0, 0, 0 ,0x16,0,0,"OmniVisi","OV56482" }, { 6746112,2592,1944, 0, 0, 0, 0, 0 ,0x16,0,0,"HTC","OneSV" }, { 9631728,2532,1902, 0, 0, 0, 0, 96,0x61,0,0,"Sony","5mp" }, { 9830400,2560,1920, 0, 0, 0, 0, 96,0x61,0,0,"NGM","ForwardArt" }, { 10186752,3264,2448, 0, 0, 0, 0, 1,0x94,0,0,"Sony","IMX219-mipi 8mp" }, { 10223360,2608,1944, 0, 0, 0, 0, 96,0x16,0,0,"Sony","IMX" }, { 10782464,3282,2448, 0, 0, 0, 0, 0 ,0x16,0,0,"HTC","MyTouch4GSlide" }, { 10788864,3282,2448, 0, 0, 0, 0, 0, 0x16,0,0,"Xperia","L" }, { 15967488,3264,2446, 0, 0, 0, 0, 96,0x16,0,0,"OmniVison","OV8850" }, { 16224256,4208,3082, 0, 0, 0, 0, 1, 0x16,0,0,"LG","G3MipiL" }, { 16424960,4208,3120, 0, 0, 0, 0, 1, 0x16,0,0,"IMX135","MipiL" }, { 17326080,4164,3120, 0, 0, 0, 0, 1, 0x16,0,0,"LG","G3LQCom" }, { 17522688,4212,3120, 0, 0, 0, 0, 0,0x16,0,0,"Sony","IMX135-QCOM" }, { 19906560,4608,3456, 0, 0, 0, 0, 1, 0x16,0,0,"Gione","E7mipi" }, { 19976192,5312,2988, 0, 0, 0, 0, 1, 0x16,0,0,"LG","G4" }, { 20389888,4632,3480, 0, 0, 0, 0, 1, 0x16,0,0,"Xiaomi","RedmiNote3Pro" }, { 20500480,4656,3496, 0, 0, 0, 0, 1,0x94,0,0,"Sony","IMX298-mipi 16mp" }, { 21233664,4608,3456, 0, 0, 0, 0, 1, 0x16,0,0,"Gione","E7qcom" }, { 26023936,4192,3104, 0, 0, 0, 0, 96,0x94,0,0,"THL","5000" }, { 26257920,4208,3120, 0, 0, 0, 0, 96,0x94,0,0,"Sony","IMX214" }, { 26357760,4224,3120, 0, 0, 0, 0, 96,0x61,0,0,"OV","13860" }, { 41312256,5248,3936, 0, 0, 0, 0, 96,0x61,0,0,"Meizu","MX4" }, { 42923008,5344,4016, 0, 0, 0, 0, 96,0x61,0,0,"Sony","IMX230" }, // Android Raw dumps id end { 20137344,3664,2748,0, 0, 0, 0,0x40,0x49,0,0,"Aptina","MT9J003",0xffff }, { 2868726,1384,1036, 0, 0, 0, 0,64,0x49,0,8,"Baumer","TXG14",1078 }, { 5298000,2400,1766,12,12,44, 2,40,0x94,0,2,"Canon","PowerShot SD300" }, { 6553440,2664,1968, 4, 4,44, 4,40,0x94,0,2,"Canon","PowerShot A460" }, { 6573120,2672,1968,12, 8,44, 0,40,0x94,0,2,"Canon","PowerShot A610" }, { 6653280,2672,1992,10, 6,42, 2,40,0x94,0,2,"Canon","PowerShot A530" }, { 7710960,2888,2136,44, 8, 4, 0,40,0x94,0,2,"Canon","PowerShot S3 IS" }, { 9219600,3152,2340,36,12, 4, 0,40,0x94,0,2,"Canon","PowerShot A620" }, { 9243240,3152,2346,12, 7,44,13,40,0x49,0,2,"Canon","PowerShot A470" }, { 10341600,3336,2480, 6, 5,32, 3,40,0x94,0,2,"Canon","PowerShot A720 IS" }, { 10383120,3344,2484,12, 6,44, 6,40,0x94,0,2,"Canon","PowerShot A630" }, { 12945240,3736,2772,12, 6,52, 6,40,0x94,0,2,"Canon","PowerShot A640" }, { 15636240,4104,3048,48,12,24,12,40,0x94,0,2,"Canon","PowerShot A650" }, { 15467760,3720,2772, 6,12,30, 0,40,0x94,0,2,"Canon","PowerShot SX110 IS" }, { 15534576,3728,2778,12, 9,44, 9,40,0x94,0,2,"Canon","PowerShot SX120 IS" }, { 18653760,4080,3048,24,12,24,12,40,0x94,0,2,"Canon","PowerShot SX20 IS" }, { 19131120,4168,3060,92,16, 4, 1,40,0x94,0,2,"Canon","PowerShot SX220 HS" }, { 21936096,4464,3276,25,10,73,12,40,0x16,0,2,"Canon","PowerShot SX30 IS" }, { 24724224,4704,3504, 8,16,56, 8,40,0x49,0,2,"Canon","PowerShot A3300 IS" }, { 30858240,5248,3920, 8,16,56,16,40,0x94,0,2,"Canon","IXUS 160" }, { 1976352,1632,1211, 0, 2, 0, 1, 0,0x94,0,1,"Casio","QV-2000UX" }, { 3217760,2080,1547, 0, 0,10, 1, 0,0x94,0,1,"Casio","QV-3*00EX" }, { 6218368,2585,1924, 0, 0, 9, 0, 0,0x94,0,1,"Casio","QV-5700" }, { 7816704,2867,2181, 0, 0,34,36, 0,0x16,0,1,"Casio","EX-Z60" }, { 2937856,1621,1208, 0, 0, 1, 0, 0,0x94,7,13,"Casio","EX-S20" }, { 4948608,2090,1578, 0, 0,32,34, 0,0x94,7,1,"Casio","EX-S100" }, { 6054400,2346,1720, 2, 0,32, 0, 0,0x94,7,1,"Casio","QV-R41" }, { 7426656,2568,1928, 0, 0, 0, 0, 0,0x94,0,1,"Casio","EX-P505" }, { 7530816,2602,1929, 0, 0,22, 0, 0,0x94,7,1,"Casio","QV-R51" }, { 7542528,2602,1932, 0, 0,32, 0, 0,0x94,7,1,"Casio","EX-Z50" }, { 7562048,2602,1937, 0, 0,25, 0, 0,0x16,7,1,"Casio","EX-Z500" }, { 7753344,2602,1986, 0, 0,32,26, 0,0x94,7,1,"Casio","EX-Z55" }, { 9313536,2858,2172, 0, 0,14,30, 0,0x94,7,1,"Casio","EX-P600" }, { 10834368,3114,2319, 0, 0,27, 0, 0,0x94,0,1,"Casio","EX-Z750" }, { 10843712,3114,2321, 0, 0,25, 0, 0,0x94,0,1,"Casio","EX-Z75" }, { 10979200,3114,2350, 0, 0,32,32, 0,0x94,7,1,"Casio","EX-P700" }, { 12310144,3285,2498, 0, 0, 6,30, 0,0x94,0,1,"Casio","EX-Z850" }, { 12489984,3328,2502, 0, 0,47,35, 0,0x94,0,1,"Casio","EX-Z8" }, { 15499264,3754,2752, 0, 0,82, 0, 0,0x94,0,1,"Casio","EX-Z1050" }, { 18702336,4096,3044, 0, 0,24, 0,80,0x94,7,1,"Casio","EX-ZR100" }, { 7684000,2260,1700, 0, 0, 0, 0,13,0x94,0,1,"Casio","QV-4000" }, { 787456,1024, 769, 0, 1, 0, 0, 0,0x49,0,0,"Creative","PC-CAM 600" }, { 28829184,4384,3288, 0, 0, 0, 0,36,0x61,0,0,"DJI" }, { 15151104,4608,3288, 0, 0, 0, 0, 0,0x94,0,0,"Matrix" }, { 3840000,1600,1200, 0, 0, 0, 0,65,0x49,0,0,"Foculus","531C" }, { 307200, 640, 480, 0, 0, 0, 0, 0,0x94,0,0,"Generic" }, { 62464, 256, 244, 1, 1, 6, 1, 0,0x8d,0,0,"Kodak","DC20" }, { 124928, 512, 244, 1, 1,10, 1, 0,0x8d,0,0,"Kodak","DC20" }, { 1652736,1536,1076, 0,52, 0, 0, 0,0x61,0,0,"Kodak","DCS200" }, { 4159302,2338,1779, 1,33, 1, 2, 0,0x94,0,0,"Kodak","C330" }, { 4162462,2338,1779, 1,33, 1, 2, 0,0x94,0,0,"Kodak","C330",3160 }, { 2247168,1232, 912, 0, 0,16, 0, 0,0x00,0,0,"Kodak","C330" }, { 3370752,1232, 912, 0, 0,16, 0, 0,0x00,0,0,"Kodak","C330" }, { 6163328,2864,2152, 0, 0, 0, 0, 0,0x94,0,0,"Kodak","C603" }, { 6166488,2864,2152, 0, 0, 0, 0, 0,0x94,0,0,"Kodak","C603",3160 }, { 460800, 640, 480, 0, 0, 0, 0, 0,0x00,0,0,"Kodak","C603" }, { 9116448,2848,2134, 0, 0, 0, 0, 0,0x00,0,0,"Kodak","C603" }, { 12241200,4040,3030, 2, 0, 0,13, 0,0x49,0,0,"Kodak","12MP" }, { 12272756,4040,3030, 2, 0, 0,13, 0,0x49,0,0,"Kodak","12MP",31556 }, { 18000000,4000,3000, 0, 0, 0, 0, 0,0x00,0,0,"Kodak","12MP" }, { 614400, 640, 480, 0, 3, 0, 0,64,0x94,0,0,"Kodak","KAI-0340" }, { 15360000,3200,2400, 0, 0, 0, 0,96,0x16,0,0,"Lenovo","A820" }, { 3884928,1608,1207, 0, 0, 0, 0,96,0x16,0,0,"Micron","2010",3212 }, { 1138688,1534, 986, 0, 0, 0, 0, 0,0x61,0,0,"Minolta","RD175",513 }, { 1581060,1305, 969, 0, 0,18, 6, 6,0x1e,4,1,"Nikon","E900" }, { 2465792,1638,1204, 0, 0,22, 1, 6,0x4b,5,1,"Nikon","E950" }, { 2940928,1616,1213, 0, 0, 0, 7,30,0x94,0,1,"Nikon","E2100" }, { 4771840,2064,1541, 0, 0, 0, 1, 6,0xe1,0,1,"Nikon","E990" }, { 4775936,2064,1542, 0, 0, 0, 0,30,0x94,0,1,"Nikon","E3700" }, { 5865472,2288,1709, 0, 0, 0, 1, 6,0xb4,0,1,"Nikon","E4500" }, { 5869568,2288,1710, 0, 0, 0, 0, 6,0x16,0,1,"Nikon","E4300" }, { 7438336,2576,1925, 0, 0, 0, 1, 6,0xb4,0,1,"Nikon","E5000" }, { 8998912,2832,2118, 0, 0, 0, 0,30,0x94,7,1,"Nikon","COOLPIX S6" }, { 5939200,2304,1718, 0, 0, 0, 0,30,0x16,0,0,"Olympus","C770UZ" }, { 3178560,2064,1540, 0, 0, 0, 0, 0,0x94,0,1,"Pentax","Optio S" }, { 4841984,2090,1544, 0, 0,22, 0, 0,0x94,7,1,"Pentax","Optio S" }, { 6114240,2346,1737, 0, 0,22, 0, 0,0x94,7,1,"Pentax","Optio S4" }, { 10702848,3072,2322, 0, 0, 0,21,30,0x94,0,1,"Pentax","Optio 750Z" }, { 4147200,1920,1080, 0, 0, 0, 0, 0,0x49,0,0,"Photron","BC2-HD" }, { 4151666,1920,1080, 0, 0, 0, 0, 0,0x49,0,0,"Photron","BC2-HD",8 }, { 13248000,2208,3000, 0, 0, 0, 0,13,0x61,0,0,"Pixelink","A782" }, { 6291456,2048,1536, 0, 0, 0, 0,96,0x61,0,0,"RoverShot","3320AF" }, { 311696, 644, 484, 0, 0, 0, 0, 0,0x16,0,8,"ST Micro","STV680 VGA" }, { 16098048,3288,2448, 0, 0,24, 0, 9,0x94,0,1,"Samsung","S85" }, { 16215552,3312,2448, 0, 0,48, 0, 9,0x94,0,1,"Samsung","S85" }, { 20487168,3648,2808, 0, 0, 0, 0,13,0x94,5,1,"Samsung","WB550" }, { 24000000,4000,3000, 0, 0, 0, 0,13,0x94,5,1,"Samsung","WB550" }, { 12582980,3072,2048, 0, 0, 0, 0,33,0x61,0,0,"Sinar","",68 }, { 33292868,4080,4080, 0, 0, 0, 0,33,0x61,0,0,"Sinar","",68 }, { 44390468,4080,5440, 0, 0, 0, 0,33,0x61,0,0,"Sinar","",68 }, { 1409024,1376,1024, 0, 0, 1, 0, 0,0x49,0,0,"Sony","XCD-SX910CR" }, { 2818048,1376,1024, 0, 0, 1, 0,97,0x49,0,0,"Sony","XCD-SX910CR" }, }; #ifdef LIBRAW_LIBRARY_BUILD libraw_custom_camera_t table[64 + sizeof(const_table)/sizeof(const_table[0])]; #endif static const char *corp[] = { "AgfaPhoto", "Canon", "Casio", "Epson", "Fujifilm", "Mamiya", "Minolta", "Motorola", "Kodak", "Konica", "Leica", "Nikon", "Nokia", "Olympus", "Pentax", "Phase One", "Ricoh", "Samsung", "Sigma", "Sinar", "Sony" }; #ifdef LIBRAW_LIBRARY_BUILD char head[64], *cp; #else char head[32], *cp; #endif int hlen, flen, fsize, zero_fsize=1, i, c; struct jhead jh; #ifdef LIBRAW_LIBRARY_BUILD unsigned camera_count = parse_custom_cameras(64,table,imgdata.params.custom_camera_strings); for(int q = 0; q < sizeof(const_table)/sizeof(const_table[0]); q++) memmove(&table[q+camera_count],&const_table[q],sizeof(const_table[0])); camera_count += sizeof(const_table)/sizeof(const_table[0]); #endif tiff_flip = flip = filters = UINT_MAX; /* unknown */ raw_height = raw_width = fuji_width = fuji_layout = cr2_slice[0] = 0; maximum = height = width = top_margin = left_margin = 0; cdesc[0] = desc[0] = artist[0] = make[0] = model[0] = model2[0] = 0; iso_speed = shutter = aperture = focal_len = unique_id = 0; tiff_nifds = 0; memset (tiff_ifd, 0, sizeof tiff_ifd); memset (gpsdata, 0, sizeof gpsdata); memset (cblack, 0, sizeof cblack); memset (white, 0, sizeof white); memset (mask, 0, sizeof mask); thumb_offset = thumb_length = thumb_width = thumb_height = 0; load_raw = thumb_load_raw = 0; write_thumb = &CLASS jpeg_thumb; data_offset = meta_offset = meta_length = tiff_bps = tiff_compress = 0; kodak_cbpp = zero_after_ff = dng_version = load_flags = 0; timestamp = shot_order = tiff_samples = black = is_foveon = 0; mix_green = profile_length = data_error = zero_is_bad = 0; pixel_aspect = is_raw = raw_color = 1; tile_width = tile_length = 0; for (i=0; i < 4; i++) { cam_mul[i] = i == 1; pre_mul[i] = i < 3; FORC3 cmatrix[c][i] = 0; FORC3 rgb_cam[c][i] = c == i; } colors = 3; for (i=0; i < 0x10000; i++) curve[i] = i; order = get2(); hlen = get4(); fseek (ifp, 0, SEEK_SET); #ifdef LIBRAW_LIBRARY_BUILD fread (head, 1, 64, ifp); libraw_internal_data.unpacker_data.lenRAFData = libraw_internal_data.unpacker_data.posRAFData = 0; #else fread (head, 1, 32, ifp); #endif fseek (ifp, 0, SEEK_END); flen = fsize = ftell(ifp); if ((cp = (char *) memmem (head, 32, (char*)"MMMM", 4)) || (cp = (char *) memmem (head, 32, (char*)"IIII", 4))) { parse_phase_one (cp-head); if (cp-head && parse_tiff(0)) apply_tiff(); } else if (order == 0x4949 || order == 0x4d4d) { if (!memcmp (head+6,"HEAPCCDR",8)) { data_offset = hlen; #ifdef LIBRAW_LIBRARY_BUILD imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens; #endif parse_ciff (hlen, flen-hlen, 0); load_raw = &CLASS canon_load_raw; } else if (parse_tiff(0)) apply_tiff(); } else if (!memcmp (head,"\xff\xd8\xff\xe1",4) && !memcmp (head+6,"Exif",4)) { fseek (ifp, 4, SEEK_SET); data_offset = 4 + get2(); fseek (ifp, data_offset, SEEK_SET); if (fgetc(ifp) != 0xff) parse_tiff(12); thumb_offset = 0; } else if (!memcmp (head+25,"ARECOYK",7)) { strcpy (make, "Contax"); strcpy (model,"N Digital"); fseek (ifp, 33, SEEK_SET); get_timestamp(1); fseek (ifp, 52, SEEK_SET); switch (get4()) { case 7: iso_speed = 25; break; case 8: iso_speed = 32; break; case 9: iso_speed = 40; break; case 10: iso_speed = 50; break; case 11: iso_speed = 64; break; case 12: iso_speed = 80; break; case 13: iso_speed = 100; break; case 14: iso_speed = 125; break; case 15: iso_speed = 160; break; case 16: iso_speed = 200; break; case 17: iso_speed = 250; break; case 18: iso_speed = 320; break; case 19: iso_speed = 400; break; } shutter = libraw_powf64(2.0f, (((float)get4())/8.0f)) / 16000.0f; FORC4 cam_mul[c ^ (c >> 1)] = get4(); fseek (ifp, 88, SEEK_SET); aperture = libraw_powf64(2.0f, ((float)get4())/16.0f); fseek (ifp, 112, SEEK_SET); focal_len = get4(); #ifdef LIBRAW_LIBRARY_BUILD fseek (ifp, 104, SEEK_SET); imgdata.lens.makernotes.MaxAp4CurFocal = libraw_powf64(2.0f, ((float)get4())/16.0f); fseek (ifp, 124, SEEK_SET); stmread(imgdata.lens.makernotes.Lens, 32, ifp); imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Contax_N; if (imgdata.lens.makernotes.Lens[0]) imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Contax_N; #endif } else if (!strcmp (head, "PXN")) { strcpy (make, "Logitech"); strcpy (model,"Fotoman Pixtura"); } else if (!strcmp (head, "qktk")) { strcpy (make, "Apple"); strcpy (model,"QuickTake 100"); load_raw = &CLASS quicktake_100_load_raw; } else if (!strcmp (head, "qktn")) { strcpy (make, "Apple"); strcpy (model,"QuickTake 150"); load_raw = &CLASS kodak_radc_load_raw; } else if (!memcmp (head,"FUJIFILM",8)) { #ifdef LIBRAW_LIBRARY_BUILD strcpy(model, head+0x1c); memcpy(model2, head+0x3c, 4); model2[4]=0; #endif fseek (ifp, 84, SEEK_SET); thumb_offset = get4(); thumb_length = get4(); fseek (ifp, 92, SEEK_SET); parse_fuji (get4()); if (thumb_offset > 120) { fseek (ifp, 120, SEEK_SET); is_raw += (i = get4())?1:0; if (is_raw == 2 && shot_select) parse_fuji (i); } load_raw = &CLASS unpacked_load_raw; fseek (ifp, 100+28*(shot_select > 0), SEEK_SET); parse_tiff (data_offset = get4()); parse_tiff (thumb_offset+12); apply_tiff(); } else if (!memcmp (head,"RIFF",4)) { fseek (ifp, 0, SEEK_SET); parse_riff(); } else if (!memcmp (head+4,"ftypqt ",9)) { fseek (ifp, 0, SEEK_SET); parse_qt (fsize); is_raw = 0; } else if (!memcmp (head,"\0\001\0\001\0@",6)) { fseek (ifp, 6, SEEK_SET); fread (make, 1, 8, ifp); fread (model, 1, 8, ifp); fread (model2, 1, 16, ifp); data_offset = get2(); get2(); raw_width = get2(); raw_height = get2(); load_raw = &CLASS nokia_load_raw; filters = 0x61616161; } else if (!memcmp (head,"NOKIARAW",8)) { strcpy (make, "NOKIA"); order = 0x4949; fseek (ifp, 300, SEEK_SET); data_offset = get4(); i = get4(); width = get2(); height = get2(); #ifdef LIBRAW_LIBRARY_BUILD // data length should be in range w*h..w*h*2 if(width*height < (LIBRAW_MAX_ALLOC_MB*1024*512L) && width*height>1 && i >= width * height && i <= width*height*2) { #endif switch (tiff_bps = i*8 / (width * height)) { case 8: load_raw = &CLASS eight_bit_load_raw; break; case 10: load_raw = &CLASS nokia_load_raw; } raw_height = height + (top_margin = i / (width * tiff_bps/8) - height); mask[0][3] = 1; filters = 0x61616161; #ifdef LIBRAW_LIBRARY_BUILD } else is_raw = 0; #endif } else if (!memcmp (head,"ARRI",4)) { order = 0x4949; fseek (ifp, 20, SEEK_SET); width = get4(); height = get4(); strcpy (make, "ARRI"); fseek (ifp, 668, SEEK_SET); fread (model, 1, 64, ifp); data_offset = 4096; load_raw = &CLASS packed_load_raw; load_flags = 88; filters = 0x61616161; } else if (!memcmp (head,"XPDS",4)) { order = 0x4949; fseek (ifp, 0x800, SEEK_SET); fread (make, 1, 41, ifp); raw_height = get2(); raw_width = get2(); fseek (ifp, 56, SEEK_CUR); fread (model, 1, 30, ifp); data_offset = 0x10000; load_raw = &CLASS canon_rmf_load_raw; gamma_curve (0, 12.25, 1, 1023); } else if (!memcmp (head+4,"RED1",4)) { strcpy (make, "Red"); strcpy (model,"One"); parse_redcine(); load_raw = &CLASS redcine_load_raw; gamma_curve (1/2.4, 12.92, 1, 4095); filters = 0x49494949; } else if (!memcmp (head,"DSC-Image",9)) parse_rollei(); else if (!memcmp (head,"PWAD",4)) parse_sinar_ia(); else if (!memcmp (head,"\0MRM",4)) parse_minolta(0); else if (!memcmp (head,"FOVb",4)) { #ifdef LIBRAW_LIBRARY_BUILD #ifdef LIBRAW_DEMOSAIC_PACK_GPL2 if(!(imgdata.params.raw_processing_options & LIBRAW_PROCESSING_FORCE_FOVEON_X3F)) parse_foveon(); else #endif parse_x3f(); #else #ifdef LIBRAW_DEMOSAIC_PACK_GPL2 parse_foveon(); #endif #endif } else if (!memcmp (head,"CI",2)) parse_cine(); if(make[0] == 0) #ifdef LIBRAW_LIBRARY_BUILD for (zero_fsize=i=0; i < camera_count; i++) #else for (zero_fsize=i=0; i < sizeof table / sizeof *table; i++) #endif if (fsize == table[i].fsize) { strcpy (make, table[i].t_make ); #ifdef LIBRAW_LIBRARY_BUILD if (!strncmp(make, "Canon",5)) { imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens; imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens; } #endif strcpy (model, table[i].t_model); flip = table[i].flags >> 2; zero_is_bad = table[i].flags & 2; if (table[i].flags & 1) parse_external_jpeg(); data_offset = table[i].offset == 0xffff?0:table[i].offset; raw_width = table[i].rw; raw_height = table[i].rh; left_margin = table[i].lm; top_margin = table[i].tm; width = raw_width - left_margin - table[i].rm; height = raw_height - top_margin - table[i].bm; filters = 0x1010101 * table[i].cf; colors = 4 - !((filters & filters >> 1) & 0x5555); load_flags = table[i].lf; switch (tiff_bps = (fsize-data_offset)*8 / (raw_width*raw_height)) { case 6: load_raw = &CLASS minolta_rd175_load_raw; break; case 8: load_raw = &CLASS eight_bit_load_raw; break; case 10: if ((fsize-data_offset)/raw_height*3 >= raw_width*4) { load_raw = &CLASS android_loose_load_raw; break; } else if (load_flags & 1) { load_raw = &CLASS android_tight_load_raw; break; } case 12: load_flags |= 128; load_raw = &CLASS packed_load_raw; break; case 16: order = 0x4949 | 0x404 * (load_flags & 1); tiff_bps -= load_flags >> 4; tiff_bps -= load_flags = load_flags >> 1 & 7; load_raw = table[i].offset == 0xffff ? &CLASS unpacked_load_raw_reversed : &CLASS unpacked_load_raw; } maximum = (1 << tiff_bps) - (1 << table[i].max); } if (zero_fsize) fsize = 0; if (make[0] == 0) parse_smal (0, flen); if (make[0] == 0) { parse_jpeg(0); fseek(ifp,0,SEEK_END); int sz = ftell(ifp); #ifdef LIBRAW_LIBRARY_BUILD if (!strncmp(model,"RP_imx219",9) && sz >= 0x9cb600 && !fseek (ifp, -0x9cb600, SEEK_END) && fread (head, 1, 0x20, ifp) && !strncmp(head, "BRCM", 4)) { strcpy (make, "Broadcom"); strcpy (model, "RPi IMX219"); if (raw_height > raw_width) flip = 5; data_offset = ftell(ifp) + 0x8000 - 0x20; parse_broadcom(); black = 66; maximum = 0x3ff; load_raw = &CLASS broadcom_load_raw; thumb_offset = 0; thumb_length = sz - 0x9cb600 - 1; } else if (!(strncmp(model,"ov5647",6) && strncmp(model,"RP_OV5647",9)) && sz >= 0x61b800 && !fseek (ifp, -0x61b800, SEEK_END) && fread (head, 1, 0x20, ifp) && !strncmp(head, "BRCM", 4)) { strcpy (make, "Broadcom"); if (!strncmp(model,"ov5647",6)) strcpy (model, "RPi OV5647 v.1"); else strcpy (model, "RPi OV5647 v.2"); if (raw_height > raw_width) flip = 5; data_offset = ftell(ifp) + 0x8000 - 0x20; parse_broadcom(); black = 16; maximum = 0x3ff; load_raw = &CLASS broadcom_load_raw; thumb_offset = 0; thumb_length = sz - 0x61b800 - 1; #else if (!(strncmp(model,"ov",2) && strncmp(model,"RP_OV",5)) && sz>=6404096 && !fseek (ifp, -6404096, SEEK_END) && fread (head, 1, 32, ifp) && !strcmp(head,"BRCMn")) { strcpy (make, "OmniVision"); data_offset = ftell(ifp) + 0x8000-32; width = raw_width; raw_width = 2611; load_raw = &CLASS nokia_load_raw; filters = 0x16161616; #endif } else is_raw = 0; } #ifdef LIBRAW_LIBRARY_BUILD // make sure strings are terminated desc[511] = artist[63] = make[63] = model[63] = model2[63] = 0; #endif for (i=0; i < sizeof corp / sizeof *corp; i++) if (strcasestr (make, corp[i])) /* Simplify company names */ strcpy (make, corp[i]); if ((!strncmp(make,"Kodak",5) || !strncmp(make,"Leica",5)) && ((cp = strcasestr(model," DIGITAL CAMERA")) || (cp = strstr(model,"FILE VERSION")))) *cp = 0; if (!strncasecmp(model,"PENTAX",6)) strcpy (make, "Pentax"); #ifdef LIBRAW_LIBRARY_BUILD remove_trailing_spaces(make,sizeof(make)); remove_trailing_spaces(model,sizeof(model)); #else cp = make + strlen(make); /* Remove trailing spaces */ while (*--cp == ' ') *cp = 0; cp = model + strlen(model); while (*--cp == ' ') *cp = 0; #endif i = strbuflen(make); /* Remove make from model */ if (!strncasecmp (model, make, i) && model[i++] == ' ') memmove (model, model+i, 64-i); if (!strncmp (model,"FinePix ",8)) strcpy (model, model+8); if (!strncmp (model,"Digital Camera ",15)) strcpy (model, model+15); desc[511] = artist[63] = make[63] = model[63] = model2[63] = 0; if (!is_raw) goto notraw; if (!height) height = raw_height; if (!width) width = raw_width; if (height == 2624 && width == 3936) /* Pentax K10D and Samsung GX10 */ { height = 2616; width = 3896; } if (height == 3136 && width == 4864) /* Pentax K20D and Samsung GX20 */ { height = 3124; width = 4688; filters = 0x16161616; } if (width == 4352 && (!strcmp(model,"K-r") || !strcmp(model,"K-x"))) { width = 4309; filters = 0x16161616; } if (width >= 4960 && !strncmp(model,"K-5",3)) { left_margin = 10; width = 4950; filters = 0x16161616; } if (width == 6080 && !strcmp(model,"K-70")) { height = 4016; top_margin=32; width=6020; left_margin = 60; } if (width == 4736 && !strcmp(model,"K-7")) { height = 3122; width = 4684; filters = 0x16161616; top_margin = 2; } if (width == 6080 && !strcmp(model,"K-3 II")) /* moved back */ { left_margin = 4; width = 6040; } if (width == 6080 && !strcmp(model,"K-3")) { left_margin = 4; width = 6040; } if (width == 7424 && !strcmp(model,"645D")) { height = 5502; width = 7328; filters = 0x61616161; top_margin = 29; left_margin = 48; } if (height == 3014 && width == 4096) /* Ricoh GX200 */ width = 4014; if (dng_version) { if (filters == UINT_MAX) filters = 0; if (filters) is_raw *= tiff_samples; else colors = tiff_samples; switch (tiff_compress) { case 0: /* Compression not set, assuming uncompressed */ case 1: load_raw = &CLASS packed_dng_load_raw; break; case 7: load_raw = &CLASS lossless_dng_load_raw; break; #ifdef LIBRAW_LIBRARY_BUILD case 8: load_raw = &CLASS deflate_dng_load_raw; break; #endif case 34892: load_raw = &CLASS lossy_dng_load_raw; break; default: load_raw = 0; } if (!strncmp(make, "Canon",5) && unique_id) { for (i = 0; i < sizeof unique / sizeof *unique; i++) if (unique_id == 0x80000000 + unique[i].id) { strcpy(model, unique[i].t_model); break; } } if (!strncasecmp(make, "Sony",4) && unique_id) { for (i = 0; i < sizeof sonique / sizeof *sonique; i++) if (unique_id == sonique[i].id) { strcpy(model, sonique[i].t_model); break; } } goto dng_skip; } if (!strncmp(make,"Canon",5) && !fsize && tiff_bps != 15) { if (!load_raw) load_raw = &CLASS lossless_jpeg_load_raw; for (i=0; i < sizeof canon / sizeof *canon; i++) if (raw_width == canon[i][0] && raw_height == canon[i][1]) { width = raw_width - (left_margin = canon[i][2]); height = raw_height - (top_margin = canon[i][3]); width -= canon[i][4]; height -= canon[i][5]; mask[0][1] = canon[i][6]; mask[0][3] = -canon[i][7]; mask[1][1] = canon[i][8]; mask[1][3] = -canon[i][9]; if (canon[i][10]) filters = canon[i][10] * 0x01010101; } if ((unique_id | 0x20000) == 0x2720000) { left_margin = 8; top_margin = 16; } } if (!strncmp(make,"Canon",5) && unique_id) { for (i=0; i < sizeof unique / sizeof *unique; i++) if (unique_id == 0x80000000 + unique[i].id) { adobe_coeff ("Canon", unique[i].t_model); strcpy(model,unique[i].t_model); } } if (!strncasecmp(make,"Sony",4) && unique_id) { for (i=0; i < sizeof sonique / sizeof *sonique; i++) if (unique_id == sonique[i].id) { adobe_coeff ("Sony", sonique[i].t_model); strcpy(model,sonique[i].t_model); } } if (!strncmp(make,"Nikon",5)) { if (!load_raw) load_raw = &CLASS packed_load_raw; if (model[0] == 'E') load_flags |= !data_offset << 2 | 2; } /* Set parameters based on camera name (for non-DNG files). */ if (!strcmp(model,"KAI-0340") && find_green (16, 16, 3840, 5120) < 25) { height = 480; top_margin = filters = 0; strcpy (model,"C603"); } if (!strcmp(make, "Sony") && raw_width > 3888 && !black && !cblack[0]) black = 128 << (tiff_bps - 12); if (is_foveon) { if (height*2 < width) pixel_aspect = 0.5; if (height > width) pixel_aspect = 2; filters = 0; #ifdef LIBRAW_DEMOSAIC_PACK_GPL2 if(!(imgdata.params.raw_processing_options & LIBRAW_PROCESSING_FORCE_FOVEON_X3F)) simple_coeff(0); #endif } else if(!strncmp(make,"Pentax",6)) { if(!strncmp(model,"K-1",3)) { top_margin = 18; height = raw_height - top_margin; if(raw_width == 7392) { left_margin = 6; width = 7376; } } } else if (!strncmp(make,"Canon",5) && tiff_bps == 15) { switch (width) { case 3344: width -= 66; case 3872: width -= 6; } if (height > width) { SWAP(height,width); SWAP(raw_height,raw_width); } if (width == 7200 && height == 3888) { raw_width = width = 6480; raw_height = height = 4320; } filters = 0; tiff_samples = colors = 3; load_raw = &CLASS canon_sraw_load_raw; } else if (!strcmp(model,"PowerShot 600")) { height = 613; width = 854; raw_width = 896; colors = 4; filters = 0xe1e4e1e4; load_raw = &CLASS canon_600_load_raw; } else if (!strcmp(model,"PowerShot A5") || !strcmp(model,"PowerShot A5 Zoom")) { height = 773; width = 960; raw_width = 992; pixel_aspect = 256/235.0; filters = 0x1e4e1e4e; goto canon_a5; } else if (!strcmp(model,"PowerShot A50")) { height = 968; width = 1290; raw_width = 1320; filters = 0x1b4e4b1e; goto canon_a5; } else if (!strcmp(model,"PowerShot Pro70")) { height = 1024; width = 1552; filters = 0x1e4b4e1b; canon_a5: colors = 4; tiff_bps = 10; load_raw = &CLASS packed_load_raw; load_flags = 40; } else if (!strcmp(model,"PowerShot Pro90 IS") || !strcmp(model,"PowerShot G1")) { colors = 4; filters = 0xb4b4b4b4; } else if (!strcmp(model,"PowerShot A610")) { if (canon_s2is()) strcpy (model+10, "S2 IS"); } else if (!strcmp(model,"PowerShot SX220 HS")) { mask[1][3] = -4; top_margin=16; left_margin = 92; } else if (!strcmp(model,"PowerShot S120")) { raw_width = 4192; raw_height = 3062; width = 4022; height = 3016; mask[0][0] = top_margin = 31; mask[0][2] = top_margin + height; left_margin = 120; mask[0][1] = 23; mask[0][3] = 72; } else if (!strcmp(model,"PowerShot G16")) { mask[0][0] = 0; mask[0][2] = 80; mask[0][1] = 0; mask[0][3] = 16; top_margin = 29; left_margin = 120; width = raw_width-left_margin-48; height = raw_height-top_margin-14; } else if (!strcmp(model,"PowerShot SX50 HS")) { top_margin = 17; } else if (!strcmp(model,"EOS D2000C")) { filters = 0x61616161; black = curve[200]; } else if (!strcmp(model,"D1")) { cam_mul[0] *= 256/527.0; cam_mul[2] *= 256/317.0; } else if (!strcmp(model,"D1X")) { width -= 4; pixel_aspect = 0.5; } else if (!strcmp(model,"D40X") || !strcmp(model,"D60") || !strcmp(model,"D80") || !strcmp(model,"D3000")) { height -= 3; width -= 4; } else if (!strcmp(model,"D3") || !strcmp(model,"D3S") || !strcmp(model,"D700")) { width -= 4; left_margin = 2; } else if (!strcmp(model,"D3100")) { width -= 28; left_margin = 6; } else if (!strcmp(model,"D5000") || !strcmp(model,"D90")) { width -= 42; } else if (!strcmp(model,"D5100") || !strcmp(model,"D7000") || !strcmp(model,"COOLPIX A")) { width -= 44; } else if (!strcmp(model,"D3200") || !strncmp(model,"D6",2) || !strncmp(model,"D800",4)) { width -= 46; } else if (!strcmp(model,"D4") || !strcmp(model,"Df")) { width -= 52; left_margin = 2; } else if (!strncmp(model,"D40",3) || !strncmp(model,"D50",3) || !strncmp(model,"D70",3)) { width--; } else if (!strcmp(model,"D100")) { if (load_flags) raw_width = (width += 3) + 3; } else if (!strcmp(model,"D200")) { left_margin = 1; width -= 4; filters = 0x94949494; } else if (!strncmp(model,"D2H",3)) { left_margin = 6; width -= 14; } else if (!strncmp(model,"D2X",3)) { if (width == 3264) width -= 32; else width -= 8; } else if (!strncmp(model,"D300",4)) { width -= 32; } else if (!strncmp(make,"Nikon",5) && raw_width == 4032) { if(!strcmp(model,"COOLPIX P7700")) { adobe_coeff ("Nikon","COOLPIX P7700"); maximum = 65504; load_flags = 0; } else if(!strcmp(model,"COOLPIX P7800")) { adobe_coeff ("Nikon","COOLPIX P7800"); maximum = 65504; load_flags = 0; } else if(!strcmp(model,"COOLPIX P340")) load_flags=0; } else if (!strncmp(model,"COOLPIX P",9) && raw_width != 4032) { load_flags = 24; filters = 0x94949494; if (model[9] == '7' && (iso_speed >= 400 || iso_speed==0) && !strstr(software,"V1.2") ) black = 255; } else if (!strncmp(model,"1 ",2)) { height -= 2; } else if (fsize == 1581060) { simple_coeff(3); pre_mul[0] = 1.2085; pre_mul[1] = 1.0943; pre_mul[3] = 1.1103; } else if (fsize == 3178560) { cam_mul[0] *= 4; cam_mul[2] *= 4; } else if (fsize == 4771840) { if (!timestamp && nikon_e995()) strcpy (model, "E995"); if (strcmp(model,"E995")) { filters = 0xb4b4b4b4; simple_coeff(3); pre_mul[0] = 1.196; pre_mul[1] = 1.246; pre_mul[2] = 1.018; } } else if (fsize == 2940928) { if (!timestamp && !nikon_e2100()) strcpy (model,"E2500"); if (!strcmp(model,"E2500")) { height -= 2; load_flags = 6; colors = 4; filters = 0x4b4b4b4b; } } else if (fsize == 4775936) { if (!timestamp) nikon_3700(); if (model[0] == 'E' && atoi(model+1) < 3700) filters = 0x49494949; if (!strcmp(model,"Optio 33WR")) { flip = 1; filters = 0x16161616; } if (make[0] == 'O') { i = find_green (12, 32, 1188864, 3576832); c = find_green (12, 32, 2383920, 2387016); if (abs(i) < abs(c)) { SWAP(i,c); load_flags = 24; } if (i < 0) filters = 0x61616161; } } else if (fsize == 5869568) { if (!timestamp && minolta_z2()) { strcpy (make, "Minolta"); strcpy (model,"DiMAGE Z2"); } load_flags = 6 + 24*(make[0] == 'M'); } else if (fsize == 6291456) { fseek (ifp, 0x300000, SEEK_SET); if ((order = guess_byte_order(0x10000)) == 0x4d4d) { height -= (top_margin = 16); width -= (left_margin = 28); maximum = 0xf5c0; strcpy (make, "ISG"); model[0] = 0; } } else if (!strncmp(make,"Fujifilm",8)) { if (!strcmp(model+7,"S2Pro")) { strcpy (model,"S2Pro"); height = 2144; width = 2880; flip = 6; } else if (load_raw != &CLASS packed_load_raw) maximum = (is_raw == 2 && shot_select) ? 0x2f00 : 0x3e00; top_margin = (raw_height - height) >> 2 << 1; left_margin = (raw_width - width ) >> 2 << 1; if (width == 2848 || width == 3664) filters = 0x16161616; if (width == 4032 || width == 4952) left_margin = 0; if (width == 3328 && (width -= 66)) left_margin = 34; if (width == 4936) left_margin = 4; if (width == 6032) left_margin = 0; if (!strcmp(model,"HS50EXR") || !strcmp(model,"F900EXR")) { width += 2; left_margin = 0; filters = 0x16161616; } if(!strcmp(model,"S5500")) { height -= (top_margin=6); } if (fuji_layout) raw_width *= is_raw; if (filters == 9) FORC(36) ((char *)xtrans)[c] = xtrans_abs[(c/6+top_margin) % 6][(c+left_margin) % 6]; } else if (!strcmp(model,"KD-400Z")) { height = 1712; width = 2312; raw_width = 2336; goto konica_400z; } else if (!strcmp(model,"KD-510Z")) { goto konica_510z; } else if (!strncasecmp(make,"Minolta",7)) { if (!load_raw && (maximum = 0xfff)) load_raw = &CLASS unpacked_load_raw; if (!strncmp(model,"DiMAGE A",8)) { if (!strcmp(model,"DiMAGE A200")) filters = 0x49494949; tiff_bps = 12; load_raw = &CLASS packed_load_raw; } else if (!strncmp(model,"ALPHA",5) || !strncmp(model,"DYNAX",5) || !strncmp(model,"MAXXUM",6)) { sprintf (model+20, "DYNAX %-10s", model+6+(model[0]=='M')); adobe_coeff (make, model+20); load_raw = &CLASS packed_load_raw; } else if (!strncmp(model,"DiMAGE G",8)) { if (model[8] == '4') { height = 1716; width = 2304; } else if (model[8] == '5') { konica_510z: height = 1956; width = 2607; raw_width = 2624; } else if (model[8] == '6') { height = 2136; width = 2848; } data_offset += 14; filters = 0x61616161; konica_400z: load_raw = &CLASS unpacked_load_raw; maximum = 0x3df; order = 0x4d4d; } } else if (!strcmp(model,"*ist D")) { load_raw = &CLASS unpacked_load_raw; data_error = -1; } else if (!strcmp(model,"*ist DS")) { height -= 2; } else if (!strncmp(make,"Samsung",7) && raw_width == 4704) { height -= top_margin = 8; width -= 2 * (left_margin = 8); load_flags = 32; } else if (!strncmp(make,"Samsung",7) && !strcmp(model,"NX3000")) { top_margin = 24; left_margin = 64; width = 5472; height = 3648; filters = 0x61616161; colors = 3; } else if (!strncmp(make,"Samsung",7) && raw_height == 3714) { height -= top_margin = 18; left_margin = raw_width - (width = 5536); if (raw_width != 5600) left_margin = top_margin = 0; filters = 0x61616161; colors = 3; } else if (!strncmp(make,"Samsung",7) && raw_width == 5632) { order = 0x4949; height = 3694; top_margin = 2; width = 5574 - (left_margin = 32 + tiff_bps); if (tiff_bps == 12) load_flags = 80; } else if (!strncmp(make,"Samsung",7) && raw_width == 5664) { height -= top_margin = 17; left_margin = 96; width = 5544; filters = 0x49494949; } else if (!strncmp(make,"Samsung",7) && raw_width == 6496) { filters = 0x61616161; #ifdef LIBRAW_LIBRARY_BUILD if(!black && !cblack[0] && !cblack[1] && !cblack[2] && !cblack[3]) #endif black = 1 << (tiff_bps - 7); } else if (!strcmp(model,"EX1")) { order = 0x4949; height -= 20; top_margin = 2; if ((width -= 6) > 3682) { height -= 10; width -= 46; top_margin = 8; } } else if (!strcmp(model,"WB2000")) { order = 0x4949; height -= 3; top_margin = 2; if ((width -= 10) > 3718) { height -= 28; width -= 56; top_margin = 8; } } else if (strstr(model,"WB550")) { strcpy (model, "WB550"); } else if (!strcmp(model,"EX2F")) { height = 3030; width = 4040; top_margin = 15; left_margin=24; order = 0x4949; filters = 0x49494949; load_raw = &CLASS unpacked_load_raw; } else if (!strcmp(model,"STV680 VGA")) { black = 16; } else if (!strcmp(model,"N95")) { height = raw_height - (top_margin = 2); } else if (!strcmp(model,"640x480")) { gamma_curve (0.45, 4.5, 1, 255); } else if (!strncmp(make,"Hasselblad",10)) { if (load_raw == &CLASS lossless_jpeg_load_raw) load_raw = &CLASS hasselblad_load_raw; if (raw_width == 7262) { height = 5444; width = 7248; top_margin = 4; left_margin = 7; filters = 0x61616161; if(!strncasecmp(model,"H3D",3)) { adobe_coeff("Hasselblad","H3DII-39"); strcpy(model,"H3DII-39"); } } else if (raw_width == 7410 || raw_width == 8282) { height -= 84; width -= 82; top_margin = 4; left_margin = 41; filters = 0x61616161; adobe_coeff("Hasselblad","H4D-40"); strcpy(model,"H4D-40"); } else if( raw_width == 8384) // X1D { top_margin = 96; height -= 96; left_margin = 48; width -= 106; adobe_coeff("Hasselblad","X1D"); } else if (raw_width == 9044) { if(black > 500) { top_margin = 12; left_margin = 44; width = 8956; height = 6708; memset(cblack,0,sizeof(cblack)); adobe_coeff("Hasselblad","H4D-60"); strcpy(model,"H4D-60"); black = 512; } else { height = 6716; width = 8964; top_margin = 8; left_margin = 40; black += load_flags = 256; maximum = 0x8101; strcpy(model,"H3DII-60"); } } else if (raw_width == 4090) { strcpy (model, "V96C"); height -= (top_margin = 6); width -= (left_margin = 3) + 7; filters = 0x61616161; } else if (raw_width == 8282 && raw_height == 6240) { if(!strncasecmp(model,"H5D",3)) { /* H5D 50*/ left_margin = 54; top_margin = 16; width = 8176; height = 6132; black = 256; strcpy(model,"H5D-50"); } else if(!strncasecmp(model,"H3D",3)) { black=0; left_margin = 54; top_margin = 16; width = 8176; height = 6132; memset(cblack,0,sizeof(cblack)); adobe_coeff("Hasselblad","H3D-50"); strcpy(model,"H3D-50"); } } else if (raw_width == 8374 && raw_height == 6304) { /* H5D 50c*/ left_margin = 52; top_margin = 100; width = 8272; height = 6200; black = 256; strcpy(model,"H5D-50c"); } if (tiff_samples > 1) { is_raw = tiff_samples+1; if (!shot_select && !half_size) filters = 0; } } else if (!strncmp(make,"Sinar",5)) { if (!load_raw) load_raw = &CLASS unpacked_load_raw; if (is_raw > 1 && !shot_select && !half_size) filters = 0; maximum = 0x3fff; } else if (!strncmp(make,"Leaf",4)) { maximum = 0x3fff; fseek (ifp, data_offset, SEEK_SET); if (ljpeg_start (&jh, 1) && jh.bits == 15) maximum = 0x1fff; if (tiff_samples > 1) filters = 0; if (tiff_samples > 1 || tile_length < raw_height) { load_raw = &CLASS leaf_hdr_load_raw; raw_width = tile_width; } if ((width | height) == 2048) { if (tiff_samples == 1) { filters = 1; strcpy (cdesc, "RBTG"); strcpy (model, "CatchLight"); top_margin = 8; left_margin = 18; height = 2032; width = 2016; } else { strcpy (model, "DCB2"); top_margin = 10; left_margin = 16; height = 2028; width = 2022; } } else if (width+height == 3144+2060) { if (!model[0]) strcpy (model, "Cantare"); if (width > height) { top_margin = 6; left_margin = 32; height = 2048; width = 3072; filters = 0x61616161; } else { left_margin = 6; top_margin = 32; width = 2048; height = 3072; filters = 0x16161616; } if (!cam_mul[0] || model[0] == 'V') filters = 0; else is_raw = tiff_samples; } else if (width == 2116) { strcpy (model, "Valeo 6"); height -= 2 * (top_margin = 30); width -= 2 * (left_margin = 55); filters = 0x49494949; } else if (width == 3171) { strcpy (model, "Valeo 6"); height -= 2 * (top_margin = 24); width -= 2 * (left_margin = 24); filters = 0x16161616; } } else if (!strncmp(make,"Leica",5) || !strncmp(make,"Panasonic",9) || !strncasecmp(make,"YUNEEC",6)) { if (raw_width > 0&& ((flen - data_offset) / (raw_width*8/7) == raw_height) ) load_raw = &CLASS panasonic_load_raw; if (!load_raw) { load_raw = &CLASS unpacked_load_raw; load_flags = 4; } zero_is_bad = 1; if ((height += 12) > raw_height) height = raw_height; for (i=0; i < sizeof pana / sizeof *pana; i++) if (raw_width == pana[i][0] && raw_height == pana[i][1]) { left_margin = pana[i][2]; top_margin = pana[i][3]; width += pana[i][4]; height += pana[i][5]; } filters = 0x01010101 * (uchar) "\x94\x61\x49\x16" [((filters-1) ^ (left_margin & 1) ^ (top_margin << 1)) & 3]; } else if (!strcmp(model,"C770UZ")) { height = 1718; width = 2304; filters = 0x16161616; load_raw = &CLASS packed_load_raw; load_flags = 30; } else if (!strncmp(make,"Olympus",7)) { height += height & 1; if (exif_cfa) filters = exif_cfa; if (width == 4100) width -= 4; if (width == 4080) width -= 24; if (width == 9280) { width -= 6; height -= 6; } if (load_raw == &CLASS unpacked_load_raw) load_flags = 4; tiff_bps = 12; if (!strcmp(model,"E-300") || !strcmp(model,"E-500")) { width -= 20; if (load_raw == &CLASS unpacked_load_raw) { maximum = 0xfc3; memset (cblack, 0, sizeof cblack); } } else if (!strcmp(model,"STYLUS1")) { width -= 14; maximum = 0xfff; } else if (!strcmp(model,"E-330")) { width -= 30; if (load_raw == &CLASS unpacked_load_raw) maximum = 0xf79; } else if (!strcmp(model,"SP550UZ")) { thumb_length = flen - (thumb_offset = 0xa39800); thumb_height = 480; thumb_width = 640; } else if (!strcmp(model,"TG-4")) { width -= 16; } } else if (!strcmp(model,"N Digital")) { height = 2047; width = 3072; filters = 0x61616161; data_offset = 0x1a00; load_raw = &CLASS packed_load_raw; } else if (!strcmp(model,"DSC-F828")) { width = 3288; left_margin = 5; mask[1][3] = -17; data_offset = 862144; load_raw = &CLASS sony_load_raw; filters = 0x9c9c9c9c; colors = 4; strcpy (cdesc, "RGBE"); } else if (!strcmp(model,"DSC-V3")) { width = 3109; left_margin = 59; mask[0][1] = 9; data_offset = 787392; load_raw = &CLASS sony_load_raw; } else if (!strncmp(make,"Sony",4) && raw_width == 3984) { width = 3925; order = 0x4d4d; } else if (!strncmp(make,"Sony",4) && raw_width == 4288) { width -= 32; } else if (!strcmp(make, "Sony") && raw_width == 4600) { if (!strcmp(model, "DSLR-A350")) height -= 4; black = 0; } else if (!strncmp(make,"Sony",4) && raw_width == 4928) { if (height < 3280) width -= 8; } else if (!strncmp(make,"Sony",4) && raw_width == 5504) { // ILCE-3000//5000 width -= height > 3664 ? 8 : 32; } else if (!strncmp(make,"Sony",4) && raw_width == 6048) { width -= 24; if (strstr(model,"RX1") || strstr(model,"A99")) width -= 6; } else if (!strncmp(make,"Sony",4) && raw_width == 7392) { width -= 30; } else if (!strncmp(make,"Sony",4) && raw_width == 8000) { width -= 32; if (!strncmp(model, "DSC", 3)) { tiff_bps = 14; load_raw = &CLASS unpacked_load_raw; } } else if (!strcmp(model,"DSLR-A100")) { if (width == 3880) { height--; width = ++raw_width; } else { height -= 4; width -= 4; order = 0x4d4d; load_flags = 2; } filters = 0x61616161; } else if (!strcmp(model,"PIXL")) { height -= top_margin = 4; width -= left_margin = 32; gamma_curve (0, 7, 1, 255); } else if (!strcmp(model,"C603") || !strcmp(model,"C330") || !strcmp(model,"12MP")) { order = 0x4949; if (filters && data_offset) { fseek (ifp, data_offset < 4096 ? 168 : 5252, SEEK_SET); read_shorts (curve, 256); } else gamma_curve (0, 3.875, 1, 255); load_raw = filters ? &CLASS eight_bit_load_raw : strcmp(model,"C330") ? &CLASS kodak_c603_load_raw : &CLASS kodak_c330_load_raw; load_flags = tiff_bps > 16; tiff_bps = 8; } else if (!strncasecmp(model,"EasyShare",9)) { data_offset = data_offset < 0x15000 ? 0x15000 : 0x17000; load_raw = &CLASS packed_load_raw; } else if (!strncasecmp(make,"Kodak",5)) { if (filters == UINT_MAX) filters = 0x61616161; if (!strncmp(model,"NC2000",6) || !strncmp(model,"EOSDCS",6) || !strncmp(model,"DCS4",4)) { width -= 4; left_margin = 2; if (model[6] == ' ') model[6] = 0; if (!strcmp(model,"DCS460A")) goto bw; } else if (!strcmp(model,"DCS660M")) { black = 214; goto bw; } else if (!strcmp(model,"DCS760M")) { bw: colors = 1; filters = 0; } if (!strcmp(model+4,"20X")) strcpy (cdesc, "MYCY"); if (strstr(model,"DC25")) { strcpy (model, "DC25"); data_offset = 15424; } if (!strncmp(model,"DC2",3)) { raw_height = 2 + (height = 242); if (!strncmp(model, "DC290", 5)) iso_speed = 100; if (!strncmp(model, "DC280", 5)) iso_speed = 70; if (flen < 100000) { raw_width = 256; width = 249; pixel_aspect = (4.0*height) / (3.0*width); } else { raw_width = 512; width = 501; pixel_aspect = (493.0*height) / (373.0*width); } top_margin = left_margin = 1; colors = 4; filters = 0x8d8d8d8d; simple_coeff(1); pre_mul[1] = 1.179; pre_mul[2] = 1.209; pre_mul[3] = 1.036; load_raw = &CLASS eight_bit_load_raw; } else if (!strcmp(model,"40")) { strcpy (model, "DC40"); height = 512; width = 768; data_offset = 1152; load_raw = &CLASS kodak_radc_load_raw; tiff_bps = 12; } else if (strstr(model,"DC50")) { strcpy (model, "DC50"); height = 512; width = 768; iso_speed=84; data_offset = 19712; load_raw = &CLASS kodak_radc_load_raw; } else if (strstr(model,"DC120")) { strcpy (model, "DC120"); height = 976; width = 848; iso_speed=160; pixel_aspect = height/0.75/width; load_raw = tiff_compress == 7 ? &CLASS kodak_jpeg_load_raw : &CLASS kodak_dc120_load_raw; } else if (!strcmp(model,"DCS200")) { thumb_height = 128; thumb_width = 192; thumb_offset = 6144; thumb_misc = 360; iso_speed=140; write_thumb = &CLASS layer_thumb; black = 17; } } else if (!strcmp(model,"Fotoman Pixtura")) { height = 512; width = 768; data_offset = 3632; load_raw = &CLASS kodak_radc_load_raw; filters = 0x61616161; simple_coeff(2); } else if (!strncmp(model,"QuickTake",9)) { if (head[5]) strcpy (model+10, "200"); fseek (ifp, 544, SEEK_SET); height = get2(); width = get2(); data_offset = (get4(),get2()) == 30 ? 738:736; if (height > width) { SWAP(height,width); fseek (ifp, data_offset-6, SEEK_SET); flip = ~get2() & 3 ? 5:6; } filters = 0x61616161; } else if (!strncmp(make,"Rollei",6) && !load_raw) { switch (raw_width) { case 1316: height = 1030; width = 1300; top_margin = 1; left_margin = 6; break; case 2568: height = 1960; width = 2560; top_margin = 2; left_margin = 8; } filters = 0x16161616; load_raw = &CLASS rollei_load_raw; } else if (!strcmp(model,"GRAS-50S5C")) { height = 2048; width = 2440; load_raw = &CLASS unpacked_load_raw; data_offset = 0; filters = 0x49494949; order = 0x4949; maximum = 0xfffC; } else if (!strcmp(model,"BB-500CL")) { height = 2058; width = 2448; load_raw = &CLASS unpacked_load_raw; data_offset = 0; filters = 0x94949494; order = 0x4949; maximum = 0x3fff; } else if (!strcmp(model,"BB-500GE")) { height = 2058; width = 2456; load_raw = &CLASS unpacked_load_raw; data_offset = 0; filters = 0x94949494; order = 0x4949; maximum = 0x3fff; } else if (!strcmp(model,"SVS625CL")) { height = 2050; width = 2448; load_raw = &CLASS unpacked_load_raw; data_offset = 0; filters = 0x94949494; order = 0x4949; maximum = 0x0fff; } /* Early reject for damaged images */ if (!load_raw || height < 22 || width < 22 || #ifdef LIBRAW_LIBRARY_BUILD (tiff_bps > 16 && load_raw != &LibRaw::deflate_dng_load_raw) #else tiff_bps > 16 #endif || tiff_samples > 4 || colors > 4 || colors < 1 /* alloc in unpack() may be fooled by size adjust */ || ( (int)width + (int)left_margin > 65535) || ( (int)height + (int)top_margin > 65535) ) { is_raw = 0; #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_IDENTIFY,1,2); #endif return; } if (!model[0]) sprintf (model, "%dx%d", width, height); if (filters == UINT_MAX) filters = 0x94949494; if (thumb_offset && !thumb_height) { fseek (ifp, thumb_offset, SEEK_SET); if (ljpeg_start (&jh, 1)) { thumb_width = jh.wide; thumb_height = jh.high; } } dng_skip: #ifdef LIBRAW_LIBRARY_BUILD if(dng_version) /* Override black level by DNG tags */ { black = imgdata.color.dng_levels.dng_black; int ll = LIM(0, (sizeof(cblack)/sizeof(cblack[0])), (sizeof(imgdata.color.dng_levels.dng_cblack)/sizeof(imgdata.color.dng_levels.dng_cblack[0]))); for(int i=0; i < ll; i++) cblack[i] = imgdata.color.dng_levels.dng_cblack[i]; } #endif /* Early reject for damaged images */ if (!load_raw || height < 22 || width < 22 || #ifdef LIBRAW_LIBRARY_BUILD (tiff_bps > 16 && load_raw != &LibRaw::deflate_dng_load_raw) #else tiff_bps > 16 #endif || tiff_samples > 4 || colors > 4 || colors < 1) { is_raw = 0; #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_IDENTIFY,1,2); #endif return; } if ((use_camera_matrix & ((use_camera_wb || dng_version) | 0x2) ) && cmatrix[0][0] > 0.125) { memcpy (rgb_cam, cmatrix, sizeof cmatrix); raw_color = 0; } if (raw_color) adobe_coeff (make, model); #ifdef LIBRAW_LIBRARY_BUILD else if(imgdata.color.cam_xyz[0][0]<0.01) adobe_coeff (make, model,1); #endif if (load_raw == &CLASS kodak_radc_load_raw) if (raw_color) adobe_coeff ("Apple","Quicktake"); #ifdef LIBRAW_LIBRARY_BUILD // Clear erorneus fuji_width if not set through parse_fuji or for DNG if(fuji_width && !dng_version && !(imgdata.process_warnings & LIBRAW_WARN_PARSEFUJI_PROCESSED )) fuji_width = 0; #endif if (fuji_width) { fuji_width = width >> !fuji_layout; filters = fuji_width & 1 ? 0x94949494 : 0x49494949; width = (height >> fuji_layout) + fuji_width; height = width - 1; pixel_aspect = 1; } else { if (raw_height < height) raw_height = height; if (raw_width < width ) raw_width = width; } if (!tiff_bps) tiff_bps = 12; if (!maximum) { maximum = (1 << tiff_bps) - 1; if(maximum < 0x10000 && curve[maximum]>0 && load_raw == &CLASS sony_arw2_load_raw) maximum = curve[maximum]; } if (!load_raw || height < 22 || width < 22 || #ifdef LIBRAW_LIBRARY_BUILD (tiff_bps > 16 && load_raw != &LibRaw::deflate_dng_load_raw) #else tiff_bps > 16 #endif || tiff_samples > 6 || colors > 4) is_raw = 0; if(raw_width < 22 || raw_width > 64000 || raw_height < 22 || raw_width > 64000) is_raw = 0; #ifdef NO_JASPER if (load_raw == &CLASS redcine_load_raw) { #ifdef DCRAW_VERBOSE fprintf (stderr,_("%s: You must link dcraw with %s!!\n"), ifname, "libjasper"); #endif is_raw = 0; #ifdef LIBRAW_LIBRARY_BUILD imgdata.process_warnings |= LIBRAW_WARN_NO_JASPER; #endif } #endif #ifdef NO_JPEG if (load_raw == &CLASS kodak_jpeg_load_raw || load_raw == &CLASS lossy_dng_load_raw) { #ifdef DCRAW_VERBOSE fprintf (stderr,_("%s: You must link dcraw with %s!!\n"), ifname, "libjpeg"); #endif is_raw = 0; #ifdef LIBRAW_LIBRARY_BUILD imgdata.process_warnings |= LIBRAW_WARN_NO_JPEGLIB; #endif } #endif if (!cdesc[0]) strcpy (cdesc, colors == 3 ? "RGBG":"GMCY"); if (!raw_height) raw_height = height; if (!raw_width ) raw_width = width; if (filters > 999 && colors == 3) filters |= ((filters >> 2 & 0x22222222) | (filters << 2 & 0x88888888)) & filters << 1; notraw: if (flip == UINT_MAX) flip = tiff_flip; if (flip == UINT_MAX) flip = 0; // Convert from degrees to bit-field if needed if(flip > 89 || flip < -89) { switch ((flip+3600) % 360) { case 270: flip = 5; break; case 180: flip = 3; break; case 90: flip = 6; break; } } #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_IDENTIFY,1,2); #endif } void CLASS convert_to_rgb() { #ifndef LIBRAW_LIBRARY_BUILD int row, col, c; #endif int i, j, k; #ifndef LIBRAW_LIBRARY_BUILD ushort *img; float out[3]; #endif float out_cam[3][4]; double num, inverse[3][3]; static const double xyzd50_srgb[3][3] = { { 0.436083, 0.385083, 0.143055 }, { 0.222507, 0.716888, 0.060608 }, { 0.013930, 0.097097, 0.714022 } }; static const double rgb_rgb[3][3] = { { 1,0,0 }, { 0,1,0 }, { 0,0,1 } }; static const double adobe_rgb[3][3] = { { 0.715146, 0.284856, 0.000000 }, { 0.000000, 1.000000, 0.000000 }, { 0.000000, 0.041166, 0.958839 } }; static const double wide_rgb[3][3] = { { 0.593087, 0.404710, 0.002206 }, { 0.095413, 0.843149, 0.061439 }, { 0.011621, 0.069091, 0.919288 } }; static const double prophoto_rgb[3][3] = { { 0.529317, 0.330092, 0.140588 }, { 0.098368, 0.873465, 0.028169 }, { 0.016879, 0.117663, 0.865457 } }; static const double aces_rgb[3][3] = { { 0.432996, 0.375380, 0.189317 }, { 0.089427, 0.816523, 0.102989 }, { 0.019165, 0.118150, 0.941914 } }; static const double (*out_rgb[])[3] = { rgb_rgb, adobe_rgb, wide_rgb, prophoto_rgb, xyz_rgb, aces_rgb }; static const char *name[] = { "sRGB", "Adobe RGB (1998)", "WideGamut D65", "ProPhoto D65", "XYZ", "ACES" }; static const unsigned phead[] = { 1024, 0, 0x2100000, 0x6d6e7472, 0x52474220, 0x58595a20, 0, 0, 0, 0x61637370, 0, 0, 0x6e6f6e65, 0, 0, 0, 0, 0xf6d6, 0x10000, 0xd32d }; unsigned pbody[] = { 10, 0x63707274, 0, 36, /* cprt */ 0x64657363, 0, 40, /* desc */ 0x77747074, 0, 20, /* wtpt */ 0x626b7074, 0, 20, /* bkpt */ 0x72545243, 0, 14, /* rTRC */ 0x67545243, 0, 14, /* gTRC */ 0x62545243, 0, 14, /* bTRC */ 0x7258595a, 0, 20, /* rXYZ */ 0x6758595a, 0, 20, /* gXYZ */ 0x6258595a, 0, 20 }; /* bXYZ */ static const unsigned pwhite[] = { 0xf351, 0x10000, 0x116cc }; unsigned pcurve[] = { 0x63757276, 0, 1, 0x1000000 }; #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_CONVERT_RGB,0,2); #endif gamma_curve (gamm[0], gamm[1], 0, 0); memcpy (out_cam, rgb_cam, sizeof out_cam); #ifndef LIBRAW_LIBRARY_BUILD raw_color |= colors == 1 || document_mode || output_color < 1 || output_color > 6; #else raw_color |= colors == 1 || output_color < 1 || output_color > 6; #endif if (!raw_color) { oprof = (unsigned *) calloc (phead[0], 1); merror (oprof, "convert_to_rgb()"); memcpy (oprof, phead, sizeof phead); if (output_color == 5) oprof[4] = oprof[5]; oprof[0] = 132 + 12*pbody[0]; for (i=0; i < pbody[0]; i++) { oprof[oprof[0]/4] = i ? (i > 1 ? 0x58595a20 : 0x64657363) : 0x74657874; pbody[i*3+2] = oprof[0]; oprof[0] += (pbody[i*3+3] + 3) & -4; } memcpy (oprof+32, pbody, sizeof pbody); oprof[pbody[5]/4+2] = strlen(name[output_color-1]) + 1; memcpy ((char *)oprof+pbody[8]+8, pwhite, sizeof pwhite); pcurve[3] = (short)(256/gamm[5]+0.5) << 16; for (i=4; i < 7; i++) memcpy ((char *)oprof+pbody[i*3+2], pcurve, sizeof pcurve); pseudoinverse ((double (*)[3]) out_rgb[output_color-1], inverse, 3); for (i=0; i < 3; i++) for (j=0; j < 3; j++) { for (num = k=0; k < 3; k++) num += xyzd50_srgb[i][k] * inverse[j][k]; oprof[pbody[j*3+23]/4+i+2] = num * 0x10000 + 0.5; } for (i=0; i < phead[0]/4; i++) oprof[i] = htonl(oprof[i]); strcpy ((char *)oprof+pbody[2]+8, "auto-generated by dcraw"); strcpy ((char *)oprof+pbody[5]+12, name[output_color-1]); for (i=0; i < 3; i++) for (j=0; j < colors; j++) for (out_cam[i][j] = k=0; k < 3; k++) out_cam[i][j] += out_rgb[output_color-1][i][k] * rgb_cam[k][j]; } #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr, raw_color ? _("Building histograms...\n") : _("Converting to %s colorspace...\n"), name[output_color-1]); #endif #ifdef LIBRAW_LIBRARY_BUILD convert_to_rgb_loop(out_cam); #else memset (histogram, 0, sizeof histogram); for (img=image[0], row=0; row < height; row++) for (col=0; col < width; col++, img+=4) { if (!raw_color) { out[0] = out[1] = out[2] = 0; FORCC { out[0] += out_cam[0][c] * img[c]; out[1] += out_cam[1][c] * img[c]; out[2] += out_cam[2][c] * img[c]; } FORC3 img[c] = CLIP((int) out[c]); } else if (document_mode) img[0] = img[fcol(row,col)]; FORCC histogram[c][img[c] >> 3]++; } #endif if (colors == 4 && output_color) colors = 3; #ifndef LIBRAW_LIBRARY_BUILD if (document_mode && filters) colors = 1; #endif #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_CONVERT_RGB,1,2); #endif } void CLASS fuji_rotate() { int i, row, col; double step; float r, c, fr, fc; unsigned ur, uc; ushort wide, high, (*img)[4], (*pix)[4]; if (!fuji_width) return; #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("Rotating image 45 degrees...\n")); #endif fuji_width = (fuji_width - 1 + shrink) >> shrink; step = sqrt(0.5); wide = fuji_width / step; high = (height - fuji_width) / step; img = (ushort (*)[4]) calloc (high, wide*sizeof *img); merror (img, "fuji_rotate()"); #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_FUJI_ROTATE,0,2); #endif for (row=0; row < high; row++) for (col=0; col < wide; col++) { ur = r = fuji_width + (row-col)*step; uc = c = (row+col)*step; if (ur > height-2 || uc > width-2) continue; fr = r - ur; fc = c - uc; pix = image + ur*width + uc; for (i=0; i < colors; i++) img[row*wide+col][i] = (pix[ 0][i]*(1-fc) + pix[ 1][i]*fc) * (1-fr) + (pix[width][i]*(1-fc) + pix[width+1][i]*fc) * fr; } free (image); width = wide; height = high; image = img; fuji_width = 0; #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_FUJI_ROTATE,1,2); #endif } void CLASS stretch() { ushort newdim, (*img)[4], *pix0, *pix1; int row, col, c; double rc, frac; if (pixel_aspect == 1) return; #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_STRETCH,0,2); #endif #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("Stretching the image...\n")); #endif if (pixel_aspect < 1) { newdim = height / pixel_aspect + 0.5; img = (ushort (*)[4]) calloc (width, newdim*sizeof *img); merror (img, "stretch()"); for (rc=row=0; row < newdim; row++, rc+=pixel_aspect) { frac = rc - (c = rc); pix0 = pix1 = image[c*width]; if (c+1 < height) pix1 += width*4; for (col=0; col < width; col++, pix0+=4, pix1+=4) FORCC img[row*width+col][c] = pix0[c]*(1-frac) + pix1[c]*frac + 0.5; } height = newdim; } else { newdim = width * pixel_aspect + 0.5; img = (ushort (*)[4]) calloc (height, newdim*sizeof *img); merror (img, "stretch()"); for (rc=col=0; col < newdim; col++, rc+=1/pixel_aspect) { frac = rc - (c = rc); pix0 = pix1 = image[c]; if (c+1 < width) pix1 += 4; for (row=0; row < height; row++, pix0+=width*4, pix1+=width*4) FORCC img[row*newdim+col][c] = pix0[c]*(1-frac) + pix1[c]*frac + 0.5; } width = newdim; } free (image); image = img; #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_STRETCH,1,2); #endif } int CLASS flip_index (int row, int col) { if (flip & 4) SWAP(row,col); if (flip & 2) row = iheight - 1 - row; if (flip & 1) col = iwidth - 1 - col; return row * iwidth + col; } void CLASS tiff_set (struct tiff_hdr *th, ushort *ntag, ushort tag, ushort type, int count, int val) { struct tiff_tag *tt; int c; tt = (struct tiff_tag *)(ntag+1) + (*ntag)++; tt->val.i = val; if (type == 1 && count <= 4) FORC(4) tt->val.c[c] = val >> (c << 3); else if (type == 2) { count = strnlen((char *)th + val, count-1) + 1; if (count <= 4) FORC(4) tt->val.c[c] = ((char *)th)[val+c]; } else if (type == 3 && count <= 2) FORC(2) tt->val.s[c] = val >> (c << 4); tt->count = count; tt->type = type; tt->tag = tag; } #define TOFF(ptr) ((char *)(&(ptr)) - (char *)th) void CLASS tiff_head (struct tiff_hdr *th, int full) { int c, psize=0; struct tm *t; memset (th, 0, sizeof *th); th->t_order = htonl(0x4d4d4949) >> 16; th->magic = 42; th->ifd = 10; th->rat[0] = th->rat[2] = 300; th->rat[1] = th->rat[3] = 1; FORC(6) th->rat[4+c] = 1000000; th->rat[4] *= shutter; th->rat[6] *= aperture; th->rat[8] *= focal_len; strncpy (th->t_desc, desc, 512); strncpy (th->t_make, make, 64); strncpy (th->t_model, model, 64); strcpy (th->soft, "dcraw v" DCRAW_VERSION); t = localtime (×tamp); sprintf (th->date, "%04d:%02d:%02d %02d:%02d:%02d", t->tm_year+1900,t->tm_mon+1,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec); strncpy (th->t_artist, artist, 64); if (full) { tiff_set (th, &th->ntag, 254, 4, 1, 0); tiff_set (th, &th->ntag, 256, 4, 1, width); tiff_set (th, &th->ntag, 257, 4, 1, height); tiff_set (th, &th->ntag, 258, 3, colors, output_bps); if (colors > 2) th->tag[th->ntag-1].val.i = TOFF(th->bps); FORC4 th->bps[c] = output_bps; tiff_set (th, &th->ntag, 259, 3, 1, 1); tiff_set (th, &th->ntag, 262, 3, 1, 1 + (colors > 1)); } tiff_set (th, &th->ntag, 270, 2, 512, TOFF(th->t_desc)); tiff_set (th, &th->ntag, 271, 2, 64, TOFF(th->t_make)); tiff_set (th, &th->ntag, 272, 2, 64, TOFF(th->t_model)); if (full) { if (oprof) psize = ntohl(oprof[0]); tiff_set (th, &th->ntag, 273, 4, 1, sizeof *th + psize); tiff_set (th, &th->ntag, 277, 3, 1, colors); tiff_set (th, &th->ntag, 278, 4, 1, height); tiff_set (th, &th->ntag, 279, 4, 1, height*width*colors*output_bps/8); } else tiff_set (th, &th->ntag, 274, 3, 1, "12435867"[flip]-'0'); tiff_set (th, &th->ntag, 282, 5, 1, TOFF(th->rat[0])); tiff_set (th, &th->ntag, 283, 5, 1, TOFF(th->rat[2])); tiff_set (th, &th->ntag, 284, 3, 1, 1); tiff_set (th, &th->ntag, 296, 3, 1, 2); tiff_set (th, &th->ntag, 305, 2, 32, TOFF(th->soft)); tiff_set (th, &th->ntag, 306, 2, 20, TOFF(th->date)); tiff_set (th, &th->ntag, 315, 2, 64, TOFF(th->t_artist)); tiff_set (th, &th->ntag, 34665, 4, 1, TOFF(th->nexif)); if (psize) tiff_set (th, &th->ntag, 34675, 7, psize, sizeof *th); tiff_set (th, &th->nexif, 33434, 5, 1, TOFF(th->rat[4])); tiff_set (th, &th->nexif, 33437, 5, 1, TOFF(th->rat[6])); tiff_set (th, &th->nexif, 34855, 3, 1, iso_speed); tiff_set (th, &th->nexif, 37386, 5, 1, TOFF(th->rat[8])); if (gpsdata[1]) { tiff_set (th, &th->ntag, 34853, 4, 1, TOFF(th->ngps)); tiff_set (th, &th->ngps, 0, 1, 4, 0x202); tiff_set (th, &th->ngps, 1, 2, 2, gpsdata[29]); tiff_set (th, &th->ngps, 2, 5, 3, TOFF(th->gps[0])); tiff_set (th, &th->ngps, 3, 2, 2, gpsdata[30]); tiff_set (th, &th->ngps, 4, 5, 3, TOFF(th->gps[6])); tiff_set (th, &th->ngps, 5, 1, 1, gpsdata[31]); tiff_set (th, &th->ngps, 6, 5, 1, TOFF(th->gps[18])); tiff_set (th, &th->ngps, 7, 5, 3, TOFF(th->gps[12])); tiff_set (th, &th->ngps, 18, 2, 12, TOFF(th->gps[20])); tiff_set (th, &th->ngps, 29, 2, 12, TOFF(th->gps[23])); memcpy (th->gps, gpsdata, sizeof th->gps); } } #ifdef LIBRAW_LIBRARY_BUILD void CLASS jpeg_thumb_writer (FILE *tfp,char *t_humb,int t_humb_length) { ushort exif[5]; struct tiff_hdr th; fputc (0xff, tfp); fputc (0xd8, tfp); if (strcmp (t_humb+6, "Exif")) { memcpy (exif, "\xff\xe1 Exif\0\0", 10); exif[1] = htons (8 + sizeof th); fwrite (exif, 1, sizeof exif, tfp); tiff_head (&th, 0); fwrite (&th, 1, sizeof th, tfp); } fwrite (t_humb+2, 1, t_humb_length-2, tfp); } void CLASS jpeg_thumb() { char *thumb; thumb = (char *) malloc (thumb_length); merror (thumb, "jpeg_thumb()"); fread (thumb, 1, thumb_length, ifp); jpeg_thumb_writer(ofp,thumb,thumb_length); free (thumb); } #else void CLASS jpeg_thumb() { char *thumb; ushort exif[5]; struct tiff_hdr th; thumb = (char *) malloc (thumb_length); merror (thumb, "jpeg_thumb()"); fread (thumb, 1, thumb_length, ifp); fputc (0xff, ofp); fputc (0xd8, ofp); if (strcmp (thumb+6, "Exif")) { memcpy (exif, "\xff\xe1 Exif\0\0", 10); exif[1] = htons (8 + sizeof th); fwrite (exif, 1, sizeof exif, ofp); tiff_head (&th, 0); fwrite (&th, 1, sizeof th, ofp); } fwrite (thumb+2, 1, thumb_length-2, ofp); free (thumb); } #endif void CLASS write_ppm_tiff() { struct tiff_hdr th; uchar *ppm; ushort *ppm2; int c, row, col, soff, rstep, cstep; int perc, val, total, t_white=0x2000; #ifdef LIBRAW_LIBRARY_BUILD perc = width * height * auto_bright_thr; #else perc = width * height * 0.01; /* 99th percentile white level */ #endif if (fuji_width) perc /= 2; if (!((highlight & ~2) || no_auto_bright)) for (t_white=c=0; c < colors; c++) { for (val=0x2000, total=0; --val > 32; ) if ((total += histogram[c][val]) > perc) break; if (t_white < val) t_white = val; } gamma_curve (gamm[0], gamm[1], 2, (t_white << 3)/bright); iheight = height; iwidth = width; if (flip & 4) SWAP(height,width); ppm = (uchar *) calloc (width, colors*output_bps/8); ppm2 = (ushort *) ppm; merror (ppm, "write_ppm_tiff()"); if (output_tiff) { tiff_head (&th, 1); fwrite (&th, sizeof th, 1, ofp); if (oprof) fwrite (oprof, ntohl(oprof[0]), 1, ofp); } else if (colors > 3) fprintf (ofp, "P7\nWIDTH %d\nHEIGHT %d\nDEPTH %d\nMAXVAL %d\nTUPLTYPE %s\nENDHDR\n", width, height, colors, (1 << output_bps)-1, cdesc); else fprintf (ofp, "P%d\n%d %d\n%d\n", colors/2+5, width, height, (1 << output_bps)-1); soff = flip_index (0, 0); cstep = flip_index (0, 1) - soff; rstep = flip_index (1, 0) - flip_index (0, width); for (row=0; row < height; row++, soff += rstep) { for (col=0; col < width; col++, soff += cstep) if (output_bps == 8) FORCC ppm [col*colors+c] = curve[image[soff][c]] >> 8; else FORCC ppm2[col*colors+c] = curve[image[soff][c]]; if (output_bps == 16 && !output_tiff && htons(0x55aa) != 0x55aa) swab ((char*)ppm2, (char*)ppm2, width*colors*2); fwrite (ppm, colors*output_bps/8, width, ofp); } free (ppm); } LibRaw-0.18.8/internal/dcraw_fileio.cpp000066400000000000000000000146421324423227700177540ustar00rootroot00000000000000/* Copyright 2008-2017 LibRaw LLC (info@libraw.org) LibRaw is free software; you can redistribute it and/or modify it under the terms of the one of two licenses as you choose: 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 (See file LICENSE.LGPL provided in LibRaw distribution archive for details). 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 (See file LICENSE.CDDL provided in LibRaw distribution archive for details). This file is generated from Dave Coffin's dcraw.c dcraw.c -- Dave Coffin's raw photo decoder Copyright 1997-2010 by Dave Coffin, dcoffin a cybercom o net Look into dcraw homepage (probably http://cybercom.net/~dcoffin/dcraw/) for more information */ #include #define CLASS LibRaw:: #include "libraw/libraw_types.h" #define LIBRAW_LIBRARY_BUILD #include "libraw/libraw.h" #include "internal/defines.h" #include "internal/var_defines.h" /* Seach from the current directory up to the root looking for a ".badpixels" file, and fix those pixels now. */ void CLASS bad_pixels (const char *cfname) { FILE *fp=NULL; #ifndef LIBRAW_LIBRARY_BUILD char *fname, *cp, line[128]; int len, time, row, col, r, c, rad, tot, n, fixed=0; #else char *cp, line[128]; int time, row, col, r, c, rad, tot, n; #ifdef DCRAW_VERBOSE int fixed = 0; #endif #endif if (!filters) return; #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_BAD_PIXELS,0,2); #endif if (cfname) fp = fopen (cfname, "r"); if (!fp) { #ifdef LIBRAW_LIBRARY_BUILD imgdata.process_warnings |= LIBRAW_WARN_NO_BADPIXELMAP; #endif return; } while (fgets (line, 128, fp)) { cp = strchr (line, '#'); if (cp) *cp = 0; if (sscanf (line, "%d %d %d", &col, &row, &time) != 3) continue; if ((unsigned) col >= width || (unsigned) row >= height) continue; if (time > timestamp) continue; for (tot=n=0, rad=1; rad < 3 && n==0; rad++) for (r = row-rad; r <= row+rad; r++) for (c = col-rad; c <= col+rad; c++) if ((unsigned) r < height && (unsigned) c < width && (r != row || c != col) && fcol(r,c) == fcol(row,col)) { tot += BAYER2(r,c); n++; } BAYER2(row,col) = tot/n; #ifdef DCRAW_VERBOSE if (verbose) { if (!fixed++) fprintf (stderr,_("Fixed dead pixels at:")); fprintf (stderr, " %d,%d", col, row); } #endif } #ifdef DCRAW_VERBOSE if (fixed) fputc ('\n', stderr); #endif fclose (fp); #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_BAD_PIXELS,1,2); #endif } void CLASS subtract (const char *fname) { FILE *fp; int dim[3]={0,0,0}, comment=0, number=0, error=0, nd=0, c, row, col; ushort *pixel; #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_DARK_FRAME,0,2); #endif if (!(fp = fopen (fname, "rb"))) { #ifdef DCRAW_VERBOSE perror (fname); #endif #ifdef LIBRAW_LIBRARY_BUILD imgdata.process_warnings |= LIBRAW_WARN_BAD_DARKFRAME_FILE; #endif return; } if (fgetc(fp) != 'P' || fgetc(fp) != '5') error = 1; while (!error && nd < 3 && (c = fgetc(fp)) != EOF) { if (c == '#') comment = 1; if (c == '\n') comment = 0; if (comment) continue; if (isdigit(c)) number = 1; if (number) { if (isdigit(c)) dim[nd] = dim[nd]*10 + c -'0'; else if (isspace(c)) { number = 0; nd++; } else error = 1; } } if (error || nd < 3) { #ifdef DCRAW_VERBOSE fprintf (stderr,_("%s is not a valid PGM file!\n"), fname); #endif fclose (fp); return; } else if (dim[0] != width || dim[1] != height || dim[2] != 65535) { #ifdef DCRAW_VERBOSE fprintf (stderr,_("%s has the wrong dimensions!\n"), fname); #endif #ifdef LIBRAW_LIBRARY_BUILD imgdata.process_warnings |= LIBRAW_WARN_BAD_DARKFRAME_DIM; #endif fclose (fp); return; } pixel = (ushort *) calloc (width, sizeof *pixel); merror (pixel, "subtract()"); for (row=0; row < height; row++) { fread (pixel, 2, width, fp); for (col=0; col < width; col++) BAYER(row,col) = MAX (BAYER(row,col) - ntohs(pixel[col]), 0); } free (pixel); fclose (fp); memset (cblack, 0, sizeof cblack); black = 0; #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_DARK_FRAME,1,2); #endif } #ifndef NO_LCMS void CLASS apply_profile (const char *input, const char *output) { char *prof; cmsHPROFILE hInProfile=0, hOutProfile=0; cmsHTRANSFORM hTransform; FILE *fp; unsigned size; if (strcmp (input, "embed")) hInProfile = cmsOpenProfileFromFile (input, "r"); else if (profile_length) { #ifndef LIBRAW_LIBRARY_BUILD prof = (char *) malloc (profile_length); merror (prof, "apply_profile()"); fseek (ifp, profile_offset, SEEK_SET); fread (prof, 1, profile_length, ifp); hInProfile = cmsOpenProfileFromMem (prof, profile_length); free (prof); #else hInProfile = cmsOpenProfileFromMem (imgdata.color.profile, profile_length); #endif } else { #ifdef LIBRAW_LIBRARY_BUILD imgdata.process_warnings |= LIBRAW_WARN_NO_EMBEDDED_PROFILE; #endif #ifdef DCRAW_VERBOSE fprintf (stderr,_("%s has no embedded profile.\n"), ifname); #endif } if (!hInProfile) { #ifdef LIBRAW_LIBRARY_BUILD imgdata.process_warnings |= LIBRAW_WARN_NO_INPUT_PROFILE; #endif return; } if (!output) hOutProfile = cmsCreate_sRGBProfile(); else if ((fp = fopen (output, "rb"))) { fread (&size, 4, 1, fp); fseek (fp, 0, SEEK_SET); oprof = (unsigned *) malloc (size = ntohl(size)); merror (oprof, "apply_profile()"); fread (oprof, 1, size, fp); fclose (fp); if (!(hOutProfile = cmsOpenProfileFromMem (oprof, size))) { free (oprof); oprof = 0; } } #ifdef DCRAW_VERBOSE else fprintf (stderr,_("Cannot open file %s!\n"), output); #endif if (!hOutProfile) { #ifdef LIBRAW_LIBRARY_BUILD imgdata.process_warnings |= LIBRAW_WARN_BAD_OUTPUT_PROFILE; #endif goto quit; } #ifdef DCRAW_VERBOSE if (verbose) fprintf (stderr,_("Applying color profile...\n")); #endif #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_APPLY_PROFILE,0,2); #endif hTransform = cmsCreateTransform (hInProfile, TYPE_RGBA_16, hOutProfile, TYPE_RGBA_16, INTENT_PERCEPTUAL, 0); cmsDoTransform (hTransform, image, image, width*height); raw_color = 1; /* Don't use rgb_cam with a profile */ cmsDeleteTransform (hTransform); cmsCloseProfile (hOutProfile); quit: cmsCloseProfile (hInProfile); #ifdef LIBRAW_LIBRARY_BUILD RUN_CALLBACK(LIBRAW_PROGRESS_APPLY_PROFILE,1,2); #endif } #endif LibRaw-0.18.8/internal/defines.h000066400000000000000000000104731324423227700164050ustar00rootroot00000000000000/* Copyright 2008-2017 LibRaw LLC (info@libraw.org) LibRaw is free software; you can redistribute it and/or modify it under the terms of the one of two licenses as you choose: 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 (See file LICENSE.LGPL provided in LibRaw distribution archive for details). 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 (See file LICENSE.CDDL provided in LibRaw distribution archive for details). This file is generated from Dave Coffin's dcraw.c dcraw.c -- Dave Coffin's raw photo decoder Copyright 1997-2010 by Dave Coffin, dcoffin a cybercom o net Look into dcraw homepage (probably http://cybercom.net/~dcoffin/dcraw/) for more information */ #ifndef USE_JPEG #define NO_JPEG #endif #ifndef USE_JASPER #define NO_JASPER #endif #define DCRAW_VERSION "9.26" #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #define _USE_MATH_DEFINES #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __CYGWIN__ #include #endif #if defined WIN32 || defined (__MINGW32__) #include #include #pragma comment(lib, "ws2_32.lib") #define snprintf _snprintf #define strcasecmp stricmp #define strncasecmp strnicmp #else #include #include #include typedef long long INT64; typedef unsigned long long UINT64; #endif #ifdef NODEPS #define NO_JASPER #define NO_JPEG #define NO_LCMS #endif #ifndef NO_JASPER #include /* Decode Red camera movies */ #endif #ifndef NO_JPEG #include /* Decode compressed Kodak DC120 photos */ #endif /* and Adobe Lossy DNGs */ #ifndef NO_LCMS #ifdef USE_LCMS #include /* Support color profiles */ #else #include /* Support color profiles */ #endif #endif #ifdef LOCALEDIR #include #define _(String) gettext(String) #else #define _(String) (String) #endif #ifdef LJPEG_DECODE #error Please compile dcraw.c by itself. #error Do not link it with ljpeg_decode. #endif #ifndef LONG_BIT #define LONG_BIT (8 * sizeof (long)) #endif #define FORC(cnt) for (c=0; c < cnt; c++) #define FORC3 FORC(3) #define FORC4 FORC(4) #define FORCC for (c=0; c < colors && c < 4; c++) #define SQR(x) ((x)*(x)) #define ABS(x) (((int)(x) ^ ((int)(x) >> 31)) - ((int)(x) >> 31)) #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define LIM(x,min,max) MAX(min,MIN(x,max)) #define ULIM(x,y,z) ((y) < (z) ? LIM(x,y,z) : LIM(x,z,y)) #define CLIP(x) LIM((int)(x),0,65535) #define SWAP(a,b) { a=a+b; b=a-b; a=a-b; } #define my_swap(type, i, j) {type t = i; i = j; j = t;} static float fMAX(float a, float b) { return MAX(a,b); } /* In order to inline this calculation, I make the risky assumption that all filter patterns can be described by a repeating pattern of eight rows and two columns Do not use the FC or BAYER macros with the Leaf CatchLight, because its pattern is 16x16, not 2x8. Return values are either 0/1/2/3 = G/M/C/Y or 0/1/2/3 = R/G1/B/G2 PowerShot 600 PowerShot A50 PowerShot Pro70 Pro90 & G1 0xe1e4e1e4: 0x1b4e4b1e: 0x1e4b4e1b: 0xb4b4b4b4: 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 G M G M G M 0 C Y C Y C Y 0 Y C Y C Y C 0 G M G M G M 1 C Y C Y C Y 1 M G M G M G 1 M G M G M G 1 Y C Y C Y C 2 M G M G M G 2 Y C Y C Y C 2 C Y C Y C Y 3 C Y C Y C Y 3 G M G M G M 3 G M G M G M 4 C Y C Y C Y 4 Y C Y C Y C PowerShot A5 5 G M G M G M 5 G M G M G M 0x1e4e1e4e: 6 Y C Y C Y C 6 C Y C Y C Y 7 M G M G M G 7 M G M G M G 0 1 2 3 4 5 0 C Y C Y C Y 1 G M G M G M 2 C Y C Y C Y 3 M G M G M G All RGB cameras use one of these Bayer grids: 0x16161616: 0x61616161: 0x49494949: 0x94949494: 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 B G B G B G 0 G R G R G R 0 G B G B G B 0 R G R G R G 1 G R G R G R 1 B G B G B G 1 R G R G R G 1 G B G B G B 2 B G B G B G 2 G R G R G R 2 G B G B G B 2 R G R G R G 3 G R G R G R 3 B G B G B G 3 R G R G R G 3 G B G B G B */ #define RAW(row,col) \ raw_image[(row)*raw_width+(col)] #define BAYER(row,col) \ image[((row) >> shrink)*iwidth + ((col) >> shrink)][FC(row,col)] #define BAYER2(row,col) \ image[((row) >> shrink)*iwidth + ((col) >> shrink)][fcol(row,col)] LibRaw-0.18.8/internal/demosaic_packs.cpp000066400000000000000000000045121324423227700202650ustar00rootroot00000000000000/* Copyright 2008-2013 LibRaw LLC (info@libraw.org) LibRaw is free software; you can redistribute it and/or modify it under the terms of the one of two licenses as you choose: 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 (See file LICENSE.LGPL provided in LibRaw distribution archive for details). 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 (See file LICENSE.CDDL provided in LibRaw distribution archive for details). */ #include #define CLASS LibRaw:: #include "libraw/libraw_types.h" #define LIBRAW_LIBRARY_BUILD #define LIBRAW_IO_REDEFINED #include "libraw/libraw.h" #include "internal/defines.h" #define SRC_USES_SHRINK #define SRC_USES_BLACK #define SRC_USES_CURVE /* WF filtering is allowed to triple libraw license */ #include "./wf_filtering.cpp" /* DHT and AAHD are LGPL licensed, so include them */ #include "./dht_demosaic.cpp" #include "./aahd_demosaic.cpp" #include "internal/var_defines.h" #ifdef LIBRAW_DEMOSAIC_PACK_GPL2 /*AHD-Mod*/ #include /*LMMSE*/ #include /*AFD*/ #include #include /* VCD*/ #include #include #include #include #else // fake implementations of all GPL2 demosaics void CLASS ahd_interpolate_mod() {ahd_interpolate();} void CLASS afd_interpolate_pl(int, int) {ahd_interpolate();} void CLASS vcd_interpolate(int) {ahd_interpolate();} void CLASS lmmse_interpolate(int) {ahd_interpolate();} void CLASS es_median_filter() {} void CLASS median_filter_new() {} void CLASS refinement() {} #endif /* DCB is BSD licensed, so include it */ #include "./dcb_demosaicing.c" #ifdef LIBRAW_DEMOSAIC_PACK_GPL3 /*AMaZE*/ #include #include #include #include #include #else // fallback to AHD and no correction void CLASS CA_correct_RT(float,float){} void CLASS amaze_demosaic_RT() { ahd_interpolate();} void CLASS green_equilibrate(float thresh) {} void CLASS cfa_linedn(float linenoise){} void CLASS cfa_impulse_gauss(float lclean, float cclean){} #endif #define sget4(s) sget4((uchar *)s) #ifndef M_PI #define M_PI 3.14159265358979323846 #endif #ifdef LIBRAW_DEMOSAIC_PACK_GPL2 #include #endif LibRaw-0.18.8/internal/dht_demosaic.cpp000066400000000000000000000736321324423227700177540ustar00rootroot00000000000000/* -*- C++ -*- * File: dht_demosaic.cpp * Copyright 2013 Anton Petrusevich * Created: Tue Apr 9, 2013 * * This code is licensed under one of two licenses as you choose: * * 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 * (See file LICENSE.LGPL provided in LibRaw distribution archive for details). * * 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 * (See file LICENSE.CDDL provided in LibRaw distribution archive for details). * */ /* * функция вычисляет яркостную дистанцию. * если две яркости отличаются в два раза, например 10 и 20, то они имеют такой же вес * при принятии решения об интерполировании, как и 100 и 200 -- фотографическая яркость между ними 1 стоп. * дистанция всегда >=1 */ static inline float calc_dist(float c1, float c2) { return c1 > c2 ? c1 / c2 : c2 / c1; } struct DHT { int nr_height, nr_width; static const int nr_topmargin = 4, nr_leftmargin = 4; float (*nraw)[3]; ushort channel_maximum[3]; float channel_minimum[3]; LibRaw &libraw; enum { HVSH = 1, HOR = 2, VER = 4, HORSH = HOR | HVSH, VERSH = VER | HVSH, DIASH = 8, LURD = 16, RULD = 32, LURDSH = LURD | DIASH, RULDSH = RULD | DIASH, HOT = 64 }; static inline float Thot(void) throw () { return 64.0f; } static inline float Tg(void) throw () { return 256.0f; } static inline float T(void) throw () { return 1.4f; } char *ndir; inline int nr_offset(int row, int col) throw () { return (row * nr_width + col); } int get_hv_grb(int x, int y, int kc) { float hv1 = 2 * nraw[nr_offset(y - 1, x)][1] / (nraw[nr_offset(y - 2, x)][kc] + nraw[nr_offset(y, x)][kc]); float hv2 = 2 * nraw[nr_offset(y + 1, x)][1] / (nraw[nr_offset(y + 2, x)][kc] + nraw[nr_offset(y, x)][kc]); float kv = calc_dist(hv1, hv2) * calc_dist(nraw[nr_offset(y, x)][kc] * nraw[nr_offset(y, x)][kc], (nraw[nr_offset(y - 2, x)][kc] * nraw[nr_offset(y + 2, x)][kc])); kv *= kv; kv *= kv; kv *= kv; float dv = kv * calc_dist(nraw[nr_offset(y - 3, x)][1] * nraw[nr_offset(y + 3, x)][1], nraw[nr_offset(y - 1, x)][1] * nraw[nr_offset(y + 1, x)][1]); float hh1 = 2 * nraw[nr_offset(y, x - 1)][1] / (nraw[nr_offset(y, x - 2)][kc] + nraw[nr_offset(y, x)][kc]); float hh2 = 2 * nraw[nr_offset(y, x + 1)][1] / (nraw[nr_offset(y, x + 2)][kc] + nraw[nr_offset(y, x)][kc]); float kh = calc_dist(hh1, hh2) * calc_dist(nraw[nr_offset(y, x)][kc] * nraw[nr_offset(y, x)][kc], (nraw[nr_offset(y, x - 2)][kc] * nraw[nr_offset(y, x + 2)][kc])); kh *= kh; kh *= kh; kh *= kh; float dh = kh * calc_dist(nraw[nr_offset(y, x - 3)][1] * nraw[nr_offset(y, x + 3)][1], nraw[nr_offset(y, x - 1)][1] * nraw[nr_offset(y, x + 1)][1]); float e = calc_dist(dh, dv); char d = dh < dv ? (e > Tg() ? HORSH : HOR) : (e > Tg() ? VERSH : VER); return d; } int get_hv_rbg(int x, int y, int hc) { float hv1 = 2 * nraw[nr_offset(y - 1, x)][hc ^ 2] / (nraw[nr_offset(y - 2, x)][1] + nraw[nr_offset(y, x)][1]); float hv2 = 2 * nraw[nr_offset(y + 1, x)][hc ^ 2] / (nraw[nr_offset(y + 2, x)][1] + nraw[nr_offset(y, x)][1]); float kv = calc_dist(hv1, hv2) * calc_dist(nraw[nr_offset(y, x)][1] * nraw[nr_offset(y, x)][1], (nraw[nr_offset(y - 2, x)][1] * nraw[nr_offset(y + 2, x)][1])); kv *= kv; kv *= kv; kv *= kv; float dv = kv * calc_dist(nraw[nr_offset(y - 3, x)][hc ^ 2] * nraw[nr_offset(y + 3, x)][hc ^ 2], nraw[nr_offset(y - 1, x)][hc ^ 2] * nraw[nr_offset(y + 1, x)][hc ^ 2]); float hh1 = 2 * nraw[nr_offset(y, x - 1)][hc] / (nraw[nr_offset(y, x - 2)][1] + nraw[nr_offset(y, x)][1]); float hh2 = 2 * nraw[nr_offset(y, x + 1)][hc] / (nraw[nr_offset(y, x + 2)][1] + nraw[nr_offset(y, x)][1]); float kh = calc_dist(hh1, hh2) * calc_dist(nraw[nr_offset(y, x)][1] * nraw[nr_offset(y, x)][1], (nraw[nr_offset(y, x - 2)][1] * nraw[nr_offset(y, x + 2)][1])); kh *= kh; kh *= kh; kh *= kh; float dh = kh * calc_dist(nraw[nr_offset(y, x - 3)][hc] * nraw[nr_offset(y, x + 3)][hc], nraw[nr_offset(y, x - 1)][hc] * nraw[nr_offset(y, x + 1)][hc]); float e = calc_dist(dh, dv); char d = dh < dv ? (e > Tg() ? HORSH : HOR) : (e > Tg() ? VERSH : VER); return d; } int get_diag_grb(int x, int y, int kc) { float hlu = nraw[nr_offset(y - 1, x - 1)][1] / nraw[nr_offset(y - 1, x - 1)][kc]; float hrd = nraw[nr_offset(y + 1, x + 1)][1] / nraw[nr_offset(y + 1, x + 1)][kc]; float hru = nraw[nr_offset(y - 1, x + 1)][1] / nraw[nr_offset(y - 1, x + 1)][kc]; float hld = nraw[nr_offset(y + 1, x - 1)][1] / nraw[nr_offset(y + 1, x - 1)][kc]; float dlurd = calc_dist(hlu, hrd) * calc_dist(nraw[nr_offset(y - 1, x - 1)][1] * nraw[nr_offset(y + 1, x + 1)][1], nraw[nr_offset(y, x)][1] * nraw[nr_offset(y, x)][1]); float druld = calc_dist(hlu, hrd) * calc_dist(nraw[nr_offset(y - 1, x + 1)][1] * nraw[nr_offset(y + 1, x - 1)][1], nraw[nr_offset(y, x)][1] * nraw[nr_offset(y, x)][1]); float e = calc_dist(dlurd, druld); char d = druld < dlurd ? (e > T() ? RULDSH : RULD) : (e > T() ? LURDSH : LURD); return d; } int get_diag_rbg(int x, int y, int hc) { float dlurd = calc_dist(nraw[nr_offset(y - 1, x - 1)][1] * nraw[nr_offset(y + 1, x + 1)][1], nraw[nr_offset(y, x)][1] * nraw[nr_offset(y, x)][1]); float druld = calc_dist(nraw[nr_offset(y - 1, x + 1)][1] * nraw[nr_offset(y + 1, x - 1)][1], nraw[nr_offset(y, x)][1] * nraw[nr_offset(y, x)][1]); float e = calc_dist(dlurd, druld); char d = druld < dlurd ? (e > T() ? RULDSH : RULD) : (e > T() ? LURDSH : LURD); return d; } static inline float scale_over(float ec, float base) { float s = base * .4; float o = ec - base; return base + sqrt(s * (o + s)) - s; } static inline float scale_under(float ec, float base) { float s = base * .6; float o = base - ec; return base - sqrt(s * (o + s)) + s; } ~DHT(); DHT(LibRaw &_libraw); void copy_to_image(); void make_greens(); void make_diag_dirs(); void make_hv_dirs(); void refine_hv_dirs(int i, int js); void refine_diag_dirs(int i, int js); void refine_ihv_dirs(int i); void refine_idiag_dirs(int i); void illustrate_dirs(); void illustrate_dline(int i); void make_hv_dline(int i); void make_diag_dline(int i); void make_gline(int i); void make_rbdiag(int i); void make_rbhv(int i); void make_rb(); void hide_hots(); void restore_hots(); }; typedef float float3[3]; /* * информация о цветах копируется во float в общем то с одной целью -- чтобы вместо 0 можно было писать 0.5, * что больше подходит для вычисления яркостной разницы. * причина: в целых числах разница в 1 стоп составляет ряд 8,4,2,1,0 -- последнее число должно быть 0.5, * которое непредствамио в целых числах. * так же это изменение позволяет не думать о специальных случаях деления на ноль. * * альтернативное решение: умножить все данные на 2 и в младший бит внести 1. правда, * всё равно придётся следить, чтобы при интерпретации зелёного цвета не получился 0 при округлении, * иначе проблема при интерпретации синих и красных. * */ DHT::DHT(LibRaw& _libraw) : libraw(_libraw) { nr_height = libraw.imgdata.sizes.iheight + nr_topmargin * 2; nr_width = libraw.imgdata.sizes.iwidth + nr_leftmargin * 2; nraw = (float3*) malloc(nr_height * nr_width * sizeof(float3)); int iwidth = libraw.imgdata.sizes.iwidth; ndir = (char*) calloc(nr_height * nr_width, 1); channel_maximum[0] = channel_maximum[1] = channel_maximum[2] = 0; channel_minimum[0] = libraw.imgdata.image[0][0]; channel_minimum[1] = libraw.imgdata.image[0][1]; channel_minimum[2] = libraw.imgdata.image[0][2]; for (int i = 0; i < nr_height * nr_width; ++i) nraw[i][0] = nraw[i][1] = nraw[i][2] = 0.5; for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) { int col_cache[48]; for (int j = 0; j < 48; ++j) { int l = libraw.COLOR(i, j); if (l == 3) l = 1; col_cache[j] = l; } for (int j = 0; j < iwidth; ++j) { int l = col_cache[j % 48]; unsigned short c = libraw.imgdata.image[i * iwidth + j][l]; if (c != 0) { if (channel_maximum[l] < c) channel_maximum[l] = c; if (channel_minimum[l] > c) channel_minimum[l] = c; nraw[nr_offset(i + nr_topmargin, j + nr_leftmargin)][l] = (float) c; } } } channel_minimum[0] += .5; channel_minimum[1] += .5; channel_minimum[2] += .5; } void DHT::hide_hots() { int iwidth = libraw.imgdata.sizes.iwidth; #if defined(LIBRAW_USE_OPENMP) #pragma omp parallel for schedule(guided) firstprivate(iwidth) #endif for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) { int js = libraw.COLOR(i, 0) & 1; int kc = libraw.COLOR(i, js); /* * js -- начальная х-координата, которая попадает мимо известного зелёного * kc -- известный цвет в точке интерполирования */ for (int j = js; j < iwidth; j += 2) { int x = j + nr_leftmargin; int y = i + nr_topmargin; float c = nraw[nr_offset(y, x)][kc]; if ((c > nraw[nr_offset(y, x + 2)][kc] && c > nraw[nr_offset(y, x - 2)][kc] && c > nraw[nr_offset(y - 2, x)][kc] && c > nraw[nr_offset(y + 2, x)][kc] && c > nraw[nr_offset(y, x + 1)][1] && c > nraw[nr_offset(y, x - 1)][1] && c > nraw[nr_offset(y - 1, x)][1] && c > nraw[nr_offset(y + 1, x)][1]) || (c < nraw[nr_offset(y, x + 2)][kc] && c < nraw[nr_offset(y, x - 2)][kc] && c < nraw[nr_offset(y - 2, x)][kc] && c < nraw[nr_offset(y + 2, x)][kc] && c < nraw[nr_offset(y, x + 1)][1] && c < nraw[nr_offset(y, x - 1)][1] && c < nraw[nr_offset(y - 1, x)][1] && c < nraw[nr_offset(y + 1, x)][1])) { float avg = 0; for (int k = -2; k < 3; k += 2) for (int m = -2; m < 3; m += 2) if (m == 0 && k == 0) continue; else avg += nraw[nr_offset(y + k, x + m)][kc]; avg /= 8; // float dev = 0; // for (int k = -2; k < 3; k += 2) // for (int l = -2; l < 3; l += 2) // if (k == 0 && l == 0) // continue; // else { // float t = nraw[nr_offset(y + k, x + l)][kc] - avg; // dev += t * t; // } // dev /= 8; // dev = sqrt(dev); if (calc_dist(c, avg) > Thot()) { ndir[nr_offset(y, x)] |= HOT; float dv = calc_dist( nraw[nr_offset(y - 2, x)][kc] * nraw[nr_offset(y - 1, x)][1], nraw[nr_offset(y + 2, x)][kc] * nraw[nr_offset(y + 1, x)][1]); float dh = calc_dist( nraw[nr_offset(y, x - 2)][kc] * nraw[nr_offset(y, x - 1)][1], nraw[nr_offset(y, x + 2)][kc] * nraw[nr_offset(y, x + 1)][1]); if (dv > dh) nraw[nr_offset(y, x)][kc] = (nraw[nr_offset(y, x + 2)][kc] + nraw[nr_offset(y, x - 2)][kc]) / 2; else nraw[nr_offset(y, x)][kc] = (nraw[nr_offset(y - 2, x)][kc] + nraw[nr_offset(y + 2, x)][kc]) / 2; } } } for (int j = js ^ 1; j < iwidth; j += 2) { int x = j + nr_leftmargin; int y = i + nr_topmargin; float c = nraw[nr_offset(y, x)][1]; if ((c > nraw[nr_offset(y, x + 2)][1] && c > nraw[nr_offset(y, x - 2)][1] && c > nraw[nr_offset(y - 2, x)][1] && c > nraw[nr_offset(y + 2, x)][1] && c > nraw[nr_offset(y, x + 1)][kc] && c > nraw[nr_offset(y, x - 1)][kc] && c > nraw[nr_offset(y - 1, x)][kc ^ 2] && c > nraw[nr_offset(y + 1, x)][kc ^ 2]) || (c < nraw[nr_offset(y, x + 2)][1] && c < nraw[nr_offset(y, x - 2)][1] && c < nraw[nr_offset(y - 2, x)][1] && c < nraw[nr_offset(y + 2, x)][1] && c < nraw[nr_offset(y, x + 1)][kc] && c < nraw[nr_offset(y, x - 1)][kc] && c < nraw[nr_offset(y - 1, x)][kc ^ 2] && c < nraw[nr_offset(y + 1, x)][kc ^ 2])) { float avg = 0; for (int k = -2; k < 3; k += 2) for (int m = -2; m < 3; m += 2) if (k == 0 && m == 0) continue; else avg += nraw[nr_offset(y + k, x + m)][1]; avg /= 8; // float dev = 0; // for (int k = -2; k < 3; k += 2) // for (int l = -2; l < 3; l += 2) // if (k == 0 && l == 0) // continue; // else { // float t = nraw[nr_offset(y + k, x + l)][1] - avg; // dev += t * t; // } // dev /= 8; // dev = sqrt(dev); if (calc_dist(c, avg) > Thot()) { ndir[nr_offset(y, x)] |= HOT; float dv = calc_dist( nraw[nr_offset(y - 2, x)][1] * nraw[nr_offset(y - 1, x)][kc ^ 2], nraw[nr_offset(y + 2, x)][1] * nraw[nr_offset(y + 1, x)][kc ^ 2]); float dh = calc_dist( nraw[nr_offset(y, x - 2)][1] * nraw[nr_offset(y, x - 1)][kc], nraw[nr_offset(y, x + 2)][1] * nraw[nr_offset(y, x + 1)][kc]); if (dv > dh) nraw[nr_offset(y, x)][1] = (nraw[nr_offset(y, x + 2)][1] + nraw[nr_offset(y, x - 2)][1]) / 2; else nraw[nr_offset(y, x)][1] = (nraw[nr_offset(y - 2, x)][1] + nraw[nr_offset(y + 2, x)][1]) / 2; } } } } } void DHT::restore_hots() { int iwidth = libraw.imgdata.sizes.iwidth; #if defined(LIBRAW_USE_OPENMP) #ifdef WIN32 #pragma omp parallel for firstprivate(iwidth) #else #pragma omp parallel for schedule(guided) firstprivate(iwidth) collapse(2) #endif #endif for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) { for (int j = 0; j < iwidth; ++j) { int x = j + nr_leftmargin; int y = i + nr_topmargin; if (ndir[nr_offset(y, x)] & HOT) { int l = libraw.COLOR(i, j); nraw[nr_offset(i + nr_topmargin, j + nr_leftmargin)][l] = libraw.imgdata.image[i * iwidth + j][l]; } } } } void DHT::make_diag_dirs() { #if defined(LIBRAW_USE_OPENMP) #pragma omp parallel for schedule(guided) #endif for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) { make_diag_dline(i); } //#if defined(LIBRAW_USE_OPENMP) //#pragma omp parallel for schedule(guided) //#endif // for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) { // refine_diag_dirs(i, i & 1); // } //#if defined(LIBRAW_USE_OPENMP) //#pragma omp parallel for schedule(guided) //#endif // for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) { // refine_diag_dirs(i, (i & 1) ^ 1); // } #if defined(LIBRAW_USE_OPENMP) #pragma omp parallel for schedule(guided) #endif for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) { refine_idiag_dirs(i); } } void DHT::make_hv_dirs() { #if defined(LIBRAW_USE_OPENMP) #pragma omp parallel for schedule(guided) #endif for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) { make_hv_dline(i); } #if defined(LIBRAW_USE_OPENMP) #pragma omp parallel for schedule(guided) #endif for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) { refine_hv_dirs(i, i & 1); } #if defined(LIBRAW_USE_OPENMP) #pragma omp parallel for schedule(guided) #endif for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) { refine_hv_dirs(i, (i & 1) ^ 1); } #if defined(LIBRAW_USE_OPENMP) #pragma omp parallel for schedule(guided) #endif for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) { refine_ihv_dirs(i); } } void DHT::refine_hv_dirs(int i, int js) { int iwidth = libraw.imgdata.sizes.iwidth; for (int j = js; j < iwidth; j += 2) { int x = j + nr_leftmargin; int y = i + nr_topmargin; if (ndir[nr_offset(y, x)] & HVSH) continue; int nv = (ndir[nr_offset(y - 1, x)] & VER) + (ndir[nr_offset(y + 1, x)] & VER) + (ndir[nr_offset(y, x - 1)] & VER) + (ndir[nr_offset(y, x + 1)] & VER); int nh = (ndir[nr_offset(y - 1, x)] & HOR) + (ndir[nr_offset(y + 1, x)] & HOR) + (ndir[nr_offset(y, x - 1)] & HOR) + (ndir[nr_offset(y, x + 1)] & HOR); bool codir = (ndir[nr_offset(y, x)] & VER) ? ((ndir[nr_offset(y - 1, x)] & VER) || (ndir[nr_offset(y + 1, x)] & VER)) : ((ndir[nr_offset(y, x - 1)] & HOR) || (ndir[nr_offset(y, x + 1)] & HOR)); nv /= VER; nh /= HOR; if ((ndir[nr_offset(y, x)] & VER) && (nh > 2 && !codir)) { ndir[nr_offset(y, x)] &= ~VER; ndir[nr_offset(y, x)] |= HOR; } if ((ndir[nr_offset(y, x)] & HOR) && (nv > 2 && !codir)) { ndir[nr_offset(y, x)] &= ~HOR; ndir[nr_offset(y, x)] |= VER; } } } void DHT::refine_ihv_dirs(int i) { int iwidth = libraw.imgdata.sizes.iwidth; for (int j = 0; j < iwidth; j++) { int x = j + nr_leftmargin; int y = i + nr_topmargin; if (ndir[nr_offset(y, x)] & HVSH) continue; int nv = (ndir[nr_offset(y - 1, x)] & VER) + (ndir[nr_offset(y + 1, x)] & VER) + (ndir[nr_offset(y, x - 1)] & VER) + (ndir[nr_offset(y, x + 1)] & VER); int nh = (ndir[nr_offset(y - 1, x)] & HOR) + (ndir[nr_offset(y + 1, x)] & HOR) + (ndir[nr_offset(y, x - 1)] & HOR) + (ndir[nr_offset(y, x + 1)] & HOR); nv /= VER; nh /= HOR; if ((ndir[nr_offset(y, x)] & VER) && nh > 3) { ndir[nr_offset(y, x)] &= ~VER; ndir[nr_offset(y, x)] |= HOR; } if ((ndir[nr_offset(y, x)] & HOR) && nv > 3) { ndir[nr_offset(y, x)] &= ~HOR; ndir[nr_offset(y, x)] |= VER; } } } void DHT::make_hv_dline(int i) { int iwidth = libraw.imgdata.sizes.iwidth; int js = libraw.COLOR(i, 0) & 1; int kc = libraw.COLOR(i, js); /* * js -- начальная х-координата, которая попадает мимо известного зелёного * kc -- известный цвет в точке интерполирования */ for (int j = 0; j < iwidth; j++) { int x = j + nr_leftmargin; int y = i + nr_topmargin; char d = 0; if ((j & 1) == js) { d = get_hv_grb(x, y, kc); } else { d = get_hv_rbg(x, y, kc); } ndir[nr_offset(y, x)] |= d; } } void DHT::make_diag_dline(int i) { int iwidth = libraw.imgdata.sizes.iwidth; int js = libraw.COLOR(i, 0) & 1; int kc = libraw.COLOR(i, js); /* * js -- начальная х-координата, которая попадает мимо известного зелёного * kc -- известный цвет в точке интерполирования */ for (int j = 0; j < iwidth; j++) { int x = j + nr_leftmargin; int y = i + nr_topmargin; char d = 0; if ((j & 1) == js) { d = get_diag_grb(x, y, kc); } else { d = get_diag_rbg(x, y, kc); } ndir[nr_offset(y, x)] |= d; } } void DHT::refine_diag_dirs(int i, int js) { int iwidth = libraw.imgdata.sizes.iwidth; for (int j = js; j < iwidth; j += 2) { int x = j + nr_leftmargin; int y = i + nr_topmargin; if (ndir[nr_offset(y, x)] & DIASH) continue; int nv = (ndir[nr_offset(y - 1, x)] & LURD) + (ndir[nr_offset(y + 1, x)] & LURD) + (ndir[nr_offset(y, x - 1)] & LURD) + (ndir[nr_offset(y, x + 1)] & LURD) + (ndir[nr_offset(y - 1, x - 1)] & LURD) + (ndir[nr_offset(y - 1, x + 1)] & LURD) + (ndir[nr_offset(y + 1, x - 1)] & LURD) + (ndir[nr_offset(y + 1, x + 1)] & LURD); int nh = (ndir[nr_offset(y - 1, x)] & RULD) + (ndir[nr_offset(y + 1, x)] & RULD) + (ndir[nr_offset(y, x - 1)] & RULD) + (ndir[nr_offset(y, x + 1)] & RULD) + (ndir[nr_offset(y - 1, x - 1)] & RULD) + (ndir[nr_offset(y - 1, x + 1)] & RULD) + (ndir[nr_offset(y + 1, x - 1)] & RULD) + (ndir[nr_offset(y + 1, x + 1)] & RULD); bool codir = (ndir[nr_offset(y, x)] & LURD) ? ((ndir[nr_offset(y - 1, x - 1)] & LURD) || (ndir[nr_offset(y + 1, x + 1)] & LURD)) : ((ndir[nr_offset(y - 1, x + 1)] & RULD) || (ndir[nr_offset(y + 1, x - 1)] & RULD)); nv /= LURD; nh /= RULD; if ((ndir[nr_offset(y, x)] & LURD) && (nh > 4 && !codir)) { ndir[nr_offset(y, x)] &= ~LURD; ndir[nr_offset(y, x)] |= RULD; } if ((ndir[nr_offset(y, x)] & RULD) && (nv > 4 && !codir)) { ndir[nr_offset(y, x)] &= ~RULD; ndir[nr_offset(y, x)] |= LURD; } } } void DHT::refine_idiag_dirs(int i) { int iwidth = libraw.imgdata.sizes.iwidth; for (int j = 0; j < iwidth; j++) { int x = j + nr_leftmargin; int y = i + nr_topmargin; if (ndir[nr_offset(y, x)] & DIASH) continue; int nv = (ndir[nr_offset(y - 1, x)] & LURD) + (ndir[nr_offset(y + 1, x)] & LURD) + (ndir[nr_offset(y, x - 1)] & LURD) + (ndir[nr_offset(y, x + 1)] & LURD) + (ndir[nr_offset(y - 1, x - 1)] & LURD) + (ndir[nr_offset(y - 1, x + 1)] & LURD) + (ndir[nr_offset(y + 1, x - 1)] & LURD) + (ndir[nr_offset(y + 1, x + 1)] & LURD); int nh = (ndir[nr_offset(y - 1, x)] & RULD) + (ndir[nr_offset(y + 1, x)] & RULD) + (ndir[nr_offset(y, x - 1)] & RULD) + (ndir[nr_offset(y, x + 1)] & RULD) + (ndir[nr_offset(y - 1, x - 1)] & RULD) + (ndir[nr_offset(y - 1, x + 1)] & RULD) + (ndir[nr_offset(y + 1, x - 1)] & RULD) + (ndir[nr_offset(y + 1, x + 1)] & RULD); bool codir = (ndir[nr_offset(y, x)] & LURD) ? ((ndir[nr_offset(y - 1, x - 1)] & LURD) || (ndir[nr_offset(y + 1, x + 1)] & LURD)) : ((ndir[nr_offset(y - 1, x + 1)] & RULD) || (ndir[nr_offset(y + 1, x - 1)] & RULD)); nv /= LURD; nh /= RULD; if ((ndir[nr_offset(y, x)] & LURD) && nh > 7) { ndir[nr_offset(y, x)] &= ~LURD; ndir[nr_offset(y, x)] |= RULD; } if ((ndir[nr_offset(y, x)] & RULD) && nv > 7) { ndir[nr_offset(y, x)] &= ~RULD; ndir[nr_offset(y, x)] |= LURD; } } } /* * вычисление недостающих зелёных точек. */ void DHT::make_greens() { #if defined(LIBRAW_USE_OPENMP) #pragma omp parallel for schedule(guided) #endif for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) { make_gline(i); } } void DHT::make_gline(int i) { int iwidth = libraw.imgdata.sizes.iwidth; int js = libraw.COLOR(i, 0) & 1; int kc = libraw.COLOR(i, js); /* * js -- начальная х-координата, которая попадает мимо известного зелёного * kc -- известный цвет в точке интерполирования */ for (int j = js; j < iwidth; j += 2) { int x = j + nr_leftmargin; int y = i + nr_topmargin; int dx, dy, dx2, dy2; float h1, h2; if (ndir[nr_offset(y, x)] & VER) { dx = dx2 = 0; dy = -1; dy2 = 1; h1 = 2 * nraw[nr_offset(y - 1, x)][1] / (nraw[nr_offset(y - 2, x)][kc] + nraw[nr_offset(y, x)][kc]); h2 = 2 * nraw[nr_offset(y + 1, x)][1] / (nraw[nr_offset(y + 2, x)][kc] + nraw[nr_offset(y, x)][kc]); } else { dy = dy2 = 0; dx = 1; dx2 = -1; h1 = 2 * nraw[nr_offset(y, x + 1)][1] / (nraw[nr_offset(y, x + 2)][kc] + nraw[nr_offset(y, x)][kc]); h2 = 2 * nraw[nr_offset(y, x - 1)][1] / (nraw[nr_offset(y, x - 2)][kc] + nraw[nr_offset(y, x)][kc]); } float b1 = 1 / calc_dist(nraw[nr_offset(y, x)][kc], nraw[nr_offset(y + dy * 2, x + dx * 2)][kc]); float b2 = 1 / calc_dist(nraw[nr_offset(y, x)][kc], nraw[nr_offset(y + dy2 * 2, x + dx2 * 2)][kc]); b1 *= b1; b2 *= b2; float eg = nraw[nr_offset(y, x)][kc] * (b1 * h1 + b2 * h2) / (b1 + b2); float min, max; min = MIN(nraw[nr_offset(y + dy, x + dx)][1], nraw[nr_offset(y + dy2, x + dx2)][1]); max = MAX(nraw[nr_offset(y + dy, x + dx)][1], nraw[nr_offset(y + dy2, x + dx2)][1]); min /= 1.2; max *= 1.2; if (eg < min) eg = scale_under(eg, min); else if (eg > max) eg = scale_over(eg, max); if (eg > channel_maximum[1]) eg = channel_maximum[1]; else if (eg < channel_minimum[1]) eg = channel_minimum[1]; nraw[nr_offset(y, x)][1] = eg; } } /* * отладочная функция */ void DHT::illustrate_dirs() { #if defined(LIBRAW_USE_OPENMP) #pragma omp parallel for schedule(guided) #endif for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) { illustrate_dline(i); } } void DHT::illustrate_dline(int i) { int iwidth = libraw.imgdata.sizes.iwidth; for (int j = 0; j < iwidth; j++) { int x = j + nr_leftmargin; int y = i + nr_topmargin; nraw[nr_offset(y, x)][0] = nraw[nr_offset(y, x)][1] = nraw[nr_offset(y, x)][2] = 0.5; int l = ndir[nr_offset(y, x)] & 8; // l >>= 3; // WTF? l = 1; if (ndir[nr_offset(y, x)] & HOT) nraw[nr_offset(y, x)][0] = l * channel_maximum[0] / 4 + channel_maximum[0] / 4; else nraw[nr_offset(y, x)][2] = l * channel_maximum[2] / 4 + channel_maximum[2] / 4; } } /* * интерполяция красных и синих. * * сначала интерполируются недостающие цвета, по диагональным направлениям от которых находятся известные, * затем ситуация сводится к тому как интерполировались зелёные. */ void DHT::make_rbdiag(int i) { int iwidth = libraw.imgdata.sizes.iwidth; int js = libraw.COLOR(i, 0) & 1; int uc = libraw.COLOR(i, js); int cl = uc ^ 2; /* * js -- начальная х-координата, которая попадает на уже интерполированный зелёный * al -- известный цвет (кроме зелёного) в точке интерполирования * cl -- неизвестный цвет */ for (int j = js; j < iwidth; j += 2) { int x = j + nr_leftmargin; int y = i + nr_topmargin; int dx, dy, dx2, dy2; if (ndir[nr_offset(y, x)] & LURD) { dx = -1; dx2 = 1; dy = -1; dy2 = 1; } else { dx = -1; dx2 = 1; dy = 1; dy2 = -1; } float g1 = 1 / calc_dist(nraw[nr_offset(y, x)][1], nraw[nr_offset(y + dy, x + dx)][1]); float g2 = 1 / calc_dist(nraw[nr_offset(y, x)][1], nraw[nr_offset(y + dy2, x + dx2)][1]); g1 *= g1 * g1; g2 *= g2 * g2; float eg; eg = nraw[nr_offset(y, x)][1] * (g1 * nraw[nr_offset(y + dy, x + dx)][cl] / nraw[nr_offset(y + dy, x + dx)][1] + g2 * nraw[nr_offset(y + dy2, x + dx2)][cl] / nraw[nr_offset(y + dy2, x + dx2)][1]) / (g1 + g2); float min, max; min = MIN(nraw[nr_offset(y + dy, x + dx)][cl], nraw[nr_offset(y + dy2, x + dx2)][cl]); max = MAX(nraw[nr_offset(y + dy, x + dx)][cl], nraw[nr_offset(y + dy2, x + dx2)][cl]); min /= 1.2; max *= 1.2; if (eg < min) eg = scale_under(eg, min); else if (eg > max) eg = scale_over(eg, max); if (eg > channel_maximum[cl]) eg = channel_maximum[cl]; else if (eg < channel_minimum[cl]) eg = channel_minimum[cl]; nraw[nr_offset(y, x)][cl] = eg; } } /* * интерполяция красных и синих в точках где был известен только зелёный, * направления горизонтальные или вертикальные */ void DHT::make_rbhv(int i) { int iwidth = libraw.imgdata.sizes.iwidth; int js = (libraw.COLOR(i, 0) & 1) ^ 1; for (int j = js; j < iwidth; j += 2) { int x = j + nr_leftmargin; int y = i + nr_topmargin; /* * поскольку сверху-снизу и справа-слева уже есть все необходимые красные и синие, * то можно выбрать наилучшее направление исходя из информации по обоим цветам. */ int dx, dy, dx2, dy2; float h1, h2; if (ndir[nr_offset(y, x)] & VER) { dx = dx2 = 0; dy = -1; dy2 = 1; } else { dy = dy2 = 0; dx = 1; dx2 = -1; } float g1 = 1 / calc_dist(nraw[nr_offset(y, x)][1], nraw[nr_offset(y + dy, x + dx)][1]); float g2 = 1 / calc_dist(nraw[nr_offset(y, x)][1], nraw[nr_offset(y + dy2, x + dx2)][1]); g1 *= g1; g2 *= g2; float eg_r, eg_b; eg_r = nraw[nr_offset(y, x)][1] * (g1 * nraw[nr_offset(y + dy, x + dx)][0] / nraw[nr_offset(y + dy, x + dx)][1] + g2 * nraw[nr_offset(y + dy2, x + dx2)][0] / nraw[nr_offset(y + dy2, x + dx2)][1]) / (g1 + g2); eg_b = nraw[nr_offset(y, x)][1] * (g1 * nraw[nr_offset(y + dy, x + dx)][2] / nraw[nr_offset(y + dy, x + dx)][1] + g2 * nraw[nr_offset(y + dy2, x + dx2)][2] / nraw[nr_offset(y + dy2, x + dx2)][1]) / (g1 + g2); float min_r, max_r; min_r = MIN(nraw[nr_offset(y + dy, x + dx)][0], nraw[nr_offset(y + dy2, x + dx2)][0]); max_r = MAX(nraw[nr_offset(y + dy, x + dx)][0], nraw[nr_offset(y + dy2, x + dx2)][0]); float min_b, max_b; min_b = MIN(nraw[nr_offset(y + dy, x + dx)][2], nraw[nr_offset(y + dy2, x + dx2)][2]); max_b = MAX(nraw[nr_offset(y + dy, x + dx)][2], nraw[nr_offset(y + dy2, x + dx2)][2]); min_r /= 1.2; max_r *= 1.2; min_b /= 1.2; max_b *= 1.2; if (eg_r < min_r) eg_r = scale_under(eg_r, min_r); else if (eg_r > max_r) eg_r = scale_over(eg_r, max_r); if (eg_b < min_b) eg_b = scale_under(eg_b, min_b); else if (eg_b > max_b) eg_b = scale_over(eg_b, max_b); if (eg_r > channel_maximum[0]) eg_r = channel_maximum[0]; else if (eg_r < channel_minimum[0]) eg_r = channel_minimum[0]; if (eg_b > channel_maximum[2]) eg_b = channel_maximum[2]; else if (eg_b < channel_minimum[2]) eg_b = channel_minimum[2]; nraw[nr_offset(y, x)][0] = eg_r; nraw[nr_offset(y, x)][2] = eg_b; } } void DHT::make_rb() { #if defined(LIBRAW_USE_OPENMP) #pragma omp barrier #pragma omp parallel for schedule(guided) #endif for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) { make_rbdiag(i); } #if defined(LIBRAW_USE_OPENMP) #pragma omp barrier #pragma omp parallel for schedule(guided) #endif for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) { make_rbhv(i); } } /* * перенос изображения в выходной массив */ void DHT::copy_to_image() { int iwidth = libraw.imgdata.sizes.iwidth; #if defined(LIBRAW_USE_OPENMP) #ifdef WIN32 #pragma omp parallel for #else #pragma omp parallel for schedule(guided) collapse(2) #endif #endif for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) { for (int j = 0; j < iwidth; ++j) { libraw.imgdata.image[i * iwidth + j][0] = (unsigned short) (nraw[nr_offset( i + nr_topmargin, j + nr_leftmargin)][0]); libraw.imgdata.image[i * iwidth + j][2] = (unsigned short) (nraw[nr_offset( i + nr_topmargin, j + nr_leftmargin)][2]); libraw.imgdata.image[i * iwidth + j][1] = libraw.imgdata.image[i * iwidth + j][3] = (unsigned short) (nraw[nr_offset(i + nr_topmargin, j + nr_leftmargin)][1]); } } } DHT::~DHT() { free(nraw); free(ndir); } void LibRaw::dht_interpolate() { printf("DHT interpolating\n"); DHT dht(*this); dht.hide_hots(); dht.make_hv_dirs(); // dht.illustrate_dirs(); dht.make_greens(); dht.make_diag_dirs(); // dht.illustrate_dirs(); dht.make_rb(); dht.restore_hots(); dht.copy_to_image(); } LibRaw-0.18.8/internal/libraw_internal_funcs.h000066400000000000000000000274051324423227700213450ustar00rootroot00000000000000/* -*- C++ -*- * File: libraw_internal_funcs.h * Copyright 2008-2017 LibRaw LLC (info@libraw.org) * Created: Sat Mar 14, 2008 LibRaw is free software; you can redistribute it and/or modify it under the terms of the one of two licenses as you choose: 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 (See file LICENSE.LGPL provided in LibRaw distribution archive for details). 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 (See file LICENSE.CDDL provided in LibRaw distribution archive for details). */ #ifndef _LIBRAW_INTERNAL_FUNCS_H #define _LIBRAW_INTERNAL_FUNCS_H #ifndef LIBRAW_LIBRARY_BUILD #error "This file should be used only for libraw library build" #else /* WF */ void wf_bayer4_igauss_filter(int radius,void* src_image, int src_imgmode, void* dst_image, int dst_imgmode); void wf_bayer4_green_blur (int mode,void* src_image, int src_imgmode, void* dst_image, int dst_imgmode); void wf_bayer4_block_filter (int* radius_list, void* src_image, int src_imgmode, void* dst_image, int dst_imgmode); double wf_filter_energy (int r1_greenmode, int r1, int r2_greenmode, int r2); /* inline functions */ ushort sget2 (uchar *s); ushort sget2Rev(uchar *s); void setCanonBodyFeatures (unsigned id); void processCanonCameraInfo (unsigned id, uchar *CameraInfo, unsigned maxlen); void Canon_CameraSettings(); void Canon_WBpresets (int skip1, int skip2); void Canon_WBCTpresets (short WBCTversion); void parseCanonMakernotes (unsigned tag, unsigned type, unsigned len); void processNikonLensData (uchar *LensData, unsigned len); void setOlympusBodyFeatures (unsigned long long id); void setPhaseOneFeatures (unsigned id); void setPentaxBodyFeatures (unsigned id); void PentaxISO (ushort c); void PentaxLensInfo (unsigned id, unsigned len); void setSonyBodyFeatures (unsigned id); void parseSonyLensType2 (uchar a, uchar b); void parseSonyLensFeatures (uchar a, uchar b); void process_Sony_0x9050 (uchar * buf, unsigned id); void process_Sony_0x940c (uchar * buf); void parseFujiMakernotes (unsigned tag, unsigned type); ushort get2(); unsigned sget4 (uchar *s); unsigned getint (int type); float int_to_float (int i); double getreal (int type); void read_shorts (ushort *pixel, unsigned count); /* Canon P&S cameras */ void canon_600_fixed_wb (int temp); int canon_600_color (int ratio[2], int mar); void canon_600_auto_wb(); void canon_600_coeff(); void canon_600_load_raw(); void canon_600_correct(); int canon_s2is(); void parse_ciff (int offset, int length, int); void ciff_block_1030(); // LJPEG decoder unsigned getbithuff (int nbits, ushort *huff); ushort* make_decoder_ref (const uchar **source); ushort* make_decoder (const uchar *source); int ljpeg_start (struct jhead *jh, int info_only); void ljpeg_end(struct jhead *jh); int ljpeg_diff (ushort *huff); ushort * ljpeg_row (int jrow, struct jhead *jh); void ljpeg_idct (struct jhead *jh); unsigned ph1_bithuff (int nbits, ushort *huff); // Canon DSLRs void crw_init_tables (unsigned table, ushort *huff[2]); int canon_has_lowbits(); void canon_load_raw(); void lossless_jpeg_load_raw(); void canon_sraw_load_raw(); // Adobe DNG void adobe_copy_pixel (unsigned int row, unsigned int col, ushort **rp); void lossless_dng_load_raw(); void deflate_dng_load_raw(); void packed_dng_load_raw(); void lossy_dng_load_raw(); //void adobe_dng_load_raw_nc(); // Pentax void pentax_load_raw(); void pentax_4shot_load_raw(); void pentax_tree(); // Nikon (and Minolta Z2) void nikon_load_raw(); void nikon_load_striped_packed_raw(); void nikon_load_sraw(); void nikon_yuv_load_raw(); void nikon_coolscan_load_raw(); int nikon_e995(); int nikon_e2100(); void nikon_3700(); int minolta_z2(); void nikon_e2100_load_raw(); // Fuji //void fuji_load_raw(); void parse_fuji (int offset); // RedCine void parse_redcine(); void redcine_load_raw(); // Rollei void rollei_load_raw(); void parse_rollei(); // MF backs //int bayer (unsigned row, unsigned col); int raw(unsigned,unsigned); void phase_one_flat_field (int is_float, int nc); void phase_one_load_raw(); unsigned ph1_bits (int nbits); void phase_one_load_raw_c(); void hasselblad_load_raw(); void leaf_hdr_load_raw(); void sinar_4shot_load_raw(); void imacon_full_load_raw(); void hasselblad_full_load_raw(); void packed_load_raw(); float find_green(int,int,int,int); void unpacked_load_raw(); void unpacked_load_raw_reversed(); void unpacked_load_raw_fuji_f700s20(); void parse_sinar_ia(); void parse_phase_one (int base); // Misc P&S cameras void parse_broadcom(); void broadcom_load_raw(); void nokia_load_raw(); void android_loose_load_raw(); void android_tight_load_raw(); void canon_rmf_load_raw(); unsigned pana_bits (int nbits); void panasonic_load_raw(); void olympus_load_raw(); void olympus_cseries_load_raw(); void minolta_rd175_load_raw(); void quicktake_100_load_raw(); const int* make_decoder_int (const int *source, int level); int radc_token (int tree); void kodak_radc_load_raw(); void kodak_jpeg_load_raw(); void kodak_dc120_load_raw(); void eight_bit_load_raw(); void smal_decode_segment (unsigned seg[2][2], int holes); void smal_v6_load_raw(); int median4 (int *p); void fill_holes (int holes); void smal_v9_load_raw(); void parse_riff(); void parse_cine(); void parse_smal (int offset, int fsize); int parse_jpeg (int offset); // Kodak void kodak_262_load_raw(); int kodak_65000_decode (short *out, int bsize); void kodak_65000_load_raw(); void kodak_rgb_load_raw(); void kodak_ycbcr_load_raw(); // void kodak_yrgb_load_raw(); void kodak_c330_load_raw(); void kodak_c603_load_raw(); void kodak_rgb_load_thumb(); void kodak_ycbcr_load_thumb(); // It's a Sony (and K&M) void sony_decrypt (unsigned *data, int len, int start, int key); void sony_load_raw(); void sony_arw_load_raw(); void sony_arw2_load_raw(); void samsung_load_raw(); void samsung2_load_raw(); void samsung3_load_raw(); void parse_minolta (int base); // Foveon/Sigma #ifdef LIBRAW_DEMOSAIC_PACK_GPL2 void foveon_sd_load_raw(); void foveon_dp_load_raw(); void foveon_huff (ushort *huff); void foveon_load_camf(); const char* foveon_camf_param (const char *block, const char *param); void * foveon_camf_matrix (unsigned dim[3], const char *name); int foveon_fixed (void *ptr, int size, const char *name); float foveon_avg (short *pix, int range[2], float cfilt); short * foveon_make_curve (double max, double mul, double filt); void foveon_make_curves(short **curvep, float dq[3], float div[3], float filt); int foveon_apply_curve (short *curve, int i); void foveon_interpolate(); char * foveon_gets (int offset, char *str, int len); void parse_foveon(); #endif // We always have x3f code compiled in! void parse_x3f(); void x3f_load_raw(); void x3f_dpq_interpolate_rg(); void x3f_dpq_interpolate_af(int xstep, int ystep, int scale); // 1x1 af pixels void x3f_dpq_interpolate_af_sd(int xstart,int ystart, int xend, int yend, int xstep, int ystep, int scale); // sd Quattro interpolation // CAM/RGB void pseudoinverse (double (*in)[3], double (*out)[3], int size); void simple_coeff (int index); // Tiff/Exif parsers void tiff_get (unsigned base,unsigned *tag, unsigned *type, unsigned *len, unsigned *save); void parse_thumb_note (int base, unsigned toff, unsigned tlen); void parse_makernote (int base, int uptag); void parse_makernote_0xc634(int base, int uptag, unsigned dng_writer); void parse_exif (int base); void linear_table (unsigned len); void Kodak_WB_0x08tags(int wb, unsigned type); void parse_kodak_ifd (int base); int parse_tiff_ifd (int base); int parse_tiff (int base); void apply_tiff(void); void parse_gps (int base); void parse_gps_libraw(int base); void romm_coeff(float romm_cam[3][3]); void parse_mos (int offset); void parse_qt (int end); void get_timestamp (int reversed); // External JPEGs, what cameras uses it ? void parse_external_jpeg(); // The identify short guess_byte_order (int words); // Tiff writer void tiff_set(struct tiff_hdr *th, ushort *ntag,ushort tag, ushort type, int count, int val); void tiff_head (struct tiff_hdr *th, int full); // splitted AHD code #define TS 512 void ahd_interpolate_green_h_and_v(int top, int left, ushort (*out_rgb)[TS][TS][3]); void ahd_interpolate_r_and_b_in_rgb_and_convert_to_cielab(int top, int left, ushort (*inout_rgb)[TS][3], short (*out_lab)[TS][3]); void ahd_interpolate_r_and_b_and_convert_to_cielab(int top, int left, ushort (*inout_rgb)[TS][TS][3], short (*out_lab)[TS][TS][3]); void ahd_interpolate_build_homogeneity_map(int top, int left, short (*lab)[TS][TS][3], char (*out_homogeneity_map)[TS][2]); void ahd_interpolate_combine_homogeneous_pixels(int top, int left, ushort (*rgb)[TS][TS][3], char (*homogeneity_map)[TS][2]); #undef TS void parse_xtrans_header(); void xtrans_compressed_load_raw(); void init_xtrans(struct xtrans_params* info); void init_xtrans_block(struct xtrans_block* info, const struct xtrans_params *params, INT64 raw_offset, unsigned dsize); void copy_line_to_xtrans(struct xtrans_block* info, int cur_line, int cur_block, int cur_block_width); void xtrans_decode_block(struct xtrans_block* info, const struct xtrans_params * params, int cur_line); // LibRaw demosaic packs functions // AMaZe int LinEqSolve(int, float*, float*, float*); // DCB void dcb_pp(); void dcb_copy_to_buffer(float (*image2)[3]); void dcb_restore_from_buffer(float (*image2)[3]); void dcb_color(); void dcb_color_full(); void dcb_map(); void dcb_correction(); void dcb_correction2(); void dcb_refinement(); void rgb_to_lch(double (*image3)[3]); void lch_to_rgb(double (*image3)[3]); void fbdd_correction(); void fbdd_correction2(double (*image3)[3]); void fbdd_green(); void dcb_ver(float (*image3)[3]); void dcb_hor(float (*image2)[3]); void dcb_color2(float (*image2)[3]); void dcb_color3(float (*image3)[3]); void dcb_decide(float (*image2)[3], float (*image3)[3]); void dcb_nyquist(); // VCD/modified dcraw void refinement(); void ahd_partial_interpolate(int threshold_value); void es_median_filter(); void median_filter_new(); #endif #endif LibRaw-0.18.8/internal/libraw_x3f.cpp000066400000000000000000001743341324423227700173720ustar00rootroot00000000000000/* Library for accessing X3F Files ---------------------------------------------------------------- BSD-style License ---------------------------------------------------------------- * Copyright (c) 2010, Roland Karlsson (roland@proxel.se) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the organization nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY ROLAND KARLSSON ''AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL ROLAND KARLSSON BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* From X3F_IO.H */ #include #include #include #include #include #include "../libraw/libraw_datastream.h" #define SIZE_UNIQUE_IDENTIFIER 16 #define SIZE_WHITE_BALANCE 32 #define SIZE_COLOR_MODE 32 #define NUM_EXT_DATA_2_1 32 #define NUM_EXT_DATA_3_0 64 #define NUM_EXT_DATA NUM_EXT_DATA_3_0 #define X3F_VERSION(MAJ,MIN) (uint32_t)(((MAJ)<<16) + MIN) #define X3F_VERSION_2_0 X3F_VERSION(2,0) #define X3F_VERSION_2_1 X3F_VERSION(2,1) #define X3F_VERSION_2_2 X3F_VERSION(2,2) #define X3F_VERSION_2_3 X3F_VERSION(2,3) #define X3F_VERSION_3_0 X3F_VERSION(3,0) #define X3F_VERSION_4_0 X3F_VERSION(4,0) /* Main file identifier */ #define X3F_FOVb (uint32_t)(0x62564f46) /* Directory identifier */ #define X3F_SECd (uint32_t)(0x64434553) /* Property section identifiers */ #define X3F_PROP (uint32_t)(0x504f5250) #define X3F_SECp (uint32_t)(0x70434553) /* Image section identifiers */ #define X3F_IMAG (uint32_t)(0x46414d49) #define X3F_IMA2 (uint32_t)(0x32414d49) #define X3F_SECi (uint32_t)(0x69434553) /* CAMF section identifiers */ #define X3F_CAMF (uint32_t)(0x464d4143) #define X3F_SECc (uint32_t)(0x63434553) /* CAMF entry identifiers */ #define X3F_CMbP (uint32_t)(0x50624d43) #define X3F_CMbT (uint32_t)(0x54624d43) #define X3F_CMbM (uint32_t)(0x4d624d43) #define X3F_CMb (uint32_t)(0x00624d43) /* SDQ section identifiers ? - TODO */ #define X3F_SPPA (uint32_t)(0x41505053) #define X3F_SECs (uint32_t)(0x73434553) #define X3F_IMAGE_THUMB_PLAIN (uint32_t)(0x00020003) #define X3F_IMAGE_THUMB_HUFFMAN (uint32_t)(0x0002000b) #define X3F_IMAGE_THUMB_JPEG (uint32_t)(0x00020012) #define X3F_IMAGE_THUMB_SDQ (uint32_t)(0x00020019) /* SDQ ? - TODO */ #define X3F_IMAGE_RAW_HUFFMAN_X530 (uint32_t)(0x00030005) #define X3F_IMAGE_RAW_HUFFMAN_10BIT (uint32_t)(0x00030006) #define X3F_IMAGE_RAW_TRUE (uint32_t)(0x0003001e) #define X3F_IMAGE_RAW_MERRILL (uint32_t)(0x0001001e) #define X3F_IMAGE_RAW_QUATTRO (uint32_t)(0x00010023) #define X3F_IMAGE_RAW_SDQ (uint32_t)(0x00010025) #define X3F_IMAGE_RAW_SDQH (uint32_t)(0x00010027) #define X3F_IMAGE_RAW_SDQH2 (uint32_t)(0x00010029) #define X3F_IMAGE_HEADER_SIZE 28 #define X3F_CAMF_HEADER_SIZE 28 #define X3F_PROPERTY_LIST_HEADER_SIZE 24 typedef uint16_t utf16_t; typedef int bool_t; typedef enum x3f_extended_types_e { X3F_EXT_TYPE_NONE=0, X3F_EXT_TYPE_EXPOSURE_ADJUST=1, X3F_EXT_TYPE_CONTRAST_ADJUST=2, X3F_EXT_TYPE_SHADOW_ADJUST=3, X3F_EXT_TYPE_HIGHLIGHT_ADJUST=4, X3F_EXT_TYPE_SATURATION_ADJUST=5, X3F_EXT_TYPE_SHARPNESS_ADJUST=6, X3F_EXT_TYPE_RED_ADJUST=7, X3F_EXT_TYPE_GREEN_ADJUST=8, X3F_EXT_TYPE_BLUE_ADJUST=9, X3F_EXT_TYPE_FILL_LIGHT_ADJUST=10 } x3f_extended_types_t; typedef struct x3f_property_s { /* Read from file */ uint32_t name_offset; uint32_t value_offset; /* Computed */ utf16_t *name; /* 0x0000 terminated UTF 16 */ utf16_t *value; /* 0x0000 terminated UTF 16 */ char *name_utf8; /* converted to UTF 8 */ char *value_utf8; /* converted to UTF 8 */ } x3f_property_t; typedef struct x3f_property_table_s { uint32_t size; x3f_property_t *element; } x3f_property_table_t; typedef struct x3f_property_list_s { /* 2.0 Fields */ uint32_t num_properties; uint32_t character_format; uint32_t reserved; uint32_t total_length; x3f_property_table_t property_table; void *data; uint32_t data_size; } x3f_property_list_t; typedef struct x3f_table8_s { uint32_t size; uint8_t *element; } x3f_table8_t; typedef struct x3f_table16_s { uint32_t size; uint16_t *element; } x3f_table16_t; typedef struct x3f_table32_s { uint32_t size; uint32_t *element; } x3f_table32_t; typedef struct { uint8_t *data; /* Pointer to actual image data */ void *buf; /* Pointer to allocated buffer for free() */ uint32_t rows; uint32_t columns; uint32_t channels; uint32_t row_stride; } x3f_area8_t; typedef struct { uint16_t *data; /* Pointer to actual image data */ void *buf; /* Pointer to allocated buffer for free() */ uint32_t rows; uint32_t columns; uint32_t channels; uint32_t row_stride; } x3f_area16_t; #define UNDEFINED_LEAF 0xffffffff typedef struct x3f_huffnode_s { struct x3f_huffnode_s *branch[2]; uint32_t leaf; } x3f_huffnode_t; typedef struct x3f_hufftree_s { uint32_t free_node_index; /* Free node index in huffman tree array */ x3f_huffnode_t *nodes; /* Coding tree */ } x3f_hufftree_t; typedef struct x3f_true_huffman_element_s { uint8_t code_size; uint8_t code; } x3f_true_huffman_element_t; typedef struct x3f_true_huffman_s { uint32_t size; x3f_true_huffman_element_t *element; } x3f_true_huffman_t; /* 0=bottom, 1=middle, 2=top */ #define TRUE_PLANES 3 typedef struct x3f_true_s { uint16_t seed[TRUE_PLANES]; /* Always 512,512,512 */ uint16_t unknown; /* Always 0 */ x3f_true_huffman_t table; /* Huffman table - zero terminated. size is the number of leaves plus 1.*/ x3f_table32_t plane_size; /* Size of the 3 planes */ uint8_t *plane_address[TRUE_PLANES]; /* computed offset to the planes */ x3f_hufftree_t tree; /* Coding tree */ x3f_area16_t x3rgb16; /* 3x16 bit X3-RGB data */ } x3f_true_t; typedef struct x3f_quattro_s { struct { uint16_t columns; uint16_t rows; } plane[TRUE_PLANES]; uint32_t unknown; bool_t quattro_layout; x3f_area16_t top16; /* Container for the bigger top layer */ } x3f_quattro_t; typedef struct x3f_huffman_s { x3f_table16_t mapping; /* Value Mapping = X3F lossy compression */ x3f_table32_t table; /* Coding Table */ x3f_hufftree_t tree; /* Coding tree */ x3f_table32_t row_offsets; /* Row offsets */ x3f_area8_t rgb8; /* 3x8 bit RGB data */ x3f_area16_t x3rgb16; /* 3x16 bit X3-RGB data */ } x3f_huffman_t; typedef struct x3f_image_data_s { /* 2.0 Fields */ /* ------------------------------------------------------------------ */ /* Known combinations of type and format are: 1-6, 2-3, 2-11, 2-18, 3-6 */ uint32_t type; /* 1 = RAW X3 (SD1) 2 = thumbnail or maybe just RGB 3 = RAW X3 */ uint32_t format; /* 3 = 3x8 bit pixmap 6 = 3x10 bit huffman with map table 11 = 3x8 bit huffman 18 = JPEG */ uint32_t type_format; /* type<<16 + format */ /* ------------------------------------------------------------------ */ uint32_t columns; /* width / row size in pixels */ uint32_t rows; /* height */ uint32_t row_stride; /* row size in bytes */ /* NULL if not used */ x3f_huffman_t *huffman; /* Huffman help data */ x3f_true_t *tru; /* TRUE help data */ x3f_quattro_t *quattro; /* Quattro help data */ void *data; /* Take from file if NULL. Otherwise, this is the actual data bytes in the file. */ uint32_t data_size; } x3f_image_data_t; typedef struct camf_dim_entry_s { uint32_t size; uint32_t name_offset; uint32_t n; /* 0,1,2,3... */ char *name; } camf_dim_entry_t; typedef enum {M_FLOAT, M_INT, M_UINT} matrix_type_t; typedef struct camf_entry_s { /* pointer into decoded data */ void *entry; /* entry header */ uint32_t id; uint32_t version; uint32_t entry_size; uint32_t name_offset; uint32_t value_offset; /* computed values */ char *name_address; void *value_address; uint32_t name_size; uint32_t value_size; /* extracted values for explicit CAMF entry types*/ uint32_t text_size; char *text; uint32_t property_num; char **property_name; uint8_t **property_value; uint32_t matrix_dim; camf_dim_entry_t *matrix_dim_entry; /* Offset, pointer and size and type of raw data */ uint32_t matrix_type; uint32_t matrix_data_off; void *matrix_data; uint32_t matrix_element_size; /* Pointer and type of copied data */ matrix_type_t matrix_decoded_type; void *matrix_decoded; /* Help data to try to estimate element size */ uint32_t matrix_elements; uint32_t matrix_used_space; double matrix_estimated_element_size; } camf_entry_t; typedef struct camf_entry_table_s { uint32_t size; camf_entry_t *element; } camf_entry_table_t; typedef struct x3f_camf_typeN_s { uint32_t val0; uint32_t val1; uint32_t val2; uint32_t val3; } x3f_camf_typeN_t; typedef struct x3f_camf_type2_s { uint32_t reserved; uint32_t infotype; uint32_t infotype_version; uint32_t crypt_key; } x3f_camf_type2_t; typedef struct x3f_camf_type4_s { uint32_t decoded_data_size; uint32_t decode_bias; uint32_t block_size; uint32_t block_count; } x3f_camf_type4_t; typedef struct x3f_camf_type5_s { uint32_t decoded_data_size; uint32_t decode_bias; uint32_t unknown2; uint32_t unknown3; } x3f_camf_type5_t; typedef struct x3f_camf_s { /* Header info */ uint32_t type; union { x3f_camf_typeN_t tN; x3f_camf_type2_t t2; x3f_camf_type4_t t4; x3f_camf_type5_t t5; }; /* The encrypted raw data */ void *data; uint32_t data_size; /* Help data for type 4 Huffman compression */ x3f_true_huffman_t table; x3f_hufftree_t tree; uint8_t *decoding_start; uint32_t decoding_size; /* The decrypted data */ void *decoded_data; uint32_t decoded_data_size; /* Pointers into the decrypted data */ camf_entry_table_t entry_table; } x3f_camf_t; typedef struct x3f_directory_entry_header_s { uint32_t identifier; /* Should be ´SECp´, "SECi", ... */ uint32_t version; /* 0x00020001 is version 2.1 */ union { x3f_property_list_t property_list; x3f_image_data_t image_data; x3f_camf_t camf; } data_subsection; } x3f_directory_entry_header_t; typedef struct x3f_directory_entry_s { struct { uint32_t offset; uint32_t size; } input, output; uint32_t type; x3f_directory_entry_header_t header; } x3f_directory_entry_t; typedef struct x3f_directory_section_s { uint32_t identifier; /* Should be ´SECd´ */ uint32_t version; /* 0x00020001 is version 2.1 */ /* 2.0 Fields */ uint32_t num_directory_entries; x3f_directory_entry_t *directory_entry; } x3f_directory_section_t; typedef struct x3f_header_s { /* 2.0 Fields */ uint32_t identifier; /* Should be ´FOVb´ */ uint32_t version; /* 0x00020001 means 2.1 */ uint8_t unique_identifier[SIZE_UNIQUE_IDENTIFIER]; uint32_t mark_bits; uint32_t columns; /* Columns and rows ... */ uint32_t rows; /* ... before rotation */ uint32_t rotation; /* 0, 90, 180, 270 */ char white_balance[SIZE_WHITE_BALANCE]; /* Introduced in 2.1 */ char color_mode[SIZE_COLOR_MODE]; /* Introduced in 2.3 */ /* Introduced in 2.1 and extended from 32 to 64 in 3.0 */ uint8_t extended_types[NUM_EXT_DATA]; /* x3f_extended_types_t */ float extended_data[NUM_EXT_DATA]; /* 32 bits, but do type differ? */ } x3f_header_t; typedef struct x3f_info_s { char *error; struct { LibRaw_abstract_datastream *file; /* Use if more data is needed */ } input, output; } x3f_info_t; typedef struct x3f_s { x3f_info_t info; x3f_header_t header; x3f_directory_section_t directory_section; } x3f_t; typedef enum x3f_return_e { X3F_OK=0, X3F_ARGUMENT_ERROR=1, X3F_INFILE_ERROR=2, X3F_OUTFILE_ERROR=3, X3F_INTERNAL_ERROR=4 } x3f_return_t; x3f_return_t x3f_delete(x3f_t *x3f); /* Hacky external flags */ /* --------------------------------------------------------------------- */ /* extern */ int legacy_offset = 0; /* extern */ bool_t auto_legacy_offset = 1; /* --------------------------------------------------------------------- */ /* Huffman Decode Macros */ /* --------------------------------------------------------------------- */ #define HUF_TREE_MAX_LENGTH 27 #define HUF_TREE_MAX_NODES(_leaves) ((HUF_TREE_MAX_LENGTH+1)*(_leaves)) #define HUF_TREE_GET_LENGTH(_v) (((_v)>>27)&0x1f) #define HUF_TREE_GET_CODE(_v) ((_v)&0x07ffffff) /* --------------------------------------------------------------------- */ /* Reading and writing - assuming little endian in the file */ /* --------------------------------------------------------------------- */ static int x3f_get1(LibRaw_abstract_datastream *f) { /* Little endian file */ return f->get_char(); } static int x3f_sget2 (uchar *s) { return s[0] | s[1] << 8; } static int x3f_get2(LibRaw_abstract_datastream *f) { uchar str[2] = { 0xff,0xff }; f->read (str, 1, 2); return x3f_sget2(str); } unsigned x3f_sget4 (uchar *s) { return s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24; } unsigned x3f_get4(LibRaw_abstract_datastream *f) { uchar str[4] = { 0xff,0xff,0xff,0xff }; f->read (str, 1, 4); return x3f_sget4(str); } #define FREE(P) do { free(P); (P) = NULL; } while (0) #define PUT_GET_N(_buffer,_size,_file,_func) \ do \ { \ int _left = _size; \ while (_left != 0) { \ int _cur = _file->_func(_buffer,1,_left); \ if (_cur == 0) { \ throw LIBRAW_EXCEPTION_IO_CORRUPT; \ exit(1); \ } \ _left -= _cur; \ } \ } while(0) #define GET1(_v) do {(_v) = x3f_get1(I->input.file);} while (0) #define GET2(_v) do {(_v) = x3f_get2(I->input.file);} while (0) #define GET4(_v) do {(_v) = x3f_get4(I->input.file);} while (0) #define GET4F(_v) \ do { \ union {int32_t i; float f;} _tmp; \ _tmp.i = x3f_get4(I->input.file); \ (_v) = _tmp.f; \ } while (0) #define GETN(_v,_s) PUT_GET_N(_v,_s,I->input.file,read) #define GET_TABLE(_T, _GETX, _NUM,_TYPE) \ do { \ int _i; \ (_T).size = (_NUM); \ (_T).element = (_TYPE *)realloc((_T).element, \ (_NUM)*sizeof((_T).element[0])); \ for (_i = 0; _i < (_T).size; _i++) \ _GETX((_T).element[_i]); \ } while (0) #define GET_PROPERTY_TABLE(_T, _NUM) \ do { \ int _i; \ (_T).size = (_NUM); \ (_T).element = (x3f_property_t *)realloc((_T).element, \ (_NUM)*sizeof((_T).element[0])); \ for (_i = 0; _i < (_T).size; _i++) { \ GET4((_T).element[_i].name_offset); \ GET4((_T).element[_i].value_offset); \ } \ } while (0) #define GET_TRUE_HUFF_TABLE(_T) \ do { \ int _i; \ (_T).element = NULL; \ for (_i = 0; ; _i++) { \ (_T).size = _i + 1; \ (_T).element = (x3f_true_huffman_element_t *)realloc((_T).element, \ (_i + 1)*sizeof((_T).element[0])); \ GET1((_T).element[_i].code_size); \ GET1((_T).element[_i].code); \ if ((_T).element[_i].code_size == 0) break; \ } \ } while (0) /* --------------------------------------------------------------------- */ /* Allocating Huffman tree help data */ /* --------------------------------------------------------------------- */ static void cleanup_huffman_tree(x3f_hufftree_t *HTP) { free(HTP->nodes); } static void new_huffman_tree(x3f_hufftree_t *HTP, int bits) { int leaves = 1<free_node_index = 0; HTP->nodes = (x3f_huffnode_t *) calloc(1, HUF_TREE_MAX_NODES(leaves)*sizeof(x3f_huffnode_t)); } /* --------------------------------------------------------------------- */ /* Allocating TRUE engine RAW help data */ /* --------------------------------------------------------------------- */ static void cleanup_true(x3f_true_t **TRUP) { x3f_true_t *TRU = *TRUP; if (TRU == NULL) return; FREE(TRU->table.element); FREE(TRU->plane_size.element); cleanup_huffman_tree(&TRU->tree); FREE(TRU->x3rgb16.buf); FREE(TRU); *TRUP = NULL; } static x3f_true_t *new_true(x3f_true_t **TRUP) { x3f_true_t *TRU = (x3f_true_t *)calloc(1, sizeof(x3f_true_t)); cleanup_true(TRUP); TRU->table.size = 0; TRU->table.element = NULL; TRU->plane_size.size = 0; TRU->plane_size.element = NULL; TRU->tree.nodes = NULL; TRU->x3rgb16.data = NULL; TRU->x3rgb16.buf = NULL; *TRUP = TRU; return TRU; } static void cleanup_quattro(x3f_quattro_t **QP) { x3f_quattro_t *Q = *QP; if (Q == NULL) return; FREE(Q->top16.buf); FREE(Q); *QP = NULL; } static x3f_quattro_t *new_quattro(x3f_quattro_t **QP) { x3f_quattro_t *Q = (x3f_quattro_t *)calloc(1, sizeof(x3f_quattro_t)); int i; cleanup_quattro(QP); for (i=0; iplane[i].columns = 0; Q->plane[i].rows = 0; } Q->unknown = 0; Q->top16.data = NULL; Q->top16.buf = NULL; *QP = Q; return Q; } /* --------------------------------------------------------------------- */ /* Allocating Huffman engine help data */ /* --------------------------------------------------------------------- */ static void cleanup_huffman(x3f_huffman_t **HUFP) { x3f_huffman_t *HUF = *HUFP; if (HUF == NULL) return; FREE(HUF->mapping.element); FREE(HUF->table.element); cleanup_huffman_tree(&HUF->tree); FREE(HUF->row_offsets.element); FREE(HUF->rgb8.buf); FREE(HUF->x3rgb16.buf); FREE(HUF); *HUFP = NULL; } static x3f_huffman_t *new_huffman(x3f_huffman_t **HUFP) { x3f_huffman_t *HUF = (x3f_huffman_t *)calloc(1, sizeof(x3f_huffman_t)); cleanup_huffman(HUFP); /* Set all not read data block pointers to NULL */ HUF->mapping.size = 0; HUF->mapping.element = NULL; HUF->table.size = 0; HUF->table.element = NULL; HUF->tree.nodes = NULL; HUF->row_offsets.size = 0; HUF->row_offsets.element = NULL; HUF->rgb8.data = NULL; HUF->rgb8.buf = NULL; HUF->x3rgb16.data = NULL; HUF->x3rgb16.buf = NULL; *HUFP = HUF; return HUF; } /* --------------------------------------------------------------------- */ /* Creating a new x3f structure from file */ /* --------------------------------------------------------------------- */ /* extern */ x3f_t *x3f_new_from_file(LibRaw_abstract_datastream *infile) { if (!infile) return NULL; INT64 fsize = infile->size(); x3f_t *x3f = (x3f_t *)calloc(1, sizeof(x3f_t)); x3f_info_t *I = NULL; x3f_header_t *H = NULL; x3f_directory_section_t *DS = NULL; int i, d; I = &x3f->info; I->error = NULL; I->input.file = infile; I->output.file = NULL; /* Read file header */ H = &x3f->header; infile->seek(0, SEEK_SET); GET4(H->identifier); if (H->identifier != X3F_FOVb) { free(x3f); return NULL; } GET4(H->version); GETN(H->unique_identifier, SIZE_UNIQUE_IDENTIFIER); /* TODO: the meaning of the rest of the header for version >= 4.0 (Quattro) is unknown */ if (H->version < X3F_VERSION_4_0) { GET4(H->mark_bits); GET4(H->columns); GET4(H->rows); GET4(H->rotation); if (H->version >= X3F_VERSION_2_1) { int num_ext_data = H->version >= X3F_VERSION_3_0 ? NUM_EXT_DATA_3_0 : NUM_EXT_DATA_2_1; GETN(H->white_balance, SIZE_WHITE_BALANCE); if (H->version >= X3F_VERSION_2_3) GETN(H->color_mode, SIZE_COLOR_MODE); GETN(H->extended_types, num_ext_data); for (i = 0; i < num_ext_data; i++) GET4F(H->extended_data[i]); } } /* Go to the beginning of the directory */ infile->seek(-4, SEEK_END); infile->seek(x3f_get4(infile), SEEK_SET); /* Read the directory header */ DS = &x3f->directory_section; GET4(DS->identifier); GET4(DS->version); GET4(DS->num_directory_entries); if (DS->num_directory_entries > 50) goto _err; // too much direntries, most likely broken file if (DS->num_directory_entries > 0) { size_t size = DS->num_directory_entries * sizeof(x3f_directory_entry_t); DS->directory_entry = (x3f_directory_entry_t *)calloc(1, size); } /* Traverse the directory */ for (d=0; dnum_directory_entries; d++) { x3f_directory_entry_t *DE = &DS->directory_entry[d]; x3f_directory_entry_header_t *DEH = &DE->header; uint32_t save_dir_pos; /* Read the directory entry info */ GET4(DE->input.offset); GET4(DE->input.size); if (DE->input.offset + DE->input.size > fsize * 2) goto _err; DE->output.offset = 0; DE->output.size = 0; GET4(DE->type); /* Save current pos and go to the entry */ save_dir_pos = infile->tell(); infile->seek(DE->input.offset, SEEK_SET); /* Read the type independent part of the entry header */ DEH = &DE->header; GET4(DEH->identifier); GET4(DEH->version); /* NOTE - the tests below could be made on DE->type instead */ if (DEH->identifier == X3F_SECp) { x3f_property_list_t *PL = &DEH->data_subsection.property_list; if (!PL) goto _err; /* Read the property part of the header */ GET4(PL->num_properties); GET4(PL->character_format); GET4(PL->reserved); GET4(PL->total_length); /* Set all not read data block pointers to NULL */ PL->data = NULL; PL->data_size = 0; } if (DEH->identifier == X3F_SECi) { x3f_image_data_t *ID = &DEH->data_subsection.image_data; if (!ID) goto _err; /* Read the image part of the header */ GET4(ID->type); GET4(ID->format); ID->type_format = (ID->type << 16) + (ID->format); GET4(ID->columns); GET4(ID->rows); GET4(ID->row_stride); /* Set all not read data block pointers to NULL */ ID->huffman = NULL; ID->data = NULL; ID->data_size = 0; } if (DEH->identifier == X3F_SECc) { x3f_camf_t *CAMF = &DEH->data_subsection.camf; if (!CAMF) goto _err; /* Read the CAMF part of the header */ GET4(CAMF->type); GET4(CAMF->tN.val0); GET4(CAMF->tN.val1); GET4(CAMF->tN.val2); GET4(CAMF->tN.val3); /* Set all not read data block pointers to NULL */ CAMF->data = NULL; CAMF->data_size = 0; /* Set all not allocated help pointers to NULL */ CAMF->table.element = NULL; CAMF->table.size = 0; CAMF->tree.nodes = NULL; CAMF->decoded_data = NULL; CAMF->decoded_data_size = 0; CAMF->entry_table.element = NULL; CAMF->entry_table.size = 0; } /* Reset the file pointer back to the directory */ infile->seek(save_dir_pos, SEEK_SET); } return x3f; _err: if (x3f) { DS = &x3f->directory_section; if (DS && DS->directory_entry) free(DS->directory_entry); free(x3f); } return NULL; } /* --------------------------------------------------------------------- */ /* Clean up an x3f structure */ /* --------------------------------------------------------------------- */ static void free_camf_entry(camf_entry_t *entry) { FREE(entry->property_name); FREE(entry->property_value); FREE(entry->matrix_decoded); FREE(entry->matrix_dim_entry); } /* extern */ x3f_return_t x3f_delete(x3f_t *x3f) { x3f_directory_section_t *DS; int d; if (x3f == NULL) return X3F_ARGUMENT_ERROR; DS = &x3f->directory_section; if (DS->num_directory_entries > 50) return X3F_ARGUMENT_ERROR; for (d=0; dnum_directory_entries; d++) { x3f_directory_entry_t *DE = &DS->directory_entry[d]; x3f_directory_entry_header_t *DEH = &DE->header; if (DEH->identifier == X3F_SECp) { x3f_property_list_t *PL = &DEH->data_subsection.property_list; if (PL) { int i; for (i = 0; i < PL->property_table.size; i++) { FREE(PL->property_table.element[i].name_utf8); FREE(PL->property_table.element[i].value_utf8); } } FREE(PL->property_table.element); FREE(PL->data); } if (DEH->identifier == X3F_SECi) { x3f_image_data_t *ID = &DEH->data_subsection.image_data; if (ID) { cleanup_huffman(&ID->huffman); cleanup_true(&ID->tru); cleanup_quattro(&ID->quattro); FREE(ID->data); } } if (DEH->identifier == X3F_SECc) { x3f_camf_t *CAMF = &DEH->data_subsection.camf; int i; if (CAMF) { FREE(CAMF->data); FREE(CAMF->table.element); cleanup_huffman_tree(&CAMF->tree); FREE(CAMF->decoded_data); for (i = 0; i < CAMF->entry_table.size; i++) { free_camf_entry(&CAMF->entry_table.element[i]); } } FREE(CAMF->entry_table.element); } } FREE(DS->directory_entry); FREE(x3f); return X3F_OK; } /* --------------------------------------------------------------------- */ /* Getting a reference to a directory entry */ /* --------------------------------------------------------------------- */ /* TODO: all those only get the first instance */ static x3f_directory_entry_t *x3f_get(x3f_t *x3f, uint32_t type, uint32_t image_type) { x3f_directory_section_t *DS; int d; if (x3f == NULL) return NULL; DS = &x3f->directory_section; for (d=0; dnum_directory_entries; d++) { x3f_directory_entry_t *DE = &DS->directory_entry[d]; x3f_directory_entry_header_t *DEH = &DE->header; if (DEH->identifier == type) { switch (DEH->identifier) { case X3F_SECi: { x3f_image_data_t *ID = &DEH->data_subsection.image_data; if (ID->type_format == image_type) return DE; } break; default: return DE; } } } return NULL; } /* extern */ x3f_directory_entry_t *x3f_get_raw(x3f_t *x3f) { x3f_directory_entry_t *DE; if ((DE = x3f_get(x3f, X3F_SECi, X3F_IMAGE_RAW_HUFFMAN_X530)) != NULL) return DE; if ((DE = x3f_get(x3f, X3F_SECi, X3F_IMAGE_RAW_HUFFMAN_10BIT)) != NULL) return DE; if ((DE = x3f_get(x3f, X3F_SECi, X3F_IMAGE_RAW_TRUE)) != NULL) return DE; if ((DE = x3f_get(x3f, X3F_SECi, X3F_IMAGE_RAW_MERRILL)) != NULL) return DE; if ((DE = x3f_get(x3f, X3F_SECi, X3F_IMAGE_RAW_QUATTRO)) != NULL) return DE; if ((DE = x3f_get(x3f, X3F_SECi, X3F_IMAGE_RAW_SDQ)) != NULL) return DE; if ((DE = x3f_get(x3f, X3F_SECi, X3F_IMAGE_RAW_SDQH)) != NULL) return DE; if ((DE = x3f_get(x3f, X3F_SECi, X3F_IMAGE_RAW_SDQH2)) != NULL) return DE; return NULL; } /* extern */ x3f_directory_entry_t *x3f_get_thumb_plain(x3f_t *x3f) { return x3f_get(x3f, X3F_SECi, X3F_IMAGE_THUMB_PLAIN); } /* extern */ x3f_directory_entry_t *x3f_get_thumb_huffman(x3f_t *x3f) { return x3f_get(x3f, X3F_SECi, X3F_IMAGE_THUMB_HUFFMAN); } /* extern */ x3f_directory_entry_t *x3f_get_thumb_jpeg(x3f_t *x3f) { return x3f_get(x3f, X3F_SECi, X3F_IMAGE_THUMB_JPEG); } /* extern */ x3f_directory_entry_t *x3f_get_camf(x3f_t *x3f) { return x3f_get(x3f, X3F_SECc, 0); } /* extern */ x3f_directory_entry_t *x3f_get_prop(x3f_t *x3f) { return x3f_get(x3f, X3F_SECp, 0); } /* For some obscure reason, the bit numbering is weird. It is generally some kind of "big endian" style - e.g. the bit 7 is the first in a byte and bit 31 first in a 4 byte int. For patterns in the huffman pattern table, bit 27 is the first bit and bit 26 the next one. */ #define PATTERN_BIT_POS(_len, _bit) ((_len) - (_bit) - 1) #define MEMORY_BIT_POS(_bit) PATTERN_BIT_POS(8, _bit) /* --------------------------------------------------------------------- */ /* Huffman Decode */ /* --------------------------------------------------------------------- */ /* Make the huffman tree */ #ifdef DBG_PRNT static char *display_code(int length, uint32_t code, char *buffer) { int i; for (i=0; i>pos)&1) == 0 ? '0' : '1'; } buffer[i] = 0; return buffer; } #endif static x3f_huffnode_t *new_node(x3f_hufftree_t *tree) { x3f_huffnode_t *t = &tree->nodes[tree->free_node_index]; t->branch[0] = NULL; t->branch[1] = NULL; t->leaf = UNDEFINED_LEAF; tree->free_node_index++; return t; } static void add_code_to_tree(x3f_hufftree_t *tree, int length, uint32_t code, uint32_t value) { int i; x3f_huffnode_t *t = tree->nodes; for (i=0; i>pos)&1; x3f_huffnode_t *t_next = t->branch[bit]; if (t_next == NULL) t_next = t->branch[bit] = new_node(tree); t = t_next; } t->leaf = value; } static void populate_true_huffman_tree(x3f_hufftree_t *tree, x3f_true_huffman_t *table) { int i; new_node(tree); for (i=0; isize; i++) { x3f_true_huffman_element_t *element = &table->element[i]; uint32_t length = element->code_size; if (length != 0) { /* add_code_to_tree wants the code right adjusted */ uint32_t code = ((element->code) >> (8 - length)) & 0xff; uint32_t value = i; add_code_to_tree(tree, length, code, value); #ifdef DBG_PRNT { char buffer[100]; x3f_printf(DEBUG, "H %5d : %5x : %5d : %02x %08x (%08x) (%s)\n", i, i, value, length, code, value, display_code(length, code, buffer)); } #endif } } } static void populate_huffman_tree(x3f_hufftree_t *tree, x3f_table32_t *table, x3f_table16_t *mapping) { int i; new_node(tree); for (i=0; isize; i++) { uint32_t element = table->element[i]; if (element != 0) { uint32_t length = HUF_TREE_GET_LENGTH(element); uint32_t code = HUF_TREE_GET_CODE(element); uint32_t value; /* If we have a valid mapping table - then the value from the mapping table shall be used. Otherwise we use the current index in the table as value. */ if (table->size == mapping->size) value = mapping->element[i]; else value = i; add_code_to_tree(tree, length, code, value); #ifdef DBG_PRNT { char buffer[100]; x3f_printf(DEBUG, "H %5d : %5x : %5d : %02x %08x (%08x) (%s)\n", i, i, value, length, code, element, display_code(length, code, buffer)); } #endif } } } #ifdef DBG_PRNT static void print_huffman_tree(x3f_huffnode_t *t, int length, uint32_t code) { char buf1[100]; char buf2[100]; x3f_printf(DEBUG, "%*s (%s,%s) %s (%s)\n", length, length < 1 ? "-" : (code&1) ? "1" : "0", t->branch[0]==NULL ? "-" : "0", t->branch[1]==NULL ? "-" : "1", t->leaf==UNDEFINED_LEAF ? "-" : (sprintf(buf1, "%x", t->leaf),buf1), display_code(length, code, buf2)); code = code << 1; if (t->branch[0]) print_huffman_tree(t->branch[0], length+1, code+0); if (t->branch[1]) print_huffman_tree(t->branch[1], length+1, code+1); } #endif /* Help machinery for reading bits in a memory */ typedef struct bit_state_s { uint8_t *next_address; uint8_t bit_offset; uint8_t bits[8]; } bit_state_t; static void set_bit_state(bit_state_t *BS, uint8_t *address) { BS->next_address = address; BS->bit_offset = 8; } static uint8_t get_bit(bit_state_t *BS) { if (BS->bit_offset == 8) { uint8_t byte = *BS->next_address; int i; for (i=7; i>= 0; i--) { BS->bits[i] = byte&1; byte = byte >> 1; } BS->next_address++; BS->bit_offset = 0; } return BS->bits[BS->bit_offset++]; } /* Decode use the TRUE algorithm */ static int32_t get_true_diff(bit_state_t *BS, x3f_hufftree_t *HTP) { int32_t diff; x3f_huffnode_t *node = &HTP->nodes[0]; uint8_t bits; while (node->branch[0] != NULL || node->branch[1] != NULL) { uint8_t bit = get_bit(BS); x3f_huffnode_t *new_node = node->branch[bit]; node = new_node; if (node == NULL) { /* TODO: Shouldn't this be treated as a fatal error? */ return 0; } } bits = node->leaf; if (bits == 0) diff = 0; else { uint8_t first_bit = get_bit(BS); int i; diff = first_bit; for (i=1; itru; x3f_quattro_t *Q = ID->quattro; uint32_t seed = TRU->seed[color]; /* TODO : Is this correct ? */ int row; x3f_hufftree_t *tree = &TRU->tree; bit_state_t BS; int32_t row_start_acc[2][2]; uint32_t rows = ID->rows; uint32_t cols = ID->columns; x3f_area16_t *area = &TRU->x3rgb16; uint16_t *dst = area->data + color; set_bit_state(&BS, TRU->plane_address[color]); row_start_acc[0][0] = seed; row_start_acc[0][1] = seed; row_start_acc[1][0] = seed; row_start_acc[1][1] = seed; if (ID->type_format == X3F_IMAGE_RAW_QUATTRO || ID->type_format == X3F_IMAGE_RAW_SDQ || ID->type_format == X3F_IMAGE_RAW_SDQH || ID->type_format == X3F_IMAGE_RAW_SDQH2 ) { rows = Q->plane[color].rows; cols = Q->plane[color].columns; if (Q->quattro_layout && color == 2) { area = &Q->top16; dst = area->data; } } else { } if(rows != area->rows || cols < area->columns) throw LIBRAW_EXCEPTION_IO_CORRUPT; for (row = 0; row < rows; row++) { int col; bool_t odd_row = row&1; int32_t acc[2]; for (col = 0; col < cols; col++) { bool_t odd_col = col&1; int32_t diff = get_true_diff(&BS, tree); int32_t prev = col < 2 ? row_start_acc[odd_row][odd_col] : acc[odd_col]; int32_t value = prev + diff; acc[odd_col] = value; if (col < 2) row_start_acc[odd_row][odd_col] = value; /* Discard additional data at the right for binned Quattro plane 2 */ if (col >= area->columns) continue; *dst = value; dst += area->channels; } } } static void true_decode(x3f_info_t *I, x3f_directory_entry_t *DE) { x3f_directory_entry_header_t *DEH = &DE->header; x3f_image_data_t *ID = &DEH->data_subsection.image_data; int color; for (color = 0; color < 3; color++) { true_decode_one_color(ID, color); } } /* Decode use the huffman tree */ static int32_t get_huffman_diff(bit_state_t *BS, x3f_hufftree_t *HTP) { int32_t diff; x3f_huffnode_t *node = &HTP->nodes[0]; while (node->branch[0] != NULL || node->branch[1] != NULL) { uint8_t bit = get_bit(BS); x3f_huffnode_t *new_node = node->branch[bit]; node = new_node; if (node == NULL) { /* TODO: Shouldn't this be treated as a fatal error? */ throw LIBRAW_EXCEPTION_IO_CORRUPT; return 0; } } diff = node->leaf; return diff; } static void huffman_decode_row(x3f_info_t *I, x3f_directory_entry_t *DE, int bits, int row, int offset, int *minimum) { x3f_directory_entry_header_t *DEH = &DE->header; x3f_image_data_t *ID = &DEH->data_subsection.image_data; x3f_huffman_t *HUF = ID->huffman; int16_t c[3] = {offset,offset,offset}; int col; bit_state_t BS; set_bit_state(&BS, (uint8_t*)ID->data + HUF->row_offsets.element[row]); for (col = 0; col < ID->columns; col++) { int color; for (color = 0; color < 3; color++) { uint16_t c_fix; c[color] += get_huffman_diff(&BS, &HUF->tree); if (c[color] < 0) { c_fix = 0; if (c[color] < *minimum) *minimum = c[color]; } else { c_fix = c[color]; } switch (ID->type_format) { case X3F_IMAGE_RAW_HUFFMAN_X530: case X3F_IMAGE_RAW_HUFFMAN_10BIT: HUF->x3rgb16.data[3*(row*ID->columns + col) + color] = (uint16_t)c_fix; break; case X3F_IMAGE_THUMB_HUFFMAN: HUF->rgb8.data[3*(row*ID->columns + col) + color] = (uint8_t)c_fix; break; default: /* TODO: Shouldn't this be treated as a fatal error? */ throw LIBRAW_EXCEPTION_IO_CORRUPT; } } } } static void huffman_decode(x3f_info_t *I, x3f_directory_entry_t *DE, int bits) { x3f_directory_entry_header_t *DEH = &DE->header; x3f_image_data_t *ID = &DEH->data_subsection.image_data; int row; int minimum = 0; int offset = legacy_offset; for (row = 0; row < ID->rows; row++) huffman_decode_row(I, DE, bits, row, offset, &minimum); if (auto_legacy_offset && minimum < 0) { offset = -minimum; for (row = 0; row < ID->rows; row++) huffman_decode_row(I, DE, bits, row, offset, &minimum); } } static int32_t get_simple_diff(x3f_huffman_t *HUF, uint16_t index) { if (HUF->mapping.size == 0) return index; else return HUF->mapping.element[index]; } static void simple_decode_row(x3f_info_t *I, x3f_directory_entry_t *DE, int bits, int row, int row_stride) { x3f_directory_entry_header_t *DEH = &DE->header; x3f_image_data_t *ID = &DEH->data_subsection.image_data; x3f_huffman_t *HUF = ID->huffman; uint32_t *data = (uint32_t *)((unsigned char*)ID->data + row*row_stride); uint16_t c[3] = {0,0,0}; int col; uint32_t mask = 0; switch (bits) { case 8: mask = 0x0ff; break; case 9: mask = 0x1ff; break; case 10: mask = 0x3ff; break; case 11: mask = 0x7ff; break; case 12: mask = 0xfff; break; default: mask = 0; /* TODO: Shouldn't this be treated as a fatal error? */ throw LIBRAW_EXCEPTION_IO_CORRUPT; break; } for (col = 0; col < ID->columns; col++) { int color; uint32_t val = data[col]; for (color = 0; color < 3; color++) { uint16_t c_fix; c[color] += get_simple_diff(HUF, (val>>(color*bits))&mask); switch (ID->type_format) { case X3F_IMAGE_RAW_HUFFMAN_X530: case X3F_IMAGE_RAW_HUFFMAN_10BIT: c_fix = (int16_t)c[color] > 0 ? c[color] : 0; HUF->x3rgb16.data[3*(row*ID->columns + col) + color] = c_fix; break; case X3F_IMAGE_THUMB_HUFFMAN: c_fix = (int8_t)c[color] > 0 ? c[color] : 0; HUF->rgb8.data[3*(row*ID->columns + col) + color] = c_fix; break; default: /* TODO: Shouldn't this be treated as a fatal error? */ throw LIBRAW_EXCEPTION_IO_CORRUPT; } } } } static void simple_decode(x3f_info_t *I, x3f_directory_entry_t *DE, int bits, int row_stride) { x3f_directory_entry_header_t *DEH = &DE->header; x3f_image_data_t *ID = &DEH->data_subsection.image_data; int row; for (row = 0; row < ID->rows; row++) simple_decode_row(I, DE, bits, row, row_stride); } /* --------------------------------------------------------------------- */ /* Loading the data in a directory entry */ /* --------------------------------------------------------------------- */ /* First you set the offset to where to start reading the data ... */ static void read_data_set_offset(x3f_info_t *I, x3f_directory_entry_t *DE, uint32_t header_size) { uint32_t i_off = DE->input.offset + header_size; I->input.file->seek(i_off, SEEK_SET); } /* ... then you read the data, block for block */ static uint32_t read_data_block(void **data, x3f_info_t *I, x3f_directory_entry_t *DE, uint32_t footer) { INT64 fpos = I->input.file->tell(); uint32_t size = DE->input.size + DE->input.offset - fpos - footer; if (fpos + size > I->input.file->size()) throw LIBRAW_EXCEPTION_IO_CORRUPT; *data = (void *)malloc(size); GETN(*data, size); return size; } static uint32_t data_block_size(void **data, x3f_info_t *I, x3f_directory_entry_t *DE, uint32_t footer) { uint32_t size = DE->input.size + DE->input.offset - I->input.file->tell() - footer; return size; } static void x3f_load_image_verbatim(x3f_info_t *I, x3f_directory_entry_t *DE) { x3f_directory_entry_header_t *DEH = &DE->header; x3f_image_data_t *ID = &DEH->data_subsection.image_data; if (!ID->data_size) ID->data_size = read_data_block(&ID->data, I, DE, 0); } static int32_t x3f_load_image_verbatim_size(x3f_info_t *I, x3f_directory_entry_t *DE) { x3f_directory_entry_header_t *DEH = &DE->header; x3f_image_data_t *ID = &DEH->data_subsection.image_data; return data_block_size(&ID->data, I, DE, 0); } static void x3f_load_property_list(x3f_info_t *I, x3f_directory_entry_t *DE) { x3f_directory_entry_header_t *DEH = &DE->header; x3f_property_list_t *PL = &DEH->data_subsection.property_list; int i; read_data_set_offset(I, DE, X3F_PROPERTY_LIST_HEADER_SIZE); GET_PROPERTY_TABLE(PL->property_table, PL->num_properties); if (!PL->data_size) PL->data_size = read_data_block(&PL->data, I, DE, 0); for (i=0; inum_properties; i++) { x3f_property_t *P = &PL->property_table.element[i]; P->name = ((utf16_t *)PL->data + P->name_offset); P->value = ((utf16_t *)PL->data + P->value_offset); P->name_utf8 = 0;// utf16le_to_utf8(P->name); P->value_utf8 = 0;//utf16le_to_utf8(P->value); } } static void x3f_load_true(x3f_info_t *I, x3f_directory_entry_t *DE) { x3f_directory_entry_header_t *DEH = &DE->header; x3f_image_data_t *ID = &DEH->data_subsection.image_data; x3f_true_t *TRU = new_true(&ID->tru); x3f_quattro_t *Q = NULL; int i; if (ID->type_format == X3F_IMAGE_RAW_QUATTRO || ID->type_format == X3F_IMAGE_RAW_SDQ || ID->type_format == X3F_IMAGE_RAW_SDQH || ID->type_format == X3F_IMAGE_RAW_SDQH2 ) { Q = new_quattro(&ID->quattro); for (i=0; iplane[i].columns); GET2(Q->plane[i].rows); } if (Q->plane[0].rows == ID->rows/2) { Q->quattro_layout = 1; } else if (Q->plane[0].rows == ID->rows) { Q->quattro_layout = 0; } else { throw LIBRAW_EXCEPTION_IO_CORRUPT; } } /* Read TRUE header data */ GET2(TRU->seed[0]); GET2(TRU->seed[1]); GET2(TRU->seed[2]); GET2(TRU->unknown); GET_TRUE_HUFF_TABLE(TRU->table); if (ID->type_format == X3F_IMAGE_RAW_QUATTRO ||ID->type_format == X3F_IMAGE_RAW_SDQ ||ID->type_format == X3F_IMAGE_RAW_SDQH ||ID->type_format == X3F_IMAGE_RAW_SDQH2 ) { GET4(Q->unknown); } GET_TABLE(TRU->plane_size, GET4, TRUE_PLANES,uint32_t); /* Read image data */ if (!ID->data_size) ID->data_size = read_data_block(&ID->data, I, DE, 0); /* TODO: can it be fewer than 8 bits? Maybe taken from TRU->table? */ new_huffman_tree(&TRU->tree, 8); populate_true_huffman_tree(&TRU->tree, &TRU->table); #ifdef DBG_PRNT print_huffman_tree(TRU->tree.nodes, 0, 0); #endif TRU->plane_address[0] = (uint8_t*)ID->data; for (i=1; iplane_address[i] = TRU->plane_address[i-1] + (((TRU->plane_size.element[i-1] + 15) / 16) * 16); if ( (ID->type_format == X3F_IMAGE_RAW_QUATTRO || ID->type_format == X3F_IMAGE_RAW_SDQ || ID->type_format == X3F_IMAGE_RAW_SDQH || ID->type_format == X3F_IMAGE_RAW_SDQH2 ) && Q->quattro_layout) { uint32_t columns = Q->plane[0].columns; uint32_t rows = Q->plane[0].rows; uint32_t channels = 3; uint32_t size = columns * rows * channels; TRU->x3rgb16.columns = columns; TRU->x3rgb16.rows = rows; TRU->x3rgb16.channels = channels; TRU->x3rgb16.row_stride = columns * channels; TRU->x3rgb16.buf = malloc(sizeof(uint16_t)*size); TRU->x3rgb16.data = (uint16_t *) TRU->x3rgb16.buf; columns = Q->plane[2].columns; rows = Q->plane[2].rows; channels = 1; size = columns * rows * channels; Q->top16.columns = columns; Q->top16.rows = rows; Q->top16.channels = channels; Q->top16.row_stride = columns * channels; Q->top16.buf = malloc(sizeof(uint16_t)*size); Q->top16.data = (uint16_t *)Q->top16.buf; } else { uint32_t size = ID->columns * ID->rows * 3; TRU->x3rgb16.columns = ID->columns; TRU->x3rgb16.rows = ID->rows; TRU->x3rgb16.channels = 3; TRU->x3rgb16.row_stride = ID->columns * 3; TRU->x3rgb16.buf =malloc(sizeof(uint16_t)*size); TRU->x3rgb16.data = (uint16_t *)TRU->x3rgb16.buf; } true_decode(I, DE); } static void x3f_load_huffman_compressed(x3f_info_t *I, x3f_directory_entry_t *DE, int bits, int use_map_table) { x3f_directory_entry_header_t *DEH = &DE->header; x3f_image_data_t *ID = &DEH->data_subsection.image_data; x3f_huffman_t *HUF = ID->huffman; int table_size = 1<rows * sizeof(HUF->row_offsets.element[0]); GET_TABLE(HUF->table, GET4, table_size,uint32_t); if (!ID->data_size) ID->data_size = read_data_block(&ID->data, I, DE, row_offsets_size); GET_TABLE(HUF->row_offsets, GET4, ID->rows,uint32_t); new_huffman_tree(&HUF->tree, bits); populate_huffman_tree(&HUF->tree, &HUF->table, &HUF->mapping); huffman_decode(I, DE, bits); } static void x3f_load_huffman_not_compressed(x3f_info_t *I, x3f_directory_entry_t *DE, int bits, int use_map_table, int row_stride) { x3f_directory_entry_header_t *DEH = &DE->header; x3f_image_data_t *ID = &DEH->data_subsection.image_data; if (!ID->data_size) ID->data_size = read_data_block(&ID->data, I, DE, 0); simple_decode(I, DE, bits, row_stride); } static void x3f_load_huffman(x3f_info_t *I, x3f_directory_entry_t *DE, int bits, int use_map_table, int row_stride) { x3f_directory_entry_header_t *DEH = &DE->header; x3f_image_data_t *ID = &DEH->data_subsection.image_data; x3f_huffman_t *HUF = new_huffman(&ID->huffman); uint32_t size; if (use_map_table) { int table_size = 1<mapping, GET2, table_size,uint16_t); } switch (ID->type_format) { case X3F_IMAGE_RAW_HUFFMAN_X530: case X3F_IMAGE_RAW_HUFFMAN_10BIT: size = ID->columns * ID->rows * 3; HUF->x3rgb16.columns = ID->columns; HUF->x3rgb16.rows = ID->rows; HUF->x3rgb16.channels = 3; HUF->x3rgb16.row_stride = ID->columns * 3; HUF->x3rgb16.buf = malloc(sizeof(uint16_t)*size); HUF->x3rgb16.data = (uint16_t *)HUF->x3rgb16.buf; break; case X3F_IMAGE_THUMB_HUFFMAN: size = ID->columns * ID->rows * 3; HUF->rgb8.columns = ID->columns; HUF->rgb8.rows = ID->rows; HUF->rgb8.channels = 3; HUF->rgb8.row_stride = ID->columns * 3; HUF->rgb8.buf = malloc(sizeof(uint8_t)*size); HUF->rgb8.data = (uint8_t *)HUF->rgb8.buf; break; default: /* TODO: Shouldn't this be treated as a fatal error? */ throw LIBRAW_EXCEPTION_IO_CORRUPT; } if (row_stride == 0) return x3f_load_huffman_compressed(I, DE, bits, use_map_table); else return x3f_load_huffman_not_compressed(I, DE, bits, use_map_table, row_stride); } static void x3f_load_pixmap(x3f_info_t *I, x3f_directory_entry_t *DE) { x3f_load_image_verbatim(I, DE); } static uint32_t x3f_load_pixmap_size(x3f_info_t *I, x3f_directory_entry_t *DE) { return x3f_load_image_verbatim_size(I, DE); } static void x3f_load_jpeg(x3f_info_t *I, x3f_directory_entry_t *DE) { x3f_load_image_verbatim(I, DE); } static uint32_t x3f_load_jpeg_size(x3f_info_t *I, x3f_directory_entry_t *DE) { return x3f_load_image_verbatim_size(I, DE); } static void x3f_load_image(x3f_info_t *I, x3f_directory_entry_t *DE) { x3f_directory_entry_header_t *DEH = &DE->header; x3f_image_data_t *ID = &DEH->data_subsection.image_data; read_data_set_offset(I, DE, X3F_IMAGE_HEADER_SIZE); switch (ID->type_format) { case X3F_IMAGE_RAW_TRUE: case X3F_IMAGE_RAW_MERRILL: case X3F_IMAGE_RAW_QUATTRO: case X3F_IMAGE_RAW_SDQ: case X3F_IMAGE_RAW_SDQH: case X3F_IMAGE_RAW_SDQH2: x3f_load_true(I, DE); break; case X3F_IMAGE_RAW_HUFFMAN_X530: case X3F_IMAGE_RAW_HUFFMAN_10BIT: x3f_load_huffman(I, DE, 10, 1, ID->row_stride); break; case X3F_IMAGE_THUMB_PLAIN: x3f_load_pixmap(I, DE); break; case X3F_IMAGE_THUMB_HUFFMAN: x3f_load_huffman(I, DE, 8, 0, ID->row_stride); break; case X3F_IMAGE_THUMB_JPEG: x3f_load_jpeg(I, DE); break; default: /* TODO: Shouldn't this be treated as a fatal error? */ throw LIBRAW_EXCEPTION_IO_CORRUPT; } } // Used only for thumbnail size estimation static uint32_t x3f_load_image_size(x3f_info_t *I, x3f_directory_entry_t *DE) { x3f_directory_entry_header_t *DEH = &DE->header; x3f_image_data_t *ID = &DEH->data_subsection.image_data; read_data_set_offset(I, DE, X3F_IMAGE_HEADER_SIZE); switch (ID->type_format) { case X3F_IMAGE_THUMB_PLAIN: return x3f_load_pixmap_size(I, DE); case X3F_IMAGE_THUMB_JPEG: return x3f_load_jpeg_size(I, DE); break; default: return 0; } } static void x3f_load_camf_decode_type2(x3f_camf_t *CAMF) { uint32_t key = CAMF->t2.crypt_key; int i; CAMF->decoded_data_size = CAMF->data_size; CAMF->decoded_data = malloc(CAMF->decoded_data_size); for (i=0; idata_size; i++) { uint8_t old, _new; uint32_t tmp; old = ((uint8_t *)CAMF->data)[i]; key = (key * 1597 + 51749) % 244944; tmp = (uint32_t)(key * ((int64_t)301593171) >> 24); _new = (uint8_t)(old ^ (uint8_t)(((((key << 8) - tmp) >> 1) + tmp) >> 17)); ((uint8_t *)CAMF->decoded_data)[i] = _new; } } /* NOTE: the unpacking in this code is in big respects identical to true_decode_one_color(). The difference is in the output you build. It might be possible to make some parts shared. NOTE ALSO: This means that the meta data is obfuscated using an image compression algorithm. */ static void camf_decode_type4(x3f_camf_t *CAMF) { uint32_t seed = CAMF->t4.decode_bias; int row; uint8_t *dst; uint32_t dst_size = CAMF->t4.decoded_data_size; uint8_t *dst_end; bool_t odd_dst = 0; x3f_hufftree_t *tree = &CAMF->tree; bit_state_t BS; int32_t row_start_acc[2][2]; uint32_t rows = CAMF->t4.block_count; uint32_t cols = CAMF->t4.block_size; CAMF->decoded_data_size = dst_size; CAMF->decoded_data = malloc(CAMF->decoded_data_size); memset(CAMF->decoded_data, 0, CAMF->decoded_data_size); dst = (uint8_t *)CAMF->decoded_data; dst_end = dst + dst_size; set_bit_state(&BS, CAMF->decoding_start); row_start_acc[0][0] = seed; row_start_acc[0][1] = seed; row_start_acc[1][0] = seed; row_start_acc[1][1] = seed; for (row = 0; row < rows; row++) { int col; bool_t odd_row = row&1; int32_t acc[2]; /* We loop through all the columns and the rows. But the actual data is smaller than that, so we break the loop when reaching the end. */ for (col = 0; col < cols; col++) { bool_t odd_col = col&1; int32_t diff = get_true_diff(&BS, tree); int32_t prev = col < 2 ? row_start_acc[odd_row][odd_col] : acc[odd_col]; int32_t value = prev + diff; acc[odd_col] = value; if (col < 2) row_start_acc[odd_row][odd_col] = value; switch(odd_dst) { case 0: *dst++ = (uint8_t)((value>>4)&0xff); if (dst >= dst_end) { goto ready; } *dst = (uint8_t)((value<<4)&0xf0); break; case 1: *dst++ |= (uint8_t)((value>>8)&0x0f); if (dst >= dst_end) { goto ready; } *dst++ = (uint8_t)((value<<0)&0xff); if (dst >= dst_end) { goto ready; } break; } odd_dst = !odd_dst; } /* end col */ } /* end row */ ready:; } static void x3f_load_camf_decode_type4(x3f_camf_t *CAMF) { int i; uint8_t *p; x3f_true_huffman_element_t *element = NULL; for (i=0, p = (uint8_t*)CAMF->data; *p != 0; i++) { /* TODO: Is this too expensive ??*/ element = (x3f_true_huffman_element_t *)realloc(element, (i+1)*sizeof(*element)); element[i].code_size = *p++; element[i].code = *p++; } CAMF->table.size = i; CAMF->table.element = element; /* TODO: where does the values 28 and 32 come from? */ #define CAMF_T4_DATA_SIZE_OFFSET 28 #define CAMF_T4_DATA_OFFSET 32 CAMF->decoding_size = *(uint32_t *)((unsigned char*)CAMF->data + CAMF_T4_DATA_SIZE_OFFSET); CAMF->decoding_start = (uint8_t *)CAMF->data + CAMF_T4_DATA_OFFSET; /* TODO: can it be fewer than 8 bits? Maybe taken from TRU->table? */ new_huffman_tree(&CAMF->tree, 8); populate_true_huffman_tree(&CAMF->tree, &CAMF->table); #ifdef DBG_PRNT print_huffman_tree(CAMF->tree.nodes, 0, 0); #endif camf_decode_type4(CAMF); } static void camf_decode_type5(x3f_camf_t *CAMF) { int32_t acc = CAMF->t5.decode_bias; uint8_t *dst; x3f_hufftree_t *tree = &CAMF->tree; bit_state_t BS; int32_t i; CAMF->decoded_data_size = CAMF->t5.decoded_data_size; CAMF->decoded_data = malloc(CAMF->decoded_data_size); dst = (uint8_t *)CAMF->decoded_data; set_bit_state(&BS, CAMF->decoding_start); for (i = 0; i < CAMF->decoded_data_size; i++) { int32_t diff = get_true_diff(&BS, tree); acc = acc + diff; *dst++ = (uint8_t)(acc & 0xff); } } static void x3f_load_camf_decode_type5(x3f_camf_t *CAMF) { int i; uint8_t *p; x3f_true_huffman_element_t *element = NULL; for (i=0, p = (uint8_t*)CAMF->data; *p != 0; i++) { /* TODO: Is this too expensive ??*/ element = (x3f_true_huffman_element_t *)realloc(element, (i+1)*sizeof(*element)); element[i].code_size = *p++; element[i].code = *p++; } CAMF->table.size = i; CAMF->table.element = element; /* TODO: where does the values 28 and 32 come from? */ #define CAMF_T5_DATA_SIZE_OFFSET 28 #define CAMF_T5_DATA_OFFSET 32 CAMF->decoding_size = *(uint32_t *)((uint8_t*)CAMF->data + CAMF_T5_DATA_SIZE_OFFSET); CAMF->decoding_start = (uint8_t *)CAMF->data + CAMF_T5_DATA_OFFSET; /* TODO: can it be fewer than 8 bits? Maybe taken from TRU->table? */ new_huffman_tree(&CAMF->tree, 8); populate_true_huffman_tree(&CAMF->tree, &CAMF->table); #ifdef DBG_PRNT print_huffman_tree(CAMF->tree.nodes, 0, 0); #endif camf_decode_type5(CAMF); } static void x3f_setup_camf_text_entry(camf_entry_t *entry) { entry->text_size = *(uint32_t *)entry->value_address; entry->text = (char*)entry->value_address + 4; } static void x3f_setup_camf_property_entry(camf_entry_t *entry) { int i; uint8_t *e = (uint8_t*)entry->entry; uint8_t *v = (uint8_t*)entry->value_address; uint32_t num = entry->property_num = *(uint32_t *)v; uint32_t off = *(uint32_t *)(v + 4); entry->property_name = (char **)malloc(num*sizeof(uint8_t*)); entry->property_value = (uint8_t **)malloc(num*sizeof(uint8_t*)); for (i=0; iproperty_name[i] = (char *)(e + name_off); entry->property_value[i] = e + value_off; } } static void set_matrix_element_info(uint32_t type, uint32_t *size, matrix_type_t *decoded_type) { switch (type) { case 0: *size = 2; *decoded_type = M_INT; /* known to be true */ break; case 1: *size = 4; *decoded_type = M_UINT; /* TODO: unknown ???? */ break; case 2: *size = 4; *decoded_type = M_UINT; /* TODO: unknown ???? */ break; case 3: *size = 4; *decoded_type = M_FLOAT; /* known to be true */ break; case 5: *size = 1; *decoded_type = M_UINT; /* TODO: unknown ???? */ break; case 6: *size = 2; *decoded_type = M_UINT; /* TODO: unknown ???? */ break; default: throw LIBRAW_EXCEPTION_IO_CORRUPT; } } static void get_matrix_copy(camf_entry_t *entry) { uint32_t element_size = entry->matrix_element_size; uint32_t elements = entry->matrix_elements; int i, size = (entry->matrix_decoded_type==M_FLOAT ? sizeof(double) : sizeof(uint32_t)) * elements; entry->matrix_decoded = malloc(size); switch (element_size) { case 4: switch (entry->matrix_decoded_type) { case M_INT: case M_UINT: memcpy(entry->matrix_decoded, entry->matrix_data, size); break; case M_FLOAT: for (i=0; imatrix_decoded)[i] = (double)((float *)entry->matrix_data)[i]; break; default: throw LIBRAW_EXCEPTION_IO_CORRUPT; } break; case 2: switch (entry->matrix_decoded_type) { case M_INT: for (i=0; imatrix_decoded)[i] = (int32_t)((int16_t *)entry->matrix_data)[i]; break; case M_UINT: for (i=0; imatrix_decoded)[i] = (uint32_t)((uint16_t *)entry->matrix_data)[i]; break; default: throw LIBRAW_EXCEPTION_IO_CORRUPT; } break; case 1: switch (entry->matrix_decoded_type) { case M_INT: for (i=0; imatrix_decoded)[i] = (int32_t)((int8_t *)entry->matrix_data)[i]; break; case M_UINT: for (i=0; imatrix_decoded)[i] = (uint32_t)((uint8_t *)entry->matrix_data)[i]; break; default: throw LIBRAW_EXCEPTION_IO_CORRUPT; } break; default: throw LIBRAW_EXCEPTION_IO_CORRUPT; } } static void x3f_setup_camf_matrix_entry(camf_entry_t *entry) { int i; int totalsize = 1; uint8_t *e = (uint8_t *)entry->entry; uint8_t *v = (uint8_t *)entry->value_address; uint32_t type = entry->matrix_type = *(uint32_t *)(v + 0); uint32_t dim = entry->matrix_dim = *(uint32_t *)(v + 4); uint32_t off = entry->matrix_data_off = *(uint32_t *)(v + 8); camf_dim_entry_t *dentry = entry->matrix_dim_entry = (camf_dim_entry_t*)malloc(dim*sizeof(camf_dim_entry_t)); for (i=0; imatrix_element_size, &entry->matrix_decoded_type); entry->matrix_data = (void *)(e + off); entry->matrix_elements = totalsize; entry->matrix_used_space = entry->entry_size - off; /* This estimate only works for matrices above a certain size */ entry->matrix_estimated_element_size = entry->matrix_used_space / totalsize; get_matrix_copy(entry); } static void x3f_setup_camf_entries(x3f_camf_t *CAMF) { uint8_t *p = (uint8_t *)CAMF->decoded_data; uint8_t *end = p + CAMF->decoded_data_size; camf_entry_t *entry = NULL; int i; for (i=0; p < end; i++) { uint32_t *p4 = (uint32_t *)p; switch (*p4) { case X3F_CMbP: case X3F_CMbT: case X3F_CMbM: break; default: goto stop; } /* TODO: lots of realloc - may be inefficient */ entry = (camf_entry_t *)realloc(entry, (i+1)*sizeof(camf_entry_t)); /* Pointer */ entry[i].entry = p; /* Header */ entry[i].id = *p4++; entry[i].version = *p4++; entry[i].entry_size = *p4++; entry[i].name_offset = *p4++; entry[i].value_offset = *p4++; /* Compute adresses and sizes */ entry[i].name_address = (char *)(p + entry[i].name_offset); entry[i].value_address = p + entry[i].value_offset; entry[i].name_size = entry[i].value_offset - entry[i].name_offset; entry[i].value_size = entry[i].entry_size - entry[i].value_offset; entry[i].text_size = 0; entry[i].text = NULL; entry[i].property_num = 0; entry[i].property_name = NULL; entry[i].property_value = NULL; entry[i].matrix_type = 0; entry[i].matrix_dim = 0; entry[i].matrix_data_off = 0; entry[i].matrix_data = NULL; entry[i].matrix_dim_entry = NULL; entry[i].matrix_decoded = NULL; switch (entry[i].id) { case X3F_CMbP: x3f_setup_camf_property_entry(&entry[i]); break; case X3F_CMbT: x3f_setup_camf_text_entry(&entry[i]); break; case X3F_CMbM: x3f_setup_camf_matrix_entry(&entry[i]); break; } p += entry[i].entry_size; } stop: CAMF->entry_table.size = i; CAMF->entry_table.element = entry; } static void x3f_load_camf(x3f_info_t *I, x3f_directory_entry_t *DE) { x3f_directory_entry_header_t *DEH = &DE->header; x3f_camf_t *CAMF = &DEH->data_subsection.camf; read_data_set_offset(I, DE, X3F_CAMF_HEADER_SIZE); if (!CAMF->data_size) CAMF->data_size = read_data_block(&CAMF->data, I, DE, 0); switch (CAMF->type) { case 2: /* Older SD9-SD14 */ x3f_load_camf_decode_type2(CAMF); break; case 4: /* TRUE ... Merrill */ x3f_load_camf_decode_type4(CAMF); break; case 5: /* Quattro ... */ x3f_load_camf_decode_type5(CAMF); break; default: /* TODO: Shouldn't this be treated as a fatal error? */ throw LIBRAW_EXCEPTION_IO_CORRUPT; } if (CAMF->decoded_data != NULL) x3f_setup_camf_entries(CAMF); else throw LIBRAW_EXCEPTION_IO_CORRUPT; } /* extern */ x3f_return_t x3f_load_data(x3f_t *x3f, x3f_directory_entry_t *DE) { x3f_info_t *I = &x3f->info; if (DE == NULL) return X3F_ARGUMENT_ERROR; switch (DE->header.identifier) { case X3F_SECp: x3f_load_property_list(I, DE); break; case X3F_SECi: x3f_load_image(I, DE); break; case X3F_SECc: x3f_load_camf(I, DE); break; default: return X3F_INTERNAL_ERROR; } return X3F_OK; } /* extern */ int64_t x3f_load_data_size(x3f_t *x3f, x3f_directory_entry_t *DE) { x3f_info_t *I = &x3f->info; if (DE == NULL) return -1; switch (DE->header.identifier) { case X3F_SECi: return x3f_load_image_size(I, DE); default: return 0; } } /* extern */ x3f_return_t x3f_load_image_block(x3f_t *x3f, x3f_directory_entry_t *DE) { x3f_info_t *I = &x3f->info; if (DE == NULL) return X3F_ARGUMENT_ERROR; switch (DE->header.identifier) { case X3F_SECi: read_data_set_offset(I, DE, X3F_IMAGE_HEADER_SIZE); x3f_load_image_verbatim(I, DE); break; default: throw LIBRAW_EXCEPTION_IO_CORRUPT; return X3F_INTERNAL_ERROR; } return X3F_OK; } /* --------------------------------------------------------------------- */ /* The End */ /* --------------------------------------------------------------------- */ LibRaw-0.18.8/internal/preprocess.pl000077500000000000000000000047441324423227700173500ustar00rootroot00000000000000#!/usr/bin/perl # File: preprocess.pl # Copyright 2008-2017 LibRaw LLC (info@libraw.org) # Created: Sat Mar 8, 2008 # LibRaw preprocessor for dcraw source # use strict; use Getopt::Std; my %opts; getopts('D:N',\%opts); my $tag = $opts{D}; my $nolines = $opts{N}; die 'use -DTAG option to specify tags, use __ALL__ tag to out all @out sections' unless $tag; process_file($_) foreach @ARGV; sub process_file { my $file = shift; return unless $file; open O,$file or die; my $lno = 0; my $out = 0; my $date = scalar localtime; print <) { $lno++; if ($line=~m|^\s*/\*\s*\@_emit\s+(.*)\*/\s*$|) { print "$1\n" if $out; next; } if ($line=~/^\s*(\/\/\s*\@out|\/\*\s*\@out)\s+(.*)/) { my @tags = split(/\s+/,$2); $out = 1 if $tag eq '__ALL__'; foreach my $t (@tags) { if ($t eq $tag) { $out = 1; print "#line ".($lno+1)." \"$file\"\n" unless $nolines; last; } } next; } if ($line=~/^\s*\/\/\s*\@end\s+(.*)/) { my @tags = split(/\s+/,$1); $out = 0 if $tag eq '__ALL__'; foreach my $t (@tags) { $out = 0 if $t eq $tag; } next; } if ($line=~/^\s*\@end\s+(.*)\*\/\s*$/) { my @tags = split(/\s+/,$1); $out = 0 if $tag eq '__ALL__'; foreach my $t (@tags) { $out = 0 if $t eq $tag; } next; } print $line if $out; } } LibRaw-0.18.8/internal/var_defines.h000066400000000000000000000221501324423227700172500ustar00rootroot00000000000000/* -*- C++ -*- * File: var_defines.h * Copyright 2008-2017 LibRaw LLC (info@libraw.org) * Created: Sat Mar 8, 2008 * * LibRaw redefinitions of dcraw internal variables LibRaw is free software; you can redistribute it and/or modify it under the terms of the one of two licenses as you choose: 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 (See file LICENSE.LGPL provided in LibRaw distribution archive for details). 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 (See file LICENSE.CDDL provided in LibRaw distribution archive for details). */ #ifndef VAR_DEFINES_H #define VAR_DEFINES_H // imgdata.idata #define make (imgdata.idata.make) #define model (imgdata.idata.model) #define software (imgdata.idata.software) #define is_raw (imgdata.idata.raw_count) #define dng_version (imgdata.idata.dng_version) #define is_foveon (imgdata.idata.is_foveon) #define colors (imgdata.idata.colors) #define cdesc (imgdata.idata.cdesc) #define filters (imgdata.idata.filters) #define xtrans (imgdata.idata.xtrans) #define xtrans_abs (imgdata.idata.xtrans_abs) #define xmpdata (imgdata.idata.xmpdata) #define xmplen (imgdata.idata.xmplen) //imgdata image #define image (imgdata.image) #define raw_image (imgdata.rawdata.raw_image) #define color_image (imgdata.rawdata.color_image) // imgdata.sizes #define raw_height (imgdata.sizes.raw_height) #define raw_width (imgdata.sizes.raw_width) #define raw_pitch (imgdata.sizes.raw_pitch) #define height (imgdata.sizes.height) #define width (imgdata.sizes.width) #define top_margin (imgdata.sizes.top_margin) #define left_margin (imgdata.sizes.left_margin) #define bottom_margin (imgdata.sizes.bottom_margin) #define right_margin (imgdata.sizes.right_margin) #define iheight (imgdata.sizes.iheight) #define iwidth (imgdata.sizes.iwidth) #define pixel_aspect (imgdata.sizes.pixel_aspect) #define flip (imgdata.sizes.flip) #define mask (imgdata.sizes.mask) //imgdata.color #define white (imgdata.color.white) #define cam_mul (imgdata.color.cam_mul) #define pre_mul (imgdata.color.pre_mul) #define cmatrix (imgdata.color.cmatrix) #define rgb_cam (imgdata.color.rgb_cam) #ifndef SRC_USES_CURVE #define curve (imgdata.color.curve) #endif #ifndef SRC_USES_BLACK #define black (imgdata.color.black) #define cblack (imgdata.color.cblack) #endif #define maximum (imgdata.color.maximum) #define channel_maximum (imgdata.color.channel_maximum) #define profile_length (imgdata.color.profile_length) #define color_flags (imgdata.color.color_flags) #define ph1 (imgdata.color.phase_one_data) #define flash_used (imgdata.color.flash_used) #define canon_ev (imgdata.color.canon_ev) #define model2 (imgdata.color.model2) #define baseline_exposure (imgdata.color.baseline_exposure) //imgdata.thumbnail #define thumb_width (imgdata.thumbnail.twidth) #define thumb_height (imgdata.thumbnail.theight) #define thumb_length (imgdata.thumbnail.tlength) //imgdata.others #define iso_speed (imgdata.other.iso_speed) #define shutter (imgdata.other.shutter) #define aperture (imgdata.other.aperture) #define focal_len (imgdata.other.focal_len) #define timestamp (imgdata.other.timestamp) #define shot_order (imgdata.other.shot_order) #define gpsdata (imgdata.other.gpsdata) #define desc (imgdata.other.desc) #define artist (imgdata.other.artist) //imgdata.output #define greybox (imgdata.params.greybox) #define cropbox (imgdata.params.cropbox) #define aber (imgdata.params.aber) #define gamm (imgdata.params.gamm) #define user_mul (imgdata.params.user_mul) #define shot_select (imgdata.params.shot_select) #define bright (imgdata.params.bright) #define threshold (imgdata.params.threshold) #define half_size (imgdata.params.half_size) #define four_color_rgb (imgdata.params.four_color_rgb) #define highlight (imgdata.params.highlight) //#define verbose (imgdata.params.verbose) #define use_auto_wb (imgdata.params.use_auto_wb) #define use_camera_wb (imgdata.params.use_camera_wb) #define use_camera_matrix (imgdata.params.use_camera_matrix) #define output_color (imgdata.params.output_color) #define output_bps (imgdata.params.output_bps) #define gamma_16bit (imgdata.params.gamma_16bit) #define output_tiff (imgdata.params.output_tiff) #define med_passes (imgdata.params.med_passes) #define no_auto_bright (imgdata.params.no_auto_bright) #define auto_bright_thr (imgdata.params.auto_bright_thr) #define use_fuji_rotate (imgdata.params.use_fuji_rotate) #define filtering_mode (imgdata.params.filtering_mode) // Demosaic packs //AFD //#define afd_noise_att (imgdata.params.afd_noise_att) //#define afd_noise_thres (imgdata.params.afd_noise_thres) //#define afd_luminance_passes (imgdata.params.afd_luminance_passes) //#define afd_chrominance_method (imgdata.params.afd_chrominance_method) //#define afd_luminance_only (imgdata.params.afd_luminance_only) // DCB #define dcb_iterations (imgdata.params.iterations) #define dcb_enhance_fl (imgdata.params.dcb_enhance) #define fbdd_noiserd (imgdata.params.fbdd_noiserd) // VCD #define eeci_refine (imgdata.params.eeci_refine) #define es_med_passes (imgdata.params.es_med_passes) //rgb_constants #define xyz_rgb (rgb_constants.xyz_rgb) #define d65_white (rgb_constants.d65_white) //libraw_internal_data.internal_data #define meta_data (libraw_internal_data.internal_data.meta_data) #define ifp libraw_internal_data.internal_data.input #define ifname ((char*)libraw_internal_data.internal_data.input->fname()) #define ofp libraw_internal_data.internal_data.output #define profile_offset (libraw_internal_data.internal_data.profile_offset) #define thumb_offset (libraw_internal_data.internal_data.toffset) #define pana_black (libraw_internal_data.internal_data.pana_black) //libraw_internal_data.internal_output_params #define mix_green (libraw_internal_data.internal_output_params.mix_green) #define raw_color (libraw_internal_data.internal_output_params.raw_color) #define use_gamma (libraw_internal_data.internal_output_params.use_gamma) #define zero_is_bad (libraw_internal_data.internal_output_params.zero_is_bad) #ifndef SRC_USES_SHRINK #define shrink (libraw_internal_data.internal_output_params.shrink) #endif #define fuji_width (libraw_internal_data.internal_output_params.fuji_width) //libraw_internal_data.output_data #define histogram (libraw_internal_data.output_data.histogram) #define oprof (libraw_internal_data.output_data.oprof) //libraw_internal_data.identify_data #define exif_cfa (libraw_internal_data.identify_data.olympus_exif_cfa) #define unique_id (libraw_internal_data.identify_data.unique_id) #define tiff_nifds (libraw_internal_data.identify_data.tiff_nifds) #define tiff_flip (libraw_internal_data.identify_data.tiff_flip) //libraw_internal_data.unpacker_data #define order (libraw_internal_data.unpacker_data.order) #define data_error (libraw_internal_data.unpacker_data.data_error) #define cr2_slice (libraw_internal_data.unpacker_data.cr2_slice) #define sraw_mul (libraw_internal_data.unpacker_data.sraw_mul) #define kodak_cbpp (libraw_internal_data.unpacker_data.kodak_cbpp) #define strip_offset (libraw_internal_data.unpacker_data.strip_offset) #define data_offset (libraw_internal_data.unpacker_data.data_offset) #define data_size (libraw_internal_data.unpacker_data.data_size) #define meta_offset (libraw_internal_data.unpacker_data.meta_offset) #define meta_length (libraw_internal_data.unpacker_data.meta_length) #define thumb_misc (libraw_internal_data.unpacker_data.thumb_misc) #define fuji_layout (libraw_internal_data.unpacker_data.fuji_layout) #define tiff_samples (libraw_internal_data.unpacker_data.tiff_samples) #define tiff_bps (libraw_internal_data.unpacker_data.tiff_bps) #define tiff_compress (libraw_internal_data.unpacker_data.tiff_compress) #define zero_after_ff (libraw_internal_data.unpacker_data.zero_after_ff) #define tile_width (libraw_internal_data.unpacker_data.tile_width) #define tile_length (libraw_internal_data.unpacker_data.tile_length) #define load_flags (libraw_internal_data.unpacker_data.load_flags) #ifdef LIBRAW_IO_REDEFINED #define fread(ptr,size,n,stream) stream->read(ptr,size,n) #define fseek(stream,o,w) stream->seek(o,w) #define fseeko(stream,o,w) stream->seek(o,w) #define ftell(stream) stream->tell() #define ftello(stream) stream->tell() #define feof(stream) stream->eof() #ifdef getc #undef getc #endif #define getc(stream) stream->get_char() #define fgetc(stream) stream->get_char() #define fgetcb(stream) stream->get_char_buf() #define fgets(str,n,stream) stream->gets(str,n) #define fscanf(stream,fmt,ptr) stream->scanf_one(fmt,ptr) #endif #endif LibRaw-0.18.8/internal/wf_filtering.cpp000066400000000000000000001272341324423227700200060ustar00rootroot00000000000000/* WF debanding code Copyright 2011 by Yan Vladimirovich Used in LibRaw with author permission. LibRaw is free software; you can redistribute it and/or modify it under the terms of the one of two licenses as you choose: 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 (See file LICENSE.LGPL provided in LibRaw distribution archive for details). 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 (See file LICENSE.CDDL provided in LibRaw distribution archive for details). */ #define P1 imgdata.idata #define S imgdata.sizes #define O imgdata.params #define C imgdata.color #define T imgdata.thumbnail #define IO libraw_internal_data.internal_output_params #define ID libraw_internal_data.internal_data int LibRaw::wf_remove_banding() { #define WF_IMGMODE_BAYER4PLANE 4 #define WF_IMGMODE_BAYER1PLANE 1 #define WF_GREENMODE_IND 0 #define WF_GREENMODE_GX_XG 1 #define WF_GREENMODE_XG_GX 2 #define WF_DEBANDING_OK 0 #define WF_DEBANDING_NOTBAYER2X2 1 #define WF_DEBANDING_TOOSMALL 2 #define WF_GAUSS_PIRAMID_SIZE 4 #define WF_MAXTRESHOLD 65536 #define WF_BAYERSRC(row, col, c) ((ushort(*)[4])imgdata.image)[((row) >> IO.shrink)*S.iwidth + ((col) >> IO.shrink)][c] #define WF_BAYERGAU(l, row, col) (gauss_pyramid[l])[((row) >> IO.shrink)*S.iwidth + ((col) >> IO.shrink)] #define WF_BAYERDFG(l, row, col) (difwg_pyramid[l])[((row) >> IO.shrink)*S.iwidth + ((col) >> IO.shrink)] #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define WF_i_1TO4 for(int i=0; i<4; i++) // too small? if (S.width<128 || S.height<128) return WF_DEBANDING_TOOSMALL; // is 2x2 bayer? int bayer2x2flag=-1; for(int row_shift=0; row_shift<=8; row_shift+=2) { for(int col_shift=0; col_shift<=8; col_shift+=2) { if ((FC(0,0)!=FC(row_shift, col_shift)) || (FC(1,0)!=FC(row_shift+1, col_shift)) || (FC(0,1)!=FC(row_shift, col_shift+1)) || (FC(1,1)!=FC(row_shift+1, col_shift+1))) { bayer2x2flag=0; } } } if (bayer2x2flag==0) return WF_DEBANDING_NOTBAYER2X2; int x_green_flag = -1; int width_d2, height_d2; int width_p1_d2, height_p1_d2; width_d2 = S.width/2; height_d2 = S.height/2; width_p1_d2 = (S.width+1)/2; height_p1_d2 = (S.height+1)/2; ushort val_max_c[4]={0,0,0,0}; ushort val_max; ushort dummy_pixel=0; ushort *dummy_line; dummy_line = (ushort*)calloc(S.width, sizeof(ushort)*4); for(int i=0; isrc_first && src[0]= (1 << 8)) { val_max_s >>= 8; data_shift -= 8; } if (val_max_s >= (1 << 4)) { val_max_s >>= 4; data_shift -= 4; } if (val_max_s >= (1 << 2)) { val_max_s >>= 2; data_shift -= 2; } if (val_max_s >= (1 << 1)) { data_shift -= 1; } data_mult = 1<src_first && src[0]src_first && src[0]>1,i&1)]; val_accepted = val_max-3*MAX(MAX(treshold[0],treshold[1]),MAX(treshold[2],treshold[3])); float (*tr_weight)[4]; tr_weight=(float(*)[4])calloc(WF_MAXTRESHOLD*4, sizeof(float)); WF_i_1TO4 treshold[i]*=data_mult; for(int v=0; vsrc_first && src[0]0) { banding_col[row_d2][i]=banding_col[row_d2][i]/banding_col_count[row_d2][i]; bsum[i]+=banding_col[row_d2][i]; } } WF_i_1TO4 bmean[i]=bsum[i]/(i<2?height_d2:height_p1_d2); for(int row_d2=0; row_d20) { banding_row[col_d2][i]=(banding_row[col_d2][i]/banding_row_count[col_d2][i]); bsum[i]+=banding_row[col_d2][i]; } } WF_i_1TO4 bmean[i]=bsum[i]/(i<2?width_d2:width_p1_d2); for(int col_d2=0; col_d20) banding_row_i[col_d2][i]=int(banding_row[col_d2][i]-bmean[i]); for(int row_d2=0; row_d2=val_accepted) { val_new[i]=*src[i]>>data_shift; } else { if (val_new[i]>val_max) val_new[i]=val_max; else if (val_new[i]<0) val_new[i]=0; val_new[i]>>=data_shift; } } WF_i_1TO4 *src[i]=val_new[i]; // Next 4 pixel or exit if (src[0]src_first && src[0]r2) { rmax=r1; rmin=r2; rmax_greenmode=r1_greenmode; rmin_greenmode=r2_greenmode; } else { rmax=r2; rmin=r1; rmax_greenmode=r2_greenmode; rmin_greenmode=r1_greenmode; } int rmin_x2_p1, rmax_x2_p1; rmin_x2_p1=rmin*2+1; rmax_x2_p1=rmax*2+1; double gau_kernel_rmin[WF_MAXFILTERSIZE]; double gau_kernel_rmax[WF_MAXFILTERSIZE]; for(int i=0; i0; j--) gau_kernel_rmin[j]=0.5*(gau_kernel_rmin[j]+gau_kernel_rmin[j-1]); } for(int i=0; i<=rmax_x2_p1; i++) gau_kernel_rmax[i]=gau_kernel_rmin[i]; for(int i=rmin_x2_p1+1; i<=rmax_x2_p1; i++) { for(int j=i; j>0; j--) gau_kernel_rmax[j]=0.5*(gau_kernel_rmax[j]+gau_kernel_rmax[j-1]); } double wmin_sum, wmax_sum, energy_sum; wmin_sum=0; wmax_sum=0; energy_sum=0; for(int row=-rmax*2-1; row<=rmax*2+1; row++) { for(int col=-rmax*2-1; col<=rmax*2+1; col++) { double wght_rmax=0; double wght_rmin=0; #define WF_WMAX(row, col) (((abs(row)<=rmax*2)&&(abs(col)<=rmax*2))?gau_kernel_rmax[abs(row)/2+rmax+1]*gau_kernel_rmax[abs(col)/2+rmax+1]:0) #define WF_WMIN(row, col) (((abs(row)<=rmin*2)&&(abs(col)<=rmin*2))?gau_kernel_rmin[abs(row)/2+rmin+1]*gau_kernel_rmin[abs(col)/2+rmin+1]:0) if ( ((row&1)==0) && ((col&1)==0)) { wght_rmax = WF_WMAX(row, col); wght_rmin = WF_WMIN(row, col); } if (rmax_greenmode) { if ( ((row&1)==0) && ((col&1)==0)) wght_rmax = 0.5*wght_rmax; else if ( ((row&1)==1) && ((col&1)==1)) { wght_rmax = 0.125*(WF_WMAX(row-1, col-1)+WF_WMAX(row-1, col+1)+WF_WMAX(row+1, col-1)+WF_WMAX(row+1, col+1)); } } if (rmin_greenmode) { if ( ((row&1)==0) && ((col&1)==0)) wght_rmin = 0.5*wght_rmin; else if ( ((row&1)==1) && ((col&1)==1)) { wght_rmin = 0.125*(WF_WMIN(row-1, col-1)+WF_WMIN(row-1, col+1)+WF_WMIN(row+1, col-1)+WF_WMIN(row+1, col+1)); } } wmin_sum+=wght_rmin; wmax_sum+=wght_rmax; energy_sum+=(wght_rmax-wght_rmin)*(wght_rmax-wght_rmin); } } return energy_sum; } void LibRaw::wf_bayer4_green_blur(int mode, void* src_image, int src_imgmode, void* dst_image, int dst_imgmode) { /* This function filters green (or any "diagonal") channel of bayer4 data with "X" kernel, 1 1 4 1 1 */ #define WF_BAYERSRC4(row, col, c) ((ushort(*)[4])src_image)[((row) >> IO.shrink)*S.iwidth + ((col) >> IO.shrink)][c] #define WF_BAYERSRC1(row, col) ((ushort*)src_image) [((row) >> IO.shrink)*S.iwidth + ((col) >> IO.shrink)] #define WF_BAYERDST4(row, col, c) ((ushort(*)[4])dst_image)[((row) >> IO.shrink)*S.iwidth + ((col) >> IO.shrink)][c] #define WF_BAYERDST1(row, col) ((ushort*)dst_image) [((row) >> IO.shrink)*S.iwidth + ((col) >> IO.shrink)] int green_mode; if ( imgdata.idata.cdesc[FC(0, 0)] == imgdata.idata.cdesc[FC(1, 1)] ) green_mode = WF_GREENMODE_GX_XG; else if ( imgdata.idata.cdesc[FC(0, 1)] == imgdata.idata.cdesc[FC(1, 0)] ) green_mode = WF_GREENMODE_XG_GX; else green_mode = WF_GREENMODE_IND; int src_h_shift, dst_h_shift, src_h_shift_x2; if (src_imgmode == WF_IMGMODE_BAYER1PLANE) src_h_shift = 2 >> IO.shrink; else if (src_imgmode == WF_IMGMODE_BAYER4PLANE) src_h_shift = 8 >> IO.shrink; src_h_shift_x2 = src_h_shift*2; if (dst_imgmode == WF_IMGMODE_BAYER1PLANE) dst_h_shift = 2 >> IO.shrink; else if (dst_imgmode == WF_IMGMODE_BAYER4PLANE) dst_h_shift = 8 >> IO.shrink; int row, col; long int *line_filtered; line_filtered = (long int*) calloc(S.width, sizeof(*line_filtered)); ushort *src, *src_c, *src_u1, *src_u2, *src_d1, *src_d2, *dst_c, *src_ca, *dst_ca, *dst_rb; int start_col, start_col_left, row_up, row_dn; if ( green_mode != WF_GREENMODE_IND) { for(row=0; row0) { if ( green_mode == WF_GREENMODE_GX_XG ) start_col = ( row+1 ) & 1; else start_col = row & 1; switch (dst_imgmode) { case WF_IMGMODE_BAYER1PLANE: dst_c = &WF_BAYERDST1(row-1, start_col); break; case WF_IMGMODE_BAYER4PLANE: dst_c = &WF_BAYERDST4(row-1, start_col, FC(row-1, start_col)); break; } for (col=start_col; col>3; dst_c+=dst_h_shift; } if (src_image != dst_image) { // copy red or blue channel if ( green_mode == WF_GREENMODE_GX_XG ) start_col = row & 1; else start_col = (row+1) & 1; switch (src_imgmode) { case WF_IMGMODE_BAYER1PLANE: src = &WF_BAYERSRC1(row-1, start_col); break; case WF_IMGMODE_BAYER4PLANE: src = &WF_BAYERSRC4(row-1, start_col, FC(row-1, start_col)); break; } switch (dst_imgmode) { case WF_IMGMODE_BAYER1PLANE: dst_rb = &WF_BAYERDST1(row-1, start_col); break; case WF_IMGMODE_BAYER4PLANE: dst_rb = &WF_BAYERDST4(row-1, start_col, FC(row-1, start_col)); break; } for (col=start_col; col>3; dst_c+=dst_h_shift; } if (src_image != dst_image) { // copy red or blue channel if ( green_mode == WF_GREENMODE_GX_XG ) start_col = row & 1; else start_col = (row+1) & 1; switch (src_imgmode) { case WF_IMGMODE_BAYER1PLANE: src = &WF_BAYERSRC1(row-1, start_col); break; case WF_IMGMODE_BAYER4PLANE: src = &WF_BAYERSRC4(row-1, start_col, FC(row-1, start_col)); break; } switch (dst_imgmode) { case WF_IMGMODE_BAYER1PLANE: dst_rb = &WF_BAYERDST1(row-1, start_col); break; case WF_IMGMODE_BAYER4PLANE: dst_rb = &WF_BAYERDST4(row-1, start_col, FC(row-1, start_col)); break; } for (col=start_col; col> IO.shrink)*S.iwidth + ((col) >> IO.shrink)][c] #define WF_BAYERSRC1(row, col) ((ushort*)src_image) [((row) >> IO.shrink)*S.iwidth + ((col) >> IO.shrink)] #define WF_BAYERDST4(row, col, c) ((ushort(*)[4])dst_image)[((row) >> IO.shrink)*S.iwidth + ((col) >> IO.shrink)][c] #define WF_BAYERDST1(row, col) ((ushort*)dst_image) [((row) >> IO.shrink)*S.iwidth + ((col) >> IO.shrink)] if (radius <= 0 || radius > 8) return; long int (*line_filtered)[4]; long int gauss_conv_kernel[9][4]; long int gauss_conv_kernel_c[8][9] = { {32768, 16384}, {24576, 16384, 4096}, {20480, 15360, 6144, 1024}, {17920, 14336, 7168, 2048, 256}, {16128, 13440, 7680, 2880, 640, 64}, {14784, 12672, 7920, 3520, 1056, 192, 16}, {13728, 12012, 8008, 4004, 1456, 364, 56, 4}, {12870, 11440, 8008, 4368, 1820, 560, 120, 16, 1}, }; int line_memory_len = (MAX(S.height, S.width)+1)/2+radius*2+1; line_filtered = (long int(*)[4]) calloc(line_memory_len, sizeof(long int[4])); int src_h_shift, src_v_shift; int dst_h_shift, dst_v_shift; if (src_imgmode == WF_IMGMODE_BAYER1PLANE) src_h_shift = 2 >> IO.shrink; else if (src_imgmode == WF_IMGMODE_BAYER4PLANE) src_h_shift = 8 >> IO.shrink; src_v_shift = S.width*src_h_shift; if (dst_imgmode == WF_IMGMODE_BAYER1PLANE) dst_h_shift = 2 >> IO.shrink; else if (dst_imgmode == WF_IMGMODE_BAYER4PLANE) dst_h_shift = 8 >> IO.shrink; dst_v_shift = S.width*dst_h_shift; int width_d2 = S.width / 2; int height_d2 = S.height / 2; int i, j; for (j=0; j<=radius; j++) { for (i=0; i<4; i++) { gauss_conv_kernel[j][i] = gauss_conv_kernel_c[radius-1][j]; } } int row, col; int rowf, colf; ushort *src [4], *dst[4]; long int src_c[4]; // Horizontal int right_edge[4]; for (i=0; i<4; i++) { int padding = i<2 && (S.width & 1) ? 1 : 0; right_edge[i]=width_d2 + radius + padding; } for(row=0; row>16; dst[i]+=dst_h_shift; } colf++; } if (col == S.width-1) { for(i=0; i<2; i++) *dst[i]=line_filtered[colf][i]>>16; } } // Vertical int lower_edge[4]; for (i=0; i<4; i++) { int padding = i<2 && (S.height & 1 ) ? 1 : 0; lower_edge[i]=height_d2 + radius + padding; } for(col=0; col>16; dst[i]+=dst_v_shift; } rowf++; } if (row == S.height-1) { for(i=0; i<2; i++) *dst[i]=line_filtered[rowf][i]>>16; } } free(line_filtered); } void LibRaw::wf_bayer4_block_filter(int* radius_list, void* src_image, int src_imgmode, void* dst_image, int dst_imgmode) { #define WF_BLOCKFILTER_MAXF 8 #define WF_BAYERSRC4(row,col,c) ((ushort(*)[4])src_image)[((row) >> IO.shrink)*S.iwidth + ((col) >> IO.shrink)][c] #define WF_BAYERSRC1(row,col) ((ushort*)src_image) [((row) >> IO.shrink)*S.iwidth + ((col) >> IO.shrink)] #define WF_BAYERDST4(row,col,c) ((ushort(*)[4])dst_image)[((row) >> IO.shrink)*S.iwidth + ((col) >> IO.shrink)][c] #define WF_BAYERDST1(row,col) ((ushort*)dst_image) [((row) >> IO.shrink)*S.iwidth + ((col) >> IO.shrink)] int filter_itrtns_num = 0; int block_radius [WF_BLOCKFILTER_MAXF]; int block_radius_x2 [WF_BLOCKFILTER_MAXF]; int block_radius_x2_p1[WF_BLOCKFILTER_MAXF]; int block_radius_max = 0; int block_radius_max_x2; int block_radius_max_x2_p1; for(int i=0; (i> IO.shrink; else if (src_imgmode == WF_IMGMODE_BAYER4PLANE) src_h_shift = 8 >> IO.shrink; src_v_shift = S.width*src_h_shift; if (dst_imgmode == WF_IMGMODE_BAYER1PLANE) dst_h_shift = 2 >> IO.shrink; else if (dst_imgmode == WF_IMGMODE_BAYER4PLANE) dst_h_shift = 8 >> IO.shrink; dst_v_shift = S.width*dst_h_shift; int width_d2 = S.width / 2; int height_d2 = S.height / 2; int width_p1_d2 = (S.width+1) / 2; int height_p1_d2 = (S.height+1) / 2; ushort *src[4], *dst[4]; long int (*src_plus)[4], (*src_minus)[4]; long int block_sum[4]; int row, col; int right_edge[4], lower_edge[4]; for(row=0; row #include #include #include #include "libraw_datastream.h" #include "libraw_types.h" #include "libraw_const.h" #include "libraw_internal.h" #include "libraw_alloc.h" #ifdef __cplusplus extern "C" { #endif DllDef const char *libraw_strerror(int errorcode); DllDef const char *libraw_strprogress(enum LibRaw_progress); /* LibRaw C API */ DllDef libraw_data_t *libraw_init(unsigned int flags); DllDef int libraw_open_file(libraw_data_t*, const char *); DllDef int libraw_open_file_ex(libraw_data_t*, const char *, INT64 max_buff_sz); #if defined(_WIN32) && !defined(__MINGW32__) && defined(_MSC_VER) && (_MSC_VER > 1310) DllDef int libraw_open_wfile(libraw_data_t*, const wchar_t *); DllDef int libraw_open_wfile_ex(libraw_data_t*, const wchar_t *, INT64 max_buff_sz); #endif DllDef int libraw_open_buffer(libraw_data_t*, void * buffer, size_t size); DllDef int libraw_unpack(libraw_data_t*); DllDef int libraw_unpack_thumb(libraw_data_t*); DllDef void libraw_recycle_datastream(libraw_data_t*); DllDef void libraw_recycle(libraw_data_t*); DllDef void libraw_close(libraw_data_t*); DllDef void libraw_subtract_black(libraw_data_t*); DllDef int libraw_raw2image(libraw_data_t*); DllDef void libraw_free_image(libraw_data_t*); /* version helpers */ DllDef const char* libraw_version(); DllDef int libraw_versionNumber(); /* Camera list */ DllDef const char** libraw_cameraList(); DllDef int libraw_cameraCount(); /* helpers */ DllDef void libraw_set_memerror_handler(libraw_data_t*, memory_callback cb, void *datap); DllDef void libraw_set_exifparser_handler(libraw_data_t*, exif_parser_callback cb, void *datap); DllDef void libraw_set_dataerror_handler(libraw_data_t*,data_callback func,void *datap); DllDef void libraw_set_progress_handler(libraw_data_t*,progress_callback cb,void *datap); DllDef const char * libraw_unpack_function_name(libraw_data_t* lr); DllDef int libraw_get_decoder_info(libraw_data_t* lr,libraw_decoder_info_t* d); DllDef int libraw_COLOR(libraw_data_t*,int row, int col); DllDef unsigned libraw_capabilities(); /* DCRAW compatibility */ DllDef int libraw_adjust_sizes_info_only(libraw_data_t*); DllDef int libraw_dcraw_ppm_tiff_writer(libraw_data_t* lr,const char *filename); DllDef int libraw_dcraw_thumb_writer(libraw_data_t* lr,const char *fname); DllDef int libraw_dcraw_process(libraw_data_t* lr); DllDef libraw_processed_image_t* libraw_dcraw_make_mem_image(libraw_data_t* lr, int *errc); DllDef libraw_processed_image_t* libraw_dcraw_make_mem_thumb(libraw_data_t* lr, int *errc); DllDef void libraw_dcraw_clear_mem(libraw_processed_image_t*); /* getters/setters used by 3DLut Creator */ DllDef void libraw_set_demosaic(libraw_data_t *lr,int value); DllDef void libraw_set_output_color(libraw_data_t *lr,int value); DllDef void libraw_set_user_mul(libraw_data_t *lr,int index, float val); DllDef void libraw_set_output_bps(libraw_data_t *lr,int value); DllDef void libraw_set_gamma(libraw_data_t *lr,int index, float value); DllDef void libraw_set_no_auto_bright(libraw_data_t *lr,int value); DllDef void libraw_set_bright(libraw_data_t *lr,float value); DllDef void libraw_set_highlight(libraw_data_t *lr,int value); DllDef void libraw_set_fbdd_noiserd(libraw_data_t *lr,int value); DllDef int libraw_get_raw_height(libraw_data_t *lr); DllDef int libraw_get_raw_width(libraw_data_t *lr); DllDef int libraw_get_iheight(libraw_data_t *lr); DllDef int libraw_get_iwidth(libraw_data_t *lr); DllDef float libraw_get_cam_mul(libraw_data_t *lr,int index); DllDef float libraw_get_pre_mul(libraw_data_t *lr,int index); DllDef float libraw_get_rgb_cam(libraw_data_t *lr,int index1, int index2); DllDef int libraw_get_color_maximum(libraw_data_t *lr); DllDef void libraw_set_ca_correction(libraw_data_t *lr,int ca_correc, float ca_red, float ca_blue); DllDef void libraw_set_cfalinenoise(libraw_data_t *lr,int cfaline, float linenoise); DllDef void libraw_set_wf_debanding(libraw_data_t *lr, int wf_debanding, float wfd0, float wfd1, float wfd2, float wfd3); DllDef void libraw_set_interpolation_passes(libraw_data_t *lr,int passes); #ifdef __cplusplus } #endif #ifdef __cplusplus class DllDef LibRaw { public: libraw_data_t imgdata; int verbose; LibRaw(unsigned int flags = LIBRAW_OPTIONS_NONE); libraw_output_params_t* output_params_ptr() { return &imgdata.params;} int open_file(const char *fname, INT64 max_buffered_sz=LIBRAW_USE_STREAMS_DATASTREAM_MAXSIZE); #if defined(_WIN32) && !defined(__MINGW32__) && defined(_MSC_VER) && (_MSC_VER > 1310) int open_file(const wchar_t *fname, INT64 max_buffered_sz=LIBRAW_USE_STREAMS_DATASTREAM_MAXSIZE); #endif int open_buffer(void *buffer, size_t size); virtual int open_datastream(LibRaw_abstract_datastream *); int error_count(){return libraw_internal_data.unpacker_data.data_error;} void recycle_datastream(); int unpack(void); int unpack_thumb(void); int thumbOK(INT64 maxsz=-1); int adjust_sizes_info_only(void); int subtract_black(); int subtract_black_internal(); int raw2image(); int raw2image_ex(int do_subtract_black); void raw2image_start(); void free_image(); int adjust_maximum(); void set_exifparser_handler( exif_parser_callback cb,void *data) {callbacks.exifparser_data = data; callbacks.exif_cb = cb; } void set_memerror_handler( memory_callback cb,void *data) {callbacks.memcb_data = data; callbacks.mem_cb = cb; } void set_dataerror_handler(data_callback func, void *data) { callbacks.datacb_data = data; callbacks.data_cb = func;} void set_progress_handler(progress_callback pcb, void *data) { callbacks.progresscb_data = data; callbacks.progress_cb = pcb;} void convertFloatToInt(float dmin=4096.f, float dmax=32767.f, float dtarget = 16383.f); /* helpers */ static unsigned capabilities(); static const char* version(); static int versionNumber(); static const char** cameraList(); static int cameraCount(); static const char* strprogress(enum LibRaw_progress); static const char* strerror(int p); /* dcraw emulation */ int dcraw_ppm_tiff_writer(const char *filename); int dcraw_thumb_writer(const char *fname); int dcraw_process(void); /* information calls */ int is_fuji_rotated(){return libraw_internal_data.internal_output_params.fuji_width;} int is_sraw(); int sraw_midpoint(); int is_nikon_sraw(); int is_coolscan_nef(); int is_floating_point(); int have_fpdata(); /* memory writers */ virtual libraw_processed_image_t* dcraw_make_mem_image(int *errcode=NULL); virtual libraw_processed_image_t* dcraw_make_mem_thumb(int *errcode=NULL); static void dcraw_clear_mem(libraw_processed_image_t*); /* Additional calls for make_mem_image */ void get_mem_image_format(int* width, int* height, int* colors, int* bps) const; int copy_mem_image(void* scan0, int stride, int bgr); /* free all internal data structures */ void recycle(); virtual ~LibRaw(void); int COLOR(int row, int col) { return libraw_internal_data.internal_output_params.fuji_width? FCF(row,col):FC(row,col);} int FC(int row,int col) { return (imgdata.idata.filters >> (((row << 1 & 14) | (col & 1)) << 1) & 3);} int fcol (int row, int col); const char *unpack_function_name(); virtual int get_decoder_info(libraw_decoder_info_t* d_info); libraw_internal_data_t * get_internal_data_pointer(){ return &libraw_internal_data; } /* Debanding filter */ int wf_remove_banding(); /* Phase one correction/subtractBL calls */ /* Returns libraw error code */ int phase_one_subtract_black(ushort *src, ushort *dest); int phase_one_correct(); int set_rawspeed_camerafile(char *filename); virtual void setCancelFlag(); virtual void clearCancelFlag(); virtual void adobe_coeff (const char *, const char *, int internal_only=0); void set_dng_host(void *); protected: int is_curve_linear(); void checkCancel(); void cam_xyz_coeff(float _rgb_cam[3][4], double cam_xyz[4][3]); void phase_one_allocate_tempbuffer(); void phase_one_free_tempbuffer(); virtual int is_phaseone_compressed(); virtual int is_canon_600(); /* Hotspots */ virtual void copy_fuji_uncropped(unsigned short cblack[4], unsigned short *dmaxp); virtual void copy_bayer(unsigned short cblack[4], unsigned short *dmaxp); virtual void fuji_rotate(); virtual void convert_to_rgb_loop(float out_cam[3][4]); virtual void lin_interpolate_loop(int code[16][16][32],int size); virtual void scale_colors_loop(float scale_mul[4]); /* Fujifilm compressed decoder public interface (to make parallel decoder) */ virtual void xtrans_decode_loop(const struct xtrans_params* common_info, int count, INT64* offsets, unsigned *sizes); void xtrans_decode_strip(const struct xtrans_params* info_common, int cur_block, INT64 raw_offset, unsigned size); int FCF(int row,int col) { int rr,cc; if (libraw_internal_data.unpacker_data.fuji_layout) { rr = libraw_internal_data.internal_output_params.fuji_width - 1 - col + (row >> 1); cc = col + ((row+1) >> 1); } else { rr = libraw_internal_data.internal_output_params.fuji_width - 1 + row - (col >> 1); cc = row + ((col+1) >> 1); } return FC(rr,cc); } void adjust_bl(); void* malloc(size_t t); void* calloc(size_t n,size_t t); void* realloc(void *p, size_t s); void free(void *p); void merror (void *ptr, const char *where); void derror(); LibRaw_TLS *tls; libraw_internal_data_t libraw_internal_data; decode first_decode[2048], *second_decode, *free_decode; tiff_ifd_t tiff_ifd[10]; libraw_memmgr memmgr; libraw_callbacks_t callbacks; LibRaw_constants rgb_constants; void (LibRaw:: *write_thumb)(); void (LibRaw:: *write_fun)(); void (LibRaw:: *load_raw)(); void (LibRaw:: *thumb_load_raw)(); void (LibRaw:: *pentax_component_load_raw)(); void (LibRaw:: *interpolate_bayer)(); void (LibRaw:: *interpolate_xtrans)(); void kodak_thumb_loader(); void write_thumb_ppm_tiff(FILE *); void x3f_thumb_loader(); INT64 x3f_thumb_size(); #ifdef LIBRAW_DEMOSAIC_PACK_GPL2 void foveon_thumb_loader (void); #endif int own_filtering_supported(){ return 0;} void identify(); unsigned parse_custom_cameras(unsigned limit, libraw_custom_camera_t table[], char** list); void write_ppm_tiff (); void convert_to_rgb(); void remove_zeroes(); void crop_masked_pixels(); #ifndef NO_LCMS void apply_profile(const char*,const char*); #endif void pre_interpolate(); void border_interpolate (int border); void lin_interpolate(); void vng_interpolate(); void ppg_interpolate(); void cielab(ushort rgb[3], short lab[3]); void xtrans_interpolate(int); void ahd_interpolate(); void dht_interpolate(); void aahd_interpolate(); /* from demosaic pack */ void ahd_interpolate_mod(); void afd_interpolate_pl(int afd_passes, int clip_on); void afd_noise_filter_pl(); void lmmse_interpolate(int gamma_apply); void dcb(int iterations, int dcb_enhance); void fbdd(int noiserd); void vcd_interpolate(int ahd_cutoff); void amaze_demosaic_RT(); void exp_bef(float expos, float preser); void CA_correct_RT(float cared, float cablue); void cfa_linedn(float linenoise); void cfa_impulse_gauss(float lclean, float cclean); void green_equilibrate(float thresh); /* demosaic pack end */ void bad_pixels(const char*); void subtract(const char*); void hat_transform (float *temp, float *base, int st, int size, int sc); void wavelet_denoise(); void scale_colors(); void median_filter (); void blend_highlights(); void recover_highlights(); void green_matching(); void stretch(); #ifdef LIBRAW_DEMOSAIC_PACK_GPL2 void foveon_thumb (); #endif void jpeg_thumb_writer (FILE *tfp,char *thumb,int thumb_length); void jpeg_thumb (); void ppm_thumb (); void ppm16_thumb(); void layer_thumb (); void rollei_thumb (); void kodak_thumb_load_raw(); #ifdef LIBRAW_DEMOSAIC_PACK_GPL2 void foveon_decoder (unsigned size, unsigned code); #endif unsigned get4(); int flip_index (int row, int col); void gamma_curve (double pwr, double ts, int mode, int imax); void cubic_spline (const int *x_, const int *y_, const int len); /* RawSpeed data */ void *_rawspeed_camerameta; void *_rawspeed_decoder; void fix_after_rawspeed(int bl); int try_rawspeed(); /* returns LIBRAW_SUCCESS on success */ /* Fast cancel flag */ long _exitflag; /* DNG SDK data */ void *dnghost; int valid_for_dngsdk(); int try_dngsdk(); /* X3F data */ void *_x3f_data; int raw_was_read() { return imgdata.rawdata.raw_image || imgdata.rawdata.color4_image || imgdata.rawdata.color3_image || imgdata.rawdata.float_image || imgdata.rawdata.float3_image || imgdata.rawdata.float4_image; } #ifdef LIBRAW_LIBRARY_BUILD #include "internal/libraw_internal_funcs.h" #endif }; #ifdef LIBRAW_LIBRARY_BUILD #define RUN_CALLBACK(stage,iter,expect) if(callbacks.progress_cb) { \ int rr = (*callbacks.progress_cb)(callbacks.progresscb_data,stage,iter,expect); \ if(rr!=0) throw LIBRAW_EXCEPTION_CANCELLED_BY_CALLBACK; \ } #endif #endif /* __cplusplus */ #endif /* _LIBRAW_CLASS_H */ LibRaw-0.18.8/libraw/libraw_alloc.h000066400000000000000000000041141324423227700170610ustar00rootroot00000000000000/* -*- C++ -*- * File: libraw_alloc.h * Copyright 2008-2017 LibRaw LLC (info@libraw.org) * Created: Sat Mar 22, 2008 * * LibRaw C++ interface * LibRaw is free software; you can redistribute it and/or modify it under the terms of the one of two licenses as you choose: 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 (See file LICENSE.LGPL provided in LibRaw distribution archive for details). 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 (See file LICENSE.CDDL provided in LibRaw distribution archive for details). */ #ifndef __LIBRAW_ALLOC_H #define __LIBRAW_ALLOC_H #include #include #ifdef __cplusplus #define LIBRAW_MSIZE 64 class DllDef libraw_memmgr { public: libraw_memmgr() { memset(mems,0,sizeof(mems)); calloc_cnt=0; } void *malloc(size_t sz) { void *ptr = ::malloc(sz); mem_ptr(ptr); return ptr; } void *calloc(size_t n, size_t sz) { void *ptr = ::calloc(n,sz); mem_ptr(ptr); return ptr; } void *realloc(void *ptr,size_t newsz) { void *ret = ::realloc(ptr,newsz); forget_ptr(ptr); mem_ptr(ret); return ret; } void free(void *ptr) { forget_ptr(ptr); ::free(ptr); } void cleanup(void) { for(int i = 0; i< LIBRAW_MSIZE; i++) if(mems[i]) { free(mems[i]); mems[i] = NULL; } } private: void *mems[LIBRAW_MSIZE]; int calloc_cnt; void mem_ptr(void *ptr) { if(ptr) for(int i=0;i < LIBRAW_MSIZE; i++) if(!mems[i]) { mems[i] = ptr; break; } } void forget_ptr(void *ptr) { if(ptr) for(int i=0;i < LIBRAW_MSIZE; i++) if(mems[i] == ptr) mems[i] = NULL; } }; #endif /* C++ */ #endif LibRaw-0.18.8/libraw/libraw_const.h000066400000000000000000000203761324423227700171250ustar00rootroot00000000000000/* -*- C++ -*- * File: libraw_const.h * Copyright 2008-2017 LibRaw LLC (info@libraw.org) * Created: Sat Mar 8 , 2008 * LibRaw error codes LibRaw is free software; you can redistribute it and/or modify it under the terms of the one of two licenses as you choose: 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 (See file LICENSE.LGPL provided in LibRaw distribution archive for details). 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 (See file LICENSE.CDDL provided in LibRaw distribution archive for details). */ #ifndef _LIBRAW_ERRORS_H #define _LIBRAW_ERRORS_H #define LIBRAW_DEFAULT_ADJUST_MAXIMUM_THRESHOLD 0.75 #define LIBRAW_DEFAULT_AUTO_BRIGHTNESS_THRESHOLD 0.01 /* limit allocation size, default is 2Gb */ #ifndef LIBRAW_MAX_ALLOC_MB #define LIBRAW_MAX_ALLOC_MB 2048L #endif enum LibRaw_whitebalance_code { /* EXIF light sources 12 = FL-D; Daylight fluorescent (D 5700K – 7100K) (F1,F5) 13 = FL-N; Day white fluorescent (N 4600K – 5400K) (F7,F8) 14 = FL-W; Cool white fluorescent (W 3900K – 4500K) (F2,F6, office, store, warehouse) 15 = FL-WW; White fluorescent (WW 3200K – 3700K) (F3, residential) 16 = FL-L; Soft/Warm white fluorescent (L 2600K - 3250K) (F4, kitchen, bath) */ LIBRAW_WBI_Unknown=0, LIBRAW_WBI_Daylight=1, LIBRAW_WBI_Fluorescent=2, LIBRAW_WBI_Tungsten=3, LIBRAW_WBI_Flash=4, LIBRAW_WBI_FineWeather=9, LIBRAW_WBI_Cloudy=10, LIBRAW_WBI_Shade=11, LIBRAW_WBI_FL_D=12, LIBRAW_WBI_FL_N=13, LIBRAW_WBI_FL_W=14, LIBRAW_WBI_FL_WW=15, LIBRAW_WBI_FL_L=16, LIBRAW_WBI_Ill_A=17, LIBRAW_WBI_Ill_B=18, LIBRAW_WBI_Ill_C=19, LIBRAW_WBI_D55=20, LIBRAW_WBI_D65=21, LIBRAW_WBI_D75=22, LIBRAW_WBI_D50=23, LIBRAW_WBI_StudioTungsten=24, LIBRAW_WBI_Sunset=64, LIBRAW_WBI_Other=255 }; enum LibRaw_dng_processing { LIBRAW_DNG_NONE=0, LIBRAW_DNG_FLOAT=1, LIBRAW_DNG_LINEAR=2, LIBRAW_DNG_DEFLATE=4, LIBRAW_DNG_XTRANS=8, LIBRAW_DNG_OTHER=16, LIBRAW_DNG_8BIT=32, /*LIBRAW_DNG_LARGERANGE=64,*/ /* more than 16 bit integer */ LIBRAW_DNG_ALL = LIBRAW_DNG_FLOAT|LIBRAW_DNG_LINEAR|LIBRAW_DNG_XTRANS|LIBRAW_DNG_8BIT|LIBRAW_DNG_OTHER /* |LIBRAW_DNG_LARGERANGE */, LIBRAW_DNG_DEFAULT=LIBRAW_DNG_FLOAT|LIBRAW_DNG_LINEAR|LIBRAW_DNG_DEFLATE|LIBRAW_DNG_8BIT }; enum LibRaw_runtime_capabilities { LIBRAW_CAPS_RAWSPEED=1, LIBRAW_CAPS_DNGSDK=2, LIBRAW_CAPS_DEMOSAICSGPL2=4, LIBRAW_CAPS_DEMOSAICSGPL3=8 }; enum LibRaw_camera_mounts { LIBRAW_MOUNT_Unknown=0, LIBRAW_MOUNT_Minolta_A=1, LIBRAW_MOUNT_Sony_E=2, LIBRAW_MOUNT_Canon_EF=3, LIBRAW_MOUNT_Canon_EF_S=4, LIBRAW_MOUNT_Canon_EF_M=5, LIBRAW_MOUNT_Nikon_F=6, LIBRAW_MOUNT_Nikon_CX=7, /* used in Nikon 1 series */ LIBRAW_MOUNT_FT=8, /* original 4/3 */ LIBRAW_MOUNT_mFT=9, /* micro 4/3 */ LIBRAW_MOUNT_Pentax_K=10, LIBRAW_MOUNT_Pentax_Q=11, LIBRAW_MOUNT_Pentax_645=12, LIBRAW_MOUNT_Fuji_X=13, LIBRAW_MOUNT_Leica_M=14, LIBRAW_MOUNT_Leica_R=15, LIBRAW_MOUNT_Leica_S=16, LIBRAW_MOUNT_Samsung_NX=17, LIBRAW_MOUNT_RicohModule=18, LIBRAW_MOUNT_Samsung_NX_M=19, LIBRAW_MOUNT_Leica_T=20, LIBRAW_MOUNT_Contax_N=21, LIBRAW_MOUNT_Sigma_X3F=22, LIBRAW_MOUNT_Leica_SL=23, LIBRAW_MOUNT_FixedLens=99 }; enum LibRaw_camera_formats { LIBRAW_FORMAT_APSC=1, LIBRAW_FORMAT_FF=2, LIBRAW_FORMAT_MF=3, LIBRAW_FORMAT_APSH=4, LIBRAW_FORMAT_1INCH=5, LIBRAW_FORMAT_FT=8 }; enum LibRaw_sony_cameratypes { LIBRAW_SONY_DSC=1, LIBRAW_SONY_DSLR=2, LIBRAW_SONY_NEX=3, LIBRAW_SONY_SLT=4, LIBRAW_SONY_ILCE=5, LIBRAW_SONY_ILCA=6 }; enum LibRaw_processing_options { LIBRAW_PROCESSING_SONYARW2_NONE=0, LIBRAW_PROCESSING_SONYARW2_BASEONLY=1, LIBRAW_PROCESSING_SONYARW2_DELTAONLY=1<<1, LIBRAW_PROCESSING_SONYARW2_DELTAZEROBASE=1<<2, LIBRAW_PROCESSING_SONYARW2_DELTATOVALUE=1<<3, LIBRAW_PROCESSING_SONYARW2_ALLFLAGS = LIBRAW_PROCESSING_SONYARW2_BASEONLY + LIBRAW_PROCESSING_SONYARW2_DELTAONLY + LIBRAW_PROCESSING_SONYARW2_DELTAZEROBASE + LIBRAW_PROCESSING_SONYARW2_DELTATOVALUE, LIBRAW_PROCESSING_DP2Q_INTERPOLATERG=1<<4, LIBRAW_PROCESSING_DP2Q_INTERPOLATEAF=1<<5, LIBRAW_PROCESSING_PENTAX_PS_ALLFRAMES=1<<6, LIBRAW_PROCESSING_CONVERTFLOAT_TO_INT=1<<7, LIBRAW_PROCESSING_SRAW_NO_RGB=1<<8, LIBRAW_PROCESSING_SRAW_NO_INTERPOLATE=1<<9, LIBRAW_PROCESSING_FORCE_FOVEON_X3F=1<<10 }; enum LibRaw_decoder_flags { LIBRAW_DECODER_HASCURVE = 1<<4, LIBRAW_DECODER_SONYARW2 = 1<<5, LIBRAW_DECODER_TRYRAWSPEED = 1<<6, LIBRAW_DECODER_OWNALLOC = 1<<7, LIBRAW_DECODER_FIXEDMAXC = 1<<8, LIBRAW_DECODER_ADOBECOPYPIXEL = 1<<9, LIBRAW_DECODER_LEGACY_WITH_MARGINS = 1<<10, LIBRAW_DECODER_NOTSET = 1<<15 }; #define LIBRAW_XTRANS 9 enum LibRaw_constructor_flags { LIBRAW_OPTIONS_NONE =0, LIBRAW_OPIONS_NO_MEMERR_CALLBACK=1, LIBRAW_OPIONS_NO_DATAERR_CALLBACK=1<<1 }; enum LibRaw_warnings { LIBRAW_WARN_NONE = 0, LIBRAW_WARN_BAD_CAMERA_WB = 1 << 2, LIBRAW_WARN_NO_METADATA = 1 << 3, LIBRAW_WARN_NO_JPEGLIB = 1 << 4, LIBRAW_WARN_NO_EMBEDDED_PROFILE = 1 << 5, LIBRAW_WARN_NO_INPUT_PROFILE = 1 << 6, LIBRAW_WARN_BAD_OUTPUT_PROFILE = 1 << 7, LIBRAW_WARN_NO_BADPIXELMAP = 1 << 8, LIBRAW_WARN_BAD_DARKFRAME_FILE = 1 << 9, LIBRAW_WARN_BAD_DARKFRAME_DIM = 1 << 10, LIBRAW_WARN_NO_JASPER = 1 << 11, LIBRAW_WARN_RAWSPEED_PROBLEM = 1 << 12, LIBRAW_WARN_RAWSPEED_UNSUPPORTED = 1 << 13, LIBRAW_WARN_RAWSPEED_PROCESSED = 1 << 14, LIBRAW_WARN_FALLBACK_TO_AHD = 1 << 15, LIBRAW_WARN_PARSEFUJI_PROCESSED = 1 << 16 }; enum LibRaw_exceptions { LIBRAW_EXCEPTION_NONE =0, LIBRAW_EXCEPTION_ALLOC =1, LIBRAW_EXCEPTION_DECODE_RAW =2, LIBRAW_EXCEPTION_DECODE_JPEG=3, LIBRAW_EXCEPTION_IO_EOF =4, LIBRAW_EXCEPTION_IO_CORRUPT =5, LIBRAW_EXCEPTION_CANCELLED_BY_CALLBACK=6, LIBRAW_EXCEPTION_BAD_CROP =7, LIBRAW_EXCEPTION_IO_BADFILE =8, LIBRAW_EXCEPTION_DECODE_JPEG2000=9 }; enum LibRaw_progress { LIBRAW_PROGRESS_START = 0, LIBRAW_PROGRESS_OPEN = 1, LIBRAW_PROGRESS_IDENTIFY = 1<<1, LIBRAW_PROGRESS_SIZE_ADJUST = 1<<2, LIBRAW_PROGRESS_LOAD_RAW = 1<<3, LIBRAW_PROGRESS_RAW2_IMAGE = 1<<4, LIBRAW_PROGRESS_REMOVE_ZEROES = 1<<5, LIBRAW_PROGRESS_BAD_PIXELS = 1<<6, LIBRAW_PROGRESS_DARK_FRAME = 1<<7, LIBRAW_PROGRESS_FOVEON_INTERPOLATE = 1<<8, LIBRAW_PROGRESS_SCALE_COLORS = 1<<9, LIBRAW_PROGRESS_PRE_INTERPOLATE = 1<<10, LIBRAW_PROGRESS_INTERPOLATE = 1<<11, LIBRAW_PROGRESS_MIX_GREEN = 1<<12, LIBRAW_PROGRESS_MEDIAN_FILTER = 1<<13, LIBRAW_PROGRESS_HIGHLIGHTS = 1<<14, LIBRAW_PROGRESS_FUJI_ROTATE = 1<<15, LIBRAW_PROGRESS_FLIP = 1<<16, LIBRAW_PROGRESS_APPLY_PROFILE = 1<<17, LIBRAW_PROGRESS_CONVERT_RGB = 1<<18, LIBRAW_PROGRESS_STRETCH = 1<<19, /* reserved */ LIBRAW_PROGRESS_STAGE20 = 1<<20, LIBRAW_PROGRESS_STAGE21 = 1<<21, LIBRAW_PROGRESS_STAGE22 = 1<<22, LIBRAW_PROGRESS_STAGE23 = 1<<23, LIBRAW_PROGRESS_STAGE24 = 1<<24, LIBRAW_PROGRESS_STAGE25 = 1<<25, LIBRAW_PROGRESS_STAGE26 = 1<<26, LIBRAW_PROGRESS_STAGE27 = 1<<27, LIBRAW_PROGRESS_THUMB_LOAD = 1<<28, LIBRAW_PROGRESS_TRESERVED1 = 1<<29, LIBRAW_PROGRESS_TRESERVED2 = 1<<30, LIBRAW_PROGRESS_TRESERVED3 = 1<<31 }; #define LIBRAW_PROGRESS_THUMB_MASK 0x0fffffff enum LibRaw_errors { LIBRAW_SUCCESS = 0, LIBRAW_UNSPECIFIED_ERROR=-1, LIBRAW_FILE_UNSUPPORTED = -2, LIBRAW_REQUEST_FOR_NONEXISTENT_IMAGE=-3, LIBRAW_OUT_OF_ORDER_CALL=-4, LIBRAW_NO_THUMBNAIL=-5, LIBRAW_UNSUPPORTED_THUMBNAIL=-6, LIBRAW_INPUT_CLOSED=-7, LIBRAW_NOT_IMPLEMENTED=-8, LIBRAW_UNSUFFICIENT_MEMORY=-100007, LIBRAW_DATA_ERROR=-100008, LIBRAW_IO_ERROR=-100009, LIBRAW_CANCELLED_BY_CALLBACK=-100010, LIBRAW_BAD_CROP=-100011 }; #define LIBRAW_FATAL_ERROR(ec) ((ec)<-100000) enum LibRaw_thumbnail_formats { LIBRAW_THUMBNAIL_UNKNOWN=0, LIBRAW_THUMBNAIL_JPEG=1, LIBRAW_THUMBNAIL_BITMAP=2, LIBRAW_THUMBNAIL_LAYER=4, LIBRAW_THUMBNAIL_ROLLEI=5 }; enum LibRaw_image_formats { LIBRAW_IMAGE_JPEG=1, LIBRAW_IMAGE_BITMAP=2 }; #endif LibRaw-0.18.8/libraw/libraw_datastream.h000066400000000000000000000212511324423227700201150ustar00rootroot00000000000000/* -*- C -*- * File: libraw_datastream.h * Copyright 2008-2017 LibRaw LLC (info@libraw.org) * Created: Sun Jan 18 13:07:35 2009 * * LibRaw Data stream interface LibRaw is free software; you can redistribute it and/or modify it under the terms of the one of two licenses as you choose: 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 (See file LICENSE.LGPL provided in LibRaw distribution archive for details). 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 (See file LICENSE.CDDL provided in LibRaw distribution archive for details). */ #ifndef __LIBRAW_DATASTREAM_H #define __LIBRAW_DATASTREAM_H #include #include #include #include #ifndef __cplusplus #else /* __cplusplus */ #include "libraw_const.h" #include "libraw_types.h" #include #include #if defined WIN32 || defined (__MINGW32__) #include /* MSVS 2008 and above... */ #if _MSC_VER >= 1500 #define WIN32SECURECALLS #endif #endif #ifdef USE_DNGSDK #if defined WIN32 || defined (__MINGW32__) #define qWinOS 1 #define qMacOS 0 #elif defined(__APPLE__) #define qWinOS 0 #define qMacOS 1 #else /* define OS types for DNG here */ #endif #define qDNGXMPDocOps 0 #define qDNGUseLibJPEG 1 #define qDNGXMPFiles 0 #define qDNGExperimental 1 #define qDNGThreadSafe 1 #include "dng_stream.h" #endif /* DNGSDK */ #define IOERROR() do { throw LIBRAW_EXCEPTION_IO_EOF; } while(0) class LibRaw_buffer_datastream; class LibRaw_bit_buffer; class DllDef LibRaw_abstract_datastream { public: LibRaw_abstract_datastream(){ substream=0;}; virtual ~LibRaw_abstract_datastream(void){if(substream) delete substream;} virtual int valid() = 0; virtual int read(void *,size_t, size_t ) = 0; virtual int seek(INT64 , int ) = 0; virtual INT64 tell() = 0; virtual INT64 size() = 0; virtual int get_char() = 0; virtual char* gets(char *, int) = 0; virtual int scanf_one(const char *, void *) = 0; virtual int eof() = 0; virtual void * make_jas_stream() = 0; virtual int jpeg_src(void *) { return -1; } /* reimplement in subclass to use parallel access in xtrans_load_raw() if OpenMP is not used */ virtual int lock() { return 1;} /* success */ virtual void unlock(){} /* subfile parsing not implemented in base class */ virtual const char* fname(){ return NULL;}; #if defined(_WIN32) && !defined(__MINGW32__) && defined(_MSC_VER) && (_MSC_VER > 1310) virtual const wchar_t* wfname(){ return NULL;}; virtual int subfile_open(const wchar_t*) { return -1;} #endif virtual int subfile_open(const char*) { return -1;} virtual void subfile_close() { } virtual int tempbuffer_open(void*, size_t); virtual void tempbuffer_close(); protected: LibRaw_abstract_datastream *substream; }; #ifdef WIN32 template class DllDef std::auto_ptr; #endif class DllDef LibRaw_file_datastream: public LibRaw_abstract_datastream { protected: std::auto_ptr f; /* will close() automatically through dtor */ std::auto_ptr saved_f; /* when *f is a subfile, *saved_f is the master file */ std::string filename; INT64 _fsize; #ifdef WIN32 std::wstring wfilename; #endif FILE *jas_file; public: virtual ~LibRaw_file_datastream(); LibRaw_file_datastream(const char *fname); #if defined(_WIN32) && !defined(__MINGW32__) && defined(_MSC_VER) && (_MSC_VER > 1310) LibRaw_file_datastream(const wchar_t *fname); #endif virtual void *make_jas_stream(); virtual int jpeg_src(void *jpegdata); 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() { return _fsize;} virtual int get_char() { if(substream) return substream->get_char(); return f->sbumpc(); } virtual char* gets(char *str, int sz); virtual int scanf_one(const char *fmt, void*val); virtual const char* fname(); #if defined(_WIN32) && !defined(__MINGW32__) && defined(_MSC_VER) && (_MSC_VER > 1310) virtual const wchar_t* wfname(); virtual int subfile_open(const wchar_t *fn); #endif virtual int subfile_open(const char *fn); virtual void subfile_close(); }; class DllDef LibRaw_buffer_datastream : public LibRaw_abstract_datastream { public: LibRaw_buffer_datastream(void *buffer, size_t bsize); virtual ~LibRaw_buffer_datastream(); virtual int valid(); virtual void *make_jas_stream(); virtual int jpeg_src(void *jpegdata); virtual int read(void * ptr,size_t sz, size_t nmemb); virtual int eof(); virtual int seek(INT64 o, int whence); virtual INT64 tell(); virtual INT64 size() { return streamsize;} virtual char* gets(char *s, int sz); virtual int scanf_one(const char *fmt, void* val); virtual int get_char() { if(substream) return substream->get_char(); if(streampos>=streamsize) return -1; return buf[streampos++]; } private: unsigned char *buf; size_t streampos,streamsize; }; class DllDef LibRaw_bigfile_datastream : public LibRaw_abstract_datastream { public: LibRaw_bigfile_datastream(const char *fname); #if defined(_WIN32) && !defined(__MINGW32__) && defined(_MSC_VER) && (_MSC_VER > 1310) LibRaw_bigfile_datastream(const wchar_t *fname); #endif virtual ~LibRaw_bigfile_datastream(); virtual int valid(); virtual int jpeg_src(void *jpegdata); virtual void *make_jas_stream(); 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() { return _fsize;} virtual char* gets(char *str, int sz); virtual int scanf_one(const char *fmt, void*val); virtual const char *fname(); #if defined(_WIN32) && !defined(__MINGW32__) && defined(_MSC_VER) && (_MSC_VER > 1310) virtual const wchar_t* wfname(); virtual int subfile_open(const wchar_t *fn); #endif virtual int subfile_open(const char *fn); virtual void subfile_close(); virtual int get_char() { #if !defined(_WIN32) && !defined(__MINGW32__) return substream?substream->get_char():getc_unlocked(f); #else return substream?substream->get_char():fgetc(f); #endif } protected: FILE *f,*sav; std::string filename; INT64 _fsize; #ifdef WIN32 std::wstring wfilename; #endif }; #ifdef WIN32 class DllDef LibRaw_windows_datastream : public LibRaw_buffer_datastream { public: /* ctor: high level constructor opens a file by name */ LibRaw_windows_datastream(const TCHAR* sFile); /* ctor: construct with a file handle - caller is responsible for closing the file handle */ LibRaw_windows_datastream(HANDLE hFile); /* dtor: unmap and close the mapping handle */ virtual ~LibRaw_windows_datastream(); virtual INT64 size() { return cbView_;} protected: void Open(HANDLE hFile); inline void reconstruct_base() { /* this subterfuge is to overcome the private-ness of LibRaw_buffer_datastream */ (LibRaw_buffer_datastream&)*this = LibRaw_buffer_datastream(pView_, (size_t)cbView_); } HANDLE hMap_; /* handle of the file mapping */ void* pView_; /* pointer to the mapped memory */ __int64 cbView_; /* size of the mapping in bytes */ }; #endif #ifdef USE_DNGSDK class libraw_dng_stream: public dng_stream { public: libraw_dng_stream(LibRaw_abstract_datastream* p): dng_stream((dng_abort_sniffer*)NULL,kBigBufferSize,0),parent_stream(p) { if(parent_stream) { off = parent_stream->tell(); parent_stream->seek(0UL,SEEK_SET); /* seek to start */ } } ~libraw_dng_stream(){ if(parent_stream) parent_stream->seek(off,SEEK_SET); } virtual uint64 DoGetLength (){ if(parent_stream) return parent_stream->size(); return 0; } virtual void DoRead (void *data, uint32 count, uint64 offset) { if(parent_stream) { parent_stream->seek(offset,SEEK_SET); parent_stream->read(data,1,count); } } private: libraw_dng_stream (const libraw_dng_stream &stream); libraw_dng_stream & operator= (const libraw_dng_stream &stream); LibRaw_abstract_datastream *parent_stream; INT64 off; }; #endif #endif /* cplusplus */ #endif LibRaw-0.18.8/libraw/libraw_internal.h000066400000000000000000000130051324423227700176020ustar00rootroot00000000000000/* -*- C++ -*- * File: libraw_internal.h * Copyright 2008-2017 LibRaw LLC (info@libraw.org) * Created: Sat Mar 8 , 2008 * * LibRaw internal data structures (not visible outside) LibRaw is free software; you can redistribute it and/or modify it under the terms of the one of two licenses as you choose: 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 (See file LICENSE.LGPL provided in LibRaw distribution archive for details). 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 (See file LICENSE.CDDL provided in LibRaw distribution archive for details). */ #ifndef _LIBRAW_INTERNAL_TYPES_H #define _LIBRAW_INTERNAL_TYPES_H #include #ifdef __cplusplus #ifdef LIBRAW_LIBRARY_BUILD #ifndef CLASS #define CLASS LibRaw:: #endif #endif #else #ifndef CLASS #define CLASS #endif #endif #ifdef __cplusplus #include "libraw_datastream.h" #include "libraw_types.h" class LibRaw_TLS { public: struct { unsigned bitbuf; int vbits, reset; }getbits; struct { UINT64 bitbuf; int vbits; }ph1_bits; struct { unsigned pad[128], p; }sony_decrypt; struct { uchar buf[0x4000]; int vbits, padding; }pana_bits; uchar jpeg_buffer[4096]; struct { float cbrt[0x10000], xyz_cam[3][4]; }ahd_data; void init() { getbits.bitbuf = 0; getbits.vbits = getbits.reset = 0; ph1_bits.bitbuf = 0; ph1_bits.vbits = 0; pana_bits.vbits = 0; ahd_data.cbrt[0]=-2.0f; } }; class LibRaw_constants { public: static const float d65_white[3]; static const double xyz_rgb[3][3]; }; #endif /* __cplusplus */ typedef struct { #ifndef __cplusplus struct #endif LibRaw_abstract_datastream *input; FILE *output; int input_internal; char *meta_data; INT64 profile_offset; INT64 toffset; unsigned pana_black[4]; } internal_data_t; #define LIBRAW_HISTOGRAM_SIZE 0x2000 typedef struct { int (*histogram)[LIBRAW_HISTOGRAM_SIZE]; unsigned *oprof; } output_data_t; typedef struct { unsigned olympus_exif_cfa; unsigned unique_id; unsigned tiff_nifds; int tiff_flip; }identify_data_t; typedef struct { short order; ushort sraw_mul[4],cr2_slice[3]; unsigned kodak_cbpp; INT64 strip_offset, data_offset; INT64 meta_offset; unsigned data_size; unsigned meta_length; unsigned thumb_misc; unsigned fuji_layout; unsigned tiff_samples; unsigned tiff_bps; unsigned tiff_compress; unsigned zero_after_ff; unsigned tile_width, tile_length,load_flags; unsigned data_error; int hasselblad_parser_flag; long long posRAFData; unsigned lenRAFData; int fuji_total_lines, fuji_total_blocks, fuji_block_width, fuji_bits; }unpacker_data_t; typedef struct { internal_data_t internal_data; libraw_internal_output_params_t internal_output_params; output_data_t output_data; identify_data_t identify_data; unpacker_data_t unpacker_data; } libraw_internal_data_t; struct decode { struct decode *branch[2]; int leaf; }; struct tiff_ifd_t { int t_width, t_height, bps, comp, phint, offset, t_flip, samples, bytes; int t_tile_width, t_tile_length,sample_format,predictor; int rows_per_strip; int *strip_offsets,strip_offsets_count; int *strip_byte_counts,strip_byte_counts_count; float t_shutter; }; struct jhead { int algo, bits, high, wide, clrs, sraw, psv, restart, vpred[6]; ushort quant[64], idct[64], *huff[20], *free[20], *row; }; struct tiff_tag { ushort tag, type; int count; union { char c[4]; short s[2]; int i; } val; }; struct tiff_hdr { ushort t_order, magic; int ifd; ushort pad, ntag; struct tiff_tag tag[23]; int nextifd; ushort pad2, nexif; struct tiff_tag exif[4]; ushort pad3, ngps; struct tiff_tag gpst[10]; short bps[4]; int rat[10]; unsigned gps[26]; char t_desc[512], t_make[64], t_model[64], soft[32], date[20], t_artist[64]; }; #ifdef DEBUG_STAGE_CHECKS #define CHECK_ORDER_HIGH(expected_stage) \ do { if((imgdata.progress_flags & LIBRAW_PROGRESS_THUMB_MASK) >= expected_stage) {fprintf(stderr,"CHECK_HIGH: check %d >= %d\n",imgdata.progress_flags & LIBRAW_PROGRESS_THUMB_MASK,expected_stage);return LIBRAW_OUT_OF_ORDER_CALL;} } while(0) #define CHECK_ORDER_LOW(expected_stage) \ do { printf("Checking LOW %d/%d : %d\n",imgdata.progress_flags,expected_stage,imgdata.progress_flags= expected_stage) \ {return LIBRAW_OUT_OF_ORDER_CALL;} } while(0) #define CHECK_ORDER_LOW(expected_stage) \ do { if((imgdata.progress_flags&LIBRAW_PROGRESS_THUMB_MASK) < expected_stage) \ return LIBRAW_OUT_OF_ORDER_CALL; } while(0) #define CHECK_ORDER_BIT(expected_stage) \ do { if(imgdata.progress_flags & expected_stage) return LIBRAW_OUT_OF_ORDER_CALL; } while(0) #define SET_PROC_FLAG(stage) do {imgdata.progress_flags |= stage;} while (0) #endif #endif LibRaw-0.18.8/libraw/libraw_types.h000066400000000000000000000444021324423227700171370ustar00rootroot00000000000000/* -*- C++ -*- * File: libraw_types.h * Copyright 2008-2017 LibRaw LLC (info@libraw.org) * Created: Sat Mar 8 , 2008 * * LibRaw C data structures * LibRaw is free software; you can redistribute it and/or modify it under the terms of the one of two licenses as you choose: 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 (See file LICENSE.LGPL provided in LibRaw distribution archive for details). 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 (See file LICENSE.CDDL provided in LibRaw distribution archive for details). */ #ifndef _LIBRAW_TYPES_H #define _LIBRAW_TYPES_H #include #ifndef WIN32 #include #endif #include #if defined(_WIN32) #if defined (_MSC_VER) && (_MSC_VER <=1500) typedef signed __int8 int8_t; typedef unsigned __int8 uint8_t; typedef signed __int16 int16_t; typedef unsigned __int16 uint16_t; typedef signed __int32 int32_t; typedef unsigned __int32 uint32_t; typedef signed __int64 int64_t; typedef unsigned __int64 uint64_t; #else #include #endif // _WIN32 #include #else #include #endif #if defined (_OPENMP) #if defined(WIN32) # if defined (_MSC_VER) && (_MSC_VER >= 1600 || (_MSC_VER == 1500 && _MSC_FULL_VER >= 150030729) ) /* VS2010+ : OpenMP works OK, VS2008: have tested by cgilles */ # define LIBRAW_USE_OPENMP #elif defined (__INTEL_COMPILER) && (__INTEL_COMPILER >=910) /* Have not tested on 9.x and 10.x, but Intel documentation claims OpenMP 2.5 support in 9.1 */ # define LIBRAW_USE_OPENMP #else # undef LIBRAW_USE_OPENMP #endif /* Not Win32 */ # elif (defined(__APPLE__) || defined(__MACOSX__)) && defined(_REENTRANT) # undef LIBRAW_USE_OPENMP # else # define LIBRAW_USE_OPENMP # endif #endif #ifdef LIBRAW_USE_OPENMP #include #endif #ifdef __cplusplus extern "C" { #endif #if defined(USE_LCMS) #include #elif defined(USE_LCMS2) #include #else #define NO_LCMS #endif #include "libraw_const.h" #include "libraw_version.h" #ifdef WIN32 typedef __int64 INT64; typedef unsigned __int64 UINT64; #else typedef long long INT64; typedef unsigned long long UINT64; #endif typedef unsigned char uchar; typedef unsigned short ushort; #ifdef WIN32 #ifdef LIBRAW_NODLL # define DllDef #else # ifdef LIBRAW_BUILDLIB # define DllDef __declspec( dllexport ) # else # define DllDef __declspec( dllimport ) # endif #endif #else # define DllDef #endif typedef struct { const char *decoder_name; unsigned decoder_flags; }libraw_decoder_info_t; typedef struct { unsigned mix_green; unsigned raw_color; unsigned zero_is_bad; ushort shrink; ushort fuji_width; } libraw_internal_output_params_t; typedef void (* memory_callback)(void * data, const char *file, const char *where); typedef void (*exif_parser_callback) (void *context, int tag, int type, int len,unsigned int ord, void *ifp); DllDef void default_memory_callback(void *data,const char *file, const char *where); typedef void (*data_callback)(void *data,const char *file, const int offset); DllDef void default_data_callback(void *data,const char *file, const int offset); typedef int (* progress_callback) (void *data,enum LibRaw_progress stage, int iteration,int expected); typedef struct { memory_callback mem_cb; void* memcb_data; data_callback data_cb; void* datacb_data; progress_callback progress_cb; void *progresscb_data; exif_parser_callback exif_cb; void *exifparser_data; } libraw_callbacks_t; typedef struct { enum LibRaw_image_formats type; ushort height, width, colors, bits; unsigned int data_size; unsigned char data[1]; }libraw_processed_image_t; typedef struct { char guard[4]; char make[64]; char model[64]; char software[64]; unsigned raw_count; unsigned dng_version; unsigned is_foveon; int colors; unsigned filters; char xtrans[6][6]; char xtrans_abs[6][6]; char cdesc[5]; unsigned xmplen; char *xmpdata; }libraw_iparams_t; typedef struct { ushort raw_height, raw_width, height, width, top_margin, left_margin; ushort iheight, iwidth; unsigned raw_pitch; double pixel_aspect; int flip; int mask[8][4]; } libraw_image_sizes_t; struct ph1_t { int format, key_off, tag_21a; int t_black, split_col, black_col, split_row, black_row; float tag_210; }; typedef struct { ushort illuminant; float calibration[4][4]; float colormatrix[4][3]; float forwardmatrix[3][4]; } libraw_dng_color_t; typedef struct { unsigned dng_cblack[4102]; unsigned dng_black; unsigned dng_whitelevel[4]; float dng_blacklevel[4]; float analogbalance[4]; } libraw_dng_levels_t; typedef struct { float romm_cam[9]; } libraw_P1_color_t; typedef struct { int CanonColorDataVer; int CanonColorDataSubVer; int SpecularWhiteLevel; int ChannelBlackLevel[4]; int AverageBlackLevel; /* metering */ short MeteringMode; short SpotMeteringMode; uchar FlashMeteringMode; short FlashExposureLock; short ExposureMode; short AESetting; uchar HighlightTonePriority; /* stabilization */ short ImageStabilization; /* focus */ short FocusMode; short AFPoint; short FocusContinuous; short AFPointsInFocus30D; uchar AFPointsInFocus1D[8]; ushort AFPointsInFocus5D; /* bytes in reverse*/ /* AFInfo */ ushort AFAreaMode; ushort NumAFPoints; ushort ValidAFPoints; ushort AFImageWidth; ushort AFImageHeight; short AFAreaWidths[61]; /* cycle to NumAFPoints */ short AFAreaHeights[61]; /* --''-- */ short AFAreaXPositions[61]; /* --''-- */ short AFAreaYPositions[61]; /* --''-- */ short AFPointsInFocus[4]; /* cycle to floor((NumAFPoints+15)/16) */ short AFPointsSelected[4]; /* --''-- */ ushort PrimaryAFPoint; /* flash */ short FlashMode; short FlashActivity; short FlashBits; short ManualFlashOutput; short FlashOutput; short FlashGuideNumber; /* drive */ short ContinuousDrive; /* sensor */ short SensorWidth; short SensorHeight; short SensorLeftBorder; short SensorTopBorder; short SensorRightBorder; short SensorBottomBorder; short BlackMaskLeftBorder; short BlackMaskTopBorder; short BlackMaskRightBorder; short BlackMaskBottomBorder; } libraw_canon_makernotes_t; typedef struct { float FujiExpoMidPointShift; ushort FujiDynamicRange; ushort FujiFilmMode; ushort FujiDynamicRangeSetting; ushort FujiDevelopmentDynamicRange; ushort FujiAutoDynamicRange; ushort FocusMode; ushort AFMode; ushort FocusPixel[2]; ushort ImageStabilization[3]; ushort FlashMode; ushort WB_Preset; ushort ShutterType; ushort ExrMode; ushort Macro; unsigned Rating; ushort FrameRate; ushort FrameWidth; ushort FrameHeight; } libraw_fuji_info_t; typedef struct { double ExposureBracketValue; ushort ActiveDLighting; ushort ShootingMode; /* stabilization */ uchar ImageStabilization[7]; uchar VibrationReduction; uchar VRMode; /* focus */ char FocusMode[7]; uchar AFPoint; ushort AFPointsInFocus; uchar ContrastDetectAF; uchar AFAreaMode; uchar PhaseDetectAF; uchar PrimaryAFPoint; uchar AFPointsUsed[29]; ushort AFImageWidth; ushort AFImageHeight; ushort AFAreaXPposition; ushort AFAreaYPosition; ushort AFAreaWidth; ushort AFAreaHeight; uchar ContrastDetectAFInFocus; /* flash */ char FlashSetting[13]; char FlashType[20]; uchar FlashExposureCompensation[4]; uchar ExternalFlashExposureComp[4]; uchar FlashExposureBracketValue[4]; uchar FlashMode; signed char FlashExposureCompensation2; signed char FlashExposureCompensation3; signed char FlashExposureCompensation4; uchar FlashSource; uchar FlashFirmware[2]; uchar ExternalFlashFlags; uchar FlashControlCommanderMode; uchar FlashOutputAndCompensation; uchar FlashFocalLength; uchar FlashGNDistance; uchar FlashGroupControlMode[4]; uchar FlashGroupOutputAndCompensation[4]; uchar FlashColorFilter; } libraw_nikon_makernotes_t; typedef struct { int OlympusCropID; ushort OlympusFrame[4]; /* upper left XY, lower right XY */ int OlympusSensorCalibration[2]; ushort FocusMode[2]; ushort AutoFocus; ushort AFPoint; unsigned AFAreas[64]; double AFPointSelected[5]; ushort AFResult; unsigned ImageStabilization; ushort ColorSpace; } libraw_olympus_makernotes_t; typedef struct { ushort FocusMode; uchar AFPointMode; ushort AFPointSelected[2]; unsigned AFPointsInFocus; uchar DriveMode[4]; uchar SRResult; uchar ShakeReduction; } libraw_pentax_makernotes_t; typedef struct { ushort SonyCameraType; } libraw_sony_info_t; typedef struct { ushort curve[0x10000]; unsigned cblack[4102]; unsigned black; unsigned data_maximum; unsigned maximum; long linear_max[4]; float fmaximum; float fnorm; ushort white[8][8]; float cam_mul[4]; float pre_mul[4]; float cmatrix[3][4]; float ccm[3][4]; float rgb_cam[3][4]; float cam_xyz[4][3]; struct ph1_t phase_one_data; float flash_used; float canon_ev; char model2[64]; char UniqueCameraModel[64]; char LocalizedCameraModel[64]; void *profile; unsigned profile_length; unsigned black_stat[8]; libraw_dng_color_t dng_color[2]; libraw_dng_levels_t dng_levels; float baseline_exposure; int WB_Coeffs[256][4]; /* R, G1, B, G2 coeffs */ float WBCT_Coeffs[64][5]; /* CCT, than R, G1, B, G2 coeffs */ libraw_P1_color_t P1_color[2]; } libraw_colordata_t; typedef struct { enum LibRaw_thumbnail_formats tformat; ushort twidth, theight; unsigned tlength; int tcolors; char *thumb; }libraw_thumbnail_t; typedef struct { float latitude[3]; /* Deg,min,sec */ float longtitude[3]; /* Deg,min,sec */ float gpstimestamp[3]; /* Deg,min,sec */ float altitude; char altref, latref, longref, gpsstatus; char gpsparsed; } libraw_gps_info_t; typedef struct { float iso_speed; float shutter; float aperture; float focal_len; time_t timestamp; unsigned shot_order; unsigned gpsdata[32]; libraw_gps_info_t parsed_gps; char desc[512], artist[64]; float FlashEC; } libraw_imgother_t; typedef struct { unsigned greybox[4]; /* -A x1 y1 x2 y2 */ unsigned cropbox[4]; /* -B x1 y1 x2 y2 */ double aber[4]; /* -C */ double gamm[6]; /* -g */ float user_mul[4]; /* -r mul0 mul1 mul2 mul3 */ unsigned shot_select; /* -s */ float bright; /* -b */ float threshold; /* -n */ int half_size; /* -h */ int four_color_rgb; /* -f */ int highlight; /* -H */ int use_auto_wb; /* -a */ int use_camera_wb; /* -w */ int use_camera_matrix; /* +M/-M */ int output_color; /* -o */ char *output_profile; /* -o */ char *camera_profile; /* -p */ char *bad_pixels; /* -P */ char *dark_frame; /* -K */ int output_bps; /* -4 */ int output_tiff; /* -T */ int user_flip; /* -t */ int user_qual; /* -q */ int user_black; /* -k */ int user_cblack[4]; int user_sat; /* -S */ int med_passes; /* -m */ float auto_bright_thr; float adjust_maximum_thr; int no_auto_bright; /* -W */ int use_fuji_rotate;/* -j */ int green_matching; /* DCB parameters */ int dcb_iterations; int dcb_enhance_fl; int fbdd_noiserd; /* VCD parameters */ int eeci_refine; int es_med_passes; /* AMaZE*/ int ca_correc; float cared; float cablue; int cfaline; float linenoise; int cfa_clean; float lclean; float cclean; int cfa_green; float green_thresh; int exp_correc; float exp_shift; float exp_preser; /* WF debanding */ int wf_debanding; float wf_deband_treshold[4]; /* Raw speed */ int use_rawspeed; /* DNG SDK */ int use_dngsdk; /* Disable Auto-scale */ int no_auto_scale; /* Disable intepolation */ int no_interpolation; /* int x3f_flags; */ /* Sony ARW2 digging mode */ /* int sony_arw2_options; */ unsigned raw_processing_options; int sony_arw2_posterization_thr; /* Nikon Coolscan */ float coolscan_nef_gamma; char p4shot_order[5]; /* Custom camera list */ char **custom_camera_strings; }libraw_output_params_t; typedef struct { /* really allocated bitmap */ void *raw_alloc; /* alias to single_channel variant */ ushort *raw_image; /* alias to 4-channel variant */ ushort (*color4_image)[4] ; /* alias to 3-color variand decoded by RawSpeed */ ushort (*color3_image)[3]; /* float bayer */ float *float_image; /* float 3-component */ float (*float3_image)[3]; /* float 4-component */ float (*float4_image)[4]; /* Phase One black level data; */ short (*ph1_cblack)[2]; short (*ph1_rblack)[2]; /* save color and sizes here, too.... */ libraw_iparams_t iparams; libraw_image_sizes_t sizes; libraw_internal_output_params_t ioparams; libraw_colordata_t color; } libraw_rawdata_t; typedef struct { unsigned long long LensID; char Lens[128]; ushort LensFormat; /* to characterize the image circle the lens covers */ ushort LensMount; /* 'male', lens itself */ unsigned long long CamID; ushort CameraFormat; /* some of the sensor formats */ ushort CameraMount; /* 'female', body throat */ char body[64]; short FocalType; /* -1/0 is unknown; 1 is fixed focal; 2 is zoom */ char LensFeatures_pre[16], LensFeatures_suf[16]; float MinFocal, MaxFocal; float MaxAp4MinFocal, MaxAp4MaxFocal, MinAp4MinFocal, MinAp4MaxFocal; float MaxAp, MinAp; float CurFocal, CurAp; float MaxAp4CurFocal, MinAp4CurFocal; float MinFocusDistance; float FocusRangeIndex; float LensFStops; unsigned long long TeleconverterID; char Teleconverter[128]; unsigned long long AdapterID; char Adapter[128]; unsigned long long AttachmentID; char Attachment[128]; ushort CanonFocalUnits; float FocalLengthIn35mmFormat; } libraw_makernotes_lens_t; typedef struct { float NikonEffectiveMaxAp; uchar NikonLensIDNumber, NikonLensFStops, NikonMCUVersion, NikonLensType; } libraw_nikonlens_t; typedef struct { float MinFocal, MaxFocal, MaxAp4MinFocal, MaxAp4MaxFocal; } libraw_dnglens_t; typedef struct { float MinFocal, MaxFocal, MaxAp4MinFocal, MaxAp4MaxFocal, EXIF_MaxAp; char LensMake[128], Lens[128], LensSerial[128], InternalLensSerial[128]; ushort FocalLengthIn35mmFormat; libraw_nikonlens_t nikon; libraw_dnglens_t dng; libraw_makernotes_lens_t makernotes; } libraw_lensinfo_t; typedef struct { libraw_canon_makernotes_t canon; libraw_fuji_info_t fuji; libraw_olympus_makernotes_t olympus; libraw_sony_info_t sony; } libraw_makernotes_t; typedef struct { short DriveMode; short FocusMode; short MeteringMode; short AFPoint; short ExposureMode; short ImageStabilization; char BodySerial[64]; char InternalBodySerial[64]; /* this may be PCB or sensor serial, depends on make/model*/ } libraw_shootinginfo_t; typedef struct { unsigned fsize; ushort rw, rh; uchar lm, tm, rm, bm, lf, cf, max, flags; char t_make[10], t_model[20]; ushort offset; } libraw_custom_camera_t; typedef struct { ushort (*image)[4] ; libraw_image_sizes_t sizes; libraw_iparams_t idata; libraw_lensinfo_t lens; libraw_makernotes_t makernotes; libraw_shootinginfo_t shootinginfo; libraw_output_params_t params; unsigned int progress_flags; unsigned int process_warnings; libraw_colordata_t color; libraw_imgother_t other; libraw_thumbnail_t thumbnail; libraw_rawdata_t rawdata; void *parent_class; } libraw_data_t; struct xtrans_params { char *q_table; /* quantization table */ int q_point[5]; /* quantization points */ int max_bits; int min_value; int raw_bits; int total_values; int maxDiff; ushort line_width; }; #ifdef __cplusplus } #endif /* Byte order */ #if defined(__POWERPC__) #define LibRawBigEndian 1 #elif defined(__INTEL__) #define LibRawBigEndian 0 #elif defined(_M_IX86) || defined(__i386__) #define LibRawBigEndian 0 #elif defined(_M_X64) || defined(__amd64__) || defined(__x86_64__) #define LibRawBigEndian 0 #elif defined(__LITTLE_ENDIAN__) #define LibRawBigEndian 0 #elif defined(__BIG_ENDIAN__) #define LibRawBigEndian 1 #elif defined(_ARM_) #define LibRawBigEndian 0 #elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ #define LibRawBigEndian 0 #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ #define LibRawBigEndian 1 #else #ifndef qXCodeRez #error Unable to figure out byte order. #endif #endif #endif LibRaw-0.18.8/libraw/libraw_version.h000066400000000000000000000037511324423227700174620ustar00rootroot00000000000000/* -*- C++ -*- * File: libraw_version.h * Copyright 2008-2017 LibRaw LLC (info@libraw.org) * Created: Mon Sept 8, 2008 * * LibRaw C++ interface * LibRaw is free software; you can redistribute it and/or modify it under the terms of the one of two licenses as you choose: 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 (See the file LICENSE.LGPL provided in LibRaw distribution archive for details). 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 (See the file LICENSE.CDDL provided in LibRaw distribution archive for details). */ #ifndef __VERSION_H #define __VERSION_H #define LIBRAW_MAJOR_VERSION 0 #define LIBRAW_MINOR_VERSION 18 #define LIBRAW_PATCH_VERSION 8 #define LIBRAW_VERSION_TAIL Release #define LIBRAW_SHLIB_CURRENT 16 #define LIBRAW_SHLIB_REVISION 0 #define LIBRAW_SHLIB_AGE 0 #define _LIBRAW_VERSION_MAKE(a,b,c,d) #a"."#b"."#c"-"#d #define LIBRAW_VERSION_MAKE(a,b,c,d) _LIBRAW_VERSION_MAKE(a,b,c,d) #define LIBRAW_VERSION_STR LIBRAW_VERSION_MAKE(LIBRAW_MAJOR_VERSION,LIBRAW_MINOR_VERSION,LIBRAW_PATCH_VERSION,LIBRAW_VERSION_TAIL) #define LIBRAW_MAKE_VERSION(major,minor,patch) \ (((major) << 16) | ((minor) << 8) | (patch)) #define LIBRAW_VERSION \ LIBRAW_MAKE_VERSION(LIBRAW_MAJOR_VERSION,LIBRAW_MINOR_VERSION,LIBRAW_PATCH_VERSION) #define LIBRAW_CHECK_VERSION(major,minor,patch) \ ( LibRaw::versionNumber() >= LIBRAW_MAKE_VERSION(major,minor,patch) ) #define LIBRAW_RUNTIME_CHECK_VERSION_EXACT() \ ( (LibRaw::versionNumber() & 0xffff00) == LIBRAW_MAKE_VERSION(LIBRAW_MAJOR_VERSION,LIBRAW_MINOR_VERSION,0) ) #define LIBRAW_RUNTIME_CHECK_VERSION_NOTLESS() \ ( (LibRaw::versionNumber() & 0xffff00) >= LIBRAW_MAKE_VERSION(LIBRAW_MAJOR_VERSION,LIBRAW_MINOR_VERSION,0) ) #define LIBRAW_COMPILE_CHECK_VERSION(major,minor) \ (LIBRAW_MAKE_VERSION(major,minor,0) == (LIBRAW_VERSION & 0xffff00)) #define LIBRAW_COMPILE_CHECK_VERSION_NOTLESS(major,minor) \ (LIBRAW_MAKE_VERSION(major,minor,0) <= (LIBRAW_VERSION & 0xffff00)) #endif LibRaw-0.18.8/libraw_build.h000066400000000000000000000001021324423227700155770ustar00rootroot00000000000000#ifndef LIBRAW_BUILD_NUMBER #define LIBRAW_BUILD_NUMBER 345 #endifLibRaw-0.18.8/libraw_r.pc.in000066400000000000000000000004321324423227700155270ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: libraw Description: Raw image decoder library (thread-safe) Requires: @PACKAGE_REQUIRES@ Version: @PACKAGE_VERSION@ Libs: -L${libdir} -lraw_r -lstdc++@PC_OPENMP@ Cflags: -I${includedir}/libraw LibRaw-0.18.8/m4/000077500000000000000000000000001324423227700133165ustar00rootroot00000000000000LibRaw-0.18.8/m4/ax_openmp.m4000066400000000000000000000102741324423227700155520ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_openmp.html # =========================================================================== # # SYNOPSIS # # AX_OPENMP([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) # # DESCRIPTION # # This macro tries to find out how to compile programs that use OpenMP a # standard API and set of compiler directives for parallel programming # (see http://www-unix.mcs/) # # On success, it sets the OPENMP_CFLAGS/OPENMP_CXXFLAGS/OPENMP_F77FLAGS # output variable to the flag (e.g. -omp) used both to compile *and* link # OpenMP programs in the current language. # # NOTE: You are assumed to not only compile your program with these flags, # but also link it with them as well. # # If you want to compile everything with OpenMP, you should set: # # CFLAGS="$CFLAGS $OPENMP_CFLAGS" # #OR# CXXFLAGS="$CXXFLAGS $OPENMP_CXXFLAGS" # #OR# FFLAGS="$FFLAGS $OPENMP_FFLAGS" # # (depending on the selected language). # # The user can override the default choice by setting the corresponding # environment variable (e.g. OPENMP_CFLAGS). # # ACTION-IF-FOUND is a list of shell commands to run if an OpenMP flag is # found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it is # not found. If ACTION-IF-FOUND is not specified, the default action will # define HAVE_OPENMP. # # LICENSE # # Copyright (c) 2008 Steven G. Johnson # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 8 AC_DEFUN([AX_OPENMP], [ AC_PREREQ(2.59) dnl for _AC_LANG_PREFIX AC_CACHE_CHECK([for OpenMP flag of _AC_LANG compiler], ax_cv_[]_AC_LANG_ABBREV[]_openmp, [save[]_AC_LANG_PREFIX[]FLAGS=$[]_AC_LANG_PREFIX[]FLAGS ax_cv_[]_AC_LANG_ABBREV[]_openmp=unknown # Flags to try: -fopenmp (gcc), -openmp (icc), -mp (SGI & PGI), # -xopenmp (Sun), -omp (Tru64), -qsmp=omp (AIX), none ax_openmp_flags="-fopenmp -openmp -mp -xopenmp -omp -qsmp=omp none" if test "x$OPENMP_[]_AC_LANG_PREFIX[]FLAGS" != x; then ax_openmp_flags="$OPENMP_[]_AC_LANG_PREFIX[]FLAGS $ax_openmp_flags" fi for ax_openmp_flag in $ax_openmp_flags; do case $ax_openmp_flag in none) []_AC_LANG_PREFIX[]FLAGS=$save[]_AC_LANG_PREFIX[] ;; *) []_AC_LANG_PREFIX[]FLAGS="$save[]_AC_LANG_PREFIX[]FLAGS $ax_openmp_flag" ;; esac AC_TRY_LINK_FUNC(omp_set_num_threads, [ax_cv_[]_AC_LANG_ABBREV[]_openmp=$ax_openmp_flag; break]) done []_AC_LANG_PREFIX[]FLAGS=$save[]_AC_LANG_PREFIX[]FLAGS ]) if test "x$ax_cv_[]_AC_LANG_ABBREV[]_openmp" = "xunknown"; then m4_default([$2],:) else if test "x$ax_cv_[]_AC_LANG_ABBREV[]_openmp" != "xnone"; then OPENMP_[]_AC_LANG_PREFIX[]FLAGS=$ax_cv_[]_AC_LANG_ABBREV[]_openmp fi m4_default([$1], [AC_DEFINE(HAVE_OPENMP,1,[Define if OpenMP is enabled])]) fi ])dnl AX_OPENMP LibRaw-0.18.8/mkdist.sh000077500000000000000000000007701324423227700146340ustar00rootroot00000000000000#!/bin/sh if [ -d CVS ] ; then echo 'Use mkdist script in cvs export-ed dirs' else if [ -f Makefile.devel ] ; then make -f Makefile.devel regenerate autoreconf --install rm -fr dcraw/* rm -f dcraw/.gdbinit cd dcraw wget http://www.cybercom.net/~dcoffin/dcraw/dcraw.c cd .. rm -f internal/preprocess.pl clist2c.pl rm -f Makefile.devel rm DEVELOPER-NOTES rm mkdist.sh export-dist.sh else echo 'Wrong directory or mkdist.sh already executed' fi fi LibRaw-0.18.8/object/000077500000000000000000000000001324423227700142445ustar00rootroot00000000000000LibRaw-0.18.8/object/.keep_me000066400000000000000000000000001324423227700156400ustar00rootroot00000000000000LibRaw-0.18.8/rsxml2c.sh000077500000000000000000000002341324423227700147260ustar00rootroot00000000000000#!/bin/sh echo "const char *_rawspeed_data_xml[]={" cat $1 | tr -d '\015' | sed -e 's/\\/\\\\/g;s/"/\\"/g;s/ /\\t/g;s/^/"/;s/$/\\n",/' echo "0" echo "};" LibRaw-0.18.8/samples/000077500000000000000000000000001324423227700144425ustar00rootroot00000000000000LibRaw-0.18.8/samples/4channels.cpp000066400000000000000000000133321324423227700170270ustar00rootroot00000000000000/* -*- C++ -*- * File: 4channels.cpp * Copyright 2008-2017 LibRaw LLC (info@libraw.org) * Created: Mon Feb 09, 2009 * * LibRaw sample * Generates 4 TIFF file from RAW data, one file per channel * LibRaw is free software; you can redistribute it and/or modify it under the terms of the one of two licenses as you choose: 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 (See file LICENSE.LGPL provided in LibRaw distribution archive for details). 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 (See file LICENSE.CDDL provided in LibRaw distribution archive for details). */ #include #include #include #ifndef WIN32 #include #else #include #endif #include "libraw/libraw.h" #ifdef WIN32 #define snprintf _snprintf #endif int main(int ac, char *av[]) { int i, ret; int autoscale=0,black_subtraction=1, use_gamma=0; char outfn[1024]; LibRaw RawProcessor; if(ac<2) { usage: printf( "4channels - LibRaw %s sample. %d cameras supported\n" "Usage: %s [-s N] [-g] [-A] [-B] [-N] raw-files....\n" "\t-s N - select Nth image in file (default=0)\n" "\t-g - use gamma correction with gamma 2.2 (not precise,use for visual inspection only)\n" "\t-A - autoscaling (by integer factor)\n" "\t-B - no black subtraction\n" ,LibRaw::version(), LibRaw::cameraCount(), av[0]); return 0; } #define P1 RawProcessor.imgdata.idata #define S RawProcessor.imgdata.sizes #define C RawProcessor.imgdata.color #define T RawProcessor.imgdata.thumbnail #define P2 RawProcessor.imgdata.other #define OUT RawProcessor.imgdata.params OUT.output_bps=16; OUT.output_tiff=1; OUT.user_flip=0; OUT.no_auto_bright = 1; OUT.half_size=1; for (i=1;i0 && max< 1<<15) { scale = (1<<16)/max; printf("Scaling with multiplier=%d (max=%d)\n",scale,max); for(int j=0; j0) { for (int rc = 0; rc < S.iheight*S.iwidth; rc++) RawProcessor.imgdata.image[rc][0] = RawProcessor.imgdata.image[rc][layer]; } char lname[8]; if(isrgb) { snprintf(lname,7,"%c",((char*)("RGBG"))[layer]); if(layer==3) strcat(lname,"2"); } else snprintf(lname,7,"%c",((char*)("GCMY"))[layer]); if(OUT.shot_select) snprintf(outfn,sizeof(outfn),"%s-%d.%s.tiff",av[i],OUT.shot_select,lname); else snprintf(outfn,sizeof(outfn),"%s.%s.tiff",av[i],lname); printf("Writing file %s\n",outfn); if( LIBRAW_SUCCESS != (ret = RawProcessor.dcraw_ppm_tiff_writer(outfn))) fprintf(stderr,"Cannot write %s: %s\n",outfn,libraw_strerror(ret)); } } return 0; } LibRaw-0.18.8/samples/Makefile000066400000000000000000000000411324423227700160750ustar00rootroot00000000000000all: (cd ..; make all_samples) LibRaw-0.18.8/samples/dcraw_emu.cpp000066400000000000000000000502771324423227700171270ustar00rootroot00000000000000/* -*- C++ -*- * File: dcraw_emu.cpp * Copyright 2008-2017 LibRaw LLC (info@libraw.org) * Created: Sun Mar 23, 2008 * * LibRaw simple C++ API sample: almost complete dcraw emulator * LibRaw is free software; you can redistribute it and/or modify it under the terms of the one of two licenses as you choose: 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 (See file LICENSE.LGPL provided in LibRaw distribution archive for details). 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 (See file LICENSE.CDDL provided in LibRaw distribution archive for details). */ #ifdef WIN32 // suppress sprintf-related warning. sprintf() is permitted in sample code #define _CRT_SECURE_NO_WARNINGS #endif #include #include #include #include #include #ifndef WIN32 #include #include #include #else #include #endif #include #include #include "libraw/libraw.h" #ifdef WIN32 #define snprintf _snprintf #include #else #define O_BINARY 0 #endif #ifdef USE_DNGSDK #include "dng_host.h" #include "dng_negative.h" #include "dng_simple_image.h" #include "dng_info.h" #endif void usage(const char *prog) { printf("dcraw_emu: almost complete dcraw emulator\n"); printf("Usage: %s [OPTION]... [FILE]...\n", prog); printf( "-c float-num Set adjust maximum threshold (default 0.75)\n" "-v Verbose: print progress messages (repeated -v will add verbosity)\n" "-w Use camera white balance, if possible\n" "-a Average the whole image for white balance\n" "-A Average a grey box for white balance\n" "-r Set custom white balance\n" "+M/-M Use/don't use an embedded color matrix\n" "-C Correct chromatic aberration\n" "-P Fix the dead pixels listed in this file\n" "-K Subtract dark frame (16-bit raw PGM)\n" "-k Set the darkness level\n" "-S Set the saturation level\n" "-R Set raw processing options to num\n" "-n Set threshold for wavelet denoising\n" "-H [0-9] Highlight mode (0=clip, 1=unclip, 2=blend, 3+=rebuild)\n" "-t [0-7] Flip image (0=none, 3=180, 5=90CCW, 6=90CW)\n" "-o [0-6] Output colorspace (raw,sRGB,Adobe,Wide,ProPhoto,XYZ,ACES)\n" #ifndef NO_LCMS "-o file Output ICC profile\n" "-p file Camera input profile (use \'embed\' for embedded profile)\n" #endif "-j Don't stretch or rotate raw pixels\n" "-W Don't automatically brighten the image\n" "-b Adjust brightness (default = 1.0)\n" "-q N Set the interpolation quality:\n" " 0 - linear, 1 - VNG, 2 - PPG, 3 - AHD, 4 - DCB\n" #ifdef LIBRAW_DEMOSAIC_PACK_GPL2 " 5 - modified AHD,6 - AFD (5pass), 7 - VCD, 8 - VCD+AHD, 9 - LMMSE\n" #endif #ifdef LIBRAW_DEMOSAIC_PACK_GPL3 " 10-AMaZE\n" #endif "-h Half-size color image (twice as fast as \"-q 0\")\n" "-f Interpolate RGGB as four colors\n" "-m Apply a 3x3 median filter to R-G and B-G\n" "-s [0..N-1] Select one raw image from input file\n" "-4 Linear 16-bit, same as \"-6 -W -g 1 1\n" "-6 Write 16-bit linear instead of 8-bit with gamma\n" "-g pow ts Set gamma curve to gamma pow and toe slope ts (default = 2.222 4.5)\n" "-T Write TIFF instead of PPM\n" "-G Use green_matching() filter\n" "-B use cropbox\n" "-F Use FILE I/O instead of streambuf API\n" "-timing Detailed timing report\n" "-fbdd N 0 - disable FBDD noise reduction (default), 1 - light FBDD, 2 - full\n" "-dcbi N Number of extra DCD iterations (default - 0)\n" "-dcbe DCB color enhance\n" #ifdef LIBRAW_DEMOSAIC_PACK_GPL2 "-eeci EECI refine for mixed VCD/AHD (q=8)\n" "-esmed N Number of edge-sensitive median filter passes (only if q=8)\n" #endif #ifdef LIBRAW_DEMOSAIC_PACK_GPL3 //"-amazeca Use AMaZE chromatic aberrations refine (only if q=10)\n" "-acae Use chromatic aberrations correction\n" //modifJD "-aline reduction of line noise\n" "-aclean clean CFA\n" "-agreen equilibrate green\n" #endif "-aexpo exposure correction\n" "-apentax4shot enables merge of 4-shot pentax files\n" "-apentax4shotorder 3102 sets pentax 4-shot alignment order\n" // WF "-dbnd debanding\n" #ifndef WIN32 "-mmap Use mmap()-ed buffer instead of plain FILE I/O\n" #endif "-mem Use memory buffer instead of FILE I/O\n" "-disars Do not use RawSpeed library\n" "-disinterp Do not run interpolation step\n" "-dsrawrgb1 Disable YCbCr to RGB conversion for sRAW (Cb/Cr interpolation enabled)\n" "-dsrawrgb2 Disable YCbCr to RGB conversion for sRAW (Cb/Cr interpolation disabled)\n" "-disadcf Do not use dcraw Foveon code even if compiled with demosaic-pack-GPL2\n" #ifdef USE_DNGSDK "-dngsdk Use Adobe DNG SDK for DNG decode\n" "-dngflags N set DNG decoding options to value N\n" #endif ); exit(1); } static int verbosity=0; int cnt=0; int my_progress_callback(void *d,enum LibRaw_progress p,int iteration, int expected) { char *passed = (char*)(d?d:"default string"); // data passed to callback at set_callback stage if(verbosity>2) // verbosity set by repeat -v switches { printf("CB: %s pass %d of %d (data passed=%s)\n",libraw_strprogress(p),iteration,expected,passed); } else if (iteration == 0) // 1st iteration of each step printf("Starting %s (expecting %d iterations)\n", libraw_strprogress(p),expected); else if (iteration == expected-1) printf("%s finished\n",libraw_strprogress(p)); /// if(++cnt>10) return 1; // emulate user termination on 10-th callback call return 0; // always return 0 to continue processing } // timer #ifndef WIN32 static struct timeval start,end; void timerstart(void) { gettimeofday(&start,NULL); } void timerprint(const char *msg,const char *filename) { gettimeofday(&end,NULL); float msec = (end.tv_sec - start.tv_sec)*1000.0f + (end.tv_usec - start.tv_usec)/1000.0f; printf("Timing: %s/%s: %6.3f msec\n",filename,msg,msec); } #else LARGE_INTEGER start; void timerstart(void) { QueryPerformanceCounter(&start); } void timerprint(const char *msg, const char *filename) { LARGE_INTEGER unit,end; QueryPerformanceCounter(&end); QueryPerformanceFrequency(&unit); float msec = (float)(end.QuadPart - start.QuadPart); msec /= (float)unit.QuadPart/1000.0f; printf("Timing: %s/%s: %6.3f msec\n",filename,msg,msec); } #endif int main(int argc, char *argv[]) { if(argc==1) usage(argv[0]); LibRaw RawProcessor; int i,arg,c,ret; char opm,opt,*cp,*sp; int use_bigfile=0, use_timing=0,use_mem=0; #ifdef USE_DNGSDK dng_host *dnghost = NULL; #endif #ifndef WIN32 int msize = 0,use_mmap=0; #endif void *iobuffer=0; #ifdef OUT #undef OUT #endif #define OUT RawProcessor.imgdata.params argv[argc] = (char*)""; for (arg=1; (((opm = argv[arg][0]) - 2) | 2) == '+'; ) { char *optstr = argv[arg]; opt = argv[arg++][1]; if ((cp = strchr (sp=(char*)"cnbrkStqmHABCgU", opt))!=0) for (i=0; i < "111411111144221"[cp-sp]-'0'; i++) if (!isdigit(argv[arg+i][0]) && !optstr[2]) { fprintf (stderr,"Non-numeric argument to \"-%c\"\n", opt); return 1; } if(!strchr("ftdeam",opt) && argv[arg-1][2]) fprintf (stderr,"Unknown option \"%s\".\n",argv[arg-1]); switch (opt) { case 'v': verbosity++; break; case 'G': OUT.green_matching = 1; break; case 'c': OUT.adjust_maximum_thr = (float)atof(argv[arg++]); break; case 'U': OUT.auto_bright_thr = (float)atof(argv[arg++]); break; case 'n': OUT.threshold = (float)atof(argv[arg++]); break; case 'b': OUT.bright = (float)atof(argv[arg++]); break; case 'P': OUT.bad_pixels = argv[arg++]; break; case 'K': OUT.dark_frame = argv[arg++]; break; case 'r': for(c=0;c<4;c++) OUT.user_mul[c] = (float)atof(argv[arg++]); break; case 'C': OUT.aber[0] = 1 / atof(argv[arg++]); OUT.aber[2] = 1 / atof(argv[arg++]); break; case 'g': OUT.gamm[0] = 1 / atof(argv[arg++]); OUT.gamm[1] = atof(argv[arg++]); break; case 'k': OUT.user_black = atoi(argv[arg++]); break; case 'S': OUT.user_sat = atoi(argv[arg++]); break; case 'R': OUT.raw_processing_options = atoi(argv[arg++]); break; case 't': if(!strcmp(optstr,"-timing")) use_timing=1; else if(!argv[arg-1][2]) OUT.user_flip = atoi(argv[arg++]); else fprintf (stderr,"Unknown option \"%s\".\n",argv[arg-1]); break; case 'q': OUT.user_qual = atoi(argv[arg++]); break; case 'm': #ifndef WIN32 if(!strcmp(optstr,"-mmap")) use_mmap = 1; else #endif if(!strcmp(optstr,"-mem")) use_mem = 1; else { if(!argv[arg-1][2]) OUT.med_passes = atoi(argv[arg++]); else fprintf (stderr,"Unknown option \"%s\".\n",argv[arg-1]); } break; case 'H': OUT.highlight = atoi(argv[arg++]); break; case 's': OUT.shot_select = abs(atoi(argv[arg++])); break; case 'o': if(isdigit(argv[arg][0]) && !isdigit(argv[arg][1])) OUT.output_color = atoi(argv[arg++]); #ifndef NO_LCMS else OUT.output_profile = argv[arg++]; break; case 'p': OUT.camera_profile = argv[arg++]; #endif break; case 'h': OUT.half_size = 1; break; case 'f': if(!strcmp(optstr,"-fbdd")) OUT.fbdd_noiserd = atoi(argv[arg++]); else { if(!argv[arg-1][2]) OUT.four_color_rgb = 1; else fprintf (stderr,"Unknown option \"%s\".\n",argv[arg-1]); } break; case 'A': for(c=0; c<4;c++) OUT.greybox[c] = atoi(argv[arg++]); break; case 'B': for(c=0; c<4;c++) OUT.cropbox[c] = atoi(argv[arg++]); break; case 'a': if(!strcmp(optstr,"-aexpo")) { OUT.exp_correc = 1; OUT.exp_shift = (float)atof(argv[arg++]); OUT.exp_preser = (float)atof(argv[arg++]); } else if(!strcmp(optstr,"-apentax4shot")) { OUT.raw_processing_options |= LIBRAW_PROCESSING_PENTAX_PS_ALLFRAMES; } else if(!strcmp(optstr,"-apentax4shotorder")) { strncpy(OUT.p4shot_order,argv[arg++],5); } else #ifdef LIBRAW_DEMOSAIC_PACK_GPL3 if(!strcmp(optstr,"-acae")) { OUT.ca_correc = 1; OUT.cared = (float)atof(argv[arg++]); OUT.cablue = (float)atof(argv[arg++]); } else if(!strcmp(optstr,"-aline")) { OUT.cfaline = 1; OUT.linenoise = (float)atof(argv[arg++]); } else if(!strcmp(optstr,"-aclean")) { OUT.cfa_clean = 1; OUT.lclean = (float)atof(argv[arg++]); OUT.cclean = (float)atof(argv[arg++]); } else if(!strcmp(optstr,"-agreen")) { OUT.cfa_green = 1; OUT.green_thresh =(float)atof(argv[arg++]); } else #endif if(!argv[arg-1][2]) OUT.use_auto_wb = 1; else fprintf (stderr,"Unknown option \"%s\".\n",argv[arg-1]); break; case 'w': OUT.use_camera_wb = 1; break; case 'M': OUT.use_camera_matrix = (opm == '+'); break; case 'j': OUT.use_fuji_rotate = 0; break; case 'W': OUT.no_auto_bright = 1; break; case 'T': OUT.output_tiff = 1; break; case '4': OUT.gamm[0] = OUT.gamm[1] = OUT.no_auto_bright = 1; /* no break here! */ case '6': OUT.output_bps = 16; break; case 'F': use_bigfile=1; break; case 'd': if(!strcmp(optstr,"-dcbi")) OUT.dcb_iterations = atoi(argv[arg++]); else if(!strcmp(optstr,"-disars")) OUT.use_rawspeed=0; else if(!strcmp(optstr,"-disadcf")) OUT.raw_processing_options |=LIBRAW_PROCESSING_FORCE_FOVEON_X3F; else if(!strcmp(optstr,"-disinterp")) OUT.no_interpolation=1; else if(!strcmp(optstr,"-dcbe")) OUT.dcb_enhance_fl = 1; else if(!strcmp(optstr,"-dsrawrgb1")) { OUT.raw_processing_options |= LIBRAW_PROCESSING_SRAW_NO_RGB; OUT.raw_processing_options &= ~LIBRAW_PROCESSING_SRAW_NO_INTERPOLATE; } else if(!strcmp(optstr,"-dsrawrgb2")) { OUT.raw_processing_options &= ~LIBRAW_PROCESSING_SRAW_NO_RGB; OUT.raw_processing_options |= LIBRAW_PROCESSING_SRAW_NO_INTERPOLATE; } else if(!strcmp(optstr,"-dbnd")) { for(c=0; c<4; c++) OUT.wf_deband_treshold[c] = (float)atof(argv[arg++]); OUT.wf_debanding = 1; } #ifdef USE_DNGSDK else if(!strcmp(optstr,"-dngsdk")) { dnghost = new dng_host; RawProcessor.set_dng_host(dnghost); } else if(!strcmp(optstr,"-dngflags")) { OUT.use_dngsdk = atoi(argv[arg++]); } #endif else fprintf (stderr,"Unknown option \"%s\".\n",argv[arg-1]); break; #ifdef LIBRAW_DEMOSAIC_PACK_GPL2 case 'e': if(!strcmp(optstr,"-eeci")) OUT.eeci_refine = 1; else if(!strcmp(optstr,"-esmed")) OUT.es_med_passes = atoi(argv[arg++]); else fprintf (stderr,"Unknown option \"%s\".\n",argv[arg-1]); break; #endif default: fprintf (stderr,"Unknown option \"-%c\".\n", opt); return 1; } } #ifndef WIN32 putenv ((char*)"TZ=UTC"); // dcraw compatibility, affects TIFF datestamp field #else _putenv ((char*)"TZ=UTC"); // dcraw compatibility, affects TIFF datestamp field #endif #define P1 RawProcessor.imgdata.idata #define S RawProcessor.imgdata.sizes #define C RawProcessor.imgdata.color #define T RawProcessor.imgdata.thumbnail #define P2 RawProcessor.imgdata.other if(verbosity>1) RawProcessor.set_progress_handler(my_progress_callback,(void*)"Sample data passed"); #ifdef LIBRAW_USE_OPENMP if(verbosity) printf ("Using %d threads\n", omp_get_max_threads()); #endif for ( ; arg < argc; arg++) { char outfn[1024]; if(verbosity) printf("Processing file %s\n",argv[arg]); timerstart(); #ifndef WIN32 if(use_mmap) { int file = open(argv[arg],O_RDONLY); struct stat st; if(file<0) { fprintf(stderr,"Cannot open %s: %s\n",argv[arg],strerror(errno)); continue; } if(fstat(file,&st)) { fprintf(stderr,"Cannot stat %s: %s\n",argv[arg],strerror(errno)); close(file); continue; } int pgsz = getpagesize(); msize = ((st.st_size+pgsz-1)/pgsz)*pgsz; iobuffer = mmap(NULL,msize,PROT_READ,MAP_PRIVATE,file,0); if(!iobuffer) { fprintf(stderr,"Cannot mmap %s: %s\n",argv[arg],strerror(errno)); close(file); continue; } close(file); if( (ret = RawProcessor.open_buffer(iobuffer,st.st_size) != LIBRAW_SUCCESS)) { fprintf(stderr,"Cannot open_buffer %s: %s\n",argv[arg],libraw_strerror(ret)); continue; // no recycle b/c open file will recycle itself } } else #endif if (use_mem) { int file = open(argv[arg],O_RDONLY|O_BINARY); struct stat st; if(file<0) { fprintf(stderr,"Cannot open %s: %s\n",argv[arg],strerror(errno)); continue; } if(fstat(file,&st)) { fprintf(stderr,"Cannot stat %s: %s\n",argv[arg],strerror(errno)); close(file); continue; } if(!(iobuffer = malloc(st.st_size))) { fprintf(stderr,"Cannot allocate %d kbytes for memory buffer\n",(int)(st.st_size/1024)); close(file); continue; } int rd; if(st.st_size!=(rd=read(file,iobuffer,st.st_size))) { fprintf(stderr,"Cannot read %d bytes instead of %d to memory buffer\n",(int)rd,(int)st.st_size); close(file); free(iobuffer); continue; } close(file); if( (ret = RawProcessor.open_buffer(iobuffer,st.st_size)) != LIBRAW_SUCCESS) { fprintf(stderr,"Cannot open_buffer %s: %s\n",argv[arg],libraw_strerror(ret)); free(iobuffer); continue; // no recycle b/c open file will recycle itself } } else { if(use_bigfile) // force open_file switch to bigfile processing ret = RawProcessor.open_file(argv[arg],1); else ret = RawProcessor.open_file(argv[arg]); if( ret != LIBRAW_SUCCESS) { fprintf(stderr,"Cannot open %s: %s\n",argv[arg],libraw_strerror(ret)); continue; // no recycle b/c open_file will recycle itself } } if(use_timing) timerprint("LibRaw::open_file()",argv[arg]); timerstart(); if( (ret = RawProcessor.unpack() ) != LIBRAW_SUCCESS) { fprintf(stderr,"Cannot unpack %s: %s\n",argv[arg],libraw_strerror(ret)); continue; } if(use_timing) timerprint("LibRaw::unpack()",argv[arg]); timerstart(); if (LIBRAW_SUCCESS != (ret = RawProcessor.dcraw_process())) { fprintf(stderr,"Cannot do postpocessing on %s: %s\n",argv[arg],libraw_strerror(ret)); if(LIBRAW_FATAL_ERROR(ret)) continue; } if(use_timing) timerprint("LibRaw::dcraw_process()",argv[arg]); snprintf(outfn,sizeof(outfn), "%s.%s", argv[arg], OUT.output_tiff ? "tiff" : (P1.colors>1?"ppm":"pgm")); if(verbosity) { printf("Writing file %s\n",outfn); } if( LIBRAW_SUCCESS != (ret = RawProcessor.dcraw_ppm_tiff_writer(outfn))) fprintf(stderr,"Cannot write %s: %s\n",outfn,libraw_strerror(ret)); #ifndef WIN32 if(use_mmap && iobuffer) { munmap(iobuffer,msize); iobuffer=0; } #endif else if(use_mem && iobuffer) { free(iobuffer); iobuffer = 0; } RawProcessor.recycle(); // just for show this call } #ifdef USE_DNGSDK if(dnghost) delete dnghost; #endif return 0; } LibRaw-0.18.8/samples/dcraw_half.c000066400000000000000000000040121324423227700166750ustar00rootroot00000000000000/* -*- C++ -*- * File: dcraw_half.c * Copyright 2008-2017 LibRaw LLC (info@libraw.org) * Created: Sat Mar 8 , 2008 * * LibRaw C API sample: emulates "dcraw -h" * LibRaw is free software; you can redistribute it and/or modify it under the terms of the one of two licenses as you choose: 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 (See file LICENSE.LGPL provided in LibRaw distribution archive for details). 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 (See file LICENSE.CDDL provided in LibRaw distribution archive for details). */ #include #include #include #include #include "libraw/libraw.h" #define HANDLE_FATAL_ERROR(ret)\ if(ret)\ {\ fprintf(stderr,"%s: libraw %s\n",av[i],libraw_strerror(ret));\ if(LIBRAW_FATAL_ERROR(ret))\ exit(1); \ }\ #define HANDLE_ALL_ERRORS(ret)\ if(ret)\ {\ fprintf(stderr,"%s: libraw %s\n",av[i],libraw_strerror(ret));\ continue; \ }\ int main(int ac, char *av[]) { int i; libraw_data_t *iprc = libraw_init(0); if(!iprc) { fprintf(stderr,"Cannot create libraw handle\n"); exit(1); } iprc->params.half_size = 1; /* dcraw -h */ for (i=1;iidata.make,iprc->idata.model); ret = libraw_unpack(iprc); HANDLE_ALL_ERRORS(ret); ret = libraw_dcraw_process(iprc); HANDLE_ALL_ERRORS(ret); strcpy(outfn,av[i]); strcat(outfn,".ppm"); printf("Writing to %s\n",outfn); ret = libraw_dcraw_ppm_tiff_writer(iprc,outfn); HANDLE_FATAL_ERROR(ret); } libraw_close(iprc); return 0; } LibRaw-0.18.8/samples/half_mt.c000066400000000000000000000112511324423227700162200ustar00rootroot00000000000000/* -*- C++ -*- * File: halt_mt.c * Copyright 2008-2017 LibRaw LLC (info@libraw.org) * Created: Sat Mar 8, 2008 * * LibRaw C API mutithreaded sample: emulates call to "dcraw -h [-w] [-a] [-v]" * LibRaw is free software; you can redistribute it and/or modify it under the terms of the one of two licenses as you choose: 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 (See file LICENSE.LGPL provided in LibRaw distribution archive for details). 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 (See file LICENSE.CDDL provided in LibRaw distribution archive for details). */ #include #include #include #include #include #include "libraw/libraw.h" #define HANDLE_ERRORS(ret) do { \ if(ret) \ { \ fprintf(stderr,"%s: %s\n",fn,libraw_strerror(ret)); \ if(LIBRAW_FATAL_ERROR(ret)) \ { \ libraw_close(iprc); \ return NULL ; \ } \ } \ }while(0) int verbose=0,use_camera_wb=0,use_auto_wb=0,tiff_mode=0; pthread_mutex_t qm; char **queue=NULL; size_t qsize=0,qptr=0; char *get_next_file() { char *ret; if(!queue) return NULL; if(qptr>=qsize) return NULL; pthread_mutex_lock(&qm); ret = queue[qptr++]; pthread_mutex_unlock(&qm); return ret; } void * process_files(void *q) { int ret; int count=0; char outfn[1024], *fn; libraw_data_t *iprc = libraw_init(0); if(!iprc) { fprintf(stderr,"Cannot create libraw handle\n"); return NULL ; } while((fn = get_next_file())) { iprc->params.half_size = 1; /* dcraw -h */ iprc->params.use_camera_wb = use_camera_wb; iprc->params.use_auto_wb = use_auto_wb; iprc->params.output_tiff = tiff_mode; ret = libraw_open_file(iprc,fn); if(verbose) fprintf(stderr,"%s: %s/%s\n",fn,iprc->idata.make,iprc->idata.model); HANDLE_ERRORS(ret); ret = libraw_unpack(iprc); HANDLE_ERRORS(ret); ret = libraw_dcraw_process(iprc); HANDLE_ERRORS(ret); snprintf(outfn,1023,"%s.%s",fn,tiff_mode?"tiff":"ppm"); if(verbose) fprintf(stderr,"Writing file %s\n",outfn); ret = libraw_dcraw_ppm_tiff_writer(iprc,outfn); HANDLE_ERRORS(ret); count++; } libraw_close(iprc); return NULL; } void usage(const char*p) { printf("%s: Multi-threaded LibRaw sample app. Emulates dcraw -h [-w] [-a]\n",p); printf( "Options:\n" "-J n - set parrallel job coun (default 2)\n" "-v - verbose\n" "-w - use camera white balance\n" "-a - average image for white balance\n"); exit(1); } int show_files(void *q) { char *p; int cnt = 0; while((p = get_next_file())) { printf("%s\n",p); cnt++; } return cnt; } int main(int ac, char *av[]) { int i, max_threads = 2; pthread_t *threads; if(ac<2) usage(av[0]); queue = calloc(ac-1,sizeof(queue[0])); for (i=1;i #include #include #include #include #include "libraw/libraw.h" #ifdef WIN32 #define snprintf _snprintf #endif #define HANDLE_ERRORS(ret) do { \ if(ret) \ { \ fprintf(stderr,"%s: %s\n",fn,libraw_strerror(ret)); \ if(LIBRAW_FATAL_ERROR(ret)) \ { \ libraw_close(iprc); \ return -1; \ } \ } \ }while(0) // global settings int verbose=0,use_camera_wb=0,use_auto_wb=0,tiff_mode=0; // global file queue HANDLE qmutex; char **queue=NULL; size_t qsize=0,qptr=0; char *get_next_file() { char *ret; DWORD dwWaitResult; if(!queue) return NULL; if(qptr>=qsize) return NULL; dwWaitResult = WaitForSingleObject( qmutex, // handle to mutex INFINITE); // no time-out interval switch (dwWaitResult) { // The thread got ownership of the mutex case WAIT_OBJECT_0: ret = queue[qptr++]; ReleaseMutex(qmutex); break; case WAIT_ABANDONED: return NULL; // cannot obtain the lock }; return ret; } // thread routine int process_files(void *q) { int ret; int count=0; char outfn[1024], *fn; libraw_data_t *iprc = libraw_init(0); if(!iprc) { fprintf(stderr,"Cannot create libraw handle\n"); return -1; } while((fn = get_next_file())) { iprc->params.half_size = 1; /* dcraw -h */ iprc->params.use_camera_wb = use_camera_wb; iprc->params.use_auto_wb = use_auto_wb; iprc->params.output_tiff = tiff_mode; ret = libraw_open_file(iprc,fn); if(verbose) fprintf(stderr,"%s: %s/%s\n",fn,iprc->idata.make,iprc->idata.model); HANDLE_ERRORS(ret); ret = libraw_unpack(iprc); HANDLE_ERRORS(ret); ret = libraw_dcraw_process(iprc); HANDLE_ERRORS(ret); snprintf(outfn,1023,"%s.%s",fn,tiff_mode?"tif":"ppm"); if(verbose) fprintf(stderr,"Writing file %s\n",outfn); ret = libraw_dcraw_ppm_tiff_writer(iprc,outfn); HANDLE_ERRORS(ret); count++; } libraw_close(iprc); printf("Processed %d files\n",count); return 0; } void usage(const char*p) { printf( "Options:\n" "-J n - set parrallel job coun (default 2)\n" "-v - verbose\n" "-w - use camera white balance\n" "-T - output TIFF instead of PPM\n" "-a - average image for white balance\n"); exit(1); } int show_files(void *q) { char *p; int cnt = 0; while(p = get_next_file()) { printf("%s\n",p); cnt++; } return cnt; } int main(int ac, char *av[]) { int i,max_threads = 2; HANDLE *threads; DWORD ThreadID; if(ac<2) usage(av[0]); queue = calloc(ac-1,sizeof(queue[0])); for (i=1;i #include #include #include "libraw/libraw.h" #ifdef WIN32 #define snprintf _snprintf #include #pragma comment(lib, "ws2_32.lib") #else #include #endif // no error reporting, only params check void write_ppm(libraw_processed_image_t *img, const char *basename) { if(!img) return; // type SHOULD be LIBRAW_IMAGE_BITMAP, but we'll check if(img->type != LIBRAW_IMAGE_BITMAP) return; // only 3-color images supported... if(img->colors != 3) return; char fn[1024]; snprintf(fn,1024,"%s.ppm",basename); FILE *f = fopen(fn,"wb"); if(!f) return; fprintf (f, "P6\n%d %d\n%d\n", img->width, img->height, (1 << img->bits)-1); /* NOTE: data in img->data is not converted to network byte order. So, we should swap values on some architectures for dcraw compatibility (unfortunately, xv cannot display 16-bit PPMs with network byte order data */ #define SWAP(a,b) { a ^= b; a ^= (b ^= a); } if (img->bits == 16 && htons(0x55aa) != 0x55aa) for(unsigned i=0; i< img->data_size; i+=2) SWAP(img->data[i],img->data[i+1]); #undef SWAP fwrite(img->data,img->data_size,1,f); fclose(f); } void write_thumb(libraw_processed_image_t *img, const char *basename) { if(!img) return; if(img->type == LIBRAW_IMAGE_BITMAP) { char fnt[1024]; snprintf(fnt,1024,"%s.thumb",basename); write_ppm(img,fnt); } else if (img->type == LIBRAW_IMAGE_JPEG) { char fn[1024]; snprintf(fn,1024,"%s.thumb.jpg",basename); FILE *f = fopen(fn,"wb"); if(!f) return; fwrite(img->data,img->data_size,1,f); fclose(f); } } int main(int ac, char *av[]) { int i, ret, output_thumbs=0; // don't use fixed size buffers in real apps! LibRaw RawProcessor; if(ac<2) { printf( "mem_image - LibRaw sample, to illustrate work for memory buffers. Emulates dcraw [-4] [-1] [-e] [-h]\n" "Usage: %s [-D] [-T] [-v] [-e] raw-files....\n" "\t-6 - output 16-bit PPM\n" "\t-4 - linear 16-bit data\n" "\t-e - extract thumbnails (same as dcraw -e in separate run)\n", "\t-h - use half_size\n"); return 0; } putenv ((char*)"TZ=UTC"); // dcraw compatibility, affects TIFF datestamp field #define P1 RawProcessor.imgdata.idata #define S RawProcessor.imgdata.sizes #define C RawProcessor.imgdata.color #define T RawProcessor.imgdata.thumbnail #define P2 RawProcessor.imgdata.other #define OUT RawProcessor.imgdata.params for (i=1;i #include #include #ifndef WIN32 #include #include #include #include #endif #include "libraw/libraw.h" #ifdef WIN32 #define snprintf _snprintf #endif int process_once(LibRaw& RawProcessor, int half_mode, int camera_wb, int auto_wb, int suffix, int user_flip,char *fname) { char outfn[1024]; RawProcessor.imgdata.params.half_size = half_mode; RawProcessor.imgdata.params.use_camera_wb = camera_wb; RawProcessor.imgdata.params.use_auto_wb = auto_wb; RawProcessor.imgdata.params.user_flip = user_flip; int ret = RawProcessor.dcraw_process(); if(LIBRAW_SUCCESS !=ret) { fprintf(stderr,"Cannot do postpocessing on %s: %s\n", fname,libraw_strerror(ret)); return ret; } snprintf(outfn,sizeof(outfn),"%s.%d.%s", fname, suffix, (RawProcessor.imgdata.idata.colors>1?"ppm":"pgm")); printf("Writing file %s\n",outfn); if( LIBRAW_SUCCESS != (ret = RawProcessor.dcraw_ppm_tiff_writer(outfn))) fprintf(stderr,"Cannot write %s: %s\n",outfn,libraw_strerror(ret)); return ret; } int main(int ac, char *av[]) { int i, ret; LibRaw RawProcessor; if(ac<2) { printf( "multirender_test - LibRaw %s sample. Performs 4 different renderings of one file\n" " %d cameras supported\n" "Usage: %s raw-files....\n" ,LibRaw::version(), LibRaw::cameraCount(), av[0]); return 0; } for (i=1;i #include #include #ifndef WIN32 #include #include #include #else #include #endif #include "libraw/libraw.h" void timerstart(void); float timerend(void); int main(int argc, char *argv[]) { int i, ret,rep=1; LibRaw RawProcessor; #ifdef OUT #undef OUT #endif #define OUT RawProcessor.imgdata.params #define S RawProcessor.imgdata.sizes if(argc<2) { printf( "postprocessing benchmark: LibRaw %s sample, %d cameras supported\n" "Measures postprocessing speed with different options\n" "Usage: %s [-a] [-H N] [-q N] [-h] [-m N] [-n N] [-s N] [-B x y w h] [-R N]\n" "-a average image for white balance\n" "-H Highlight mode (0=clip, 1=unclip, 2=blend, 3+=rebuild)\n" "-q Set the interpolation quality\n" "-h Half-size color image\n" "-m Apply a num-passes 3x3 median filter to R-G and B-G\n" "-n Set threshold for wavelet denoising\n" "-s Select one raw image from input file\n" "-B Crop output image\n" "-R Number of repetitions\n" "-c Do not use rawspeed\n" ,LibRaw::version(), LibRaw::cameraCount(), argv[0]); return 0; } char opm,opt,*cp,*sp; int arg,c; int shrink = 0; argv[argc] = (char*)""; for (arg=1; (((opm = argv[arg][0]) - 2) | 2) == '+'; ) { char *optstr = argv[arg]; opt = argv[arg++][1]; if ((cp = strchr (sp=(char*)"HqmnsBR", opt))!=0) for (i=0; i < "1111141"[cp-sp]-'0'; i++) if (!isdigit(argv[arg+i][0]) && !optstr[2]) { fprintf (stderr,"Non-numeric argument to \"-%c\"\n", opt); return 1; } switch (opt) { case 'a': OUT.use_auto_wb = 1; break; case 'H': OUT.highlight = atoi(argv[arg++]); break; case 'q': OUT.user_qual = atoi(argv[arg++]); break; case 'h': OUT.half_size = 1; OUT.four_color_rgb = 1; shrink = 1; break; case 'm': OUT.med_passes = atoi(argv[arg++]); break; case 'n': OUT.threshold = (float)atof(argv[arg++]); break; case 's': OUT.shot_select = abs(atoi(argv[arg++])); break; case 'B': for(c=0; c<4;c++) OUT.cropbox[c] = atoi(argv[arg++]); break; case 'R': rep = abs(atoi(argv[arg++])); if(rep<1) rep = 1; break; case 'c': OUT.use_rawspeed = 0; break; default: fprintf (stderr,"Unknown option \"-%c\".\n", opt); return 1; } } for ( ; arg < argc; arg++) { printf("Processing file %s\n",argv[arg]); timerstart(); if( (ret = RawProcessor.open_file(argv[arg])) != LIBRAW_SUCCESS) { fprintf(stderr,"Cannot open_file %s: %s\n",argv[arg],libraw_strerror(ret)); continue; // no recycle b/c open file will recycle itself } if( (ret = RawProcessor.unpack() ) != LIBRAW_SUCCESS) { fprintf(stderr,"Cannot unpack %s: %s\n",argv[arg],libraw_strerror(ret)); continue; } float qsec = timerend(); printf("\n%.1f msec for unpack\n",qsec); float mpix,rmpix; timerstart(); for(c=0; c < rep; c++) { if( (ret = RawProcessor.dcraw_process() ) != LIBRAW_SUCCESS) { fprintf(stderr,"Cannot postprocess %s: %s\n",argv[arg],libraw_strerror(ret)); break; } libraw_processed_image_t *p = RawProcessor.dcraw_make_mem_image(); if(p) RawProcessor.dcraw_clear_mem(p); RawProcessor.free_image(); } float msec = timerend()/(float)rep; if( (ret = RawProcessor.adjust_sizes_info_only() ) != LIBRAW_SUCCESS) { fprintf(stderr,"Cannot adjust sizes for %s: %s\n",argv[arg],libraw_strerror(ret)); break; } rmpix = (S.iwidth*S.iheight)/1000000.0f; if(c==rep) // no failure { unsigned int crop[4]; for(int i=0;i<4;i++) crop[i] = (OUT.cropbox[i])>>shrink; if(crop[0]+crop[2]>S.iwidth) crop[2] = S.iwidth-crop[0]; if(crop[1]+crop[3]>S.iheight) crop[3] = S.iheight-crop[1]; mpix = float(crop[2]*crop[3])/1000000.0f; float mpixsec = mpix*1000.0f/msec; printf( "Performance: %.2f Mpix/sec\n" "File: %s, Frame: %d %.1f total Mpix, %.1f msec\n" "Params: WB=%s Highlight=%d Qual=%d HalfSize=%s Median=%d Wavelet=%.0f\n" "Crop: %u-%u:%ux%u, active Mpix: %.2f, %.1f frames/sec\n", mpixsec ,argv[arg],OUT.shot_select,rmpix,msec, OUT.use_auto_wb?"auto":"default",OUT.highlight,OUT.user_qual,OUT.half_size?"YES":"No", OUT.med_passes,OUT.threshold, crop[0],crop[1],crop[2],crop[3],mpix,1000.0f/msec); } } return 0; } #ifndef WIN32 static struct timeval start,end; void timerstart(void) { gettimeofday(&start,NULL); } float timerend(void) { gettimeofday(&end,NULL); float msec = (end.tv_sec - start.tv_sec)*1000.0f + (end.tv_usec - start.tv_usec)/1000.0f; return msec; } #else LARGE_INTEGER start; void timerstart(void) { QueryPerformanceCounter(&start); } float timerend() { LARGE_INTEGER unit,end; QueryPerformanceCounter(&end); QueryPerformanceFrequency(&unit); float msec = (float)(end.QuadPart - start.QuadPart); msec /= (float)unit.QuadPart/1000.0f; return msec; } #endif LibRaw-0.18.8/samples/raw-identify.cpp000066400000000000000000000517031324423227700175560ustar00rootroot00000000000000/* -*- C++ -*- * File: identify.cpp * Copyright 2008-2017 LibRaw LLC (info@libraw.org) * Created: Sat Mar 8, 2008 * * LibRaw C++ demo: emulates dcraw -i [-v] * LibRaw is free software; you can redistribute it and/or modify it under the terms of the one of two licenses as you choose: 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 (See file LICENSE.LGPL provided in LibRaw distribution archive for details). 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 (See file LICENSE.CDDL provided in LibRaw distribution archive for details). */ #include #include #include #include #include "libraw/libraw.h" #ifdef WIN32 #define snprintf _snprintf #define strcasecmp stricmp #define strncasecmp strnicmp #endif #define P1 MyCoolRawProcessor.imgdata.idata #define P2 MyCoolRawProcessor.imgdata.other #define mnLens MyCoolRawProcessor.imgdata.lens.makernotes #define exifLens MyCoolRawProcessor.imgdata.lens #define ShootingInfo MyCoolRawProcessor.imgdata.shootinginfo #define S MyCoolRawProcessor.imgdata.sizes #define O MyCoolRawProcessor.imgdata.params #define C MyCoolRawProcessor.imgdata.color #define T MyCoolRawProcessor.imgdata.thumbnail #define Canon MyCoolRawProcessor.imgdata.makernotes.canon #define Fuji MyCoolRawProcessor.imgdata.makernotes.fuji #define Oly MyCoolRawProcessor.imgdata.makernotes.olympus const char *EXIF_LightSources[] = { "Unknown", "Daylight", "Fluorescent", "Tungsten", "Flash", "Reserved", "Reserved", "Reserved", "Reserved", "Fine Weather", "Cloudy", "Shade", "Daylight Fluorescent D", "Day White Fluorescent N", "Cool White Fluorescent W", "White Fluorescent WW", "Warm White Fluorescent L", "Illuminant A", "Illuminant B", "Illuminant C", "D55", "D65", "D75", "D50", "ISO Studio Tungsten", }; /* table of fluorescents: 12 = FL-D; Daylight fluorescent (D 5700K – 7100K) (F1,F5) 13 = FL-N; Day white fluorescent (N 4600K – 5400K) (F7,F8) 14 = FL-W; Cool white fluorescent (W 3900K – 4500K) (F2,F6, office, store, warehouse) 15 = FL-WW; White fluorescent (WW 3200K – 3700K) (F3, residential) 16 = FL-L; Soft/Warm white fluorescent (L 2600K - 3250K) (F4, kitchen, bath) */ const char *WB_LightSources[] = { "Unknown", "Daylight", "Fluorescent", "Tungsten", "Flash", "Reserved", "Reserved", "Reserved", "Reserved", "Fine Weather", "Cloudy", "Shade", "FL-D", "FL-N", "FL-W", "FL-WW", "FL-L", "Ill. A", "Ill. B", "Ill. C", "D55", "D65", "D75", "D50", "Studio Tungsten", }; void trimSpaces(char *s) { char *p = s; if (!strncasecmp(p, "NO=", 3)) p = p+3; /* fix for Nikon D70, D70s */ int l = strlen(p); if(!l) return; while(isspace(p[l - 1])) p[--l] = 0; /* trim trailing spaces */ while(*p && isspace(*p)) ++p, --l; /* trim leading spaces */ memmove(s, p, l + 1); } int main(int ac, char *av[]) { int verbose = 0, ret,print_unpack=0,print_frame=0,print_wb=0; int compact = 0; LibRaw MyCoolRawProcessor; for (int i=1;i= 0; i -= 8) printf ("%d%c", P1.dng_version >> i & 255, i ? '.':'\n'); } printf ("\nEXIF:\n"); printf ("\tMinFocal: %0.1f mm\n", exifLens.MinFocal); printf ("\tMaxFocal: %0.1f mm\n", exifLens.MaxFocal); printf ("\tMaxAp @MinFocal: f/%0.1f\n", exifLens.MaxAp4MinFocal); printf ("\tMaxAp @MaxFocal: f/%0.1f\n", exifLens.MaxAp4MaxFocal); printf ("\tMaxAperture @CurFocal: f/%0.1f\n", exifLens.EXIF_MaxAp); printf ("\tFocalLengthIn35mmFormat: %d mm\n", exifLens.FocalLengthIn35mmFormat); printf ("\tLensMake: %s\n", exifLens.LensMake); printf ("\tLens: %s\n", exifLens.Lens); printf ("\n"); printf ("\nMakernotes:\n"); printf ("\tDriveMode: %d\n", ShootingInfo.DriveMode); printf ("\tFocusMode: %d\n", ShootingInfo.FocusMode); printf ("\tMeteringMode: %d\n", ShootingInfo.MeteringMode); printf ("\tAFPoint: %d\n", ShootingInfo.AFPoint); printf ("\tExposureMode: %d\n", ShootingInfo.ExposureMode); printf ("\tImageStabilization: %d\n", ShootingInfo.ImageStabilization); if (mnLens.body[0]) { printf("\tMF Camera Body: %s\n", mnLens.body); } printf("\tCameraFormat: %d, ", mnLens.CameraFormat); switch (mnLens.CameraFormat) { case 0: printf("Undefined\n"); break; case 1: printf("APS-C\n"); break; case 2: printf("FF\n"); break; case 3: printf("MF\n"); break; case 4: printf("APS-H\n"); break; case 5: printf("1\"\n"); break; case 8: printf("4/3\n"); break; default: printf("Unknown\n"); break; } printf("\tCameraMount: %d, ", mnLens.CameraMount); switch (mnLens.CameraMount) { case 0: printf("Undefined or Fixed Lens\n"); break; case 1: printf("Sony/Minolta A\n"); break; case 2: printf("Sony E\n"); break; case 3: printf("Canon EF\n"); break; case 4: printf("Canon EF-S\n"); break; case 5: printf("Canon EF-M\n"); break; case 6: printf("Nikon F\n"); break; case 7: printf("Nikon CX\n"); break; case 8: printf("4/3\n"); break; case 9: printf("m4/3\n"); break; case 10: printf("Pentax K\n"); break; case 11: printf("Pentax Q\n"); break; case 12: printf("Pentax 645\n"); break; case 13: printf("Fuji X\n"); break; case 14: printf("Leica M\n"); break; case 15: printf("Leica R\n"); break; case 16: printf("Leica S\n"); break; case 17: printf("Samsung NX\n"); break; case 19: printf("Samsung NX-M\n"); break; case 99: printf("Fixed Lens\n"); break; default: printf("Unknown\n"); break; } if (mnLens.LensID == -1) { printf("\tLensID: n/a\n"); } else { printf("\tLensID: %llu 0x%0llx\n", mnLens.LensID, mnLens.LensID); } printf("\tLens: %s\n", mnLens.Lens); printf("\tLensFormat: %d, ", mnLens.LensFormat); switch (mnLens.LensFormat) { case 0: printf("Undefined\n"); break; case 1: printf("APS-C\n"); break; case 2: printf("FF\n"); break; case 3: printf("MF\n"); break; case 8: printf("4/3\n"); break; default: printf("Unknown\n"); break; } printf("\tLensMount: %d, ", mnLens.LensMount); switch (mnLens.LensMount) { case 0: printf("Undefined or Fixed Lens\n"); break; case 1: printf("Sony/Minolta A\n"); break; case 2: printf("Sony E\n"); break; case 3: printf("Canon EF\n"); break; case 4: printf("Canon EF-S\n"); break; case 5: printf("Canon EF-M\n"); break; case 6: printf("Nikon F\n"); break; case 7: printf("Nikon CX\n"); break; case 8: printf("4/3\n"); break; case 9: printf("m4/3\n"); break; case 10: printf("Pentax K\n"); break; case 11: printf("Pentax Q\n"); break; case 12: printf("Pentax 645\n"); break; case 13: printf("Fuji X\n"); break; case 14: printf("Leica M\n"); break; case 15: printf("Leica R\n"); break; case 16: printf("Leica S\n"); break; case 17: printf("Samsung NX\n"); break; case 18: printf("Ricoh module\n"); break; case 99: printf("Fixed Lens\n"); break; default: printf("Unknown\n"); break; } printf("\tFocalType: %d, ", mnLens.FocalType); switch (mnLens.FocalType) { case 0: printf("Undefined\n"); break; case 1: printf("Fixed Focal\n"); break; case 2: printf("Zoom\n"); break; default: printf("Unknown\n"); break; } printf("\tLensFeatures_pre: %s\n", mnLens.LensFeatures_pre); printf("\tLensFeatures_suf: %s\n", mnLens.LensFeatures_suf); printf("\tMinFocal: %0.1f mm\n", mnLens.MinFocal); printf("\tMaxFocal: %0.1f mm\n", mnLens.MaxFocal); printf("\tMaxAp @MinFocal: f/%0.1f\n", mnLens.MaxAp4MinFocal); printf("\tMaxAp @MaxFocal: f/%0.1f\n", mnLens.MaxAp4MaxFocal); printf("\tMinAp @MinFocal: f/%0.1f\n", mnLens.MinAp4MinFocal); printf("\tMinAp @MaxFocal: f/%0.1f\n", mnLens.MinAp4MaxFocal); printf("\tMaxAp: f/%0.1f\n", mnLens.MaxAp); printf("\tMinAp: f/%0.1f\n", mnLens.MinAp); printf("\tCurFocal: %0.1f mm\n", mnLens.CurFocal); printf("\tCurAp: f/%0.1f\n", mnLens.CurAp); printf("\tMaxAp @CurFocal: f/%0.1f\n", mnLens.MaxAp4CurFocal); printf("\tMinAp @CurFocal: f/%0.1f\n", mnLens.MinAp4CurFocal); if (exifLens.makernotes.FocalLengthIn35mmFormat > 1.0f) printf("\tFocalLengthIn35mmFormat: %0.1f mm\n", exifLens.makernotes.FocalLengthIn35mmFormat); if (exifLens.nikon.NikonEffectiveMaxAp > 0.1f) printf("\tNikonEffectiveMaxAp: f/%0.1f\n", exifLens.nikon.NikonEffectiveMaxAp); if (exifLens.makernotes.LensFStops > 0.1f) printf("\tLensFStops @CurFocal: %0.2f\n", exifLens.makernotes.LensFStops); printf("\tTeleconverterID: %lld\n", mnLens.TeleconverterID); printf("\tTeleconverter: %s\n", mnLens.Teleconverter); printf("\tAdapterID: %lld\n", mnLens.AdapterID); printf("\tAdapter: %s\n", mnLens.Adapter); printf("\tAttachmentID: %lld\n", mnLens.AttachmentID); printf("\tAttachment: %s\n", mnLens.Attachment); printf ("\n"); printf ("ISO speed: %d\n", (int) P2.iso_speed); printf ("Shutter: "); if (P2.shutter > 0 && P2.shutter < 1) P2.shutter = (printf ("1/"), 1 / P2.shutter); printf ("%0.1f sec\n", P2.shutter); printf ("Aperture: f/%0.1f\n", P2.aperture); printf ("Focal length: %0.1f mm\n", P2.focal_len); printf ("Flash exposure compensation: %0.2f EV\n", P2.FlashEC); if(C.profile) printf ("Embedded ICC profile: yes, %d bytes\n", C.profile_length); else printf ("Embedded ICC profile: no\n"); if (C.baseline_exposure > -999.f) printf ("Baseline exposure: %04.3f\n", C.baseline_exposure); printf ("Number of raw images: %d\n", P1.raw_count); if (Fuji.FujiExpoMidPointShift > -999.f) printf ("Fuji Exposure shift: %04.3f\n", Fuji.FujiExpoMidPointShift); if (Fuji.FujiDynamicRange != 0xffff) printf ("Fuji Dynamic Range: %d\n", Fuji.FujiDynamicRange); if (Fuji.FujiFilmMode != 0xffff) printf ("Fuji Film Mode: %d\n", Fuji.FujiFilmMode); if (Fuji.FujiDynamicRangeSetting != 0xffff) printf ("Fuji Dynamic Range Setting: %d\n", Fuji.FujiDynamicRangeSetting); if (Fuji.FujiDevelopmentDynamicRange != 0xffff) printf ("Fuji Development Dynamic Range: %d\n", Fuji.FujiDevelopmentDynamicRange); if (Fuji.FujiAutoDynamicRange != 0xffff) printf ("Fuji Auto Dynamic Range: %d\n", Fuji.FujiAutoDynamicRange); if (S.pixel_aspect != 1) printf ("Pixel Aspect Ratio: %0.6f\n", S.pixel_aspect); if (T.tlength) printf ("Thumb size: %4d x %d\n", T.twidth, T.theight); printf ("Full size: %4d x %d\n", S.raw_width, S.raw_height); printf ("Image size: %4d x %d\n", S.width, S.height); printf ("Output size: %4d x %d\n", S.iwidth, S.iheight); if (Canon.SensorWidth) printf("SensorWidth = %d\n", Canon.SensorWidth); if (Canon.SensorHeight) printf("SensorHeight = %d\n", Canon.SensorHeight); if (Canon.SensorLeftBorder) printf("SensorLeftBorder = %d\n", Canon.SensorLeftBorder); if (Canon.SensorTopBorder) printf("SensorTopBorder = %d\n", Canon.SensorTopBorder); if (Canon.SensorRightBorder) printf("SensorRightBorder = %d\n", Canon.SensorRightBorder); if (Canon.SensorBottomBorder) printf("SensorBottomBorder = %d\n", Canon.SensorBottomBorder); if (Canon.BlackMaskLeftBorder) printf("BlackMaskLeftBorder = %d\n", Canon.BlackMaskLeftBorder); if (Canon.BlackMaskTopBorder) printf("BlackMaskTopBorder = %d\n", Canon.BlackMaskTopBorder); if (Canon.BlackMaskRightBorder) printf("BlackMaskRightBorder = %d\n", Canon.BlackMaskRightBorder); if (Canon.BlackMaskBottomBorder) printf("BlackMaskBottomBorder= %d\n", Canon.BlackMaskBottomBorder); if (Oly.OlympusCropID != -1) { printf ("Olympus aspect ID: %d\nOlympus crop", Oly.OlympusCropID); for (int c=0;c<4;c++) printf (" %d", Oly.OlympusFrame[c]); printf ("\n"); } printf ("Raw colors: %d", P1.colors); if (P1.filters) { printf ("\nFilter pattern: "); if (!P1.cdesc[3]) P1.cdesc[3] = 'G'; for (int i=0; i < 16; i++) putchar (P1.cdesc[MyCoolRawProcessor.fcol(i >> 1,i & 1)]); } if (C.linear_max[0] != 0) { printf ("\nHighlight linearity limits:"); for(int c=0;c<4;c++) printf (" %ld", C.linear_max[c]); } if (C.cam_mul[0] > 0) { printf ("\nMakernotes 'As shot' multipliers:"); for(int c=0;c<4;c++) printf (" %f", C.cam_mul[c]); } for (int cnt=0; cnt<25; cnt++) { if (C.WB_Coeffs[cnt][0] > 0) { printf ("\nMakernotes '%s' multipliers:", EXIF_LightSources[cnt]); for(int c=0;c<4;c++) printf (" %d", C.WB_Coeffs[cnt][c]); } } if (C.WB_Coeffs[LIBRAW_WBI_Other][0] > 0) { printf ("\nMakernotes 'Other' multipliers:"); for(int c=0;c<4;c++) printf (" %d", C.WB_Coeffs[LIBRAW_WBI_Other][c]); } if(C.rgb_cam[0][0] > 0.0001 && P1.colors>1) { printf("\nCamera2RGB matrix:\n"); for(int i=0; i< P1.colors; i++) printf("%6.4f\t%6.4f\t%6.4f\n",C.rgb_cam[i][0],C.rgb_cam[i][1],C.rgb_cam[i][2]); } printf("\nXYZ->CamRGB matrix:\n"); for(int i=0; i< P1.colors; i++) printf("%6.4f\t%6.4f\t%6.4f\n",C.cam_xyz[i][0],C.cam_xyz[i][1],C.cam_xyz[i][2]); if (C.dng_color[0].illuminant < 0xffff) printf ("\nDNG Illuminant 1: %s", EXIF_LightSources[C.dng_color[0].illuminant]); if (C.dng_color[1].illuminant < 0xffff) printf ("\nDNG Illuminant 2: %s", EXIF_LightSources[C.dng_color[1].illuminant]); if (fabsf(C.P1_color[0].romm_cam[0]) > 0) { printf("\nPhaseOne Matrix1:\n"); for(int i=0; i< 3; i++) printf("%6.4f\t%6.4f\t%6.4f\n",C.P1_color[0].romm_cam[i*3],C.P1_color[0].romm_cam[i*3+1],C.P1_color[0].romm_cam[i*3+2]); } if (fabsf(C.P1_color[1].romm_cam[0]) > 0) { printf("\nPhaseOne Matrix2:\n"); for(int i=0; i< 3; i++) printf("%6.4f\t%6.4f\t%6.4f\n",C.P1_color[1].romm_cam[i*3],C.P1_color[1].romm_cam[i*3+1],C.P1_color[1].romm_cam[i*3+2]); } if (fabsf(C.cmatrix[0][0]) > 0) { printf("\ncamRGB -> sRGB Matrix:\n"); for(int i=0; i< P1.colors; i++) { for(int j=0; j< P1.colors; j++) printf("%6.4f\t",C.cmatrix[j][i]); printf ("\n"); } } if (fabsf(C.ccm[0][0]) > 0) { printf("\nColor Correction Matrix:\n"); for(int i=0; i< P1.colors; i++) { for(int j=0; j< P1.colors; j++) printf("%6.4f\t",C.ccm[j][i]); printf ("\n"); } } if (fabsf(C.dng_color[0].colormatrix[0][0]) > 0) { printf("\nDNG color matrix 1:\n"); for(int i=0; i< P1.colors; i++) printf("%6.4f\t%6.4f\t%6.4f\n",C.dng_color[0].colormatrix[i][0],C.dng_color[0].colormatrix[i][1],C.dng_color[0].colormatrix[i][2]); } if (fabsf(C.dng_color[1].colormatrix[0][0]) > 0) { printf("\nDNG color matrix 2:\n"); for(int i=0; i< P1.colors; i++) printf("%6.4f\t%6.4f\t%6.4f\n",C.dng_color[1].colormatrix[i][0],C.dng_color[1].colormatrix[i][1],C.dng_color[1].colormatrix[i][2]); } if (fabsf(C.dng_color[0].calibration[0][0]) > 0) { printf("\nDNG calibration matrix 1:\n"); for(int i=0; i< P1.colors; i++) { for(int j=0; j< P1.colors; j++) printf("%6.4f\t",C.dng_color[0].calibration[j][i]); printf ("\n"); } } if (fabsf(C.dng_color[1].calibration[0][0]) > 0) { printf("\nDNG calibration matrix 2:\n"); for(int i=0; i< P1.colors; i++) { for(int j=0; j< P1.colors; j++) printf("%6.4f\t",C.dng_color[1].calibration[j][i]); printf ("\n"); } } if (fabsf(C.dng_color[0].forwardmatrix[0][0]) > 0) { printf("\nDNG forward matrix 1:\n"); for(int i=0; i< P1.colors; i++) printf("%6.4f\t%6.4f\t%6.4f\n",C.dng_color[0].forwardmatrix[0][i],C.dng_color[0].forwardmatrix[1][i],C.dng_color[0].forwardmatrix[2][i]); } if (fabsf(C.dng_color[1].forwardmatrix[0][0]) > 0) { printf("\nDNG forward matrix 2:\n"); for(int i=0; i< P1.colors; i++) printf("%6.4f\t%6.4f\t%6.4f\n",C.dng_color[1].forwardmatrix[0][i],C.dng_color[1].forwardmatrix[1][i],C.dng_color[1].forwardmatrix[2][i]); } printf ("\nDerived D65 multipliers:"); for(int c=0;c #include #include #ifndef WIN32 #include #include #include #include #endif #include "libraw/libraw.h" #ifdef WIN32 #define snprintf _snprintf #endif int my_progress_callback(void *unused_data,enum LibRaw_progress state,int iter, int expected) { if(iter==0) printf("CB: state=%x, expected %d iterations\n",state,expected); return 0; } char * customCameras[]= { (char*)"43704960,4080,5356, 0, 0, 0, 0,0,148,0,0, Dalsa, FTF4052C Full,0", (char*)"42837504,4008,5344, 0, 0, 0, 0,0,148,0,0,Dalsa, FTF4052C 3:4", (char*)"32128128,4008,4008, 0, 0, 0, 0,0,148,0,0,Dalsa, FTF4052C 1:1", (char*)"24096096,4008,3006, 0, 0, 0, 0,0,148,0,0,Dalsa, FTF4052C 4:3", (char*)"18068064,4008,2254, 0, 0, 0, 0,0,148,0,0,Dalsa, FTF4052C 16:9", (char*)"67686894,5049,6703, 0, 0, 0, 0,0,148,0,0,Dalsa, FTF5066C Full", (char*)"66573312,4992,6668, 0, 0, 0, 0,0,148,0,0,Dalsa, FTF5066C 3:4", (char*)"49840128,4992,4992, 0, 0, 0, 0,0,148,0,0,Dalsa, FTF5066C 1:1", (char*)"37400064,4992,3746, 0, 0, 0, 0,0,148,0,0,Dalsa, FTF5066C 4:3", (char*)"28035072,4992,2808, 0, 0, 0, 0,0,148,0,0,Dalsa, FTF5066C 16:9", NULL }; int main(int ac, char *av[]) { int i, ret, verbose=0, output_thumbs=0; // don't use fixed size buffers in real apps! char outfn[1024],thumbfn[1024]; LibRaw RawProcessor; RawProcessor.imgdata.params.custom_camera_strings = customCameras; if(ac<2) { printf( "simple_dcraw - LibRaw %s sample. Emulates dcraw [-D] [-T] [-v] [-e] [-E]\n" " %d cameras supported\n" "Usage: %s [-D] [-T] [-v] [-e] raw-files....\n" "\t-4 - 16-bit mode\n" "\t-L - list supported cameras and exit\n" "\t-v - verbose output\n" "\t-T - output TIFF files instead of .pgm/ppm\n" "\t-e - extract thumbnails (same as dcraw -e in separate run)\n",LibRaw::version(), LibRaw::cameraCount(), av[0]); return 0; } putenv ((char*)"TZ=UTC"); // dcraw compatibility, affects TIFF datestamp field #define P1 RawProcessor.imgdata.idata #define S RawProcessor.imgdata.sizes #define C RawProcessor.imgdata.color #define T RawProcessor.imgdata.thumbnail #define P2 RawProcessor.imgdata.other #define OUT RawProcessor.imgdata.params for (i=1;i1?"ppm":"pgm")); if(verbose) printf("Writing file %s\n",outfn); if( LIBRAW_SUCCESS != (ret = RawProcessor.dcraw_ppm_tiff_writer(outfn))) fprintf(stderr,"Cannot write %s: %s\n",outfn,libraw_strerror(ret)); RawProcessor.recycle(); // just for show this call } return 0; } LibRaw-0.18.8/samples/unprocessed_raw.cpp000066400000000000000000000224231324423227700203540ustar00rootroot00000000000000/* -*- C++ -*- * File: unprocessed_raw.cpp * Copyright 2009-2016 LibRaw LLC (info@libraw.org) * Created: Fri Jan 02, 2009 * * LibRaw sample * Generates unprocessed raw image: with masked pixels and without black subtraction * LibRaw is free software; you can redistribute it and/or modify it under the terms of the one of two licenses as you choose: 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 (See file LICENSE.LGPL provided in LibRaw distribution archive for details). 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 (See file LICENSE.CDDL provided in LibRaw distribution archive for details). */ #include #include #include #include #ifndef WIN32 #include #else #include #include #endif #include "libraw/libraw.h" #ifdef WIN32 #define snprintf _snprintf #endif #if !(LIBRAW_COMPILE_CHECK_VERSION_NOTLESS(0,14)) #error This code is for LibRaw 0.14+ only #endif void gamma_curve (unsigned short curve[]); void write_ppm(unsigned width, unsigned height, unsigned short *bitmap, const char *basename); void write_tiff(int width, int height, unsigned short *bitmap, const char *basename); int main(int ac, char *av[]) { int i, ret; int verbose=1,autoscale=0,use_gamma=0,out_tiff=0; char outfn[1024]; LibRaw RawProcessor; if(ac<2) { usage: printf( "unprocessed_raw - LibRaw %s sample. %d cameras supported\n" "Usage: %s [-q] [-A] [-g] [-s N] raw-files....\n" "\t-q - be quiet\n" "\t-s N - select Nth image in file (default=0)\n" "\t-g - use gamma correction with gamma 2.2 (not precise,use for visual inspection only)\n" "\t-A - autoscaling (by integer factor)\n" "\t-T - write tiff instead of pgm\n" ,LibRaw::version(), LibRaw::cameraCount(), av[0]); return 0; } #define S RawProcessor.imgdata.sizes #define OUT RawProcessor.imgdata.params for (i=1;i0 && max< 1<<15) { scale = (1<<16)/max; if(verbose) printf("Scaling with multiplier=%d (max=%d)\n",scale,max); for(int j=0; j= 1] = 1; if (g[1] && (g[1]-1)*(g[0]-1) <= 0) { for (i=0; i < 48; i++) { g[2] = (bnd[0] + bnd[1])/2; if (g[0]) bnd[(pow(g[2]/g[1],-g[0]) - 1)/g[0] - 1/g[2] > -1] = g[2]; else bnd[g[2]/exp(1-1/g[2]) < g[1]] = g[2]; } g[3] = g[2] / g[1]; if (g[0]) g[4] = g[2] * (1/g[0] - 1); } if (g[0]) g[5] = 1 / (g[1]*SQR(g[3])/2 - g[4]*(1 - g[3]) + (1 - pow(g[3],1+g[0]))*(1 + g[4])/(1 + g[0])) - 1; else g[5] = 1 / (g[1]*SQR(g[3])/2 + 1 - g[2] - g[3] - g[2]*g[3]*(log(g[3]) - 1)) - 1; for (i=0; i < 0x10000; i++) { curve[i] = 0xffff; if ((r = (double) i / imax) < 1) curve[i] = 0x10000 * ( mode ? (r < g[3] ? r*g[1] : (g[0] ? pow( r,g[0])*(1+g[4])-g[4] : log(r)*g[2]+1)) : (r < g[2] ? r/g[1] : (g[0] ? pow((r+g[4])/(1+g[4]),1/g[0]) : exp((r-1)/g[2])))); } } void tiff_set (ushort *ntag, ushort tag, ushort type, int count, int val) { struct tiff_tag *tt; int c; tt = (struct tiff_tag *)(ntag+1) + (*ntag)++; tt->tag = tag; tt->type = type; tt->count = count; if (type < 3 && count <= 4) for(c=0;c<4;c++) tt->val.c[c] = val >> (c << 3); else if (type == 3 && count <= 2) for(c=0;c<2;c++) tt->val.s[c] = val >> (c << 4); else tt->val.i = val; } #define TOFF(ptr) ((char *)(&(ptr)) - (char *)th) void tiff_head (int width, int height, struct tiff_hdr *th) { int c; time_t timestamp = time(NULL); struct tm *t; memset (th, 0, sizeof *th); th->t_order = htonl(0x4d4d4949) >> 16; th->magic = 42; th->ifd = 10; tiff_set (&th->ntag, 254, 4, 1, 0); tiff_set (&th->ntag, 256, 4, 1, width); tiff_set (&th->ntag, 257, 4, 1, height); tiff_set (&th->ntag, 258, 3, 1, 16); for(c=0;c<4;c++) th->bps[c] = 16; tiff_set (&th->ntag, 259, 3, 1, 1); tiff_set (&th->ntag, 262, 3, 1, 1); tiff_set (&th->ntag, 273, 4, 1, sizeof *th); tiff_set (&th->ntag, 277, 3, 1, 1); tiff_set (&th->ntag, 278, 4, 1, height); tiff_set (&th->ntag, 279, 4, 1, height*width*2); tiff_set (&th->ntag, 282, 5, 1, TOFF(th->rat[0])); tiff_set (&th->ntag, 283, 5, 1, TOFF(th->rat[2])); tiff_set (&th->ntag, 284, 3, 1, 1); tiff_set (&th->ntag, 296, 3, 1, 2); tiff_set (&th->ntag, 306, 2, 20, TOFF(th->date)); th->rat[0] = th->rat[2] = 300; th->rat[1] = th->rat[3] = 1; t = localtime (×tamp); if(t) sprintf (th->date, "%04d:%02d:%02d %02d:%02d:%02d", t->tm_year+1900,t->tm_mon+1,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec); } void write_tiff(int width, int height, unsigned short *bitmap, const char *fn) { struct tiff_hdr th; FILE *ofp = fopen(fn,"wb"); if(!ofp) return; tiff_head (width,height,&th); fwrite (&th, sizeof th, 1, ofp); fwrite (bitmap, 2, width*height, ofp); fclose(ofp); } LibRaw-0.18.8/shlib-version.sh000077500000000000000000000004551324423227700161250ustar00rootroot00000000000000#!/bin/sh vfile=./libraw/libraw_version.h major=`grep LIBRAW_SHLIB_CURRENT $vfile |head -1 | awk '{print $3}'` minor=`grep LIBRAW_SHLIB_REVISION $vfile | head -1 | awk '{print $3}'` patch=`grep LIBRAW_SHLIB_AGE $vfile | head -1 | awk '{print $3}'` echo "$major:$minor:$patch" | awk '{printf $1}' LibRaw-0.18.8/src/000077500000000000000000000000001324423227700135655ustar00rootroot00000000000000LibRaw-0.18.8/src/Makefile000066400000000000000000000000351324423227700152230ustar00rootroot00000000000000all: (cd ..; make library) LibRaw-0.18.8/src/libraw_c_api.cpp000066400000000000000000000250271324423227700167120ustar00rootroot00000000000000/* -*- C++ -*- * File: libraw_c_api.cpp * Copyright 2008-2017 LibRaw LLC (info@libraw.org) * Created: Sat Mar 8 , 2008 * * LibRaw C interface LibRaw is free software; you can redistribute it and/or modify it under the terms of the one of two licenses as you choose: 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 (See file LICENSE.LGPL provided in LibRaw distribution archive for details). 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 (See file LICENSE.CDDL provided in LibRaw distribution archive for details). */ #include #include #include "libraw/libraw.h" #ifdef __cplusplus #include extern "C" { #endif libraw_data_t *libraw_init(unsigned int flags) { LibRaw *ret; try { ret = new LibRaw(flags); } catch (std::bad_alloc) { return NULL; } return &(ret->imgdata); } unsigned libraw_capabilities() { return LibRaw::capabilities();} const char* libraw_version() { return LibRaw::version();} const char* libraw_strprogress(enum LibRaw_progress p) { return LibRaw::strprogress(p);} int libraw_versionNumber() { return LibRaw::versionNumber();} const char** libraw_cameraList() { return LibRaw::cameraList();} int libraw_cameraCount() { return LibRaw::cameraCount(); } const char* libraw_unpack_function_name(libraw_data_t* lr) { if(!lr) return "NULL parameter passed"; LibRaw *ip = (LibRaw*) lr->parent_class; return ip->unpack_function_name(); } void libraw_subtract_black(libraw_data_t* lr) { if(!lr) return; LibRaw *ip = (LibRaw*) lr->parent_class; ip->subtract_black(); } int libraw_open_file(libraw_data_t* lr, const char *file) { if(!lr) return EINVAL; LibRaw *ip = (LibRaw*) lr->parent_class; return ip->open_file(file); } int libraw_open_file_ex(libraw_data_t* lr, const char *file,INT64 sz) { if(!lr) return EINVAL; LibRaw *ip = (LibRaw*) lr->parent_class; return ip->open_file(file,sz); } #if defined(_WIN32) && !defined(__MINGW32__) && defined(_MSC_VER) && (_MSC_VER > 1310) int libraw_open_wfile(libraw_data_t* lr, const wchar_t *file) { if(!lr) return EINVAL; LibRaw *ip = (LibRaw*) lr->parent_class; return ip->open_file(file); } int libraw_open_wfile_ex(libraw_data_t* lr, const wchar_t *file,INT64 sz) { if(!lr) return EINVAL; LibRaw *ip = (LibRaw*) lr->parent_class; return ip->open_file(file,sz); } #endif int libraw_open_buffer(libraw_data_t* lr, void *buffer, size_t size) { if(!lr) return EINVAL; LibRaw *ip = (LibRaw*) lr->parent_class; return ip->open_buffer(buffer,size); } int libraw_unpack(libraw_data_t* lr) { if(!lr) return EINVAL; LibRaw *ip = (LibRaw*) lr->parent_class; return ip->unpack(); } int libraw_unpack_thumb(libraw_data_t* lr) { if(!lr) return EINVAL; LibRaw *ip = (LibRaw*) lr->parent_class; return ip->unpack_thumb(); } void libraw_recycle_datastream(libraw_data_t* lr) { if(!lr) return; LibRaw *ip = (LibRaw*) lr->parent_class; ip->recycle_datastream(); } void libraw_recycle(libraw_data_t* lr) { if(!lr) return; LibRaw *ip = (LibRaw*) lr->parent_class; ip->recycle(); } void libraw_close(libraw_data_t* lr) { if(!lr) return; LibRaw *ip = (LibRaw*) lr->parent_class; delete ip; } void libraw_set_exifparser_handler(libraw_data_t* lr, exif_parser_callback cb,void *data) { if(!lr) return; LibRaw *ip = (LibRaw*) lr->parent_class; ip->set_exifparser_handler(cb,data); } void libraw_set_memerror_handler(libraw_data_t* lr, memory_callback cb,void *data) { if(!lr) return; LibRaw *ip = (LibRaw*) lr->parent_class; ip->set_memerror_handler(cb,data); } void libraw_set_dataerror_handler(libraw_data_t* lr,data_callback func,void *data) { if(!lr) return; LibRaw *ip = (LibRaw*) lr->parent_class; ip->set_dataerror_handler(func,data); } void libraw_set_progress_handler(libraw_data_t* lr, progress_callback cb,void *data) { if(!lr) return; LibRaw *ip = (LibRaw*) lr->parent_class; ip->set_progress_handler(cb,data); } // DCRAW int libraw_adjust_sizes_info_only(libraw_data_t* lr) { if(!lr) return EINVAL; LibRaw *ip = (LibRaw*) lr->parent_class; return ip->adjust_sizes_info_only(); } int libraw_dcraw_ppm_tiff_writer(libraw_data_t* lr,const char *filename) { if(!lr) return EINVAL; LibRaw *ip = (LibRaw*) lr->parent_class; return ip->dcraw_ppm_tiff_writer(filename); } int libraw_dcraw_thumb_writer(libraw_data_t* lr,const char *fname) { if(!lr) return EINVAL; LibRaw *ip = (LibRaw*) lr->parent_class; return ip->dcraw_thumb_writer(fname); } int libraw_dcraw_process(libraw_data_t* lr) { if(!lr) return EINVAL; LibRaw *ip = (LibRaw*) lr->parent_class; return ip->dcraw_process(); } libraw_processed_image_t *libraw_dcraw_make_mem_image(libraw_data_t* lr,int *errc) { if(!lr) { if(errc) *errc=EINVAL; return NULL;} LibRaw *ip = (LibRaw*) lr->parent_class; return ip->dcraw_make_mem_image(errc); } libraw_processed_image_t *libraw_dcraw_make_mem_thumb(libraw_data_t* lr,int *errc) { if(!lr) { if(errc) *errc=EINVAL; return NULL;} LibRaw *ip = (LibRaw*) lr->parent_class; return ip->dcraw_make_mem_thumb(errc); } void libraw_dcraw_clear_mem(libraw_processed_image_t* p) { LibRaw::dcraw_clear_mem(p); } int libraw_raw2image(libraw_data_t* lr) { if(!lr) return EINVAL; LibRaw *ip = (LibRaw*) lr->parent_class; return ip->raw2image(); } void libraw_free_image(libraw_data_t* lr) { if(!lr) return; LibRaw *ip = (LibRaw*) lr->parent_class; ip->free_image(); } int libraw_get_decoder_info(libraw_data_t* lr,libraw_decoder_info_t *d) { if(!lr || !d) return EINVAL; LibRaw *ip = (LibRaw*) lr->parent_class; return ip->get_decoder_info(d); } int libraw_COLOR(libraw_data_t *lr, int row, int col) { if(!lr) return EINVAL; LibRaw *ip = (LibRaw*) lr->parent_class; return ip->COLOR(row,col); } /* getters/setters used by 3DLut Creator */ DllDef void libraw_set_demosaic(libraw_data_t *lr,int value) { if(!lr) return; LibRaw *ip = (LibRaw*) lr->parent_class; ip->imgdata.params.user_qual = value; } DllDef void libraw_set_output_color(libraw_data_t *lr,int value) { if(!lr) return; LibRaw *ip = (LibRaw*) lr->parent_class; ip->imgdata.params.output_color = value; } DllDef void libraw_set_output_bps(libraw_data_t *lr,int value) { if(!lr) return; LibRaw *ip = (LibRaw*) lr->parent_class; ip->imgdata.params.output_bps = value; } #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define LIM(x,min,max) MAX(min,MIN(x,max)) DllDef void libraw_set_user_mul(libraw_data_t *lr,int index, float val) { if(!lr) return; LibRaw *ip = (LibRaw*) lr->parent_class; ip->imgdata.params.user_mul[LIM(index,0,3)]=val; } DllDef void libraw_set_gamma(libraw_data_t *lr,int index, float value) { if(!lr) return; LibRaw *ip = (LibRaw*) lr->parent_class; ip->imgdata.params.gamm[LIM(index,0,5)] = value; } DllDef void libraw_set_no_auto_bright(libraw_data_t *lr,int value) { if(!lr) return; LibRaw *ip = (LibRaw*) lr->parent_class; ip->imgdata.params.no_auto_bright = value; } DllDef void libraw_set_bright(libraw_data_t *lr,float value) { if(!lr) return; LibRaw *ip = (LibRaw*) lr->parent_class; ip->imgdata.params.bright = value; } DllDef void libraw_set_highlight(libraw_data_t *lr,int value) { if(!lr) return; LibRaw *ip = (LibRaw*) lr->parent_class; ip->imgdata.params.highlight = value; } DllDef void libraw_set_fbdd_noiserd(libraw_data_t *lr,int value) { if(!lr) return; LibRaw *ip = (LibRaw*) lr->parent_class; ip->imgdata.params.fbdd_noiserd = value; } DllDef int libraw_get_raw_height(libraw_data_t *lr) { if(!lr) return EINVAL; return lr->sizes.raw_height; } DllDef int libraw_get_raw_width(libraw_data_t *lr) { if(!lr) return EINVAL; return lr->sizes.raw_width; } DllDef int libraw_get_iheight(libraw_data_t *lr) { if(!lr) return EINVAL; return lr->sizes.iheight; } DllDef int libraw_get_iwidth(libraw_data_t *lr) { if(!lr) return EINVAL; return lr->sizes.iwidth; } DllDef float libraw_get_cam_mul(libraw_data_t *lr,int index) { if(!lr) return EINVAL; return lr->color.cam_mul[LIM(index,0,3)]; } DllDef float libraw_get_pre_mul(libraw_data_t *lr,int index) { if(!lr) return EINVAL; return lr->color.pre_mul[LIM(index,0,3)]; } DllDef float libraw_get_rgb_cam(libraw_data_t *lr,int index1, int index2) { if(!lr) return EINVAL; return lr->color.rgb_cam[LIM(index1,0,2)][LIM(index2,0,3)]; } DllDef int libraw_get_color_maximum(libraw_data_t *lr) { if(!lr) return EINVAL; return lr->color.maximum; } DllDef void libraw_set_ca_correction(libraw_data_t *lr,int ca_correc, float ca_red, float ca_blue) { if(!lr) return; LibRaw *ip = (LibRaw*) lr->parent_class; ip->imgdata.params.ca_correc = ca_correc; ip->imgdata.params.cared = ca_red; ip->imgdata.params.cablue = ca_blue; } DllDef void libraw_set_cfalinenoise(libraw_data_t *lr,int cfaline, float linenoise) { if(!lr) return; LibRaw *ip = (LibRaw*) lr->parent_class; ip->imgdata.params.cfaline = cfaline; ip->imgdata.params.linenoise = linenoise; } DllDef void libraw_set_wf_debanding(libraw_data_t *lr, int wf_debanding, float wfd0, float wfd1, float wfd2, float wfd3) { if(!lr) return; LibRaw *ip = (LibRaw*) lr->parent_class; ip->imgdata.params.wf_debanding = wf_debanding; ip->imgdata.params.wf_deband_treshold[0] = wfd0; ip->imgdata.params.wf_deband_treshold[1] = wfd1; ip->imgdata.params.wf_deband_treshold[2] = wfd2; ip->imgdata.params.wf_deband_treshold[3] = wfd3; } DllDef void libraw_set_interpolation_passes(libraw_data_t *lr,int passes) { if(!lr) return; LibRaw *ip = (LibRaw*) lr->parent_class; ip->imgdata.params.med_passes = passes; ip->imgdata.params.es_med_passes = passes; ip->imgdata.params.dcb_iterations = passes; } #ifdef __cplusplus } #endif LibRaw-0.18.8/src/libraw_cxx.cpp000066400000000000000000005322351324423227700164450ustar00rootroot00000000000000/* -*- C++ -*- * File: libraw_cxx.cpp * Copyright 2008-2017 LibRaw LLC (info@libraw.org) * Created: Sat Mar 8 , 2008 * * LibRaw C++ interface (implementation) LibRaw is free software; you can redistribute it and/or modify it under the terms of the one of two licenses as you choose: 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 (See file LICENSE.LGPL provided in LibRaw distribution archive for details). 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 (See file LICENSE.CDDL provided in LibRaw distribution archive for details). */ #include #include #include #include #include #include #include #if !defined(_WIN32) && !defined(__MINGW32__) #include #else #include #endif #define LIBRAW_LIBRARY_BUILD #include "libraw/libraw.h" #include "internal/defines.h" #ifdef USE_ZLIB #include #endif #ifdef USE_RAWSPEED #include "../RawSpeed/rawspeed_xmldata.cpp" #include #include #include #include #include #include #endif #ifdef USE_DNGSDK #include "dng_host.h" #include "dng_negative.h" #include "dng_simple_image.h" #include "dng_info.h" #endif #include "libraw_xtrans_compressed.cpp" #ifdef __cplusplus extern "C" { #endif void default_memory_callback(void *,const char *file,const char *where) { fprintf (stderr,"%s: Out of memory in %s\n", file?file:"unknown file", where); } void default_data_callback(void*,const char *file, const int offset) { if(offset < 0) fprintf (stderr,"%s: Unexpected end of file\n", file?file:"unknown file"); else fprintf (stderr,"%s: data corrupted at %d\n",file?file:"unknown file",offset); } const char *libraw_strerror(int e) { enum LibRaw_errors errorcode = (LibRaw_errors)e; switch(errorcode) { case LIBRAW_SUCCESS: return "No error"; case LIBRAW_UNSPECIFIED_ERROR: return "Unspecified error"; case LIBRAW_FILE_UNSUPPORTED: return "Unsupported file format or not RAW file"; case LIBRAW_REQUEST_FOR_NONEXISTENT_IMAGE: return "Request for nonexisting image number"; case LIBRAW_OUT_OF_ORDER_CALL: return "Out of order call of libraw function"; case LIBRAW_NO_THUMBNAIL: return "No thumbnail in file"; case LIBRAW_UNSUPPORTED_THUMBNAIL: return "Unsupported thumbnail format"; case LIBRAW_INPUT_CLOSED: return "No input stream, or input stream closed"; case LIBRAW_UNSUFFICIENT_MEMORY: return "Unsufficient memory"; case LIBRAW_DATA_ERROR: return "Corrupted data or unexpected EOF"; case LIBRAW_IO_ERROR: return "Input/output error"; case LIBRAW_CANCELLED_BY_CALLBACK: return "Cancelled by user callback"; case LIBRAW_BAD_CROP: return "Bad crop box"; default: return "Unknown error code"; } } #ifdef __cplusplus } #endif #define Sigma_X3F 22 const double LibRaw_constants::xyz_rgb[3][3] = { { 0.412453, 0.357580, 0.180423 }, { 0.212671, 0.715160, 0.072169 }, { 0.019334, 0.119193, 0.950227 } }; const float LibRaw_constants::d65_white[3] = { 0.950456f, 1.0f, 1.088754f }; #define P1 imgdata.idata #define S imgdata.sizes #define O imgdata.params #define C imgdata.color #define T imgdata.thumbnail #define IO libraw_internal_data.internal_output_params #define ID libraw_internal_data.internal_data #define EXCEPTION_HANDLER(e) do{ \ /* fprintf(stderr,"Exception %d caught\n",e);*/ \ switch(e) \ { \ case LIBRAW_EXCEPTION_ALLOC: \ recycle(); \ return LIBRAW_UNSUFFICIENT_MEMORY; \ case LIBRAW_EXCEPTION_DECODE_RAW: \ case LIBRAW_EXCEPTION_DECODE_JPEG: \ recycle(); \ return LIBRAW_DATA_ERROR; \ case LIBRAW_EXCEPTION_DECODE_JPEG2000: \ recycle(); \ return LIBRAW_DATA_ERROR; \ case LIBRAW_EXCEPTION_IO_EOF: \ case LIBRAW_EXCEPTION_IO_CORRUPT: \ recycle(); \ return LIBRAW_IO_ERROR; \ case LIBRAW_EXCEPTION_CANCELLED_BY_CALLBACK: \ recycle(); \ return LIBRAW_CANCELLED_BY_CALLBACK; \ case LIBRAW_EXCEPTION_BAD_CROP: \ recycle(); \ return LIBRAW_BAD_CROP; \ default: \ return LIBRAW_UNSPECIFIED_ERROR; \ } \ }while(0) const char* LibRaw::version() { return LIBRAW_VERSION_STR;} int LibRaw::versionNumber() { return LIBRAW_VERSION; } const char* LibRaw::strerror(int p) { return libraw_strerror(p);} unsigned LibRaw::capabilities() { unsigned ret = 0; #ifdef USE_RAWSPEED ret |= LIBRAW_CAPS_RAWSPEED; #endif #ifdef USE_DNGSDK ret |= LIBRAW_CAPS_DNGSDK; #endif #ifdef LIBRAW_DEMOSAIC_PACK_GPL2 ret |= LIBRAW_CAPS_DEMOSAICSGPL2; #endif #ifdef LIBRAW_DEMOSAIC_PACK_GPL3 ret |= LIBRAW_CAPS_DEMOSAICSGPL3; #endif return ret; } unsigned LibRaw:: parse_custom_cameras(unsigned limit, libraw_custom_camera_t table[], char** list) { if(!list) return 0; unsigned index = 0; for(int i=0; i< limit; i++) { if(!list[i]) break; if(strlen(list[i])<10) continue; char *string = (char*)malloc(strlen(list[i])+1); strcpy(string,list[i]); char *start = string; memset(&table[index],0,sizeof(table[0])); for(int j = 0; start && j < 14; j++) { char *end = strchr(start,','); if(end) { *end = 0; end++; } // move to next char while(isspace(*start) && *start) start++; // skip leading spaces? unsigned val = strtol(start,0,10); switch(j) { case 0: table[index].fsize = val; break; case 1: table[index].rw = val; break; case 2: table[index].rh = val; break; case 3: table[index].lm = val; break; case 4: table[index].tm = val; break; case 5: table[index].rm = val; break; case 6: table[index].bm = val; break; case 7: table[index].lf = val; break; case 8: table[index].cf = val; break; case 9: table[index].max = val; break; case 10: table[index].flags = val; break; case 11: strncpy(table[index].t_make,start,sizeof(table[index].t_make)-1); break; case 12: strncpy(table[index].t_model,start,sizeof(table[index].t_model)-1); break; case 13: table[index].offset = val; break; default: break; } start = end; } free(string); if(table[index].t_make[0]) index++; } return index; } void LibRaw::derror() { if (!libraw_internal_data.unpacker_data.data_error && libraw_internal_data.internal_data.input) { if (libraw_internal_data.internal_data.input->eof()) { if(callbacks.data_cb)(*callbacks.data_cb)(callbacks.datacb_data, libraw_internal_data.internal_data.input->fname(),-1); throw LIBRAW_EXCEPTION_IO_EOF; } else { if(callbacks.data_cb)(*callbacks.data_cb)(callbacks.datacb_data, libraw_internal_data.internal_data.input->fname(), libraw_internal_data.internal_data.input->tell()); //throw LIBRAW_EXCEPTION_IO_CORRUPT; } } libraw_internal_data.unpacker_data.data_error++; } void LibRaw::dcraw_clear_mem(libraw_processed_image_t* p) { if(p) ::free(p); } int LibRaw::is_sraw() { return load_raw == &LibRaw::canon_sraw_load_raw || load_raw == &LibRaw::nikon_load_sraw ; } int LibRaw::is_coolscan_nef() { return load_raw == &LibRaw::nikon_coolscan_load_raw;} int LibRaw::is_nikon_sraw(){ return load_raw == &LibRaw::nikon_load_sraw; } int LibRaw::sraw_midpoint() { if (load_raw == &LibRaw::canon_sraw_load_raw) return 8192; else if (load_raw == &LibRaw::nikon_load_sraw) return 2048; else return 0; } #ifdef USE_RAWSPEED using namespace RawSpeed; class CameraMetaDataLR : public CameraMetaData { public: CameraMetaDataLR() : CameraMetaData() {} CameraMetaDataLR(char *filename) : CameraMetaData(filename){} CameraMetaDataLR(char *data, int sz); }; CameraMetaDataLR::CameraMetaDataLR(char *data, int sz) : CameraMetaData() { ctxt = xmlNewParserCtxt(); if (ctxt == NULL) { ThrowCME("CameraMetaData:Could not initialize context."); } xmlResetLastError(); doc = xmlCtxtReadMemory(ctxt, data,sz, "", NULL, XML_PARSE_DTDVALID); if (doc == NULL) { ThrowCME("CameraMetaData: XML Document could not be parsed successfully. Error was: %s", ctxt->lastError.message); } if (ctxt->valid == 0) { if (ctxt->lastError.code == 0x5e) { // printf("CameraMetaData: Unable to locate DTD, attempting to ignore."); } else { ThrowCME("CameraMetaData: XML file does not validate. DTD Error was: %s", ctxt->lastError.message); } } xmlNodePtr cur; cur = xmlDocGetRootElement(doc); if (xmlStrcmp(cur->name, (const xmlChar *) "Cameras")) { ThrowCME("CameraMetaData: XML document of the wrong type, root node is not cameras."); return; } cur = cur->xmlChildrenNode; while (cur != NULL) { if ((!xmlStrcmp(cur->name, (const xmlChar *)"Camera"))) { Camera *camera = new Camera(doc, cur); addCamera(camera); // Create cameras for aliases. for (unsigned int i = 0; i < camera->aliases.size(); i++) { addCamera(new Camera(camera, i)); } } cur = cur->next; } if (doc) xmlFreeDoc(doc); doc = 0; if (ctxt) xmlFreeParserCtxt(ctxt); ctxt = 0; } #define RAWSPEED_DATA_COUNT (sizeof(_rawspeed_data_xml)/sizeof(_rawspeed_data_xml[0])) static CameraMetaDataLR* make_camera_metadata() { int len = 0,i; for(i=0;ilen) break; memmove(rawspeed_xml+offt,_rawspeed_data_xml[i],ll); offt+=ll; } rawspeed_xml[offt]=0; CameraMetaDataLR *ret=NULL; try { ret = new CameraMetaDataLR(rawspeed_xml,offt); } catch (...) { // Mask all exceptions } free(rawspeed_xml); return ret; } #endif #define ZERO(a) memset(&a,0,sizeof(a)) static void cleargps(libraw_gps_info_t*q) { for (int i = 0; i < 3; i++) q->latitude[i] = q->longtitude[i] = q->gpstimestamp[i] = 0.f; q->altitude = 0.f; q->altref = q->latref = q->longref = q->gpsstatus = q->gpsparsed = 0; } LibRaw:: LibRaw(unsigned int flags) { double aber[4] = {1,1,1,1}; double gamm[6] = { 0.45,4.5,0,0,0,0 }; unsigned greybox[4] = { 0, 0, UINT_MAX, UINT_MAX }; unsigned cropbox[4] = { 0, 0, UINT_MAX, UINT_MAX }; #ifdef DCRAW_VERBOSE verbose = 1; #else verbose = 0; #endif ZERO(imgdata); cleargps(&imgdata.other.parsed_gps); ZERO(libraw_internal_data); ZERO(callbacks); _rawspeed_camerameta = _rawspeed_decoder = NULL; dnghost = NULL; _x3f_data = NULL; #ifdef USE_RAWSPEED CameraMetaDataLR *camerameta = make_camera_metadata(); // May be NULL in case of exception in make_camera_metadata() _rawspeed_camerameta = static_cast(camerameta); #endif callbacks.mem_cb = (flags & LIBRAW_OPIONS_NO_MEMERR_CALLBACK) ? NULL: &default_memory_callback; callbacks.data_cb = (flags & LIBRAW_OPIONS_NO_DATAERR_CALLBACK)? NULL : &default_data_callback; callbacks.exif_cb = NULL; // no default callback memmove(&imgdata.params.aber,&aber,sizeof(aber)); memmove(&imgdata.params.gamm,&gamm,sizeof(gamm)); memmove(&imgdata.params.greybox,&greybox,sizeof(greybox)); memmove(&imgdata.params.cropbox,&cropbox,sizeof(cropbox)); imgdata.params.bright=1; imgdata.params.use_camera_matrix=1; imgdata.params.user_flip=-1; imgdata.params.user_black=-1; imgdata.params.user_cblack[0]=imgdata.params.user_cblack[1]=imgdata.params.user_cblack[2]=imgdata.params.user_cblack[3]=-1000001; imgdata.params.user_sat=-1; imgdata.params.user_qual=-1; imgdata.params.output_color=1; imgdata.params.output_bps=8; imgdata.params.use_fuji_rotate=1; imgdata.params.exp_shift = 1.0; imgdata.params.auto_bright_thr = LIBRAW_DEFAULT_AUTO_BRIGHTNESS_THRESHOLD; imgdata.params.adjust_maximum_thr= LIBRAW_DEFAULT_ADJUST_MAXIMUM_THRESHOLD; imgdata.params.use_rawspeed = 1; imgdata.params.use_dngsdk = LIBRAW_DNG_DEFAULT; imgdata.params.no_auto_scale = 0; imgdata.params.no_interpolation = 0; imgdata.params.raw_processing_options = LIBRAW_PROCESSING_DP2Q_INTERPOLATERG|LIBRAW_PROCESSING_DP2Q_INTERPOLATEAF | LIBRAW_PROCESSING_CONVERTFLOAT_TO_INT; imgdata.params.sony_arw2_posterization_thr = 0; imgdata.params.green_matching = 0; imgdata.params.custom_camera_strings=0; imgdata.params.coolscan_nef_gamma = 1.0f; imgdata.parent_class = this; imgdata.progress_flags = 0; imgdata.color.baseline_exposure = -999.f; _exitflag = 0; tls = new LibRaw_TLS; tls->init(); interpolate_bayer = 0; interpolate_xtrans = 0; } int LibRaw::set_rawspeed_camerafile(char *filename) { #ifdef USE_RAWSPEED try { CameraMetaDataLR *camerameta = new CameraMetaDataLR(filename); if(_rawspeed_camerameta) { CameraMetaDataLR *d = static_cast(_rawspeed_camerameta); delete d; } _rawspeed_camerameta = static_cast(camerameta); } catch (...) { //just return error code return -1; } #endif return 0; } LibRaw::~LibRaw() { recycle(); delete tls; #ifdef USE_RAWSPEED if(_rawspeed_camerameta) { CameraMetaDataLR *cmeta = static_cast(_rawspeed_camerameta); delete cmeta; _rawspeed_camerameta = NULL; } #endif } void* LibRaw:: malloc(size_t t) { void *p = memmgr.malloc(t); if(!p) throw LIBRAW_EXCEPTION_ALLOC; return p; } void* LibRaw:: realloc(void *q,size_t t) { void *p = memmgr.realloc(q,t); if(!p) throw LIBRAW_EXCEPTION_ALLOC; return p; } void* LibRaw:: calloc(size_t n,size_t t) { void *p = memmgr.calloc(n,t); if(!p) throw LIBRAW_EXCEPTION_ALLOC; return p; } void LibRaw:: free(void *p) { memmgr.free(p); } void LibRaw:: recycle_datastream() { if(libraw_internal_data.internal_data.input && libraw_internal_data.internal_data.input_internal) { delete libraw_internal_data.internal_data.input; libraw_internal_data.internal_data.input = NULL; } libraw_internal_data.internal_data.input_internal = 0; } void x3f_clear(void*); void LibRaw:: recycle() { recycle_datastream(); #define FREE(a) do { if(a) { free(a); a = NULL;} }while(0) FREE(imgdata.image); FREE(imgdata.thumbnail.thumb); FREE(libraw_internal_data.internal_data.meta_data); FREE(libraw_internal_data.output_data.histogram); FREE(libraw_internal_data.output_data.oprof); FREE(imgdata.color.profile); FREE(imgdata.rawdata.ph1_cblack); FREE(imgdata.rawdata.ph1_rblack); FREE(imgdata.rawdata.raw_alloc); FREE(imgdata.idata.xmpdata); #undef FREE ZERO(imgdata.sizes); ZERO(imgdata.idata); ZERO(imgdata.makernotes); ZERO(imgdata.color); ZERO(imgdata.other); ZERO(imgdata.thumbnail); ZERO(imgdata.rawdata); imgdata.makernotes.olympus.OlympusCropID = -1; cleargps(&imgdata.other.parsed_gps); imgdata.color.baseline_exposure = -999.f; imgdata.makernotes.fuji.FujiExpoMidPointShift = -999.f; imgdata.makernotes.fuji.FujiDynamicRange = 0xffff; imgdata.makernotes.fuji.FujiFilmMode = 0xffff; imgdata.makernotes.fuji.FujiDynamicRangeSetting = 0xffff; imgdata.makernotes.fuji.FujiDevelopmentDynamicRange = 0xffff; imgdata.makernotes.fuji.FujiAutoDynamicRange = 0xffff; imgdata.makernotes.fuji.FocusMode = 0xffff; imgdata.makernotes.fuji.AFMode = 0xffff; imgdata.makernotes.fuji.FocusPixel[0] = imgdata.makernotes.fuji.FocusPixel[1] = 0xffff; imgdata.makernotes.fuji.ImageStabilization[0] = imgdata.makernotes.fuji.ImageStabilization[1] = imgdata.makernotes.fuji.ImageStabilization[2] = 0xffff; imgdata.makernotes.sony.SonyCameraType = 0xffff; imgdata.color.dng_color[0].illuminant = imgdata.color.dng_color[1].illuminant = 0xffff; for(int i = 0; i < 4; i++) imgdata.color.dng_levels.analogbalance[i]= imgdata.color.dng_levels.analogbalance[i]=1.0f; ZERO(libraw_internal_data); ZERO(imgdata.lens); imgdata.lens.makernotes.CanonFocalUnits = 1; imgdata.lens.makernotes.LensID = 0xffffffffffffffffULL; ZERO(imgdata.shootinginfo); imgdata.shootinginfo.DriveMode = -1; imgdata.shootinginfo.FocusMode = -1; imgdata.shootinginfo.MeteringMode = -1; imgdata.shootinginfo.AFPoint = -1; imgdata.shootinginfo.ExposureMode = -1; imgdata.shootinginfo.ImageStabilization = -1; _exitflag = 0; #ifdef USE_RAWSPEED if(_rawspeed_decoder) { RawDecoder *d = static_cast(_rawspeed_decoder); delete d; } _rawspeed_decoder = 0; #endif if(_x3f_data) { x3f_clear(_x3f_data); _x3f_data = 0; } memmgr.cleanup(); imgdata.thumbnail.tformat = LIBRAW_THUMBNAIL_UNKNOWN; imgdata.progress_flags = 0; load_raw = thumb_load_raw = 0; tls->init(); } const char * LibRaw::unpack_function_name() { libraw_decoder_info_t decoder_info; get_decoder_info(&decoder_info); return decoder_info.decoder_name; } int LibRaw::get_decoder_info(libraw_decoder_info_t* d_info) { if(!d_info) return LIBRAW_UNSPECIFIED_ERROR; d_info->decoder_name = 0; d_info->decoder_flags = 0; if (!load_raw) return LIBRAW_OUT_OF_ORDER_CALL; int rawdata = (imgdata.idata.filters || P1.colors == 1); // dcraw.c names order if (load_raw == &LibRaw::android_tight_load_raw) { d_info->decoder_name = "android_tight_load_raw()"; d_info->decoder_flags = LIBRAW_DECODER_FIXEDMAXC; } else if (load_raw == &LibRaw::android_loose_load_raw) { d_info->decoder_name = "android_loose_load_raw()"; d_info->decoder_flags = LIBRAW_DECODER_FIXEDMAXC; } else if (load_raw == &LibRaw::canon_600_load_raw) { d_info->decoder_name = "canon_600_load_raw()"; d_info->decoder_flags = LIBRAW_DECODER_FIXEDMAXC; } else if (load_raw == &LibRaw::xtrans_compressed_load_raw) { d_info->decoder_name = "xtrans_compressed_load_raw()"; } else if (load_raw == &LibRaw::canon_load_raw) { d_info->decoder_name = "canon_load_raw()"; } else if (load_raw == &LibRaw::lossless_jpeg_load_raw) { d_info->decoder_name = "lossless_jpeg_load_raw()"; d_info->decoder_flags = LIBRAW_DECODER_HASCURVE | LIBRAW_DECODER_TRYRAWSPEED; } else if (load_raw == &LibRaw::canon_sraw_load_raw) { d_info->decoder_name = "canon_sraw_load_raw()"; //d_info->decoder_flags = LIBRAW_DECODER_TRYRAWSPEED; } else if (load_raw == &LibRaw::lossless_dng_load_raw) { d_info->decoder_name = "lossless_dng_load_raw()"; d_info->decoder_flags = LIBRAW_DECODER_HASCURVE | LIBRAW_DECODER_TRYRAWSPEED | LIBRAW_DECODER_ADOBECOPYPIXEL; } else if (load_raw == &LibRaw::packed_dng_load_raw) { d_info->decoder_name = "packed_dng_load_raw()"; d_info->decoder_flags = LIBRAW_DECODER_HASCURVE | LIBRAW_DECODER_TRYRAWSPEED | LIBRAW_DECODER_ADOBECOPYPIXEL; } else if (load_raw == &LibRaw::pentax_load_raw ) { d_info->decoder_name = "pentax_load_raw()"; d_info->decoder_flags = LIBRAW_DECODER_TRYRAWSPEED; } else if (load_raw == &LibRaw::nikon_load_raw) { d_info->decoder_name = "nikon_load_raw()"; d_info->decoder_flags = LIBRAW_DECODER_TRYRAWSPEED; } else if (load_raw == &LibRaw::nikon_coolscan_load_raw ) { d_info->decoder_name = "nikon_coolscan_load_raw()"; d_info->decoder_flags = LIBRAW_DECODER_FIXEDMAXC; } else if (load_raw == &LibRaw::nikon_load_sraw ) { d_info->decoder_name = "nikon_load_sraw()"; d_info->decoder_flags = LIBRAW_DECODER_HASCURVE | LIBRAW_DECODER_FIXEDMAXC; } else if (load_raw == &LibRaw::nikon_yuv_load_raw ) { d_info->decoder_name = "nikon_load_yuv_load_raw()"; d_info->decoder_flags = LIBRAW_DECODER_HASCURVE | LIBRAW_DECODER_FIXEDMAXC; } else if (load_raw == &LibRaw::rollei_load_raw ) { // UNTESTED d_info->decoder_name = "rollei_load_raw()"; d_info->decoder_flags = LIBRAW_DECODER_FIXEDMAXC; } else if (load_raw == &LibRaw::phase_one_load_raw ) { d_info->decoder_name = "phase_one_load_raw()"; } else if (load_raw == &LibRaw::phase_one_load_raw_c ) { d_info->decoder_name = "phase_one_load_raw_c()"; } else if (load_raw == &LibRaw::hasselblad_load_raw ) { d_info->decoder_name = "hasselblad_load_raw()"; } else if (load_raw == &LibRaw::leaf_hdr_load_raw ) { d_info->decoder_name = "leaf_hdr_load_raw()"; } else if (load_raw == &LibRaw::unpacked_load_raw ) { d_info->decoder_name = "unpacked_load_raw()"; } else if (load_raw == &LibRaw::unpacked_load_raw_reversed ) { d_info->decoder_name = "unpacked_load_raw_reversed()"; d_info->decoder_flags = LIBRAW_DECODER_FIXEDMAXC; } else if (load_raw == &LibRaw::sinar_4shot_load_raw ) { // UNTESTED d_info->decoder_name = "sinar_4shot_load_raw()"; } else if (load_raw == &LibRaw::imacon_full_load_raw ) { d_info->decoder_name = "imacon_full_load_raw()"; } else if (load_raw == &LibRaw::hasselblad_full_load_raw ) { d_info->decoder_name = "hasselblad_full_load_raw()"; } else if (load_raw == &LibRaw::packed_load_raw ) { d_info->decoder_name = "packed_load_raw()"; d_info->decoder_flags = LIBRAW_DECODER_TRYRAWSPEED; } else if (load_raw == &LibRaw::broadcom_load_raw ) { // UNTESTED d_info->decoder_name = "broadcom_load_raw()"; d_info->decoder_flags = LIBRAW_DECODER_FIXEDMAXC; } else if (load_raw == &LibRaw::nokia_load_raw ) { // UNTESTED d_info->decoder_name = "nokia_load_raw()"; d_info->decoder_flags = LIBRAW_DECODER_FIXEDMAXC; } else if (load_raw == &LibRaw::canon_rmf_load_raw ) { // UNTESTED d_info->decoder_name = "canon_rmf_load_raw()"; } else if (load_raw == &LibRaw::panasonic_load_raw ) { d_info->decoder_name = "panasonic_load_raw()"; d_info->decoder_flags = LIBRAW_DECODER_TRYRAWSPEED; } else if (load_raw == &LibRaw::olympus_load_raw ) { d_info->decoder_name = "olympus_load_raw()"; d_info->decoder_flags = LIBRAW_DECODER_TRYRAWSPEED; } else if (load_raw == &LibRaw::minolta_rd175_load_raw ) { // UNTESTED d_info->decoder_name = "minolta_rd175_load_raw()"; } else if (load_raw == &LibRaw::quicktake_100_load_raw ) { // UNTESTED d_info->decoder_name = "quicktake_100_load_raw()"; } else if (load_raw == &LibRaw::kodak_radc_load_raw ) { d_info->decoder_name = "kodak_radc_load_raw()"; } else if (load_raw == &LibRaw::kodak_jpeg_load_raw ) { // UNTESTED + RBAYER d_info->decoder_name = "kodak_jpeg_load_raw()"; } else if (load_raw == &LibRaw::lossy_dng_load_raw) { // Check rbayer d_info->decoder_name = "lossy_dng_load_raw()"; d_info->decoder_flags = LIBRAW_DECODER_TRYRAWSPEED | LIBRAW_DECODER_HASCURVE; } else if (load_raw == &LibRaw::kodak_dc120_load_raw ) { d_info->decoder_name = "kodak_dc120_load_raw()"; } else if (load_raw == &LibRaw::eight_bit_load_raw ) { d_info->decoder_name = "eight_bit_load_raw()"; d_info->decoder_flags = LIBRAW_DECODER_HASCURVE|LIBRAW_DECODER_FIXEDMAXC; } else if (load_raw == &LibRaw::kodak_c330_load_raw ) { d_info->decoder_name = "kodak_yrgb_load_raw()"; d_info->decoder_flags = LIBRAW_DECODER_HASCURVE|LIBRAW_DECODER_FIXEDMAXC; } else if (load_raw == &LibRaw::kodak_c603_load_raw ) { d_info->decoder_name = "kodak_yrgb_load_raw()"; d_info->decoder_flags = LIBRAW_DECODER_HASCURVE|LIBRAW_DECODER_FIXEDMAXC; } else if (load_raw == &LibRaw::kodak_262_load_raw ) { d_info->decoder_name = "kodak_262_load_raw()"; // UNTESTED! d_info->decoder_flags = LIBRAW_DECODER_HASCURVE|LIBRAW_DECODER_FIXEDMAXC; } else if (load_raw == &LibRaw::kodak_65000_load_raw ) { d_info->decoder_name = "kodak_65000_load_raw()"; d_info->decoder_flags = LIBRAW_DECODER_HASCURVE; } else if (load_raw == &LibRaw::kodak_ycbcr_load_raw ) { // UNTESTED d_info->decoder_name = "kodak_ycbcr_load_raw()"; d_info->decoder_flags = LIBRAW_DECODER_HASCURVE|LIBRAW_DECODER_FIXEDMAXC; } else if (load_raw == &LibRaw::kodak_rgb_load_raw ) { // UNTESTED d_info->decoder_name = "kodak_rgb_load_raw()"; d_info->decoder_flags = LIBRAW_DECODER_FIXEDMAXC; } else if (load_raw == &LibRaw::sony_load_raw ) { d_info->decoder_name = "sony_load_raw()"; } else if (load_raw == &LibRaw::sony_arw_load_raw ) { d_info->decoder_name = "sony_arw_load_raw()"; d_info->decoder_flags = LIBRAW_DECODER_TRYRAWSPEED; } else if (load_raw == &LibRaw::sony_arw2_load_raw ) { d_info->decoder_name = "sony_arw2_load_raw()"; d_info->decoder_flags = LIBRAW_DECODER_HASCURVE | LIBRAW_DECODER_TRYRAWSPEED | LIBRAW_DECODER_SONYARW2; } else if (load_raw == &LibRaw::samsung_load_raw ) { d_info->decoder_name = "samsung_load_raw()"; d_info->decoder_flags = LIBRAW_DECODER_TRYRAWSPEED; } else if (load_raw == &LibRaw::samsung2_load_raw ) { d_info->decoder_name = "samsung2_load_raw()"; } else if (load_raw == &LibRaw::samsung3_load_raw ) { d_info->decoder_name = "samsung3_load_raw()"; } else if (load_raw == &LibRaw::smal_v6_load_raw ) { // UNTESTED d_info->decoder_name = "smal_v6_load_raw()"; d_info->decoder_flags = LIBRAW_DECODER_FIXEDMAXC; } else if (load_raw == &LibRaw::smal_v9_load_raw ) { // UNTESTED d_info->decoder_name = "smal_v9_load_raw()"; d_info->decoder_flags = LIBRAW_DECODER_FIXEDMAXC; } else if (load_raw == &LibRaw::redcine_load_raw) { d_info->decoder_name = "redcine_load_raw()"; d_info->decoder_flags = LIBRAW_DECODER_HASCURVE; } else if (load_raw == &LibRaw::x3f_load_raw ) { d_info->decoder_name = "x3f_load_raw()"; d_info->decoder_flags = LIBRAW_DECODER_OWNALLOC|LIBRAW_DECODER_FIXEDMAXC | LIBRAW_DECODER_LEGACY_WITH_MARGINS ; } else if (load_raw == &LibRaw::pentax_4shot_load_raw ) { d_info->decoder_name = "pentax_4shot_load_raw()"; d_info->decoder_flags = LIBRAW_DECODER_OWNALLOC; } else if (load_raw == &LibRaw::deflate_dng_load_raw ) { d_info->decoder_name = "deflate_dng_load_raw()"; d_info->decoder_flags = LIBRAW_DECODER_OWNALLOC; } else if (load_raw == &LibRaw::nikon_load_striped_packed_raw ) { d_info->decoder_name = "nikon_load_striped_packed_raw()"; } #ifdef LIBRAW_DEMOSAIC_PACK_GPL2 else if (load_raw == &LibRaw::foveon_sd_load_raw ) { d_info->decoder_name = "foveon_sd_load_raw()"; } else if (load_raw == &LibRaw::foveon_dp_load_raw ) { d_info->decoder_name = "foveon_dp_load_raw()"; } #endif else { d_info->decoder_name = "Unknown unpack function"; d_info->decoder_flags = LIBRAW_DECODER_NOTSET; } return LIBRAW_SUCCESS; } int LibRaw::adjust_maximum() { ushort real_max; float auto_threshold; if(O.adjust_maximum_thr < 0.00001) return LIBRAW_SUCCESS; else if (O.adjust_maximum_thr > 0.99999) auto_threshold = LIBRAW_DEFAULT_ADJUST_MAXIMUM_THRESHOLD; else auto_threshold = O.adjust_maximum_thr; real_max = C.data_maximum; if (real_max > 0 && real_max < C.maximum && real_max > C.maximum* auto_threshold) { C.maximum = real_max; } return LIBRAW_SUCCESS; } void LibRaw:: merror (void *ptr, const char *where) { if (ptr) return; if(callbacks.mem_cb)(*callbacks.mem_cb)(callbacks.memcb_data, libraw_internal_data.internal_data.input ?libraw_internal_data.internal_data.input->fname() :NULL, where); throw LIBRAW_EXCEPTION_ALLOC; } int LibRaw::open_file(const char *fname, INT64 max_buf_size) { #ifndef WIN32 struct stat st; if(stat(fname,&st)) return LIBRAW_IO_ERROR; int big = (st.st_size > max_buf_size)?1:0; #else struct _stati64 st; if(_stati64(fname,&st)) return LIBRAW_IO_ERROR; int big = (st.st_size > max_buf_size)?1:0; #endif LibRaw_abstract_datastream *stream; try { if(big) stream = new LibRaw_bigfile_datastream(fname); else stream = new LibRaw_file_datastream(fname); } catch (std::bad_alloc) { recycle(); return LIBRAW_UNSUFFICIENT_MEMORY; } if(!stream->valid()) { delete stream; return LIBRAW_IO_ERROR; } ID.input_internal = 0; // preserve from deletion on error int ret = open_datastream(stream); if (ret == LIBRAW_SUCCESS) { ID.input_internal =1 ; // flag to delete datastream on recycle } else { delete stream; ID.input_internal = 0; } return ret; } #if defined(_WIN32) && !defined(__MINGW32__) && defined(_MSC_VER) && (_MSC_VER > 1310) int LibRaw::open_file(const wchar_t *fname, INT64 max_buf_size) { struct _stati64 st; if(_wstati64(fname,&st)) return LIBRAW_IO_ERROR; int big = (st.st_size > max_buf_size)?1:0; LibRaw_abstract_datastream *stream; try { if(big) stream = new LibRaw_bigfile_datastream(fname); else stream = new LibRaw_file_datastream(fname); } catch (std::bad_alloc) { recycle(); return LIBRAW_UNSUFFICIENT_MEMORY; } if(!stream->valid()) { delete stream; return LIBRAW_IO_ERROR; } ID.input_internal = 0; // preserve from deletion on error int ret = open_datastream(stream); if (ret == LIBRAW_SUCCESS) { ID.input_internal =1 ; // flag to delete datastream on recycle } else { delete stream; ID.input_internal = 0; } return ret; } #endif int LibRaw::open_buffer(void *buffer, size_t size) { // this stream will close on recycle() if(!buffer || buffer==(void*)-1) return LIBRAW_IO_ERROR; LibRaw_buffer_datastream *stream; try { stream = new LibRaw_buffer_datastream(buffer,size); } catch (std::bad_alloc) { recycle(); return LIBRAW_UNSUFFICIENT_MEMORY; } if(!stream->valid()) { delete stream; return LIBRAW_IO_ERROR; } ID.input_internal = 0; // preserve from deletion on error int ret = open_datastream(stream); if (ret == LIBRAW_SUCCESS) { ID.input_internal =1 ; // flag to delete datastream on recycle } else { delete stream; ID.input_internal = 0; } return ret; } #ifdef USE_ZLIB inline unsigned int __DNG_HalfToFloat (ushort halfValue) { int sign = (halfValue >> 15) & 0x00000001; int exponent = (halfValue >> 10) & 0x0000001f; int mantissa = halfValue & 0x000003ff; if (exponent == 0) { if (mantissa == 0) { return (unsigned int) (sign << 31); } else { while (!(mantissa & 0x00000400)) { mantissa <<= 1; exponent -= 1; } exponent += 1; mantissa &= ~0x00000400; } } else if (exponent == 31) { if (mantissa == 0) { return (unsigned int) ((sign << 31) | ((0x1eL + 127 - 15) << 23) | (0x3ffL << 13)); } else { return 0; } } exponent += (127 - 15); mantissa <<= 13; return (unsigned int) ((sign << 31) | (exponent << 23) | mantissa); } inline unsigned int __DNG_FP24ToFloat (const unsigned char *input) { int sign = (input [0] >> 7) & 0x01; int exponent = (input [0] ) & 0x7F; int mantissa = (((int) input [1]) << 8) | input[2]; if (exponent == 0) { if (mantissa == 0) { return (unsigned int) (sign << 31); } else { while (!(mantissa & 0x00010000)) { mantissa <<= 1; exponent -= 1; } exponent += 1; mantissa &= ~0x00010000; } } else if (exponent == 127) { if (mantissa == 0) { return (unsigned int) ((sign << 31) | ((0x7eL + 128 - 64) << 23) | (0xffffL << 7)); } else { // Nan -- Just set to zero. return 0; } } exponent += (128 - 64); mantissa <<= 7; return (uint32_t) ((sign << 31) | (exponent << 23) | mantissa); } inline void DecodeDeltaBytes (unsigned char *bytePtr, int cols, int channels) { if (channels == 1) { unsigned char b0 = bytePtr [0]; bytePtr += 1; for (uint32_t col = 1; col < cols; ++col) { b0 += bytePtr [0]; bytePtr [0] = b0; bytePtr += 1; } } else if (channels == 3) { unsigned char b0 = bytePtr [0]; unsigned char b1 = bytePtr [1]; unsigned char b2 = bytePtr [2]; bytePtr += 3; for (int col = 1; col < cols; ++col) { b0 += bytePtr [0]; b1 += bytePtr [1]; b2 += bytePtr [2]; bytePtr [0] = b0; bytePtr [1] = b1; bytePtr [2] = b2; bytePtr += 3; } } else if (channels == 4) { unsigned char b0 = bytePtr [0]; unsigned char b1 = bytePtr [1]; unsigned char b2 = bytePtr [2]; unsigned char b3 = bytePtr [3]; bytePtr += 4; for (uint32_t col = 1; col < cols; ++col) { b0 += bytePtr [0]; b1 += bytePtr [1]; b2 += bytePtr [2]; b3 += bytePtr [3]; bytePtr [0] = b0; bytePtr [1] = b1; bytePtr [2] = b2; bytePtr [3] = b3; bytePtr += 4; } } else { for (int col = 1; col < cols; ++col) { for (int chan = 0; chan < channels; ++chan) { bytePtr [chan + channels] += bytePtr [chan]; } bytePtr += channels; } } } static void DecodeFPDelta (unsigned char *input, unsigned char *output, int cols, int channels, int bytesPerSample) { DecodeDeltaBytes (input, cols * bytesPerSample, channels); int32_t rowIncrement = cols * channels; if (bytesPerSample == 2) { #if LibRawBigEndian const unsigned char *input0 = input; const unsigned char *input1 = input + rowIncrement; #else const unsigned char *input1 = input; const unsigned char *input0 = input + rowIncrement; #endif for (int col = 0; col < rowIncrement; ++col) { output [0] = input0 [col]; output [1] = input1 [col]; output += 2; } } else if (bytesPerSample == 3) { const unsigned char *input0 = input; const unsigned char *input1 = input + rowIncrement; const unsigned char *input2 = input + rowIncrement * 2; for (int col = 0; col < rowIncrement; ++col) { output [0] = input0 [col]; output [1] = input1 [col]; output [2] = input2 [col]; output += 3; } } else { #if LibRawBigEndian const unsigned char *input0 = input; const unsigned char *input1 = input + rowIncrement; const unsigned char *input2 = input + rowIncrement * 2; const unsigned char *input3 = input + rowIncrement * 3; #else const unsigned char *input3 = input; const unsigned char *input2 = input + rowIncrement; const unsigned char *input1 = input + rowIncrement * 2; const unsigned char *input0 = input + rowIncrement * 3; #endif for (int col = 0; col < rowIncrement; ++col) { output [0] = input0 [col]; output [1] = input1 [col]; output [2] = input2 [col]; output [3] = input3 [col]; output += 4; } } } static float expandFloats(unsigned char * dst, int tileWidth, int bytesps) { float max = 0.f; if (bytesps == 2) { uint16_t * dst16 = (ushort *) dst; uint32_t * dst32 = (unsigned int *) dst; float *f32 = (float*) dst; for (int index = tileWidth - 1; index >= 0; --index) { dst32[index] = __DNG_HalfToFloat(dst16[index]); max = MAX(max,f32[index]); } } else if (bytesps == 3) { uint8_t * dst8 = ((unsigned char *) dst) + (tileWidth - 1) * 3; uint32_t * dst32 = (unsigned int *) dst; float *f32 = (float*) dst; for (int index = tileWidth - 1; index >= 0; --index, dst8 -= 3) { dst32[index] = __DNG_FP24ToFloat(dst8); max = MAX(max,f32[index]); } } else if (bytesps==4) { float *f32 = (float*) dst; for (int index = 0; index < tileWidth; index++) max = MAX(max,f32[index]); } return max; } void LibRaw::deflate_dng_load_raw() { struct tiff_ifd_t * ifd = &tiff_ifd[0]; while (ifd < &tiff_ifd[libraw_internal_data.identify_data.tiff_nifds] && ifd->offset != libraw_internal_data.unpacker_data.data_offset) ++ifd; if (ifd == &tiff_ifd[libraw_internal_data.identify_data.tiff_nifds]) { throw LIBRAW_EXCEPTION_DECODE_RAW; } float *float_raw_image=0; float max = 0.f; if(ifd->samples!=1 && ifd->samples!=3 && ifd->samples !=4) throw LIBRAW_EXCEPTION_DECODE_RAW; // Only float deflated supported if(libraw_internal_data.unpacker_data.tiff_samples != ifd->samples) throw LIBRAW_EXCEPTION_DECODE_RAW; // Wrong IFD size_t tilesH = (imgdata.sizes.raw_width + libraw_internal_data.unpacker_data.tile_width - 1) / libraw_internal_data.unpacker_data.tile_width; size_t tilesV = (imgdata.sizes.raw_height + libraw_internal_data.unpacker_data.tile_length - 1) / libraw_internal_data.unpacker_data.tile_length; size_t tileCnt = tilesH * tilesV; if (ifd->sample_format == 3) { // Floating point data float_raw_image = (float*)calloc(tileCnt*libraw_internal_data.unpacker_data.tile_length* libraw_internal_data.unpacker_data.tile_width * ifd->samples,sizeof(float)); //imgdata.color.maximum = 65535; //imgdata.color.black = 0; //memset(imgdata.color.cblack,0,sizeof(imgdata.color.cblack)); } else throw LIBRAW_EXCEPTION_DECODE_RAW; // Only float deflated supported int xFactor; switch(ifd->predictor) { case 3: default: xFactor = 1; break; case 34894: xFactor = 2; break; case 34895: xFactor = 4; break; } if (libraw_internal_data.unpacker_data.tile_length < INT_MAX) { if(tileCnt<1 || tileCnt > 1000000) throw LIBRAW_EXCEPTION_DECODE_RAW; size_t *tOffsets = (size_t*)malloc(tileCnt*sizeof(size_t)); for (int t = 0; t < tileCnt; ++t) tOffsets[t] = get4(); size_t *tBytes = (size_t*) malloc(tileCnt*sizeof(size_t)); unsigned long maxBytesInTile = 0; if (tileCnt == 1) tBytes[0] = maxBytesInTile = ifd->bytes; else { libraw_internal_data.internal_data.input->seek(ifd->bytes, SEEK_SET); for (size_t t = 0; t < tileCnt; ++t) { tBytes[t] = get4(); maxBytesInTile = MAX(maxBytesInTile,tBytes[t]); } } unsigned tilePixels = libraw_internal_data.unpacker_data.tile_width * libraw_internal_data.unpacker_data.tile_length; unsigned pixelSize = sizeof(float)*ifd->samples; unsigned tileBytes = tilePixels*pixelSize; unsigned tileRowBytes = libraw_internal_data.unpacker_data.tile_width*pixelSize; unsigned char *cBuffer = (unsigned char*)malloc(maxBytesInTile); unsigned char *uBuffer = (unsigned char*)malloc(tileBytes+tileRowBytes); // extra row for decoding for (size_t y = 0, t = 0; y < imgdata.sizes.raw_height; y += libraw_internal_data.unpacker_data.tile_length) { for (size_t x = 0; x < imgdata.sizes.raw_width; x += libraw_internal_data.unpacker_data.tile_width, ++t) { libraw_internal_data.internal_data.input->seek(tOffsets[t], SEEK_SET); libraw_internal_data.internal_data.input->read(cBuffer, 1, tBytes[t]); unsigned long dstLen = tileBytes; int err = uncompress(uBuffer+tileRowBytes, &dstLen, cBuffer, tBytes[t]); if (err != Z_OK) { free(tOffsets); free(tBytes); free(cBuffer); free(uBuffer); throw LIBRAW_EXCEPTION_DECODE_RAW; return; } else { int bytesps = ifd->bps >> 3; size_t rowsInTile = y + libraw_internal_data.unpacker_data.tile_length > imgdata.sizes.raw_height ? imgdata.sizes.raw_height - y : libraw_internal_data.unpacker_data.tile_length; size_t colsInTile= x + libraw_internal_data.unpacker_data.tile_width > imgdata.sizes.raw_width ? imgdata.sizes.raw_width - x : libraw_internal_data.unpacker_data.tile_width; for (size_t row = 0; row < rowsInTile; ++row) // do not process full tile if not needed { unsigned char* dst = uBuffer + row*libraw_internal_data.unpacker_data.tile_width*bytesps*ifd->samples; unsigned char* src = dst+tileRowBytes; DecodeFPDelta (src,dst, libraw_internal_data.unpacker_data.tile_width/ xFactor, ifd->samples * xFactor, bytesps); float lmax = expandFloats(dst, libraw_internal_data.unpacker_data.tile_width*ifd->samples, bytesps); max = MAX(max,lmax); unsigned char* dst2 = (unsigned char*)&float_raw_image[((y+row)*imgdata.sizes.raw_width + x)*ifd->samples]; memmove(dst2,dst,colsInTile*ifd->samples*sizeof(float)); } } } } free(tOffsets); free(tBytes); free(cBuffer); free(uBuffer); } imgdata.color.fmaximum = max; // Set fields according to data format imgdata.rawdata.raw_alloc = float_raw_image; if(ifd->samples == 1) { imgdata.rawdata.float_image = float_raw_image; imgdata.rawdata.sizes.raw_pitch = imgdata.sizes.raw_pitch = imgdata.sizes.raw_width*4; } else if(ifd->samples == 3) { imgdata.rawdata.float3_image = (float(*)[3])float_raw_image; imgdata.rawdata.sizes.raw_pitch = imgdata.sizes.raw_pitch = imgdata.sizes.raw_width*12; } else if(ifd->samples == 4) { imgdata.rawdata.float4_image = (float(*)[4])float_raw_image; imgdata.rawdata.sizes.raw_pitch = imgdata.sizes.raw_pitch = imgdata.sizes.raw_width*16; } if(imgdata.params.raw_processing_options & LIBRAW_PROCESSING_CONVERTFLOAT_TO_INT) convertFloatToInt(); // with default settings } #else void LibRaw::deflate_dng_load_raw() { throw LIBRAW_EXCEPTION_DECODE_RAW; } #endif int LibRaw::is_floating_point() { struct tiff_ifd_t * ifd = &tiff_ifd[0]; while (ifd < &tiff_ifd[libraw_internal_data.identify_data.tiff_nifds] && ifd->offset != libraw_internal_data.unpacker_data.data_offset) ++ifd; if (ifd == &tiff_ifd[libraw_internal_data.identify_data.tiff_nifds]) return 0; return ifd->sample_format == 3; } int LibRaw::have_fpdata() { return imgdata.rawdata.float_image || imgdata.rawdata.float3_image || imgdata.rawdata.float4_image; } void LibRaw::convertFloatToInt(float dmin/* =4096.f */, float dmax/* =32767.f */, float dtarget /*= 16383.f */) { int samples = 0; float *data = 0; if(imgdata.rawdata.float_image) { samples = 1; data = imgdata.rawdata.float_image; } else if (imgdata.rawdata.float3_image) { samples = 3; data = (float*)imgdata.rawdata.float3_image; } else if (imgdata.rawdata.float4_image) { samples = 4; data = (float*)imgdata.rawdata.float4_image; } else return; ushort *raw_alloc = (ushort*)malloc(imgdata.sizes.raw_height*imgdata.sizes.raw_width*libraw_internal_data.unpacker_data.tiff_samples*sizeof(ushort)); float tmax = MAX(imgdata.color.maximum,1); float datamax = imgdata.color.fmaximum; tmax = MAX(tmax,datamax); tmax = MAX(tmax,1.f); float multip = 1.f; if(tmax < dmin || tmax > dmax) { imgdata.rawdata.color.fnorm = imgdata.color.fnorm = multip = dtarget / tmax; imgdata.rawdata.color.maximum = imgdata.color.maximum = dtarget; imgdata.rawdata.color.black = imgdata.color.black = (float)imgdata.color.black*multip; for(int i=0; i= '0' && imgdata.params.p4shot_order[i] <= '3') { move_row = (imgdata.params.p4shot_order[i]-'0' & 2)?1:0; move_col = (imgdata.params.p4shot_order[i]-'0' & 1)?1:0; } else { move_row = _move[i].row; move_col = _move[i].col; } for(; tidx<16; tidx++) if(tiff_ifd[tidx].t_width == imgdata.sizes.raw_width && tiff_ifd[tidx].t_height == imgdata.sizes.raw_height && tiff_ifd[tidx].bps>8 && tiff_ifd[tidx].samples == 1 ) break; if(tidx>=16) break; imgdata.rawdata.raw_image = plane; ID.input->seek(tiff_ifd[tidx].offset, SEEK_SET); imgdata.idata.filters = 0xb4b4b4b4; libraw_internal_data.unpacker_data.data_offset = tiff_ifd[tidx].offset; (this->*pentax_component_load_raw)(); for(int row = 0; row < imgdata.sizes.raw_height-move_row; row++) { int colors[2]; for(int c = 0; c < 2; c++ ) colors[c] = COLOR(row,c); ushort *srcrow = &plane[imgdata.sizes.raw_width*row]; ushort (*dstrow)[4] = & result[(imgdata.sizes.raw_width)*(row+move_row)+move_col]; for(int col = 0; col < imgdata.sizes.raw_width-move_col; col++) dstrow[col][colors[col%2]] = srcrow[col]; } tidx++; } // assign things back: imgdata.sizes.raw_pitch = imgdata.sizes.raw_width*8; imgdata.idata.filters = 0; imgdata.rawdata.raw_alloc = imgdata.rawdata.color4_image = result; free(plane); imgdata.rawdata.raw_image = 0; } void LibRaw::hasselblad_full_load_raw() { int row, col; for (row=0; row < S.height; row++) for (col=0; col < S.width; col++) { read_shorts (&imgdata.image[row*S.width+col][2], 1); // B read_shorts (&imgdata.image[row*S.width+col][1], 1); // G read_shorts (&imgdata.image[row*S.width+col][0], 1); // R } } void LibRaw::nikon_load_striped_packed_raw() { int vbits=0, bwide, rbits, bite,row, col, val, i; UINT64 bitbuf=0; unsigned load_flags = 24; //libraw_internal_data.unpacker_data.load_flags; unsigned tiff_bps = libraw_internal_data.unpacker_data.tiff_bps; int tiff_compress = libraw_internal_data.unpacker_data.tiff_compress; struct tiff_ifd_t * ifd = &tiff_ifd[0]; while (ifd < &tiff_ifd[libraw_internal_data.identify_data.tiff_nifds] && ifd->offset != libraw_internal_data.unpacker_data.data_offset) ++ifd; if (ifd == &tiff_ifd[libraw_internal_data.identify_data.tiff_nifds]) throw LIBRAW_EXCEPTION_DECODE_RAW; if(!ifd->rows_per_strip || !ifd->strip_offsets_count) return; // not unpacked int stripcnt = 0; bwide = S.raw_width * tiff_bps / 8; bwide += bwide & load_flags >> 7; rbits = bwide * 8 - S.raw_width * tiff_bps; if (load_flags & 1) bwide = bwide * 16 / 15; bite = 8 + (load_flags & 24); for (row=0; row < S.raw_height; row++) { checkCancel(); if(!(row%ifd->rows_per_strip)) { if(stripcnt >= ifd->strip_offsets_count) return; // run out of data libraw_internal_data.internal_data.input->seek(ifd->strip_offsets[stripcnt],SEEK_SET); stripcnt++; } for (col=0; col < S.raw_width; col++) { for (vbits -= tiff_bps; vbits < 0; vbits += bite) { bitbuf <<= bite; for (i=0; i < bite; i+=8) bitbuf |= (unsigned) (libraw_internal_data.internal_data.input->get_char() << i); } imgdata.rawdata.raw_image[(row)*S.raw_width+(col)] = bitbuf << (64-tiff_bps-vbits) >> (64-tiff_bps); } vbits -= rbits; } } struct foveon_data_t { const char *make; const char *model; const int raw_width,raw_height; const int white; const int left_margin,top_margin; const int width,height; } foveon_data [] = { {"Sigma","SD9",2304,1531,12000,20,8,2266,1510}, {"Sigma","SD9",1152,763,12000,10,2,1132,755}, {"Sigma","SD10",2304,1531,12000,20,8,2266,1510}, {"Sigma","SD10",1152,763,12000,10,2,1132,755}, {"Sigma","SD14",2688,1792,14000,18,12,2651,1767}, {"Sigma","SD14",2688,896,14000,18,6,2651,883}, // 2/3 {"Sigma","SD14",1344,896,14000,9,6,1326,883}, // 1/2 {"Sigma","SD15",2688,1792,2900,18,12,2651,1767}, {"Sigma","SD15",2688,896,2900,18,6,2651,883}, // 2/3 ? {"Sigma","SD15",1344,896,2900,9,6,1326,883}, // 1/2 ? {"Sigma","DP1",2688,1792,2100,18,12,2651,1767}, {"Sigma","DP1",2688,896,2100,18,6,2651,883}, // 2/3 ? {"Sigma","DP1",1344,896,2100,9,6,1326,883}, // 1/2 ? {"Sigma","DP1S",2688,1792,2200,18,12,2651,1767}, {"Sigma","DP1S",2688,896,2200,18,6,2651,883}, // 2/3 {"Sigma","DP1S",1344,896,2200,9,6,1326,883}, // 1/2 {"Sigma","DP1X",2688,1792,3560,18,12,2651,1767}, {"Sigma","DP1X",2688,896,3560,18,6,2651,883}, // 2/3 {"Sigma","DP1X",1344,896,3560,9,6,1326,883}, // 1/2 {"Sigma","DP2",2688,1792,2326,13,16,2651,1767}, {"Sigma","DP2",2688,896,2326,13,8,2651,883}, // 2/3 ?? {"Sigma","DP2",1344,896,2326,7,8,1325,883}, // 1/2 ?? {"Sigma","DP2S",2688,1792,2300,18,12,2651,1767}, {"Sigma","DP2S",2688,896,2300,18,6,2651,883}, // 2/3 {"Sigma","DP2S",1344,896,2300,9,6,1326,883}, // 1/2 {"Sigma","DP2X",2688,1792,2300,18,12,2651,1767}, {"Sigma","DP2X",2688,896,2300,18,6,2651,883}, // 2/3 {"Sigma","DP2X",1344,896,2300,9,6,1325,883}, // 1/2 {"Sigma","SD1",4928,3264,3900,12,52,4807,3205}, // Full size {"Sigma","SD1",4928,1632,3900,12,26,4807,1603}, // 2/3 size {"Sigma","SD1",2464,1632,3900,6,26,2403,1603}, // 1/2 size {"Sigma","SD1 Merrill",4928,3264,3900,12,52,4807,3205}, // Full size {"Sigma","SD1 Merrill",4928,1632,3900,12,26,4807,1603}, // 2/3 size {"Sigma","SD1 Merrill",2464,1632,3900,6,26,2403,1603}, // 1/2 size {"Sigma","DP1 Merrill",4928,3264,3900,12,0,4807,3205}, {"Sigma","DP1 Merrill",2464,1632,3900,12,0,2403,1603}, // 1/2 size {"Sigma","DP1 Merrill",4928,1632,3900,12,0,4807,1603}, // 2/3 size {"Sigma","DP2 Merrill",4928,3264,3900,12,0,4807,3205}, {"Sigma","DP2 Merrill",2464,1632,3900,12,0,2403,1603}, // 1/2 size {"Sigma","DP2 Merrill",4928,1632,3900,12,0,4807,1603}, // 2/3 size {"Sigma","DP3 Merrill",4928,3264,3900,12,0,4807,3205}, {"Sigma","DP3 Merrill",2464,1632,3900,12,0,2403,1603}, // 1/2 size {"Sigma","DP3 Merrill",4928,1632,3900,12,0,4807,1603}, // 2/3 size {"Polaroid","x530",1440,1088,2700,10,13,1419,1059}, // dp2 Q {"Sigma","dp3 Quattro",5888,3672,16383,204,24,5446,3624}, // full size {"Sigma","dp3 Quattro",2944,1836,16383,102,12,2723,1812}, // half size {"Sigma","dp2 Quattro",5888,3672,16383,204,24,5446,3624}, // full size {"Sigma","dp2 Quattro",2944,1836,16383,102,12,2723,1812}, // half size {"Sigma","dp1 Quattro",5888,3672,16383,204,24,5446,3624}, // full size {"Sigma","dp1 Quattro",2944,1836,16383,102,12,2723,1812}, // half size {"Sigma","dp0 Quattro",5888,3672,16383,204,24,5446,3624}, // full size {"Sigma","dp0 Quattro",2944,1836,16383,102,12,2723,1812}, // half size // Sigma sd Quattro {"Sigma","sd Quattro",5888,3776,16383,204,76,5446,3624}, // full size {"Sigma","sd Quattro",2944,1888,16383,102,38,2723,1812}, // half size // Sd Quattro H {"Sigma","sd Quattro H",6656,4480,16383,224,160,6208,4160}, // full size {"Sigma","sd Quattro H",3328,2240,16383,112,80,3104,2080}, // half size {"Sigma","sd Quattro H",5504,3680,16383,0,4,5496,3668}, // full size {"Sigma","sd Quattro H",2752,1840,16383,0,2,2748,1834}, // half size }; const int foveon_count = sizeof(foveon_data)/sizeof(foveon_data[0]); int LibRaw::open_datastream(LibRaw_abstract_datastream *stream) { if(!stream) return ENOENT; if(!stream->valid()) return LIBRAW_IO_ERROR; recycle(); try { ID.input = stream; SET_PROC_FLAG(LIBRAW_PROGRESS_OPEN); identify(); if (!strcasecmp(imgdata.idata.make, "Canon") && (load_raw == &LibRaw::canon_sraw_load_raw) && imgdata.sizes.raw_width>0) { float ratio = float(imgdata.sizes.raw_height) / float(imgdata.sizes.raw_width); if((ratio < 0.57 || ratio > 0.75) && imgdata.makernotes.canon.SensorHeight>1 && imgdata.makernotes.canon.SensorWidth > 1) { imgdata.sizes.raw_width = imgdata.makernotes.canon.SensorWidth; imgdata.sizes.left_margin = imgdata.makernotes.canon.SensorLeftBorder; imgdata.sizes.iwidth = imgdata.sizes.width = imgdata.makernotes.canon.SensorRightBorder - imgdata.makernotes.canon.SensorLeftBorder+1; imgdata.sizes.raw_height = imgdata.makernotes.canon.SensorHeight; imgdata.sizes.top_margin = imgdata.makernotes.canon.SensorTopBorder; imgdata.sizes.iheight = imgdata.sizes.height = imgdata.makernotes.canon.SensorBottomBorder - imgdata.makernotes.canon.SensorTopBorder+1; libraw_internal_data.unpacker_data.load_flags |= 256; // reset width/height in canon_sraw_load_raw() imgdata.sizes.raw_pitch = 8*imgdata.sizes.raw_width; } else if(imgdata.sizes.raw_width == 4032 && imgdata.sizes.raw_height == 3402 && !strcasecmp(imgdata.idata.model, "EOS 80D")) // 80D hardcoded { imgdata.sizes.raw_width = 4536; imgdata.sizes.left_margin = 28; imgdata.sizes.iwidth = imgdata.sizes.width = imgdata.sizes.raw_width - imgdata.sizes.left_margin; imgdata.sizes.raw_height = 3024; imgdata.sizes.top_margin = 8; imgdata.sizes.iheight = imgdata.sizes.height = imgdata.sizes.raw_height - imgdata.sizes.top_margin; libraw_internal_data.unpacker_data.load_flags |= 256; imgdata.sizes.raw_pitch = 8*imgdata.sizes.raw_width; } } // XTrans Compressed? if (!imgdata.idata.dng_version && !strcasecmp(imgdata.idata.make, "Fujifilm") && (load_raw == &LibRaw::unpacked_load_raw) ) { if (imgdata.sizes.raw_width * imgdata.sizes.raw_height * 2 != libraw_internal_data.unpacker_data.data_size) parse_xtrans_header(); if(imgdata.idata.filters == 9) { // Adjust top/left margins for X-Trans int newtm = imgdata.sizes.top_margin%6?(imgdata.sizes.top_margin/6+1)*6 : imgdata.sizes.top_margin; int newlm = imgdata.sizes.left_margin%6?(imgdata.sizes.left_margin/6+1)*6 : imgdata.sizes.left_margin; if(newtm != imgdata.sizes.top_margin || newlm != imgdata.sizes.left_margin) { imgdata.sizes.height -= (newtm - imgdata.sizes.top_margin); imgdata.sizes.top_margin = newtm; imgdata.sizes.width -= (newlm - imgdata.sizes.left_margin); imgdata.sizes.left_margin = newlm; for(int c = 0; c < 36; c++) imgdata.idata.xtrans[0][c] = imgdata.idata.xtrans_abs[0][c]; } } } // Fix DNG white balance if needed if(imgdata.idata.dng_version && (imgdata.idata.filters == 0) && imgdata.idata.colors > 1 && imgdata.idata.colors < 5) { float delta[4]={0.f,0.f,0.f,0.f}; for(int c = 0; c < imgdata.idata.colors ; c++ ) delta[c] = imgdata.color.dng_levels.dng_whitelevel[c] - imgdata.color.dng_levels.dng_blacklevel[c]; float mindelta = delta[0],maxdelta = delta[0]; for(int c = 1; c < imgdata.idata.colors; c++) { if(mindelta > delta[c]) mindelta = delta[c]; if(maxdelta < delta[c]) maxdelta = delta[c]; } if(mindelta > 1 && maxdelta < (mindelta *20)) // safety { for(int c = 0; c < imgdata.idata.colors; c++) { imgdata.color.cam_mul[c] /= (delta[c]/maxdelta); imgdata.color.pre_mul[c] /= (delta[c]/maxdelta); } imgdata.color.maximum = imgdata.color.cblack[0]+maxdelta; } } if(imgdata.idata.dng_version && ( (!strcasecmp(imgdata.idata.make,"Leica") && !strcasecmp(imgdata.idata.model,"D-LUX (Typ 109)")) || (!strcasecmp(imgdata.idata.make,"Panasonic") && !strcasecmp(imgdata.idata.model,"LX100")) ) ) imgdata.sizes.width = 4288; if (!strncasecmp(imgdata.idata.make, "Sony", 4) && imgdata.idata.dng_version) { if(S.raw_width == 3984) S.width = 3925; else if (S.raw_width == 4288) S.width = S.raw_width-32; else if (S.raw_width == 4928 && S.height < 3280) S.width = S.raw_width-8; else if (S.raw_width == 5504) S.width = S.raw_width-(S.height > 3664 ? 8 : 32); else if (S.raw_width == 6048) { S.width = S.raw_width-24; if (strstr(imgdata.idata.model,"RX1") || strstr(imgdata.idata.model,"A99")) S.width -= 6; } else if (S.raw_width == 7392) S.width = S.raw_width-30; else if(S.raw_width == 8000) S.width = S.raw_width - 32; } if(!strcasecmp(imgdata.idata.make,"Pentax") && /*!strcasecmp(imgdata.idata.model,"K-3 II") &&*/ imgdata.idata.raw_count == 4 && (imgdata.params.raw_processing_options & LIBRAW_PROCESSING_PENTAX_PS_ALLFRAMES)) { imgdata.idata.raw_count = 1; imgdata.idata.filters = 0; imgdata.idata.colors = 4; IO.mix_green = 1; pentax_component_load_raw = load_raw; load_raw= &LibRaw::pentax_4shot_load_raw; } if (!imgdata.idata.dng_version && !strcmp(imgdata.idata.make, "Leaf") && !strcmp(imgdata.idata.model, "Credo 50")) { imgdata.color.pre_mul[0] = 1.f / 0.3984f; imgdata.color.pre_mul[2] = 1.f / 0.7666f; imgdata.color.pre_mul[1] = imgdata.color.pre_mul[3] = 1.0; } // S3Pro DNG patch if(imgdata.idata.dng_version && !strcmp(imgdata.idata.make,"Fujifilm") && !strcmp(imgdata.idata.model,"S3Pro") && imgdata.sizes.raw_width == 4288 ) { imgdata.sizes.left_margin++; imgdata.sizes.width--; } if(imgdata.idata.dng_version && !strcmp(imgdata.idata.make,"Fujifilm") && !strcmp(imgdata.idata.model,"S5Pro") && imgdata.sizes.raw_width == 4288 ) { imgdata.sizes.left_margin++; imgdata.sizes.width--; } if(!imgdata.idata.dng_version && !strcmp(imgdata.idata.make,"Fujifilm") && (!strncmp(imgdata.idata.model,"S20Pro",6) || !strncmp(imgdata.idata.model,"F700",4)) ) { imgdata.sizes.raw_width/=2; load_raw= &LibRaw::unpacked_load_raw_fuji_f700s20; } if(load_raw == &LibRaw::packed_load_raw && !strcasecmp(imgdata.idata.make,"Nikon") && !libraw_internal_data.unpacker_data.load_flags && (!strncasecmp(imgdata.idata.model,"D810",4) || !strcasecmp(imgdata.idata.model,"D4S")) && libraw_internal_data.unpacker_data.data_size*2 == imgdata.sizes.raw_height*imgdata.sizes.raw_width*3) { libraw_internal_data.unpacker_data.load_flags = 80; } // Adjust BL for Sony A900/A850 if(load_raw == &LibRaw::packed_load_raw && !strcasecmp(imgdata.idata.make,"Sony")) // 12 bit sony, but metadata may be for 14-bit range { if(C.maximum>4095) C.maximum = 4095; if(C.black > 256 || C.cblack[0] > 256) { C.black /=4; for(int c=0; c< 4; c++) C.cblack[c]/=4; for(int c=0; c< C.cblack[4]*C.cblack[5];c++) C.cblack[6+c]/=4; } } if( load_raw == &LibRaw::nikon_yuv_load_raw ) // Is it Nikon sRAW? { load_raw= &LibRaw::nikon_load_sraw; C.black =0; memset(C.cblack,0,sizeof(C.cblack)); imgdata.idata.filters = 0; libraw_internal_data.unpacker_data.tiff_samples=3; imgdata.idata.colors = 3; double beta_1 = -5.79342238397656E-02; double beta_2 = 3.28163551282665; double beta_3 = -8.43136004842678; double beta_4 = 1.03533181861023E+01; for(int i=0; i<=3072;i++) { double x = (double)i/3072.; double y = (1.-exp(-beta_1*x-beta_2*x*x-beta_3*x*x*x-beta_4*x*x*x*x)); if(y<0.)y=0.; imgdata.color.curve[i] = (y*16383.); } for(int i=0;i<3;i++) for(int j=0;j<4;j++) imgdata.color.rgb_cam[i][j]=float(i==j); } // Adjust BL for Nikon 12bit if(( load_raw == &LibRaw::nikon_load_raw || load_raw == &LibRaw::packed_load_raw) && !strcasecmp(imgdata.idata.make,"Nikon") && strncmp(imgdata.idata.model,"COOLPIX",7) // && strncmp(imgdata.idata.model,"1 ",2) && libraw_internal_data.unpacker_data.tiff_bps == 12) { C.maximum = 4095; C.black /=4; for(int c=0; c< 4; c++) C.cblack[c]/=4; for(int c=0; c< C.cblack[4]*C.cblack[5];c++) C.cblack[6+c]/=4; } // Adjust Highlight Linearity limit if (C.linear_max[0] < 0) { if (imgdata.idata.dng_version) { for (int c=0; c<4; c++) C.linear_max[c] = -1 * C.linear_max[c] + imgdata.color.cblack[c+6]; } else { for (int c=0; c<4; c++) C.linear_max[c] = -1 * C.linear_max[c] + imgdata.color.cblack[c]; } } if (!strcasecmp(imgdata.idata.make,"Nikon") && (!C.linear_max[0]) && (C.maximum > 1024) && (load_raw != &LibRaw::nikon_load_sraw)) { C.linear_max[0] = C.linear_max[1] = C.linear_max[2] = C.linear_max[3] = (long) ((float)(C.maximum) / 1.07f); } // Correct WB for Samsung GX20 if (!strcasecmp(imgdata.idata.make,"Samsung") && !strcasecmp(imgdata.idata.model,"GX20")) { C.WB_Coeffs[LIBRAW_WBI_Daylight][2] = (int) ((float) (C.WB_Coeffs[LIBRAW_WBI_Daylight][2]) * 2.56f); C.WB_Coeffs[LIBRAW_WBI_Shade][2] = (int) ((float) (C.WB_Coeffs[LIBRAW_WBI_Shade][2]) * 2.56f); C.WB_Coeffs[LIBRAW_WBI_Cloudy][2] = (int) ((float) (C.WB_Coeffs[LIBRAW_WBI_Cloudy][2]) * 2.56f); C.WB_Coeffs[LIBRAW_WBI_Tungsten][2] = (int) ((float) (C.WB_Coeffs[LIBRAW_WBI_Tungsten][2]) * 2.56f); C.WB_Coeffs[LIBRAW_WBI_FL_D][2] = (int) ((float) (C.WB_Coeffs[LIBRAW_WBI_FL_D][2]) * 2.56f); C.WB_Coeffs[LIBRAW_WBI_FL_N][2] = (int) ((float) (C.WB_Coeffs[LIBRAW_WBI_FL_N][2]) * 2.56f); C.WB_Coeffs[LIBRAW_WBI_FL_W][2] = (int) ((float) (C.WB_Coeffs[LIBRAW_WBI_FL_W][2]) * 2.56f); C.WB_Coeffs[LIBRAW_WBI_Flash][2] = (int) ((float) (C.WB_Coeffs[LIBRAW_WBI_Flash][2]) * 2.56f); for (int c=0; c<64; c++) { if (imgdata.color.WBCT_Coeffs[c][0] > 0.0f) { imgdata.color.WBCT_Coeffs[c][3] *= 2.56f; } } } // Adjust BL for Panasonic if(load_raw == &LibRaw::panasonic_load_raw && (!strcasecmp(imgdata.idata.make,"Panasonic") || !strcasecmp(imgdata.idata.make,"Leica") || !strcasecmp(imgdata.idata.make,"YUNEEC")) && ID.pana_black[0] && ID.pana_black[1] && ID.pana_black[2]) { C.black=0; C.cblack[0] = ID.pana_black[0]+ID.pana_black[3]; C.cblack[1] = C.cblack[3] = ID.pana_black[1]+ID.pana_black[3]; C.cblack[2] = ID.pana_black[2]+ID.pana_black[3]; int i = C.cblack[3]; for(int c=0; c<3; c++) if(i>C.cblack[c]) i = C.cblack[c]; for(int c=0; c< 4; c++) C.cblack[c]-=i; C.black = i; } // Adjust sizes for X3F processing if(load_raw == &LibRaw::x3f_load_raw) { for(int i=0; i< foveon_count;i++) if(!strcasecmp(imgdata.idata.make,foveon_data[i].make) && !strcasecmp(imgdata.idata.model,foveon_data[i].model) && imgdata.sizes.raw_width == foveon_data[i].raw_width && imgdata.sizes.raw_height == foveon_data[i].raw_height ) { imgdata.sizes.top_margin = foveon_data[i].top_margin; imgdata.sizes.left_margin = foveon_data[i].left_margin; imgdata.sizes.width = imgdata.sizes.iwidth = foveon_data[i].width; imgdata.sizes.height = imgdata.sizes.iheight = foveon_data[i].height; C.maximum = foveon_data[i].white; break; } } #if 0 size_t bytes = ID.input->size()-libraw_internal_data.unpacker_data.data_offset; float bpp = float(bytes)/float(S.raw_width)/float(S.raw_height); float bpp2 = float(bytes)/float(S.width)/float(S.height); printf("RawSize: %dx%d data offset: %d data size:%d bpp: %g bpp2: %g\n",S.raw_width,S.raw_height,libraw_internal_data.unpacker_data.data_offset,bytes,bpp,bpp2); if(!strcasecmp(imgdata.idata.make,"Hasselblad") && bpp == 6.0f) { load_raw = &LibRaw::hasselblad_full_load_raw; S.width = S.raw_width; S.height = S.raw_height; P1.filters = 0; P1.colors=3; P1.raw_count=1; C.maximum=0xffff; printf("3 channel hassy found\n"); } #endif if(C.profile_length) { if(C.profile) free(C.profile); C.profile = malloc(C.profile_length); merror(C.profile,"LibRaw::open_file()"); ID.input->seek(ID.profile_offset,SEEK_SET); ID.input->read(C.profile,C.profile_length,1); } SET_PROC_FLAG(LIBRAW_PROGRESS_IDENTIFY); } catch ( LibRaw_exceptions err) { EXCEPTION_HANDLER(err); } catch (std::exception ee) { EXCEPTION_HANDLER(LIBRAW_EXCEPTION_IO_CORRUPT); } if(P1.raw_count < 1) return LIBRAW_FILE_UNSUPPORTED; write_fun = &LibRaw::write_ppm_tiff; if (load_raw == &LibRaw::kodak_ycbcr_load_raw) { S.height += S.height & 1; S.width += S.width & 1; } IO.shrink = P1.filters && (O.half_size || ((O.threshold || O.aber[0] != 1 || O.aber[2] != 1) )); S.iheight = (S.height + IO.shrink) >> IO.shrink; S.iwidth = (S.width + IO.shrink) >> IO.shrink; // Save color,sizes and internal data into raw_image fields memmove(&imgdata.rawdata.color,&imgdata.color,sizeof(imgdata.color)); memmove(&imgdata.rawdata.sizes,&imgdata.sizes,sizeof(imgdata.sizes)); memmove(&imgdata.rawdata.iparams,&imgdata.idata,sizeof(imgdata.idata)); memmove(&imgdata.rawdata.ioparams,&libraw_internal_data.internal_output_params,sizeof(libraw_internal_data.internal_output_params)); SET_PROC_FLAG(LIBRAW_PROGRESS_SIZE_ADJUST); return LIBRAW_SUCCESS; } #ifdef USE_RAWSPEED void LibRaw::fix_after_rawspeed(int bl) { if (load_raw == &LibRaw::lossy_dng_load_raw) C.maximum = 0xffff; else if (load_raw == &LibRaw::sony_load_raw) C.maximum = 0x3ff0; } #else void LibRaw::fix_after_rawspeed(int) { } #endif void LibRaw::clearCancelFlag() { #ifdef WIN32 InterlockedExchange(&_exitflag, 0); #else __sync_fetch_and_and(&_exitflag, 0); #endif #ifdef RAWSPEED_FASTEXIT if (_rawspeed_decoder) { RawDecoder *d = static_cast(_rawspeed_decoder); d->resumeProcessing(); } #endif } void LibRaw::setCancelFlag() { #ifdef WIN32 InterlockedExchange(&_exitflag,1); #else __sync_fetch_and_add(&_exitflag,1); #endif #ifdef RAWSPEED_FASTEXIT if(_rawspeed_decoder) { RawDecoder *d = static_cast(_rawspeed_decoder); d->cancelProcessing(); } #endif } void LibRaw::checkCancel() { #ifdef WIN32 if(InterlockedExchange(&_exitflag,0)) throw LIBRAW_EXCEPTION_CANCELLED_BY_CALLBACK; #else if( __sync_fetch_and_and(&_exitflag,0)) throw LIBRAW_EXCEPTION_CANCELLED_BY_CALLBACK; #endif } int LibRaw::try_rawspeed() { #ifdef USE_RAWSPEED int ret=LIBRAW_SUCCESS; int rawspeed_ignore_errors = 0; if (imgdata.idata.dng_version && imgdata.idata.colors == 3 && !strcasecmp(imgdata.idata.software, "Adobe Photoshop Lightroom 6.1.1 (Windows)")) rawspeed_ignore_errors = 1; // RawSpeed Supported, INT64 spos = ID.input->tell(); void *_rawspeed_buffer = 0; try { // printf("Using rawspeed\n"); ID.input->seek(0,SEEK_SET); INT64 _rawspeed_buffer_sz = ID.input->size()+32; _rawspeed_buffer = malloc(_rawspeed_buffer_sz); if(!_rawspeed_buffer) throw LIBRAW_EXCEPTION_ALLOC; ID.input->read(_rawspeed_buffer,_rawspeed_buffer_sz,1); FileMap map((uchar8*)_rawspeed_buffer,_rawspeed_buffer_sz); RawParser t(&map); RawDecoder *d = 0; CameraMetaDataLR *meta = static_cast(_rawspeed_camerameta); d = t.getDecoder(); if(!d) throw "Unable to find decoder"; try { d->checkSupport(meta); } catch (const RawDecoderException& e) { imgdata.process_warnings |= LIBRAW_WARN_RAWSPEED_UNSUPPORTED; throw e; } d->interpolateBadPixels = FALSE; d->applyStage1DngOpcodes = FALSE; _rawspeed_decoder = static_cast(d); d->decodeRaw(); d->decodeMetaData(meta); RawImage r = d->mRaw; if( r->errors.size()>0 && !rawspeed_ignore_errors) { delete d; _rawspeed_decoder = 0; throw 1; } if (r->isCFA) { imgdata.rawdata.raw_image = (ushort*) r->getDataUncropped(0,0); } else if(r->getCpp()==4) { imgdata.rawdata.color4_image = (ushort(*)[4]) r->getDataUncropped(0,0); if(r->whitePoint > 0 && r->whitePoint < 65536) C.maximum = r->whitePoint; } else if(r->getCpp() == 3) { imgdata.rawdata.color3_image = (ushort(*)[3]) r->getDataUncropped(0,0); if(r->whitePoint > 0 && r->whitePoint < 65536) C.maximum = r->whitePoint; } else { delete d; _rawspeed_decoder = 0; ret = LIBRAW_UNSPECIFIED_ERROR; } if(_rawspeed_decoder) { // set sizes iPoint2D rsdim = r->getUncroppedDim(); S.raw_pitch = r->pitch; S.raw_width = rsdim.x; S.raw_height = rsdim.y; //C.maximum = r->whitePoint; fix_after_rawspeed(r->blackLevel); } free(_rawspeed_buffer); _rawspeed_buffer = 0; imgdata.process_warnings |= LIBRAW_WARN_RAWSPEED_PROCESSED; } catch (const RawDecoderException& RDE) { imgdata.process_warnings |= LIBRAW_WARN_RAWSPEED_PROBLEM; if (_rawspeed_buffer) { free(_rawspeed_buffer); _rawspeed_buffer = 0; } const char *p = RDE.what(); if (!strncmp(RDE.what(), "Decoder canceled", strlen("Decoder canceled"))) throw LIBRAW_EXCEPTION_CANCELLED_BY_CALLBACK; ret = LIBRAW_UNSPECIFIED_ERROR; } catch (...) { // We may get here due to cancellation flag imgdata.process_warnings |= LIBRAW_WARN_RAWSPEED_PROBLEM; if(_rawspeed_buffer) { free(_rawspeed_buffer); _rawspeed_buffer = 0; } ret = LIBRAW_UNSPECIFIED_ERROR; } ID.input->seek(spos,SEEK_SET); return ret; #else return LIBRAW_NOT_IMPLEMENTED; #endif } int LibRaw::valid_for_dngsdk() { #ifndef USE_DNGSDK return 0; #else if(!imgdata.idata.dng_version) return 0; if(!imgdata.params.use_dngsdk) return 0; if (load_raw == &LibRaw::lossy_dng_load_raw) return 0; if(is_floating_point() && (imgdata.params.use_dngsdk & LIBRAW_DNG_FLOAT)) return 1; if(!imgdata.idata.filters && (imgdata.params.use_dngsdk & LIBRAW_DNG_LINEAR)) return 1; if(libraw_internal_data.unpacker_data.tiff_bps == 8 && (imgdata.params.use_dngsdk & LIBRAW_DNG_8BIT)) return 1; if(libraw_internal_data.unpacker_data.tiff_compress == 8 && (imgdata.params.use_dngsdk & LIBRAW_DNG_DEFLATE)) return 1; if(libraw_internal_data.unpacker_data.tiff_samples == 2 ) return 0; // Always deny 2-samples (old fuji superccd) if(imgdata.idata.filters == 9 && (imgdata.params.use_dngsdk & LIBRAW_DNG_XTRANS)) return 1; if(is_fuji_rotated()) return 0; // refuse if(imgdata.params.use_dngsdk & LIBRAW_DNG_OTHER) return 1; return 0; #endif } int LibRaw::is_curve_linear() { for (int i=0; i < 0x10000; i++) if(imgdata.color.curve[i] != i) return 0; return 1; } int LibRaw::try_dngsdk() { #ifdef USE_DNGSDK if(!dnghost) return LIBRAW_UNSPECIFIED_ERROR; dng_host *host = static_cast(dnghost); try { libraw_dng_stream stream(libraw_internal_data.internal_data.input); AutoPtr negative; negative.Reset (host->Make_dng_negative ()); dng_info info; info.Parse (*host, stream); info.PostParse (*host); if (!info.IsValidDNG ()) { return LIBRAW_DATA_ERROR; } negative->Parse (*host, stream, info); negative->PostParse (*host, stream, info); negative->ReadStage1Image (*host, stream, info); dng_simple_image *stage2 = (dng_simple_image *)negative->Stage1Image (); if(stage2->Bounds().W() != S.raw_width || stage2->Bounds().H()!= S.raw_height) { return LIBRAW_DATA_ERROR; } int pplanes = stage2->Planes(); int ptype = stage2->PixelType(); dng_pixel_buffer buffer; stage2->GetPixelBuffer(buffer); int pixels = stage2->Bounds().H () * stage2->Bounds().W () * pplanes; if(ptype == ttByte ) imgdata.rawdata.raw_alloc = malloc(pixels * TagTypeSize(ttShort)); else imgdata.rawdata.raw_alloc = malloc(pixels * TagTypeSize(ptype)); if(ptype == ttShort && !is_curve_linear()) { ushort *src = (ushort *)buffer.fData; ushort *dst = (ushort*)imgdata.rawdata.raw_alloc; for(int i = 0; i < pixels; i++) dst[i] = imgdata.color.curve[src[i]]; S.raw_pitch = S.raw_width*pplanes*TagTypeSize(ptype); } else if(ptype == ttByte) { unsigned char *src = (unsigned char *)buffer.fData; ushort *dst = (ushort*)imgdata.rawdata.raw_alloc; if(is_curve_linear()) { for(int i = 0; i < pixels; i++) dst[i] = src[i]; } else { for(int i = 0; i < pixels; i++) dst[i] = imgdata.color.curve[src[i]]; } S.raw_pitch = S.raw_width*pplanes*TagTypeSize(ttShort); } else { memmove(imgdata.rawdata.raw_alloc,buffer.fData,pixels * TagTypeSize(ptype)); S.raw_pitch = S.raw_width*pplanes*TagTypeSize(ptype); } switch(ptype) { case ttFloat: if(pplanes==1) imgdata.rawdata.float_image = (float*)imgdata.rawdata.raw_alloc; else if(pplanes == 3) imgdata.rawdata.float3_image = (float (*)[3])imgdata.rawdata.raw_alloc; else if(pplanes == 4) imgdata.rawdata.float4_image = (float (*)[4])imgdata.rawdata.raw_alloc; break; case ttByte: case ttShort: if(pplanes==1) imgdata.rawdata.raw_image = (ushort*)imgdata.rawdata.raw_alloc; else if(pplanes == 3) imgdata.rawdata.color3_image = (ushort(*)[3])imgdata.rawdata.raw_alloc; else if(pplanes == 4) imgdata.rawdata.color4_image = (ushort(*)[4])imgdata.rawdata.raw_alloc; break; default: /* do nothing */ break; } } catch (...) { return LIBRAW_UNSPECIFIED_ERROR; } return imgdata.rawdata.raw_alloc?LIBRAW_SUCCESS:LIBRAW_UNSPECIFIED_ERROR; #else return LIBRAW_UNSPECIFIED_ERROR; #endif } void LibRaw::set_dng_host(void *p) { #ifdef USE_DNGSDK dnghost = p; #endif } int LibRaw::unpack(void) { CHECK_ORDER_HIGH(LIBRAW_PROGRESS_LOAD_RAW); CHECK_ORDER_LOW(LIBRAW_PROGRESS_IDENTIFY); try { if(!libraw_internal_data.internal_data.input) return LIBRAW_INPUT_CLOSED; RUN_CALLBACK(LIBRAW_PROGRESS_LOAD_RAW,0,2); if (O.shot_select >= P1.raw_count) return LIBRAW_REQUEST_FOR_NONEXISTENT_IMAGE; if(!load_raw) return LIBRAW_UNSPECIFIED_ERROR; // already allocated ? if(imgdata.image) { free(imgdata.image); imgdata.image = 0; } if(imgdata.rawdata.raw_alloc) { free(imgdata.rawdata.raw_alloc); imgdata.rawdata.raw_alloc = 0; } if (libraw_internal_data.unpacker_data.meta_length) { libraw_internal_data.internal_data.meta_data = (char *) malloc (libraw_internal_data.unpacker_data.meta_length); merror (libraw_internal_data.internal_data.meta_data, "LibRaw::unpack()"); } libraw_decoder_info_t decoder_info; get_decoder_info(&decoder_info); int save_iwidth = S.iwidth, save_iheight = S.iheight, save_shrink = IO.shrink; int rwidth = S.raw_width, rheight = S.raw_height; if( !IO.fuji_width) { // adjust non-Fuji allocation if(rwidth < S.width + S.left_margin) rwidth = S.width + S.left_margin; if(rheight < S.height + S.top_margin) rheight = S.height + S.top_margin; } if(rwidth > 65535 || rheight > 65535) // No way to make image larger than 64k pix throw LIBRAW_EXCEPTION_IO_CORRUPT; imgdata.rawdata.raw_image = 0; imgdata.rawdata.color4_image = 0; imgdata.rawdata.color3_image = 0; imgdata.rawdata.float_image = 0; imgdata.rawdata.float3_image = 0; #ifdef USE_DNGSDK if(imgdata.idata.dng_version && dnghost && valid_for_dngsdk() && load_raw != &LibRaw::pentax_4shot_load_raw) { int rr = try_dngsdk(); } #endif #ifdef USE_RAWSPEED if(!raw_was_read()) { int rawspeed_enabled = 1; if(imgdata.idata.dng_version && libraw_internal_data.unpacker_data.tiff_samples == 2) rawspeed_enabled = 0; if(imgdata.idata.raw_count > 1) rawspeed_enabled = 0; // Disable rawspeed for double-sized Oly files if(!strncasecmp(imgdata.idata.make,"Olympus",7) && ( ( imgdata.sizes.raw_width > 6000) || !strncasecmp(imgdata.idata.model,"SH-2",4) || !strncasecmp(imgdata.idata.model,"SH-3",4) || !strncasecmp(imgdata.idata.model,"TG-4",4)) ) rawspeed_enabled = 0; if(imgdata.idata.dng_version && imgdata.idata.filters==0 && libraw_internal_data.unpacker_data.tiff_bps == 8) // Disable for 8 bit rawspeed_enabled = 0; if(load_raw == &LibRaw::packed_load_raw && !strncasecmp(imgdata.idata.make,"Nikon",5) && !strncasecmp(imgdata.idata.model,"E",1) ) rawspeed_enabled = 0; // RawSpeed Supported, if(O.use_rawspeed && rawspeed_enabled && !(is_sraw() && (O.raw_processing_options & (LIBRAW_PROCESSING_SRAW_NO_RGB | LIBRAW_PROCESSING_SRAW_NO_INTERPOLATE))) && (decoder_info.decoder_flags & LIBRAW_DECODER_TRYRAWSPEED) && _rawspeed_camerameta) { int rr = try_rawspeed(); } } #endif if(!raw_was_read()) //RawSpeed failed or not run { // Not allocated on RawSpeed call, try call LibRaow int zero_rawimage = 0; if(decoder_info.decoder_flags & LIBRAW_DECODER_OWNALLOC) { // x3f foveon decoder and DNG float // Do nothing! Decoder will allocate data internally } else if(imgdata.idata.filters || P1.colors == 1) // Bayer image or single color -> decode to raw_image { if(INT64(rwidth)*INT64(rheight+8)*sizeof(imgdata.rawdata.raw_image[0]) > LIBRAW_MAX_ALLOC_MB * INT64(1024*1024)) throw LIBRAW_EXCEPTION_ALLOC; imgdata.rawdata.raw_alloc = malloc(rwidth*(rheight+8)*sizeof(imgdata.rawdata.raw_image[0])); imgdata.rawdata.raw_image = (ushort*) imgdata.rawdata.raw_alloc; if(!S.raw_pitch) S.raw_pitch = S.raw_width*2; // Bayer case, not set before } else // NO LEGACY FLAG if (decoder_info.decoder_flags & LIBRAW_DECODER_LEGACY) { // sRAW and old Foveon decoders only, so extra buffer size is just 1/4 S.iwidth = S.width; S.iheight= S.height; IO.shrink = 0; if(!S.raw_pitch) S.raw_pitch = (decoder_info.decoder_flags & LIBRAW_DECODER_LEGACY_WITH_MARGINS) ? S.raw_width*8 : S.width*8; // allocate image as temporary buffer, size imgdata.rawdata.raw_alloc = 0; if(INT64(MAX(S.width,S.raw_width))*INT64(MAX(S.height,S.raw_height))*sizeof(*imgdata.image) > LIBRAW_MAX_ALLOC_MB * INT64(1024*1024)) throw LIBRAW_EXCEPTION_ALLOC; imgdata.image = (ushort (*)[4]) calloc(unsigned(MAX(S.width,S.raw_width))*unsigned(MAX(S.height,S.raw_height)),sizeof(*imgdata.image)); if(!(decoder_info.decoder_flags & LIBRAW_DECODER_ADOBECOPYPIXEL)) { imgdata.rawdata.raw_image = (ushort*) imgdata.image ; zero_rawimage = 1; } } ID.input->seek(libraw_internal_data.unpacker_data.data_offset, SEEK_SET); unsigned m_save = C.maximum; if(load_raw == &LibRaw::unpacked_load_raw && !strcasecmp(imgdata.idata.make,"Nikon")) C.maximum=65535; (this->*load_raw)(); if(zero_rawimage) imgdata.rawdata.raw_image = 0; if(load_raw == &LibRaw::unpacked_load_raw && !strcasecmp(imgdata.idata.make,"Nikon")) C.maximum = m_save; if(decoder_info.decoder_flags & LIBRAW_DECODER_OWNALLOC) { // x3f foveon decoder only: do nothing } else if (!(imgdata.idata.filters || P1.colors == 1) ) // legacy decoder, ownalloc handled above { // successfully decoded legacy image, attach image to raw_alloc imgdata.rawdata.raw_alloc = imgdata.image; imgdata.rawdata.color4_image = (ushort (*)[4]) imgdata.rawdata.raw_alloc; imgdata.image = 0; // Restore saved values. Note: Foveon have masked frame // Other 4-color legacy data: no borders if(!(libraw_internal_data.unpacker_data.load_flags & 256)) { S.raw_width = S.width; S.left_margin = 0; S.raw_height = S.height; S.top_margin = 0; } } } if(imgdata.rawdata.raw_image) crop_masked_pixels(); // calculate black levels // recover image sizes S.iwidth = save_iwidth; S.iheight = save_iheight; IO.shrink = save_shrink; // adjust black to possible maximum unsigned int i = C.cblack[3]; unsigned int c; for(c=0;c<3;c++) if (i > C.cblack[c]) i = C.cblack[c]; for (c=0;c<4;c++) C.cblack[c] -= i; C.black += i; // Save color,sizes and internal data into raw_image fields memmove(&imgdata.rawdata.color,&imgdata.color,sizeof(imgdata.color)); memmove(&imgdata.rawdata.sizes,&imgdata.sizes,sizeof(imgdata.sizes)); memmove(&imgdata.rawdata.iparams,&imgdata.idata,sizeof(imgdata.idata)); memmove(&imgdata.rawdata.ioparams,&libraw_internal_data.internal_output_params,sizeof(libraw_internal_data.internal_output_params)); SET_PROC_FLAG(LIBRAW_PROGRESS_LOAD_RAW); RUN_CALLBACK(LIBRAW_PROGRESS_LOAD_RAW,1,2); return 0; } catch ( LibRaw_exceptions err) { EXCEPTION_HANDLER(err); } catch (std::exception ee) { EXCEPTION_HANDLER(LIBRAW_EXCEPTION_IO_CORRUPT); } } void LibRaw::unpacked_load_raw_fuji_f700s20() { int base_offset = 0; int row_size = imgdata.sizes.raw_width * 2; // in bytes if(imgdata.idata.raw_count==2 && imgdata.params.shot_select) { libraw_internal_data.internal_data.input->seek(-row_size,SEEK_CUR); base_offset = row_size; // in bytes } unsigned char *buffer = (unsigned char*)malloc(row_size*2); for(int row = 0; row < imgdata.sizes.raw_height; row++) { read_shorts((ushort*)buffer,imgdata.sizes.raw_width * 2); memmove(&imgdata.rawdata.raw_image[row*imgdata.sizes.raw_pitch/2],buffer+base_offset,row_size); } free(buffer); } void LibRaw::nikon_load_sraw() { // We're already seeked to data! unsigned char *rd = (unsigned char *)malloc(3*(imgdata.sizes.raw_width+2)); if(!rd) throw LIBRAW_EXCEPTION_ALLOC; try { int row,col; for(row = 0; row < imgdata.sizes.raw_height; row++) { checkCancel(); libraw_internal_data.internal_data.input->read(rd,3,imgdata.sizes.raw_width); for(col = 0; col < imgdata.sizes.raw_width-1;col+=2) { int bi = col*3; ushort bits1 = (rd[bi+1] &0xf)<<8| rd[bi]; // 3,0,1 ushort bits2 = rd[bi+2] << 4 | ((rd[bi+1]>>4)& 0xf); //452 ushort bits3 = ((rd[bi+4] & 0xf)<<8) | rd[bi+3]; // 967 ushort bits4 = rd[bi+5] << 4 | ((rd[bi+4]>>4)& 0xf); // ab8 imgdata.image[row*imgdata.sizes.raw_width+col][0]=bits1; imgdata.image[row*imgdata.sizes.raw_width+col][1]=bits3; imgdata.image[row*imgdata.sizes.raw_width+col][2]=bits4; imgdata.image[row*imgdata.sizes.raw_width+col+1][0]=bits2; imgdata.image[row*imgdata.sizes.raw_width+col+1][1]=2048; imgdata.image[row*imgdata.sizes.raw_width+col+1][2]=2048; } } }catch (...) { free(rd); throw ; } free(rd); C.maximum = 0xfff; // 12 bit? if(imgdata.params.raw_processing_options & LIBRAW_PROCESSING_SRAW_NO_INTERPOLATE) { return; // no CbCr interpolation } // Interpolate CC channels int row,col; for(row = 0; row < imgdata.sizes.raw_height; row++) { checkCancel(); // will throw out for(col = 0; col < imgdata.sizes.raw_width;col+=2) { int col2 = col1.f) Y = 1.f; if(Y>0.803f) Ch2 = Ch3 = 0.5f; float r = Y + 1.40200f*(Ch3 - 0.5f); if(r<0.f) r=0.f; if(r>1.f) r=1.f; float g = Y - 0.34414f*(Ch2-0.5f) - 0.71414*(Ch3 - 0.5f) ; if(g>1.f) g = 1.f; if(g<0.f) g = 0.f; float b = Y + 1.77200*(Ch2-0.5f); if(b>1.f) b = 1.f; if(b<0.f) b = 0.f; imgdata.image[row*imgdata.sizes.raw_width+col][0]=imgdata.color.curve[int(r*3072.f)]; imgdata.image[row*imgdata.sizes.raw_width+col][1]=imgdata.color.curve[int(g*3072.f)]; imgdata.image[row*imgdata.sizes.raw_width+col][2]=imgdata.color.curve[int(b*3072.f)]; } } C.maximum=16383; } void LibRaw::free_image(void) { if(imgdata.image) { free(imgdata.image); imgdata.image = 0; imgdata.progress_flags = LIBRAW_PROGRESS_START|LIBRAW_PROGRESS_OPEN |LIBRAW_PROGRESS_IDENTIFY|LIBRAW_PROGRESS_SIZE_ADJUST|LIBRAW_PROGRESS_LOAD_RAW; } } void LibRaw::raw2image_start() { // restore color,sizes and internal data into raw_image fields memmove(&imgdata.color,&imgdata.rawdata.color,sizeof(imgdata.color)); memmove(&imgdata.sizes,&imgdata.rawdata.sizes,sizeof(imgdata.sizes)); memmove(&imgdata.idata,&imgdata.rawdata.iparams,sizeof(imgdata.idata)); memmove(&libraw_internal_data.internal_output_params,&imgdata.rawdata.ioparams,sizeof(libraw_internal_data.internal_output_params)); if (O.user_flip >= 0) S.flip = O.user_flip; switch ((S.flip+3600) % 360) { case 270: S.flip = 5; break; case 180: S.flip = 3; break; case 90: S.flip = 6; break; } // adjust for half mode! IO.shrink = P1.filters && (O.half_size || ((O.threshold || O.aber[0] != 1 || O.aber[2] != 1) )); S.iheight = (S.height + IO.shrink) >> IO.shrink; S.iwidth = (S.width + IO.shrink) >> IO.shrink; } int LibRaw::is_phaseone_compressed() { return (load_raw == &LibRaw::phase_one_load_raw_c || load_raw == &LibRaw::phase_one_load_raw); } int LibRaw::is_canon_600() { return load_raw == &LibRaw::canon_600_load_raw; } int LibRaw::raw2image(void) { CHECK_ORDER_LOW(LIBRAW_PROGRESS_LOAD_RAW); try { raw2image_start(); if (is_phaseone_compressed()) { phase_one_allocate_tempbuffer(); int rc = phase_one_subtract_black((ushort*)imgdata.rawdata.raw_alloc,imgdata.rawdata.raw_image); if(rc == 0) rc = phase_one_correct(); if(rc!=0) { phase_one_free_tempbuffer(); return rc; } } // free and re-allocate image bitmap if(imgdata.image) { imgdata.image = (ushort (*)[4]) realloc (imgdata.image,S.iheight*S.iwidth *sizeof (*imgdata.image)); memset(imgdata.image,0,S.iheight*S.iwidth *sizeof (*imgdata.image)); } else imgdata.image = (ushort (*)[4]) calloc (S.iheight*S.iwidth, sizeof (*imgdata.image)); merror (imgdata.image, "raw2image()"); libraw_decoder_info_t decoder_info; get_decoder_info(&decoder_info); // Move saved bitmap to imgdata.image if( imgdata.idata.filters || P1.colors == 1) { if (IO.fuji_width) { unsigned r,c; int row,col; for (row=0; row < S.raw_height-S.top_margin*2; row++) { for (col=0; col < IO.fuji_width << !libraw_internal_data.unpacker_data.fuji_layout; col++) { if (libraw_internal_data.unpacker_data.fuji_layout) { r = IO.fuji_width - 1 - col + (row >> 1); c = col + ((row+1) >> 1); } else { r = IO.fuji_width - 1 + row - (col >> 1); c = row + ((col+1) >> 1); } if (r < S.height && c < S.width) imgdata.image[((r)>>IO.shrink)*S.iwidth+((c)>>IO.shrink)][FC(r,c)] = imgdata.rawdata.raw_image[(row+S.top_margin)*S.raw_pitch/2+(col+S.left_margin)]; } } } else { int row,col; for (row=0; row < S.height; row++) for (col=0; col < S.width; col++) imgdata.image[((row) >> IO.shrink)*S.iwidth + ((col) >> IO.shrink)][fcol(row,col)] = imgdata.rawdata.raw_image[(row+S.top_margin)*S.raw_pitch/2+(col+S.left_margin)]; } } else // if(decoder_info.decoder_flags & LIBRAW_DECODER_LEGACY) { if(imgdata.rawdata.color4_image) { if(S.width*8 == S.raw_pitch) memmove(imgdata.image,imgdata.rawdata.color4_image,S.width*S.height*sizeof(*imgdata.image)); else { for(int row = 0; row < S.height; row++) memmove(&imgdata.image[row*S.width], &imgdata.rawdata.color4_image[(row+S.top_margin)*S.raw_pitch/8+S.left_margin], S.width*sizeof(*imgdata.image)); } } else if(imgdata.rawdata.color3_image) { unsigned char *c3image = (unsigned char*) imgdata.rawdata.color3_image; for(int row = 0; row < S.height; row++) { ushort (*srcrow)[3] = (ushort (*)[3]) &c3image[(row+S.top_margin)*S.raw_pitch]; ushort (*dstrow)[4] = (ushort (*)[4]) &imgdata.image[row*S.width]; for(int col=0; col < S.width; col++) { for(int c=0; c< 3; c++) dstrow[col][c] = srcrow[S.left_margin+col][c]; dstrow[col][3]=0; } } } else { // legacy decoder, but no data? throw LIBRAW_EXCEPTION_DECODE_RAW; } } // Free PhaseOne separate copy allocated at function start if (is_phaseone_compressed()) { phase_one_free_tempbuffer(); } // hack - clear later flags! if (load_raw == &CLASS canon_600_load_raw && S.width < S.raw_width) { canon_600_correct(); } imgdata.progress_flags = LIBRAW_PROGRESS_START|LIBRAW_PROGRESS_OPEN | LIBRAW_PROGRESS_RAW2_IMAGE |LIBRAW_PROGRESS_IDENTIFY|LIBRAW_PROGRESS_SIZE_ADJUST|LIBRAW_PROGRESS_LOAD_RAW; return 0; } catch ( LibRaw_exceptions err) { EXCEPTION_HANDLER(err); } } void LibRaw::phase_one_allocate_tempbuffer() { // Allocate temp raw_image buffer imgdata.rawdata.raw_image = (ushort*)malloc(S.raw_pitch*S.raw_height); merror (imgdata.rawdata.raw_image, "phase_one_prepare_to_correct()"); } void LibRaw::phase_one_free_tempbuffer() { free(imgdata.rawdata.raw_image); imgdata.rawdata.raw_image = (ushort*) imgdata.rawdata.raw_alloc; } int LibRaw::phase_one_subtract_black(ushort *src, ushort *dest) { try { if (O.user_black < 0 && O.user_cblack[0] <= -1000000 && O.user_cblack[1] <= -1000000 && O.user_cblack[2] <= -1000000 && O.user_cblack[3] <= -1000000) { if (!imgdata.rawdata.ph1_cblack || !imgdata.rawdata.ph1_rblack) { register int bl = imgdata.color.phase_one_data.t_black; for (int row = 0; row < S.raw_height; row++) { checkCancel(); for (int col = 0; col < S.raw_width; col++) { int idx = row*S.raw_width + col; int val = int(src[idx]) - bl; dest[idx] = val>0 ? val : 0; } } } else { register int bl = imgdata.color.phase_one_data.t_black; for (int row = 0; row < S.raw_height; row++) { checkCancel(); for (int col = 0; col < S.raw_width; col++) { int idx = row*S.raw_width + col; int val = int(src[idx]) - bl + imgdata.rawdata.ph1_cblack[row][col >= imgdata.rawdata.color.phase_one_data.split_col] + imgdata.rawdata.ph1_rblack[col][row >= imgdata.rawdata.color.phase_one_data.split_row]; dest[idx] = val>0 ? val : 0; } } } } else // black set by user interaction { // Black level in cblack! for (int row = 0; row < S.raw_height; row++) { checkCancel(); unsigned short cblk[16]; for (int cc = 0; cc < 16; cc++) cblk[cc] = C.cblack[fcol(row, cc)]; for (int col = 0; col < S.raw_width; col++) { int idx = row*S.raw_width + col; ushort val = src[idx]; ushort bl = cblk[col & 0xf]; dest[idx] = val>bl ? val - bl : 0; } } } return 0; } catch (LibRaw_exceptions err) { return LIBRAW_CANCELLED_BY_CALLBACK; } } void LibRaw::copy_fuji_uncropped(unsigned short cblack[4],unsigned short *dmaxp) { int row; #if defined(LIBRAW_USE_OPENMP) #pragma omp parallel for default(shared) #endif for (row=0; row < S.raw_height-S.top_margin*2; row++) { int col; unsigned short ldmax = 0; for (col=0; col < IO.fuji_width << !libraw_internal_data.unpacker_data.fuji_layout; col++) { unsigned r,c; if (libraw_internal_data.unpacker_data.fuji_layout) { r = IO.fuji_width - 1 - col + (row >> 1); c = col + ((row+1) >> 1); } else { r = IO.fuji_width - 1 + row - (col >> 1); c = row + ((col+1) >> 1); } if (r < S.height && c < S.width) { unsigned short val = imgdata.rawdata.raw_image[(row+S.top_margin)*S.raw_pitch/2+(col+S.left_margin)]; int cc = FC(r,c); if(val>cblack[cc]) { val-=cblack[cc]; if(val>ldmax)ldmax = val; } else val = 0; imgdata.image[((r)>>IO.shrink)*S.iwidth+((c)>>IO.shrink)][cc] = val; } } #if defined(LIBRAW_USE_OPENMP) #pragma omp critical(dataupdate) #endif { if(*dmaxp < ldmax) *dmaxp = ldmax; } } } void LibRaw::copy_bayer(unsigned short cblack[4],unsigned short *dmaxp) { // Both cropped and uncropped int row; #if defined(LIBRAW_USE_OPENMP) #pragma omp parallel for default(shared) #endif for (row=0; row < S.height; row++) { int col; unsigned short ldmax = 0; for (col=0; col < S.width; col++) { unsigned short val = imgdata.rawdata.raw_image[(row+S.top_margin)*S.raw_pitch/2+(col+S.left_margin)]; int cc = fcol(row,col); if(val>cblack[cc]) { val-=cblack[cc]; if(val>ldmax)ldmax = val; } else val = 0; imgdata.image[((row) >> IO.shrink)*S.iwidth + ((col) >> IO.shrink)][cc] = val; } #if defined(LIBRAW_USE_OPENMP) #pragma omp critical(dataupdate) #endif { if(*dmaxp < ldmax) *dmaxp = ldmax; } } } int LibRaw::raw2image_ex(int do_subtract_black) { CHECK_ORDER_LOW(LIBRAW_PROGRESS_LOAD_RAW); try { raw2image_start(); // Compressed P1 files with bl data! if (is_phaseone_compressed()) { phase_one_allocate_tempbuffer(); int rc = phase_one_subtract_black((ushort*)imgdata.rawdata.raw_alloc,imgdata.rawdata.raw_image); if(rc == 0) rc = phase_one_correct(); if(rc!=0) { phase_one_free_tempbuffer(); return rc; } } // process cropping int do_crop = 0; unsigned save_width = S.width; if (~O.cropbox[2] && ~O.cropbox[3] #ifdef LIBRAW_DEMOSAIC_PACK_GPL2 && load_raw != &LibRaw::foveon_sd_load_raw #endif ) // Foveon SD to be cropped later { int crop[4],c,filt; for(int c=0;c<4;c++) { crop[c] = O.cropbox[c]; if(crop[c]<0) crop[c]=0; } if(IO.fuji_width && imgdata.idata.filters >= 1000) { crop[0] = (crop[0]/4)*4; crop[1] = (crop[1]/4)*4; if(!libraw_internal_data.unpacker_data.fuji_layout) { crop[2]*=sqrt(2.0); crop[3]/=sqrt(2.0); } crop[2] = (crop[2]/4+1)*4; crop[3] = (crop[3]/4+1)*4; } else if (imgdata.idata.filters == 1) { crop[0] = (crop[0]/16)*16; crop[1] = (crop[1]/16)*16; } else if(imgdata.idata.filters == LIBRAW_XTRANS) { crop[0] = (crop[0]/6)*6; crop[1] = (crop[1]/6)*6; } do_crop = 1; crop[2] = MIN (crop[2], (signed) S.width-crop[0]); crop[3] = MIN (crop[3], (signed) S.height-crop[1]); if (crop[2] <= 0 || crop[3] <= 0) throw LIBRAW_EXCEPTION_BAD_CROP; // adjust sizes! S.left_margin+=crop[0]; S.top_margin+=crop[1]; S.width=crop[2]; S.height=crop[3]; S.iheight = (S.height + IO.shrink) >> IO.shrink; S.iwidth = (S.width + IO.shrink) >> IO.shrink; if(!IO.fuji_width && imgdata.idata.filters && imgdata.idata.filters >= 1000) { for (filt=c=0; c < 16; c++) filt |= FC((c >> 1)+(crop[1]), (c & 1)+(crop[0])) << c*2; imgdata.idata.filters = filt; } } int alloc_width = S.iwidth; int alloc_height = S.iheight; if(IO.fuji_width && do_crop) { int IO_fw = S.width >> !libraw_internal_data.unpacker_data.fuji_layout; int t_alloc_width = (S.height >> libraw_internal_data.unpacker_data.fuji_layout) + IO_fw; int t_alloc_height = t_alloc_width - 1; alloc_height = (t_alloc_height + IO.shrink) >> IO.shrink; alloc_width = (t_alloc_width + IO.shrink) >> IO.shrink; } int alloc_sz = alloc_width*alloc_height; if(imgdata.image) { imgdata.image = (ushort (*)[4]) realloc (imgdata.image,alloc_sz *sizeof (*imgdata.image)); memset(imgdata.image,0,alloc_sz *sizeof (*imgdata.image)); } else imgdata.image = (ushort (*)[4]) calloc (alloc_sz, sizeof (*imgdata.image)); merror (imgdata.image, "raw2image_ex()"); libraw_decoder_info_t decoder_info; get_decoder_info(&decoder_info); // Adjust black levels unsigned short cblack[4]={0,0,0,0}; unsigned short dmax = 0; if(do_subtract_black) { adjust_bl(); for(int i=0; i< 4; i++) cblack[i] = (unsigned short)C.cblack[i]; } // Move saved bitmap to imgdata.image if(imgdata.idata.filters || P1.colors == 1) { if (IO.fuji_width) { if(do_crop) { IO.fuji_width = S.width >> !libraw_internal_data.unpacker_data.fuji_layout; int IO_fwidth = (S.height >> libraw_internal_data.unpacker_data.fuji_layout) + IO.fuji_width; int IO_fheight = IO_fwidth - 1; int row,col; for(row=0;row> 1); c = col + ((row+1) >> 1); } else { r = IO.fuji_width - 1 + row - (col >> 1); c = row + ((col+1) >> 1); } unsigned short val = imgdata.rawdata.raw_image[(row+S.top_margin)*S.raw_pitch/2 +(col+S.left_margin)]; int cc = FCF(row,col); if(val > cblack[cc]) { val-=cblack[cc]; if(dmax < val) dmax = val; } else val = 0; imgdata.image[((r) >> IO.shrink)*alloc_width + ((c) >> IO.shrink)][cc] = val; } } S.height = IO_fheight; S.width = IO_fwidth; S.iheight = (S.height + IO.shrink) >> IO.shrink; S.iwidth = (S.width + IO.shrink) >> IO.shrink; S.raw_height -= 2*S.top_margin; } else { copy_fuji_uncropped(cblack,&dmax); } } // end Fuji else { copy_bayer(cblack,&dmax); } } else //if(decoder_info.decoder_flags & LIBRAW_DECODER_LEGACY) { if(imgdata.rawdata.color4_image) { if(S.raw_pitch != S.width*8) { for(int row = 0; row < S.height; row++) memmove(&imgdata.image[row*S.width], &imgdata.rawdata.color4_image[(row+S.top_margin)*S.raw_pitch/8+S.left_margin], S.width*sizeof(*imgdata.image)); } else { // legacy is always 4channel and not shrinked! memmove(imgdata.image,imgdata.rawdata.color4_image,S.width*S.height*sizeof(*imgdata.image)); } } else if(imgdata.rawdata.color3_image) { unsigned char *c3image = (unsigned char*) imgdata.rawdata.color3_image; for(int row = 0; row < S.height; row++) { ushort (*srcrow)[3] = (ushort (*)[3]) &c3image[(row+S.top_margin)*S.raw_pitch]; ushort (*dstrow)[4] = (ushort (*)[4]) &imgdata.image[row*S.width]; for(int col=0; col < S.width; col++) { for(int c=0; c< 3; c++) dstrow[col][c] = srcrow[S.left_margin+col][c]; dstrow[col][3]=0; } } } else { // legacy decoder, but no data? throw LIBRAW_EXCEPTION_DECODE_RAW; } } // Free PhaseOne separate copy allocated at function start if (is_phaseone_compressed()) { phase_one_free_tempbuffer(); } if (load_raw == &CLASS canon_600_load_raw && S.width < S.raw_width) { canon_600_correct(); } if(do_subtract_black) { C.data_maximum = (int)dmax; C.maximum -= C.black; // ZERO(C.cblack); C.cblack[0]=C.cblack[1]=C.cblack[2]=C.cblack[3]=0; C.black = 0; } // hack - clear later flags! imgdata.progress_flags = LIBRAW_PROGRESS_START|LIBRAW_PROGRESS_OPEN | LIBRAW_PROGRESS_RAW2_IMAGE |LIBRAW_PROGRESS_IDENTIFY|LIBRAW_PROGRESS_SIZE_ADJUST|LIBRAW_PROGRESS_LOAD_RAW; return 0; } catch ( LibRaw_exceptions err) { EXCEPTION_HANDLER(err); } } #if 1 libraw_processed_image_t * LibRaw::dcraw_make_mem_thumb(int *errcode) { if(!T.thumb) { if ( !ID.toffset && !(imgdata.thumbnail.tlength>0 && load_raw == &LibRaw::broadcom_load_raw) // RPi ) { if(errcode) *errcode= LIBRAW_NO_THUMBNAIL; } else { if(errcode) *errcode= LIBRAW_OUT_OF_ORDER_CALL; } return NULL; } if (T.tformat == LIBRAW_THUMBNAIL_BITMAP) { libraw_processed_image_t * ret = (libraw_processed_image_t *)::malloc(sizeof(libraw_processed_image_t)+T.tlength); if(!ret) { if(errcode) *errcode= ENOMEM; return NULL; } memset(ret,0,sizeof(libraw_processed_image_t)); ret->type = LIBRAW_IMAGE_BITMAP; ret->height = T.theight; ret->width = T.twidth; ret->colors = 3; ret->bits = 8; ret->data_size = T.tlength; memmove(ret->data,T.thumb,T.tlength); if(errcode) *errcode= 0; return ret; } else if (T.tformat == LIBRAW_THUMBNAIL_JPEG) { ushort exif[5]; int mk_exif = 0; if(strcmp(T.thumb+6,"Exif")) mk_exif = 1; int dsize = T.tlength + mk_exif * (sizeof(exif)+sizeof(tiff_hdr)); libraw_processed_image_t * ret = (libraw_processed_image_t *)::malloc(sizeof(libraw_processed_image_t)+dsize); if(!ret) { if(errcode) *errcode= ENOMEM; return NULL; } memset(ret,0,sizeof(libraw_processed_image_t)); ret->type = LIBRAW_IMAGE_JPEG; ret->data_size = dsize; ret->data[0] = 0xff; ret->data[1] = 0xd8; if(mk_exif) { struct tiff_hdr th; memcpy (exif, "\xff\xe1 Exif\0\0", 10); exif[1] = htons (8 + sizeof th); memmove(ret->data+2,exif,sizeof(exif)); tiff_head (&th, 0); memmove(ret->data+(2+sizeof(exif)),&th,sizeof(th)); memmove(ret->data+(2+sizeof(exif)+sizeof(th)),T.thumb+2,T.tlength-2); } else { memmove(ret->data+2,T.thumb+2,T.tlength-2); } if(errcode) *errcode= 0; return ret; } else { if(errcode) *errcode= LIBRAW_UNSUPPORTED_THUMBNAIL; return NULL; } } // jlb // macros for copying pixels to either BGR or RGB formats #define FORBGR for(c=P1.colors-1; c >=0 ; c--) #define FORRGB for(c=0; c < P1.colors ; c++) void LibRaw::get_mem_image_format(int* width, int* height, int* colors, int* bps) const { if (S.flip & 4) { *width = S.height; *height = S.width; } else { *width = S.width; *height = S.height; } *colors = P1.colors; *bps = O.output_bps; } int LibRaw::copy_mem_image(void* scan0, int stride, int bgr) { // the image memory pointed to by scan0 is assumed to be in the format returned by get_mem_image_format if((imgdata.progress_flags & LIBRAW_PROGRESS_THUMB_MASK) < LIBRAW_PROGRESS_PRE_INTERPOLATE) return LIBRAW_OUT_OF_ORDER_CALL; if(libraw_internal_data.output_data.histogram) { int perc, val, total, t_white=0x2000,c; perc = S.width * S.height * O.auto_bright_thr; if (IO.fuji_width) perc /= 2; if (!((O.highlight & ~2) || O.no_auto_bright)) for (t_white=c=0; c < P1.colors; c++) { for (val=0x2000, total=0; --val > 32; ) if ((total += libraw_internal_data.output_data.histogram[c][val]) > perc) break; if (t_white < val) t_white = val; } gamma_curve (O.gamm[0], O.gamm[1], 2, (t_white << 3)/O.bright); } int s_iheight = S.iheight; int s_iwidth = S.iwidth; int s_width = S.width; int s_hwight = S.height; S.iheight = S.height; S.iwidth = S.width; if (S.flip & 4) SWAP(S.height,S.width); uchar *ppm; ushort *ppm2; int c, row, col, soff, rstep, cstep; soff = flip_index (0, 0); cstep = flip_index (0, 1) - soff; rstep = flip_index (1, 0) - flip_index (0, S.width); for (row=0; row < S.height; row++, soff += rstep) { uchar *bufp = ((uchar*)scan0)+row*stride; ppm2 = (ushort*) (ppm = bufp); // keep trivial decisions in the outer loop for speed if (bgr) { if (O.output_bps == 8) { for (col=0; col < S.width; col++, soff += cstep) FORBGR *ppm++ = imgdata.color.curve[imgdata.image[soff][c]]>>8; } else { for (col=0; col < S.width; col++, soff += cstep) FORBGR *ppm2++ = imgdata.color.curve[imgdata.image[soff][c]]; } } else { if (O.output_bps == 8) { for (col=0; col < S.width; col++, soff += cstep) FORRGB *ppm++ = imgdata.color.curve[imgdata.image[soff][c]]>>8; } else { for (col=0; col < S.width; col++, soff += cstep) FORRGB *ppm2++ = imgdata.color.curve[imgdata.image[soff][c]]; } } // bufp += stride; // go to the next line } S.iheight = s_iheight; S.iwidth = s_iwidth; S.width = s_width; S.height = s_hwight; return 0; } #undef FORBGR #undef FORRGB libraw_processed_image_t *LibRaw::dcraw_make_mem_image(int *errcode) { int width, height, colors, bps; get_mem_image_format(&width, &height, &colors, &bps); int stride = width * (bps/8) * colors; unsigned ds = height * stride; libraw_processed_image_t *ret = (libraw_processed_image_t*)::malloc(sizeof(libraw_processed_image_t)+ds); if(!ret) { if(errcode) *errcode= ENOMEM; return NULL; } memset(ret,0,sizeof(libraw_processed_image_t)); // metadata init ret->type = LIBRAW_IMAGE_BITMAP; ret->height = height; ret->width = width; ret->colors = colors; ret->bits = bps; ret->data_size = ds; copy_mem_image(ret->data, stride, 0); return ret; } #undef FORC #undef FORCC #undef SWAP #endif int LibRaw::dcraw_ppm_tiff_writer(const char *filename) { CHECK_ORDER_LOW(LIBRAW_PROGRESS_LOAD_RAW); if(!imgdata.image) return LIBRAW_OUT_OF_ORDER_CALL; if(!filename) return ENOENT; FILE *f = fopen(filename,"wb"); if(!f) return errno; try { if(!libraw_internal_data.output_data.histogram) { libraw_internal_data.output_data.histogram = (int (*)[LIBRAW_HISTOGRAM_SIZE]) malloc(sizeof(*libraw_internal_data.output_data.histogram)*4); merror(libraw_internal_data.output_data.histogram,"LibRaw::dcraw_ppm_tiff_writer()"); } libraw_internal_data.internal_data.output = f; write_ppm_tiff(); SET_PROC_FLAG(LIBRAW_PROGRESS_FLIP); libraw_internal_data.internal_data.output = NULL; fclose(f); return 0; } catch ( LibRaw_exceptions err) { fclose(f); EXCEPTION_HANDLER(err); } } #define THUMB_READ_BEYOND 16384 void LibRaw::kodak_thumb_loader() { INT64 est_datasize = T.theight * T.twidth / 3; // is 0.3 bytes per pixel good estimate? if (ID.toffset < 0) throw LIBRAW_EXCEPTION_IO_CORRUPT; if (ID.toffset + est_datasize > ID.input->size() + THUMB_READ_BEYOND) throw LIBRAW_EXCEPTION_IO_EOF; // some kodak cameras ushort s_height = S.height, s_width = S.width,s_iwidth = S.iwidth,s_iheight=S.iheight; ushort s_flags = libraw_internal_data.unpacker_data.load_flags; libraw_internal_data.unpacker_data.load_flags = 12; int s_colors = P1.colors; unsigned s_filters = P1.filters; ushort (*s_image)[4] = imgdata.image; S.height = T.theight; S.width = T.twidth; P1.filters = 0; if (thumb_load_raw == &CLASS kodak_ycbcr_load_raw) { S.height += S.height & 1; S.width += S.width & 1; } imgdata.image = (ushort (*)[4]) calloc (S.iheight*S.iwidth, sizeof (*imgdata.image)); merror (imgdata.image, "LibRaw::kodak_thumb_loader()"); ID.input->seek(ID.toffset, SEEK_SET); // read kodak thumbnail into T.image[] try { (this->*thumb_load_raw)(); } catch (...) { free(imgdata.image); imgdata.image = s_image; T.twidth = 0; S.width = s_width; S.iwidth = s_iwidth; S.iheight = s_iheight; T.theight = 0; S.height = s_height; T.tcolors = 0; P1.colors = s_colors; P1.filters = s_filters; T.tlength=0; libraw_internal_data.unpacker_data.load_flags = s_flags; return; } // copy-n-paste from image pipe #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define LIM(x,min,max) MAX(min,MIN(x,max)) #ifndef CLIP #define CLIP(x) LIM(x,0,65535) #endif #define SWAP(a,b) { a ^= b; a ^= (b ^= a); } // from scale_colors { double dmax; float scale_mul[4]; int c,val; for (dmax=DBL_MAX, c=0; c < 3; c++) if (dmax > C.pre_mul[c]) dmax = C.pre_mul[c]; for( c=0; c< 3; c++) scale_mul[c] = (C.pre_mul[c] / dmax) * 65535.0 / C.maximum; scale_mul[3] = scale_mul[1]; size_t size = S.height * S.width; for (unsigned i=0; i < size*4 ; i++) { val = imgdata.image[0][i]; if(!val) continue; val *= scale_mul[i & 3]; imgdata.image[0][i] = CLIP(val); } } // from convert_to_rgb ushort *img; int row,col; int (*t_hist)[LIBRAW_HISTOGRAM_SIZE] = (int (*)[LIBRAW_HISTOGRAM_SIZE]) calloc(sizeof(*t_hist),4); merror (t_hist, "LibRaw::kodak_thumb_loader()"); float out[3], out_cam[3][4] = { {2.81761312, -1.98369181, 0.166078627, 0}, {-0.111855984, 1.73688626, -0.625030339, 0}, {-0.0379119813, -0.891268849, 1.92918086, 0} }; for (img=imgdata.image[0], row=0; row < S.height; row++) for (col=0; col < S.width; col++, img+=4) { out[0] = out[1] = out[2] = 0; int c; for(c=0;c<3;c++) { out[0] += out_cam[0][c] * img[c]; out[1] += out_cam[1][c] * img[c]; out[2] += out_cam[2][c] * img[c]; } for(c=0; c<3; c++) img[c] = CLIP((int) out[c]); for(c=0; c> 3]++; } // from gamma_lut int (*save_hist)[LIBRAW_HISTOGRAM_SIZE] = libraw_internal_data.output_data.histogram; libraw_internal_data.output_data.histogram = t_hist; // make curve output curve! ushort (*t_curve) = (ushort*) calloc(sizeof(C.curve),1); merror (t_curve, "LibRaw::kodak_thumb_loader()"); memmove(t_curve,C.curve,sizeof(C.curve)); memset(C.curve,0,sizeof(C.curve)); { int perc, val, total, t_white=0x2000,c; perc = S.width * S.height * 0.01; /* 99th percentile white level */ if (IO.fuji_width) perc /= 2; if (!((O.highlight & ~2) || O.no_auto_bright)) for (t_white=c=0; c < P1.colors; c++) { for (val=0x2000, total=0; --val > 32; ) if ((total += libraw_internal_data.output_data.histogram[c][val]) > perc) break; if (t_white < val) t_white = val; } gamma_curve (O.gamm[0], O.gamm[1], 2, (t_white << 3)/O.bright); } libraw_internal_data.output_data.histogram = save_hist; free(t_hist); // from write_ppm_tiff - copy pixels into bitmap S.iheight = S.height; S.iwidth = S.width; if (S.flip & 4) SWAP(S.height,S.width); if(T.thumb) free(T.thumb); T.thumb = (char*) calloc (S.width * S.height, P1.colors); merror (T.thumb, "LibRaw::kodak_thumb_loader()"); T.tlength = S.width * S.height * P1.colors; // from write_tiff_ppm { int soff = flip_index(0, 0); int cstep = flip_index(0, 1) - soff; int rstep = flip_index(1, 0) - flip_index(0, S.width); for (int row = 0; row < S.height; row++, soff += rstep) { char *ppm = T.thumb + row*S.width*P1.colors; for (int col = 0; col < S.width; col++, soff += cstep) for (int c = 0; c < P1.colors; c++) ppm[col*P1.colors + c] = imgdata.color.curve[imgdata.image[soff][c]] >> 8; } } memmove(C.curve, t_curve, sizeof(C.curve)); free(t_curve); // restore variables free(imgdata.image); imgdata.image = s_image; T.twidth = S.width; S.width = s_width; S.iwidth = s_iwidth; S.iheight = s_iheight; T.theight = S.height; S.height = s_height; T.tcolors = P1.colors; P1.colors = s_colors; P1.filters = s_filters; libraw_internal_data.unpacker_data.load_flags = s_flags; } #undef MIN #undef MAX #undef LIM #undef CLIP #undef SWAP // ������� thumbnail �� �����, ������ thumb_format � ������������ � �������� int LibRaw::thumbOK(INT64 maxsz) { if (!ID.input) return 0; if (!ID.toffset && !(imgdata.thumbnail.tlength > 0 && load_raw == &LibRaw::broadcom_load_raw) // RPi ) return 0; INT64 fsize = ID.input->size(); if (fsize > 0x7fffffffU) return 0; // No thumb for raw > 2Gb int tsize = 0; int tcol = (T.tcolors > 0 && T.tcolors < 4) ? T.tcolors : 3; if (write_thumb == &LibRaw::jpeg_thumb) tsize = T.tlength; else if (write_thumb == &LibRaw::ppm_thumb) tsize = tcol * T.twidth * T.theight; else if (write_thumb == &LibRaw::ppm16_thumb) tsize = tcol * T.twidth * T.theight * 2; else if (write_thumb == &LibRaw::x3f_thumb_loader) { tsize = x3f_thumb_size(); } else // Kodak => no check tsize = 1; if (tsize < 0) return 0; if (maxsz > 0 && tsize > maxsz) return 0; return (tsize + ID.toffset <= fsize) ? 1 : 0; } int LibRaw::unpack_thumb(void) { CHECK_ORDER_LOW(LIBRAW_PROGRESS_IDENTIFY); CHECK_ORDER_BIT(LIBRAW_PROGRESS_THUMB_LOAD); try { if (!libraw_internal_data.internal_data.input) return LIBRAW_INPUT_CLOSED; if (!ID.toffset && !(imgdata.thumbnail.tlength > 0 && load_raw == &LibRaw::broadcom_load_raw) // RPi ) { return LIBRAW_NO_THUMBNAIL; } else if (thumb_load_raw) { kodak_thumb_loader(); T.tformat = LIBRAW_THUMBNAIL_BITMAP; SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); return 0; } else { if (write_thumb == &LibRaw::x3f_thumb_loader) { INT64 tsize = x3f_thumb_size(); if (tsize < 2048 ||INT64(ID.toffset) + tsize < 1) throw LIBRAW_EXCEPTION_IO_CORRUPT; if (INT64(ID.toffset) + tsize > ID.input->size() + THUMB_READ_BEYOND) throw LIBRAW_EXCEPTION_IO_EOF; } else { if (INT64(ID.toffset) + INT64(T.tlength) < 1) throw LIBRAW_EXCEPTION_IO_CORRUPT; if (INT64(ID.toffset) + INT64(T.tlength) > ID.input->size() + THUMB_READ_BEYOND) throw LIBRAW_EXCEPTION_IO_EOF; } ID.input->seek(ID.toffset, SEEK_SET); if ( write_thumb == &LibRaw::jpeg_thumb) { if(T.thumb) free(T.thumb); T.thumb = (char *) malloc (T.tlength); merror (T.thumb, "jpeg_thumb()"); ID.input->read (T.thumb, 1, T.tlength); T.thumb[0] = 0xff; T.thumb[1] = 0xd8; T.tcolors = 3; T.tformat = LIBRAW_THUMBNAIL_JPEG; SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); return 0; } else if (write_thumb == &LibRaw::ppm_thumb) { T.tlength = T.twidth * T.theight*3; if(T.thumb) free(T.thumb); T.thumb = (char *) malloc (T.tlength); merror (T.thumb, "ppm_thumb()"); ID.input->read(T.thumb, 1, T.tlength); T.tformat = LIBRAW_THUMBNAIL_BITMAP; SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); return 0; } else if (write_thumb == &LibRaw::ppm16_thumb) { T.tlength = T.twidth * T.theight*3; ushort *t_thumb = (ushort*)calloc(T.tlength,2); ID.input->read(t_thumb,2,T.tlength); if ((libraw_internal_data.unpacker_data.order == 0x4949) == (ntohs(0x1234) == 0x1234)) swab ((char*)t_thumb, (char*)t_thumb, T.tlength*2); if(T.thumb) free(T.thumb); T.thumb = (char *) malloc (T.tlength); merror (T.thumb, "ppm_thumb()"); for (int i=0; i < T.tlength; i++) T.thumb[i] = t_thumb[i] >> 8; free(t_thumb); T.tformat = LIBRAW_THUMBNAIL_BITMAP; SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); return 0; } else if (write_thumb == &LibRaw::x3f_thumb_loader) { x3f_thumb_loader(); SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); return 0; } #ifdef LIBRAW_DEMOSAIC_PACK_GPL2 else if (write_thumb == &LibRaw::foveon_thumb) { foveon_thumb_loader(); // may return with error, so format is set in // foveon thumb loader itself SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); return 0; } // else if -- all other write_thumb cases! #endif else { return LIBRAW_UNSUPPORTED_THUMBNAIL; } } // last resort return LIBRAW_UNSUPPORTED_THUMBNAIL; } catch ( LibRaw_exceptions err) { EXCEPTION_HANDLER(err); } } int LibRaw::dcraw_thumb_writer(const char *fname) { // CHECK_ORDER_LOW(LIBRAW_PROGRESS_THUMB_LOAD); if(!fname) return ENOENT; FILE *tfp = fopen(fname,"wb"); if(!tfp) return errno; if(!T.thumb) { fclose(tfp); return LIBRAW_OUT_OF_ORDER_CALL; } try { switch (T.tformat) { case LIBRAW_THUMBNAIL_JPEG: jpeg_thumb_writer (tfp,T.thumb,T.tlength); break; case LIBRAW_THUMBNAIL_BITMAP: fprintf (tfp, "P6\n%d %d\n255\n", T.twidth, T.theight); fwrite (T.thumb, 1, T.tlength, tfp); break; default: fclose(tfp); return LIBRAW_UNSUPPORTED_THUMBNAIL; } fclose(tfp); return 0; } catch ( LibRaw_exceptions err) { fclose(tfp); EXCEPTION_HANDLER(err); } } int LibRaw::adjust_sizes_info_only(void) { CHECK_ORDER_LOW(LIBRAW_PROGRESS_IDENTIFY); raw2image_start(); if (O.use_fuji_rotate) { if (IO.fuji_width) { IO.fuji_width = (IO.fuji_width - 1 + IO.shrink) >> IO.shrink; S.iwidth = (ushort)(IO.fuji_width / sqrt(0.5)); S.iheight = (ushort)( (S.iheight - IO.fuji_width) / sqrt(0.5)); } else { if (S.pixel_aspect < 0.995) S.iheight = (ushort)( S.iheight / S.pixel_aspect + 0.5); if (S.pixel_aspect > 1.005) S.iwidth = (ushort) (S.iwidth * S.pixel_aspect + 0.5); } } SET_PROC_FLAG(LIBRAW_PROGRESS_FUJI_ROTATE); if ( S.flip & 4) { unsigned short t = S.iheight; S.iheight=S.iwidth; S.iwidth = t; SET_PROC_FLAG(LIBRAW_PROGRESS_FLIP); } return 0; } int LibRaw::subtract_black() { adjust_bl(); return subtract_black_internal(); } int LibRaw::subtract_black_internal() { CHECK_ORDER_LOW(LIBRAW_PROGRESS_RAW2_IMAGE); try { if(!is_phaseone_compressed() && (C.cblack[0] || C.cblack[1] || C.cblack[2] || C.cblack[3] || (C.cblack[4] && C.cblack[5]) )) { #define BAYERC(row,col,c) imgdata.image[((row) >> IO.shrink)*S.iwidth + ((col) >> IO.shrink)][c] int cblk[4],i; for(i=0;i<4;i++) cblk[i] = C.cblack[i]; int size = S.iheight * S.iwidth; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define LIM(x,min,max) MAX(min,MIN(x,max)) #define CLIP(x) LIM(x,0,65535) int dmax = 0; if(C.cblack[4] && C.cblack[5]) { for(i=0; i< size*4; i++) { int val = imgdata.image[0][i]; val -= C.cblack[6 + i/4 / S.iwidth % C.cblack[4] * C.cblack[5] + i/4 % S.iwidth % C.cblack[5]]; val -= cblk[i & 3]; imgdata.image[0][i] = CLIP(val); if(dmax < val) dmax = val; } } else { for(i=0; i< size*4; i++) { int val = imgdata.image[0][i]; val -= cblk[i & 3]; imgdata.image[0][i] = CLIP(val); if(dmax < val) dmax = val; } } C.data_maximum = dmax & 0xffff; #undef MIN #undef MAX #undef LIM #undef CLIP C.maximum -= C.black; ZERO(C.cblack); // Yeah, we used cblack[6+] values too! C.black = 0; #undef BAYERC } else { // Nothing to Do, maximum is already calculated, black level is 0, so no change // only calculate channel maximum; int idx; ushort *p = (ushort*)imgdata.image; int dmax = 0; for(idx=0;idx8) shift = 8; if(shift<0.25) shift = 0.25; if(smooth < 0.0) smooth = 0.0; if(smooth > 1.0) smooth = 1.0; unsigned short *lut = (ushort*)malloc((TBLN+1)*sizeof(unsigned short)); if(shift <=1.0) { for(int i=0;i<=TBLN;i++) lut[i] = (unsigned short)((float)i*shift); } else { float x1,x2,y1,y2; float cstops = log(shift)/log(2.0f); float room = cstops*2; float roomlin = powf(2.0f,room); x2 = (float)TBLN; x1 = (x2+1)/roomlin-1; y1 = x1*shift; y2 = x2*(1+(1-smooth)*(shift-1)); float sq3x=powf(x1*x1*x2,1.0f/3.0f); float B = (y2-y1+shift*(3*x1-3.0f*sq3x)) / (x2+2.0f*x1-3.0f*sq3x); float A = (shift - B)*3.0f*powf(x1*x1,1.0f/3.0f); float CC = y2 - A*powf(x2,1.0f/3.0f)-B*x2; for(int i=0;i<=TBLN;i++) { float X = (float)i; float Y = A*powf(X,1.0f/3.0f)+B*X+CC; if(iTBLN?TBLN:(unsigned short)(Y)); } } for(int i=0; i< S.height*S.width; i++) { imgdata.image[i][0] = lut[imgdata.image[i][0]]; imgdata.image[i][1] = lut[imgdata.image[i][1]]; imgdata.image[i][2] = lut[imgdata.image[i][2]]; imgdata.image[i][3] = lut[imgdata.image[i][3]]; } if(C.data_maximum <=TBLN) C.data_maximum = lut[C.data_maximum]; if(C.maximum <= TBLN) C.maximum = lut[C.maximum]; // no need to adjust the minumum, black is already subtracted free(lut); } #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define LIM(x,min,max) MAX(min,MIN(x,max)) #define ULIM(x,y,z) ((y) < (z) ? LIM(x,y,z) : LIM(x,z,y)) #define CLIP(x) LIM(x,0,65535) void LibRaw::convert_to_rgb_loop(float out_cam[3][4]) { int row,col,c; float out[3]; ushort *img; memset(libraw_internal_data.output_data.histogram,0,sizeof(int)*LIBRAW_HISTOGRAM_SIZE*4); for (img=imgdata.image[0], row=0; row < S.height; row++) for (col=0; col < S.width; col++, img+=4) { if (!libraw_internal_data.internal_output_params.raw_color) { out[0] = out[1] = out[2] = 0; for(c=0; c< imgdata.idata.colors; c++) { out[0] += out_cam[0][c] * img[c]; out[1] += out_cam[1][c] * img[c]; out[2] += out_cam[2][c] * img[c]; } for(c=0;c<3;c++) img[c] = CLIP((int) out[c]); } for(c=0; c< imgdata.idata.colors; c++) libraw_internal_data.output_data.histogram[c][img[c] >> 3]++; } } void LibRaw::scale_colors_loop(float scale_mul[4]) { unsigned size = S.iheight*S.iwidth; if (C.cblack[4] && C.cblack[5]) { int val; for (unsigned i=0; i < size*4; i++) { if (!(val = imgdata.image[0][i])) continue; val -= C.cblack[6 + i/4 / S.iwidth % C.cblack[4] * C.cblack[5] + i/4 % S.iwidth % C.cblack[5]]; val -= C.cblack[i & 3]; val *= scale_mul[i & 3]; imgdata.image[0][i] = CLIP(val); } } else if(C.cblack[0]||C.cblack[1]||C.cblack[2]||C.cblack[3]) { for (unsigned i=0; i < size*4; i++) { int val = imgdata.image[0][i]; if (!val) continue; val -= C.cblack[i & 3]; val *= scale_mul[i & 3]; imgdata.image[0][i] = CLIP(val); } } else // BL is zero { for (unsigned i=0; i < size*4; i++) { int val = imgdata.image[0][i]; val *= scale_mul[i & 3]; imgdata.image[0][i] = CLIP(val); } } } void LibRaw::adjust_bl() { int clear_repeat=0; if (O.user_black >= 0) { C.black = O.user_black; clear_repeat = 1; } for(int i=0; i<4; i++) if(O.user_cblack[i]>-1000000) { C.cblack[i] = O.user_cblack[i]; clear_repeat = 1; } if(clear_repeat) C.cblack[4]=C.cblack[5]=0; // Add common part to cblack[] early if (imgdata.idata.filters > 1000 && (C.cblack[4]+1)/2 == 1 && (C.cblack[5]+1)/2 == 1) { int clrs[4]; int lastg = -1, gcnt = 0; for(int c = 0; c < 4; c++) { clrs[c] = FC(c/2,c%2); if(clrs[c]==1) { gcnt++; lastg = c; } } if(gcnt>1 && lastg>=0) clrs[lastg] = 3; for(int c=0; c<4; c++) C.cblack[clrs[c]] += C.cblack[6 + c/2 % C.cblack[4] * C.cblack[5] + c%2 % C.cblack[5]]; C.cblack[4]=C.cblack[5]=0; //imgdata.idata.filters = sfilters; } else if(imgdata.idata.filters <= 1000 && C.cblack[4]==1 && C.cblack[5]==1) // Fuji RAF dng { for(int c=0; c<4; c++) C.cblack[c] += C.cblack[6]; C.cblack[4]=C.cblack[5]=0; } // remove common part from C.cblack[] int i = C.cblack[3]; int c; for(c=0;c<3;c++) if (i > C.cblack[c]) i = C.cblack[c]; for(c=0;c<4;c++) C.cblack[c] -= i; // remove common part C.black += i; // Now calculate common part for cblack[6+] part and move it to C.black if(C.cblack[4] && C.cblack[5]) { i = C.cblack[6]; for(c=1; cC.cblack[6+c]) i = C.cblack[6+c]; // Remove i from cblack[6+] int nonz=0; for(c=0; c= 0) quality = O.user_qual; if(!subtract_inline || !C.data_maximum) { adjust_bl(); subtract_black_internal(); } if(!(di.decoder_flags & LIBRAW_DECODER_FIXEDMAXC)) adjust_maximum(); if (O.user_sat > 0) C.maximum = O.user_sat; if (P1.is_foveon) { if(load_raw == &LibRaw::x3f_load_raw) { // Filter out zeroes for (int i=0; i < S.height*S.width*4; i++) if ((short) imgdata.image[0][i] < 0) imgdata.image[0][i] = 0; } #ifdef LIBRAW_DEMOSAIC_PACK_GPL2 else if(load_raw == &LibRaw::foveon_dp_load_raw) { for (int i=0; i < S.height*S.width*4; i++) if ((short) imgdata.image[0][i] < 0) imgdata.image[0][i] = 0; } else { foveon_interpolate(); } #endif SET_PROC_FLAG(LIBRAW_PROGRESS_FOVEON_INTERPOLATE); } if (O.green_matching && !O.half_size) { green_matching(); } if ( #ifdef LIBRAW_DEMOSAIC_PACK_GPL2 (!P1.is_foveon || (O.raw_processing_options & LIBRAW_PROCESSING_FORCE_FOVEON_X3F)) && #endif !O.no_auto_scale) { scale_colors(); SET_PROC_FLAG(LIBRAW_PROGRESS_SCALE_COLORS); } pre_interpolate(); SET_PROC_FLAG(LIBRAW_PROGRESS_PRE_INTERPOLATE); if (O.dcb_iterations >= 0) iterations = O.dcb_iterations; if (O.dcb_enhance_fl >=0 ) dcb_enhance = O.dcb_enhance_fl; if (O.fbdd_noiserd >=0 ) noiserd = O.fbdd_noiserd; if (O.eeci_refine >=0 ) eeci_refine_fl = O.eeci_refine; if (O.es_med_passes >0 ) es_med_passes_fl = O.es_med_passes; // LIBRAW_DEMOSAIC_PACK_GPL3 if (!O.half_size && O.cfa_green >0) {thresh=O.green_thresh ;green_equilibrate(thresh);} if (O.exp_correc >0) {expos=O.exp_shift ; preser=O.exp_preser; exp_bef(expos,preser);} if (O.ca_correc >0 ) {cablue=O.cablue; cared=O.cared; CA_correct_RT(cablue, cared);} if (O.cfaline >0 ) {linenoise=O.linenoise; cfa_linedn(linenoise);} if (O.cfa_clean >0 ) {lclean=O.lclean; cclean=O.cclean; cfa_impulse_gauss(lclean,cclean);} if (P1.filters && !O.no_interpolation) { if (noiserd>0 && P1.colors==3 && P1.filters) fbdd(noiserd); if(P1.filters>1000 && interpolate_bayer) (this->*interpolate_bayer)(); else if(P1.filters==9 && interpolate_xtrans) (this->*interpolate_xtrans)(); else if (quality == 0) lin_interpolate(); else if (quality == 1 || P1.colors > 3) vng_interpolate(); else if (quality == 2 && P1.filters > 1000) ppg_interpolate(); else if (P1.filters == LIBRAW_XTRANS) { // Fuji X-Trans xtrans_interpolate(quality>2?3:1); } else if (quality == 3) ahd_interpolate(); // really don't need it here due to fallback op else if (quality == 4) dcb(iterations, dcb_enhance); // LIBRAW_DEMOSAIC_PACK_GPL2 else if (quality == 5) ahd_interpolate_mod(); else if (quality == 6) afd_interpolate_pl(2,1); else if (quality == 7) vcd_interpolate(0); else if (quality == 8) vcd_interpolate(12); else if (quality == 9) lmmse_interpolate(1); // LIBRAW_DEMOSAIC_PACK_GPL3 else if (quality == 10) amaze_demosaic_RT(); // LGPL2 else if (quality == 11) dht_interpolate(); else if (quality == 12) aahd_interpolate(); // fallback to AHD else { ahd_interpolate(); imgdata.process_warnings |= LIBRAW_WARN_FALLBACK_TO_AHD; } SET_PROC_FLAG(LIBRAW_PROGRESS_INTERPOLATE); } if (IO.mix_green) { for (P1.colors=3, i=0; i < S.height * S.width; i++) imgdata.image[i][1] = (imgdata.image[i][1] + imgdata.image[i][3]) >> 1; SET_PROC_FLAG(LIBRAW_PROGRESS_MIX_GREEN); } if(!P1.is_foveon) { if (P1.colors == 3) { if (quality == 8) { if (eeci_refine_fl == 1) refinement(); if (O.med_passes > 0) median_filter_new(); if (es_med_passes_fl > 0) es_median_filter(); } else { median_filter(); } SET_PROC_FLAG(LIBRAW_PROGRESS_MEDIAN_FILTER); } } if (O.highlight == 2) { blend_highlights(); SET_PROC_FLAG(LIBRAW_PROGRESS_HIGHLIGHTS); } if (O.highlight > 2) { recover_highlights(); SET_PROC_FLAG(LIBRAW_PROGRESS_HIGHLIGHTS); } if (O.use_fuji_rotate) { fuji_rotate(); SET_PROC_FLAG(LIBRAW_PROGRESS_FUJI_ROTATE); } if(!libraw_internal_data.output_data.histogram) { libraw_internal_data.output_data.histogram = (int (*)[LIBRAW_HISTOGRAM_SIZE]) malloc(sizeof(*libraw_internal_data.output_data.histogram)*4); merror(libraw_internal_data.output_data.histogram,"LibRaw::dcraw_process()"); } #ifndef NO_LCMS if(O.camera_profile) { apply_profile(O.camera_profile,O.output_profile); SET_PROC_FLAG(LIBRAW_PROGRESS_APPLY_PROFILE); } #endif convert_to_rgb(); SET_PROC_FLAG(LIBRAW_PROGRESS_CONVERT_RGB); if (O.use_fuji_rotate) { stretch(); SET_PROC_FLAG(LIBRAW_PROGRESS_STRETCH); } O.four_color_rgb = save_4color; // also, restore return 0; } catch ( LibRaw_exceptions err) { EXCEPTION_HANDLER(err); } } // Supported cameras: static const char *static_camera_list[] = { "Adobe Digital Negative (DNG)", "AgfaPhoto DC-833m", "Alcatel 5035D", "Apple iPad Pro", "Apple iPhone SE", "Apple iPhone 6s", "Apple iPhone 6 plus", "Apple iPhone 7", "Apple iPhone 7 plus", "Apple QuickTake 100", "Apple QuickTake 150", "Apple QuickTake 200", "ARRIRAW format", "AVT F-080C", "AVT F-145C", "AVT F-201C", "AVT F-510C", "AVT F-810C", "Baumer TXG14", "BlackMagic Cinema Camera", "BlackMagic Micro Cinema Camera", "BlackMagic Pocket Cinema Camera", "BlackMagic Production Camera 4k", "BlackMagic URSA", "BlackMagic URSA Mini", "Canon PowerShot 600", "Canon PowerShot A5", "Canon PowerShot A5 Zoom", "Canon PowerShot A50", "Canon PowerShot A460 (CHDK hack)", "Canon PowerShot A470 (CHDK hack)", "Canon PowerShot A530 (CHDK hack)", "Canon PowerShot A550 (CHDK hack)", "Canon PowerShot A570 (CHDK hack)", "Canon PowerShot A590 (CHDK hack)", "Canon PowerShot A610 (CHDK hack)", "Canon PowerShot A620 (CHDK hack)", "Canon PowerShot A630 (CHDK hack)", "Canon PowerShot A640 (CHDK hack)", "Canon PowerShot A650 (CHDK hack)", "Canon PowerShot A710 IS (CHDK hack)", "Canon PowerShot A720 IS (CHDK hack)", "Canon PowerShot A3300 IS (CHDK hack)", "Canon PowerShot Pro70", "Canon PowerShot Pro90 IS", "Canon PowerShot Pro1", "Canon PowerShot G1", "Canon PowerShot G1 X", "Canon PowerShot G1 X Mark II", "Canon PowerShot G2", "Canon PowerShot G3", "Canon PowerShot G3 X", "Canon PowerShot G5", "Canon PowerShot G5 X", "Canon PowerShot G6", "Canon PowerShot G7 (CHDK hack)", "Canon PowerShot G7 X", "Canon PowerShot G7 X Mark II", "Canon PowerShot G9", "Canon PowerShot G9 X", "Canon PowerShot G10", "Canon PowerShot G11", "Canon PowerShot G12", "Canon PowerShot G15", "Canon PowerShot G16", "Canon PowerShot S2 IS (CHDK hack)", "Canon PowerShot S3 IS (CHDK hack)", "Canon PowerShot S5 IS (CHDK hack)", "Canon PowerShot SD300 (CHDK hack)", "Canon PowerShot SD950 (CHDK hack)", "Canon PowerShot S30", "Canon PowerShot S40", "Canon PowerShot S45", "Canon PowerShot S50", "Canon PowerShot S60", "Canon PowerShot S70", "Canon PowerShot S90", "Canon PowerShot S95", "Canon PowerShot S100", "Canon PowerShot S110", "Canon PowerShot S120", "Canon PowerShot SX1 IS", "Canon PowerShot SX50 HS", "Canon PowerShot SX60 HS", "Canon PowerShot SX110 IS (CHDK hack)", "Canon PowerShot SX120 IS (CHDK hack)", "Canon PowerShot SX220 HS (CHDK hack)", "Canon PowerShot SX20 IS (CHDK hack)", "Canon PowerShot SX30 IS (CHDK hack)", "Canon PowerShot IXUS 160 (CHDK hack)", "Canon EOS D30", "Canon EOS D60", "Canon EOS 5D", "Canon EOS 5DS", "Canon EOS 5DS R", "Canon EOS 5D Mark II", "Canon EOS 5D Mark III", "Canon EOS 5D Mark IV", "Canon EOS 6D", "Canon EOS 7D", "Canon EOS 7D Mark II", "Canon EOS 10D", "Canon EOS 20D", "Canon EOS 20Da", "Canon EOS 30D", "Canon EOS 40D", "Canon EOS 50D", "Canon EOS 60D", "Canon EOS 60Da", "Canon EOS 70D", "Canon EOS 80D", "Canon EOS 300D / Digital Rebel / Kiss Digital", "Canon EOS 350D / Digital Rebel XT / Kiss Digital N", "Canon EOS 400D / Digital Rebel XTi / Kiss Digital X", "Canon EOS 450D / Digital Rebel XSi / Kiss Digital X2", "Canon EOS 500D / Digital Rebel T1i / Kiss Digital X3", "Canon EOS 550D / Digital Rebel T2i / Kiss Digital X4", "Canon EOS 600D / Digital Rebel T3i / Kiss Digital X5", "Canon EOS 650D / Digital Rebel T4i / Kiss Digital X6i", "Canon EOS 700D / Digital Rebel T5i", "Canon EOS 750D / Digital Rebel T6i", "Canon EOS 760D / Digital Rebel T6S", "Canon EOS 100D / Digital Rebel SL1", "Canon EOS 1000D / Digital Rebel XS / Kiss Digital F", "Canon EOS 1100D / Digital Rebel T3 / Kiss Digital X50", "Canon EOS 1200D", "Canon EOS 1300D", "Canon EOS C500", "Canon EOS D2000C", "Canon EOS M", "Canon EOS M2", "Canon EOS M3", "Canon EOS M5", "Canon EOS M10", "Canon EOS-1D", "Canon EOS-1DS", "Canon EOS-1D C", "Canon EOS-1D X", "Canon EOS-1D Mark II", "Canon EOS-1D Mark II N", "Canon EOS-1D Mark III", "Canon EOS-1D Mark IV", "Canon EOS-1Ds Mark II", "Canon EOS-1Ds Mark III", "Canon EOS-1D X Mark II", "Casio QV-2000UX", "Casio QV-3000EX", "Casio QV-3500EX", "Casio QV-4000", "Casio QV-5700", "Casio QV-R41", "Casio QV-R51", "Casio QV-R61", "Casio EX-F1", "Casio EX-FC300S", "Casio EX-FC400S", "Casio EX-FH20", "Casio EX-FH25", "Casio EX-FH100", "Casio EX-S20", "Casio EX-S100", "Casio EX-Z4", "Casio EX-Z50", "Casio EX-Z500", "Casio EX-Z55", "Casio EX-Z60", "Casio EX-Z75", "Casio EX-Z750", "Casio EX-Z8", "Casio EX-Z850", "Casio EX-Z1050", "Casio EX-ZR100", "Casio EX-Z1080", "Casio EX-ZR700", "Casio EX-ZR710", "Casio EX-ZR750", "Casio EX-ZR800", "Casio EX-ZR850", "Casio EX-ZR1000", "Casio EX-ZR1100", "Casio EX-ZR1200", "Casio EX-ZR1300", "Casio EX-ZR1500", "Casio EX-ZR3000", "Casio EX-ZR4000/5000", "Casio EX-100", "Casio EX-100F", "Casio EX-10", "Casio Exlim Pro 505", "Casio Exlim Pro 600", "Casio Exlim Pro 700", "Contax N Digital", "Creative PC-CAM 600", "Digital Bolex D16", "Digital Bolex D16M", "DJI 4384x3288", "DXO One", "Epson R-D1", "Epson R-D1s", "Epson R-D1x", "Foculus 531C", "FujiFilm E505", "FujiFilm E550", "FujiFilm E900", "FujiFilm F700", "FujiFilm F710", "FujiFilm F800", "FujiFilm F810", "FujiFilm S2Pro", "FujiFilm S3Pro", "FujiFilm S5Pro", "FujiFilm S20Pro", "FujiFilm S1", "FujiFilm S100FS", "FujiFilm S5000", "FujiFilm S5100/S5500", "FujiFilm S5200/S5600", "FujiFilm S6000fd", "FujiFilm S7000", "FujiFilm S9000/S9500", "FujiFilm S9100/S9600", "FujiFilm S200EXR", "FujiFilm S205EXR", "FujiFilm SL1000", "FujiFilm HS10/HS11", "FujiFilm HS20EXR", "FujiFilm HS22EXR", "FujiFilm HS30EXR", "FujiFilm HS33EXR", "FujiFilm HS35EXR", "FujiFilm HS50EXR", "FujiFilm F505EXR", "FujiFilm F550EXR", "FujiFilm F600EXR", "FujiFilm F605EXR", "FujiFilm F770EXR", "FujiFilm F775EXR", "FujiFilm F800EXR", "FujiFilm F900EXR", "FujiFilm X-Pro1", "FujiFilm X-Pro2", "FujiFilm X-S1", "FujiFilm XQ1", "FujiFilm XQ2", "FujiFilm X100", "FujiFilm X100S", "FujiFilm X100T", "FujiFilm X10", "FujiFilm X20", "FujiFilm X30", "FujiFilm X70", "FujiFilm X-A1", "FujiFilm X-A2", "FujiFilm X-E1", "FujiFilm X-E2", "FujiFilm X-E2S", "FujiFilm X-M1", "FujiFilm XF1", "FujiFilm X-T1", "FujiFilm X-T1 Graphite Silver", "FujiFilm X-T2", "FujiFilm X-T10", "FujiFilm IS-1", "Gione E7", "GITUP GIT2", "Google Pixel", "Google Pixel XL", "Hasselblad H5D-60", "Hasselblad H5D-50", "Hasselblad H5D-50c", "Hasselblad H5D-40", "Hasselblad H4D-60", "Hasselblad H4D-50", "Hasselblad H4D-40", "Hasselblad H4D-31", "Hasselblad H3DII-22", "Hasselblad H3DII-31", "Hasselblad H3DII-39", "Hasselblad H3DII-50", "Hasselblad H3D-22", "Hasselblad H3D-31", "Hasselblad H3D-39", "Hasselblad H2D-22", "Hasselblad H2D-39", "Hasselblad CFV", "Hasselblad CFH", "Hasselblad CF-22", "Hasselblad CF-31", "Hasselblad CF-39", "Hasselblad V96C", "Hasselblad Lusso", "Hasselblad Lunar", "Hasselblad True Zoom", "Hasselblad Stellar", "Hasselblad Stellar II", "Hasselblad HV", "Hasselblad X1D", "HTC UltraPixel", "HTC MyTouch 4G", "HTC One (A9)", "HTC One (M9)", "HTC 10", "Huawei P9", "Imacon Ixpress 96, 96C", "Imacon Ixpress 384, 384C (single shot only)", "Imacon Ixpress 132C", "Imacon Ixpress 528C (single shot only)", "ISG 2020x1520", "Ikonoskop A-Cam dII Panchromatic", "Ikonoskop A-Cam dII", "Kinefinity KineMINI", "Kinefinity KineRAW Mini", "Kinefinity KineRAW S35", "Kodak DC20", "Kodak DC25", "Kodak DC40", "Kodak DC50", "Kodak DC120", "Kodak DCS200", "Kodak DCS315C", "Kodak DCS330C", "Kodak DCS420", "Kodak DCS460", "Kodak DCS460A", "Kodak DCS460D", "Kodak DCS520C", "Kodak DCS560C", "Kodak DCS620C", "Kodak DCS620X", "Kodak DCS660C", "Kodak DCS660M", "Kodak DCS720X", "Kodak DCS760C", "Kodak DCS760M", "Kodak EOSDCS1", "Kodak EOSDCS3B", "Kodak NC2000F", "Kodak ProBack", "Kodak PB645C", "Kodak PB645H", "Kodak PB645M", "Kodak DCS Pro 14n", "Kodak DCS Pro 14nx", "Kodak DCS Pro SLR/c", "Kodak DCS Pro SLR/n", "Kodak C330", "Kodak C603", "Kodak P850", "Kodak P880", "Kodak S-1", "Kodak Z980", "Kodak Z981", "Kodak Z990", "Kodak Z1015", "Kodak KAI-0340", "Konica KD-400Z", "Konica KD-510Z", "Leaf AFi 5", "Leaf AFi 6", "Leaf AFi 7", "Leaf AFi-II 6", "Leaf AFi-II 7", "Leaf AFi-II 10", "Leaf AFi-II 10R", "Leaf Aptus-II 5", "Leaf Aptus-II 6", "Leaf Aptus-II 7", "Leaf Aptus-II 8", "Leaf Aptus-II 10", "Leaf Aptus-II 12", "Leaf Aptus-II 12R", "Leaf Aptus 17", "Leaf Aptus 22", "Leaf Aptus 54S", "Leaf Aptus 65", "Leaf Aptus 65S", "Leaf Aptus 75", "Leaf Aptus 75S", "Leaf Cantare", "Leaf Cantare XY", "Leaf CatchLight", "Leaf CMost", "Leaf Credo 40", "Leaf Credo 50", "Leaf Credo 60", "Leaf Credo 80 (low compression mode only)", "Leaf DCB-II", "Leaf Valeo 6", "Leaf Valeo 11", "Leaf Valeo 17", "Leaf Valeo 17wi", "Leaf Valeo 22", "Leaf Valeo 22wi", "Leaf Volare", "Lenovo a820", "Leica C (Typ 112)", "Leica Digilux 2", "Leica Digilux 3", "Leica Digital-Modul-R", "Leica D-LUX2", "Leica D-LUX3", "Leica D-LUX4", "Leica D-LUX5", "Leica D-LUX6", "Leica D-Lux (Typ 109)", "Leica M8", "Leica M8.2", "Leica M9", "Leica M (Typ 240)", "Leica M (Typ 262)", "Leica Monochrom (Typ 240)", "Leica Monochrom (Typ 246)", "Leica M-D (Typ 262)", "Leica M-E", "Leica M-P", "Leica R8", "Leica Q (Typ 116)", "Leica S", "Leica S2", "Leica S (Typ 007)", "Leica SL (Typ 601)", "Leica T (Typ 701)", "Leica TL", "Leica X1", "Leica X (Typ 113)", "Leica X2", "Leica X-E (Typ 102)", "Leica X-U (Typ 113)", "Leica V-LUX1", "Leica V-LUX2", "Leica V-LUX3", "Leica V-LUX4", "Leica V-Lux (Typ 114)", "Leica X VARIO (Typ 107)", "LG G3", "LG G4", "Logitech Fotoman Pixtura", "Mamiya ZD", "Matrix 4608x3288", "Meizy MX4", "Micron 2010", "Minolta RD175", "Minolta DiMAGE 5", "Minolta DiMAGE 7", "Minolta DiMAGE 7i", "Minolta DiMAGE 7Hi", "Minolta DiMAGE A1", "Minolta DiMAGE A2", "Minolta DiMAGE A200", "Minolta DiMAGE G400", "Minolta DiMAGE G500", "Minolta DiMAGE G530", "Minolta DiMAGE G600", "Minolta DiMAGE Z2", "Minolta Alpha/Dynax/Maxxum 5D", "Minolta Alpha/Dynax/Maxxum 7D", "Motorola PIXL", "Nikon D1", "Nikon D1H", "Nikon D1X", "Nikon D2H", "Nikon D2Hs", "Nikon D2X", "Nikon D2Xs", "Nikon D3", "Nikon D3s", "Nikon D3X", "Nikon D4", "Nikon D4s", "Nikon D40", "Nikon D40X", "Nikon D5", "Nikon D50", "Nikon D60", "Nikon D70", "Nikon D70s", "Nikon D80", "Nikon D90", "Nikon D100", "Nikon D200", "Nikon D300", "Nikon D300s", "Nikon D500", "Nikon D600", "Nikon D610", "Nikon D700", "Nikon D750", "Nikon D800", "Nikon D800E", "Nikon D810", "Nikon D810A", "Nikon D3000", "Nikon D3100", "Nikon D3200", "Nikon D3300", "Nikon D3400", "Nikon D5000", "Nikon D5100", "Nikon D5200", "Nikon D5300", "Nikon D5500", "Nikon D7000", "Nikon D7100", "Nikon D7200", "Nikon Df", "Nikon 1 AW1", "Nikon 1 J1", "Nikon 1 J2", "Nikon 1 J3", "Nikon 1 J4", "Nikon 1 J5", "Nikon 1 S1", "Nikon 1 S2", "Nikon 1 V1", "Nikon 1 V2", "Nikon 1 V3", "Nikon E700 (\"DIAG RAW\" hack)", "Nikon E800 (\"DIAG RAW\" hack)", "Nikon E880 (\"DIAG RAW\" hack)", "Nikon E900 (\"DIAG RAW\" hack)", "Nikon E950 (\"DIAG RAW\" hack)", "Nikon E990 (\"DIAG RAW\" hack)", "Nikon E995 (\"DIAG RAW\" hack)", "Nikon E2100 (\"DIAG RAW\" hack)", "Nikon E2500 (\"DIAG RAW\" hack)", "Nikon E3200 (\"DIAG RAW\" hack)", "Nikon E3700 (\"DIAG RAW\" hack)", "Nikon E4300 (\"DIAG RAW\" hack)", "Nikon E4500 (\"DIAG RAW\" hack)", "Nikon E5000", "Nikon E5400", "Nikon E5700", "Nikon E8400", "Nikon E8700", "Nikon E8800", "Nikon Coolpix A", "Nikon Coolpix P330", "Nikon Coolpix P340", "Nikon Coolpix P6000", "Nikon Coolpix P7000", "Nikon Coolpix P7100", "Nikon Coolpix P7700", "Nikon Coolpix P7800", "Nikon Coolpix S6 (\"DIAG RAW\" hack)", "Nikon Coolscan NEF", "Nokia N95", "Nokia X2", "Nokia 1200x1600", "Nokia Lumia 950 XL", "Nokia Lumia 1020", "Nokia Lumia 1520", "Olympus AIR A01", "Olympus C3030Z", "Olympus C5050Z", "Olympus C5060Z", "Olympus C7070WZ", "Olympus C70Z,C7000Z", "Olympus C740UZ", "Olympus C770UZ", "Olympus C8080WZ", "Olympus X200,D560Z,C350Z", "Olympus E-1", "Olympus E-3", "Olympus E-5", "Olympus E-10", "Olympus E-20", "Olympus E-30", "Olympus E-300", "Olympus E-330", "Olympus E-400", "Olympus E-410", "Olympus E-420", "Olympus E-450", "Olympus E-500", "Olympus E-510", "Olympus E-520", "Olympus E-600", "Olympus E-620", "Olympus E-P1", "Olympus E-P2", "Olympus E-P3", "Olympus E-P5", "Olympus E-PL1", "Olympus E-PL1s", "Olympus E-PL2", "Olympus E-PL3", "Olympus E-PL5", "Olympus E-PL6", "Olympus E-PL7", "Olympus E-PL8", "Olympus E-PM1", "Olympus E-PM2", "Olympus E-M1", "Olympus E-M1 Mark II", "Olympus E-M10", "Olympus E-M10 Mark II", "Olympus E-M5", "Olympus E-M5 Mark II", "Olympus Pen F", "Olympus SP310", "Olympus SP320", "Olympus SP350", "Olympus SP500UZ", "Olympus SP510UZ", "Olympus SP550UZ", "Olympus SP560UZ", "Olympus SP565UZ", "Olympus SP570UZ", "Olympus STYLUS1", "Olympus STYLUS1s", "Olympus SH-2", "Olympus SH-3", "Olympus TG-4", "Olympus XZ-1", "Olympus XZ-2", "Olympus XZ-10", "OmniVision 4688", "OmniVision OV5647", "OmniVision OV5648", "OmniVision OV8850", "OmniVision 13860", "Panasonic DMC-CM1", "Panasonic DMC-FZ8", "Panasonic DMC-FZ18", "Panasonic DMC-FZ28", "Panasonic DMC-FZ30", "Panasonic DMC-FZ35/FZ38", "Panasonic DMC-FZ40", "Panasonic DMC-FZ50", "Panasonic DMC-FZ7", "Panasonic DMC-FZ70", "Panasonic DMC-FZ100", "Panasonic DMC-FZ150", "Panasonic DMC-FZ200", "Panasonic DMC-FZ300/330", "Panasonic DMC-FZ1000", "Panasonic DMC-FZ2000/2500/FZH1", "Panasonic DMC-FX150", "Panasonic DMC-G1", "Panasonic DMC-G10", "Panasonic DMC-G2", "Panasonic DMC-G3", "Panasonic DMC-G5", "Panasonic DMC-G6", "Panasonic DMC-G7/G70", "Panasonic DMC-G8/80/81/85", "Panasonic DMC-GF1", "Panasonic DMC-GF2", "Panasonic DMC-GF3", "Panasonic DMC-GF5", "Panasonic DMC-GF6", "Panasonic DMC-GF7", "Panasonic DMC-GH1", "Panasonic DMC-GH2", "Panasonic DMC-GH3", "Panasonic DMC-GH4", "Panasonic AG-GH4", "Panasonic DMC-GM1", "Panasonic DMC-GM1s", "Panasonic DMC-GM5", "Panasonic DMC-GX1", "Panasonic DMC-GX7", "Panasonic DMC-GX8", "Panasonic DMC-GX80/85", "Panasonic DMC-L1", "Panasonic DMC-L10", "Panasonic DMC-LC1", "Panasonic DMC-LX1", "Panasonic DMC-LF1", "Panasonic DMC-LX2", "Panasonic DMC-LX3", "Panasonic DMC-LX5", "Panasonic DMC-LX7", "Panasonic DMC-LX9/10/15", "Panasonic DMC-LX100", "Panasonic DMC-TZ60/61/SZ40", "Panasonic DMC-TZ70/71/ZS50", "Panasonic DMC-TZ80/81/85/ZS60", "Panasonic DMC-TZ100/101/ZS100", "Pentax *ist D", "Pentax *ist DL", "Pentax *ist DL2", "Pentax *ist DS", "Pentax *ist DS2", "Pentax GR", "Pentax K10D", "Pentax K20D", "Pentax K100D", "Pentax K100D Super", "Pentax K110D", "Pentax K200D", "Pentax K2000/K-m", "Pentax K-x", "Pentax K-r", "Pentax K-01", "Pentax K-1", "Pentax K-3", "Pentax K-3 II", "Pentax K-30", "Pentax K-5", "Pentax K-5 II", "Pentax K-5 IIs", "Pentax K-50", "Pentax K-500", "Pentax K-7", "Pentax K-70", "Pentax K-S1", "Pentax K-S2", "Pentax MX-1", "Pentax Q", "Pentax Q7", "Pentax Q10", "Pentax QS-1", "Pentax Optio S", "Pentax Optio S4", "Pentax Optio 33WR", "Pentax Optio 750Z", "Pentax 645D", "Pentax 645Z", "PhaseOne IQ140", "PhaseOne IQ150", "PhaseOne IQ160", "PhaseOne IQ180", "PhaseOne IQ180 IR", "PhaseOne IQ250", "PhaseOne IQ260", "PhaseOne IQ260 Achromatic", "PhaseOne IQ280", "PhaseOne IQ3 50MP", "PhaseOne IQ3 60MP", "PhaseOne IQ3 80MP", "PhaseOne IQ3 100MP", "PhaseOne LightPhase", "PhaseOne Achromatic+", "PhaseOne H 10", "PhaseOne H 20", "PhaseOne H 25", "PhaseOne P 20", "PhaseOne P 20+", "PhaseOne P 21", "PhaseOne P 25", "PhaseOne P 25+", "PhaseOne P 30", "PhaseOne P 30+", "PhaseOne P 40+", "PhaseOne P 45", "PhaseOne P 45+", "PhaseOne P 65", "PhaseOne P 65+", "Photron BC2-HD", "Pixelink A782", "Polaroid x530", "RaspberryPi Camera", "RaspberryPi Camera V2", "Ricoh GR", "Ricoh GR Digital", "Ricoh GR Digital II", "Ricoh GR Digital III", "Ricoh GR Digital IV", "Ricoh GR II", "Ricoh GX100", "Ricoh GX200", "Ricoh GXR MOUNT A12", "Ricoh GXR MOUNT A16 24-85mm F3.5-5.5", "Ricoh GXR, S10 24-72mm F2.5-4.4 VC", "Ricoh GXR, GR A12 50mm F2.5 MACRO", "Ricoh GXR, GR LENS A12 28mm F2.5", "Ricoh GXR, GXR P10", #ifndef NO_JASPER "Redcode R3D format", #endif "Rollei d530flex", "RoverShot 3320af", "Samsung EX1", "Samsung EX2F", "Samsung GX-1L", "Samsung GX-1S", "Samsung GX10", "Samsung GX20", "Samsung Galaxy NX (EK-GN120)", "Samsung Galaxy S7 (SM-G935F)", "Samsung NX1", "Samsung NX5", "Samsung NX10", "Samsung NX11", "Samsung NX100", "Samsung NX1000", "Samsung NX1100", "Samsung NX20", "Samsung NX200", "Samsung NX210", "Samsung NX2000", "Samsung NX30", "Samsung NX300", "Samsung NX300M", "Samsung NX3000", "Samsung NX500", "Samsung NX mini", "Samsung Pro815", "Samsung WB550", "Samsung WB2000", "Samsung S85 (hacked)", "Samsung S850 (hacked)", "Samsung Galaxy S3", "Samsung Galaxy S7", "Samsung Galaxy S7 Edge", "Samsung Galaxy Nexus", "Sarnoff 4096x5440", "Seitz 6x17", "Seitz Roundshot D3", "Seitz Roundshot D2X", "Seitz Roundshot D2Xs", "Sigma SD9", "Sigma SD10", "Sigma SD14", "Sigma SD15", "Sigma SD1", "Sigma SD1 Merill", "Sigma DP1", "Sigma DP1 Merill", "Sigma DP1S", "Sigma DP1X", "Sigma DP2", "Sigma DP2 Merill", "Sigma DP2S", "Sigma DP2X", "Sigma DP3 Merill", "Sigma dp0 Quattro", "Sigma dp1 Quattro", "Sigma dp2 Quattro", "Sigma dp3 Quattro", "Sigma sd Quattro", "Sigma sd Quattro H", "Sinar eMotion 22", "Sinar eMotion 54", "Sinar eSpirit 65", "Sinar eMotion 75", "Sinar eVolution 75", "Sinar 3072x2048", "Sinar 4080x4080", "Sinar 4080x5440", "Sinar STI format", "Sinar Sinarback 54", "SMaL Ultra-Pocket 3", "SMaL Ultra-Pocket 4", "SMaL Ultra-Pocket 5", "Sony A7", "Sony A7 II", "Sony A7R", "Sony A7R II", "Sony A7S", "Sony A7S II", "Sony ILCA-68 (A68)", "Sony ILCA-77M2 (A77-II)", "Sony ILCA-99M2 (A99-II)", "Sony ILCE-3000", "Sony ILCE-5000", "Sony ILCE-5100", "Sony ILCE-6000", "Sony ILCE-6300", "Sony ILCE-6500", "Sony ILCE-QX1", "Sony DSC-F828", "Sony DSC-R1", "Sony DSC-RX1", "Sony DSC-RX1R", "Sony DSC-RX1R II", "Sony DSC-RX10", "Sony DSC-RX10II", "Sony DSC-RX10III", "Sony DSC-RX100", "Sony DSC-RX100II", "Sony DSC-RX100III", "Sony DSC-RX100IV", "Sony DSC-RX100V", "Sony DSC-V3", "Sony DSLR-A100", "Sony DSLR-A200", "Sony DSLR-A230", "Sony DSLR-A290", "Sony DSLR-A300", "Sony DSLR-A330", "Sony DSLR-A350", "Sony DSLR-A380", "Sony DSLR-A390", "Sony DSLR-A450", "Sony DSLR-A500", "Sony DSLR-A550", "Sony DSLR-A560", "Sony DSLR-A580", "Sony DSLR-A700", "Sony DSLR-A850", "Sony DSLR-A900", "Sony NEX-3", "Sony NEX-3N", "Sony NEX-5", "Sony NEX-5N", "Sony NEX-5R", "Sony NEX-5T", "Sony NEX-6", "Sony NEX-7", "Sony NEX-C3", "Sony NEX-F3", "Sony NEX-VG20", "Sony NEX-VG30", "Sony NEX-VG900", "Sony SLT-A33", "Sony SLT-A35", "Sony SLT-A37", "Sony SLT-A55V", "Sony SLT-A57", "Sony SLT-A58", "Sony SLT-A65V", "Sony SLT-A77V", "Sony SLT-A99V", "Sony XCD-SX910CR", "Sony IMX135-mipi 13mp", "Sony IMX135-QCOM", "Sony IMX072-mipi", "Sony IMX214", "Sony IMX219", "Sony IMX230", "Sony IMX298-mipi 16mp", "Sony IMX219-mipi 8mp", "Sony Xperia L", "STV680 VGA", "PtGrey GRAS-50S5C", "JaiPulnix BB-500CL", "JaiPulnix BB-500GE", "SVS SVS625CL", "YUNEEC CGO4", "Xiaomi MI3", "Xiaomi RedMi Note3 Pro", NULL }; const char** LibRaw::cameraList() { return static_camera_list;} int LibRaw::cameraCount() { return (sizeof(static_camera_list)/sizeof(static_camera_list[0]))-1; } const char * LibRaw::strprogress(enum LibRaw_progress p) { switch(p) { case LIBRAW_PROGRESS_START: return "Starting"; case LIBRAW_PROGRESS_OPEN : return "Opening file"; case LIBRAW_PROGRESS_IDENTIFY : return "Reading metadata"; case LIBRAW_PROGRESS_SIZE_ADJUST: return "Adjusting size"; case LIBRAW_PROGRESS_LOAD_RAW: return "Reading RAW data"; case LIBRAW_PROGRESS_REMOVE_ZEROES: return "Clearing zero values"; case LIBRAW_PROGRESS_BAD_PIXELS : return "Removing dead pixels"; case LIBRAW_PROGRESS_DARK_FRAME: return "Subtracting dark frame data"; case LIBRAW_PROGRESS_FOVEON_INTERPOLATE: return "Interpolating Foveon sensor data"; case LIBRAW_PROGRESS_SCALE_COLORS: return "Scaling colors"; case LIBRAW_PROGRESS_PRE_INTERPOLATE: return "Pre-interpolating"; case LIBRAW_PROGRESS_INTERPOLATE: return "Interpolating"; case LIBRAW_PROGRESS_MIX_GREEN : return "Mixing green channels"; case LIBRAW_PROGRESS_MEDIAN_FILTER : return "Median filter"; case LIBRAW_PROGRESS_HIGHLIGHTS: return "Highlight recovery"; case LIBRAW_PROGRESS_FUJI_ROTATE : return "Rotating Fuji diagonal data"; case LIBRAW_PROGRESS_FLIP : return "Flipping image"; case LIBRAW_PROGRESS_APPLY_PROFILE: return "ICC conversion"; case LIBRAW_PROGRESS_CONVERT_RGB: return "Converting to RGB"; case LIBRAW_PROGRESS_STRETCH: return "Stretching image"; case LIBRAW_PROGRESS_THUMB_LOAD: return "Loading thumbnail"; default: return "Some strange things"; } } #undef ID #include "../internal/libraw_x3f.cpp" void x3f_clear(void *p) { x3f_delete((x3f_t*)p); } static char *utf2char(utf16_t *str, char *buffer) { char *b = buffer; while (*str != 0x00) { char *chr = (char *)str; *b++ = *chr; str++; } *b = 0; return buffer; } static void *lr_memmem(const void *l, size_t l_len, const void *s, size_t s_len) { register char *cur, *last; const char *cl = (const char *)l; const char *cs = (const char *)s; /* we need something to compare */ if (l_len == 0 || s_len == 0) return NULL; /* "s" must be smaller or equal to "l" */ if (l_len < s_len) return NULL; /* special case where s_len == 1 */ if (s_len == 1) return (void*)memchr(l, (int)*cs, l_len); /* the last position where its possible to find "s" in "l" */ last = (char *)cl + l_len - s_len; for (cur = (char *)cl; cur <= last; cur++) if (cur[0] == cs[0] && memcmp(cur, cs, s_len) == 0) return cur; return NULL; } void LibRaw::parse_x3f() { x3f_t *x3f = x3f_new_from_file(libraw_internal_data.internal_data.input); if(!x3f) return; _x3f_data = x3f; x3f_header_t *H = NULL; x3f_directory_section_t *DS = NULL; H = &x3f->header; // Parse RAW size from RAW section x3f_directory_entry_t *DE = x3f_get_raw(x3f); if(!DE) return; imgdata.sizes.flip = H->rotation; x3f_directory_entry_header_t *DEH = &DE->header; x3f_image_data_t *ID = &DEH->data_subsection.image_data; imgdata.sizes.raw_width = ID->columns; imgdata.sizes.raw_height = ID->rows; // Parse other params from property section DE = x3f_get_prop(x3f); if((x3f_load_data(x3f,DE) == X3F_OK)) { // Parse property list DEH = &DE->header; x3f_property_list_t *PL = &DEH->data_subsection.property_list; if (PL->property_table.size != 0) { int i; x3f_property_t *P = PL->property_table.element; for (i=0; inum_properties; i++) { char name[100], value[100]; utf2char(P[i].name,name); utf2char(P[i].value,value); if (!strcmp (name, "ISO")) imgdata.other.iso_speed = atoi(value); if (!strcmp (name, "CAMMANUF")) strcpy (imgdata.idata.make, value); if (!strcmp (name, "CAMMODEL")) strcpy (imgdata.idata.model, value); if (!strcmp (name, "CAMSERIAL")) strcpy (imgdata.shootinginfo.BodySerial, value); if (!strcmp (name, "WB_DESC")) strcpy (imgdata.color.model2, value); if (!strcmp (name, "TIME")) imgdata.other.timestamp = atoi(value); if (!strcmp (name, "SHUTTER")) imgdata.other.shutter = atof(value); if (!strcmp (name, "APERTURE")) imgdata.other.aperture = atof(value); if (!strcmp (name, "FLENGTH")) imgdata.other.focal_len = atof(value); if (!strcmp (name, "FLEQ35MM")) imgdata.lens.makernotes.FocalLengthIn35mmFormat = atof(value); if (!strcmp (name, "LENSARANGE")) { char *sp; imgdata.lens.makernotes.MaxAp4CurFocal = imgdata.lens.makernotes.MinAp4CurFocal = atof(value); sp = strrchr (value, ' '); if (sp) { imgdata.lens.makernotes.MinAp4CurFocal = atof(sp); if (imgdata.lens.makernotes.MaxAp4CurFocal > imgdata.lens.makernotes.MinAp4CurFocal) my_swap (float, imgdata.lens.makernotes.MaxAp4CurFocal, imgdata.lens.makernotes.MinAp4CurFocal); } } if (!strcmp (name, "LENSFRANGE")) { char *sp; imgdata.lens.makernotes.MinFocal = imgdata.lens.makernotes.MaxFocal = atof(value); sp = strrchr (value, ' '); if (sp) { imgdata.lens.makernotes.MaxFocal = atof(sp); if ((imgdata.lens.makernotes.MaxFocal + 0.17f) < imgdata.lens.makernotes.MinFocal) my_swap (float, imgdata.lens.makernotes.MaxFocal, imgdata.lens.makernotes.MinFocal); } } if (!strcmp (name, "LENSMODEL")) { char *sp; imgdata.lens.makernotes.LensID = strtol (value, &sp, 16); // atoi(value); if (imgdata.lens.makernotes.LensID) imgdata.lens.makernotes.LensMount = Sigma_X3F; } } imgdata.idata.raw_count=1; load_raw = &LibRaw::x3f_load_raw; imgdata.sizes.raw_pitch = imgdata.sizes.raw_width*6; imgdata.idata.is_foveon = 1; libraw_internal_data.internal_output_params.raw_color=1; // Force adobe coeff imgdata.color.maximum=0x3fff; // To be reset by color table libraw_internal_data.unpacker_data.order = 0x4949; } } else { // No property list if(imgdata.sizes.raw_width == 5888 ||imgdata.sizes.raw_width == 2944 || imgdata.sizes.raw_width == 6656 ||imgdata.sizes.raw_width == 3328 || imgdata.sizes.raw_width == 5504 ||imgdata.sizes.raw_width == 2752 ) // Quattro { imgdata.idata.raw_count=1; load_raw = &LibRaw::x3f_load_raw; imgdata.sizes.raw_pitch = imgdata.sizes.raw_width*6; imgdata.idata.is_foveon = 1; libraw_internal_data.internal_output_params.raw_color=1; // Force adobe coeff libraw_internal_data.unpacker_data.order = 0x4949; strcpy (imgdata.idata.make, "SIGMA"); #if 1 // Try to find model number in first 2048 bytes; int pos = libraw_internal_data.internal_data.input->tell(); libraw_internal_data.internal_data.input->seek(0,SEEK_SET); unsigned char buf[2048]; libraw_internal_data.internal_data.input->read(buf,2048,1); libraw_internal_data.internal_data.input->seek(pos,SEEK_SET); unsigned char *fnd=(unsigned char*)lr_memmem(buf,2048,"SIGMA dp",8); unsigned char *fndsd=(unsigned char*)lr_memmem(buf,2048,"sd Quatt",8); if(fnd) { unsigned char *nm = fnd+8; snprintf(imgdata.idata.model,64,"dp%c Quattro",*nm<='9' && *nm >='0' ? *nm: '2'); } else if(fndsd) { snprintf(imgdata.idata.model,64,"%s",fndsd); } else #endif if(imgdata.sizes.raw_width == 6656 ||imgdata.sizes.raw_width == 3328 ) strcpy (imgdata.idata.model, "sd Quattro H"); else strcpy (imgdata.idata.model, "dp2 Quattro"); } //else } // Try to get thumbnail data LibRaw_thumbnail_formats format = LIBRAW_THUMBNAIL_UNKNOWN; if( (DE = x3f_get_thumb_jpeg(x3f))) { format = LIBRAW_THUMBNAIL_JPEG; } else if( (DE = x3f_get_thumb_plain(x3f))) { format = LIBRAW_THUMBNAIL_BITMAP; } if(DE) { x3f_directory_entry_header_t *DEH = &DE->header; x3f_image_data_t *ID = &DEH->data_subsection.image_data; imgdata.thumbnail.twidth = ID->columns; imgdata.thumbnail.theight = ID->rows; imgdata.thumbnail.tcolors = 3; imgdata.thumbnail.tformat = format; libraw_internal_data.internal_data.toffset = DE->input.offset; write_thumb = &LibRaw::x3f_thumb_loader; } } INT64 LibRaw::x3f_thumb_size() { try { x3f_t *x3f = (x3f_t*)_x3f_data; if (!x3f) return -1; // No data pointer set x3f_directory_entry_t *DE = x3f_get_thumb_jpeg(x3f); if (!DE) DE = x3f_get_thumb_plain(x3f); if (!DE) return -1; int64_t p = x3f_load_data_size(x3f, DE); if (p < 0 || p > 0xffffffff) return -1; return p; } catch (...) { return -1; } } void LibRaw::x3f_thumb_loader() { try { x3f_t *x3f = (x3f_t*)_x3f_data; if (!x3f) return; // No data pointer set x3f_directory_entry_t *DE = x3f_get_thumb_jpeg(x3f); if (!DE) DE = x3f_get_thumb_plain(x3f); if (!DE) return; if (X3F_OK != x3f_load_data(x3f, DE)) throw LIBRAW_EXCEPTION_IO_CORRUPT; x3f_directory_entry_header_t *DEH = &DE->header; x3f_image_data_t *ID = &DEH->data_subsection.image_data; imgdata.thumbnail.twidth = ID->columns; imgdata.thumbnail.theight = ID->rows; imgdata.thumbnail.tcolors = 3; if (imgdata.thumbnail.tformat == LIBRAW_THUMBNAIL_JPEG) { imgdata.thumbnail.thumb = (char*)malloc(ID->data_size); merror(imgdata.thumbnail.thumb, "LibRaw::x3f_thumb_loader()"); memmove(imgdata.thumbnail.thumb, ID->data, ID->data_size); imgdata.thumbnail.tlength = ID->data_size; } else if (imgdata.thumbnail.tformat == LIBRAW_THUMBNAIL_BITMAP) { imgdata.thumbnail.tlength = ID->columns * ID->rows * 3; imgdata.thumbnail.thumb = (char*)malloc(ID->columns * ID->rows * 3); merror(imgdata.thumbnail.thumb, "LibRaw::x3f_thumb_loader()"); char *src0 = (char*)ID->data; for (int row = 0; row < ID->rows; row++) { int offset = row * ID->row_stride; if (offset + ID->columns * 3 > ID->data_size) break; char *dest = &imgdata.thumbnail.thumb[row*ID->columns * 3]; char *src = &src0[offset]; memmove(dest, src, ID->columns * 3); } } } catch (...) { // do nothing } } static inline uint32_t _clampbits(int x, uint32_t n) { uint32_t _y_temp; if( (_y_temp=x>>n) ) x = ~_y_temp >> (32-n); return x; } void LibRaw::x3f_dpq_interpolate_rg() { int w = imgdata.sizes.raw_width/2; int h = imgdata.sizes.raw_height/2; unsigned short *image = (ushort*)imgdata.rawdata.color3_image; for (int color = 0; color < 2; color++) { for (int y = 2; y < (h-2); y++) { uint16_t* row0 = &image[imgdata.sizes.raw_width*3*(y*2)+color]; // dst[1] uint16_t row0_3 = row0[3]; uint16_t* row1 = &image[imgdata.sizes.raw_width*3*(y*2+1)+color]; //dst1[1] uint16_t row1_3 = row1[3]; for (int x = 2; x < (w-2); x++) { row1[0]=row1[3]=row0[3]=row0[0]; row0 += 6; row1 += 6; } } } } #define _ABS(a) ((a)<0?-(a):(a)) #undef CLIP #define CLIP(value,high) ((value)>(high)?(high):(value)) void LibRaw::x3f_dpq_interpolate_af(int xstep, int ystep, int scale) { unsigned short *image = (ushort*)imgdata.rawdata.color3_image; unsigned int rowpitch = imgdata.rawdata.sizes.raw_pitch/2; // in 16-bit words // Interpolate single pixel for(int y = 0; y < imgdata.rawdata.sizes.height+imgdata.rawdata.sizes.top_margin; y+=ystep) { if(yimgdata.rawdata.sizes.raw_height-scale) break; uint16_t* row0 = &image[imgdata.sizes.raw_width*3*y]; // Наша строка uint16_t* row_minus = &image[imgdata.sizes.raw_width*3*(y-scale)]; // Строка выше uint16_t* row_plus = &image[imgdata.sizes.raw_width*3*(y+scale)]; // Строка ниже for(int x = 0; x < imgdata.rawdata.sizes.width+imgdata.rawdata.sizes.left_margin; x+= xstep) { if(ximgdata.rawdata.sizes.raw_width-scale) break; uint16_t* pixel0 = &row0[x*3]; uint16_t* pixel_top = &row_minus[x*3]; uint16_t* pixel_bottom = &row_plus[x*3]; uint16_t* pixel_left = &row0[(x-scale)*3]; uint16_t* pixel_right = &row0[(x+scale)*3]; uint16_t* pixf = pixel_top; if(_ABS(pixf[2]-pixel0[2])>_ABS(pixel_bottom[2]-pixel0[2])) pixf = pixel_bottom; if(_ABS(pixf[2]-pixel0[2])>_ABS(pixel_left[2]-pixel0[2])) pixf = pixel_left; if(_ABS(pixf[2]-pixel0[2])>_ABS(pixel_right[2]-pixel0[2])) pixf = pixel_right; int blocal = pixel0[2],bnear = pixf[2]; if(blocal < imgdata.color.black+16 || bnear < imgdata.color.black+16 ) { if(pixel0[0] < imgdata.color.black) pixel0[0] = imgdata.color.black; if(pixel0[1] < imgdata.color.black) pixel0[1] = imgdata.color.black; pixel0[0] = CLIP((pixel0[0] - imgdata.color.black)*4 + imgdata.color.black,16383); pixel0[1] = CLIP((pixel0[1] - imgdata.color.black)*4 + imgdata.color.black,16383); } else { float multip = float(bnear - imgdata.color.black)/float(blocal-imgdata.color.black); if(pixel0[0] < imgdata.color.black) pixel0[0] = imgdata.color.black; if(pixel0[1] < imgdata.color.black) pixel0[1] = imgdata.color.black; float pixf0 = pixf[0]; if(pixf0 < imgdata.color.black) pixf0 = imgdata.color.black; float pixf1 = pixf[1]; if(pixf1 < imgdata.color.black) pixf1 = imgdata.color.black; pixel0[0] = CLIP(((float(pixf0-imgdata.color.black)*multip + imgdata.color.black)+((pixel0[0]-imgdata.color.black)*3.75 + imgdata.color.black))/2,16383); pixel0[1] = CLIP(((float(pixf1-imgdata.color.black)*multip + imgdata.color.black)+((pixel0[1]-imgdata.color.black)*3.75 + imgdata.color.black))/2,16383); //pixel0[1] = float(pixf[1]-imgdata.color.black)*multip + imgdata.color.black; } } } } void LibRaw::x3f_dpq_interpolate_af_sd(int xstart,int ystart, int xend, int yend, int xstep, int ystep, int scale) { unsigned short *image = (ushort*)imgdata.rawdata.color3_image; unsigned int rowpitch = imgdata.rawdata.sizes.raw_pitch/2; // in 16-bit words // Interpolate single pixel for(int y = ystart; y< yend && y < imgdata.rawdata.sizes.height+imgdata.rawdata.sizes.top_margin; y+=ystep) { uint16_t* row0 = &image[imgdata.sizes.raw_width*3*y]; // Наша строка uint16_t* row1 = &image[imgdata.sizes.raw_width*3*(y+1)]; // Следующая строка uint16_t* row_minus = &image[imgdata.sizes.raw_width*3*(y-scale)]; // Строка выше uint16_t* row_plus = &image[imgdata.sizes.raw_width*3*(y+scale)]; // Строка ниже AF-point (scale=2 -> ниже row1 uint16_t* row_minus1 = &image[imgdata.sizes.raw_width*3*(y-1)]; for(int x = xstart; x< xend && x < imgdata.rawdata.sizes.width+imgdata.rawdata.sizes.left_margin; x+= xstep) { uint16_t* pixel00 = &row0[x*3]; // Current pixel float sumR = 0.f,sumG=0.f; float cnt = 0.f; for(int xx = -scale; xx <= scale; xx+= scale) { sumR += row_minus[(x+xx)*3]; sumR += row_plus[(x+xx)*3]; sumG += row_minus[(x+xx)*3+1]; sumG += row_plus[(x+xx)*3+1]; cnt +=1.f; if(xx) { cnt +=1.f; sumR += row0[(x+xx)*3]; sumG += row0[(x+xx)*3+1]; } } pixel00[0] = sumR/8.f; pixel00[1] = sumG/8.f; if(scale == 2) { uint16_t* pixel0B = &row0[x*3+3]; // right pixel uint16_t* pixel1B = &row1[x*3+3]; // right pixel float sumG0 = 0, sumG1 = 0.f; float cnt = 0.f; for(int xx = -scale; xx <= scale; xx+= scale) { sumG0 += row_minus1[(x+xx)*3+2]; sumG1 += row_plus[(x+xx)*3+2]; cnt +=1.f; if(xx) { sumG0 += row0[(x+xx)*3+2]; sumG1 += row1[(x+xx)*3+2]; cnt +=1.f; } } pixel0B[2] = sumG0/cnt; pixel1B[2] = sumG1/cnt; } // uint16_t* pixel10 = &row1[x*3]; // Pixel below current // uint16_t* pixel_bottom = &row_plus[x*3]; } } } void LibRaw::x3f_load_raw() { // already in try/catch int raise_error=0; x3f_t *x3f = (x3f_t*)_x3f_data; if(!x3f) return; // No data pointer set if(X3F_OK == x3f_load_data(x3f, x3f_get_raw(x3f))) { x3f_directory_entry_t *DE = x3f_get_raw(x3f); x3f_directory_entry_header_t *DEH = &DE->header; x3f_image_data_t *ID = &DEH->data_subsection.image_data; if(!ID) throw LIBRAW_EXCEPTION_IO_CORRUPT; x3f_quattro_t *Q = ID->quattro; x3f_huffman_t *HUF = ID->huffman; x3f_true_t *TRU = ID->tru; uint16_t *data = NULL; if(ID->rows != S.raw_height || ID->columns != S.raw_width) { raise_error = 1; goto end; } if (HUF != NULL) data = HUF->x3rgb16.data; if (TRU != NULL) data = TRU->x3rgb16.data; if (data == NULL) { raise_error = 1; goto end; } size_t datasize = S.raw_height*S.raw_width*3*sizeof(unsigned short); S.raw_pitch = S.raw_width*3*sizeof(unsigned short); if(!(imgdata.rawdata.raw_alloc = malloc(datasize))) throw LIBRAW_EXCEPTION_ALLOC; imgdata.rawdata.color3_image = (ushort (*)[3])imgdata.rawdata.raw_alloc; if(HUF) memmove(imgdata.rawdata.raw_alloc,data,datasize); else if(TRU && (!Q || !Q->quattro_layout)) memmove(imgdata.rawdata.raw_alloc,data,datasize); else if(TRU && Q) { // Move quattro data in place // R/B plane for(int prow = 0; prow < TRU->x3rgb16.rows && prow < S.raw_height/2; prow++) { ushort (*destrow)[3] = (unsigned short (*)[3]) &imgdata.rawdata.color3_image[prow*2*S.raw_pitch/3/sizeof(ushort)][0]; ushort (*srcrow)[3] = (unsigned short (*)[3]) &data[prow*TRU->x3rgb16.row_stride]; for(int pcol = 0; pcol < TRU->x3rgb16.columns && pcol < S.raw_width/2; pcol++) { destrow[pcol*2][0] = srcrow[pcol][0]; destrow[pcol*2][1] = srcrow[pcol][1]; } } for(int row = 0; row < Q->top16.rows && row < S.raw_height; row++) { ushort (*destrow)[3] = (unsigned short (*)[3]) &imgdata.rawdata.color3_image[row*S.raw_pitch/3/sizeof(ushort)][0]; ushort (*srcrow) = (unsigned short *) &Q->top16.data[row * Q->top16.columns]; for(int col = 0; col < Q->top16.columns && col < S.raw_width; col++) destrow[col][2] = srcrow[col]; } } #if 1 if(TRU && Q && (imgdata.params.raw_processing_options & LIBRAW_PROCESSING_DP2Q_INTERPOLATEAF) ) { if(imgdata.sizes.raw_width == 5888 && imgdata.sizes.raw_height == 3672) // dpN Quattro normal { x3f_dpq_interpolate_af(32,8,2); } else if(imgdata.sizes.raw_width == 5888 && imgdata.sizes.raw_height == 3776) // sd Quattro normal raw { x3f_dpq_interpolate_af_sd(216,464,imgdata.sizes.raw_width-1,3312,16,32,2); } else if(imgdata.sizes.raw_width == 6656 && imgdata.sizes.raw_height == 4480) // sd Quattro H normal raw { x3f_dpq_interpolate_af_sd(232,592,imgdata.sizes.raw_width-1,3888,16,32,2); } else if(imgdata.sizes.raw_width == 3328 && imgdata.sizes.raw_height == 2240) // sd Quattro H half size { x3f_dpq_interpolate_af_sd(116,296,imgdata.sizes.raw_width-1,2200,8,16,1); } else if(imgdata.sizes.raw_width == 5504 && imgdata.sizes.raw_height == 3680) // sd Quattro H APS-C raw { x3f_dpq_interpolate_af_sd(8,192,imgdata.sizes.raw_width-1,3185,16,32,2); } else if(imgdata.sizes.raw_width == 2752 && imgdata.sizes.raw_height == 1840) // sd Quattro H APS-C half size { x3f_dpq_interpolate_af_sd(4, 96,imgdata.sizes.raw_width-1,1800,8,16,1); } else if(imgdata.sizes.raw_width == 2944 && imgdata.sizes.raw_height == 1836) // dpN Quattro small raw { x3f_dpq_interpolate_af(16,4,1); } else if(imgdata.sizes.raw_width == 2944 && imgdata.sizes.raw_height == 1888) // sd Quattro small { x3f_dpq_interpolate_af_sd(108,232,imgdata.sizes.raw_width-1,1656,8,16,1); } } #endif if(TRU && Q && Q->quattro_layout && (imgdata.params.raw_processing_options & LIBRAW_PROCESSING_DP2Q_INTERPOLATERG) ) x3f_dpq_interpolate_rg(); } else raise_error = 1; end: if(raise_error) throw LIBRAW_EXCEPTION_IO_CORRUPT; } LibRaw-0.18.8/src/libraw_datastream.cpp000066400000000000000000000406031324423227700177610ustar00rootroot00000000000000/* -*- C++ -*- * File: libraw_datastream.cpp * Copyright 2008-2017 LibRaw LLC (info@libraw.org) * * LibRaw C++ interface (implementation) LibRaw is free software; you can redistribute it and/or modify it under the terms of the one of two licenses as you choose: 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 (See file LICENSE.LGPL provided in LibRaw distribution archive for details). 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 (See file LICENSE.CDDL provided in LibRaw distribution archive for details). */ #ifdef WIN32 #ifdef __MINGW32__ #define _WIN32_WINNT 0x0500 #include #endif #endif #define LIBRAW_LIBRARY_BUILD #include "libraw/libraw_types.h" #include "libraw/libraw.h" #include "libraw/libraw_datastream.h" #include #ifdef USE_JASPER #include /* Decode RED camera movies */ #else #define NO_JASPER #endif #ifdef USE_JPEG #include #else #define NO_JPEG #endif int LibRaw_abstract_datastream::tempbuffer_open(void *buf, size_t size) { if(substream) return EBUSY; substream = new LibRaw_buffer_datastream(buf,size); return substream?0:EINVAL; } void LibRaw_abstract_datastream::tempbuffer_close() { if(substream) delete substream; substream = NULL; } // == LibRaw_file_datastream == LibRaw_file_datastream::~LibRaw_file_datastream() { if(jas_file) fclose(jas_file); } LibRaw_file_datastream::LibRaw_file_datastream(const char *fname) :filename(fname) ,_fsize(0) #ifdef WIN32 ,wfilename() #endif ,jas_file(NULL) { if (filename.size()>0) { #ifndef WIN32 struct stat st; if(!stat(filename.c_str(),&st)) _fsize = st.st_size; #else struct _stati64 st; if(!_stati64(filename.c_str(),&st)) _fsize = st.st_size; #endif std::auto_ptr buf(new std::filebuf()); buf->open(filename.c_str(), std::ios_base::in | std::ios_base::binary); if (buf->is_open()) { f = buf; } } } #if defined(_WIN32) && !defined(__MINGW32__) && defined(_MSC_VER) && (_MSC_VER > 1310) LibRaw_file_datastream::LibRaw_file_datastream(const wchar_t *fname) : filename(),wfilename(fname),jas_file(NULL),_fsize(0) { if (wfilename.size()>0) { struct _stati64 st; if(!_wstati64(wfilename.c_str(),&st)) _fsize = st.st_size; std::auto_ptr buf(new std::filebuf()); buf->open(wfilename.c_str(), std::ios_base::in | std::ios_base::binary); if (buf->is_open()) { f = buf; } } } const wchar_t *LibRaw_file_datastream::wfname() { return wfilename.size()>0?wfilename.c_str():NULL; } #endif int LibRaw_file_datastream::valid() { return f.get() ? 1 : 0; } #define LR_STREAM_CHK() do {if(!f.get()) throw LIBRAW_EXCEPTION_IO_EOF;}while(0) int LibRaw_file_datastream::read(void * ptr,size_t size, size_t nmemb) { if(substream) return substream->read(ptr,size,nmemb); /* Visual Studio 2008 marks sgetn as insecure, but VS2010 does not. */ #if defined(WIN32SECURECALLS) && (_MSC_VER < 1600) LR_STREAM_CHK(); return int(f->_Sgetn_s(static_cast(ptr), nmemb * size,nmemb * size) / (size>0?size:1)); #else LR_STREAM_CHK(); return int(f->sgetn(static_cast(ptr), std::streamsize(nmemb * size)) / (size>0?size:1)); #endif } int LibRaw_file_datastream::eof() { if(substream) return substream->eof(); LR_STREAM_CHK(); return f->sgetc() == EOF; } int LibRaw_file_datastream::seek(INT64 o, int whence) { if(substream) return substream->seek(o,whence); LR_STREAM_CHK(); std::ios_base::seekdir dir; switch (whence) { case SEEK_SET: dir = std::ios_base::beg; break; case SEEK_CUR: dir = std::ios_base::cur; break; case SEEK_END: dir = std::ios_base::end; break; default: dir = std::ios_base::beg; } return f->pubseekoff((long)o, dir) < 0; } INT64 LibRaw_file_datastream::tell() { if(substream) return substream->tell(); LR_STREAM_CHK(); return f->pubseekoff(0, std::ios_base::cur); } char* LibRaw_file_datastream::gets(char *str, int sz) { if(substream) return substream->gets(str,sz); LR_STREAM_CHK(); std::istream is(f.get()); is.getline(str, sz); if (is.fail()) return 0; return str; } int LibRaw_file_datastream::scanf_one(const char *fmt, void*val) { if(substream) return substream->scanf_one(fmt,val); LR_STREAM_CHK(); std::istream is(f.get()); /* HUGE ASSUMPTION: *fmt is either "%d" or "%f" */ if (strcmp(fmt, "%d") == 0) { int d; is >> d; if (is.fail()) return EOF; *(static_cast(val)) = d; } else { float f; is >> f; if (is.fail()) return EOF; *(static_cast(val)) = f; } return 1; } const char* LibRaw_file_datastream::fname() { return filename.size()>0?filename.c_str():NULL; } /* You can't have a "subfile" and a "tempfile" at the same time. */ int LibRaw_file_datastream::subfile_open(const char *fn) { LR_STREAM_CHK(); if (saved_f.get()) return EBUSY; saved_f = f; std::auto_ptr buf(new std::filebuf()); buf->open(fn, std::ios_base::in | std::ios_base::binary); if (!buf->is_open()) { f = saved_f; return ENOENT; } else { f = buf; } return 0; } #if defined(_WIN32) && !defined(__MINGW32__) && defined(_MSC_VER) && (_MSC_VER > 1310) int LibRaw_file_datastream::subfile_open(const wchar_t *fn) { LR_STREAM_CHK(); if (saved_f.get()) return EBUSY; saved_f = f; std::auto_ptr buf(new std::filebuf()); buf->open(fn, std::ios_base::in | std::ios_base::binary); if (!buf->is_open()) { f = saved_f; return ENOENT; } else { f = buf; } return 0; } #endif void LibRaw_file_datastream::subfile_close() { if (!saved_f.get()) return; f = saved_f; } #undef LR_STREAM_CHK void * LibRaw_file_datastream::make_jas_stream() { #ifdef NO_JASPER return NULL; #else #if defined(_WIN32) && !defined(__MINGW32__) && defined(_MSC_VER) && (_MSC_VER > 1310) if(wfname()) { jas_file = _wfopen(wfname(),L"rb"); return jas_stream_fdopen(fileno(jas_file),"rb"); } else #endif { return jas_stream_fopen(fname(),"rb"); } #endif } int LibRaw_file_datastream::jpeg_src(void *jpegdata) { #ifdef NO_JPEG return -1; // not supported #else if(jas_file) { fclose(jas_file); jas_file = NULL;} #if defined(_WIN32) && !defined(__MINGW32__) && defined(_MSC_VER) && (_MSC_VER > 1310) if(wfname()) { jas_file = _wfopen(wfname(),L"rb"); } else #endif { jas_file = fopen(fname(),"rb"); } if(jas_file) { fseek(jas_file,tell(),SEEK_SET); j_decompress_ptr cinfo = (j_decompress_ptr) jpegdata; jpeg_stdio_src(cinfo,jas_file); return 0; // OK } return -1; #endif } // == LibRaw_buffer_datastream LibRaw_buffer_datastream::LibRaw_buffer_datastream(void *buffer, size_t bsize) { buf = (unsigned char*)buffer; streampos = 0; streamsize = bsize; } LibRaw_buffer_datastream::~LibRaw_buffer_datastream(){} int LibRaw_buffer_datastream::read(void * ptr,size_t sz, size_t nmemb) { if(substream) return substream->read(ptr,sz,nmemb); size_t to_read = sz*nmemb; if(to_read > streamsize - streampos) to_read = streamsize-streampos; if(to_read<1) return 0; memmove(ptr,buf+streampos,to_read); streampos+=to_read; return int((to_read+sz-1)/(sz>0?sz:1)); } int LibRaw_buffer_datastream::seek(INT64 o, int whence) { if(substream) return substream->seek(o,whence); switch(whence) { case SEEK_SET: if(o<0) streampos = 0; else if (size_t(o) > streamsize) streampos = streamsize; else streampos = size_t(o); return 0; case SEEK_CUR: if(o<0) { if(size_t(-o) >= streampos) streampos = 0; else streampos += (size_t)o; } else if (o>0) { if(o+streampos> streamsize) streampos = streamsize; else streampos += (size_t)o; } return 0; case SEEK_END: if(o>0) streampos = streamsize; else if ( size_t(-o) > streamsize) streampos = 0; else streampos = streamsize+(size_t)o; return 0; default: return 0; } } INT64 LibRaw_buffer_datastream::tell() { if(substream) return substream->tell(); return INT64(streampos); } char* LibRaw_buffer_datastream::gets(char *s, int sz) { if (substream) return substream->gets(s,sz); unsigned char *psrc,*pdest,*str; str = (unsigned char *)s; psrc = buf+streampos; pdest = str; while ( (size_t(psrc - buf) < streamsize) && ((pdest-str)scanf_one(fmt,val); int scanf_res; if(streampos>streamsize) return 0; #ifndef WIN32SECURECALLS scanf_res = sscanf((char*)(buf+streampos),fmt,val); #else scanf_res = sscanf_s((char*)(buf+streampos),fmt,val); #endif if(scanf_res>0) { int xcnt=0; while(streampos24) break; } } return scanf_res; } int LibRaw_buffer_datastream::eof() { if(substream) return substream->eof(); return streampos >= streamsize; } int LibRaw_buffer_datastream::valid() { return buf?1:0; } void * LibRaw_buffer_datastream::make_jas_stream() { #ifdef NO_JASPER return NULL; #else return jas_stream_memopen((char*)buf+streampos,streamsize-streampos); #endif } int LibRaw_buffer_datastream::jpeg_src(void *jpegdata) { #if defined(NO_JPEG) || !defined (USE_JPEG) return -1; #else j_decompress_ptr cinfo = (j_decompress_ptr) jpegdata; jpeg_mem_src(cinfo,(unsigned char*)buf+streampos,streamsize-streampos); return 0; #endif } //int LibRaw_buffer_datastream // == LibRaw_bigfile_datastream LibRaw_bigfile_datastream::LibRaw_bigfile_datastream(const char *fname): filename(fname) #ifdef WIN32 ,wfilename() #endif { if(filename.size()>0) { #ifndef WIN32 struct stat st; if(!stat(filename.c_str(),&st)) _fsize = st.st_size; #else struct _stati64 st; if(!_stati64(filename.c_str(),&st)) _fsize = st.st_size; #endif #ifndef WIN32SECURECALLS f = fopen(fname,"rb"); #else if(fopen_s(&f,fname,"rb")) f = 0; #endif } else {filename=std::string();f=0;} sav=0; } #if defined(_WIN32) && !defined(__MINGW32__) && defined(_MSC_VER) && (_MSC_VER > 1310) LibRaw_bigfile_datastream::LibRaw_bigfile_datastream(const wchar_t *fname) : filename(),wfilename(fname) { if(wfilename.size()>0) { struct _stati64 st; if(!_wstati64(wfilename.c_str(),&st)) _fsize = st.st_size; #ifndef WIN32SECURECALLS f = _wfopen(wfilename.c_str(),L"rb"); #else if(_wfopen_s(&f,fname,L"rb")) f = 0; #endif } else { wfilename=std::wstring(); f=0; } sav=0; } const wchar_t *LibRaw_bigfile_datastream::wfname() { return wfilename.size()>0?wfilename.c_str():NULL; } #endif LibRaw_bigfile_datastream::~LibRaw_bigfile_datastream() {if(f)fclose(f); if(sav)fclose(sav);} int LibRaw_bigfile_datastream::valid() { return f?1:0;} #define LR_BF_CHK() do {if(!f) throw LIBRAW_EXCEPTION_IO_EOF;}while(0) int LibRaw_bigfile_datastream::read(void * ptr,size_t size, size_t nmemb) { LR_BF_CHK(); return substream?substream->read(ptr,size,nmemb):int(fread(ptr,size,nmemb,f)); } int LibRaw_bigfile_datastream::eof() { LR_BF_CHK(); return substream?substream->eof():feof(f); } int LibRaw_bigfile_datastream:: seek(INT64 o, int whence) { LR_BF_CHK(); #if defined (WIN32) #ifdef WIN32SECURECALLS return substream?substream->seek(o,whence):_fseeki64(f,o,whence); #else return substream?substream->seek(o,whence):fseek(f,(long)o,whence); #endif #else return substream?substream->seek(o,whence):fseeko(f,o,whence); #endif } INT64 LibRaw_bigfile_datastream::tell() { LR_BF_CHK(); #if defined (WIN32) #ifdef WIN32SECURECALLS return substream?substream->tell():_ftelli64(f); #else return substream?substream->tell():ftell(f); #endif #else return substream?substream->tell():ftello(f); #endif } char* LibRaw_bigfile_datastream::gets(char *str, int sz) { LR_BF_CHK(); return substream?substream->gets(str,sz):fgets(str,sz,f); } int LibRaw_bigfile_datastream::scanf_one(const char *fmt, void*val) { LR_BF_CHK(); return substream?substream->scanf_one(fmt,val): #ifndef WIN32SECURECALLS fscanf(f,fmt,val) #else fscanf_s(f,fmt,val) #endif ; } const char *LibRaw_bigfile_datastream::fname() { return filename.size()>0?filename.c_str():NULL; } int LibRaw_bigfile_datastream::subfile_open(const char *fn) { if(sav) return EBUSY; sav = f; #ifndef WIN32SECURECALLS f = fopen(fn,"rb"); #else fopen_s(&f,fn,"rb"); #endif if(!f) { f = sav; sav = NULL; return ENOENT; } else return 0; } #if defined(_WIN32) && !defined(__MINGW32__) && defined(_MSC_VER) && (_MSC_VER > 1310) int LibRaw_bigfile_datastream::subfile_open(const wchar_t *fn) { if(sav) return EBUSY; sav = f; #ifndef WIN32SECURECALLS f = _wfopen(fn,L"rb"); #else _wfopen_s(&f,fn,L"rb"); #endif if(!f) { f = sav; sav = NULL; return ENOENT; } else return 0; } #endif void LibRaw_bigfile_datastream::subfile_close() { if(!sav) return; fclose(f); f = sav; sav = 0; } void *LibRaw_bigfile_datastream::make_jas_stream() { #ifdef NO_JASPER return NULL; #else return jas_stream_fdopen(fileno(f),"rb"); #endif } int LibRaw_bigfile_datastream::jpeg_src(void *jpegdata) { #ifdef NO_JPEG return -1; #else if(!f) return -1; j_decompress_ptr cinfo = (j_decompress_ptr) jpegdata; jpeg_stdio_src(cinfo,f); return 0; // OK #endif } // == LibRaw_windows_datastream #ifdef WIN32 LibRaw_windows_datastream::LibRaw_windows_datastream(const TCHAR* sFile) : LibRaw_buffer_datastream(NULL, 0) , hMap_(0) , pView_(NULL) { HANDLE hFile = CreateFile(sFile, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (hFile == INVALID_HANDLE_VALUE) throw std::runtime_error("failed to open the file"); try { Open(hFile); } catch(...) { CloseHandle(hFile); throw; } CloseHandle(hFile); // windows will defer the actual closing of this handle until the hMap_ is closed reconstruct_base(); } // ctor: construct with a file handle - caller is responsible for closing the file handle LibRaw_windows_datastream::LibRaw_windows_datastream(HANDLE hFile) : LibRaw_buffer_datastream(NULL, 0) , hMap_(0) , pView_(NULL) { Open(hFile); reconstruct_base(); } // dtor: unmap and close the mapping handle LibRaw_windows_datastream::~LibRaw_windows_datastream() { if (pView_ != NULL) ::UnmapViewOfFile(pView_); if (hMap_ != 0) ::CloseHandle(hMap_); } void LibRaw_windows_datastream::Open(HANDLE hFile) { // create a file mapping handle on the file handle hMap_ = ::CreateFileMapping(hFile, 0, PAGE_READONLY, 0, 0, 0); if (hMap_ == NULL) throw std::runtime_error("failed to create file mapping"); // now map the whole file base view if (!::GetFileSizeEx(hFile, (PLARGE_INTEGER)&cbView_)) throw std::runtime_error("failed to get the file size"); pView_ = ::MapViewOfFile(hMap_, FILE_MAP_READ, 0, 0, (size_t)cbView_); if (pView_ == NULL) throw std::runtime_error("failed to map the file"); } #endif LibRaw-0.18.8/src/libraw_xtrans_compressed.cpp000066400000000000000000000555561324423227700214140ustar00rootroot00000000000000/* -*- C++ -*- * File: libraw_xtrans_compressed.cpp * Copyright (C) 2016 Alexey Danilchenko * * Adopted to LibRaw by Alex Tutubalin, lexa@lexa.ru * LibRaw Fujifilm/compressed decoder LibRaw is free software; you can redistribute it and/or modify it under the terms of the one of two licenses as you choose: 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 (See file LICENSE.LGPL provided in LibRaw distribution archive for details). 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 (See file LICENSE.CDDL provided in LibRaw distribution archive for details). */ // This file is #included in libraw_cxx #ifdef _abs #undef _abs #undef _min #endif #define _abs(x) (((int)(x) ^ ((int)(x) >> 31)) - ((int)(x) >> 31)) #define _min(a,b) ((a) < (b) ? (a) : (b)) struct int_pair { int value1; int value2; }; enum _xt_lines { _R0=0,_R1,_R2,_R3,_R4, _G0,_G1,_G2,_G3,_G4,_G5,_G6,_G7, _B0,_B1,_B2,_B3,_B4, _ltotal }; struct xtrans_block { int cur_bit; // current bit being read (from left to right) int cur_pos; // current position in a buffer INT64 cur_buf_offset; // offset of this buffer in a file unsigned max_read_size; // Amount of data to be read int cur_buf_size; // buffer size uchar *cur_buf; // currently read block bool lastlast; LibRaw_abstract_datastream *input; struct int_pair grad_even[3][41]; // tables of gradients struct int_pair grad_odd[3][41]; ushort *linealloc; ushort *linebuf[_ltotal]; }; static unsigned sgetn(int n, uchar *s) { unsigned result = 0; while (n-- > 0) result = (result<<8) | (*s++); return result; } void LibRaw::init_xtrans(struct xtrans_params* info) { int cur_val, i; char *qt; if (libraw_internal_data.unpacker_data.fuji_block_width % 3) derror(); info->q_table = (char *) malloc(32768); merror(info->q_table, "init_xtrans()"); info->line_width = (libraw_internal_data.unpacker_data.fuji_block_width*2)/3; info->q_point[0] = 0; info->q_point[1] = 0x12; info->q_point[2] = 0x43; info->q_point[3] = 0x114; info->q_point[4] = (1 << libraw_internal_data.unpacker_data.fuji_bits) - 1; info->min_value = 0x40; cur_val = -info->q_point[4]; for (qt = info->q_table; cur_val<=info->q_point[4]; ++qt, ++cur_val) { if (cur_val<= -info->q_point[3]) *qt = -4; else if (cur_val<= -info->q_point[2]) *qt = -3; else if (cur_val<= -info->q_point[1]) *qt = -2; else if (cur_val< 0) *qt = -1; else if (cur_val== 0) *qt = 0; else if (cur_val< info->q_point[1]) *qt = 1; else if (cur_val< info->q_point[2]) *qt = 2; else if (cur_val< info->q_point[3]) *qt = 3; else *qt = 4; } // populting gradients if (info->q_point[4] == 0x3FFF) { info->total_values = 0x4000; info->raw_bits = 14; info->max_bits = 56; info->maxDiff = 256; } else if (info->q_point[4] == 0xFFF) { info->total_values = 4096; info->raw_bits = 12; info->max_bits = 48; info->maxDiff = 64; } else derror(); } #define XTRANS_BUF_SIZE 0x10000 static inline void fuji_fill_buffer(struct xtrans_block *info) { if (info->cur_pos >= info->cur_buf_size) { info->cur_pos = 0; info->cur_buf_offset += info->cur_buf_size; #ifdef LIBRAW_USE_OPENMP #pragma omp critical #endif { #ifndef LIBRAW_USE_OPENMP info->input->lock(); #endif info->input->seek(info->cur_buf_offset, SEEK_SET); info->cur_buf_size=info->input->read(info->cur_buf, 1, _min(info->max_read_size,XTRANS_BUF_SIZE)); #ifndef LIBRAW_USE_OPENMP info->input->unlock(); #endif if(info->cur_buf_size<1 && !info->lastlast) // nothing read throw LIBRAW_EXCEPTION_IO_EOF; info->max_read_size -= info->cur_buf_size; } } } void LibRaw::init_xtrans_block(struct xtrans_block* info, const struct xtrans_params *params, INT64 raw_offset, unsigned dsize) { info->linealloc = (ushort*)calloc(sizeof(ushort),_ltotal*(params->line_width+2)); merror(info->linealloc, "init_xtrans_block()"); INT64 fsize = libraw_internal_data.internal_data.input->size(); info->max_read_size = _min(unsigned(fsize-raw_offset),dsize+16); // Data size may be incorrect? info->lastlast = false; info->input = libraw_internal_data.internal_data.input; info->linebuf[_R0] = info->linealloc; for(int i = _R1; i<=_B4;i++) info->linebuf[i] = info->linebuf[i-1] + params->line_width + 2; // init buffer info->cur_buf = (uchar*)malloc(XTRANS_BUF_SIZE); merror(info->cur_buf, "init_xtrans_block()"); info->cur_bit = 0; info->cur_pos = 0; info->cur_buf_offset = raw_offset; for(int j=0; j < 3; j++) for (int i=0; i<41; i++) { info->grad_even[j][i].value1 = params->maxDiff; info->grad_even[j][i].value2 = 1; info->grad_odd[j][i].value1 = params->maxDiff; info->grad_odd[j][i].value2 = 1; } info->cur_buf_size = 0; fuji_fill_buffer(info); } void LibRaw::copy_line_to_xtrans(struct xtrans_block* info, int cur_line, int cur_block, int cur_block_width) { ushort *lineBufB[3]; ushort *lineBufG[6]; ushort *lineBufR[3]; unsigned pixel_count; ushort* line_buf; int index; int offset =libraw_internal_data.unpacker_data.fuji_block_width*cur_block + 6 * imgdata.sizes.raw_width * cur_line; ushort* raw_block_data = imgdata.rawdata.raw_image + offset; int row_count = 0; for(int i = 0; i<3; i++) { lineBufR[i] = info->linebuf[_R2+i] + 1; lineBufB[i] = info->linebuf[_B2+i] + 1; } for(int i = 0; i<6; i++) lineBufG[i] = info->linebuf[_G2+i] + 1; while (row_count < 6) { pixel_count = 0; while (pixel_count < cur_block_width) { switch (imgdata.idata.xtrans_abs[row_count][(pixel_count % 6)]) { case 0: // red line_buf = lineBufR[row_count >> 1]; break; case 1: // green default: // to make static analyzer happy line_buf = lineBufG[row_count]; break; case 2: // blue line_buf = lineBufB[row_count >> 1]; break; } index = (((pixel_count*2/3) & 0x7FFFFFFE) | ((pixel_count % 3) & 1)) + ((pixel_count % 3) >> 1); raw_block_data[pixel_count] = line_buf[index]; ++pixel_count; } ++row_count; raw_block_data += imgdata.sizes.raw_width; } } #define fuji_quant_gradient(i,v1,v2) (9*i->q_table[i->q_point[4]+(v1)] + i->q_table[i->q_point[4]+(v2)]) static inline void fuji_zerobits(struct xtrans_block* info, int *count) { uchar zero = 0; *count = 0; while (zero == 0) { zero = (info->cur_buf[info->cur_pos] >> (7 - info->cur_bit)) & 1; info->cur_bit++; info->cur_bit &= 7; if (!info->cur_bit) { ++info->cur_pos; fuji_fill_buffer(info); } if (zero) break; ++*count; } } static inline void fuji_read_code(struct xtrans_block* info, int *data, int bits_to_read) { uchar bits_left = bits_to_read; uchar bits_left_in_byte = 8 - (info->cur_bit & 7); *data = 0; if (!bits_to_read) return; if (bits_to_read >= bits_left_in_byte) { do { *data <<= bits_left_in_byte; bits_left -= bits_left_in_byte; *data |= info->cur_buf[info->cur_pos] & ((1 << bits_left_in_byte) - 1); ++info->cur_pos; fuji_fill_buffer(info); bits_left_in_byte = 8; } while (bits_left >= 8); } if (!bits_left) { info->cur_bit = (8 - (bits_left_in_byte & 7)) & 7; return; } *data <<= bits_left; bits_left_in_byte -= bits_left; *data |= ((1 << bits_left) - 1) & ((unsigned)info->cur_buf[info->cur_pos] >> bits_left_in_byte); info->cur_bit = (8 - (bits_left_in_byte & 7)) & 7; } static inline int bitDiff(int value1, int value2) { int decBits = 0; if ( value2 < value1 ) while (decBits <= 12 && (value2 << ++decBits) < value1) ; return decBits; } static inline int fuji_decode_sample_even(struct xtrans_block* info, const struct xtrans_params * params, ushort* line_buf, int pos, struct int_pair* grads) { int interp_val = 0; //ushort decBits; int errcnt=0; int sample=0, code=0; ushort* line_buf_cur = line_buf + pos; int Rb = line_buf_cur[-2 - params->line_width]; int Rc = line_buf_cur[-3 - params->line_width]; int Rd = line_buf_cur[-1 - params->line_width]; int Rf = line_buf_cur[-4 - 2*params->line_width]; int grad, gradient, diffRcRb, diffRfRb, diffRdRb; grad = fuji_quant_gradient(params, Rb - Rf, Rc - Rb); gradient = _abs(grad); diffRcRb = _abs(Rc - Rb); diffRfRb = _abs(Rf - Rb); diffRdRb = _abs(Rd - Rb); if ( diffRcRb > diffRfRb && diffRcRb > diffRdRb ) interp_val = Rf + Rd + 2 * Rb; else if ( diffRdRb > diffRcRb && diffRdRb > diffRfRb ) interp_val = Rf + Rc + 2 * Rb; else interp_val = Rd + Rc + 2 * Rb; fuji_zerobits(info, &sample); if (sample < params->max_bits - params->raw_bits - 1) { int decBits = bitDiff(grads[gradient].value1, grads[gradient].value2); fuji_read_code(info, &code, decBits); code += sample << decBits; } else { fuji_read_code(info, &code, params->raw_bits); code++; } if (code < 0 || code >= params->total_values) errcnt++; if (code & 1) code = -1 - code/2; else code /= 2; grads[gradient].value1 += _abs(code); if (grads[gradient].value2 == params->min_value ) { grads[gradient].value1 >>= 1; grads[gradient].value2 >>= 1; } grads[gradient].value2++; if (grad < 0) interp_val = (interp_val >> 2) - code; else interp_val = (interp_val >> 2) + code; if ( interp_val < 0 ) interp_val += params->total_values; else if (interp_val > params->q_point[4]) interp_val -= params->total_values; if ( interp_val >= 0 ) line_buf_cur[0] = _min(interp_val, params->q_point[4]); else line_buf_cur[0] = 0; return errcnt; } static inline int fuji_decode_sample_odd(struct xtrans_block* info, const struct xtrans_params * params, ushort* line_buf, int pos, struct int_pair* grads) { int interp_val = 0; int errcnt = 0; int sample=0, code=0; ushort* line_buf_cur = line_buf + pos; int Ra = line_buf_cur[-1]; int Rb = line_buf_cur[-2 - params->line_width]; int Rc = line_buf_cur[-3 - params->line_width]; int Rd = line_buf_cur[-1 - params->line_width]; int Rg = line_buf_cur[1]; int grad, gradient; grad = fuji_quant_gradient(params, Rb - Rc, Rc - Ra); gradient = _abs(grad); if ((Rb > Rc && Rb > Rd) || (Rb < Rc && Rb < Rd)) interp_val = (Rg + Ra + 2 * Rb) >> 2; else interp_val = (Ra + Rg) >> 1; fuji_zerobits(info, &sample); if (sample < params->max_bits - params->raw_bits - 1) { int decBits = bitDiff(grads[gradient].value1, grads[gradient].value2); fuji_read_code(info, &code, decBits); code += sample << decBits; } else { fuji_read_code(info, &code, params->raw_bits); code++; } if (code < 0 || code >= params->total_values) errcnt++; if (code & 1) code = -1 - code/2; else code /= 2; grads[gradient].value1 += _abs(code); if (grads[gradient].value2 == params->min_value) { grads[gradient].value1 >>= 1; grads[gradient].value2 >>= 1; } grads[gradient].value2++; if (grad < 0) interp_val -= code; else interp_val += code; if ( interp_val < 0 ) interp_val += params->total_values; else if (interp_val > params->q_point[4]) interp_val -= params->total_values; if ( interp_val >= 0 ) line_buf_cur[0] = _min(interp_val, params->q_point[4]); else line_buf_cur[0] = 0; return errcnt; } static void fuji_decode_interpolation_even(int line_width, ushort* line_buf, int pos) { ushort* line_buf_cur = line_buf + pos; int Rb = line_buf_cur[-2 - line_width]; int Rc = line_buf_cur[-3 - line_width]; int Rd = line_buf_cur[-1 - line_width]; int Rf = line_buf_cur[-4 - 2*line_width]; int diffRcRb = _abs(Rc - Rb); int diffRfRb = _abs(Rf - Rb); int diffRdRb = _abs(Rd - Rb); if ( diffRcRb > diffRfRb && diffRcRb > diffRdRb ) *line_buf_cur = (Rf + Rd + 2 * Rb) >> 2; else if ( diffRdRb > diffRcRb && diffRdRb > diffRfRb ) *line_buf_cur = (Rf + Rc + 2 * Rb) >> 2; else *line_buf_cur = (Rd + Rc + 2 * Rb) >> 2; } static void xtrans_extend_generic(ushort *linebuf[_ltotal], int line_width, int start, int end) { for(int i = start; i<= end; i++) { linebuf[i][0] = linebuf[i-1][1]; linebuf[i][line_width + 1] = linebuf[i-1][line_width]; } } static void xtrans_extend_red(ushort *linebuf[_ltotal], int line_width) { xtrans_extend_generic(linebuf,line_width,_R2,_R4); } static void xtrans_extend_green(ushort *linebuf[_ltotal], int line_width) { xtrans_extend_generic(linebuf,line_width,_G2,_G7); } static void xtrans_extend_blue(ushort *linebuf[_ltotal], int line_width) { xtrans_extend_generic(linebuf,line_width,_B2,_B4); } void LibRaw::xtrans_decode_block(struct xtrans_block* info, const struct xtrans_params *params, int cur_line) { int r_even_pos = 0, r_odd_pos = 1; int g_even_pos = 0, g_odd_pos = 1; int b_even_pos = 0, b_odd_pos = 1; int errcnt = 0; const int line_width = params->line_width; while (g_even_pos < line_width || g_odd_pos < line_width) { if (g_even_pos < line_width) { fuji_decode_interpolation_even(line_width, info->linebuf[_R2] + 1, r_even_pos); r_even_pos += 2; errcnt+=fuji_decode_sample_even(info, params, info->linebuf[_G2] + 1, g_even_pos, info->grad_even[0]); g_even_pos += 2; } if (g_even_pos > 8) { errcnt+=fuji_decode_sample_odd(info, params, info->linebuf[_R2] + 1, r_odd_pos, info->grad_odd[0]); r_odd_pos += 2; errcnt+=fuji_decode_sample_odd(info, params, info->linebuf[_G2] + 1, g_odd_pos, info->grad_odd[0]); g_odd_pos += 2; } } xtrans_extend_red(info->linebuf,line_width); xtrans_extend_green(info->linebuf,line_width); g_even_pos = 0, g_odd_pos = 1; while (g_even_pos < line_width || g_odd_pos < line_width) { if (g_even_pos < line_width) { errcnt+=fuji_decode_sample_even(info, params, info->linebuf[_G3] + 1, g_even_pos, info->grad_even[1]); g_even_pos += 2; fuji_decode_interpolation_even(line_width,info->linebuf[_B2] + 1, b_even_pos); b_even_pos += 2; } if (g_even_pos > 8) { errcnt+=fuji_decode_sample_odd(info,params, info->linebuf[_G3] + 1, g_odd_pos, info->grad_odd[1]); g_odd_pos += 2; errcnt+=fuji_decode_sample_odd(info,params, info->linebuf[_B2] + 1, b_odd_pos, info->grad_odd[1]); b_odd_pos += 2; } } xtrans_extend_green(info->linebuf,line_width); xtrans_extend_blue(info->linebuf,line_width); r_even_pos = 0, r_odd_pos = 1; g_even_pos = 0, g_odd_pos = 1; while (g_even_pos < line_width || g_odd_pos < line_width) { if (g_even_pos < line_width) { if (r_even_pos & 3) errcnt+=fuji_decode_sample_even(info, params, info->linebuf[_R3] + 1, r_even_pos, info->grad_even[2]); else fuji_decode_interpolation_even(line_width, info->linebuf[_R3] + 1, r_even_pos); r_even_pos += 2; fuji_decode_interpolation_even(line_width, info->linebuf[_G4] + 1, g_even_pos); g_even_pos += 2; } if (g_even_pos > 8) { errcnt+=fuji_decode_sample_odd(info, params,info->linebuf[_R3] + 1, r_odd_pos, info->grad_odd[2]); r_odd_pos += 2; errcnt+=fuji_decode_sample_odd(info,params, info->linebuf[_G4] + 1, g_odd_pos, info->grad_odd[2]); g_odd_pos += 2; } } xtrans_extend_red(info->linebuf,line_width); xtrans_extend_green(info->linebuf,line_width); g_even_pos = 0, g_odd_pos = 1; b_even_pos = 0, b_odd_pos = 1; while (g_even_pos < line_width || g_odd_pos < line_width) { if (g_even_pos < line_width) { errcnt+=fuji_decode_sample_even(info,params, info->linebuf[_G5] + 1, g_even_pos, info->grad_even[0]); g_even_pos += 2; if ((b_even_pos & 3) == 2) fuji_decode_interpolation_even(line_width, info->linebuf[_B3] + 1, b_even_pos); else errcnt+=fuji_decode_sample_even(info, params,info->linebuf[_B3] + 1, b_even_pos, info->grad_even[0]); b_even_pos += 2; } if (g_even_pos > 8) { errcnt+=fuji_decode_sample_odd(info, params,info->linebuf[_G5] + 1, g_odd_pos, info->grad_odd[0]); g_odd_pos += 2; errcnt+=fuji_decode_sample_odd(info, params,info->linebuf[_B3] + 1, b_odd_pos, info->grad_odd[0]); b_odd_pos += 2; } } xtrans_extend_green(info->linebuf,line_width); xtrans_extend_blue(info->linebuf,line_width); r_even_pos = 0, r_odd_pos = 1; g_even_pos = 0, g_odd_pos = 1; while (g_even_pos < line_width || g_odd_pos < line_width) { if (g_even_pos < line_width) { if ((r_even_pos & 3) == 2) fuji_decode_interpolation_even(line_width, info->linebuf[_R4] + 1, r_even_pos); else errcnt+=fuji_decode_sample_even(info,params, info->linebuf[_R4] + 1, r_even_pos, info->grad_even[1]); r_even_pos += 2; errcnt+=fuji_decode_sample_even(info,params, info->linebuf[_G6] + 1, g_even_pos, info->grad_even[1]); g_even_pos += 2; } if (g_even_pos > 8) { errcnt+=fuji_decode_sample_odd(info,params, info->linebuf[_R4] + 1, r_odd_pos, info->grad_odd[1]); r_odd_pos += 2; errcnt+=fuji_decode_sample_odd(info,params, info->linebuf[_G6] + 1, g_odd_pos, info->grad_odd[1]); g_odd_pos += 2; } } xtrans_extend_red(info->linebuf,line_width); xtrans_extend_green(info->linebuf,line_width); g_even_pos = 0, g_odd_pos = 1; b_even_pos = 0, b_odd_pos = 1; while (g_even_pos < line_width || g_odd_pos < line_width) { if (g_even_pos < line_width) { fuji_decode_interpolation_even(line_width, info->linebuf[_G7] + 1, g_even_pos); g_even_pos += 2; if (b_even_pos & 3) errcnt+=fuji_decode_sample_even(info,params, info->linebuf[_B4] + 1, b_even_pos, info->grad_even[2]); else fuji_decode_interpolation_even(line_width, info->linebuf[_B4] + 1, b_even_pos); b_even_pos += 2; } if (g_even_pos > 8) { errcnt+=fuji_decode_sample_odd(info, params,info->linebuf[_G7] + 1, g_odd_pos, info->grad_odd[2]); g_odd_pos += 2; errcnt+=fuji_decode_sample_odd(info, params,info->linebuf[_B4] + 1, b_odd_pos, info->grad_odd[2]); b_odd_pos += 2; } } xtrans_extend_green(info->linebuf,line_width); xtrans_extend_blue(info->linebuf,line_width); if(errcnt) derror(); } void LibRaw::xtrans_decode_strip(const struct xtrans_params* info_common, int cur_block, INT64 raw_offset, unsigned dsize) { int cur_block_width, cur_line; unsigned line_size; struct xtrans_block info; init_xtrans_block(&info, info_common, raw_offset,dsize); line_size = sizeof(ushort)*(info_common->line_width+2); cur_block_width = libraw_internal_data.unpacker_data.fuji_block_width; if (cur_block+1 == libraw_internal_data.unpacker_data.fuji_total_blocks) cur_block_width = imgdata.sizes.raw_width % libraw_internal_data.unpacker_data.fuji_block_width; struct i_pair { int a,b; }; const i_pair mtable[6] = { {_R0,_R3},{_R1,_R4},{_G0,_G6},{_G1,_G7},{_B0,_B3},{_B1,_B4}}, ztable[3]= {{_R2,3},{_G2,6},{_B2,3}}; for (cur_line = 0; cur_line < libraw_internal_data.unpacker_data.fuji_total_lines; cur_line++) { info.lastlast = (cur_block == libraw_internal_data.unpacker_data.fuji_total_blocks-1) && (cur_line ==libraw_internal_data.unpacker_data.fuji_total_lines-1); xtrans_decode_block(&info, info_common, cur_line); // copy data from line buffers and advance for(int i=0; i < 6; i++) memcpy(info.linebuf[mtable[i].a], info.linebuf[mtable[i].b], line_size); copy_line_to_xtrans(&info, cur_line, cur_block, cur_block_width); for(int i=0; i < 3; i++) { memset(info.linebuf[ztable[i].a], 0, ztable[i].b*line_size); info.linebuf[ztable[i].a][0] = info.linebuf[ztable[i].a-1][1]; info.linebuf[ztable[i].a][info_common->line_width + 1] = info.linebuf[ztable[i].a-1][info_common->line_width]; } } // release data free(info.linealloc); free(info.cur_buf); } void LibRaw::xtrans_compressed_load_raw() { struct xtrans_params common_info; int cur_block; unsigned line_size, *block_sizes; INT64 raw_offset, *raw_block_offsets; //struct xtrans_block info; init_xtrans(&common_info); line_size = sizeof(ushort)*(common_info.line_width+2); // read block sizes block_sizes = (unsigned*) malloc(sizeof(unsigned)* libraw_internal_data.unpacker_data.fuji_total_blocks); merror(block_sizes, "xtrans_load_raw()"); raw_block_offsets = (INT64*) malloc(sizeof(INT64)*libraw_internal_data.unpacker_data.fuji_total_blocks); merror(raw_block_offsets, "xtrans_load_raw()"); raw_offset = sizeof(unsigned)*libraw_internal_data.unpacker_data.fuji_total_blocks; if (raw_offset & 0xC) raw_offset += 0x10 - (raw_offset & 0xC); raw_offset += libraw_internal_data.unpacker_data.data_offset; libraw_internal_data.internal_data.input->seek (libraw_internal_data.unpacker_data.data_offset, SEEK_SET); libraw_internal_data.internal_data.input->read (block_sizes, 1, sizeof(unsigned)*libraw_internal_data.unpacker_data.fuji_total_blocks); raw_block_offsets[0] = raw_offset; // calculating raw block offsets for (cur_block = 0; cur_block < libraw_internal_data.unpacker_data.fuji_total_blocks; cur_block++) { unsigned bsize = sgetn(4, (uchar *)(block_sizes+cur_block)); block_sizes[cur_block] = bsize; } for (cur_block = 1; cur_block < libraw_internal_data.unpacker_data.fuji_total_blocks; cur_block++) raw_block_offsets[cur_block] = raw_block_offsets[cur_block-1] + block_sizes[cur_block-1] ; xtrans_decode_loop(&common_info,libraw_internal_data.unpacker_data.fuji_total_blocks,raw_block_offsets,block_sizes); free(block_sizes); free(raw_block_offsets); free(common_info.q_table); } void LibRaw::xtrans_decode_loop(const struct xtrans_params* common_info, int count, INT64* raw_block_offsets, unsigned *block_sizes) { int cur_block; #ifdef LIBRAW_USE_OPENMP #pragma omp parallel for private(cur_block) #endif for (cur_block = 0; cur_block < count ; cur_block++) { xtrans_decode_strip(common_info, cur_block, raw_block_offsets[cur_block], block_sizes[cur_block]); } } void LibRaw::parse_xtrans_header() { unsigned signature, version, h_raw_type, h_raw_bits, h_raw_height, h_raw_rounded_width, h_raw_width, h_block_size, h_blocks_in_row, h_total_lines; uchar header[16]; libraw_internal_data.internal_data.input->seek(libraw_internal_data.unpacker_data.data_offset,SEEK_SET); libraw_internal_data.internal_data.input->read(header, 1, sizeof(header)); // read all header signature = sgetn(2, header); version = header[2]; h_raw_type = header[3]; h_raw_bits = header[4]; h_raw_height = sgetn(2, header+5); h_raw_rounded_width = sgetn(2, header+7); h_raw_width = sgetn(2, header+9); h_block_size = sgetn(2, header+11); h_blocks_in_row = header[13]; h_total_lines = sgetn(2, header+14); // general validation if (signature != 0x4953 || version != 1 || h_raw_height > 0x3000 || h_raw_height < 6 || h_raw_height % 6 || h_raw_width > 0x3000 || h_raw_width < 0x300 || h_raw_width % 24 || h_raw_rounded_width > 0x3000 || h_raw_rounded_width < h_block_size || h_raw_rounded_width % h_block_size || h_raw_rounded_width - h_raw_width >= h_block_size || h_block_size != 0x300 || h_blocks_in_row > 0x10 || h_blocks_in_row == 0 || h_blocks_in_row != h_raw_rounded_width / h_block_size || h_total_lines > 0x800 || h_total_lines == 0 || h_total_lines != h_raw_height / 6 || (h_raw_bits != 12 && h_raw_bits != 14) || h_raw_type != 16) return; // modify data libraw_internal_data.unpacker_data.fuji_total_lines = h_total_lines; libraw_internal_data.unpacker_data.fuji_total_blocks = h_blocks_in_row; libraw_internal_data.unpacker_data.fuji_block_width = h_block_size; libraw_internal_data.unpacker_data.fuji_bits = h_raw_bits; imgdata.sizes.raw_width = h_raw_width; imgdata.sizes.raw_height = h_raw_height; libraw_internal_data.unpacker_data.data_offset += 16; load_raw = &LibRaw::xtrans_compressed_load_raw; } #undef _abs #undef _min LibRaw-0.18.8/version.sh000077500000000000000000000007241324423227700150250ustar00rootroot00000000000000#!/bin/sh vfile=./libraw/libraw_version.h major=`grep LIBRAW_MAJOR_VERSION $vfile |head -1 | awk '{print $3}'` minor=`grep LIBRAW_MINOR_VERSION $vfile | head -1 | awk '{print $3}'` patch=`grep LIBRAW_PATCH_VERSION $vfile | head -1 | awk '{print $3}'` tail=`grep LIBRAW_VERSION_TAIL $vfile | head -1 | awk '{print $3}'` if [ x$tail = xRelease ] ; then echo "$major.$minor.$patch" | awk '{printf $1}' else echo "$major.$minor.$patch-$tail" | awk '{printf $1}' fi LibRaw-0.18.8/win32pre.cmd000066400000000000000000000001201324423227700151250ustar00rootroot00000000000000 cd .. nmake -f Makefile-preprocess.msvc touch internal/dcraw_common_fake.cpp