diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
new file mode 100644
index 000000000..bab7397a6
--- /dev/null
+++ b/.github/workflows/main.yml
@@ -0,0 +1,69 @@
+name: macOS build
+
+on:
+ push
+
+jobs:
+ build:
+
+ runs-on: macos-latest
+
+ steps:
+ - uses: actions/checkout@v1
+ - name: Install dependencies
+ run: brew install gtk+3 gtkmm3 gtk-mac-integration adwaita-icon-theme libsigc++ little-cms2 libiptcdata fftw lensfun llvm expat pkgconfig libomp shared-mime-info
+ - name: patch libiconv
+ run: |
+ mkdir libiconv && cd libiconv
+ wget https://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.16.tar.gz
+ tar xf libiconv-1.16.tar.gz
+ cd libiconv-1.16
+ patch -p1 < "${GITHUB_WORKSPACE}/tools/osx/libiconv_1.16_rt.patch"
+ mkdir build && cd build
+ destDir="$(pwd)"
+ ../configure --prefix=/opt/local --disable-static 'CFLAGS=-arch x86_64 -mmacosx-version-min=10.9' 'LDFLAGS=-arch x86_64 -mmacosx-version-min=10.9' CXXFLAGS="-arch x86_64 -mmacosx-version-min=10.9"
+ make --jobs
+ make DESTDIR="${destDir}" install
+ sudo mv opt/local /usr/local/opt/libiconv
+ - name: cmake
+ env:
+ CMAKE_CXX_STANDARD: 11
+ PKG_CONFIG_PATH: /usr/local/opt/libffi/lib/pkgconfig:/usr/local/opt/expat/lib/pkgconfig
+ RAW_THERAPEE_MAJOR: '5'
+ RAW_THERAPEE_MINOR: '7'
+ C_FLAGS: -Xpreprocessor -fopenmp /usr/local/lib/libomp.dylib -I/usr/local/include -I/usr/local/opt/gdk-pixbuf/include -I/usr/local/opt/libiconv/include -I/usr/local/opt/libxml2/include -I/usr/local/opt/expat/include -I/usr/local/opt/llvm/include
+ run: |
+ # GITHUB_REF is the ref that triggered the build, like refs/heads/new-feature - the next line parses that to REF: the branch name only (new-feature)
+ REF=${GITHUB_REF##*/}
+ mkdir build && cd build
+ cmake \
+ -DCMAKE_BUILD_TYPE="release" \
+ -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \
+ -DCMAKE_EXE_LINKER_FLAGS="-L/usr/local/lib -L/usr/local/opt/llvm/lib -Wl,-rpath,/usr/local/opt/llvm/lib -L/usr/local/opt/gdk-pixbuf/lib -L/usr/local/opt/libiconv/lib -L/usr/local/opt/libffi/lib -L/usr/local/opt/libffi/lib -L/usr/local/opt/libxml2/lib -L/usr/local/opt/expat/lib" \
+ -DCACHE_NAME_SUFFIX="${RAW_THERAPEE_MAJOR}.${RAW_THERAPEE_MINOR}-${REF}" \
+ -DPROC_TARGET_NUMBER="2" \
+ -DPROC_LABEL="generic processor" \
+ -DWITH_LTO="OFF" \
+ -DLENSFUNDBDIR="./share/lensfun" \
+ -DOpenMP_C_FLAGS=-fopenmp=libomp \
+ -DOpenMP_CXX_FLAGS=-fopenmp=libomp \
+ -DOpenMP_C_LIB_NAMES="libomp" \
+ -DOpenMP_CXX_LIB_NAMES="libomp" \
+ -DOpenMP_libomp_LIBRARY="/usr/local/lib/libomp.dylib" \
+ -DOpenMP_C_FLAGS="${C_FLAGS}" \
+ -DOpenMP_CXX_FLAGS="${C_FLAGS}" \
+ -DCMAKE_AR="/usr/local/opt/llvm/bin/llvm-ar" \
+ -DCMAKE_RANLIB="/usr/local/opt/llvm/bin/llvm-ranlib" \
+ ..
+ make --jobs
+ make install
+ sudo make macosx_bundle
+ ARTIFACT=(RawTherapee*.zip)
+ echo "=== artifact: ${ARTIFACT}"
+ # defining environment variables for next step as per https://github.com/actions/starter-workflows/issues/68
+ echo "::set-env name=ARTIFACT_PATH::${GITHUB_WORKSPACE}/build/${ARTIFACT}"
+ echo "::set-env name=ARTIFACT_FILE::${ARTIFACT}"
+ - uses: actions/upload-artifact@v1
+ with:
+ name: ${{env.ARTIFACT_FILE}}
+ path: ${{env.ARTIFACT_PATH}}
diff --git a/rtdata/images/svg/questionmark.svg b/rtdata/images/svg/questionmark.svg
new file mode 100644
index 000000000..4c4b59590
--- /dev/null
+++ b/rtdata/images/svg/questionmark.svg
@@ -0,0 +1,122 @@
+
+
+
+
diff --git a/rtdata/languages/Catala b/rtdata/languages/Catala
index 36666a533..31614c7b3 100644
--- a/rtdata/languages/Catala
+++ b/rtdata/languages/Catala
@@ -977,6 +977,7 @@ ZOOMPANEL_ZOOMOUT;Allunya\nDrecera: -
!GENERAL_AUTO;Automatic
!GENERAL_CLOSE;Close
!GENERAL_CURRENT;Current
+!GENERAL_HELP;Help
!GENERAL_OPEN;Open
!GENERAL_RESET;Reset
!GENERAL_SAVE_AS;Save as...
diff --git a/rtdata/languages/Chinese (Simplified) b/rtdata/languages/Chinese (Simplified)
index 89a4dd9b4..5be2958e8 100644
--- a/rtdata/languages/Chinese (Simplified)
+++ b/rtdata/languages/Chinese (Simplified)
@@ -973,6 +973,7 @@ ZOOMPANEL_ZOOMOUT;缩放拉远\n快捷键: -
!FILEBROWSER_SHOWUNCOLORHINT;Show images without a color label.\nShortcut: Alt-0
!FILEBROWSER_UNRANK_TOOLTIP;Unrank.\nShortcut: Shift-0
!GENERAL_CURRENT;Current
+!GENERAL_HELP;Help
!GENERAL_RESET;Reset
!GENERAL_SAVE_AS;Save as...
!GENERAL_SLIDER;Slider
diff --git a/rtdata/languages/Czech b/rtdata/languages/Czech
index 0ce34e3ee..25bcf2820 100644
--- a/rtdata/languages/Czech
+++ b/rtdata/languages/Czech
@@ -2323,6 +2323,7 @@ ZOOMPANEL_ZOOMOUT;Oddálit\nZkratka: -
!FILEBROWSER_POPUPREMOVE;Delete permanently
!FILEBROWSER_POPUPREMOVEINCLPROC;Delete permanently, including queue-processed version
!FILEBROWSER_SHOWNOTTRASHHINT;Show only images not in trash.
+!GENERAL_HELP;Help
!HISTORY_MSG_494;Capture Sharpening
!HISTORY_MSG_DEHAZE_LUMINANCE;Dehaze - Luminance only
!HISTORY_MSG_FILMNEGATIVE_ENABLED;Film Negative
diff --git a/rtdata/languages/Deutsch b/rtdata/languages/Deutsch
index 9122d5984..592801054 100644
--- a/rtdata/languages/Deutsch
+++ b/rtdata/languages/Deutsch
@@ -2390,5 +2390,6 @@ ZOOMPANEL_ZOOMOUT;Herauszoomen\nTaste: -
! Untranslated keys follow; remove the ! prefix after an entry is translated.
!!!!!!!!!!!!!!!!!!!!!!!!!
+!GENERAL_HELP;Help
!HISTORY_MSG_PDSHARPEN_CHECKITER;CS - Auto limit iterations
!TP_SHARPENING_ITERCHECK;Auto limit iterations
diff --git a/rtdata/languages/English (UK) b/rtdata/languages/English (UK)
index 1fc07391e..e30425b68 100644
--- a/rtdata/languages/English (UK)
+++ b/rtdata/languages/English (UK)
@@ -340,6 +340,7 @@ TP_WBALANCE_EQBLUERED_TOOLTIP;Allows to deviate from the normal behaviour of "wh
!GENERAL_ENABLE;Enable
!GENERAL_ENABLED;Enabled
!GENERAL_FILE;File
+!GENERAL_HELP;Help
!GENERAL_LANDSCAPE;Landscape
!GENERAL_NA;n/a
!GENERAL_NO;No
diff --git a/rtdata/languages/English (US) b/rtdata/languages/English (US)
index 63dff83da..a1e0050a8 100644
--- a/rtdata/languages/English (US)
+++ b/rtdata/languages/English (US)
@@ -226,6 +226,7 @@
!GENERAL_ENABLE;Enable
!GENERAL_ENABLED;Enabled
!GENERAL_FILE;File
+!GENERAL_HELP;Help
!GENERAL_LANDSCAPE;Landscape
!GENERAL_NA;n/a
!GENERAL_NO;No
diff --git a/rtdata/languages/Espanol b/rtdata/languages/Espanol
index 96bce0cdf..ee8b0d17d 100644
--- a/rtdata/languages/Espanol
+++ b/rtdata/languages/Espanol
@@ -2321,6 +2321,7 @@ ZOOMPANEL_ZOOMOUT;Reducir Zoom\nTecla de Atajo: -
!FILEBROWSER_POPUPREMOVE;Delete permanently
!FILEBROWSER_POPUPREMOVEINCLPROC;Delete permanently, including queue-processed version
!FILEBROWSER_SHOWNOTTRASHHINT;Show only images not in trash.
+!GENERAL_HELP;Help
!HISTORY_MSG_494;Capture Sharpening
!HISTORY_MSG_DEHAZE_LUMINANCE;Dehaze - Luminance only
!HISTORY_MSG_FILMNEGATIVE_ENABLED;Film Negative
diff --git a/rtdata/languages/Francais b/rtdata/languages/Francais
index 9d1c6a3f7..9ecf43733 100644
--- a/rtdata/languages/Francais
+++ b/rtdata/languages/Francais
@@ -2266,6 +2266,7 @@ ZOOMPANEL_ZOOMOUT;Zoom Arrière\nRaccourci: -
!FILEBROWSER_POPUPREMOVE;Delete permanently
!FILEBROWSER_POPUPREMOVEINCLPROC;Delete permanently, including queue-processed version
!FILEBROWSER_SHOWNOTTRASHHINT;Show only images not in trash.
+!GENERAL_HELP;Help
!HISTORY_MSG_494;Capture Sharpening
!HISTORY_MSG_DEHAZE_LUMINANCE;Dehaze - Luminance only
!HISTORY_MSG_FILMNEGATIVE_ENABLED;Film Negative
diff --git a/rtdata/languages/Italiano b/rtdata/languages/Italiano
index db09b5d3a..0fd256d7c 100644
--- a/rtdata/languages/Italiano
+++ b/rtdata/languages/Italiano
@@ -1285,6 +1285,7 @@ ZOOMPANEL_ZOOMOUT;Rimpicciolisci.\nScorciatoia: -
!GENERAL_APPLY;Apply
!GENERAL_ASIMAGE;As Image
!GENERAL_CURRENT;Current
+!GENERAL_HELP;Help
!GENERAL_OPEN;Open
!GENERAL_RESET;Reset
!GENERAL_SAVE_AS;Save as...
diff --git a/rtdata/languages/Japanese b/rtdata/languages/Japanese
index 91ef2e931..588a817f2 100644
--- a/rtdata/languages/Japanese
+++ b/rtdata/languages/Japanese
@@ -8,30 +8,6 @@
#08 2012-12-22 a3novy
#09 2013-04-01 a3novy
#10 2013-04-19 a3novy
-#11 2013-09-10 firefly
-#12 2013-10-28 firefly
-#13 2014-01-07 firefly
-#14 2014-01-15 firefly
-#15 2014-02-25 firefly
-#16 2014-04-07 firefly
-#17 2014-04-08 firefly
-#18 2014-05-16 firefly
-#19 2014-07-13 firefly
-#20 2014-07-24 firefly
-#21 2014-09-11 firefly
-#22 2014-10-21 firefly
-#23 2014-11-07 firefly
-#24 2014-11-18 firefly
-#25 2015-01-05 firefly
-#26 2015-02-17 firefly
-#27 2015-02-21 firefly
-#28 2015-03-03 firefly
-#29 2015-04-20 firefly
-#30 2015-05-01 firefly
-#31 2015-05-31 firefly
-#32 2015-06-13 firefly
-#33 2015-07-20 firefly
-#34 2015-08-12 firefly
ABOUT_TAB_BUILD;バージョン
ABOUT_TAB_CREDITS;クレジット
@@ -49,7 +25,7 @@ CURVEEDITOR_CURVE;カーブ
CURVEEDITOR_CURVES;カーブ
CURVEEDITOR_CUSTOM;カスタム
CURVEEDITOR_DARKS;ダーク
-CURVEEDITOR_EDITPOINT_HINT;ボタンを押すと数値で入出力を編集出来ます\n\n編集したいカーブ上のポイントを右クリックします\n編集を無効にする場合はポイント以外の部分んで右クリックします
+CURVEEDITOR_EDITPOINT_HINT;ボタンを押すと数値で入出力を編集出来ます\n\n編集したいカーブ上のポイントを右クリックします\n編集を無効にする場合はポイント以外の部分で右クリックします
CURVEEDITOR_HIGHLIGHTS;ハイライト
CURVEEDITOR_LIGHTS;ライト
CURVEEDITOR_LINEAR;リニア
@@ -489,8 +465,8 @@ HISTORY_MSG_205;CAM02 ホット/バッドピクセル
HISTORY_MSG_206;CAT02 - 自動で順応
HISTORY_MSG_207;フリンジ低減 - 色相カーブ
HISTORY_MSG_208;ブルー/レッド イコライザ
-HISTORY_MSG_210;グラデーションフィルター - 角度
-HISTORY_MSG_211;グラデーションフィルター
+HISTORY_MSG_210;減光フィルター - 角度
+HISTORY_MSG_211;減光フィルター
HISTORY_MSG_212;ビネットフィルター - 強さ
HISTORY_MSG_213;ビネットフィルター
HISTORY_MSG_214;白黒
@@ -517,10 +493,10 @@ HISTORY_MSG_234;白黒 ‘後の‘カーブのタイプ
HISTORY_MSG_235;白黒 チャンネルミキサー 自動
HISTORY_MSG_236;--未使用--
HISTORY_MSG_237;白黒 チャンネルミキサー
-HISTORY_MSG_238;グラデーションフィルター フェザー処理
-HISTORY_MSG_239;グラデーションフィルター 強さ
-HISTORY_MSG_240;グラデーションフィルター 中央
-HISTORY_MSG_241;ビネットフィルター フェザー処理
+HISTORY_MSG_238;減光フィルター フェザー
+HISTORY_MSG_239;減光フィルター 強さ
+HISTORY_MSG_240;減光フィルター 中央
+HISTORY_MSG_241;ビネットフィルター フェザー
HISTORY_MSG_242;ビネットフィルター 形状
HISTORY_MSG_243;半径
HISTORY_MSG_244;ビネットフィルター 強さ
@@ -757,6 +733,7 @@ HISTORY_MSG_490;DRC - 量
HISTORY_MSG_491;ホワイトバランス
HISTORY_MSG_492;RGBカーブ
HISTORY_MSG_493;L*a*b*調整
+HISTORY_MSG_494;キャプチャーシャープニング
HISTORY_MSG_CLAMPOOG;色域外の色を切り取る
HISTORY_MSG_COLORTONING_LABGRID_VALUE;CT - カラー補正
HISTORY_MSG_COLORTONING_LABREGION_AB;CT - 色の補正
@@ -774,6 +751,7 @@ HISTORY_MSG_COLORTONING_LABREGION_SHOWMASK;CT - マスクの表示
HISTORY_MSG_COLORTONING_LABREGION_SLOPE;CT - スロープ
HISTORY_MSG_DEHAZE_DEPTH;霞除去 - 深度
HISTORY_MSG_DEHAZE_ENABLED;霞除去
+HISTORY_MSG_DEHAZE_LUMINANCE;霞除去 - 輝度のみ
HISTORY_MSG_DEHAZE_SHOW_DEPTH_MAP;霞除去 - 深度マップの表示
HISTORY_MSG_DEHAZE_STRENGTH;霞除去 - 強さ
HISTORY_MSG_DUALDEMOSAIC_AUTO_CONTRAST;デュアルデモザイク - 自動しきい値
@@ -794,6 +772,13 @@ HISTORY_MSG_LOCALCONTRAST_LIGHTNESS;ローカルコントラスト - 明るい
HISTORY_MSG_LOCALCONTRAST_RADIUS;ローカルコントラスト - 半径
HISTORY_MSG_METADATA_MODE;メタデータ コピーモード
HISTORY_MSG_MICROCONTRAST_CONTRAST;マイクロコントラスト - コントラストのしきい値
+HISTORY_MSG_PDSHARPEN_AUTO_CONTRAST;CS - しきい値の自動設定
+HISTORY_MSG_PDSHARPEN_AUTO_RADIUS;CS - シグマの自動設定
+HISTORY_MSG_PDSHARPEN_CHECKITER;CS - 繰り返しの自動制限
+HISTORY_MSG_PDSHARPEN_CONTRAST;CS - コントラストのしきい値
+HISTORY_MSG_PDSHARPEN_ITERATIONS;CS - 繰り返し
+HISTORY_MSG_PDSHARPEN_RADIUS;CS - シグマ
+HISTORY_MSG_PDSHARPEN_RADIUS_BOOST;CS - 周辺のシグマを増やす
HISTORY_MSG_PIXELSHIFT_DEMOSAIC;PS - 振れに対するデモザイクの方式
HISTORY_MSG_PREPROCESS_LINEDENOISE_DIRECTION;ラインノイズフィルタの方向
HISTORY_MSG_PREPROCESS_PDAFLINESFILTER;PDAFラインフィルタ
@@ -960,8 +945,8 @@ MAIN_TOOLTIP_BACKCOLOR2;プレビューの背景色を指定します: 白中間のグレー\nショートカット: 9
MAIN_TOOLTIP_BEFOREAFTERLOCK;固定 / 固定解除 - 補正前 の表示設定\n\n固定: 補正前をそのまま表示し変更されません\n複数のツールの累積効果を評価するのに役立ちます\nさらに、比較は履歴上のどこからでも行うことができます\n\n固定解除: 現在使用のツールの効果が 補正後 に表示され、その1段階前が 補正前 に表示されます
MAIN_TOOLTIP_HIDEHP;左パネル 表示/非表示 (履歴含む)\nショートカット: l
-MAIN_TOOLTIP_INDCLIPPEDH;ハイライト・クリッピング領域の表示\nショートカット: >
-MAIN_TOOLTIP_INDCLIPPEDS;シャドウ・クリッピング領域の表示\nショートカット: <
+MAIN_TOOLTIP_INDCLIPPEDH;ハイライト・クリッピング領域の表示\nショートカット: <
+MAIN_TOOLTIP_INDCLIPPEDS;シャドウ・クリッピング領域の表示\nショートカット: >
MAIN_TOOLTIP_PREVIEWB;ブルー チャンネル表示\nショートカット: b
MAIN_TOOLTIP_PREVIEWFOCUSMASK;フォーカス・マスク表示\nショートカット: Shift-f\n\n浅い被写界深度、低ノイズ、高ズームの画像の場合は、より正確に\n\nノイズの多い画像に対しては、検出精度を向上させるため10から30%縮小して評価します\n\nフォーカス・マスクをオンにすると表示に時間が掛かります
MAIN_TOOLTIP_PREVIEWG;グリーン チャンネル表示\nショートカット: g
@@ -1023,7 +1008,7 @@ PARTIALPASTE_FLATFIELDBLURRADIUS;フラットフィールド ぼかし半径
PARTIALPASTE_FLATFIELDBLURTYPE;フラットフィールド ぼかしタイプ
PARTIALPASTE_FLATFIELDCLIPCONTROL;フラットフィールド クリップコントロール
PARTIALPASTE_FLATFIELDFILE;フラットフィールド ファイル
-PARTIALPASTE_GRADIENT;グラデーションフィルター
+PARTIALPASTE_GRADIENT;減光フィルター
PARTIALPASTE_HSVEQUALIZER;HSV イコライザ
PARTIALPASTE_ICMSETTINGS;ICM 設定
PARTIALPASTE_IMPULSEDENOISE;インパルス・ノイズ低減
@@ -1562,6 +1547,7 @@ TP_DEFRINGE_RADIUS;半径
TP_DEFRINGE_THRESHOLD;しきい値
TP_DEHAZE_DEPTH;深度
TP_DEHAZE_LABEL;霞除去
+TP_DEHAZE_LUMINANCE;輝度のみ
TP_DEHAZE_SHOW_DEPTH_MAP;深度マップの表示
TP_DEHAZE_STRENGTH;強さ
TP_DIRPYRDENOISE_CHROMINANCE_AMZ;自動(多分割方式)
@@ -1672,9 +1658,9 @@ TP_EXPOS_BLACKPOINT_LABEL;raw ブラック・ポイント
TP_EXPOS_WHITEPOINT_LABEL;raw ホワイト・ポイント
TP_FILMNEGATIVE_BLUE;ブルーの比率
TP_FILMNEGATIVE_GREEN;参考指数(コントラスト)
-TP_FILMNEGATIVE_GUESS_TOOLTIP;Automatically set the red and blue ratios by picking two patches which had a neutral hue (no color) in the original scene. The patches should differ in brightness. Set the white balance afterwards.
+TP_FILMNEGATIVE_GUESS_TOOLTIP;原画像の中で色相がニュートラルな部分2か所をピックすることでレッドとブルーの比率を自動で設定します。明るさが異なる2か所をピックします。その後、ホワイトバランスを設定します。
TP_FILMNEGATIVE_LABEL;ネガフィルム
-TP_FILMNEGATIVE_PICK;Pick neutral spots
+TP_FILMNEGATIVE_PICK;ニュートラルなポイントをピック
TP_FILMNEGATIVE_RED;レッドの比率
TP_FILMSIMULATION_LABEL;フィルムシミュレーション
TP_FILMSIMULATION_SLOWPARSEDIR;RawTherapeeはフィルムシミュレーション機能に使う画像をHald CLUTフォルダーの中から探すよう設計されています(プログラムに組み込むにはフォルダーが大き過ぎるため)。\n変更するには、環境設定 > 画像処理 > フィルムシミュレーションと進み\nどのフォルダーが使われているか確認します。機能を利用する場合は、Hald CLUTだけが入っているフォルダーを指定するか、 この機能を使わない場合はそのフォルダーを空にしておきます。\n\n詳しくはRawPediaを参照して下さい。\n\nフィルム画像のスキャンを止めますか?
@@ -1698,9 +1684,9 @@ TP_GRADIENT_CENTER_Y;中央 Y軸
TP_GRADIENT_CENTER_Y_TOOLTIP;アンカーポイントの位置 y軸: -100=上端, 0=中央, +100=下端
TP_GRADIENT_DEGREE;角度
TP_GRADIENT_DEGREE_TOOLTIP;回転角度の度数
-TP_GRADIENT_FEATHER;フェザー処理
-TP_GRADIENT_FEATHER_TOOLTIP;対角線に対するグラデーションの幅の割合
-TP_GRADIENT_LABEL;グラデーションフィルター
+TP_GRADIENT_FEATHER;フェザー
+TP_GRADIENT_FEATHER_TOOLTIP;対角線に対する減光の幅の割合
+TP_GRADIENT_LABEL;減光フィルター
TP_GRADIENT_STRENGTH;強さ
TP_GRADIENT_STRENGTH_TOOLTIP;終点位置でのフィルターの強さ
TP_HLREC_BLEND;ブレンド
@@ -1817,13 +1803,14 @@ TP_METADATA_STRIP;メタデータを全て取り除く
TP_METADATA_TUNNEL;変更なしでコピー
TP_NEUTRAL;リセット
TP_NEUTRAL_TIP;露光量補正のスライダー値をニュートラルにリセットします。\n自動露光補正の調整値ついても同様にリセットされます
-TP_PCVIGNETTE_FEATHER;フェザー処理
-TP_PCVIGNETTE_FEATHER_TOOLTIP;フェザー処理: 0=四隅だけ、50=中央までの半分、100=中央まで
+TP_PCVIGNETTE_FEATHER;フェザー
+TP_PCVIGNETTE_FEATHER_TOOLTIP;フェザー: 0=四隅だけ、50=中央までの半分、100=中央まで
TP_PCVIGNETTE_LABEL;ビネットフィルター
TP_PCVIGNETTE_ROUNDNESS;フィルター形状
TP_PCVIGNETTE_ROUNDNESS_TOOLTIP;形状: 0=長方形、50=楕円形、100=円形
TP_PCVIGNETTE_STRENGTH;強さ
TP_PCVIGNETTE_STRENGTH_TOOLTIP;終点位置でのフィルターの強さ(四隅)
+TP_PDSHARPENING_LABEL;キャプチャーシャープニング
TP_PERSPECTIVE_HORIZONTAL;水平
TP_PERSPECTIVE_LABEL;パースペクティブ
TP_PERSPECTIVE_VERTICAL;垂直
@@ -2054,10 +2041,12 @@ TP_SHARPENING_EDRADIUS;半径
TP_SHARPENING_EDTOLERANCE;エッジ許容
TP_SHARPENING_HALOCONTROL;ハロ抑制
TP_SHARPENING_HCAMOUNT;適用量
+TP_SHARPENING_ITERCHECK;繰り返しの自動制限
TP_SHARPENING_LABEL;シャープニング
TP_SHARPENING_METHOD;方式
TP_SHARPENING_ONLYEDGES;エッジのみシャープニング
TP_SHARPENING_RADIUS;半径
+TP_SHARPENING_RADIUS_BOOST;周辺のシグマを増やす
TP_SHARPENING_RLD;RL デコンボリューション
TP_SHARPENING_RLD_AMOUNT;適用量
TP_SHARPENING_RLD_DAMPING;減衰
@@ -2311,6 +2300,7 @@ TP_WBALANCE_TUNGSTEN;タングステン
TP_WBALANCE_WATER1;水中 1
TP_WBALANCE_WATER2;水中 2
TP_WBALANCE_WATER_HEADER;水中
+The last update by firefly 2019-12-21
ZOOMPANEL_100;(100%)
ZOOMPANEL_NEWCROPWINDOW;新規ディテール ウィンドウを開く
ZOOMPANEL_ZOOM100;100%にズーム\nショートカット: z
@@ -2323,16 +2313,4 @@ ZOOMPANEL_ZOOMOUT;ズームアウト\nショートカット: -
! Untranslated keys follow; remove the ! prefix after an entry is translated.
!!!!!!!!!!!!!!!!!!!!!!!!!
-!HISTORY_MSG_494;Capture Sharpening
-!HISTORY_MSG_DEHAZE_LUMINANCE;Dehaze - Luminance only
-!HISTORY_MSG_PDSHARPEN_AUTO_CONTRAST;CS - Auto threshold
-!HISTORY_MSG_PDSHARPEN_AUTO_RADIUS;CS - Auto radius
-!HISTORY_MSG_PDSHARPEN_CHECKITER;CS - Auto limit iterations
-!HISTORY_MSG_PDSHARPEN_CONTRAST;CS - Contrast threshold
-!HISTORY_MSG_PDSHARPEN_ITERATIONS;CS - Iterations
-!HISTORY_MSG_PDSHARPEN_RADIUS;CS - Radius
-!HISTORY_MSG_PDSHARPEN_RADIUS_BOOST;CS - Corner radius boost
-!TP_DEHAZE_LUMINANCE;Luminance only
-!TP_PDSHARPENING_LABEL;Capture Sharpening
-!TP_SHARPENING_ITERCHECK;Auto limit iterations
-!TP_SHARPENING_RADIUS_BOOST;Corner radius boost
+!GENERAL_HELP;Help
diff --git a/rtdata/languages/Magyar b/rtdata/languages/Magyar
index 43a4ae1e1..4b6f2811b 100644
--- a/rtdata/languages/Magyar
+++ b/rtdata/languages/Magyar
@@ -908,6 +908,7 @@ ZOOMPANEL_ZOOMOUT;Kicsinyítés -
!GENERAL_AUTO;Automatic
!GENERAL_CLOSE;Close
!GENERAL_CURRENT;Current
+!GENERAL_HELP;Help
!GENERAL_OPEN;Open
!GENERAL_RESET;Reset
!GENERAL_SAVE_AS;Save as...
diff --git a/rtdata/languages/Nederlands b/rtdata/languages/Nederlands
index 07e40256f..c230323f5 100644
--- a/rtdata/languages/Nederlands
+++ b/rtdata/languages/Nederlands
@@ -1982,6 +1982,7 @@ ZOOMPANEL_ZOOMOUT;Zoom uit\nSneltoets: -
!FILEBROWSER_POPUPREMOVEINCLPROC;Delete permanently, including queue-processed version
!FILEBROWSER_SHOWNOTTRASHHINT;Show only images not in trash.
!GENERAL_CURRENT;Current
+!GENERAL_HELP;Help
!GENERAL_RESET;Reset
!GENERAL_SAVE_AS;Save as...
!GENERAL_SLIDER;Slider
diff --git a/rtdata/languages/Polish b/rtdata/languages/Polish
index c923c3bad..4e5d950fc 100644
--- a/rtdata/languages/Polish
+++ b/rtdata/languages/Polish
@@ -1407,6 +1407,7 @@ ZOOMPANEL_ZOOMOUT;Oddal\nSkrót: -
!GENERAL_APPLY;Apply
!GENERAL_ASIMAGE;As Image
!GENERAL_CURRENT;Current
+!GENERAL_HELP;Help
!GENERAL_OPEN;Open
!GENERAL_RESET;Reset
!GENERAL_SAVE_AS;Save as...
diff --git a/rtdata/languages/Portugues b/rtdata/languages/Portugues
index efe3214f8..789d26cd6 100644
--- a/rtdata/languages/Portugues
+++ b/rtdata/languages/Portugues
@@ -2264,6 +2264,7 @@ ZOOMPANEL_ZOOMOUT;Afastar\nAtalho: -
!FILEBROWSER_POPUPREMOVE;Delete permanently
!FILEBROWSER_POPUPREMOVEINCLPROC;Delete permanently, including queue-processed version
!FILEBROWSER_SHOWNOTTRASHHINT;Show only images not in trash.
+!GENERAL_HELP;Help
!HISTORY_MSG_494;Capture Sharpening
!HISTORY_MSG_DEHAZE_LUMINANCE;Dehaze - Luminance only
!HISTORY_MSG_FILMNEGATIVE_ENABLED;Film Negative
diff --git a/rtdata/languages/Portugues (Brasil) b/rtdata/languages/Portugues (Brasil)
index e6adf3bc4..d619356a9 100644
--- a/rtdata/languages/Portugues (Brasil)
+++ b/rtdata/languages/Portugues (Brasil)
@@ -2269,6 +2269,7 @@ ZOOMPANEL_ZOOMOUT;Menos Zoom\nAtalho: -
!!!!!!!!!!!!!!!!!!!!!!!!!
!FILEBROWSER_BROWSEPATHBUTTONHINT;Click to open specified path, reload folder and apply "find" keywords.
+!GENERAL_HELP;Help
!HISTORY_MSG_494;Capture Sharpening
!HISTORY_MSG_COLORTONING_LABREGION_OFFSET;CT - region offset
!HISTORY_MSG_COLORTONING_LABREGION_POWER;CT - region power
diff --git a/rtdata/languages/Russian b/rtdata/languages/Russian
index a4e501a77..4246ecbb6 100644
--- a/rtdata/languages/Russian
+++ b/rtdata/languages/Russian
@@ -1475,6 +1475,7 @@ ZOOMPANEL_ZOOMOUT;Отдалить\nГорячая клавиша: -
!FILEBROWSER_SHOWORIGINALHINT;Show only original images.\n\nWhen several images exist with the same filename but different extensions, the one considered original is the one whose extension is nearest the top of the parsed extensions list in Preferences > File Browser > Parsed Extensions.
!FILECHOOSER_FILTER_PP;Processing profiles
!FILECHOOSER_FILTER_SAME;Same format as current photo
+!GENERAL_HELP;Help
!GIMP_PLUGIN_INFO;Welcome to the RawTherapee GIMP plugin!\nOnce you are done editing, simply close the main RawTherapee window and the image will be automatically imported in GIMP.
!HISTOGRAM_TOOLTIP_MODE;Toggle between linear, log-linear and log-log scaling of the histogram.
!HISTORY_MSG_235;B&W - CM - Auto
diff --git a/rtdata/languages/Serbian (Cyrilic Characters) b/rtdata/languages/Serbian (Cyrilic Characters)
index 9ec7c998b..7fd0ca378 100644
--- a/rtdata/languages/Serbian (Cyrilic Characters)
+++ b/rtdata/languages/Serbian (Cyrilic Characters)
@@ -1257,6 +1257,7 @@ ZOOMPANEL_ZOOMOUT;Умањује приказ слике -
!GENERAL_APPLY;Apply
!GENERAL_ASIMAGE;As Image
!GENERAL_CURRENT;Current
+!GENERAL_HELP;Help
!GENERAL_OPEN;Open
!GENERAL_RESET;Reset
!GENERAL_SAVE_AS;Save as...
diff --git a/rtdata/languages/Slovenian b/rtdata/languages/Slovenian
index b015cb6f1..0afaa83e9 100644
--- a/rtdata/languages/Slovenian
+++ b/rtdata/languages/Slovenian
@@ -2306,5 +2306,6 @@ ZOOMPANEL_ZOOMOUT;Zoom Out\nBližnjica: -
! Untranslated keys follow; remove the ! prefix after an entry is translated.
!!!!!!!!!!!!!!!!!!!!!!!!!
+!GENERAL_HELP;Help
!HISTORY_MSG_PDSHARPEN_CHECKITER;CS - Auto limit iterations
!TP_SHARPENING_ITERCHECK;Auto limit iterations
diff --git a/rtdata/languages/Swedish b/rtdata/languages/Swedish
index 7861f2276..6dbea54d8 100644
--- a/rtdata/languages/Swedish
+++ b/rtdata/languages/Swedish
@@ -1772,6 +1772,7 @@ ZOOMPANEL_ZOOMOUT;Förminska.\nKortkommando: -
!FILEBROWSER_RESETDEFAULTPROFILE;Reset to default
!FILEBROWSER_SHOWNOTTRASHHINT;Show only images not in trash.
!GENERAL_CURRENT;Current
+!GENERAL_HELP;Help
!GENERAL_RESET;Reset
!GENERAL_SAVE_AS;Save as...
!GENERAL_SLIDER;Slider
diff --git a/rtdata/languages/default b/rtdata/languages/default
index 62a421fe1..1bbb70816 100644
--- a/rtdata/languages/default
+++ b/rtdata/languages/default
@@ -225,6 +225,7 @@ GENERAL_DISABLED;Disabled
GENERAL_ENABLE;Enable
GENERAL_ENABLED;Enabled
GENERAL_FILE;File
+GENERAL_HELP;Help
GENERAL_LANDSCAPE;Landscape
GENERAL_NA;n/a
GENERAL_NO;No
diff --git a/rtdata/mime-types b/rtdata/mime-types
index 505b00140..bfd1ccbd9 100644
--- a/rtdata/mime-types
+++ b/rtdata/mime-types
@@ -6,6 +6,7 @@ image/png;
image/tiff;
image/x-adobe-dng;
image/x-canon-cr2;
+image/x-canon-cr3;
image/x-canon-crf;
image/x-canon-crw;
image/x-fuji-raf;
diff --git a/rtdata/rawtherapee.desktop.in b/rtdata/rawtherapee.desktop.in
index f6bc3afeb..350afc45e 100644
--- a/rtdata/rawtherapee.desktop.in
+++ b/rtdata/rawtherapee.desktop.in
@@ -14,7 +14,7 @@ Icon=rawtherapee
TryExec=rawtherapee
Exec=rawtherapee %f
Terminal=false
-MimeType=image/jpeg;image/png;image/tiff;image/x-adobe-dng;image/x-canon-cr2;image/x-canon-crf;image/x-canon-crw;image/x-fuji-raf;image/x-hasselblad-3fr;image/x-hasselblad-fff;image/x-jpg;image/x-kodak-dcr;image/x-kodak-k25;image/x-kodak-kdc;image/x-leaf-mos;image/x-leica-rwl;image/x-mamiya-mef;image/x-minolta-mrw;image/x-nikon-nef;image/x-nikon-nrw;image/x-olympus-orf;image/x-panasonic-raw;image/x-panasonic-rw2;image/x-pentax-pef;image/x-pentax-raw;image/x-phaseone-iiq;image/x-raw;image/x-rwz;image/x-samsung-srw;image/x-sigma-x3f;image/x-sony-arq;image/x-sony-arw;image/x-sony-sr2;image/x-sony-srf;image/x-tif;
+MimeType=image/jpeg;image/png;image/tiff;image/x-adobe-dng;image/x-canon-cr2;image/x-canon-cr3;image/x-canon-crf;image/x-canon-crw;image/x-fuji-raf;image/x-hasselblad-3fr;image/x-hasselblad-fff;image/x-jpg;image/x-kodak-dcr;image/x-kodak-k25;image/x-kodak-kdc;image/x-leaf-mos;image/x-leica-rwl;image/x-mamiya-mef;image/x-minolta-mrw;image/x-nikon-nef;image/x-nikon-nrw;image/x-olympus-orf;image/x-panasonic-raw;image/x-panasonic-rw2;image/x-pentax-pef;image/x-pentax-raw;image/x-phaseone-iiq;image/x-raw;image/x-rwz;image/x-samsung-srw;image/x-sigma-x3f;image/x-sony-arq;image/x-sony-arw;image/x-sony-sr2;image/x-sony-srf;image/x-tif;inode/directory;
Categories=Graphics;Photography;2DGraphics;RasterGraphics;GTK;
Keywords=raw;photo;photography;develop;pp3;graphics;
StartupNotify=true
diff --git a/rtengine/CA_correct_RT.cc b/rtengine/CA_correct_RT.cc
index 4dc2019c1..f4d082199 100644
--- a/rtengine/CA_correct_RT.cc
+++ b/rtengine/CA_correct_RT.cc
@@ -1258,12 +1258,12 @@ float* RawImageSource::CA_correct_RT(
int indx = (row * width + col) >> 1;
#ifdef __SSE2__
for (; col < width - 7 - cb; col += 8, indx += 4) {
- vfloat val = LVFU(RawDataTmp[indx]);
+ const vfloat val = vmaxf(LVFU(RawDataTmp[indx]), ZEROV);
STC2VFU(rawData[row][col], val);
}
#endif
for (; col < width - cb; col += 2, indx++) {
- rawData[row][col] = RawDataTmp[indx];
+ rawData[row][col] = std::max(0.f, RawDataTmp[indx]);
}
}
diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt
index f58afde5e..6bce68d1a 100644
--- a/rtengine/CMakeLists.txt
+++ b/rtengine/CMakeLists.txt
@@ -103,6 +103,7 @@ set(RTENGINESOURCEFILES
labimage.cc
lcp.cc
lj92.c
+ lmmse_demosaic.cc
loadinitial.cc
myfile.cc
panasonic_decoders.cc
diff --git a/rtengine/amaze_demosaic_RT.cc b/rtengine/amaze_demosaic_RT.cc
index 24c463458..2041f3130 100644
--- a/rtengine/amaze_demosaic_RT.cc
+++ b/rtengine/amaze_demosaic_RT.cc
@@ -1470,48 +1470,48 @@ void RawImageSource::amaze_demosaic_RT(int winx, int winy, int winw, int winh, c
vfloat bluev1 = greenv - (temp00v * vdup(LVFU(Dgrb[1][(indx - v1) >> 1])) + (onev - vdup(LVFU(hvwt[(indx + 1 + offset) >> 1]))) * vdup(LVFU(Dgrb[1][(indx + 1 + offset) >> 1])) + (onev - vdup(LVFU(hvwt[(indx - 1 + offset) >> 1]))) * vdup(LVFU(Dgrb[1][(indx - 1 + offset) >> 1])) + temp01v * vdup(LVFU(Dgrb[1][(indx + v1) >> 1]))) * tempv;
vfloat redv2 = greenv - vdup(LVFU(Dgrb[0][indx >> 1]));
vfloat bluev2 = greenv - vdup(LVFU(Dgrb[1][indx >> 1]));
- STVFU(red[row][col], c65535v * vself(selmask, redv1, redv2));
- STVFU(blue[row][col], c65535v * vself(selmask, bluev1, bluev2));
+ STVFU(red[row][col], vmaxf(c65535v * vself(selmask, redv1, redv2), ZEROV));
+ STVFU(blue[row][col], vmaxf(c65535v * vself(selmask, bluev1, bluev2), ZEROV));
}
if(offset == 0) {
for (; indx < rr * ts + cc1 - 16 - (cc1 & 1); indx++, col++) {
float temp = 1.f / (hvwt[(indx - v1) >> 1] + 2.f - hvwt[(indx + 1) >> 1] - hvwt[(indx - 1) >> 1] + hvwt[(indx + v1) >> 1]);
- red[row][col] = 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[0][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[0][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[0][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[0][(indx + v1) >> 1]) *
- temp);
- blue[row][col] = 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[1][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[1][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[1][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[1][(indx + v1) >> 1]) *
- temp);
+ red[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[0][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[0][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[0][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[0][(indx + v1) >> 1]) *
+ temp));
+ blue[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[1][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[1][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[1][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[1][(indx + v1) >> 1]) *
+ temp));
indx++;
col++;
- red[row][col] = 65535.f * (rgbgreen[indx] - Dgrb[0][indx >> 1]);
- blue[row][col] = 65535.f * (rgbgreen[indx] - Dgrb[1][indx >> 1]);
+ red[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - Dgrb[0][indx >> 1]));
+ blue[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - Dgrb[1][indx >> 1]));
}
if(cc1 & 1) { // width of tile is odd
float temp = 1.f / (hvwt[(indx - v1) >> 1] + 2.f - hvwt[(indx + 1) >> 1] - hvwt[(indx - 1) >> 1] + hvwt[(indx + v1) >> 1]);
- red[row][col] = 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[0][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[0][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[0][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[0][(indx + v1) >> 1]) *
- temp);
- blue[row][col] = 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[1][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[1][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[1][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[1][(indx + v1) >> 1]) *
- temp);
+ red[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[0][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[0][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[0][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[0][(indx + v1) >> 1]) *
+ temp));
+ blue[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[1][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[1][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[1][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[1][(indx + v1) >> 1]) *
+ temp));
}
} else {
for (; indx < rr * ts + cc1 - 16 - (cc1 & 1); indx++, col++) {
- red[row][col] = 65535.f * (rgbgreen[indx] - Dgrb[0][indx >> 1]);
- blue[row][col] = 65535.f * (rgbgreen[indx] - Dgrb[1][indx >> 1]);
+ red[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - Dgrb[0][indx >> 1]));
+ blue[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - Dgrb[1][indx >> 1]));
indx++;
col++;
float temp = 1.f / (hvwt[(indx - v1) >> 1] + 2.f - hvwt[(indx + 1) >> 1] - hvwt[(indx - 1) >> 1] + hvwt[(indx + v1) >> 1]);
- red[row][col] = 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[0][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[0][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[0][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[0][(indx + v1) >> 1]) *
- temp);
- blue[row][col] = 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[1][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[1][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[1][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[1][(indx + v1) >> 1]) *
- temp);
+ red[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[0][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[0][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[0][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[0][(indx + v1) >> 1]) *
+ temp));
+ blue[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[1][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[1][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[1][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[1][(indx + v1) >> 1]) *
+ temp));
}
if(cc1 & 1) { // width of tile is odd
- red[row][col] = 65535.f * (rgbgreen[indx] - Dgrb[0][indx >> 1]);
- blue[row][col] = 65535.f * (rgbgreen[indx] - Dgrb[1][indx >> 1]);
+ red[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - Dgrb[0][indx >> 1]));
+ blue[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - Dgrb[1][indx >> 1]));
}
}
@@ -1520,41 +1520,41 @@ void RawImageSource::amaze_demosaic_RT(int winx, int winy, int winw, int winh, c
if((fc(cfarray, rr, 2) & 1) == 1) {
for (; indx < rr * ts + cc1 - 16 - (cc1 & 1); indx++, col++) {
float temp = 1.f / (hvwt[(indx - v1) >> 1] + 2.f - hvwt[(indx + 1) >> 1] - hvwt[(indx - 1) >> 1] + hvwt[(indx + v1) >> 1]);
- red[row][col] = 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[0][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[0][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[0][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[0][(indx + v1) >> 1]) *
- temp);
- blue[row][col] = 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[1][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[1][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[1][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[1][(indx + v1) >> 1]) *
- temp);
+ red[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[0][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[0][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[0][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[0][(indx + v1) >> 1]) *
+ temp));
+ blue[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[1][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[1][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[1][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[1][(indx + v1) >> 1]) *
+ temp));
indx++;
col++;
- red[row][col] = 65535.f * (rgbgreen[indx] - Dgrb[0][indx >> 1]);
- blue[row][col] = 65535.f * (rgbgreen[indx] - Dgrb[1][indx >> 1]);
+ red[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - Dgrb[0][indx >> 1]));
+ blue[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - Dgrb[1][indx >> 1]));
}
if(cc1 & 1) { // width of tile is odd
float temp = 1.f / (hvwt[(indx - v1) >> 1] + 2.f - hvwt[(indx + 1) >> 1] - hvwt[(indx - 1) >> 1] + hvwt[(indx + v1) >> 1]);
- red[row][col] = 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[0][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[0][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[0][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[0][(indx + v1) >> 1]) *
- temp);
- blue[row][col] = 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[1][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[1][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[1][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[1][(indx + v1) >> 1]) *
- temp);
+ red[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[0][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[0][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[0][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[0][(indx + v1) >> 1]) *
+ temp));
+ blue[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[1][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[1][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[1][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[1][(indx + v1) >> 1]) *
+ temp));
}
} else {
for (; indx < rr * ts + cc1 - 16 - (cc1 & 1); indx++, col++) {
- red[row][col] = 65535.f * (rgbgreen[indx] - Dgrb[0][indx >> 1]);
- blue[row][col] = 65535.f * (rgbgreen[indx] - Dgrb[1][indx >> 1]);
+ red[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - Dgrb[0][indx >> 1]));
+ blue[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - Dgrb[1][indx >> 1]));
indx++;
col++;
float temp = 1.f / (hvwt[(indx - v1) >> 1] + 2.f - hvwt[(indx + 1) >> 1] - hvwt[(indx - 1) >> 1] + hvwt[(indx + v1) >> 1]);
- red[row][col] = 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[0][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[0][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[0][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[0][(indx + v1) >> 1]) *
- temp);
- blue[row][col] = 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[1][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[1][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[1][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[1][(indx + v1) >> 1]) *
- temp);
+ red[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[0][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[0][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[0][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[0][(indx + v1) >> 1]) *
+ temp));
+ blue[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - ((hvwt[(indx - v1) >> 1]) * Dgrb[1][(indx - v1) >> 1] + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[1][(indx + 1) >> 1] + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[1][(indx - 1) >> 1] + (hvwt[(indx + v1) >> 1]) * Dgrb[1][(indx + v1) >> 1]) *
+ temp));
}
if(cc1 & 1) { // width of tile is odd
- red[row][col] = 65535.f * (rgbgreen[indx] - Dgrb[0][indx >> 1]);
- blue[row][col] = 65535.f * (rgbgreen[indx] - Dgrb[1][indx >> 1]);
+ red[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - Dgrb[0][indx >> 1]));
+ blue[row][col] = std::max(0.f, 65535.f * (rgbgreen[indx] - Dgrb[1][indx >> 1]));
}
}
@@ -1568,13 +1568,13 @@ void RawImageSource::amaze_demosaic_RT(int winx, int winy, int winw, int winh, c
#ifdef __SSE2__
for (; cc < cc1 - 19; cc += 4) {
- STVFU(green[row][cc + left], LVF(rgbgreen[rr * ts + cc]) * c65535v);
+ STVFU(green[row][cc + left], vmaxf(LVF(rgbgreen[rr * ts + cc]) * c65535v, ZEROV));
}
#endif
for (; cc < cc1 - 16; cc++) {
- green[row][cc + left] = 65535.f * rgbgreen[rr * ts + cc];
+ green[row][cc + left] = std::max(0.f, 65535.f * rgbgreen[rr * ts + cc]);
}
}
diff --git a/rtengine/cJSON.h b/rtengine/cJSON.h
index 786dd2e0e..49fd67b72 100644
--- a/rtengine/cJSON.h
+++ b/rtengine/cJSON.h
@@ -195,7 +195,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
/* Create a string where valuestring references a string so
* it will not be freed by cJSON_Delete */
CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
-/* Create an object/arrray that only references it's elements so
+/* Create an object/array that only references it's elements so
* they will not be freed by cJSON_Delete */
CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
diff --git a/rtengine/camconst.cc b/rtengine/camconst.cc
index e8f7b1cbf..d136d6a21 100644
--- a/rtengine/camconst.cc
+++ b/rtengine/camconst.cc
@@ -253,7 +253,7 @@ CameraConst::parseEntry(void *cJSON_, const char *make_model)
}
if (i % 4 != 0) {
- fprintf(stderr, "\"masked_areas\" array length must be divisable by 4\n");
+ fprintf(stderr, "\"masked_areas\" array length must be divisible by 4\n");
goto parse_error;
}
}
diff --git a/rtengine/camconst.json b/rtengine/camconst.json
index 8639ea2e1..ab42f3d19 100644
--- a/rtengine/camconst.json
+++ b/rtengine/camconst.json
@@ -1323,6 +1323,11 @@ Camera constants:
"ranges": { "white": 16100 }
},
+ { // Quality C, bisected from the overexposed region of one pre-release sample file
+ "make_model": "FUJIFILM X-A7",
+ "ranges": { "white": 16382 }
+ },
+
{ // Quality B
"make_model": "FUJIFILM X-A10",
"dcraw_matrix": [ 11540,-4999,-991,-2949,10963,2278,-382,1049,5605 ], // DNGv9.12 D65
@@ -1398,6 +1403,11 @@ Camera constants:
"raw_crop": [ 4, 4, -4, -4 ] // full raw 6016x4016, Official 6000x4000
},
+ { // Quality C, only raw crop
+ "make_model": "Leica SL2",
+ "raw_crop": [ 0, 0, 0, -18 ] // 18 rows at bottom are garbage
+ },
+
{ // Quality C
"make_model": "LG mobile LG-H815",
"dcraw_matrix": [ 5859,547,-1250,-6484,15547,547,-2422,5625,3906 ], // DNG D65
diff --git a/rtengine/canon_cr3_decoder.cc b/rtengine/canon_cr3_decoder.cc
index 359243ed5..6274154cb 100644
--- a/rtengine/canon_cr3_decoder.cc
+++ b/rtengine/canon_cr3_decoder.cc
@@ -1,5 +1,25 @@
-/* -*- C++ -*-
- *
+/*
+ * This file is part of RawTherapee.
+ *
+ * Copyright (c) 2019 RawTherapee development team
+ *
+ * RawTherapee 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.
+ *
+ * RawTherapee 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 RawTherapee. If not, see .
+ */
+
+// Code adapted from ART
+/*
+ *
* This file is part of ART.
*
* ART is free software: you can redistribute it and/or modify
@@ -16,15 +36,6 @@
* along with ART. If not, see .
*/
-#include
-#include "dcraw.h"
-#ifdef __GNUC__ // silence warning
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wsign-compare"
-#pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
-#endif
-
// Code adapted from libraw
/* -*- C++ -*-
* Copyright 2019 LibRaw LLC (info@libraw.org)
@@ -40,570 +51,589 @@
*/
+#include
+#include
+#include
+#include
+#include
+
+#include "dcraw.h"
+
+#include "rt_math.h"
void DCraw::parse_canon_cr3()
{
- int err;
- unsigned long long szAtomList;
+ strncpy(make, "Canon", sizeof(make));
+
+ unsigned long long szAtomList = ifp->size;
short nesting = -1;
- short nTrack = -1;
- short TrackType;
char AtomNameStack[128];
- strcpy(make, "Canon");
+ unsigned short nTrack = 0;
+ short TrackType;
- szAtomList = ifp->size;
- err = parseCR3(0ULL, szAtomList, nesting, AtomNameStack, nTrack, TrackType);
- if ((err == 0 || err == -14) &&
- nTrack >= 0) // no error, or too deep nesting
+ const int err = parseCR3(0, szAtomList, nesting, AtomNameStack, nTrack, TrackType);
+
+ if (err == 0 || err == -14) { // no error, or too deep nesting
selectCRXTrack(nTrack);
+ }
}
-#define LIBRAW_CRXTRACKS_MAXCOUNT RT_canon_CR3_data.CRXTRACKS_MAXCOUNT
-
-void DCraw::selectCRXTrack(short maxTrack)
+void DCraw::selectCRXTrack(unsigned short maxTrack)
{
- if (maxTrack < 0)
- return;
- INT64 bitcounts[LIBRAW_CRXTRACKS_MAXCOUNT], maxbitcount = 0;
- uint32_t maxjpegbytes = 0;
- memset(bitcounts, 0, sizeof(bitcounts));
- for (int i = 0; i <= maxTrack && i < LIBRAW_CRXTRACKS_MAXCOUNT; i++)
- {
- CanonCR3Data::crx_data_header_t *d = &RT_canon_CR3_data.crx_header[i];
- if (d->MediaType == 1) // RAW
- {
- bitcounts[i] = INT64(d->nBits) * INT64(d->f_width) * INT64(d->f_height);
- if (bitcounts[i] > maxbitcount)
- maxbitcount = bitcounts[i];
- }
- else if (d->MediaType == 2) // JPEG
- {
- if (d->MediaSize > maxjpegbytes)
- {
- maxjpegbytes = d->MediaSize;
- thumb_offset = d->MediaOffset;
- thumb_length = d->MediaSize;
- }
- }
- }
- if (maxbitcount < 8)
- return;
- int framei = -1, framecnt = 0;
- for (int i = 0; i <= maxTrack && i < LIBRAW_CRXTRACKS_MAXCOUNT; i++)
- {
- if (bitcounts[i] == maxbitcount)
- {
- if (framecnt <= shot_select)
- framei = i;
- framecnt++;
- }
- }
- is_raw = framecnt;
- if (framei >= 0 && framei < LIBRAW_CRXTRACKS_MAXCOUNT)
- {
- CanonCR3Data::crx_data_header_t *d =
- &RT_canon_CR3_data.crx_header[framei];
- data_offset = d->MediaOffset;
- //data_size = d->MediaSize;
- raw_width = d->f_width;
- raw_height = d->f_height;
- load_raw = &DCraw::crxLoadRaw;
- switch (d->cfaLayout)
- {
- case 0:
- filters = 0x94949494;
- break;
- case 1:
- filters = 0x61616161;
- break;
- case 2:
- filters = 0x49494949;
- break;
- case 3:
- filters = 0x16161616;
- break;
- }
+ std::int64_t bitcounts[CanonCR3Data::CRXTRACKS_MAXCOUNT] = {};
+ std::int64_t maxbitcount = 0;
+ std::uint32_t maxjpegbytes = 0;
- RT_canon_CR3_data.crx_track_selected = framei;
+ for (unsigned int i = 0; i <= maxTrack && i < RT_canon_CR3_data.CRXTRACKS_MAXCOUNT; ++i) {
+ CanonCR3Data::crx_data_header_t* const d = &RT_canon_CR3_data.crx_header[i];
- int tiff_idx = -1;
- INT64 tpixels = 0;
- for (int i = 0; i < tiff_nifds; i++)
- if (INT64(tiff_ifd[i].height) * INT64(tiff_ifd[i].height) > tpixels)
- {
- tpixels = INT64(tiff_ifd[i].height) * INT64(tiff_ifd[i].height);
- tiff_idx = i;
- }
- if (tiff_idx >= 0)
- flip = tiff_ifd[tiff_idx].flip;
- }
-}
+ if (d->MediaType == 1) { // RAW
+ bitcounts[i] = std::int64_t(d->nBits) * std::int64_t(d->f_width) * std::int64_t(d->f_height);
-#define FORC4 for (c=0; c < 4; c++)
-
-#define bad_hdr \
- (((order != 0x4d4d) && (order != 0x4949)) || (get2() != 0x002a) || \
- (get4() != 0x00000008))
-int DCraw::parseCR3(unsigned long long oAtomList,
- unsigned long long szAtomList, short &nesting,
- char *AtomNameStack, short &nTrack, short &TrackType)
-{
- /*
- Atom starts with 4 bytes for Atom size and 4 bytes containing Atom name
- Atom size includes the length of the header and the size of all "contained"
- Atoms if Atom size == 1, Atom has the extended size stored in 8 bytes located
- after the Atom name if Atom size == 0, it is the last top-level Atom extending
- to the end of the file Atom name is often a 4 symbol mnemonic, but can be a
- 4-byte integer
- */
- const char UIID_Canon[17] =
- "\x85\xc0\xb6\x87\x82\x0f\x11\xe0\x81\x11\xf4\xce\x46\x2b\x6a\x48";
- const char UIID_Preview[17] =
- "\xea\xf4\x2b\x5e\x1c\x98\x4b\x88\xb9\xfb\xb7\xdc\x40\x6e\x4d\x16";
-
- /*
- AtomType = 0 - unknown: "unk."
- AtomType = 1 - container atom: "cont"
- AtomType = 2 - leaf atom: "leaf"
- AtomType = 3 - can be container, can be leaf: "both"
- */
- const char sAtomeType[4][5] = {"unk.", "cont", "leaf", "both"};
- short AtomType;
- static const struct
- {
- char AtomName[5];
- short AtomType;
- } AtomNamesList[] = {
- {"dinf", 1},
- {"edts", 1},
- {"fiin", 1},
- {"ipro", 1},
- {"iprp", 1},
- {"mdia", 1},
- {"meco", 1},
- {"mere", 1},
- {"mfra", 1},
- {"minf", 1},
- {"moof", 1},
- {"moov", 1},
- {"mvex", 1},
- {"paen", 1},
- {"schi", 1},
- {"sinf", 1},
- {"skip", 1},
- {"stbl", 1},
- {"stsd", 1},
- {"strk", 1},
- {"tapt", 1},
- {"traf", 1},
- {"trak", 1},
-
- {"cdsc", 2},
- {"colr", 2},
- {"dimg", 2},
- // {"dref", 2},
- {"free", 2},
- {"frma", 2},
- {"ftyp", 2},
- {"hdlr", 2},
- {"hvcC", 2},
- {"iinf", 2},
- {"iloc", 2},
- {"infe", 2},
- {"ipco", 2},
- {"ipma", 2},
- {"iref", 2},
- {"irot", 2},
- {"ispe", 2},
- {"meta", 2},
- {"mvhd", 2},
- {"pitm", 2},
- {"pixi", 2},
- {"schm", 2},
- {"thmb", 2},
- {"tkhd", 2},
- {"url ", 2},
- {"urn ", 2},
-
- {"CCTP", 1},
- {"CRAW", 1},
-
- {"JPEG", 2},
- {"CDI1", 2},
- {"CMP1", 2},
-
- {"CNCV", 2},
- {"CCDT", 2},
- {"CTBO", 2},
- {"CMT1", 2},
- {"CMT2", 2},
- {"CMT3", 2},
- {"CMT4", 2},
- {"THMB", 2},
- {"co64", 2},
- {"mdat", 2},
- {"mdhd", 2},
- {"nmhd", 2},
- {"stsc", 2},
- {"stsz", 2},
- {"stts", 2},
- {"vmhd", 2},
-
- {"dref", 3},
- {"uuid", 3},
- };
-
- const char sHandlerType[5][5] = {"unk.", "soun", "vide", "hint", "meta"};
-
- int c, err = 0;
-
- ushort tL; // Atom length represented in 4 or 8 bytes
- char nmAtom[5]; // Atom name
- unsigned long long oAtom, szAtom; // Atom offset and Atom size
- unsigned long long oAtomContent,
- szAtomContent; // offset and size of Atom content
- unsigned long long lHdr;
-
- char UIID[16];
- uchar CMP1[36];
- char HandlerType[5], MediaFormatID[5];
- unsigned ImageWidth, ImageHeight;
- long relpos_inDir, relpos_inBox;
- unsigned szItem, Tag, lTag;
- ushort tItem;
-
- nmAtom[0] = MediaFormatID[0] = nmAtom[4] = MediaFormatID[4] = '\0';
- strcpy(HandlerType, sHandlerType[0]);
- ImageWidth = ImageHeight = 0U;
- oAtom = oAtomList;
- nesting++;
- if (nesting > 31)
- return -14; // too deep nesting
- short s_order = order;
-
- while ((oAtom + 8ULL) <= (oAtomList + szAtomList))
- {
- lHdr = 0ULL;
- err = 0;
- order = 0x4d4d;
- fseek(ifp, oAtom, SEEK_SET);
- szAtom = get4();
- FORC4 nmAtom[c] = AtomNameStack[nesting * 4 + c] = fgetc(ifp);
- AtomNameStack[(nesting + 1) * 4] = '\0';
- tL = 4;
- AtomType = 0;
-
- for (c = 0; c < sizeof AtomNamesList / sizeof *AtomNamesList; c++)
- if (!strcmp(nmAtom, AtomNamesList[c].AtomName))
- {
- AtomType = AtomNamesList[c].AtomType;
- break;
- }
-
- if (!AtomType)
- {
- err = 1;
- }
-
- if (szAtom == 0ULL)
- {
- if (nesting != 0)
- {
- err = -2;
- goto fin;
- }
- szAtom = szAtomList - oAtom;
- oAtomContent = oAtom + 8ULL;
- szAtomContent = szAtom - 8ULL;
- }
- else if (szAtom == 1ULL)
- {
- if ((oAtom + 16ULL) > (oAtomList + szAtomList))
- {
- err = -3;
- goto fin;
- }
- tL = 8;
- szAtom = (((unsigned long long)get4()) << 32) | get4();
- oAtomContent = oAtom + 16ULL;
- szAtomContent = szAtom - 16ULL;
- }
- else
- {
- oAtomContent = oAtom + 8ULL;
- szAtomContent = szAtom - 8ULL;
- }
-
- if (!strcmp(nmAtom, "trak"))
- {
- nTrack++;
- TrackType = 0;
- if (nTrack >= LIBRAW_CRXTRACKS_MAXCOUNT)
- break;
- }
- if (!strcmp(AtomNameStack, "moovuuid"))
- {
- lHdr = 16ULL;
- fread(UIID, 1, lHdr, ifp);
- if (!strncmp(UIID, UIID_Canon, lHdr))
- {
- AtomType = 1;
- }
- else
- fseek(ifp, -lHdr, SEEK_CUR);
- }
- else if (!strcmp(AtomNameStack, "moovuuidCCTP"))
- {
- lHdr = 12ULL;
- }
- else if (!strcmp(AtomNameStack, "moovuuidCMT1"))
- {
- short q_order = order;
- order = get2();
- if ((tL != 4) || bad_hdr)
- {
- err = -4;
- goto fin;
- }
- parse_tiff_ifd(oAtomContent);
- order = q_order;
- }
- else if (!strcmp(AtomNameStack, "moovuuidCMT2"))
- {
- short q_order = order;
- order = get2();
- if ((tL != 4) || bad_hdr)
- {
- err = -5;
- goto fin;
- }
- parse_exif(oAtomContent);
- order = q_order;
- }
- else if (!strcmp(AtomNameStack, "moovuuidCMT3"))
- {
- short q_order = order;
- order = get2();
- if ((tL != 4) || bad_hdr)
- {
- err = -6;
- goto fin;
- }
- fseek(ifp, -12L, SEEK_CUR);
- parse_makernote(oAtomContent, 0);
- order = q_order;
- }
- else if (!strcmp(AtomNameStack, "moovuuidCMT4"))
- {
- short q_order = order;
- order = get2();
- if ((tL != 4) || bad_hdr)
- {
- err = -6;
- goto fin;
- }
- INT64 off = ftell(ifp);
- parse_gps(oAtomContent);
- fseek(ifp, off, SEEK_SET);
-// parse_gps_libraw(oAtomContent);
- order = q_order;
- }
- else if (!strcmp(AtomNameStack, "moovtrakmdiahdlr"))
- {
- fseek(ifp, 8L, SEEK_CUR);
- FORC4 HandlerType[c] = fgetc(ifp);
- for (c = 1; c < sizeof sHandlerType / sizeof *sHandlerType; c++)
- if (!strcmp(HandlerType, sHandlerType[c]))
- {
- TrackType = c;
- break;
- }
- }
- else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsd"))
- {
- if (szAtomContent >= 16)
- {
- fseek(ifp, 12L, SEEK_CUR);
- lHdr = 8;
- }
- else
- {
- err = -7;
- goto fin;
- }
- FORC4 MediaFormatID[c] = fgetc(ifp);
- if ((TrackType == 2) && (!strcmp(MediaFormatID, "CRAW")))
- {
- if (szAtomContent >= 44)
- fseek(ifp, 24L, SEEK_CUR);
- else
- {
- err = -8;
- goto fin;
- }
- }
- else
- {
- AtomType = 2; // only continue for CRAW
- lHdr = 0;
- }
-#define current_track RT_canon_CR3_data.crx_header[nTrack]
-
- ImageWidth = get2();
- ImageHeight = get2();
- }
- else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAW"))
- {
- lHdr = 82;
- }
- else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAWCMP1"))
- {
- if (szAtomContent >= 40)
- fread(CMP1, 1, 36, ifp);
- else
- {
- err = -7;
- goto fin;
- }
- if (!crxParseImageHeader(CMP1, nTrack))
- current_track.MediaType = 1;
- }
- else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAWJPEG"))
- {
- current_track.MediaType = 2;
- }
- else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsz"))
- {
- if (szAtomContent == 12)
- fseek(ifp, 4L, SEEK_CUR);
- else if (szAtomContent == 16)
- fseek(ifp, 12L, SEEK_CUR);
- else
- {
- err = -9;
- goto fin;
- }
- current_track.MediaSize = get4();
- }
- else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblco64"))
- {
- if (szAtomContent == 16)
- fseek(ifp, 8L, SEEK_CUR);
- else
- {
- err = -10;
- goto fin;
- }
- current_track.MediaOffset = (((unsigned long long)get4()) << 32) | get4();
- }
-
- if (current_track.MediaSize && current_track.MediaOffset &&
- ((oAtom + szAtom) >= (oAtomList + szAtomList)) &&
- !strncmp(AtomNameStack, "moovtrakmdiaminfstbl", 20))
- {
- if ((TrackType == 4) && (!strcmp(MediaFormatID, "CTMD")))
- {
- order = 0x4949;
- relpos_inDir = 0L;
- while (relpos_inDir + 6 < current_track.MediaSize)
- {
- fseek(ifp, current_track.MediaOffset + relpos_inDir, SEEK_SET);
- szItem = get4();
- tItem = get2();
- if ((relpos_inDir + szItem) > current_track.MediaSize)
- {
- err = -11;
- goto fin;
- }
- if ((tItem == 7) || (tItem == 8) || (tItem == 9))
- {
- relpos_inBox = relpos_inDir + 12L;
- while (relpos_inBox + 8 < relpos_inDir + szItem)
- {
- fseek(ifp, current_track.MediaOffset + relpos_inBox, SEEK_SET);
- lTag = get4();
- Tag = get4();
- if (lTag < 8)
- {
- err = -12;
- goto fin;
- }
- else if ((relpos_inBox + lTag) > (relpos_inDir + szItem))
- {
- err = -11;
- goto fin;
- }
- if ((Tag == 0x927c) && ((tItem == 7) || (tItem == 8)))
- {
- fseek(ifp, current_track.MediaOffset + relpos_inBox + 8L,
- SEEK_SET);
- short q_order = order;
- order = get2();
- if (bad_hdr)
- {
- err = -13;
- goto fin;
- }
- fseek(ifp, -8L, SEEK_CUR);
- RT_canon_CR3_data.CR3_CTMDtag = 1;
- parse_makernote(current_track.MediaOffset + relpos_inBox + 8,
- 0);
- RT_canon_CR3_data.CR3_CTMDtag = 0;
- order = q_order;
- }
- relpos_inBox += lTag;
+ if (bitcounts[i] > maxbitcount) {
+ maxbitcount = bitcounts[i];
+ }
+ } else if (d->MediaType == 2) { // JPEG
+ if (d->MediaSize > maxjpegbytes) {
+ maxjpegbytes = d->MediaSize;
+ thumb_offset = d->MediaOffset;
+ thumb_length = d->MediaSize;
}
- }
- relpos_inDir += szItem;
}
- order = 0x4d4d;
- }
}
-#undef current_track
- if (AtomType == 1)
- {
- err = parseCR3(oAtomContent + lHdr, szAtomContent - lHdr, nesting,
- AtomNameStack, nTrack, TrackType);
- if (err)
- goto fin;
+
+ if (maxbitcount < 8) {
+ return;
+ }
+
+ bool has_framei = false;
+ unsigned int framei = 0;
+ unsigned int framecnt = 0;
+
+ for (unsigned int i = 0; i <= maxTrack && i < RT_canon_CR3_data.CRXTRACKS_MAXCOUNT; ++i) {
+ if (bitcounts[i] == maxbitcount) {
+ if (framecnt <= shot_select) {
+ has_framei = true;
+ framei = i;
+ }
+
+ framecnt++;
+ }
+ }
+
+ is_raw = framecnt;
+
+ if (has_framei) {
+ CanonCR3Data::crx_data_header_t* const d = &RT_canon_CR3_data.crx_header[framei];
+ data_offset = d->MediaOffset;
+ // data_size = d->MediaSize;
+ raw_width = d->f_width;
+ raw_height = d->f_height;
+ load_raw = &DCraw::crxLoadRaw;
+
+ switch (d->cfaLayout) {
+ case 0: {
+ filters = 0x94949494;
+ break;
+ }
+
+ case 1: {
+ filters = 0x61616161;
+ break;
+ }
+
+ case 2: {
+ filters = 0x49494949;
+ break;
+ }
+
+ case 3: {
+ filters = 0x16161616;
+ break;
+ }
+ }
+
+ RT_canon_CR3_data.crx_track_selected = framei;
+
+ int tiff_idx = -1;
+ std::int64_t tpixels = 0;
+
+ for (unsigned int i = 0; i < tiff_nifds; ++i) {
+ if (std::int64_t(tiff_ifd[i].height) * std::int64_t(tiff_ifd[i].height) > tpixels) {
+ tpixels = std::int64_t(tiff_ifd[i].height) * std::int64_t(tiff_ifd[i].height);
+ tiff_idx = i;
+ }
+ }
+
+ if (tiff_idx >= 0) {
+ flip = tiff_ifd[tiff_idx].flip;
+ }
+ }
+}
+
+int DCraw::parseCR3(
+ unsigned long long oAtomList,
+ unsigned long long szAtomList,
+ short& nesting,
+ char* AtomNameStack,
+ unsigned short& nTrack,
+ short& TrackType
+)
+{
+ /*
+ Atom starts with 4 bytes for Atom size and 4 bytes containing Atom name
+ Atom size includes the length of the header and the size of all "contained"
+ Atoms if Atom size == 1, Atom has the extended size stored in 8 bytes located
+ after the Atom name if Atom size == 0, it is the last top-level Atom extending
+ to the end of the file Atom name is often a 4 symbol mnemonic, but can be a
+ 4-byte integer
+ */
+ const char UIID_Canon[17] =
+ "\x85\xc0\xb6\x87\x82\x0f\x11\xe0\x81\x11\xf4\xce\x46\x2b\x6a\x48";
+// const char UIID_Preview[17] =
+// "\xea\xf4\x2b\x5e\x1c\x98\x4b\x88\xb9\xfb\xb7\xdc\x40\x6e\x4d\x16";
+
+ /*
+ AtomType = 0 - unknown: "unk."
+ AtomType = 1 - container atom: "cont"
+ AtomType = 2 - leaf atom: "leaf"
+ AtomType = 3 - can be container, can be leaf: "both"
+ */
+// const char sAtomeType[4][5] = {"unk.", "cont", "leaf", "both"};
+ short AtomType;
+ static const struct {
+ char AtomName[5];
+ short AtomType;
+ } AtomNamesList[] = {
+ {"dinf", 1},
+ {"edts", 1},
+ {"fiin", 1},
+ {"ipro", 1},
+ {"iprp", 1},
+ {"mdia", 1},
+ {"meco", 1},
+ {"mere", 1},
+ {"mfra", 1},
+ {"minf", 1},
+ {"moof", 1},
+ {"moov", 1},
+ {"mvex", 1},
+ {"paen", 1},
+ {"schi", 1},
+ {"sinf", 1},
+ {"skip", 1},
+ {"stbl", 1},
+ {"stsd", 1},
+ {"strk", 1},
+ {"tapt", 1},
+ {"traf", 1},
+ {"trak", 1},
+
+ {"cdsc", 2},
+ {"colr", 2},
+ {"dimg", 2},
+ // {"dref", 2},
+ {"free", 2},
+ {"frma", 2},
+ {"ftyp", 2},
+ {"hdlr", 2},
+ {"hvcC", 2},
+ {"iinf", 2},
+ {"iloc", 2},
+ {"infe", 2},
+ {"ipco", 2},
+ {"ipma", 2},
+ {"iref", 2},
+ {"irot", 2},
+ {"ispe", 2},
+ {"meta", 2},
+ {"mvhd", 2},
+ {"pitm", 2},
+ {"pixi", 2},
+ {"schm", 2},
+ {"thmb", 2},
+ {"tkhd", 2},
+ {"url ", 2},
+ {"urn ", 2},
+
+ {"CCTP", 1},
+ {"CRAW", 1},
+
+ {"JPEG", 2},
+ {"CDI1", 2},
+ {"CMP1", 2},
+
+ {"CNCV", 2},
+ {"CCDT", 2},
+ {"CTBO", 2},
+ {"CMT1", 2},
+ {"CMT2", 2},
+ {"CMT3", 2},
+ {"CMT4", 2},
+ {"THMB", 2},
+ {"co64", 2},
+ {"mdat", 2},
+ {"mdhd", 2},
+ {"nmhd", 2},
+ {"stsc", 2},
+ {"stsz", 2},
+ {"stts", 2},
+ {"vmhd", 2},
+
+ {"dref", 3},
+ {"uuid", 3},
+ };
+
+ const char sHandlerType[5][5] = {
+ "unk.",
+ "soun",
+ "vide",
+ "hint",
+ "meta"
+ };
+
+ int err = 0;
+
+ unsigned short tL; // Atom length represented in 4 or 8 bytes
+ char nmAtom[5]; // Atom name
+ unsigned long long oAtom;
+ unsigned long long szAtom; // Atom offset and Atom size
+ unsigned long long oAtomContent;
+ unsigned long long szAtomContent; // offset and size of Atom content
+ unsigned long long lHdr;
+
+ char UIID[16];
+ uchar CMP1[36];
+ char HandlerType[5];
+ char MediaFormatID[5];
+// unsigned int ImageWidth, ImageHeight;
+ unsigned long relpos_inDir;
+ unsigned long relpos_inBox;
+ unsigned int szItem;
+ unsigned int Tag;
+ unsigned int lTag;
+ unsigned short tItem;
+
+ nmAtom[0] = MediaFormatID[0] = nmAtom[4] = MediaFormatID[4] = '\0';
+ strncpy(HandlerType, sHandlerType[0], sizeof(HandlerType));
+// ImageWidth = ImageHeight = 0U;
+ oAtom = oAtomList;
+ ++nesting;
+
+ if (nesting > 31) {
+ return -14; // too deep nesting
+ }
+
+ short s_order = order;
+
+ const auto is_bad_header =
+ [this]() -> bool
+ {
+ return
+ (
+ order != 0x4D4D
+ && order != 0x4949
+ )
+ || get2() != 0x002A
+ || get4() != 0x00000008;
+ };
+
+ while ((oAtom + 8) <= (oAtomList + szAtomList)) {
+ lHdr = 0U;
+ err = 0;
+ order = 0x4D4D;
+ fseek(ifp, oAtom, SEEK_SET);
+ szAtom = get4();
+ for (unsigned int c = 0; c < 4; ++c) {
+ nmAtom[c] = AtomNameStack[nesting * 4 + c] = fgetc(ifp);
+ }
+ AtomNameStack[(nesting + 1) * 4] = '\0';
+ tL = 4;
+ AtomType = 0;
+
+ for (const auto& atom : AtomNamesList) {
+ if (!strcmp(nmAtom, atom.AtomName)) {
+ AtomType = atom.AtomType;
+ break;
+ }
+ }
+
+ if (!AtomType) {
+ err = 1;
+ }
+
+ if (szAtom == 0) {
+ if (nesting != 0) {
+ err = -2;
+ goto fin;
+ }
+
+ szAtom = szAtomList - oAtom;
+ oAtomContent = oAtom + 8;
+ szAtomContent = szAtom - 8;
+ } else if (szAtom == 1) {
+ if ((oAtom + 16) > (oAtomList + szAtomList)) {
+ err = -3;
+ goto fin;
+ }
+
+ tL = 8;
+ szAtom = (static_cast(get4()) << 32) | get4();
+ oAtomContent = oAtom + 16;
+ szAtomContent = szAtom - 16;
+ } else {
+ oAtomContent = oAtom + 8;
+ szAtomContent = szAtom - 8;
+ }
+
+ if (!strcmp(nmAtom, "trak")) {
+ nTrack++;
+ TrackType = 0;
+
+ if (nTrack >= RT_canon_CR3_data.CRXTRACKS_MAXCOUNT) {
+ break;
+ }
+ }
+
+ if (!strcmp(AtomNameStack, "moovuuid")) {
+ lHdr = 16;
+ fread(UIID, 1, lHdr, ifp);
+
+ if (!strncmp(UIID, UIID_Canon, lHdr)) {
+ AtomType = 1;
+ } else {
+ fseek(ifp, -lHdr, SEEK_CUR);
+ }
+ } else if (!strcmp(AtomNameStack, "moovuuidCCTP")) {
+ lHdr = 12;
+ } else if (!strcmp(AtomNameStack, "moovuuidCMT1")) {
+ const short q_order = order;
+ order = get2();
+
+ if (tL != 4 || is_bad_header()) {
+ err = -4;
+ goto fin;
+ }
+
+ parse_tiff_ifd(oAtomContent);
+ order = q_order;
+ } else if (!strcmp(AtomNameStack, "moovuuidCMT2")) {
+ const short q_order = order;
+ order = get2();
+
+ if (tL != 4 || is_bad_header()) {
+ err = -5;
+ goto fin;
+ }
+
+ parse_exif(oAtomContent);
+ order = q_order;
+ } else if (!strcmp(AtomNameStack, "moovuuidCMT3")) {
+ const short q_order = order;
+ order = get2();
+
+ if (tL != 4 || is_bad_header()) {
+ err = -6;
+ goto fin;
+ }
+
+ fseek(ifp, -12L, SEEK_CUR);
+ parse_makernote(oAtomContent, 0);
+ order = q_order;
+ } else if (!strcmp(AtomNameStack, "moovuuidCMT4")) {
+ const short q_order = order;
+ order = get2();
+
+ if (tL != 4 || is_bad_header()) {
+ err = -6;
+ goto fin;
+ }
+
+ const long off = ftell(ifp);
+ parse_gps(oAtomContent);
+ fseek(ifp, off, SEEK_SET);
+// parse_gps_libraw(oAtomContent);
+ order = q_order;
+ } else if (!strcmp(AtomNameStack, "moovtrakmdiahdlr")) {
+ fseek(ifp, 8, SEEK_CUR);
+ for (unsigned int c = 0; c < 4; ++c) {
+ HandlerType[c] = fgetc(ifp);
+ }
+
+ for (unsigned int c = 1; c < sizeof(sHandlerType) / sizeof(*sHandlerType); ++c) {
+ if (!strcmp(HandlerType, sHandlerType[c])) {
+ TrackType = c;
+ break;
+ }
+ }
+ } else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsd")) {
+ if (szAtomContent >= 16) {
+ fseek(ifp, 12, SEEK_CUR);
+ lHdr = 8;
+ } else {
+ err = -7;
+ goto fin;
+ }
+
+ for (unsigned int c = 0; c < 4; ++c) {
+ MediaFormatID[c] = fgetc(ifp);
+ }
+
+ if (TrackType == 2 && !strcmp(MediaFormatID, "CRAW")) {
+ if (szAtomContent >= 44) {
+ fseek(ifp, 24, SEEK_CUR);
+ } else {
+ err = -8;
+ goto fin;
+ }
+ } else {
+ AtomType = 2; // only continue for CRAW
+ lHdr = 0;
+ }
+
+ /*ImageWidth = */ get2();
+ /*ImageHeight = */ get2();
+ } else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAW")) {
+ lHdr = 82;
+ } else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAWCMP1")) {
+ if (szAtomContent >= 40) {
+ fread(CMP1, 1, 36, ifp);
+ } else {
+ err = -7;
+ goto fin;
+ }
+
+ if (crxParseImageHeader(CMP1, nTrack)) {
+ RT_canon_CR3_data.crx_header[nTrack].MediaType = 1;
+ }
+ } else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAWJPEG")) {
+ RT_canon_CR3_data.crx_header[nTrack].MediaType = 2;
+ } else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsz")) {
+ if (szAtomContent == 12) {
+ fseek(ifp, 4, SEEK_CUR);
+ } else if (szAtomContent == 16) {
+ fseek(ifp, 12, SEEK_CUR);
+ } else {
+ err = -9;
+ goto fin;
+ }
+
+ RT_canon_CR3_data.crx_header[nTrack].MediaSize = get4();
+ } else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblco64")) {
+ if (szAtomContent == 16) {
+ fseek(ifp, 8, SEEK_CUR);
+ } else {
+ err = -10;
+ goto fin;
+ }
+
+ RT_canon_CR3_data.crx_header[nTrack].MediaOffset = (static_cast(get4()) << 32) | get4();
+ }
+
+ if (
+ RT_canon_CR3_data.crx_header[nTrack].MediaSize
+ && RT_canon_CR3_data.crx_header[nTrack].MediaOffset
+ && oAtom + szAtom >= oAtomList + szAtomList
+ && !strncmp(AtomNameStack, "moovtrakmdiaminfstbl", 20)
+ ) {
+ if (TrackType == 4 && !strcmp(MediaFormatID, "CTMD")) {
+ order = 0x4949;
+ relpos_inDir = 0;
+
+ while (relpos_inDir + 6 < RT_canon_CR3_data.crx_header[nTrack].MediaSize) {
+ fseek(ifp, RT_canon_CR3_data.crx_header[nTrack].MediaOffset + relpos_inDir, SEEK_SET);
+ szItem = get4();
+ tItem = get2();
+
+ if ((relpos_inDir + szItem) > RT_canon_CR3_data.crx_header[nTrack].MediaSize) {
+ err = -11;
+ goto fin;
+ }
+
+ if (
+ tItem == 7
+ || tItem == 8
+ || tItem == 9
+ ) {
+ relpos_inBox = relpos_inDir + 12;
+
+ while (relpos_inBox + 8 < relpos_inDir + szItem) {
+ fseek(ifp, RT_canon_CR3_data.crx_header[nTrack].MediaOffset + relpos_inBox, SEEK_SET);
+ lTag = get4();
+ Tag = get4();
+
+ if (lTag < 8) {
+ err = -12;
+ goto fin;
+ } else if (relpos_inBox + lTag > relpos_inDir + szItem) {
+ err = -11;
+ goto fin;
+ }
+
+ if (
+ Tag == 0x927C
+ && (
+ tItem == 7
+ || tItem == 8
+ )
+ ) {
+ fseek(ifp, RT_canon_CR3_data.crx_header[nTrack].MediaOffset + relpos_inBox + 8, SEEK_SET);
+ const short q_order = order;
+ order = get2();
+
+ if (is_bad_header()) {
+ err = -13;
+ goto fin;
+ }
+
+ fseek(ifp, -8, SEEK_CUR);
+ RT_canon_CR3_data.CR3_CTMDtag = 1;
+ parse_makernote(RT_canon_CR3_data.crx_header[nTrack].MediaOffset + relpos_inBox + 8, 0);
+ RT_canon_CR3_data.CR3_CTMDtag = 0;
+ order = q_order;
+ }
+
+ relpos_inBox += lTag;
+ }
+ }
+
+ relpos_inDir += szItem;
+ }
+
+ order = 0x4D4D;
+ }
+ }
+
+ if (AtomType == 1) {
+ err = parseCR3(oAtomContent + lHdr, szAtomContent - lHdr, nesting, AtomNameStack, nTrack, TrackType);
+
+ if (err) {
+ goto fin;
+ }
+ }
+
+ oAtom += szAtom;
}
- oAtom += szAtom;
- }
fin:
- nesting--;
- if (nesting >= 0)
- AtomNameStack[nesting * 4] = '\0';
- order = s_order;
- return err;
+ --nesting;
+
+ if (nesting >= 0) {
+ AtomNameStack[nesting * 4] = '\0';
+ }
+
+ order = s_order;
+ return err;
}
-#undef bad_hdr
+// -----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-#ifdef _abs
-#undef _abs
-#undef _min
-#undef _constrain
-#endif
-#define _abs(x) (((x) ^ ((int32_t)(x) >> 31)) - ((int32_t)(x) >> 31))
-#define _min(a, b) ((a) < (b) ? (a) : (b))
-#define _constrain(x, l, u) ((x) < (l) ? (l) : ((x) > (u) ? (u) : (x)))
-
-#if defined(__clang__) || defined(__GNUG__)
-#define libraw_inline inline __attribute__((always_inline))
-#elif defined(_MSC_VER) && _MSC_VER > 1400
-#define libraw_inline __forceinline
-#else
-#define libraw_inline inline
-#endif
-
-namespace {
-
-static unsigned sgetn (int n, unsigned char *s)
+namespace
{
- unsigned result = 0;
+
+unsigned int sgetn(int n, unsigned char* s)
+{
+ unsigned int result = 0;
while (n-- > 0) {
result = (result << 8) | (*s++);
@@ -613,143 +643,147 @@ static unsigned sgetn (int n, unsigned char *s)
}
// this should be divisible by 4
-#define CRX_BUF_SIZE 0x10000
-#if !defined(_WIN32) || (defined (__GNUC__) && !defined(__INTRINSIC_SPECIAL__BitScanReverse))
+constexpr std::uint64_t CRX_BUF_SIZE = 0x10000;
+
+#if !defined (_WIN32) || (defined (__GNUC__) && !defined (__INTRINSIC_SPECIAL__BitScanReverse))
/* __INTRINSIC_SPECIAL__BitScanReverse found in MinGW32-W64 v7.30 headers, may be there is a better solution? */
-typedef uint32_t DWORD;
-typedef uint8_t byte;
-libraw_inline void _BitScanReverse(DWORD *Index, unsigned long Mask)
+inline void _BitScanReverse(std::uint32_t* Index, unsigned long Mask)
{
- *Index = sizeof(unsigned long) * 8 - 1 - __builtin_clzl(Mask);
+ *Index = sizeof(unsigned long) * 8 - 1 - __builtin_clzl(Mask);
+}
+std::uint32_t _byteswap_ulong(std::uint32_t x)
+{
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ return x;
+#else
+ return __builtin_bswap32(x);
+#endif
}
-#define _byteswap_ulong(x) __builtin_bswap32(x)
#endif
-
-#define LIBRAW_EXCEPTION_IO_EOF std::exception()
-
struct LibRaw_abstract_datastream {
- IMFILE *ifp;
-
- void lock() {}
- void unlock() {}
- void seek(int p, int how) { fseek(ifp, p, how); }
+ IMFILE* ifp;
+
+ void lock()
+ {
+ }
+ void unlock()
+ {
+ }
+ void seek(long p, int how)
+ {
+ fseek(ifp, p, how);
+ }
int read(void* dst, int es, int count)
- { return fread(dst, es, count, ifp); }
+ {
+ return fread(dst, es, count, ifp);
+ }
};
-struct CrxBitstream
-{
- uint8_t mdatBuf[CRX_BUF_SIZE];
- uint64_t mdatSize;
- uint64_t curBufOffset;
- uint32_t curPos;
- uint32_t curBufSize;
- uint32_t bitData;
- int32_t bitsLeft;
- LibRaw_abstract_datastream *input;
+struct CrxBitstream {
+ std::uint8_t mdatBuf[CRX_BUF_SIZE];
+ std::uint64_t mdatSize;
+ std::uint64_t curBufOffset;
+ std::uint32_t curPos;
+ std::uint32_t curBufSize;
+ std::uint32_t bitData;
+ std::int32_t bitsLeft;
+ LibRaw_abstract_datastream* input;
};
-struct CrxBandParam
-{
- CrxBitstream bitStream;
- int16_t subbandWidth;
- int16_t subbandHeight;
- int32_t roundedBitsMask;
- int32_t roundedBits;
- int16_t curLine;
- int32_t *lineBuf0;
- int32_t *lineBuf1;
- int32_t *lineBuf2;
- int32_t sParam;
- int32_t kParam;
- int32_t *paramData;
- int32_t *nonProgrData;
- int8_t supportsPartial;
+struct CrxBandParam {
+ CrxBitstream bitStream;
+ std::int16_t subbandWidth;
+ std::int16_t subbandHeight;
+ std::int32_t roundedBitsMask;
+ std::int32_t roundedBits;
+ std::int16_t curLine;
+ std::int32_t* lineBuf0;
+ std::int32_t* lineBuf1;
+ std::int32_t* lineBuf2;
+ std::int32_t sParam;
+ std::int32_t kParam;
+ std::int32_t* paramData;
+ std::int32_t* nonProgrData;
+ bool supportsPartial;
};
-struct CrxWaveletTransform
-{
- int32_t *subband0Buf;
- int32_t *subband1Buf;
- int32_t *subband2Buf;
- int32_t *subband3Buf;
- int32_t *lineBuf[8];
- int16_t curLine;
- int16_t curH;
- int8_t fltTapH;
- int16_t height;
- int16_t width;
+struct CrxWaveletTransform {
+ std::int32_t* subband0Buf;
+ std::int32_t* subband1Buf;
+ std::int32_t* subband2Buf;
+ std::int32_t* subband3Buf;
+ std::int32_t* lineBuf[8];
+ std::int16_t curLine;
+ std::int16_t curH;
+ std::int8_t fltTapH;
+ std::int16_t height;
+ std::int16_t width;
};
-struct CrxSubband
-{
- CrxBandParam *bandParam;
- uint64_t mdatOffset;
- uint8_t *bandBuf;
- int32_t bandSize;
- uint64_t dataSize;
- int8_t supportsPartial;
- int32_t quantValue;
- uint16_t width;
- uint16_t height;
- int32_t paramK;
- int64_t dataOffset;
+struct CrxSubband {
+ CrxBandParam* bandParam;
+ std::uint64_t mdatOffset;
+ std::uint8_t* bandBuf;
+ std::int32_t bandSize;
+ std::uint64_t dataSize;
+ bool supportsPartial;
+ std::int32_t quantValue;
+ std::uint16_t width;
+ std::uint16_t height;
+ std::int32_t paramK;
+ std::int64_t dataOffset;
};
-struct CrxPlaneComp
-{
- byte *compBuf;
- CrxSubband *subBands;
- CrxWaveletTransform *waveletTransform;
- int8_t compNumber;
- int64_t dataOffset;
- int32_t compSize;
- int8_t supportsPartial;
- int32_t roundedBitsMask;
- int8_t tileFlag;
+struct CrxPlaneComp {
+ std::uint8_t* compBuf;
+ CrxSubband* subBands;
+ CrxWaveletTransform* waveletTransform;
+ std::int8_t compNumber;
+ std::int64_t dataOffset;
+ std::int32_t compSize;
+ bool supportsPartial;
+ std::int32_t roundedBitsMask;
+ std::int8_t tileFlag;
};
-struct CrxTile
-{
- CrxPlaneComp *comps;
- int8_t tileFlag;
- int8_t tileNumber;
- int64_t dataOffset;
- int32_t tileSize;
- uint16_t width;
- uint16_t height;
+struct CrxTile {
+ CrxPlaneComp* comps;
+ std::int8_t tileFlag;
+ std::int8_t tileNumber;
+ std::int64_t dataOffset;
+ std::int32_t tileSize;
+ std::uint16_t width;
+ std::uint16_t height;
};
-struct CrxImage
-{
- uint8_t nPlanes;
- uint16_t planeWidth;
- uint16_t planeHeight;
- uint8_t samplePrecision;
- uint8_t subbandCount;
- uint8_t levels;
- uint8_t nBits;
- uint8_t encType;
- uint8_t tileCols;
- uint8_t tileRows;
- CrxTile *tiles;
- uint64_t mdatOffset;
- uint64_t mdatSize;
- int16_t *outBufs[4]; // one per plane
- int16_t *planeBuf;
- LibRaw_abstract_datastream *input;
+struct CrxImage {
+ std::uint8_t nPlanes;
+ std::uint16_t planeWidth;
+ std::uint16_t planeHeight;
+ std::uint8_t samplePrecision;
+ std::uint8_t subbandCount;
+ std::uint8_t levels;
+ std::uint8_t nBits;
+ std::uint8_t encType;
+ std::uint8_t tileCols;
+ std::uint8_t tileRows;
+ CrxTile* tiles;
+ std::uint64_t mdatOffset;
+ std::uint64_t mdatSize;
+ std::int16_t* outBufs[4]; // one per plane
+ std::int16_t* planeBuf;
+ LibRaw_abstract_datastream* input;
};
-enum TileFlags
-{
- E_HAS_TILES_ON_THE_RIGHT = 1,
- E_HAS_TILES_ON_THE_LEFT = 2,
- E_HAS_TILES_ON_THE_BOTTOM = 4,
- E_HAS_TILES_ON_THE_TOP = 8
+enum TileFlags {
+ E_HAS_TILES_ON_THE_RIGHT = 1,
+ E_HAS_TILES_ON_THE_LEFT = 2,
+ E_HAS_TILES_ON_THE_BOTTOM = 4,
+ E_HAS_TILES_ON_THE_TOP = 8
};
-int32_t exCoefNumTbl[0x120] = {
+const std::int32_t exCoefNumTbl[0x120] = {
// level 1
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
@@ -766,2351 +800,2442 @@ int32_t exCoefNumTbl[0x120] = {
1, 1, 7, 7, 1, 1, 3, 3, 1, 1, 1, 1, 1, 0, 7, 6, 1, 0, 3, 2, 1, 0, 1, 0, 1,
2, 10, 10, 2, 2, 5, 4, 2, 1, 2, 1, 1, 1, 10, 9, 1, 2, 4, 4, 2, 1, 2, 1, 1,
1, 9, 9, 1, 2, 4, 4, 2, 1, 2, 1, 1, 0, 9, 8, 1, 1, 4, 3, 1, 1, 1, 1, 1, 2,
- 8, 8, 2, 1, 4, 3, 1, 1, 1, 1, 1, 1, 8, 7, 1, 1, 3, 3, 1, 1, 1, 1};
+ 8, 8, 2, 1, 4, 3, 1, 1, 1, 1, 1, 1, 8, 7, 1, 1, 3, 3, 1, 1, 1, 1
+};
-uint32_t JS[32] = {1, 1, 1, 1, 2, 2, 2, 2,
- 4, 4, 4, 4, 8, 8, 8, 8,
- 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x80, 0x80,
- 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000};
+const std::uint32_t JS[32] = {
+ 0x0001, 0x0001, 0x0001, 0x0001, 0x0002, 0x0002, 0x0002, 0x0002,
+ 0x0004, 0x0004, 0x0004, 0x0004, 0x0008, 0x0008, 0x0008, 0x0008,
+ 0x0010, 0x0010, 0x0020, 0x0020, 0x0040, 0x0040, 0x0080, 0x0080,
+ 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000
+};
-uint32_t J[32] = {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2,
- 2, 3, 3, 3, 3, 4, 4, 5, 5, 6, 6,
- 7, 7, 8, 9, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
+const std::uint32_t J[32] = {
+ 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2,
+ 0x2, 0x3, 0x3, 0x3, 0x3, 0x4, 0x4, 0x5, 0x5, 0x6, 0x6,
+ 0x7, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF
+};
-static inline void crxFillBuffer(CrxBitstream *bitStrm)
+inline void crxFillBuffer(CrxBitstream* bitStrm)
{
- if (bitStrm->curPos >= bitStrm->curBufSize && bitStrm->mdatSize)
- {
- bitStrm->curPos = 0;
- bitStrm->curBufOffset += bitStrm->curBufSize;
+ if (bitStrm->curPos >= bitStrm->curBufSize && bitStrm->mdatSize) {
+ bitStrm->curPos = 0;
+ bitStrm->curBufOffset += bitStrm->curBufSize;
#ifdef _OPENMP
-#pragma omp critical
+ #pragma omp critical
#endif
- {
+ {
#ifndef _OPENMP
- bitStrm->input->lock();
+ bitStrm->input->lock();
#endif
- bitStrm->input->seek(bitStrm->curBufOffset, SEEK_SET);
- bitStrm->curBufSize = bitStrm->input->read(
- bitStrm->mdatBuf, 1, _min(bitStrm->mdatSize, CRX_BUF_SIZE));
+ bitStrm->input->seek(bitStrm->curBufOffset, SEEK_SET);
+ bitStrm->curBufSize = bitStrm->input->read(bitStrm->mdatBuf, 1, std::min(bitStrm->mdatSize, CRX_BUF_SIZE));
#ifndef _OPENMP
- bitStrm->input->unlock();
+ bitStrm->input->unlock();
#endif
- if (bitStrm->curBufSize < 1) // nothing read
- throw LIBRAW_EXCEPTION_IO_EOF;
- bitStrm->mdatSize -= bitStrm->curBufSize;
- }
- }
-}
-libraw_inline int crxBitstreamGetZeros(CrxBitstream *bitStrm)
-{
- uint32_t bitData = bitStrm->bitData;
- uint32_t nonZeroBit = 0;
- uint64_t nextData = 0;
- int32_t result = 0;
-
- if (bitStrm->bitData)
- {
- _BitScanReverse((DWORD *)&nonZeroBit, (DWORD)bitStrm->bitData);
- result = 31 - nonZeroBit;
- bitStrm->bitData <<= 32 - nonZeroBit;
- bitStrm->bitsLeft -= 32 - nonZeroBit;
- }
- else
- {
- uint32_t bitsLeft = bitStrm->bitsLeft;
- while (1)
- {
- while (bitStrm->curPos + 4 <= bitStrm->curBufSize)
- {
- nextData =
- _byteswap_ulong(*(uint32_t *)(bitStrm->mdatBuf + bitStrm->curPos));
- bitStrm->curPos += 4;
- crxFillBuffer(bitStrm);
- if (nextData)
- {
- _BitScanReverse((DWORD *)&nonZeroBit, (DWORD)nextData);
- result = bitsLeft + 31 - nonZeroBit;
- bitStrm->bitData = nextData << (32 - nonZeroBit);
- bitStrm->bitsLeft = nonZeroBit;
- return result;
- }
- bitsLeft += 32;
- }
- if (bitStrm->curBufSize < bitStrm->curPos + 1)
- break; // error
- nextData = bitStrm->mdatBuf[bitStrm->curPos++];
- crxFillBuffer(bitStrm);
- if (nextData)
- break;
- bitsLeft += 8;
- }
- _BitScanReverse((DWORD *)&nonZeroBit, (DWORD)nextData);
- result = (uint32_t)(bitsLeft + 7 - nonZeroBit);
- bitStrm->bitData = nextData << (32 - nonZeroBit);
- bitStrm->bitsLeft = nonZeroBit;
- }
- return result;
-}
-
-libraw_inline uint32_t crxBitstreamGetBits(CrxBitstream *bitStrm, int bits)
-{
- int bitsLeft = bitStrm->bitsLeft;
- uint32_t bitData = bitStrm->bitData;
- uint32_t nextWord;
- uint8_t nextByte;
- uint32_t result;
-
- if (bitsLeft < bits)
- {
- // get them from stream
- if (bitStrm->curPos + 4 <= bitStrm->curBufSize)
- {
- nextWord =
- _byteswap_ulong(*(uint32_t *)(bitStrm->mdatBuf + bitStrm->curPos));
- bitStrm->curPos += 4;
- crxFillBuffer(bitStrm);
- bitStrm->bitsLeft = 32 - (bits - bitsLeft);
- result = ((nextWord >> bitsLeft) | bitData) >> (32 - bits);
- bitStrm->bitData = nextWord << (bits - bitsLeft);
- return result;
- }
- // less than a word left - read byte at a time
- do
- {
- if (bitStrm->curPos >= bitStrm->curBufSize)
- break; // error
- bitsLeft += 8;
- nextByte = bitStrm->mdatBuf[bitStrm->curPos++];
- crxFillBuffer(bitStrm);
- bitData |= nextByte << (32 - bitsLeft);
- } while (bitsLeft < bits);
- }
- result = bitData >> (32 - bits); // 32-bits
- bitStrm->bitData = bitData << bits;
- bitStrm->bitsLeft = bitsLeft - bits;
- return result;
-}
-
-libraw_inline int crxPredictKParameter(int32_t prevK, int32_t bitCode,
- int32_t maxVal = 0)
-{
- int32_t newKParam = prevK - (bitCode < (1 << prevK >> 1)) +
- ((bitCode >> prevK) > 2) + ((bitCode >> prevK) > 5);
-
- return !maxVal || newKParam < maxVal ? newKParam : maxVal;
-}
-
-libraw_inline void crxDecodeSymbolL1(CrxBandParam *param,
- int32_t doMedianPrediction,
- int32_t notEOL = 0)
-{
- if (doMedianPrediction)
- {
- int32_t symb[4];
-
- int32_t delta = param->lineBuf0[1] - param->lineBuf0[0];
- symb[2] = param->lineBuf1[0];
- symb[0] = symb[1] = delta + symb[2];
- symb[3] = param->lineBuf0[1];
-
- param->lineBuf1[1] =
- symb[(((param->lineBuf0[0] < param->lineBuf1[0]) ^ (delta < 0)) << 1) +
- ((param->lineBuf1[0] < param->lineBuf0[1]) ^ (delta < 0))];
- }
- else
- param->lineBuf1[1] = param->lineBuf0[1];
-
- // get next error symbol
- uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
- if (bitCode >= 41)
- bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
- else if (param->kParam)
- bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) |
- (bitCode << param->kParam);
-
- // add converted (+/-) error code to predicted value
- param->lineBuf1[1] += -(bitCode & 1) ^ (bitCode >> 1);
-
- // for not end of the line - use one symbol ahead to estimate next K
- if (notEOL)
- {
- int32_t nextDelta = (param->lineBuf0[2] - param->lineBuf0[1]) << 1;
- bitCode = (bitCode + _abs(nextDelta)) >> 1;
- ++param->lineBuf0;
- }
-
- // update K parameter
- param->kParam = crxPredictKParameter(param->kParam, bitCode, 15);
-
- ++param->lineBuf1;
-}
-
-int crxDecodeLine(CrxBandParam *param)
-{
- int length = param->subbandWidth;
-
- param->lineBuf1[0] = param->lineBuf0[1];
- for (; length > 1; --length)
- {
- if (param->lineBuf1[0] != param->lineBuf0[1] ||
- param->lineBuf1[0] != param->lineBuf0[2])
- {
- crxDecodeSymbolL1(param, 1, 1);
- }
- else
- {
- int nSyms = 0;
- if (crxBitstreamGetBits(¶m->bitStream, 1))
- {
- nSyms = 1;
- while (crxBitstreamGetBits(¶m->bitStream, 1))
- {
- nSyms += JS[param->sParam];
- if (nSyms > length)
- {
- nSyms = length;
- break;
- }
- if (param->sParam < 31)
- ++param->sParam;
- if (nSyms == length)
- break;
- }
-
- if (nSyms < length)
- {
- if (J[param->sParam])
- nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]);
- if (param->sParam > 0)
- --param->sParam;
- if (nSyms > length)
- return -1;
- }
-
- length -= nSyms;
-
- // copy symbol nSyms times
- param->lineBuf0 += nSyms;
-
- // copy symbol nSyms times
- while (nSyms-- > 0)
- {
- param->lineBuf1[1] = param->lineBuf1[0];
- ++param->lineBuf1;
- }
- }
-
- if (length > 0)
- crxDecodeSymbolL1(param, 0, (length > 1));
- }
- }
-
- if (length == 1)
- crxDecodeSymbolL1(param, 1, 0);
-
- param->lineBuf1[1] = param->lineBuf1[0] + 1;
-
- return 0;
-}
-
-libraw_inline void crxDecodeSymbolL1Rounded(CrxBandParam *param,
- int32_t doSym = 1,
- int32_t doCode = 1)
-{
- int32_t sym = param->lineBuf0[1];
-
- if (doSym)
- {
- // calculate the next symbol gradient
- int32_t symb[4];
- int32_t deltaH = param->lineBuf0[1] - param->lineBuf0[0];
- symb[2] = param->lineBuf1[0];
- symb[0] = symb[1] = deltaH + symb[2];
- symb[3] = param->lineBuf0[1];
- sym =
- symb[(((param->lineBuf0[0] < param->lineBuf1[0]) ^ (deltaH < 0)) << 1) +
- ((param->lineBuf1[0] < param->lineBuf0[1]) ^ (deltaH < 0))];
- }
-
- uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
- if (bitCode >= 41)
- bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
- else if (param->kParam)
- bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) |
- (bitCode << param->kParam);
- int32_t code = -(bitCode & 1) ^ (bitCode >> 1);
- param->lineBuf1[1] = param->roundedBitsMask * 2 * code + (code >> 31) + sym;
-
- if (doCode)
- {
- if (param->lineBuf0[2] > param->lineBuf0[1])
- code = (param->lineBuf0[2] - param->lineBuf0[1] + param->roundedBitsMask -
- 1) >>
- param->roundedBits;
- else
- code = -(
- (param->lineBuf0[1] - param->lineBuf0[2] + param->roundedBitsMask) >>
- param->roundedBits);
-
- param->kParam = crxPredictKParameter(param->kParam,
- (bitCode + 2 * _abs(code)) >> 1, 15);
- }
- else
- param->kParam = crxPredictKParameter(param->kParam, bitCode, 15);
-
- ++param->lineBuf1;
-}
-
-int crxDecodeLineRounded(CrxBandParam *param)
-{
- int32_t valueReached = 0;
-
- param->lineBuf0[0] = param->lineBuf0[1];
- param->lineBuf1[0] = param->lineBuf0[1];
- int32_t length = param->subbandWidth;
-
- for (; length > 1; --length)
- {
- if (_abs(param->lineBuf0[2] - param->lineBuf0[1]) > param->roundedBitsMask)
- {
- crxDecodeSymbolL1Rounded(param);
- ++param->lineBuf0;
- valueReached = 1;
- }
- else if (valueReached || _abs(param->lineBuf0[0] - param->lineBuf1[0]) >
- param->roundedBitsMask)
- {
- crxDecodeSymbolL1Rounded(param);
- ++param->lineBuf0;
- valueReached = 0;
- }
- else
- {
- int nSyms = 0;
- if (crxBitstreamGetBits(¶m->bitStream, 1))
- {
- nSyms = 1;
- while (crxBitstreamGetBits(¶m->bitStream, 1))
- {
- nSyms += JS[param->sParam];
- if (nSyms > length)
- {
- nSyms = length;
- break;
- }
- if (param->sParam < 31)
- ++param->sParam;
- if (nSyms == length)
- break;
- }
- if (nSyms < length)
- {
- if (J[param->sParam])
- nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]);
- if (param->sParam > 0)
- --param->sParam;
- }
- if (nSyms > length)
- return -1;
- }
- length -= nSyms;
-
- // copy symbol nSyms times
- param->lineBuf0 += nSyms;
-
- // copy symbol nSyms times
- while (nSyms-- > 0)
- {
- param->lineBuf1[1] = param->lineBuf1[0];
- ++param->lineBuf1;
- }
-
- if (length > 1)
- {
- crxDecodeSymbolL1Rounded(param, 0);
- ++param->lineBuf0;
- valueReached = _abs(param->lineBuf0[1] - param->lineBuf0[0]) >
- param->roundedBitsMask;
- }
- else if (length == 1)
- crxDecodeSymbolL1Rounded(param, 0, 0);
- }
- }
- if (length == 1)
- crxDecodeSymbolL1Rounded(param, 1, 0);
-
- param->lineBuf1[1] = param->lineBuf1[0] + 1;
-
- return 0;
-}
-
-int crxDecodeLineNoRefPrevLine(CrxBandParam *param)
-{
- int32_t i = 0;
-
- for (; i < param->subbandWidth - 1; i++)
- {
- if (param->lineBuf0[i + 2] | param->lineBuf0[i + 1] | param->lineBuf1[i])
- {
- uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
- if (bitCode >= 41)
- bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
- else if (param->kParam)
- bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) |
- (bitCode << param->kParam);
- param->lineBuf1[i + 1] = -(bitCode & 1) ^ (bitCode >> 1);
- param->kParam = crxPredictKParameter(param->kParam, bitCode);
- if (param->lineBuf2[i + 1] - param->kParam <= 1)
- {
- if (param->kParam >= 15)
- param->kParam = 15;
- }
- else
- ++param->kParam;
- }
- else
- {
- int nSyms = 0;
- if (crxBitstreamGetBits(¶m->bitStream, 1))
- {
- nSyms = 1;
- if (i != param->subbandWidth - 1)
- {
- while (crxBitstreamGetBits(¶m->bitStream, 1))
- {
- nSyms += JS[param->sParam];
- if (i + nSyms > param->subbandWidth)
- {
- nSyms = param->subbandWidth - i;
- break;
+ if (bitStrm->curBufSize < 1) { // nothing read
+ throw std::exception();
}
- if (param->sParam < 31)
- ++param->sParam;
- if (i + nSyms == param->subbandWidth)
- break;
- }
- if (i + nSyms < param->subbandWidth)
- {
- if (J[param->sParam])
- nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]);
- if (param->sParam > 0)
- --param->sParam;
- }
- if (i + nSyms > param->subbandWidth)
- return -1;
+
+ bitStrm->mdatSize -= bitStrm->curBufSize;
}
- }
- else if (i > param->subbandWidth)
- return -1;
+ }
+}
- if (nSyms > 0)
- {
- memset(param->lineBuf1 + i + 1, 0, nSyms * sizeof(int32_t));
- memset(param->lineBuf2 + i, 0, nSyms * sizeof(int32_t));
- i += nSyms;
- }
+inline int crxBitstreamGetZeros(CrxBitstream* bitStrm)
+{
+// std::uint32_t bitData = bitStrm->bitData;
+ std::uint32_t nonZeroBit = 0;
+ std::uint64_t nextData = 0;
+ std::int32_t result = 0;
- if (i >= param->subbandWidth - 1)
- {
- if (i == param->subbandWidth - 1)
- {
- uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
- if (bitCode >= 41)
+ if (bitStrm->bitData) {
+ _BitScanReverse(&nonZeroBit, bitStrm->bitData);
+ result = 31 - nonZeroBit;
+ bitStrm->bitData <<= 32 - nonZeroBit;
+ bitStrm->bitsLeft -= 32 - nonZeroBit;
+ } else {
+ std::uint32_t bitsLeft = bitStrm->bitsLeft;
+
+ while (true) {
+ while (bitStrm->curPos + 4 <= bitStrm->curBufSize) {
+ nextData = _byteswap_ulong(*reinterpret_cast(bitStrm->mdatBuf + bitStrm->curPos));
+ bitStrm->curPos += 4;
+ crxFillBuffer(bitStrm);
+
+ if (nextData) {
+ _BitScanReverse(&nonZeroBit, static_cast(nextData));
+ result = bitsLeft + 31 - nonZeroBit;
+ bitStrm->bitData = nextData << (32 - nonZeroBit);
+ bitStrm->bitsLeft = nonZeroBit;
+ return result;
+ }
+
+ bitsLeft += 32;
+ }
+
+ if (bitStrm->curBufSize < bitStrm->curPos + 1) {
+ break; // error
+ }
+
+ nextData = bitStrm->mdatBuf[bitStrm->curPos++];
+ crxFillBuffer(bitStrm);
+
+ if (nextData) {
+ break;
+ }
+
+ bitsLeft += 8;
+ }
+
+ _BitScanReverse(&nonZeroBit, static_cast(nextData));
+ result = static_cast(bitsLeft + 7 - nonZeroBit);
+ bitStrm->bitData = nextData << (32 - nonZeroBit);
+ bitStrm->bitsLeft = nonZeroBit;
+ }
+
+ return result;
+}
+
+inline std::uint32_t crxBitstreamGetBits(CrxBitstream* bitStrm, int bits)
+{
+ int bitsLeft = bitStrm->bitsLeft;
+ std::uint32_t bitData = bitStrm->bitData;
+ std::uint32_t nextWord;
+ std::uint8_t nextByte;
+ std::uint32_t result;
+
+ if (bitsLeft < bits) {
+ // get them from stream
+ if (bitStrm->curPos + 4 <= bitStrm->curBufSize) {
+ nextWord = _byteswap_ulong(*reinterpret_cast(bitStrm->mdatBuf + bitStrm->curPos));
+ bitStrm->curPos += 4;
+ crxFillBuffer(bitStrm);
+ bitStrm->bitsLeft = 32 - (bits - bitsLeft);
+ result = ((nextWord >> bitsLeft) | bitData) >> (32 - bits);
+ bitStrm->bitData = nextWord << (bits - bitsLeft);
+ return result;
+ }
+
+ // less than a word left - read byte at a time
+ do {
+ if (bitStrm->curPos >= bitStrm->curBufSize) {
+ break; // error
+ }
+
+ bitsLeft += 8;
+ nextByte = bitStrm->mdatBuf[bitStrm->curPos++];
+ crxFillBuffer(bitStrm);
+ bitData |= nextByte << (32 - bitsLeft);
+ } while (bitsLeft < bits);
+ }
+
+ result = bitData >> (32 - bits); // 32-bits
+ bitStrm->bitData = bitData << bits;
+ bitStrm->bitsLeft = bitsLeft - bits;
+ return result;
+}
+
+inline std::int32_t crxPredictKParameter(std::int32_t prevK, std::int32_t bitCode, std::int32_t maxVal = 0)
+{
+ const std::int32_t newKParam =
+ prevK
+ - (bitCode < (1 << prevK >> 1))
+ + ((bitCode >> prevK) > 2) + ((bitCode >> prevK) > 5);
+
+ return
+ !maxVal || newKParam < maxVal
+ ? newKParam
+ : maxVal;
+}
+
+inline void crxDecodeSymbolL1(CrxBandParam* param, bool doMedianPrediction, bool notEOL = false)
+{
+ if (doMedianPrediction) {
+ const std::int32_t delta = param->lineBuf0[1] - param->lineBuf0[0];
+ const std::int32_t symb[4] = {
+ delta + param->lineBuf1[0],
+ delta + param->lineBuf1[0],
+ param->lineBuf1[0],
+ param->lineBuf0[1]
+ };
+
+ param->lineBuf1[1] = symb[
+ (((param->lineBuf0[0] < param->lineBuf1[0]) ^ (delta < 0)) << 1)
+ + ((param->lineBuf1[0] < param->lineBuf0[1]) ^ (delta < 0))
+ ];
+ } else {
+ param->lineBuf1[1] = param->lineBuf0[1];
+ }
+
+ // get next error symbol
+ std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
+
+ if (bitCode >= 41) {
+ bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
+ } else if (param->kParam) {
+ bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam);
+ }
+
+ // add converted (+/-) error code to predicted value
+ param->lineBuf1[1] += -(bitCode & 1) ^ (bitCode >> 1);
+
+ // for not end of the line - use one symbol ahead to estimate next K
+ if (notEOL) {
+ const std::int32_t nextDelta = (param->lineBuf0[2] - param->lineBuf0[1]) << 1;
+ bitCode = (bitCode + std::abs(nextDelta)) >> 1;
+ ++param->lineBuf0;
+ }
+
+ // update K parameter
+ param->kParam = crxPredictKParameter(param->kParam, bitCode, 15);
+
+ ++param->lineBuf1;
+}
+
+bool crxDecodeLine(CrxBandParam* param)
+{
+ int length = param->subbandWidth;
+
+ param->lineBuf1[0] = param->lineBuf0[1];
+
+ for (; length > 1; --length) {
+ if (param->lineBuf1[0] != param->lineBuf0[1] || param->lineBuf1[0] != param->lineBuf0[2]) {
+ crxDecodeSymbolL1(param, true, true);
+ } else {
+ if (crxBitstreamGetBits(¶m->bitStream, 1)) {
+ int nSyms = 1;
+
+ while (crxBitstreamGetBits(¶m->bitStream, 1)) {
+ nSyms += JS[param->sParam];
+
+ if (nSyms > length) {
+ nSyms = length;
+ break;
+ }
+
+ if (param->sParam < 31) {
+ ++param->sParam;
+ }
+
+ if (nSyms == length) {
+ break;
+ }
+ }
+
+ if (nSyms < length) {
+ if (J[param->sParam]) {
+ nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]);
+ }
+
+ if (param->sParam > 0) {
+ --param->sParam;
+ }
+
+ if (nSyms > length) {
+ return false;
+ }
+ }
+
+ length -= nSyms;
+
+ // copy symbol nSyms times
+ param->lineBuf0 += nSyms;
+
+ // copy symbol nSyms times
+ while (nSyms-- > 0) {
+ param->lineBuf1[1] = param->lineBuf1[0];
+ ++param->lineBuf1;
+ }
+ }
+
+ if (length > 0) {
+ crxDecodeSymbolL1(param, false, length > 1);
+ }
+ }
+ }
+
+ if (length == 1) {
+ crxDecodeSymbolL1(param, true, false);
+ }
+
+ param->lineBuf1[1] = param->lineBuf1[0] + 1;
+
+ return true;
+}
+
+inline void crxDecodeSymbolL1Rounded(CrxBandParam* param, bool doSym = true, bool doCode = true)
+{
+ std::int32_t sym = param->lineBuf0[1];
+
+ if (doSym) {
+ // calculate the next symbol gradient
+ const std::int32_t deltaH = param->lineBuf0[1] - param->lineBuf0[0];
+ const std::int32_t symb[4] = {
+ deltaH + param->lineBuf1[0],
+ deltaH + param->lineBuf1[0],
+ param->lineBuf1[0],
+ param->lineBuf0[1]
+ };
+ sym = symb[
+ (((param->lineBuf0[0] < param->lineBuf1[0]) ^ (deltaH < 0)) << 1)
+ + ((param->lineBuf1[0] < param->lineBuf0[1]) ^ (deltaH < 0))
+ ];
+ }
+
+ std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
+
+ if (bitCode >= 41) {
+ bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
+ } else if (param->kParam) {
+ bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam);
+ }
+
+ std::int32_t code = -(bitCode & 1) ^ (bitCode >> 1);
+ param->lineBuf1[1] = param->roundedBitsMask * 2 * code + (code < 0) + sym;
+
+ if (doCode) {
+ if (param->lineBuf0[2] > param->lineBuf0[1]) {
+ code = (param->lineBuf0[2] - param->lineBuf0[1] + param->roundedBitsMask - 1) >> param->roundedBits;
+ } else {
+ code = -((param->lineBuf0[1] - param->lineBuf0[2] + param->roundedBitsMask) >> param->roundedBits);
+ }
+
+ param->kParam = crxPredictKParameter(param->kParam, (bitCode + 2 * std::abs(code)) >> 1, 15);
+ } else {
+ param->kParam = crxPredictKParameter(param->kParam, bitCode, 15);
+ }
+
+ ++param->lineBuf1;
+}
+
+bool crxDecodeLineRounded(CrxBandParam* param)
+{
+ bool valueReached = false;
+
+ param->lineBuf0[0] = param->lineBuf0[1];
+ param->lineBuf1[0] = param->lineBuf0[1];
+ std::int32_t length = param->subbandWidth;
+
+ for (; length > 1; --length) {
+ if (std::abs(param->lineBuf0[2] - param->lineBuf0[1]) > param->roundedBitsMask) {
+ crxDecodeSymbolL1Rounded(param);
+ ++param->lineBuf0;
+ valueReached = true;
+ } else if (valueReached || std::abs(param->lineBuf0[0] - param->lineBuf1[0]) > param->roundedBitsMask) {
+ crxDecodeSymbolL1Rounded(param);
+ ++param->lineBuf0;
+ valueReached = false;
+ } else {
+ int nSyms = 0;
+
+ if (crxBitstreamGetBits(¶m->bitStream, 1)) {
+ nSyms = 1;
+
+ while (crxBitstreamGetBits(¶m->bitStream, 1)) {
+ nSyms += JS[param->sParam];
+
+ if (nSyms > length) {
+ nSyms = length;
+ break;
+ }
+
+ if (param->sParam < 31) {
+ ++param->sParam;
+ }
+
+ if (nSyms == length) {
+ break;
+ }
+ }
+
+ if (nSyms < length) {
+ if (J[param->sParam]) {
+ nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]);
+ }
+
+ if (param->sParam > 0) {
+ --param->sParam;
+ }
+ }
+
+ if (nSyms > length) {
+ return false;
+ }
+ }
+
+ length -= nSyms;
+
+ // copy symbol nSyms times
+ param->lineBuf0 += nSyms;
+
+ // copy symbol nSyms times
+ while (nSyms-- > 0) {
+ param->lineBuf1[1] = param->lineBuf1[0];
+ ++param->lineBuf1;
+ }
+
+ if (length > 1) {
+ crxDecodeSymbolL1Rounded(param, false);
+ ++param->lineBuf0;
+ valueReached = std::abs(param->lineBuf0[1] - param->lineBuf0[0]) > param->roundedBitsMask;
+ } else if (length == 1) {
+ crxDecodeSymbolL1Rounded(param, false, false);
+ }
+ }
+ }
+
+ if (length == 1) {
+ crxDecodeSymbolL1Rounded(param, true, false);
+ }
+
+ param->lineBuf1[1] = param->lineBuf1[0] + 1;
+
+ return true;
+}
+
+bool crxDecodeLineNoRefPrevLine(CrxBandParam* param)
+{
+ std::int32_t i = 0;
+
+ for (; i < param->subbandWidth - 1; ++i) {
+ if (param->lineBuf0[i + 2] || param->lineBuf0[i + 1] || param->lineBuf1[i]) {
+ std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
+
+ if (bitCode >= 41) {
+ bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
+ } else if (param->kParam) {
+ bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam);
+ }
+
+ param->lineBuf1[i + 1] = -(bitCode & 1) ^ (bitCode >> 1);
+ param->kParam = crxPredictKParameter(param->kParam, bitCode);
+
+ if (param->lineBuf2[i + 1] - param->kParam <= 1) {
+ if (param->kParam >= 15) {
+ param->kParam = 15;
+ }
+ } else {
+ ++param->kParam;
+ }
+ } else {
+ int nSyms = 0;
+
+ if (crxBitstreamGetBits(¶m->bitStream, 1)) {
+ nSyms = 1;
+
+ if (i != param->subbandWidth - 1) {
+ while (crxBitstreamGetBits(¶m->bitStream, 1)) {
+ nSyms += JS[param->sParam];
+
+ if (i + nSyms > param->subbandWidth) {
+ nSyms = param->subbandWidth - i;
+ break;
+ }
+
+ if (param->sParam < 31) {
+ ++param->sParam;
+ }
+
+ if (i + nSyms == param->subbandWidth) {
+ break;
+ }
+ }
+
+ if (i + nSyms < param->subbandWidth) {
+ if (J[param->sParam]) {
+ nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]);
+ }
+
+ if (param->sParam > 0) {
+ --param->sParam;
+ }
+ }
+
+ if (i + nSyms > param->subbandWidth) {
+ return false;
+ }
+ }
+ } else if (i > param->subbandWidth) {
+ return false;
+ }
+
+ if (nSyms > 0) {
+ memset(param->lineBuf1 + i + 1, 0, nSyms * sizeof(std::int32_t));
+ memset(param->lineBuf2 + i, 0, nSyms * sizeof(std::int32_t));
+ i += nSyms;
+ }
+
+ if (i >= param->subbandWidth - 1) {
+ if (i == param->subbandWidth - 1) {
+ std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
+
+ if (bitCode >= 41) {
+ bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
+ } else if (param->kParam) {
+ bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam);
+ }
+
+ param->lineBuf1[i + 1] = -((bitCode + 1) & 1) ^ ((bitCode + 1) >> 1);
+ param->kParam = crxPredictKParameter(param->kParam, bitCode, 15);
+ param->lineBuf2[i] = param->kParam;
+ }
+
+ continue;
+ } else {
+ std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
+
+ if (bitCode >= 41) {
+ bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
+ } else if (param->kParam) {
+ bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam);
+ }
+
+ param->lineBuf1[i + 1] = -((bitCode + 1) & 1) ^ ((bitCode + 1) >> 1);
+ param->kParam = crxPredictKParameter(param->kParam, bitCode);
+
+ if (param->lineBuf2[i + 1] - param->kParam <= 1) {
+ if (param->kParam >= 15) {
+ param->kParam = 15;
+ }
+ } else {
+ ++param->kParam;
+ }
+ }
+ }
+
+ param->lineBuf2[i] = param->kParam;
+ }
+
+ if (i == param->subbandWidth - 1) {
+ std::int32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
+
+ if (bitCode >= 41) {
bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
- else if (param->kParam)
- bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) |
- (bitCode << param->kParam);
- param->lineBuf1[i + 1] = -((bitCode + 1) & 1) ^ ((bitCode + 1) >> 1);
- param->kParam = crxPredictKParameter(param->kParam, bitCode, 15);
- param->lineBuf2[i] = param->kParam;
- }
- continue;
- }
- else
- {
- uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
- if (bitCode >= 41)
- bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
- else if (param->kParam)
- bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) |
- (bitCode << param->kParam);
- param->lineBuf1[i + 1] = -((bitCode + 1) & 1) ^ ((bitCode + 1) >> 1);
- param->kParam = crxPredictKParameter(param->kParam, bitCode);
- if (param->lineBuf2[i + 1] - param->kParam <= 1)
- {
- if (param->kParam >= 15)
- param->kParam = 15;
- }
- else
- ++param->kParam;
- }
- }
- param->lineBuf2[i] = param->kParam;
- }
- if (i == param->subbandWidth - 1)
- {
- int32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
- if (bitCode >= 41)
- bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
- else if (param->kParam)
- bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) |
- (bitCode << param->kParam);
- param->lineBuf1[i + 1] = -(bitCode & 1) ^ (bitCode >> 1);
- param->kParam = crxPredictKParameter(param->kParam, bitCode, 15);
- param->lineBuf2[i] = param->kParam;
- }
-
- return 0;
-}
-
-int crxDecodeTopLine(CrxBandParam *param)
-{
- param->lineBuf1[0] = 0;
-
- int32_t length = param->subbandWidth;
-
- // read the line from bitstream
- for (; length > 1; --length)
- {
- if (param->lineBuf1[0])
- param->lineBuf1[1] = param->lineBuf1[0];
- else
- {
- int nSyms = 0;
- if (crxBitstreamGetBits(¶m->bitStream, 1))
- {
- nSyms = 1;
- while (crxBitstreamGetBits(¶m->bitStream, 1))
- {
- nSyms += JS[param->sParam];
- if (nSyms > length)
- {
- nSyms = length;
- break;
- }
- if (param->sParam < 31)
- ++param->sParam;
- if (nSyms == length)
- break;
- }
- if (nSyms < length)
- {
- if (J[param->sParam])
- nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]);
- if (param->sParam > 0)
- --param->sParam;
- if (nSyms > length)
- return -1;
+ } else if (param->kParam) {
+ bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam);
}
- length -= nSyms;
-
- // copy symbol nSyms times
- while (nSyms-- > 0)
- {
- param->lineBuf1[1] = param->lineBuf1[0];
- ++param->lineBuf1;
- }
-
- if (length <= 0)
- break;
- }
-
- param->lineBuf1[1] = 0;
+ param->lineBuf1[i + 1] = -(bitCode & 1) ^ (bitCode >> 1);
+ param->kParam = crxPredictKParameter(param->kParam, bitCode, 15);
+ param->lineBuf2[i] = param->kParam;
}
- uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
- if (bitCode >= 41)
- bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
- else if (param->kParam)
- bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) |
- (bitCode << param->kParam);
- param->lineBuf1[1] += -(bitCode & 1) ^ (bitCode >> 1);
- param->kParam = crxPredictKParameter(param->kParam, bitCode, 15);
- ++param->lineBuf1;
- }
-
- if (length == 1)
- {
- param->lineBuf1[1] = param->lineBuf1[0];
- uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
- if (bitCode >= 41)
- bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
- else if (param->kParam)
- bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) |
- (bitCode << param->kParam);
- param->lineBuf1[1] += -(bitCode & 1) ^ (bitCode >> 1);
- param->kParam = crxPredictKParameter(param->kParam, bitCode, 15);
- ++param->lineBuf1;
- }
-
- param->lineBuf1[1] = param->lineBuf1[0] + 1;
-
- return 0;
+ return true;
}
-int crxDecodeTopLineRounded(CrxBandParam *param)
+bool crxDecodeTopLine(CrxBandParam* param)
{
- param->lineBuf1[0] = 0;
+ param->lineBuf1[0] = 0;
- int32_t length = param->subbandWidth;
+ std::int32_t length = param->subbandWidth;
- // read the line from bitstream
- for (; length > 1; --length)
- {
- if (_abs(param->lineBuf1[0]) > param->roundedBitsMask)
- param->lineBuf1[1] = param->lineBuf1[0];
- else
- {
- int nSyms = 0;
- if (crxBitstreamGetBits(¶m->bitStream, 1))
- {
- nSyms = 1;
- while (crxBitstreamGetBits(¶m->bitStream, 1))
- {
- nSyms += JS[param->sParam];
- if (nSyms > length)
- {
- nSyms = length;
- break;
- }
- if (param->sParam < 31)
- ++param->sParam;
- if (nSyms == length)
- break;
+ // read the line from bitstream
+ for (; length > 1; --length) {
+ if (param->lineBuf1[0]) {
+ param->lineBuf1[1] = param->lineBuf1[0];
+ } else {
+ if (crxBitstreamGetBits(¶m->bitStream, 1)) {
+ int nSyms = 1;
+
+ while (crxBitstreamGetBits(¶m->bitStream, 1)) {
+ nSyms += JS[param->sParam];
+
+ if (nSyms > length) {
+ nSyms = length;
+ break;
+ }
+
+ if (param->sParam < 31) {
+ ++param->sParam;
+ }
+
+ if (nSyms == length) {
+ break;
+ }
+ }
+
+ if (nSyms < length) {
+ if (J[param->sParam]) {
+ nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]);
+ }
+
+ if (param->sParam > 0) {
+ --param->sParam;
+ }
+
+ if (nSyms > length) {
+ return false;
+ }
+ }
+
+ length -= nSyms;
+
+ // copy symbol nSyms times
+ while (nSyms-- > 0) {
+ param->lineBuf1[1] = param->lineBuf1[0];
+ ++param->lineBuf1;
+ }
+
+ if (length <= 0) {
+ break;
+ }
+ }
+
+ param->lineBuf1[1] = 0;
}
- if (nSyms < length)
- {
- if (J[param->sParam])
- nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]);
- if (param->sParam > 0)
- --param->sParam;
- if (nSyms > length)
- return -1;
+
+ std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
+
+ if (bitCode >= 41) {
+ bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
+ } else if (param->kParam) {
+ bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam);
}
- }
- length -= nSyms;
+ param->lineBuf1[1] += -(bitCode & 1) ^ (bitCode >> 1);
+ param->kParam = crxPredictKParameter(param->kParam, bitCode, 15);
+ ++param->lineBuf1;
+ }
- // copy symbol nSyms times
- while (nSyms-- > 0)
- {
+ if (length == 1) {
param->lineBuf1[1] = param->lineBuf1[0];
+ std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
+
+ if (bitCode >= 41) {
+ bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
+ } else if (param->kParam) {
+ bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam);
+ }
+
+ param->lineBuf1[1] += -(bitCode & 1) ^ (bitCode >> 1);
+ param->kParam = crxPredictKParameter(param->kParam, bitCode, 15);
++param->lineBuf1;
- }
-
- if (length <= 0)
- break;
-
- param->lineBuf1[1] = 0;
}
- uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
- if (bitCode >= 41)
- bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
- else if (param->kParam)
- bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) |
- (bitCode << param->kParam);
+ param->lineBuf1[1] = param->lineBuf1[0] + 1;
- int32_t sVal = -(bitCode & 1) ^ (bitCode >> 1);
- param->lineBuf1[1] += param->roundedBitsMask * 2 * sVal + (sVal >> 31);
- param->kParam = crxPredictKParameter(param->kParam, bitCode, 15);
- ++param->lineBuf1;
- }
-
- if (length == 1)
- {
- uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
- if (bitCode >= 41)
- bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
- else if (param->kParam)
- bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) |
- (bitCode << param->kParam);
- int32_t sVal = -(bitCode & 1) ^ (bitCode >> 1);
- param->lineBuf1[1] += param->roundedBitsMask * 2 * sVal + (sVal >> 31);
- param->kParam = crxPredictKParameter(param->kParam, bitCode, 15);
- ++param->lineBuf1;
- }
-
- param->lineBuf1[1] = param->lineBuf1[0] + 1;
-
- return 0;
+ return true;
}
-int crxDecodeTopLineNoRefPrevLine(CrxBandParam *param)
+bool crxDecodeTopLineRounded(CrxBandParam* param)
{
- param->lineBuf0[0] = 0;
- param->lineBuf1[0] = 0;
- int32_t length = param->subbandWidth;
- for (; length > 1; --length)
- {
- if (param->lineBuf1[0])
- {
- uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
- if (bitCode >= 41)
- bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
- else if (param->kParam)
- bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) |
- (bitCode << param->kParam);
- param->lineBuf1[1] = -(bitCode & 1) ^ (bitCode >> 1);
- param->kParam = crxPredictKParameter(param->kParam, bitCode, 15);
- }
- else
- {
- int nSyms = 0;
- if (crxBitstreamGetBits(¶m->bitStream, 1))
- {
- nSyms = 1;
- while (crxBitstreamGetBits(¶m->bitStream, 1))
- {
- nSyms += JS[param->sParam];
- if (nSyms > length)
- {
- nSyms = length;
- break;
- }
- if (param->sParam < 31)
- ++param->sParam;
- if (nSyms == length)
- break;
- }
- if (nSyms < length)
- {
- if (J[param->sParam])
- nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]);
- if (param->sParam > 0)
- --param->sParam;
- if (nSyms > length)
- return -1;
- }
- }
+ param->lineBuf1[0] = 0;
- length -= nSyms;
+ std::int32_t length = param->subbandWidth;
- // copy symbol nSyms times
- while (nSyms-- > 0)
- {
- param->lineBuf2[0] = 0;
- param->lineBuf1[1] = 0;
+ // read the line from bitstream
+ for (; length > 1; --length) {
+ if (std::abs(param->lineBuf1[0]) > param->roundedBitsMask) {
+ param->lineBuf1[1] = param->lineBuf1[0];
+ } else {
+ int nSyms = 0;
+
+ if (crxBitstreamGetBits(¶m->bitStream, 1)) {
+ nSyms = 1;
+
+ while (crxBitstreamGetBits(¶m->bitStream, 1)) {
+ nSyms += JS[param->sParam];
+
+ if (nSyms > length) {
+ nSyms = length;
+ break;
+ }
+
+ if (param->sParam < 31) {
+ ++param->sParam;
+ }
+
+ if (nSyms == length) {
+ break;
+ }
+ }
+
+ if (nSyms < length) {
+ if (J[param->sParam]) {
+ nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]);
+ }
+
+ if (param->sParam > 0) {
+ --param->sParam;
+ }
+
+ if (nSyms > length) {
+ return false;
+ }
+ }
+ }
+
+ length -= nSyms;
+
+ // copy symbol nSyms times
+ while (nSyms-- > 0) {
+ param->lineBuf1[1] = param->lineBuf1[0];
+ ++param->lineBuf1;
+ }
+
+ if (length <= 0) {
+ break;
+ }
+
+ param->lineBuf1[1] = 0;
+ }
+
+ std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
+
+ if (bitCode >= 41) {
+ bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
+ } else if (param->kParam) {
+ bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam);
+ }
+
+ const std::int32_t sVal = -(bitCode & 1) ^ (bitCode >> 1);
+ param->lineBuf1[1] += param->roundedBitsMask * 2 * sVal + (sVal >> 31);
+ param->kParam = crxPredictKParameter(param->kParam, bitCode, 15);
++param->lineBuf1;
+ }
+
+ if (length == 1) {
+ std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
+
+ if (bitCode >= 41) {
+ bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
+ } else if (param->kParam) {
+ bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam);
+ }
+
+ const std::int32_t sVal = -(bitCode & 1) ^ (bitCode >> 1);
+ param->lineBuf1[1] += param->roundedBitsMask * 2 * sVal + (sVal >> 31);
+ param->kParam = crxPredictKParameter(param->kParam, bitCode, 15);
+ ++param->lineBuf1;
+ }
+
+ param->lineBuf1[1] = param->lineBuf1[0] + 1;
+
+ return true;
+}
+
+bool crxDecodeTopLineNoRefPrevLine(CrxBandParam* param)
+{
+ param->lineBuf0[0] = 0;
+ param->lineBuf1[0] = 0;
+ std::int32_t length = param->subbandWidth;
+
+ for (; length > 1; --length) {
+ if (param->lineBuf1[0]) {
+ std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
+
+ if (bitCode >= 41) {
+ bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
+ } else if (param->kParam) {
+ bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam);
+ }
+
+ param->lineBuf1[1] = -(bitCode & 1) ^ (bitCode >> 1);
+ param->kParam = crxPredictKParameter(param->kParam, bitCode, 15);
+ } else {
+ int nSyms = 0;
+
+ if (crxBitstreamGetBits(¶m->bitStream, 1)) {
+ nSyms = 1;
+
+ while (crxBitstreamGetBits(¶m->bitStream, 1)) {
+ nSyms += JS[param->sParam];
+
+ if (nSyms > length) {
+ nSyms = length;
+ break;
+ }
+
+ if (param->sParam < 31) {
+ ++param->sParam;
+ }
+
+ if (nSyms == length) {
+ break;
+ }
+ }
+
+ if (nSyms < length) {
+ if (J[param->sParam]) {
+ nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]);
+ }
+
+ if (param->sParam > 0) {
+ --param->sParam;
+ }
+
+ if (nSyms > length) {
+ return false;
+ }
+ }
+ }
+
+ length -= nSyms;
+
+ // copy symbol nSyms times
+ while (nSyms-- > 0) {
+ param->lineBuf2[0] = 0;
+ param->lineBuf1[1] = 0;
+ ++param->lineBuf1;
+ ++param->lineBuf2;
+ }
+
+ if (length <= 0) {
+ break;
+ }
+
+ std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
+
+ if (bitCode >= 41) {
+ bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
+ } else if (param->kParam) {
+ bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam);
+ }
+
+ param->lineBuf1[1] = -((bitCode + 1) & 1) ^ ((bitCode + 1) >> 1);
+ param->kParam = crxPredictKParameter(param->kParam, bitCode, 15);
+ }
+
+ param->lineBuf2[0] = param->kParam;
++param->lineBuf2;
- }
-
- if (length <= 0)
- break;
- uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
- if (bitCode >= 41)
- bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
- else if (param->kParam)
- bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) |
- (bitCode << param->kParam);
- param->lineBuf1[1] = -((bitCode + 1) & 1) ^ ((bitCode + 1) >> 1);
- param->kParam = crxPredictKParameter(param->kParam, bitCode, 15);
+ ++param->lineBuf1;
}
- param->lineBuf2[0] = param->kParam;
- ++param->lineBuf2;
- ++param->lineBuf1;
- }
- if (length == 1)
- {
- uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
- if (bitCode >= 41)
- bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
- else if (param->kParam)
- bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) |
- (bitCode << param->kParam);
- param->lineBuf1[1] = -(bitCode & 1) ^ (bitCode >> 1);
- param->kParam = crxPredictKParameter(param->kParam, bitCode, 15);
- param->lineBuf2[0] = param->kParam;
- ++param->lineBuf1;
- }
+ if (length == 1) {
+ std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream);
- param->lineBuf1[1] = 0;
-
- return 0;
-}
-
-int crxDecodeLine(CrxBandParam *param, uint8_t *bandBuf)
-{
- if (!param || !bandBuf)
- return -1;
- if (param->curLine >= param->subbandHeight)
- return -1;
-
- if (param->curLine == 0)
- {
- int32_t lineLength = param->subbandWidth + 2;
-
- param->sParam = 0;
- param->kParam = 0;
- if (param->supportsPartial)
- {
- if (param->roundedBitsMask <= 0)
- {
- param->lineBuf0 = (int32_t *)param->paramData;
- param->lineBuf1 = param->lineBuf0 + lineLength;
- int32_t *lineBuf = param->lineBuf1 + 1;
- if (crxDecodeTopLine(param))
- return -1;
- memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t));
- ++param->curLine;
- }
- else
- {
- param->roundedBits = 1;
- if (param->roundedBitsMask & ~1)
- {
- while (param->roundedBitsMask >> param->roundedBits)
- ++param->roundedBits;
+ if (bitCode >= 41) {
+ bitCode = crxBitstreamGetBits(¶m->bitStream, 21);
+ } else if (param->kParam) {
+ bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam);
}
- param->lineBuf0 = (int32_t *)param->paramData;
- param->lineBuf1 = param->lineBuf0 + lineLength;
- int32_t *lineBuf = param->lineBuf1 + 1;
- if (crxDecodeTopLineRounded(param))
- return -1;
- memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t));
- ++param->curLine;
- }
+
+ param->lineBuf1[1] = -(bitCode & 1) ^ (bitCode >> 1);
+ param->kParam = crxPredictKParameter(param->kParam, bitCode, 15);
+ param->lineBuf2[0] = param->kParam;
+ ++param->lineBuf1;
}
- else
- {
- param->lineBuf2 = (int32_t *)param->nonProgrData;
- param->lineBuf0 = (int32_t *)param->paramData;
- param->lineBuf1 = param->lineBuf0 + lineLength;
- int32_t *lineBuf = param->lineBuf1 + 1;
- if (crxDecodeTopLineNoRefPrevLine(param))
- return -1;
- memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t));
- ++param->curLine;
- }
- }
- else if (!param->supportsPartial)
- {
- int32_t lineLength = param->subbandWidth + 2;
- param->lineBuf2 = (int32_t *)param->nonProgrData;
- if (param->curLine & 1)
- {
- param->lineBuf1 = (int32_t *)param->paramData;
- param->lineBuf0 = param->lineBuf1 + lineLength;
- }
- else
- {
- param->lineBuf0 = (int32_t *)param->paramData;
- param->lineBuf1 = param->lineBuf0 + lineLength;
- }
- int32_t *lineBuf = param->lineBuf1 + 1;
- if (crxDecodeLineNoRefPrevLine(param))
- return -1;
- memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t));
- ++param->curLine;
- }
- else if (param->roundedBitsMask <= 0)
- {
- int32_t lineLength = param->subbandWidth + 2;
- if (param->curLine & 1)
- {
- param->lineBuf1 = (int32_t *)param->paramData;
- param->lineBuf0 = param->lineBuf1 + lineLength;
- }
- else
- {
- param->lineBuf0 = (int32_t *)param->paramData;
- param->lineBuf1 = param->lineBuf0 + lineLength;
- }
- int32_t *lineBuf = param->lineBuf1 + 1;
- if (crxDecodeLine(param))
- return -1;
- memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t));
- ++param->curLine;
- }
- else
- {
- int32_t lineLength = param->subbandWidth + 2;
- if (param->curLine & 1)
- {
- param->lineBuf1 = (int32_t *)param->paramData;
- param->lineBuf0 = param->lineBuf1 + lineLength;
- }
- else
- {
- param->lineBuf0 = (int32_t *)param->paramData;
- param->lineBuf1 = param->lineBuf0 + lineLength;
- }
- int32_t *lineBuf = param->lineBuf1 + 1;
- if (crxDecodeLineRounded(param))
- return -1;
- memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t));
- ++param->curLine;
- }
- return 0;
+
+ param->lineBuf1[1] = 0;
+
+ return true;
}
-int crxDecodeLineWithIQuantization(CrxSubband *subband)
+bool crxDecodeLine(CrxBandParam* param, std::uint8_t* bandBuf)
{
- int32_t q_step_tbl[6] = {0x28, 0x2D, 0x33, 0x39, 0x40, 0x48};
-
- if (!subband->dataSize)
- {
- memset(subband->bandBuf, 0, subband->bandSize);
- return 0;
- }
-
- if (subband->supportsPartial)
- {
- uint32_t bitCode = crxBitstreamGetZeros(&subband->bandParam->bitStream);
- if (bitCode >= 23)
- bitCode = crxBitstreamGetBits(&subband->bandParam->bitStream, 8);
- else if (subband->paramK)
- bitCode =
- crxBitstreamGetBits(&subband->bandParam->bitStream, subband->paramK) |
- (bitCode << subband->paramK);
-
- subband->quantValue +=
- -(bitCode & 1) ^ (bitCode >> 1); // converting encoded to signed integer
- subband->paramK = crxPredictKParameter(subband->paramK, bitCode);
- if (subband->paramK > 7)
- return -1;
- }
- if (crxDecodeLine(subband->bandParam, subband->bandBuf))
- return -1;
-
- if (subband->width <= 0)
- return 0LL;
-
- // update subband buffers
- int32_t *bandBuf = (int32_t *)subband->bandBuf;
- int32_t qScale =
- q_step_tbl[subband->quantValue % 6] >> (6 - subband->quantValue / 6);
- if (subband->quantValue / 6 >= 6)
- qScale = q_step_tbl[subband->quantValue % 6] *
- (1 << (subband->quantValue / 6 + 26));
-
- if (qScale != 1)
- for (int32_t i = 0; i < subband->width; i++)
- bandBuf[i] *= qScale;
-
- return 0;
-}
-
-void crxHorizontal53(int32_t *lineBufLA, int32_t *lineBufLB,
- CrxWaveletTransform *wavelet, uint32_t tileFlag)
-{
- int32_t *band0Buf = wavelet->subband0Buf;
- int32_t *band1Buf = wavelet->subband1Buf;
- int32_t *band2Buf = wavelet->subband2Buf;
- int32_t *band3Buf = wavelet->subband3Buf;
-
- if (wavelet->width <= 1)
- {
- lineBufLA[0] = band0Buf[0];
- lineBufLB[0] = band2Buf[0];
- }
- else
- {
- if (tileFlag & E_HAS_TILES_ON_THE_LEFT)
- {
- lineBufLA[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
- lineBufLB[0] = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2);
- ++band1Buf;
- ++band3Buf;
+ if (!param || !bandBuf) {
+ return false;
}
- else
- {
- lineBufLA[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1);
- lineBufLB[0] = band2Buf[0] - ((band3Buf[0] + 1) >> 1);
+
+ if (param->curLine >= param->subbandHeight) {
+ return false;
}
- ++band0Buf;
- ++band2Buf;
- for (int i = 0; i < wavelet->width - 3; i += 2)
- {
- int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
- lineBufLA[1] = band1Buf[0] + ((delta + lineBufLA[0]) >> 1);
- lineBufLA[2] = delta;
+ if (param->curLine == 0) {
+ const std::int32_t lineLength = param->subbandWidth + 2;
- delta = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2);
- lineBufLB[1] = band3Buf[0] + ((delta + lineBufLB[0]) >> 1);
- lineBufLB[2] = delta;
+ param->sParam = 0;
+ param->kParam = 0;
- ++band0Buf;
- ++band1Buf;
- ++band2Buf;
- ++band3Buf;
- lineBufLA += 2;
- lineBufLB += 2;
- }
- if (tileFlag & E_HAS_TILES_ON_THE_RIGHT)
- {
- int32_t deltaA = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
- lineBufLA[1] = band1Buf[0] + ((deltaA + lineBufLA[0]) >> 1);
+ if (param->supportsPartial) {
+ if (param->roundedBitsMask <= 0) {
+ param->lineBuf0 = param->paramData;
+ param->lineBuf1 = param->lineBuf0 + lineLength;
+ const std::int32_t* const lineBuf = param->lineBuf1 + 1;
- int32_t deltaB = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2);
- lineBufLB[1] = band3Buf[0] + ((deltaB + lineBufLB[0]) >> 1);
+ if (!crxDecodeTopLine(param)) {
+ return false;
+ }
- if (wavelet->width & 1)
- {
- lineBufLA[2] = deltaA;
- lineBufLB[2] = deltaB;
- }
- }
- else if (wavelet->width & 1)
- {
- lineBufLA[1] =
- band1Buf[0] +
- ((lineBufLA[0] + band0Buf[0] - ((band1Buf[0] + 1) >> 1)) >> 1);
- lineBufLA[2] = band0Buf[0] - ((band1Buf[0] + 1) >> 1);
+ memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(std::int32_t));
+ ++param->curLine;
+ } else {
+ param->roundedBits = 1;
- lineBufLB[1] =
- band3Buf[0] +
- ((lineBufLB[0] + band2Buf[0] - ((band3Buf[0] + 1) >> 1)) >> 1);
- lineBufLB[2] = band2Buf[0] - ((band3Buf[0] + 1) >> 1);
- }
- else
- {
- lineBufLA[1] = lineBufLA[0] + band1Buf[0];
- lineBufLB[1] = lineBufLB[0] + band3Buf[0];
- }
- }
-}
+ if (param->roundedBitsMask & ~1) {
+ while (param->roundedBitsMask >> param->roundedBits) {
+ ++param->roundedBits;
+ }
+ }
-int32_t *crxIdwt53FilterGetLine(CrxPlaneComp *comp, int32_t level)
-{
- int32_t *result = comp->waveletTransform[level]
- .lineBuf[(comp->waveletTransform[level].fltTapH -
- comp->waveletTransform[level].curH + 5) %
- 5 +
- 3];
- comp->waveletTransform[level].curH--;
- return result;
-}
+ param->lineBuf0 = param->paramData;
+ param->lineBuf1 = param->lineBuf0 + lineLength;
+ const std::int32_t* const lineBuf = param->lineBuf1 + 1;
-int crxIdwt53FilterDecode(CrxPlaneComp *comp, int32_t level)
-{
- if (comp->waveletTransform[level].curH)
- return 0;
+ if (!crxDecodeTopLineRounded(param)) {
+ return false;
+ }
- CrxSubband *sband = comp->subBands + 3 * level;
+ memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(std::int32_t));
+ ++param->curLine;
+ }
+ } else {
+ param->lineBuf2 = param->nonProgrData;
+ param->lineBuf0 = param->paramData;
+ param->lineBuf1 = param->lineBuf0 + lineLength;
+ const std::int32_t* const lineBuf = param->lineBuf1 + 1;
- if (comp->waveletTransform[level].height - 3 <=
- comp->waveletTransform[level].curLine &&
- !(comp->tileFlag & E_HAS_TILES_ON_THE_BOTTOM))
- {
- if (comp->waveletTransform[level].height & 1)
- {
- if (level)
- {
- if (crxIdwt53FilterDecode(comp, level - 1))
- return -1;
- }
- else if (crxDecodeLineWithIQuantization(sband))
- return -1;
+ if (!crxDecodeTopLineNoRefPrevLine(param)) {
+ return false;
+ }
- if (crxDecodeLineWithIQuantization(sband + 1))
- return -1;
- }
- }
- else
- {
- if (level)
- {
- if (crxIdwt53FilterDecode(comp, level - 1))
- return -1;
- }
- else if (crxDecodeLineWithIQuantization(sband)) // LL band
- return -1;
-
- if (crxDecodeLineWithIQuantization(sband + 1) || // HL band
- crxDecodeLineWithIQuantization(sband + 2) || // LH band
- crxDecodeLineWithIQuantization(sband + 3)) // HH band
- return -1;
- }
-
- return 0;
-}
-
-int crxIdwt53FilterTransform(CrxPlaneComp *comp, uint32_t level)
-{
- CrxWaveletTransform *wavelet = comp->waveletTransform + level;
-
- if (wavelet->curH)
- return 0;
-
- if (wavelet->curLine >= wavelet->height - 3)
- {
- if (!(comp->tileFlag & E_HAS_TILES_ON_THE_BOTTOM))
- {
- if (wavelet->height & 1)
- {
- if (level)
- {
- if (!wavelet[-1].curH)
- if (crxIdwt53FilterTransform(comp, level - 1))
- return -1;
- wavelet->subband0Buf = crxIdwt53FilterGetLine(comp, level - 1);
+ memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(std::int32_t));
+ ++param->curLine;
}
- int32_t *band0Buf = wavelet->subband0Buf;
- int32_t *band1Buf = wavelet->subband1Buf;
- int32_t *lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3];
- int32_t *lineBufH1 = wavelet->lineBuf[(wavelet->fltTapH + 1) % 5 + 3];
- int32_t *lineBufH2 = wavelet->lineBuf[(wavelet->fltTapH + 2) % 5 + 3];
+ } else if (!param->supportsPartial) {
+ const std::int32_t lineLength = param->subbandWidth + 2;
+ param->lineBuf2 = param->nonProgrData;
+
+ if (param->curLine & 1) {
+ param->lineBuf1 = param->paramData;
+ param->lineBuf0 = param->lineBuf1 + lineLength;
+ } else {
+ param->lineBuf0 = param->paramData;
+ param->lineBuf1 = param->lineBuf0 + lineLength;
+ }
+
+ const std::int32_t* const lineBuf = param->lineBuf1 + 1;
+
+ if (!crxDecodeLineNoRefPrevLine(param)) {
+ return false;
+ }
+
+ memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(std::int32_t));
+ ++param->curLine;
+ } else if (param->roundedBitsMask <= 0) {
+ const std::int32_t lineLength = param->subbandWidth + 2;
+
+ if (param->curLine & 1) {
+ param->lineBuf1 = param->paramData;
+ param->lineBuf0 = param->lineBuf1 + lineLength;
+ } else {
+ param->lineBuf0 = param->paramData;
+ param->lineBuf1 = param->lineBuf0 + lineLength;
+ }
+
+ const std::int32_t* const lineBuf = param->lineBuf1 + 1;
+
+ if (!crxDecodeLine(param)) {
+ return false;
+ }
+
+ memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(std::int32_t));
+ ++param->curLine;
+ } else {
+ const std::int32_t lineLength = param->subbandWidth + 2;
+
+ if (param->curLine & 1) {
+ param->lineBuf1 = param->paramData;
+ param->lineBuf0 = param->lineBuf1 + lineLength;
+ } else {
+ param->lineBuf0 = param->paramData;
+ param->lineBuf1 = param->lineBuf0 + lineLength;
+ }
+
+ const std::int32_t* const lineBuf = param->lineBuf1 + 1;
+
+ if (!crxDecodeLineRounded(param)) {
+ return false;
+ }
+
+ memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(std::int32_t));
+ ++param->curLine;
+ }
+
+ return true;
+}
+
+bool crxDecodeLineWithIQuantization(CrxSubband* subband)
+{
+ constexpr std::int32_t q_step_tbl[6] = {0x28, 0x2D, 0x33, 0x39, 0x40, 0x48};
+
+ if (!subband->dataSize) {
+ memset(subband->bandBuf, 0, subband->bandSize);
+ return true;
+ }
+
+ if (subband->supportsPartial) {
+ std::uint32_t bitCode = crxBitstreamGetZeros(&subband->bandParam->bitStream);
+
+ if (bitCode >= 23) {
+ bitCode = crxBitstreamGetBits(&subband->bandParam->bitStream, 8);
+ } else if (subband->paramK) {
+ bitCode = crxBitstreamGetBits(&subband->bandParam->bitStream, subband->paramK) | (bitCode << subband->paramK);
+ }
+
+ subband->quantValue += -(bitCode & 1) ^ (bitCode >> 1); // converting encoded to signed integer
+ subband->paramK = crxPredictKParameter(subband->paramK, bitCode);
+
+ if (subband->paramK > 7) {
+ return false;
+ }
+ }
+
+ if (!crxDecodeLine(subband->bandParam, subband->bandBuf)) {
+ return false;
+ }
+
+ if (subband->width == 0) {
+ return true;
+ }
+
+ // update subband buffers
+ std::int32_t* const bandBuf = reinterpret_cast(subband->bandBuf);
+ std::int32_t qScale = q_step_tbl[subband->quantValue % 6] >> (6 - subband->quantValue / 6);
+
+ if (subband->quantValue / 6 >= 6) {
+ qScale = q_step_tbl[subband->quantValue % 6] * (1 << (subband->quantValue / 6 + 26));
+ }
+
+ if (qScale != 1) {
+ for (std::int32_t i = 0; i < subband->width; ++i) {
+ bandBuf[i] *= qScale;
+ }
+ }
+
+ return true;
+}
+
+void crxHorizontal53(
+ std::int32_t* lineBufLA,
+ std::int32_t* lineBufLB,
+ CrxWaveletTransform* wavelet,
+ std::uint32_t tileFlag
+)
+{
+ std::int32_t* band0Buf = wavelet->subband0Buf;
+ std::int32_t* band1Buf = wavelet->subband1Buf;
+ std::int32_t* band2Buf = wavelet->subband2Buf;
+ std::int32_t* band3Buf = wavelet->subband3Buf;
+
+ if (wavelet->width <= 1) {
+ lineBufLA[0] = band0Buf[0];
+ lineBufLB[0] = band2Buf[0];
+ } else {
+ if (tileFlag & E_HAS_TILES_ON_THE_LEFT) {
+ lineBufLA[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
+ lineBufLB[0] = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2);
+ ++band1Buf;
+ ++band3Buf;
+ } else {
+ lineBufLA[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1);
+ lineBufLB[0] = band2Buf[0] - ((band3Buf[0] + 1) >> 1);
+ }
+
+ ++band0Buf;
+ ++band2Buf;
+
+ for (int i = 0; i < wavelet->width - 3; i += 2) {
+ std::int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
+ lineBufLA[1] = band1Buf[0] + ((delta + lineBufLA[0]) >> 1);
+ lineBufLA[2] = delta;
+
+ delta = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2);
+ lineBufLB[1] = band3Buf[0] + ((delta + lineBufLB[0]) >> 1);
+ lineBufLB[2] = delta;
+
+ ++band0Buf;
+ ++band1Buf;
+ ++band2Buf;
+ ++band3Buf;
+ lineBufLA += 2;
+ lineBufLB += 2;
+ }
+
+ if (tileFlag & E_HAS_TILES_ON_THE_RIGHT) {
+ const std::int32_t deltaA = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
+ lineBufLA[1] = band1Buf[0] + ((deltaA + lineBufLA[0]) >> 1);
+
+ const std::int32_t deltaB = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2);
+ lineBufLB[1] = band3Buf[0] + ((deltaB + lineBufLB[0]) >> 1);
+
+ if (wavelet->width & 1) {
+ lineBufLA[2] = deltaA;
+ lineBufLB[2] = deltaB;
+ }
+ } else if (wavelet->width & 1) {
+ lineBufLA[1] = band1Buf[0] + ((lineBufLA[0] + band0Buf[0] - ((band1Buf[0] + 1) >> 1)) >> 1);
+ lineBufLA[2] = band0Buf[0] - ((band1Buf[0] + 1) >> 1);
+
+ lineBufLB[1] = band3Buf[0] + ((lineBufLB[0] + band2Buf[0] - ((band3Buf[0] + 1) >> 1)) >> 1);
+ lineBufLB[2] = band2Buf[0] - ((band3Buf[0] + 1) >> 1);
+ } else {
+ lineBufLA[1] = lineBufLA[0] + band1Buf[0];
+ lineBufLB[1] = lineBufLB[0] + band3Buf[0];
+ }
+ }
+}
+
+std::int32_t* crxIdwt53FilterGetLine(CrxPlaneComp* comp, std::int32_t level)
+{
+ std::int32_t* const result = comp->waveletTransform[level].lineBuf[
+ (comp->waveletTransform[level].fltTapH - comp->waveletTransform[level].curH + 5) % 5 + 3
+ ];
+ --comp->waveletTransform[level].curH;
+ return result;
+}
+
+bool crxIdwt53FilterDecode(CrxPlaneComp* comp, std::int32_t level)
+{
+ if (comp->waveletTransform[level].curH) {
+ return true;
+ }
+
+ CrxSubband* const sband = comp->subBands + 3 * level;
+
+ if (comp->waveletTransform[level].height - 3 <= comp->waveletTransform[level].curLine && !(comp->tileFlag & E_HAS_TILES_ON_THE_BOTTOM)) {
+ if (comp->waveletTransform[level].height & 1) {
+ if (level) {
+ if (!crxIdwt53FilterDecode(comp, level - 1)) {
+ return false;
+ }
+ } else if (!crxDecodeLineWithIQuantization(sband)) {
+ return false;
+ }
+
+ if (!crxDecodeLineWithIQuantization(sband + 1)) {
+ return false;
+ }
+ }
+ } else {
+ if (level) {
+ if (!crxIdwt53FilterDecode(comp, level - 1)) {
+ return false;
+ }
+ } else if (!crxDecodeLineWithIQuantization(sband)) { // LL band
+ return false;
+ }
+
+ if (
+ !crxDecodeLineWithIQuantization(sband + 1) // HL band
+ || !crxDecodeLineWithIQuantization(sband + 2) // LH band
+ || !crxDecodeLineWithIQuantization(sband + 3) // HH band
+ ) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool crxIdwt53FilterTransform(CrxPlaneComp* comp, std::uint32_t level)
+{
+ CrxWaveletTransform* const wavelet = comp->waveletTransform + level;
+
+ if (wavelet->curH) {
+ return true;
+ }
+
+ if (wavelet->curLine >= wavelet->height - 3) {
+ if (!(comp->tileFlag & E_HAS_TILES_ON_THE_BOTTOM)) {
+ if (wavelet->height & 1) {
+ if (level) {
+ if (!wavelet[-1].curH) {
+ if (!crxIdwt53FilterTransform(comp, level - 1)) {
+ return false;
+ }
+ }
+
+ wavelet->subband0Buf = crxIdwt53FilterGetLine(comp, level - 1);
+ }
+
+ const std::int32_t* band0Buf = wavelet->subband0Buf;
+ const std::int32_t* band1Buf = wavelet->subband1Buf;
+ const std::int32_t* const lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3];
+ std::int32_t* const lineBufH1 = wavelet->lineBuf[(wavelet->fltTapH + 1) % 5 + 3];
+ std::int32_t* const lineBufH2 = wavelet->lineBuf[(wavelet->fltTapH + 2) % 5 + 3];
+
+ std::int32_t* lineBufL0 = wavelet->lineBuf[0];
+ std::int32_t* lineBufL1 = wavelet->lineBuf[1];
+ wavelet->lineBuf[1] = wavelet->lineBuf[2];
+ wavelet->lineBuf[2] = lineBufL1;
+
+ // process L bands
+ if (wavelet->width <= 1) {
+ lineBufL0[0] = band0Buf[0];
+ } else {
+ if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT) {
+ lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
+ ++band1Buf;
+ } else {
+ lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1);
+ }
+
+ ++band0Buf;
+
+ for (int i = 0; i < wavelet->width - 3; i += 2) {
+ const std::int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
+ lineBufL0[1] = band1Buf[0] + ((lineBufL0[0] + delta) >> 1);
+ lineBufL0[2] = delta;
+ ++band0Buf;
+ ++band1Buf;
+ lineBufL0 += 2;
+ }
+
+ if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT) {
+ const std::int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
+ lineBufL0[1] = band1Buf[0] + ((lineBufL0[0] + delta) >> 1);
+
+ if (wavelet->width & 1) {
+ lineBufL0[2] = delta;
+ }
+ } else if (wavelet->width & 1) {
+ const std::int32_t delta = band0Buf[0] - ((band1Buf[0] + 1) >> 1);
+ lineBufL0[1] = band1Buf[0] + ((lineBufL0[0] + delta) >> 1);
+ lineBufL0[2] = delta;
+ } else {
+ lineBufL0[1] = band1Buf[0] + lineBufL0[0];
+ }
+ }
+
+ // process H bands
+ lineBufL0 = wavelet->lineBuf[0];
+ lineBufL1 = wavelet->lineBuf[1];
+
+ for (std::int32_t i = 0; i < wavelet->width; ++i) {
+ const std::int32_t delta = lineBufL0[i] - ((lineBufL1[i] + 1) >> 1);
+ lineBufH1[i] = lineBufL1[i] + ((delta + lineBufH0[i]) >> 1);
+ lineBufH2[i] = delta;
+ }
+
+ wavelet->curH += 3;
+ wavelet->curLine += 3;
+ wavelet->fltTapH = (wavelet->fltTapH + 3) % 5;
+ } else {
+ std::int32_t* const lineBufL2 = wavelet->lineBuf[2];
+ const std::int32_t* const lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3];
+ std::int32_t* const lineBufH1 = wavelet->lineBuf[(wavelet->fltTapH + 1) % 5 + 3];
+ wavelet->lineBuf[1] = lineBufL2;
+ wavelet->lineBuf[2] = wavelet->lineBuf[1];
+
+ for (std::int32_t i = 0; i < wavelet->width; ++i) {
+ lineBufH1[i] = lineBufH0[i] + lineBufL2[i];
+ }
+
+ wavelet->curH += 2;
+ wavelet->curLine += 2;
+ wavelet->fltTapH = (wavelet->fltTapH + 2) % 5;
+ }
+ }
+ } else {
+ if (level) {
+ if (!wavelet[-1].curH && !crxIdwt53FilterTransform(comp, level - 1)) {
+ return false;
+ }
+
+ wavelet->subband0Buf = crxIdwt53FilterGetLine(comp, level - 1);
+ }
+
+ const std::int32_t* band0Buf = wavelet->subband0Buf;
+ const std::int32_t* band1Buf = wavelet->subband1Buf;
+ const std::int32_t* band2Buf = wavelet->subband2Buf;
+ const std::int32_t* band3Buf = wavelet->subband3Buf;
+
+ std::int32_t* lineBufL0 = wavelet->lineBuf[0];
+ std::int32_t* lineBufL1 = wavelet->lineBuf[1];
+ const std::int32_t* const lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3];
+ std::int32_t* const lineBufH1 = wavelet->lineBuf[(wavelet->fltTapH + 1) % 5 + 3];
+ std::int32_t* const lineBufH2 = wavelet->lineBuf[(wavelet->fltTapH + 2) % 5 + 3];
- int32_t *lineBufL0 = wavelet->lineBuf[0];
- int32_t *lineBufL1 = wavelet->lineBuf[1];
wavelet->lineBuf[1] = wavelet->lineBuf[2];
wavelet->lineBuf[2] = lineBufL1;
// process L bands
- if (wavelet->width <= 1)
- {
- lineBufL0[0] = band0Buf[0];
- }
- else
- {
- if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT)
- {
- lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
- ++band1Buf;
- }
- else
- {
- lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1);
- }
- ++band0Buf;
- for (int i = 0; i < wavelet->width - 3; i += 2)
- {
- int32_t delta =
- band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
- lineBufL0[1] = band1Buf[0] + ((lineBufL0[0] + delta) >> 1);
- lineBufL0[2] = delta;
+ if (wavelet->width <= 1) {
+ lineBufL0[0] = band0Buf[0];
+ lineBufL1[0] = band2Buf[0];
+ } else {
+ if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT) {
+ lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
+ lineBufL1[0] = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2);
+ ++band1Buf;
+ ++band3Buf;
+ } else {
+ lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1);
+ lineBufL1[0] = band2Buf[0] - ((band3Buf[0] + 1) >> 1);
+ }
+
++band0Buf;
- ++band1Buf;
- lineBufL0 += 2;
- }
- if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT)
- {
- int32_t delta =
- band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
- lineBufL0[1] = band1Buf[0] + ((lineBufL0[0] + delta) >> 1);
- if (wavelet->width & 1)
- lineBufL0[2] = delta;
- }
- else if (wavelet->width & 1)
- {
- int32_t delta = band0Buf[0] - ((band1Buf[0] + 1) >> 1);
- lineBufL0[1] = band1Buf[0] + ((lineBufL0[0] + delta) >> 1);
- lineBufL0[2] = delta;
- }
- else
- lineBufL0[1] = band1Buf[0] + lineBufL0[0];
+ ++band2Buf;
+
+ for (int i = 0; i < wavelet->width - 3; i += 2) {
+ std::int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
+ lineBufL0[1] = band1Buf[0] + ((delta + lineBufL0[0]) >> 1);
+ lineBufL0[2] = delta;
+
+ delta = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2);
+ lineBufL1[1] = band3Buf[0] + ((delta + lineBufL1[0]) >> 1);
+ lineBufL1[2] = delta;
+
+ ++band0Buf;
+ ++band1Buf;
+ ++band2Buf;
+ ++band3Buf;
+ lineBufL0 += 2;
+ lineBufL1 += 2;
+ }
+
+ if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT) {
+ const std::int32_t deltaA = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
+ lineBufL0[1] = band1Buf[0] + ((deltaA + lineBufL0[0]) >> 1);
+
+ const std::int32_t deltaB = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2);
+ lineBufL1[1] = band3Buf[0] + ((deltaB + lineBufL1[0]) >> 1);
+
+ if (wavelet->width & 1) {
+ lineBufL0[2] = deltaA;
+ lineBufL1[2] = deltaB;
+ }
+ } else if (wavelet->width & 1) {
+ std::int32_t delta = band0Buf[0] - ((band1Buf[0] + 1) >> 1);
+ lineBufL0[1] = band1Buf[0] + ((delta + lineBufL0[0]) >> 1);
+ lineBufL0[2] = delta;
+
+ delta = band2Buf[0] - ((band3Buf[0] + 1) >> 1);
+ lineBufL1[1] = band3Buf[0] + ((delta + lineBufL1[0]) >> 1);
+ lineBufL1[2] = delta;
+ } else {
+ lineBufL0[1] = lineBufL0[0] + band1Buf[0];
+ lineBufL1[1] = lineBufL1[0] + band3Buf[0];
+ }
}
// process H bands
lineBufL0 = wavelet->lineBuf[0];
lineBufL1 = wavelet->lineBuf[1];
- for (int32_t i = 0; i < wavelet->width; i++)
- {
- int32_t delta = lineBufL0[i] - ((lineBufL1[i] + 1) >> 1);
- lineBufH1[i] = lineBufL1[i] + ((delta + lineBufH0[i]) >> 1);
- lineBufH2[i] = delta;
+ const std::int32_t* lineBufL2 = wavelet->lineBuf[2];
+
+ for (std::int32_t i = 0; i < wavelet->width; ++i) {
+ const std::int32_t delta = lineBufL0[i] - ((lineBufL2[i] + lineBufL1[i] + 2) >> 2);
+ lineBufH1[i] = lineBufL1[i] + ((delta + lineBufH0[i]) >> 1);
+ lineBufH2[i] = delta;
}
- wavelet->curH += 3;
- wavelet->curLine += 3;
- wavelet->fltTapH = (wavelet->fltTapH + 3) % 5;
- }
- else
- {
- int32_t *lineBufL2 = wavelet->lineBuf[2];
- int32_t *lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3];
- int32_t *lineBufH1 = wavelet->lineBuf[(wavelet->fltTapH + 1) % 5 + 3];
- wavelet->lineBuf[1] = lineBufL2;
- wavelet->lineBuf[2] = wavelet->lineBuf[1];
- for (int32_t i = 0; i < wavelet->width; i++)
- lineBufH1[i] = lineBufH0[i] + lineBufL2[i];
-
- wavelet->curH += 2;
- wavelet->curLine += 2;
- wavelet->fltTapH = (wavelet->fltTapH + 2) % 5;
- }
- }
- }
- else
- {
- if (level)
- {
- if (!wavelet[-1].curH && crxIdwt53FilterTransform(comp, level - 1))
- return -1;
- wavelet->subband0Buf = crxIdwt53FilterGetLine(comp, level - 1);
- }
-
- int32_t *band0Buf = wavelet->subband0Buf;
- int32_t *band1Buf = wavelet->subband1Buf;
- int32_t *band2Buf = wavelet->subband2Buf;
- int32_t *band3Buf = wavelet->subband3Buf;
-
- int32_t *lineBufL0 = wavelet->lineBuf[0];
- int32_t *lineBufL1 = wavelet->lineBuf[1];
- int32_t *lineBufL2 = wavelet->lineBuf[2];
- int32_t *lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3];
- int32_t *lineBufH1 = wavelet->lineBuf[(wavelet->fltTapH + 1) % 5 + 3];
- int32_t *lineBufH2 = wavelet->lineBuf[(wavelet->fltTapH + 2) % 5 + 3];
-
- wavelet->lineBuf[1] = wavelet->lineBuf[2];
- wavelet->lineBuf[2] = lineBufL1;
-
- // process L bands
- if (wavelet->width <= 1)
- {
- lineBufL0[0] = band0Buf[0];
- lineBufL1[0] = band2Buf[0];
- }
- else
- {
- if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT)
- {
- lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
- lineBufL1[0] = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2);
- ++band1Buf;
- ++band3Buf;
- }
- else
- {
- lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1);
- lineBufL1[0] = band2Buf[0] - ((band3Buf[0] + 1) >> 1);
- }
- ++band0Buf;
- ++band2Buf;
- for (int i = 0; i < wavelet->width - 3; i += 2)
- {
- int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
- lineBufL0[1] = band1Buf[0] + ((delta + lineBufL0[0]) >> 1);
- lineBufL0[2] = delta;
-
- delta = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2);
- lineBufL1[1] = band3Buf[0] + ((delta + lineBufL1[0]) >> 1);
- lineBufL1[2] = delta;
-
- ++band0Buf;
- ++band1Buf;
- ++band2Buf;
- ++band3Buf;
- lineBufL0 += 2;
- lineBufL1 += 2;
- }
- if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT)
- {
- int32_t deltaA = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
- lineBufL0[1] = band1Buf[0] + ((deltaA + lineBufL0[0]) >> 1);
-
- int32_t deltaB = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2);
- lineBufL1[1] = band3Buf[0] + ((deltaB + lineBufL1[0]) >> 1);
-
- if (wavelet->width & 1)
- {
- lineBufL0[2] = deltaA;
- lineBufL1[2] = deltaB;
+ if (wavelet->curLine >= wavelet->height - 3 && (wavelet->height & 1)) {
+ wavelet->curH += 3;
+ wavelet->curLine += 3;
+ wavelet->fltTapH = (wavelet->fltTapH + 3) % 5;
+ } else {
+ wavelet->curH += 2;
+ wavelet->curLine += 2;
+ wavelet->fltTapH = (wavelet->fltTapH + 2) % 5;
}
- }
- else if (wavelet->width & 1)
- {
- int32_t delta = band0Buf[0] - ((band1Buf[0] + 1) >> 1);
- lineBufL0[1] = band1Buf[0] + ((delta + lineBufL0[0]) >> 1);
- lineBufL0[2] = delta;
-
- delta = band2Buf[0] - ((band3Buf[0] + 1) >> 1);
- lineBufL1[1] = band3Buf[0] + ((delta + lineBufL1[0]) >> 1);
- lineBufL1[2] = delta;
- }
- else
- {
- lineBufL0[1] = lineBufL0[0] + band1Buf[0];
- lineBufL1[1] = lineBufL1[0] + band3Buf[0];
- }
}
- // process H bands
- lineBufL0 = wavelet->lineBuf[0];
- lineBufL1 = wavelet->lineBuf[1];
- lineBufL2 = wavelet->lineBuf[2];
- for (int32_t i = 0; i < wavelet->width; i++)
- {
- int32_t delta = lineBufL0[i] - ((lineBufL2[i] + lineBufL1[i] + 2) >> 2);
- lineBufH1[i] = lineBufL1[i] + ((delta + lineBufH0[i]) >> 1);
- lineBufH2[i] = delta;
- }
- if (wavelet->curLine >= wavelet->height - 3 && wavelet->height & 1)
- {
- wavelet->curH += 3;
- wavelet->curLine += 3;
- wavelet->fltTapH = (wavelet->fltTapH + 3) % 5;
- }
- else
- {
- wavelet->curH += 2;
- wavelet->curLine += 2;
- wavelet->fltTapH = (wavelet->fltTapH + 2) % 5;
- }
- }
-
- return 0;
+ return true;
}
-int crxIdwt53FilterInitialize(CrxPlaneComp *comp, int32_t prevLevel)
+bool crxIdwt53FilterInitialize(CrxPlaneComp* comp, std::int32_t prevLevel)
{
- if (prevLevel < 0)
- return 0;
+ if (prevLevel < 0) {
+ return true;
+ }
- for (int curLevel = 0, curBand = 0; curLevel < prevLevel + 1;
- curLevel++, curBand += 3)
- {
- CrxWaveletTransform *wavelet = comp->waveletTransform + curLevel;
- if (curLevel)
- wavelet[0].subband0Buf = crxIdwt53FilterGetLine(comp, curLevel - 1);
- else if (crxDecodeLineWithIQuantization(comp->subBands + curBand))
- return -1;
+ for (int curLevel = 0, curBand = 0; curLevel < prevLevel + 1; ++curLevel, curBand += 3) {
+ CrxWaveletTransform* const wavelet = comp->waveletTransform + curLevel;
- int32_t *lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3];
- if (wavelet->height > 1)
- {
- if (crxDecodeLineWithIQuantization(comp->subBands + curBand + 1) ||
- crxDecodeLineWithIQuantization(comp->subBands + curBand + 2) ||
- crxDecodeLineWithIQuantization(comp->subBands + curBand + 3))
- return -1;
-
- int32_t *lineBufL0 = wavelet->lineBuf[0];
- int32_t *lineBufL1 = wavelet->lineBuf[1];
- int32_t *lineBufL2 = wavelet->lineBuf[2];
-
- if (comp->tileFlag & E_HAS_TILES_ON_THE_TOP)
- {
- crxHorizontal53(lineBufL0, wavelet->lineBuf[1], wavelet,
- comp->tileFlag);
- if (crxDecodeLineWithIQuantization(comp->subBands + curBand + 3) ||
- crxDecodeLineWithIQuantization(comp->subBands + curBand + 2))
- return -1;
-
- int32_t *band2Buf = wavelet->subband2Buf;
- int32_t *band3Buf = wavelet->subband3Buf;
-
- // process L band
- if (wavelet->width <= 1)
- lineBufL2[0] = band2Buf[0];
- else
- {
- if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT)
- {
- lineBufL2[0] = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2);
- ++band3Buf;
- }
- else
- lineBufL2[0] = band2Buf[0] - ((band3Buf[0] + 1) >> 1);
-
- ++band2Buf;
-
- for (int i = 0; i < wavelet->width - 3; i += 2)
- {
- int32_t delta =
- band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2);
- lineBufL2[1] = band3Buf[0] + ((lineBufL2[0] + delta) >> 1);
- lineBufL2[2] = delta;
-
- ++band2Buf;
- ++band3Buf;
- lineBufL2 += 2;
- }
- if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT)
- {
- int32_t delta =
- band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2);
- lineBufL2[1] = band3Buf[0] + ((lineBufL2[0] + delta) >> 1);
- if (wavelet->width & 1)
- lineBufL2[2] = delta;
- }
- else if (wavelet->width & 1)
- {
- int32_t delta = band2Buf[0] - ((band3Buf[0] + 1) >> 1);
-
- lineBufL2[1] = band3Buf[0] + ((lineBufL2[0] + delta) >> 1);
- lineBufL2[2] = delta;
- }
- else
- {
- lineBufL2[1] = band3Buf[0] + lineBufL2[0];
- }
+ if (curLevel) {
+ wavelet[0].subband0Buf = crxIdwt53FilterGetLine(comp, curLevel - 1);
+ } else if (!crxDecodeLineWithIQuantization(comp->subBands + curBand)) {
+ return false;
}
- // process H band
- for (int32_t i = 0; i < wavelet->width; i++)
- lineBufH0[i] =
- lineBufL0[i] - ((lineBufL1[i] + lineBufL2[i] + 2) >> 2);
- }
- else
- {
- crxHorizontal53(lineBufL0, wavelet->lineBuf[2], wavelet,
- comp->tileFlag);
- for (int i = 0; i < wavelet->width; i++)
- lineBufH0[i] = lineBufL0[i] - ((lineBufL2[i] + 1) >> 1);
- }
-
- if (crxIdwt53FilterDecode(comp, curLevel) ||
- crxIdwt53FilterTransform(comp, curLevel))
- return -1;
- }
- else
- {
- if (crxDecodeLineWithIQuantization(comp->subBands + curBand + 1))
- return -1;
-
- int32_t *band0Buf = wavelet->subband0Buf;
- int32_t *band1Buf = wavelet->subband1Buf;
-
- // process H band
- if (wavelet->width <= 1)
- lineBufH0[0] = band0Buf[0];
- else
- {
- if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT)
- {
- lineBufH0[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
- ++band1Buf;
- }
- else
- lineBufH0[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1);
-
- ++band0Buf;
-
- for (int i = 0; i < wavelet->width - 3; i += 2)
- {
- int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
- lineBufH0[1] = band1Buf[0] + ((lineBufH0[0] + delta) >> 1);
- lineBufH0[2] = delta;
-
- ++band0Buf;
- ++band1Buf;
- lineBufH0 += 2;
- }
-
- if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT)
- {
- int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
- lineBufH0[1] = band1Buf[0] + ((lineBufH0[0] + delta) >> 1);
- lineBufH0[2] = delta;
- }
- else if (wavelet->width & 1)
- {
- int32_t delta = band0Buf[0] - ((band1Buf[0] + 1) >> 1);
- lineBufH0[1] = band1Buf[0] + ((lineBufH0[0] + delta) >> 1);
- lineBufH0[2] = delta;
- }
- else
- {
- lineBufH0[1] = band1Buf[0] + lineBufH0[0];
- }
- }
- ++wavelet->curLine;
- ++wavelet->curH;
- wavelet->fltTapH = (wavelet->fltTapH + 1) % 5;
- }
- }
-
- return 0;
-}
-
-void crxFreeSubbandData(CrxImage *image, CrxPlaneComp *comp)
-{
- if (comp->compBuf)
- {
- free(comp->compBuf);
- comp->compBuf = 0;
- }
-
- if (!comp->subBands)
- return;
-
- for (int32_t i = 0; i < image->subbandCount; i++)
- {
- if (comp->subBands[i].bandParam)
- {
- free(comp->subBands[i].bandParam);
- comp->subBands[i].bandParam = 0LL;
- }
- comp->subBands[i].bandBuf = 0;
- comp->subBands[i].bandSize = 0;
- }
-}
-
-void crxConvertPlaneLine(CrxImage *img, int imageRow, int imageCol = 0,
- int plane = 0, int32_t *lineData = 0,
- int lineLength = 0)
-{
- if (lineData)
- {
- uint64_t rawOffset = 4 * img->planeWidth * imageRow + 2 * imageCol;
- if (img->encType == 1)
- {
- int32_t maxVal = 1 << (img->nBits - 1);
- int32_t minVal = -maxVal;
- --maxVal;
- for (int i = 0; i < lineLength; i++)
- img->outBufs[plane][rawOffset + 2 * i] =
- _constrain(lineData[i], minVal, maxVal);
- }
- else if (img->encType == 3)
- {
- // copy to intermediate planeBuf
- rawOffset = plane * img->planeWidth * img->planeHeight +
- img->planeWidth * imageRow + imageCol;
- for (int i = 0; i < lineLength; i++)
- img->planeBuf[rawOffset + i] = lineData[i];
- }
- else if (img->nPlanes == 4)
- {
- int32_t median = 1 << (img->nBits - 1);
- int32_t maxVal = (1 << img->nBits) - 1;
- for (int i = 0; i < lineLength; i++)
- img->outBufs[plane][rawOffset + 2 * i] =
- _constrain(median + lineData[i], 0, maxVal);
- }
- else if (img->nPlanes == 1)
- {
- int32_t maxVal = (1 << img->nBits) - 1;
- int32_t median = 1 << (img->nBits - 1);
- rawOffset = img->planeWidth * imageRow + imageCol;
- for (int i = 0; i < lineLength; i++)
- img->outBufs[0][rawOffset + i] =
- _constrain(median + lineData[i], 0, maxVal);
- }
- }
- else if (img->encType == 3 && img->planeBuf)
- {
- int32_t planeSize = img->planeWidth * img->planeHeight;
- int16_t *plane0 = img->planeBuf + imageRow * img->planeWidth;
- int16_t *plane1 = plane0 + planeSize;
- int16_t *plane2 = plane1 + planeSize;
- int16_t *plane3 = plane2 + planeSize;
-
- int32_t median = 1 << (img->nBits - 1) << 10;
- int32_t maxVal = (1 << img->nBits) - 1;
- uint32_t rawLineOffset = 4 * img->planeWidth * imageRow;
-
- // for this stage - all except imageRow is ignored
- for (int i = 0; i < img->planeWidth; i++)
- {
- int32_t gr =
- median + (plane0[i] << 10) - 168 * plane1[i] - 585 * plane3[i];
- int32_t val = 0;
- if (gr < 0)
- gr = -(((_abs(gr) + 512) >> 9) & ~1);
- else
- gr = ((_abs(gr) + 512) >> 9) & ~1;
-
- // Essentially R = round(median + P0 + 1.474*P3)
- val = (median + (plane0[i] << 10) + 1510 * plane3[i] + 512) >> 10;
- img->outBufs[0][rawLineOffset + 2 * i] = _constrain(val, 0, maxVal);
- // Essentially G1 = round(median + P0 + P2 - 0.164*P1 - 0.571*P3)
- val = (plane2[i] + gr + 1) >> 1;
- img->outBufs[1][rawLineOffset + 2 * i] = _constrain(val, 0, maxVal);
- // Essentially G1 = round(median + P0 - P2 - 0.164*P1 - 0.571*P3)
- val = (gr - plane2[i] + 1) >> 1;
- img->outBufs[2][rawLineOffset + 2 * i] = _constrain(val, 0, maxVal);
- // Essentially B = round(median + P0 + 1.881*P1)
- val = (median + (plane0[i] << 10) + 1927 * plane1[i] + 512) >> 10;
- img->outBufs[3][rawLineOffset + 2 * i] = _constrain(val, 0, maxVal);
- }
- }
-}
-
-int crxParamInit(CrxBandParam **param, uint64_t subbandMdatOffset,
- uint64_t subbandDataSize, uint32_t subbandWidth,
- uint32_t subbandHeight, int32_t supportsPartial,
- uint32_t roundedBitsMask, LibRaw_abstract_datastream *input)
-{
- int32_t progrDataSize = supportsPartial ? 0 : sizeof(int32_t) * subbandWidth;
- int32_t paramLength = 2 * subbandWidth + 4;
- uint8_t *paramBuf = (uint8_t *)calloc(
- 1, sizeof(CrxBandParam) + sizeof(int32_t) * paramLength + progrDataSize);
-
- if (!paramBuf)
- return -1;
-
- *param = (CrxBandParam *)paramBuf;
-
- paramBuf += sizeof(CrxBandParam);
-
- (*param)->paramData = (int32_t *)paramBuf;
- (*param)->nonProgrData =
- progrDataSize ? (*param)->paramData + paramLength : 0;
- (*param)->subbandWidth = subbandWidth;
- (*param)->subbandHeight = subbandHeight;
- (*param)->roundedBits = 0;
- (*param)->curLine = 0;
- (*param)->roundedBitsMask = roundedBitsMask;
- (*param)->supportsPartial = supportsPartial;
- (*param)->bitStream.bitData = 0;
- (*param)->bitStream.bitsLeft = 0;
- (*param)->bitStream.mdatSize = subbandDataSize;
- (*param)->bitStream.curPos = 0;
- (*param)->bitStream.curBufSize = 0;
- (*param)->bitStream.curBufOffset = subbandMdatOffset;
- (*param)->bitStream.input = input;
-
- crxFillBuffer(&(*param)->bitStream);
-
- return 0;
-}
-
-int crxSetupSubbandData(CrxImage *img, CrxPlaneComp *planeComp,
- const CrxTile *tile, uint32_t mdatOffset)
-{
- long compDataSize = 0;
- long waveletDataOffset = 0;
- long compCoeffDataOffset = 0;
- int32_t toSubbands = 3 * img->levels + 1;
- int32_t transformWidth = 0;
-
- CrxSubband *subbands = planeComp->subBands;
-
- // calculate sizes
- for (int32_t subbandNum = 0; subbandNum < toSubbands; subbandNum++)
- {
- subbands[subbandNum].bandSize =
- subbands[subbandNum].width * sizeof(int32_t); // 4bytes
- compDataSize += subbands[subbandNum].bandSize;
- }
-
- if (img->levels)
- {
- int32_t encLevels = img->levels ? img->levels : 1;
- waveletDataOffset = (compDataSize + 7) & ~7;
- compDataSize =
- (sizeof(CrxWaveletTransform) * encLevels + waveletDataOffset + 7) & ~7;
- compCoeffDataOffset = compDataSize;
-
- // calc wavelet line buffer sizes (always at one level up from current)
- for (int level = 0; level < img->levels; ++level)
- if (level < img->levels - 1)
- compDataSize += 8 * sizeof(int32_t) *
- planeComp->subBands[3 * (level + 1) + 2].width;
- else
- compDataSize += 8 * sizeof(int32_t) * tile->width;
- }
-
- // buffer allocation
- planeComp->compBuf = (uint8_t *)malloc(compDataSize);
- if (!planeComp->compBuf)
- return -1;
-
- // subbands buffer and sizes initialisation
- uint64_t subbandMdatOffset = img->mdatOffset + mdatOffset;
- uint8_t *subbandBuf = planeComp->compBuf;
-
- for (int32_t subbandNum = 0; subbandNum < toSubbands; subbandNum++)
- {
- subbands[subbandNum].bandBuf = subbandBuf;
- subbandBuf += subbands[subbandNum].bandSize;
- subbands[subbandNum].mdatOffset =
- subbandMdatOffset + subbands[subbandNum].dataOffset;
- }
-
- // wavelet data initialisation
- if (img->levels)
- {
- CrxWaveletTransform *waveletTransforms =
- (CrxWaveletTransform *)(planeComp->compBuf + waveletDataOffset);
- int32_t *paramData = (int32_t *)(planeComp->compBuf + compCoeffDataOffset);
-
- planeComp->waveletTransform = waveletTransforms;
- waveletTransforms[0].subband0Buf = (int32_t *)subbands->bandBuf;
-
- for (int level = 0; level < img->levels; ++level)
- {
- int32_t band = 3 * level + 1;
-
- if (level >= img->levels - 1)
- {
- waveletTransforms[level].height = tile->height;
- transformWidth = tile->width;
- }
- else
- {
- waveletTransforms[level].height = subbands[band + 3].height;
- transformWidth = subbands[band + 4].width;
- }
- waveletTransforms[level].width = transformWidth;
- waveletTransforms[level].lineBuf[0] = paramData;
- waveletTransforms[level].lineBuf[1] =
- waveletTransforms[level].lineBuf[0] + transformWidth;
- waveletTransforms[level].lineBuf[2] =
- waveletTransforms[level].lineBuf[1] + transformWidth;
- waveletTransforms[level].lineBuf[3] =
- waveletTransforms[level].lineBuf[2] + transformWidth;
- waveletTransforms[level].lineBuf[4] =
- waveletTransforms[level].lineBuf[3] + transformWidth;
- waveletTransforms[level].lineBuf[5] =
- waveletTransforms[level].lineBuf[4] + transformWidth;
- waveletTransforms[level].lineBuf[6] =
- waveletTransforms[level].lineBuf[5] + transformWidth;
- waveletTransforms[level].lineBuf[7] =
- waveletTransforms[level].lineBuf[6] + transformWidth;
- waveletTransforms[level].curLine = 0;
- waveletTransforms[level].curH = 0;
- waveletTransforms[level].fltTapH = 0;
- waveletTransforms[level].subband1Buf = (int32_t *)subbands[band].bandBuf;
- waveletTransforms[level].subband2Buf =
- (int32_t *)subbands[band + 1].bandBuf;
- waveletTransforms[level].subband3Buf =
- (int32_t *)subbands[band + 2].bandBuf;
-
- paramData = waveletTransforms[level].lineBuf[7] + transformWidth;
- }
- }
-
- // decoding params and bitstream initialisation
- for (int32_t subbandNum = 0; subbandNum < toSubbands; subbandNum++)
- {
- if (subbands[subbandNum].dataSize)
- {
- int32_t supportsPartial = 0;
- uint32_t roundedBitsMask = 0;
-
- if (planeComp->supportsPartial && subbandNum == 0)
- {
- roundedBitsMask = planeComp->roundedBitsMask;
- supportsPartial = 1;
- }
- if (crxParamInit(&subbands[subbandNum].bandParam,
- subbands[subbandNum].mdatOffset,
- subbands[subbandNum].dataSize,
- subbands[subbandNum].width, subbands[subbandNum].height,
- supportsPartial, roundedBitsMask, img->input))
- return -1;
- }
- }
-
- return 0;
-}
-
-} // namespace
-
-
-int DCraw::crxDecodePlane(void *p, uint32_t planeNumber)
-{
- CrxImage *img = (CrxImage *)p;
- int imageRow = 0;
- for (int tRow = 0; tRow < img->tileRows; tRow++)
- {
- int imageCol = 0;
- for (int tCol = 0; tCol < img->tileCols; tCol++)
- {
- CrxTile *tile = img->tiles + tRow * img->tileRows + tCol;
- CrxPlaneComp *planeComp = tile->comps + planeNumber;
- uint64_t tileMdatOffset = tile->dataOffset + planeComp->dataOffset;
-
- // decode single tile
- if (crxSetupSubbandData(img, planeComp, tile, tileMdatOffset))
- return -1;
-
- if (img->levels)
- {
- if (crxIdwt53FilterInitialize(planeComp, img->levels - 1))
- return -1;
- for (int i = 0; i < tile->height; ++i)
- {
- if (crxIdwt53FilterDecode(planeComp, img->levels - 1) ||
- crxIdwt53FilterTransform(planeComp, img->levels - 1))
- return -1;
- int32_t *lineData =
- crxIdwt53FilterGetLine(planeComp, img->levels - 1);
- crxConvertPlaneLine(img, imageRow + i, imageCol, planeNumber,
- lineData, tile->width);
- }
- }
- else
- {
- // we have the only subband in this case
- if (!planeComp->subBands->dataSize)
- {
- memset(planeComp->subBands->bandBuf, 0,
- planeComp->subBands->bandSize);
- return 0;
- }
-
- for (int i = 0; i < tile->height; ++i)
- {
- if (crxDecodeLine(planeComp->subBands->bandParam,
- planeComp->subBands->bandBuf))
- return -1;
- int32_t *lineData = (int32_t *)planeComp->subBands->bandBuf;
- crxConvertPlaneLine(img, imageRow + i, imageCol, planeNumber,
- lineData, tile->width);
- }
- }
- imageCol += tile->width;
- }
- imageRow += img->tiles[tRow * img->tileRows].height;
- }
-
- return 0;
-}
-
-
-namespace {
-
-typedef DCraw::CanonCR3Data::crx_data_header_t crx_data_header_t;
-
-
-int crxReadSubbandHeaders(crx_data_header_t *hdr, CrxImage *img, CrxTile *tile,
- CrxPlaneComp *comp, uint8_t **subbandMdatPtr,
- uint32_t *mdatSize)
-{
- CrxSubband *band = comp->subBands + img->subbandCount - 1; // set to last band
- uint32_t bandHeight = tile->height;
- uint32_t bandWidth = tile->width;
- int32_t bandWidthExCoef = 0;
- int32_t bandHeightExCoef = 0;
- if (img->levels)
- {
- // Build up subband sequences to crxDecode to a level in a header
-
- // Coefficient structure is a bit unclear and convoluted:
- // 3 levels max - 8 groups (for tile width rounded to 8 bytes)
- // of 3 band per level 4 sets of coefficients for each
- int32_t *rowExCoef =
- exCoefNumTbl + 0x60 * (img->levels - 1) + 12 * (tile->width & 7);
- int32_t *colExCoef =
- exCoefNumTbl + 0x60 * (img->levels - 1) + 12 * (tile->height & 7);
- for (int level = 0; level < img->levels; ++level)
- {
- int32_t widthOddPixel = bandWidth & 1;
- int32_t heightOddPixel = bandHeight & 1;
- bandWidth = (widthOddPixel + bandWidth) >> 1;
- bandHeight = (heightOddPixel + bandHeight) >> 1;
-
- int32_t bandWidthExCoef0 = 0;
- int32_t bandWidthExCoef1 = 0;
- int32_t bandHeightExCoef0 = 0;
- int32_t bandHeightExCoef1 = 0;
- if (tile->tileFlag & E_HAS_TILES_ON_THE_RIGHT)
- {
- bandWidthExCoef0 = rowExCoef[0];
- bandWidthExCoef1 = rowExCoef[1];
- }
- if (tile->tileFlag & E_HAS_TILES_ON_THE_LEFT)
- ++bandWidthExCoef0;
- if (tile->tileFlag & E_HAS_TILES_ON_THE_BOTTOM)
- {
- bandHeightExCoef0 = colExCoef[0];
- bandHeightExCoef1 = colExCoef[1];
- }
- if (tile->tileFlag & E_HAS_TILES_ON_THE_TOP)
- ++bandHeightExCoef0;
-
- band[0].width = bandWidth + bandWidthExCoef0 - widthOddPixel;
- band[0].height = bandHeight + bandHeightExCoef0 - heightOddPixel;
-
- band[-1].width = bandWidth + bandWidthExCoef1;
- band[-1].height = bandHeight + bandHeightExCoef0 - heightOddPixel;
-
- band[-2].width = bandWidth + bandWidthExCoef0 - widthOddPixel;
- band[-2].height = bandHeight + bandHeightExCoef1;
-
- rowExCoef += 4;
- colExCoef += 4;
- band -= 3;
- }
- bandWidthExCoef = bandHeightExCoef = 0;
- if (tile->tileFlag & E_HAS_TILES_ON_THE_RIGHT)
- bandWidthExCoef =
- exCoefNumTbl[0x60 * (img->levels - 1) + 12 * (tile->width & 7) +
- 4 * (img->levels - 1) + 1];
- if (tile->tileFlag & E_HAS_TILES_ON_THE_BOTTOM)
- bandHeightExCoef =
- exCoefNumTbl[0x60 * (img->levels - 1) + 12 * (tile->height & 7) +
- 4 * (img->levels - 1) + 1];
- }
- band->width = bandWidthExCoef + bandWidth;
- band->height = bandHeightExCoef + bandHeight;
-
- if (!img->subbandCount)
- return 0;
- int32_t curSubband = 0;
- int32_t subbandOffset = 0;
- band = comp->subBands;
- for (int curSubband = 0; curSubband < img->subbandCount; curSubband++, band++)
- {
- if (*mdatSize < 0xC)
- return -1;
-
- if (sgetn(2, *subbandMdatPtr) != 0xFF03)
- return -1;
-
- uint32_t bitData = sgetn(4, *subbandMdatPtr + 8);
- uint32_t subbandSize = sgetn(4, *subbandMdatPtr + 4);
-
- if (curSubband != bitData >> 28)
- {
- band->dataSize = subbandSize;
- return -1;
- }
- band->dataSize = subbandSize - (bitData & 0x7FF);
- band->supportsPartial = bitData & 0x8000 ? 1 : 0;
- band->dataOffset = subbandOffset;
- band->quantValue = (bitData >> 19) & 0xFF;
- band->paramK = 0;
- band->bandParam = 0;
- band->bandBuf = 0;
- band->bandSize = 0;
-
- subbandOffset += subbandSize;
-
- *subbandMdatPtr += 0xC;
- *mdatSize -= 0xC;
- }
- return 0;
-}
-
-int crxReadImageHeaders(crx_data_header_t *hdr, CrxImage *img, uint8_t *mdatPtr,
- uint32_t mdatSize)
-{
- int nTiles = img->tileRows * img->tileCols;
-
- if (!nTiles)
- return -1;
-
- if (!img->tiles)
- {
- img->tiles = (CrxTile *)malloc(
- sizeof(CrxTile) * nTiles +
- sizeof(CrxPlaneComp) * nTiles * img->nPlanes +
- sizeof(CrxSubband) * nTiles * img->nPlanes * img->subbandCount);
- if (!img->tiles)
- return -1;
-
- // memory areas in allocated chunk
- CrxTile *tile = img->tiles;
- CrxPlaneComp *comps = (CrxPlaneComp *)(tile + nTiles);
- CrxSubband *bands = (CrxSubband *)(comps + img->nPlanes * nTiles);
-
- for (int curTile = 0; curTile < nTiles; curTile++, tile++)
- {
- tile->tileFlag = 0; // tile neighbouring flags
- tile->tileNumber = curTile;
- tile->tileSize = 0;
- tile->comps = comps + curTile * img->nPlanes;
-
- if ((curTile + 1) % img->tileCols)
- {
- // not the last tile in a tile row
- tile->width = hdr->tileWidth;
- if (img->tileCols > 1)
- {
- tile->tileFlag = E_HAS_TILES_ON_THE_RIGHT;
- if (curTile % img->tileCols)
- // not the first tile in tile row
- tile->tileFlag |= E_HAS_TILES_ON_THE_LEFT;
- }
- }
- else
- {
- // last tile in a tile row
- tile->width = img->planeWidth - hdr->tileWidth * (img->tileCols - 1);
- if (img->tileCols > 1)
- tile->tileFlag = E_HAS_TILES_ON_THE_LEFT;
- }
- if (curTile < nTiles - img->tileCols)
- {
- // in first tile row
- tile->height = hdr->tileHeight;
- if (img->tileRows > 1)
- {
- tile->tileFlag |= E_HAS_TILES_ON_THE_BOTTOM;
- if (curTile >= img->tileCols)
- tile->tileFlag |= E_HAS_TILES_ON_THE_TOP;
- }
- }
- else
- {
- // non first tile row
- tile->height = img->planeHeight - hdr->tileHeight * (img->tileRows - 1);
- if (img->tileRows > 1)
- tile->tileFlag |= E_HAS_TILES_ON_THE_TOP;
- }
- if (img->nPlanes)
- {
- CrxPlaneComp *comp = tile->comps;
- CrxSubband *band = bands + curTile * img->nPlanes * img->subbandCount;
-
- for (int curComp = 0; curComp < img->nPlanes; curComp++, comp++)
- {
- comp->compNumber = curComp;
- comp->supportsPartial = 1;
- comp->tileFlag = tile->tileFlag;
- comp->subBands = band;
- comp->compBuf = 0;
- comp->waveletTransform = 0;
- if (img->subbandCount)
- {
- for (int curBand = 0; curBand < img->subbandCount;
- curBand++, band++)
- {
- band->supportsPartial = 0;
- band->quantValue = 4;
- band->bandParam = 0;
- band->dataSize = 0;
+ std::int32_t* lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3];
+
+ if (wavelet->height > 1) {
+ if (
+ !crxDecodeLineWithIQuantization(comp->subBands + curBand + 1)
+ || !crxDecodeLineWithIQuantization(comp->subBands + curBand + 2)
+ || !crxDecodeLineWithIQuantization(comp->subBands + curBand + 3)
+ ) {
+ return false;
}
- }
+
+ std::int32_t* const lineBufL0 = wavelet->lineBuf[0];
+ const std::int32_t* const lineBufL1 = wavelet->lineBuf[1];
+ std::int32_t* lineBufL2 = wavelet->lineBuf[2];
+
+ if (comp->tileFlag & E_HAS_TILES_ON_THE_TOP) {
+ crxHorizontal53(lineBufL0, wavelet->lineBuf[1], wavelet, comp->tileFlag);
+
+ if (!crxDecodeLineWithIQuantization(comp->subBands + curBand + 3)|| !crxDecodeLineWithIQuantization(comp->subBands + curBand + 2)) {
+ return false;
+ }
+
+ const std::int32_t* band2Buf = wavelet->subband2Buf;
+ const std::int32_t* band3Buf = wavelet->subband3Buf;
+
+ // process L band
+ if (wavelet->width <= 1) {
+ lineBufL2[0] = band2Buf[0];
+ } else {
+ if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT) {
+ lineBufL2[0] = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2);
+ ++band3Buf;
+ } else {
+ lineBufL2[0] = band2Buf[0] - ((band3Buf[0] + 1) >> 1);
+ }
+
+ ++band2Buf;
+
+ for (int i = 0; i < wavelet->width - 3; i += 2) {
+ const std::int32_t delta = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2);
+ lineBufL2[1] = band3Buf[0] + ((lineBufL2[0] + delta) >> 1);
+ lineBufL2[2] = delta;
+
+ ++band2Buf;
+ ++band3Buf;
+ lineBufL2 += 2;
+ }
+
+ if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT) {
+ const std::int32_t delta = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2);
+ lineBufL2[1] = band3Buf[0] + ((lineBufL2[0] + delta) >> 1);
+
+ if (wavelet->width & 1) {
+ lineBufL2[2] = delta;
+ }
+ } else if (wavelet->width & 1) {
+ const std::int32_t delta = band2Buf[0] - ((band3Buf[0] + 1) >> 1);
+
+ lineBufL2[1] = band3Buf[0] + ((lineBufL2[0] + delta) >> 1);
+ lineBufL2[2] = delta;
+ } else {
+ lineBufL2[1] = band3Buf[0] + lineBufL2[0];
+ }
+ }
+
+ // process H band
+ for (std::int32_t i = 0; i < wavelet->width; ++i) {
+ lineBufH0[i] = lineBufL0[i] - ((lineBufL1[i] + lineBufL2[i] + 2) >> 2);
+ }
+ } else {
+ crxHorizontal53(lineBufL0, wavelet->lineBuf[2], wavelet, comp->tileFlag);
+
+ for (int i = 0; i < wavelet->width; ++i) {
+ lineBufH0[i] = lineBufL0[i] - ((lineBufL2[i] + 1) >> 1);
+ }
+ }
+
+ if (!crxIdwt53FilterDecode(comp, curLevel) || !crxIdwt53FilterTransform(comp, curLevel)) {
+ return false;
+ }
+ } else {
+ if (!crxDecodeLineWithIQuantization(comp->subBands + curBand + 1)) {
+ return false;
+ }
+
+ const std::int32_t* band0Buf = wavelet->subband0Buf;
+ const std::int32_t* band1Buf = wavelet->subband1Buf;
+
+ // process H band
+ if (wavelet->width <= 1) {
+ lineBufH0[0] = band0Buf[0];
+ } else {
+ if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT) {
+ lineBufH0[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
+ ++band1Buf;
+ } else {
+ lineBufH0[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1);
+ }
+
+ ++band0Buf;
+
+ for (int i = 0; i < wavelet->width - 3; i += 2) {
+ std::int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
+ lineBufH0[1] = band1Buf[0] + ((lineBufH0[0] + delta) >> 1);
+ lineBufH0[2] = delta;
+
+ ++band0Buf;
+ ++band1Buf;
+ lineBufH0 += 2;
+ }
+
+ if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT) {
+ const std::int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2);
+ lineBufH0[1] = band1Buf[0] + ((lineBufH0[0] + delta) >> 1);
+ lineBufH0[2] = delta;
+ } else if (wavelet->width & 1) {
+ const std::int32_t delta = band0Buf[0] - ((band1Buf[0] + 1) >> 1);
+ lineBufH0[1] = band1Buf[0] + ((lineBufH0[0] + delta) >> 1);
+ lineBufH0[2] = delta;
+ } else {
+ lineBufH0[1] = band1Buf[0] + lineBufH0[0];
+ }
+ }
+
+ ++wavelet->curLine;
+ ++wavelet->curH;
+ wavelet->fltTapH = (wavelet->fltTapH + 1) % 5;
}
- }
}
- }
- uint32_t tileOffset = 0;
- uint32_t dataSize = mdatSize;
- uint8_t *dataPtr = mdatPtr;
- CrxTile *tile = img->tiles;
-
- for (int curTile = 0; curTile < nTiles; curTile++, tile++)
- {
- if (dataSize < 0xC)
- return -1;
-
- if (sgetn(2, dataPtr) != 0xFF01)
- return -1;
- if (sgetn(2, dataPtr + 8) != curTile)
- return -1;
-
- dataSize -= 0xC;
-
- tile->tileSize = sgetn(4, dataPtr + 4);
- tile->dataOffset = tileOffset;
-
- int32_t hdrExtraBytes = sgetn(2, dataPtr + 2) - 8;
- tileOffset += tile->tileSize;
- dataPtr += hdrExtraBytes + 0xC;
- dataSize -= hdrExtraBytes;
-
- uint32_t compOffset = 0;
- CrxPlaneComp *comp = tile->comps;
-
- for (int compNum = 0; compNum < img->nPlanes; compNum++, comp++)
- {
- if (dataSize < 0xC)
- return -1;
-
- if (sgetn(2, dataPtr) != 0xFF02)
- return -1;
- if (compNum != dataPtr[8] >> 4)
- return -1;
-
- comp->compSize = sgetn(4, dataPtr + 4);
-
- int32_t compHdrRoundedBits = (dataPtr[8] >> 1) & 3;
- comp->supportsPartial = (dataPtr[8] & 8) != 0;
-
- comp->dataOffset = compOffset;
- comp->tileFlag = tile->tileFlag;
-
- compOffset += comp->compSize;
- dataSize -= 0xC;
- dataPtr += 0xC;
-
- comp->roundedBitsMask = 0;
-
- if (compHdrRoundedBits)
- {
- if (img->levels || !comp->supportsPartial)
- return -1;
-
- comp->roundedBitsMask = 1 << (compHdrRoundedBits - 1);
- }
-
- if (crxReadSubbandHeaders(hdr, img, tile, comp, &dataPtr, &dataSize))
- return -1;
- }
- }
- return 0;
+ return true;
}
-int crxSetupImageData(crx_data_header_t *hdr, CrxImage *img, int16_t *outBuf,
- uint64_t mdatOffset, uint32_t mdatSize,
- uint8_t *mdatHdrPtr)
+void crxFreeSubbandData(CrxImage* image, CrxPlaneComp* comp)
{
- int IncrBitTable[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0,
- 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0};
-
- img->planeWidth = hdr->f_width;
- img->planeHeight = hdr->f_height;
-
- if (hdr->tileWidth < 0x16 || hdr->tileHeight < 0x16 ||
- img->planeWidth > 0x7FFF || img->planeHeight > 0x7FFF)
- return -1;
-
- img->tileCols = (img->planeWidth + hdr->tileWidth - 1) / hdr->tileWidth;
- img->tileRows = (img->planeHeight + hdr->tileHeight - 1) / hdr->tileHeight;
-
- if (img->tileCols > 0xFF || img->tileRows > 0xFF ||
- img->planeWidth - hdr->tileWidth * (img->tileCols - 1) < 0x16 ||
- img->planeHeight - hdr->tileHeight * (img->tileRows - 1) < 0x16)
- return -1;
-
- img->tiles = 0;
- img->levels = hdr->imageLevels;
- img->subbandCount = 3 * img->levels + 1; // 3 bands per level + one last LL
- img->nPlanes = hdr->nPlanes;
- img->nBits = hdr->nBits;
- img->encType = hdr->encType;
- img->samplePrecision = hdr->nBits + IncrBitTable[4 * hdr->encType + 2] + 1;
- img->mdatOffset = mdatOffset + hdr->mdatHdrSize;
- img->mdatSize = mdatSize;
- img->planeBuf = 0;
- img->outBufs[0] = img->outBufs[1] = img->outBufs[2] = img->outBufs[3] = 0;
-
- // The encoding type 3 needs all 4 planes to be decoded to generate row of
- // RGGB values. It seems to be using some other colour space for raw encoding
- // It is a massive buffer so ideallly it will need a different approach:
- // decode planes line by line and convert single line then without
- // intermediate plane buffer. At the moment though it's too many changes so
- // left as is.
- if (img->encType == 3 && img->nPlanes == 4 && img->nBits > 8)
- {
- img->planeBuf =
- (int16_t *)malloc(img->planeHeight * img->planeWidth * img->nPlanes *
- ((img->samplePrecision + 7) >> 3));
- if (!img->planeBuf)
- return -1;
- }
-
- int32_t rowSize = 2 * img->planeWidth;
-
- if (img->nPlanes == 1)
- img->outBufs[0] = outBuf;
- else
- switch (hdr->cfaLayout)
- {
- case 0:
- // R G
- // G B
- img->outBufs[0] = outBuf;
- img->outBufs[1] = outBuf + 1;
- img->outBufs[2] = outBuf + rowSize;
- img->outBufs[3] = img->outBufs[2] + 1;
- break;
- case 1:
- // G R
- // B G
- img->outBufs[1] = outBuf;
- img->outBufs[0] = outBuf + 1;
- img->outBufs[3] = outBuf + rowSize;
- img->outBufs[2] = img->outBufs[3] + 1;
- break;
- case 2:
- // G B
- // R G
- img->outBufs[2] = outBuf;
- img->outBufs[3] = outBuf + 1;
- img->outBufs[0] = outBuf + rowSize;
- img->outBufs[1] = img->outBufs[0] + 1;
- break;
- case 3:
- // B G
- // G R
- img->outBufs[3] = outBuf;
- img->outBufs[2] = outBuf + 1;
- img->outBufs[1] = outBuf + rowSize;
- img->outBufs[0] = img->outBufs[1] + 1;
- break;
+ if (comp->compBuf) {
+ free(comp->compBuf);
+ comp->compBuf = nullptr;
}
- // read header
- return crxReadImageHeaders(hdr, img, mdatHdrPtr, mdatSize);
+ if (!comp->subBands) {
+ return;
+ }
+
+ for (std::int32_t i = 0; i < image->subbandCount; ++i) {
+ if (comp->subBands[i].bandParam) {
+ free(comp->subBands[i].bandParam);
+ comp->subBands[i].bandParam = nullptr;
+ }
+
+ comp->subBands[i].bandBuf = nullptr;
+ comp->subBands[i].bandSize = 0;
+ }
}
-int crxFreeImageData(CrxImage *img)
+void crxConvertPlaneLine(
+ CrxImage* img,
+ int imageRow,
+ int imageCol = 0,
+ int plane = 0,
+ const std::int32_t* lineData = nullptr,
+ int lineLength = 0
+)
{
- CrxTile *tile = img->tiles;
- int nTiles = img->tileRows * img->tileCols;
+ if (lineData) {
+ std::uint64_t rawOffset = 4 * img->planeWidth * imageRow + 2 * imageCol;
- if (img->tiles)
- {
- for (int32_t curTile = 0; curTile < nTiles; curTile++, tile++)
- if (tile[curTile].comps)
- for (int32_t curPlane = 0; curPlane < img->nPlanes; curPlane++)
- crxFreeSubbandData(img, tile[curTile].comps + curPlane);
- free(img->tiles);
- img->tiles = 0;
- }
+ if (img->encType == 1) {
+ const std::int32_t maxVal = 1 << (img->nBits - 1);
+ const std::int32_t minVal = -maxVal;
- if (img->planeBuf)
- {
- free(img->planeBuf);
- img->planeBuf = 0;
- }
+ for (int i = 0; i < lineLength; ++i) {
+ img->outBufs[plane][rawOffset + 2 * i] = rtengine::LIM(lineData[i], minVal, maxVal - 1);
+ }
+ } else if (img->encType == 3) {
+ // copy to intermediate planeBuf
+ rawOffset = plane * img->planeWidth * img->planeHeight + img->planeWidth * imageRow + imageCol;
- return 0;
+ for (int i = 0; i < lineLength; ++i) {
+ img->planeBuf[rawOffset + i] = lineData[i];
+ }
+ } else if (img->nPlanes == 4) {
+ const std::int32_t median = 1 << (img->nBits - 1);
+ const std::int32_t maxVal = (1 << img->nBits) - 1;
+
+ for (int i = 0; i < lineLength; ++i) {
+ img->outBufs[plane][rawOffset + 2 * i] = rtengine::LIM(median + lineData[i], 0, maxVal);
+ }
+ } else if (img->nPlanes == 1) {
+ const std::int32_t maxVal = (1 << img->nBits) - 1;
+ const std::int32_t median = 1 << (img->nBits - 1);
+
+ rawOffset = img->planeWidth * imageRow + imageCol;
+
+ for (int i = 0; i < lineLength; ++i) {
+ img->outBufs[0][rawOffset + i] = rtengine::LIM(median + lineData[i], 0, maxVal);
+ }
+ }
+ } else if (img->encType == 3 && img->planeBuf) {
+ const std::int32_t planeSize = img->planeWidth * img->planeHeight;
+ const std::int16_t* const plane0 = img->planeBuf + imageRow * img->planeWidth;
+ const std::int16_t* const plane1 = plane0 + planeSize;
+ const std::int16_t* const plane2 = plane1 + planeSize;
+ const std::int16_t* const plane3 = plane2 + planeSize;
+
+ const std::int32_t median = 1 << (img->nBits - 1) << 10;
+ const std::int32_t maxVal = (1 << img->nBits) - 1;
+ const std::uint32_t rawLineOffset = 4 * img->planeWidth * imageRow;
+
+ // for this stage - all except imageRow is ignored
+ for (int i = 0; i < img->planeWidth; ++i) {
+ std::int32_t gr = median + (plane0[i] << 10) - 168 * plane1[i] - 585 * plane3[i];
+
+ if (gr < 0) {
+ gr = -(((std::abs(gr) + 512) >> 9) & ~1);
+ } else {
+ gr = ((std::abs(gr) + 512) >> 9) & ~1;
+ }
+
+ // Essentially R = round(median + P0 + 1.474*P3)
+ std::int32_t val = (median + (plane0[i] << 10) + 1510 * plane3[i] + 512) >> 10;
+ img->outBufs[0][rawLineOffset + 2 * i] = rtengine::LIM(val, 0, maxVal);
+ // Essentially G1 = round(median + P0 + P2 - 0.164*P1 - 0.571*P3)
+ val = (plane2[i] + gr + 1) >> 1;
+ img->outBufs[1][rawLineOffset + 2 * i] = rtengine::LIM(val, 0, maxVal);
+ // Essentially G1 = round(median + P0 - P2 - 0.164*P1 - 0.571*P3)
+ val = (gr - plane2[i] + 1) >> 1;
+ img->outBufs[2][rawLineOffset + 2 * i] = rtengine::LIM(val, 0, maxVal);
+ // Essentially B = round(median + P0 + 1.881*P1)
+ val = (median + (plane0[i] << 10) + 1927 * plane1[i] + 512) >> 10;
+ img->outBufs[3][rawLineOffset + 2 * i] = rtengine::LIM(val, 0, maxVal);
+ }
+ }
+}
+
+bool crxParamInit(
+ CrxBandParam** param,
+ std::uint64_t subbandMdatOffset,
+ std::uint64_t subbandDataSize,
+ std::uint32_t subbandWidth,
+ std::uint32_t subbandHeight,
+ bool supportsPartial,
+ std::uint32_t roundedBitsMask,
+ LibRaw_abstract_datastream* input
+)
+{
+ const std::int32_t progrDataSize =
+ supportsPartial
+ ? 0
+ : sizeof(std::int32_t) * subbandWidth;
+ const std::int32_t paramLength = 2 * subbandWidth + 4;
+
+ std::uint8_t* paramBuf = static_cast(calloc(1, sizeof(CrxBandParam) + sizeof(std::int32_t) * paramLength + progrDataSize));
+
+ if (!paramBuf) {
+ return false;
+ }
+
+ *param = reinterpret_cast(paramBuf);
+
+ paramBuf += sizeof(CrxBandParam);
+
+ (*param)->paramData = reinterpret_cast(paramBuf);
+ (*param)->nonProgrData =
+ progrDataSize
+ ? (*param)->paramData + paramLength
+ : nullptr;
+ (*param)->subbandWidth = subbandWidth;
+ (*param)->subbandHeight = subbandHeight;
+ (*param)->roundedBits = 0;
+ (*param)->curLine = 0;
+ (*param)->roundedBitsMask = roundedBitsMask;
+ (*param)->supportsPartial = supportsPartial;
+ (*param)->bitStream.bitData = 0;
+ (*param)->bitStream.bitsLeft = 0;
+ (*param)->bitStream.mdatSize = subbandDataSize;
+ (*param)->bitStream.curPos = 0;
+ (*param)->bitStream.curBufSize = 0;
+ (*param)->bitStream.curBufOffset = subbandMdatOffset;
+ (*param)->bitStream.input = input;
+
+ crxFillBuffer(&(*param)->bitStream);
+
+ return true;
+}
+
+bool crxSetupSubbandData(
+ CrxImage* img,
+ CrxPlaneComp* planeComp,
+ const CrxTile* tile,
+ std::uint32_t mdatOffset
+)
+{
+ long compDataSize = 0;
+ long waveletDataOffset = 0;
+ long compCoeffDataOffset = 0;
+ const std::int32_t toSubbands = 3 * img->levels + 1;
+
+ CrxSubband* const subbands = planeComp->subBands;
+
+ // calculate sizes
+ for (std::int32_t subbandNum = 0; subbandNum < toSubbands; ++subbandNum) {
+ subbands[subbandNum].bandSize = subbands[subbandNum].width * sizeof(std::int32_t); // 4 bytes
+ compDataSize += subbands[subbandNum].bandSize;
+ }
+
+ if (img->levels) {
+ const std::int32_t encLevels =
+ img->levels
+ ? img->levels
+ : 1;
+ waveletDataOffset = (compDataSize + 7) & ~7;
+ compDataSize = (sizeof(CrxWaveletTransform) * encLevels + waveletDataOffset + 7) & ~7;
+ compCoeffDataOffset = compDataSize;
+
+ // calc wavelet line buffer sizes (always at one level up from current)
+ for (int level = 0; level < img->levels; ++level) {
+ if (level < img->levels - 1) {
+ compDataSize += 8 * sizeof(std::int32_t) * planeComp->subBands[3 * (level + 1) + 2].width;
+ } else {
+ compDataSize += 8 * sizeof(std::int32_t) * tile->width;
+ }
+ }
+ }
+
+ // buffer allocation
+ planeComp->compBuf = static_cast(malloc(compDataSize));
+
+ if (!planeComp->compBuf) {
+ return false;
+ }
+
+ // subbands buffer and sizes initialisation
+ const std::uint64_t subbandMdatOffset = img->mdatOffset + mdatOffset;
+ std::uint8_t* subbandBuf = planeComp->compBuf;
+
+ for (std::int32_t subbandNum = 0; subbandNum < toSubbands; ++subbandNum) {
+ subbands[subbandNum].bandBuf = subbandBuf;
+ subbandBuf += subbands[subbandNum].bandSize;
+ subbands[subbandNum].mdatOffset = subbandMdatOffset + subbands[subbandNum].dataOffset;
+ }
+
+ // wavelet data initialisation
+ if (img->levels) {
+ CrxWaveletTransform* const waveletTransforms = reinterpret_cast(planeComp->compBuf + waveletDataOffset);
+ std::int32_t* paramData = reinterpret_cast(planeComp->compBuf + compCoeffDataOffset);
+
+ planeComp->waveletTransform = waveletTransforms;
+ waveletTransforms[0].subband0Buf = reinterpret_cast(subbands->bandBuf);
+
+ for (int level = 0; level < img->levels; ++level) {
+ const std::int32_t band = 3 * level + 1;
+
+ std::int32_t transformWidth = 0;
+
+ if (level >= img->levels - 1) {
+ waveletTransforms[level].height = tile->height;
+ transformWidth = tile->width;
+ } else {
+ waveletTransforms[level].height = subbands[band + 3].height;
+ transformWidth = subbands[band + 4].width;
+ }
+
+ waveletTransforms[level].width = transformWidth;
+ waveletTransforms[level].lineBuf[0] = paramData;
+ waveletTransforms[level].lineBuf[1] = waveletTransforms[level].lineBuf[0] + transformWidth;
+ waveletTransforms[level].lineBuf[2] = waveletTransforms[level].lineBuf[1] + transformWidth;
+ waveletTransforms[level].lineBuf[3] = waveletTransforms[level].lineBuf[2] + transformWidth;
+ waveletTransforms[level].lineBuf[4] = waveletTransforms[level].lineBuf[3] + transformWidth;
+ waveletTransforms[level].lineBuf[5] = waveletTransforms[level].lineBuf[4] + transformWidth;
+ waveletTransforms[level].lineBuf[6] = waveletTransforms[level].lineBuf[5] + transformWidth;
+ waveletTransforms[level].lineBuf[7] = waveletTransforms[level].lineBuf[6] + transformWidth;
+ waveletTransforms[level].curLine = 0;
+ waveletTransforms[level].curH = 0;
+ waveletTransforms[level].fltTapH = 0;
+ waveletTransforms[level].subband1Buf = reinterpret_cast(subbands[band].bandBuf);
+ waveletTransforms[level].subband2Buf = reinterpret_cast(subbands[band + 1].bandBuf);
+ waveletTransforms[level].subband3Buf = reinterpret_cast(subbands[band + 2].bandBuf);
+
+ paramData = waveletTransforms[level].lineBuf[7] + transformWidth;
+ }
+ }
+
+ // decoding params and bitstream initialisation
+ for (std::int32_t subbandNum = 0; subbandNum < toSubbands; ++subbandNum) {
+ if (subbands[subbandNum].dataSize) {
+ bool supportsPartial = false;
+ std::uint32_t roundedBitsMask = 0;
+
+ if (planeComp->supportsPartial && subbandNum == 0) {
+ roundedBitsMask = planeComp->roundedBitsMask;
+ supportsPartial = true;
+ }
+
+ if (
+ !crxParamInit(
+ &subbands[subbandNum].bandParam,
+ subbands[subbandNum].mdatOffset,
+ subbands[subbandNum].dataSize,
+ subbands[subbandNum].width,
+ subbands[subbandNum].height,
+ supportsPartial,
+ roundedBitsMask,
+ img->input
+ )
+ ) {
+ return false;
+ }
+ }
+ }
+
+ return true;
}
} // namespace
-void DCraw::crxLoadDecodeLoop(void *img, int nPlanes)
+bool DCraw::crxDecodePlane(void* p, std::uint32_t planeNumber)
+{
+ CrxImage* const img = static_cast(p);
+ int imageRow = 0;
+
+ for (int tRow = 0; tRow < img->tileRows; ++tRow) {
+ int imageCol = 0;
+
+ for (int tCol = 0; tCol < img->tileCols; ++tCol) {
+ const CrxTile* const tile = img->tiles + tRow * img->tileRows + tCol;
+ CrxPlaneComp* const planeComp = tile->comps + planeNumber;
+ const std::uint64_t tileMdatOffset = tile->dataOffset + planeComp->dataOffset;
+
+ // decode single tile
+ if (!crxSetupSubbandData(img, planeComp, tile, tileMdatOffset)) {
+ return false;
+ }
+
+ if (img->levels) {
+ if (!crxIdwt53FilterInitialize(planeComp, img->levels - 1)) {
+ return false;
+ }
+
+ for (int i = 0; i < tile->height; ++i) {
+ if (!crxIdwt53FilterDecode(planeComp, img->levels - 1) || !crxIdwt53FilterTransform(planeComp, img->levels - 1)) {
+ return false;
+ }
+
+ const std::int32_t* const lineData = crxIdwt53FilterGetLine(planeComp, img->levels - 1);
+ crxConvertPlaneLine(img, imageRow + i, imageCol, planeNumber, lineData, tile->width);
+ }
+ } else {
+ // we have the only subband in this case
+ if (!planeComp->subBands->dataSize) {
+ memset(planeComp->subBands->bandBuf, 0, planeComp->subBands->bandSize);
+ return true;
+ }
+
+ for (int i = 0; i < tile->height; ++i) {
+ if (!crxDecodeLine(planeComp->subBands->bandParam, planeComp->subBands->bandBuf)) {
+ return false;
+ }
+
+ const std::int32_t* const lineData = reinterpret_cast(planeComp->subBands->bandBuf);
+ crxConvertPlaneLine(img, imageRow + i, imageCol, planeNumber, lineData, tile->width);
+ }
+ }
+
+ imageCol += tile->width;
+ }
+
+ imageRow += img->tiles[tRow * img->tileRows].height;
+ }
+
+ return true;
+}
+
+namespace
+{
+
+using crx_data_header_t = DCraw::CanonCR3Data::crx_data_header_t;
+
+bool crxReadSubbandHeaders(
+ CrxImage* img,
+ CrxTile* tile,
+ CrxPlaneComp* comp,
+ std::uint8_t** subbandMdatPtr,
+ std::uint32_t* mdatSize
+)
+{
+ CrxSubband* band = comp->subBands + img->subbandCount - 1; // set to last band
+ std::uint32_t bandHeight = tile->height;
+ std::uint32_t bandWidth = tile->width;
+ std::int32_t bandWidthExCoef = 0;
+ std::int32_t bandHeightExCoef = 0;
+
+ if (img->levels) {
+ // Build up subband sequences to crxDecode to a level in a header
+
+ // Coefficient structure is a bit unclear and convoluted:
+ // 3 levels max - 8 groups (for tile width rounded to 8 bytes)
+ // of 3 band per level 4 sets of coefficients for each
+ const std::int32_t* rowExCoef = exCoefNumTbl + 0x60 * (img->levels - 1) + 12 * (tile->width & 7);
+ const std::int32_t* colExCoef = exCoefNumTbl + 0x60 * (img->levels - 1) + 12 * (tile->height & 7);
+
+ for (int level = 0; level < img->levels; ++level) {
+ const std::int32_t widthOddPixel = bandWidth & 1;
+ const std::int32_t heightOddPixel = bandHeight & 1;
+ bandWidth = (widthOddPixel + bandWidth) >> 1;
+ bandHeight = (heightOddPixel + bandHeight) >> 1;
+
+ std::int32_t bandWidthExCoef0 = 0;
+ std::int32_t bandWidthExCoef1 = 0;
+ std::int32_t bandHeightExCoef0 = 0;
+ std::int32_t bandHeightExCoef1 = 0;
+
+ if (tile->tileFlag & E_HAS_TILES_ON_THE_RIGHT) {
+ bandWidthExCoef0 = rowExCoef[0];
+ bandWidthExCoef1 = rowExCoef[1];
+ }
+
+ if (tile->tileFlag & E_HAS_TILES_ON_THE_LEFT) {
+ ++bandWidthExCoef0;
+ }
+
+ if (tile->tileFlag & E_HAS_TILES_ON_THE_BOTTOM) {
+ bandHeightExCoef0 = colExCoef[0];
+ bandHeightExCoef1 = colExCoef[1];
+ }
+
+ if (tile->tileFlag & E_HAS_TILES_ON_THE_TOP) {
+ ++bandHeightExCoef0;
+ }
+
+ band[0].width = bandWidth + bandWidthExCoef0 - widthOddPixel;
+ band[0].height = bandHeight + bandHeightExCoef0 - heightOddPixel;
+
+ band[-1].width = bandWidth + bandWidthExCoef1;
+ band[-1].height = bandHeight + bandHeightExCoef0 - heightOddPixel;
+
+ band[-2].width = bandWidth + bandWidthExCoef0 - widthOddPixel;
+ band[-2].height = bandHeight + bandHeightExCoef1;
+
+ rowExCoef += 4;
+ colExCoef += 4;
+ band -= 3;
+ }
+
+ bandWidthExCoef = 0;
+ bandHeightExCoef = 0;
+
+ if (tile->tileFlag & E_HAS_TILES_ON_THE_RIGHT) {
+ bandWidthExCoef = exCoefNumTbl[0x60 * (img->levels - 1) + 12 * (tile->width & 7) + 4 * (img->levels - 1) + 1];
+ }
+
+ if (tile->tileFlag & E_HAS_TILES_ON_THE_BOTTOM) {
+ bandHeightExCoef = exCoefNumTbl[0x60 * (img->levels - 1) + 12 * (tile->height & 7) + 4 * (img->levels - 1) + 1];
+ }
+ }
+
+ band->width = bandWidthExCoef + bandWidth;
+ band->height = bandHeightExCoef + bandHeight;
+
+ if (!img->subbandCount) {
+ return true;
+ }
+
+ std::int32_t subbandOffset = 0;
+ band = comp->subBands;
+
+ for (unsigned int curSubband = 0; curSubband < img->subbandCount; curSubband++, band++) {
+ if (*mdatSize < 0xC) {
+ return false;
+ }
+
+ if (sgetn(2, *subbandMdatPtr) != 0xFF03) {
+ return false;
+ }
+
+ const std::uint32_t bitData = sgetn(4, *subbandMdatPtr + 8);
+ const std::uint32_t subbandSize = sgetn(4, *subbandMdatPtr + 4);
+
+ if (curSubband != bitData >> 28) {
+ band->dataSize = subbandSize;
+ return false;
+ }
+
+ band->dataSize = subbandSize - (bitData & 0x7FF);
+ band->supportsPartial = bitData & 0x8000;
+ band->dataOffset = subbandOffset;
+ band->quantValue = (bitData >> 19) & 0xFF;
+ band->paramK = 0;
+ band->bandParam = nullptr;
+ band->bandBuf = nullptr;
+ band->bandSize = 0;
+
+ subbandOffset += subbandSize;
+
+ *subbandMdatPtr += 0xC;
+ *mdatSize -= 0xC;
+ }
+
+ return true;
+}
+
+bool crxReadImageHeaders(
+ crx_data_header_t* hdr,
+ CrxImage* img,
+ std::uint8_t* mdatPtr,
+ std::uint32_t mdatSize
+)
+{
+ const unsigned int nTiles = img->tileRows * img->tileCols;
+
+ if (!nTiles) {
+ return false;
+ }
+
+ if (!img->tiles) {
+ img->tiles = static_cast(
+ malloc(
+ sizeof(CrxTile) * nTiles
+ + sizeof(CrxPlaneComp) * nTiles * img->nPlanes
+ + sizeof(CrxSubband) * nTiles * img->nPlanes * img->subbandCount
+ )
+ );
+
+ if (!img->tiles) {
+ return false;
+ }
+
+ // memory areas in allocated chunk
+ CrxTile* tile = img->tiles;
+ CrxPlaneComp* const comps = reinterpret_cast(tile + nTiles);
+ CrxSubband* const bands = reinterpret_cast(comps + img->nPlanes * nTiles);
+
+ for (unsigned int curTile = 0; curTile < nTiles; curTile++, tile++) {
+ tile->tileFlag = 0; // tile neighbouring flags
+ tile->tileNumber = curTile;
+ tile->tileSize = 0;
+ tile->comps = comps + curTile * img->nPlanes;
+
+ if ((curTile + 1) % img->tileCols) {
+ // not the last tile in a tile row
+ tile->width = hdr->tileWidth;
+
+ if (img->tileCols > 1) {
+ tile->tileFlag = E_HAS_TILES_ON_THE_RIGHT;
+
+ if (curTile % img->tileCols) {
+ // not the first tile in tile row
+ tile->tileFlag |= E_HAS_TILES_ON_THE_LEFT;
+ }
+ }
+ } else {
+ // last tile in a tile row
+ tile->width = img->planeWidth - hdr->tileWidth * (img->tileCols - 1);
+
+ if (img->tileCols > 1) {
+ tile->tileFlag = E_HAS_TILES_ON_THE_LEFT;
+ }
+ }
+
+ if (curTile < nTiles - img->tileCols) {
+ // in first tile row
+ tile->height = hdr->tileHeight;
+
+ if (img->tileRows > 1) {
+ tile->tileFlag |= E_HAS_TILES_ON_THE_BOTTOM;
+
+ if (curTile >= img->tileCols) {
+ tile->tileFlag |= E_HAS_TILES_ON_THE_TOP;
+ }
+ }
+ } else {
+ // non first tile row
+ tile->height = img->planeHeight - hdr->tileHeight * (img->tileRows - 1);
+
+ if (img->tileRows > 1) {
+ tile->tileFlag |= E_HAS_TILES_ON_THE_TOP;
+ }
+ }
+
+ if (img->nPlanes) {
+ CrxPlaneComp* comp = tile->comps;
+ CrxSubband* band = bands + curTile * img->nPlanes * img->subbandCount;
+
+ for (int curComp = 0; curComp < img->nPlanes; curComp++, comp++) {
+ comp->compNumber = curComp;
+ comp->supportsPartial = true;
+ comp->tileFlag = tile->tileFlag;
+ comp->subBands = band;
+ comp->compBuf = nullptr;
+ comp->waveletTransform = nullptr;
+
+ if (img->subbandCount) {
+ for (int curBand = 0; curBand < img->subbandCount; curBand++, band++) {
+ band->supportsPartial = false;
+ band->quantValue = 4;
+ band->bandParam = nullptr;
+ band->dataSize = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ std::uint32_t tileOffset = 0;
+ std::uint32_t dataSize = mdatSize;
+ std::uint8_t* dataPtr = mdatPtr;
+ CrxTile* tile = img->tiles;
+
+ for (unsigned int curTile = 0; curTile < nTiles; curTile++, tile++) {
+ if (dataSize < 0xC) {
+ return false;
+ }
+
+ if (sgetn(2, dataPtr) != 0xFF01) {
+ return false;
+ }
+
+ if (sgetn(2, dataPtr + 8) != curTile) {
+ return false;
+ }
+
+ dataSize -= 0xC;
+
+ tile->tileSize = sgetn(4, dataPtr + 4);
+ tile->dataOffset = tileOffset;
+
+ const std::int32_t hdrExtraBytes = sgetn(2, dataPtr + 2) - 8;
+ tileOffset += tile->tileSize;
+ dataPtr += hdrExtraBytes + 0xC;
+ dataSize -= hdrExtraBytes;
+
+ std::uint32_t compOffset = 0;
+ CrxPlaneComp* comp = tile->comps;
+
+ for (int compNum = 0; compNum < img->nPlanes; compNum++, comp++) {
+ if (dataSize < 0xC) {
+ return false;
+ }
+
+ if (sgetn(2, dataPtr) != 0xFF02) {
+ return false;
+ }
+
+ if (compNum != dataPtr[8] >> 4) {
+ return false;
+ }
+
+ comp->compSize = sgetn(4, dataPtr + 4);
+
+ std::int32_t compHdrRoundedBits = (dataPtr[8] >> 1) & 3;
+ comp->supportsPartial = (dataPtr[8] & 8) != 0;
+
+ comp->dataOffset = compOffset;
+ comp->tileFlag = tile->tileFlag;
+
+ compOffset += comp->compSize;
+ dataSize -= 0xC;
+ dataPtr += 0xC;
+
+ comp->roundedBitsMask = 0;
+
+ if (compHdrRoundedBits) {
+ if (img->levels || !comp->supportsPartial) {
+ return false;
+ }
+
+ comp->roundedBitsMask = 1 << (compHdrRoundedBits - 1);
+ }
+
+ if (!crxReadSubbandHeaders(img, tile, comp, &dataPtr, &dataSize)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool crxSetupImageData(
+ crx_data_header_t* hdr,
+ CrxImage* img,
+ std::int16_t* outBuf,
+ std::uint64_t mdatOffset,
+ std::uint32_t mdatSize,
+ std::uint8_t* mdatHdrPtr
+)
+{
+ constexpr bool IncrBitTable[32] = {
+ false, false, false, false, false, false, false, false, false, true, true, false, false, false, true, false,
+ false, false, true, false, false, true, true, true, false, true, true, true, false, false, false, false
+ };
+
+ img->planeWidth = hdr->f_width;
+ img->planeHeight = hdr->f_height;
+
+ if (
+ hdr->tileWidth < 0x16
+ || hdr->tileHeight < 0x16
+ || img->planeWidth > 0x7FFF
+ || img->planeHeight > 0x7FFF
+ ) {
+ return false;
+ }
+
+ img->tileCols = (img->planeWidth + hdr->tileWidth - 1) / hdr->tileWidth;
+ img->tileRows = (img->planeHeight + hdr->tileHeight - 1) / hdr->tileHeight;
+
+ if (img->planeWidth - hdr->tileWidth * (img->tileCols - 1) < 0x16 || img->planeHeight - hdr->tileHeight * (img->tileRows - 1) < 0x16) {
+ return false;
+ }
+
+ img->tiles = nullptr;
+ img->levels = hdr->imageLevels;
+ img->subbandCount = 3 * img->levels + 1; // 3 bands per level + one last LL
+ img->nPlanes = hdr->nPlanes;
+ img->nBits = hdr->nBits;
+ img->encType = hdr->encType;
+ img->samplePrecision = hdr->nBits + IncrBitTable[4 * hdr->encType + 2] + 1;
+ img->mdatOffset = mdatOffset + hdr->mdatHdrSize;
+ img->mdatSize = mdatSize;
+ img->planeBuf = nullptr;
+ img->outBufs[0] = img->outBufs[1] = img->outBufs[2] = img->outBufs[3] = nullptr;
+
+ // The encoding type 3 needs all 4 planes to be decoded to generate row of
+ // RGGB values. It seems to be using some other colour space for raw encoding
+ // It is a massive buffer so ideallly it will need a different approach:
+ // decode planes line by line and convert single line then without
+ // intermediate plane buffer. At the moment though it's too many changes so
+ // left as is.
+ if (img->encType == 3 && img->nPlanes == 4 && img->nBits > 8) {
+ img->planeBuf = static_cast(
+ malloc(img->planeHeight * img->planeWidth * img->nPlanes * ((img->samplePrecision + 7) >> 3))
+ );
+
+ if (!img->planeBuf) {
+ return false;
+ }
+ }
+
+ const std::int32_t rowSize = 2 * img->planeWidth;
+
+ if (img->nPlanes == 1) {
+ img->outBufs[0] = outBuf;
+ } else {
+ switch (hdr->cfaLayout) {
+ case 0: {
+ // R G
+ // G B
+ img->outBufs[0] = outBuf;
+ img->outBufs[1] = outBuf + 1;
+ img->outBufs[2] = outBuf + rowSize;
+ img->outBufs[3] = img->outBufs[2] + 1;
+ break;
+ }
+
+ case 1: {
+ // G R
+ // B G
+ img->outBufs[1] = outBuf;
+ img->outBufs[0] = outBuf + 1;
+ img->outBufs[3] = outBuf + rowSize;
+ img->outBufs[2] = img->outBufs[3] + 1;
+ break;
+ }
+
+ case 2: {
+ // G B
+ // R G
+ img->outBufs[2] = outBuf;
+ img->outBufs[3] = outBuf + 1;
+ img->outBufs[0] = outBuf + rowSize;
+ img->outBufs[1] = img->outBufs[0] + 1;
+ break;
+ }
+
+ case 3: {
+ // B G
+ // G R
+ img->outBufs[3] = outBuf;
+ img->outBufs[2] = outBuf + 1;
+ img->outBufs[1] = outBuf + rowSize;
+ img->outBufs[0] = img->outBufs[1] + 1;
+ break;
+ }
+ }
+ }
+
+ // read header
+ return crxReadImageHeaders(hdr, img, mdatHdrPtr, mdatSize);
+}
+
+void crxFreeImageData(CrxImage* img)
+{
+ CrxTile* tile = img->tiles;
+ const int nTiles = img->tileRows * img->tileCols;
+
+ if (img->tiles) {
+ for (std::int32_t curTile = 0; curTile < nTiles; curTile++, tile++) {
+ if (tile[curTile].comps) {
+ for (std::int32_t curPlane = 0; curPlane < img->nPlanes; ++curPlane) {
+ crxFreeSubbandData(img, tile[curTile].comps + curPlane);
+ }
+ }
+ }
+
+ free(img->tiles);
+ img->tiles = nullptr;
+ }
+
+ if (img->planeBuf) {
+ free(img->planeBuf);
+ img->planeBuf = nullptr;
+ }
+}
+
+} // namespace
+
+void DCraw::crxLoadDecodeLoop(void* img, int nPlanes)
{
#ifdef _OPENMP
- int results[4]; // nPlanes is always <= 4
-#pragma omp parallel for
- for (int32_t plane = 0; plane < nPlanes; ++plane)
- results[plane] = crxDecodePlane(img, plane);
+ bool results[4]; // nPlanes is always <= 4
+ #pragma omp parallel for
+
+ for (std::int32_t plane = 0; plane < nPlanes; ++plane) {
+ results[plane] = crxDecodePlane(img, plane);
+ }
+
+ for (std::int32_t plane = 0; plane < nPlanes; ++plane) {
+ if (!results[plane]) {
+ derror();
+ }
+ }
- for (int32_t plane = 0; plane < nPlanes; ++plane)
- if (results[plane])
- derror();
#else
- for (int32_t plane = 0; plane < nPlanes; ++plane)
- if (crxDecodePlane(img, plane))
- derror();
+
+ for (std::int32_t plane = 0; plane < nPlanes; ++plane) {
+ if (!crxDecodePlane(img, plane)) {
+ derror();
+ }
+ }
+
#endif
}
-void DCraw::crxConvertPlaneLineDf(void *p, int imageRow)
+void DCraw::crxConvertPlaneLineDf(void* p, int imageRow)
{
- crxConvertPlaneLine((CrxImage *)p, imageRow);
+ crxConvertPlaneLine(static_cast(p), imageRow);
}
-void DCraw::crxLoadFinalizeLoopE3(void *p, int planeHeight)
+void DCraw::crxLoadFinalizeLoopE3(void* p, int planeHeight)
{
#ifdef _OPENMP
-#pragma omp parallel for
+ #pragma omp parallel for
#endif
- for (int i = 0; i < planeHeight; ++i)
- crxConvertPlaneLineDf(p, i);
+
+ for (int i = 0; i < planeHeight; ++i) {
+ crxConvertPlaneLineDf(p, i);
+ }
}
void DCraw::crxLoadRaw()
{
- CrxImage img;
- if (RT_canon_CR3_data.crx_track_selected < 0 ||
- RT_canon_CR3_data.crx_track_selected >=
- LIBRAW_CRXTRACKS_MAXCOUNT)
- derror();
- crx_data_header_t hdr =
- RT_canon_CR3_data
- .crx_header[RT_canon_CR3_data.crx_track_selected];
+ CrxImage img;
- LibRaw_abstract_datastream input = { ifp };
- img.input = &input; //libraw_internal_data.internal_data.input;
+ if (RT_canon_CR3_data.crx_track_selected >= RT_canon_CR3_data.CRXTRACKS_MAXCOUNT) {
+ derror();
+ }
- // update sizes for the planes
- if (hdr.nPlanes == 4)
- {
- hdr.f_width >>= 1;
- hdr.f_height >>= 1;
- hdr.tileWidth >>= 1;
- hdr.tileHeight >>= 1;
- }
+ crx_data_header_t hdr = RT_canon_CR3_data.crx_header[RT_canon_CR3_data.crx_track_selected];
+
+ LibRaw_abstract_datastream input = {ifp};
+ img.input = &input; // libraw_internal_data.internal_data.input;
+
+ // update sizes for the planes
+ if (hdr.nPlanes == 4) {
+ hdr.f_width >>= 1;
+ hdr.f_height >>= 1;
+ hdr.tileWidth >>= 1;
+ hdr.tileHeight >>= 1;
+ }
// /*imgdata.color.*/maximum = (1 << hdr.nBits) - 1;
- uint8_t *hdrBuf = (uint8_t *)malloc(hdr.mdatHdrSize);
+ std::uint8_t* const hdrBuf = static_cast(malloc(hdr.mdatHdrSize));
- // read image header
+ // read image header
#ifdef _OPENMP
-#pragma omp critical
+ #pragma omp critical
#endif
- {
+ {
#ifndef _OPENMP
- /*libraw_internal_data.internal_data.input->*/input.lock();
+ /*libraw_internal_data.internal_data.input->*/ input.lock();
#endif
- /*libraw_internal_data.internal_data.input->*/input.seek(
- data_offset, SEEK_SET);
- /*libraw_internal_data.internal_data.input->*/input.read(hdrBuf, 1, hdr.mdatHdrSize);
+ /*libraw_internal_data.internal_data.input->*/ input.seek(data_offset, SEEK_SET);
+ /*libraw_internal_data.internal_data.input->*/ input.read(hdrBuf, 1, hdr.mdatHdrSize);
#ifndef _OPENMP
- /*libraw_internal_data.internal_data.input->*/input.unlock();
+ /*libraw_internal_data.internal_data.input->*/ input.unlock();
#endif
- }
+ }
- // parse and setup the image data
- if (crxSetupImageData(&hdr, &img, (int16_t *)raw_image,
- hdr.MediaOffset/*data_offset*/,
- hdr.MediaSize/*RT_canon_CR3_data.data_size*/, hdrBuf))
- derror();
- free(hdrBuf);
+ // parse and setup the image data
+ if (!crxSetupImageData(&hdr, &img, reinterpret_cast(raw_image), hdr.MediaOffset /*data_offset*/, hdr.MediaSize /*RT_canon_CR3_data.data_size*/, hdrBuf)) {
+ derror();
+ }
- crxLoadDecodeLoop(&img, hdr.nPlanes);
+ free(hdrBuf);
- if (img.encType == 3)
- crxLoadFinalizeLoopE3(&img, img.planeHeight);
+ crxLoadDecodeLoop(&img, hdr.nPlanes);
- crxFreeImageData(&img);
+ if (img.encType == 3) {
+ crxLoadFinalizeLoopE3(&img, img.planeHeight);
+ }
+
+ crxFreeImageData(&img);
}
-int DCraw::crxParseImageHeader(uchar *cmp1TagData, int nTrack)
+bool DCraw::crxParseImageHeader(uchar* cmp1TagData, unsigned int nTrack)
{
- if (nTrack < 0 || nTrack >= LIBRAW_CRXTRACKS_MAXCOUNT)
- return -1;
- if (!cmp1TagData)
- return -1;
+ if (nTrack >= RT_canon_CR3_data.CRXTRACKS_MAXCOUNT) {
+ return false;
+ }
- crx_data_header_t *hdr =
- &RT_canon_CR3_data.crx_header[nTrack];
+ if (!cmp1TagData) {
+ return false;
+ }
- hdr->version = sgetn(2, cmp1TagData + 4);
- hdr->f_width = sgetn(4, cmp1TagData + 8);
- hdr->f_height = sgetn(4, cmp1TagData + 12);
- hdr->tileWidth = sgetn(4, cmp1TagData + 16);
- hdr->tileHeight = sgetn(4, cmp1TagData + 20);
- hdr->nBits = cmp1TagData[24];
- hdr->nPlanes = cmp1TagData[25] >> 4;
- hdr->cfaLayout = cmp1TagData[25] & 0xF;
- hdr->encType = cmp1TagData[26] >> 4;
- hdr->imageLevels = cmp1TagData[26] & 0xF;
- hdr->hasTileCols = cmp1TagData[27] >> 7;
- hdr->hasTileRows = (cmp1TagData[27] >> 6) & 1;
- hdr->mdatHdrSize = sgetn(4, cmp1TagData + 28);
+ crx_data_header_t* const hdr = &RT_canon_CR3_data.crx_header[nTrack];
- // validation
- if (hdr->version != 0x100 || !hdr->mdatHdrSize)
- return -1;
- if (hdr->encType == 1)
- {
- if (hdr->nBits > 15)
- return -1;
- }
- else
- {
- if (hdr->encType && hdr->encType != 3)
- return -1;
- if (hdr->nBits > 14)
- return -1;
- }
+ hdr->version = sgetn(2, cmp1TagData + 4);
+ hdr->f_width = sgetn(4, cmp1TagData + 8);
+ hdr->f_height = sgetn(4, cmp1TagData + 12);
+ hdr->tileWidth = sgetn(4, cmp1TagData + 16);
+ hdr->tileHeight = sgetn(4, cmp1TagData + 20);
+ hdr->nBits = cmp1TagData[24];
+ hdr->nPlanes = cmp1TagData[25] >> 4;
+ hdr->cfaLayout = cmp1TagData[25] & 0xF;
+ hdr->encType = cmp1TagData[26] >> 4;
+ hdr->imageLevels = cmp1TagData[26] & 0xF;
+ hdr->hasTileCols = cmp1TagData[27] >> 7;
+ hdr->hasTileRows = (cmp1TagData[27] >> 6) & 1;
+ hdr->mdatHdrSize = sgetn(4, cmp1TagData + 28);
- if (hdr->nPlanes == 1)
- {
- if (hdr->cfaLayout || hdr->encType)
- return -1;
- if (hdr->nBits != 8)
- return -1;
- }
- else if (hdr->nPlanes != 4 || hdr->f_width & 1 || hdr->f_height & 1 ||
- hdr->tileWidth & 1 || hdr->tileHeight & 1 || hdr->cfaLayout > 3u ||
- (hdr->encType && hdr->encType != 1 && hdr->encType != 3) ||
- hdr->nBits == 8)
- return -1;
+ // validation
+ if (hdr->version != 0x100 || !hdr->mdatHdrSize) {
+ return false;
+ }
- if (hdr->tileWidth > hdr->f_width || hdr->tileHeight > hdr->f_height)
- return -1;
+ if (hdr->encType == 1) {
+ if (hdr->nBits > 15) {
+ return false;
+ }
+ } else {
+ if (hdr->encType && hdr->encType != 3) {
+ return false;
+ }
- if (hdr->imageLevels > 3 || hdr->hasTileCols > 1 || hdr->hasTileRows > 1)
- return -1;
- return 0;
+ if (hdr->nBits > 14) {
+ return false;
+ }
+ }
+
+ if (hdr->nPlanes == 1) {
+ if (hdr->cfaLayout || hdr->encType) {
+ return false;
+ }
+
+ if (hdr->nBits != 8) {
+ return false;
+ }
+ } else if (
+ hdr->nPlanes != 4
+ || (hdr->f_width & 1)
+ || (hdr->f_height & 1)
+ || (hdr->tileWidth & 1)
+ || (hdr->tileHeight & 1)
+ || hdr->cfaLayout > 3
+ || (
+ hdr->encType
+ && hdr->encType != 1
+ && hdr->encType != 3
+ )
+ || hdr->nBits == 8
+ ) {
+ return false;
+ }
+
+ if (hdr->tileWidth > hdr->f_width || hdr->tileHeight > hdr->f_height) {
+ return false;
+ }
+
+ if (hdr->imageLevels > 3 || hdr->hasTileCols > 1 || hdr->hasTileRows > 1) {
+ return false;
+ }
+
+ return true;
}
-
-#undef _abs
-#undef _min
-#undef _constrain
-#undef libraw_inline
-#undef LIBRAW_CRXTRACKS_MAXCOUNT
-
-#ifdef __GNUC__ // silence warning
-#pragma GCC diagnostic pop
-#endif
diff --git a/rtengine/capturesharpening.cc b/rtengine/capturesharpening.cc
index e8770f95a..e5bfde555 100644
--- a/rtengine/capturesharpening.cc
+++ b/rtengine/capturesharpening.cc
@@ -152,7 +152,7 @@ inline void gauss5x5div (float** RESTRICT src, float** RESTRICT dst, float** RES
for (int i = 2; i < tileSize - 2; ++i) {
// I tried hand written SSE code but gcc vectorizes better
for (int j = 2; j < tileSize - 2; ++j) {
- const float val = c21 * (src[i - 2][j - 1] + src[i - 2][j + 1] + src[i - 1][j - 2] + src[i - 1][j + 2] + src[i + 1][j - 2] + src[i + 1][j + 2] + src[i + 2][j - 1] + src[i + 2][j + 1]) +
+ const float val = c21 * ((src[i - 2][j - 1] + src[i - 2][j + 1]) + (src[i - 1][j - 2] + src[i - 1][j + 2]) + (src[i + 1][j - 2] + src[i + 1][j + 2]) + (src[i + 2][j - 1] + src[i + 2][j + 1])) +
c20 * (src[i - 2][j] + src[i][j - 2] + src[i][j + 2] + src[i + 2][j]) +
c11 * (src[i - 1][j - 1] + src[i - 1][j + 1] + src[i + 1][j - 1] + src[i + 1][j + 1]) +
c10 * (src[i - 1][j] + src[i][j - 1] + src[i][j + 1] + src[i + 1][j]) +
@@ -178,10 +178,10 @@ inline void gauss7x7div(float** RESTRICT src, float** RESTRICT dst, float** REST
for (int i = 3; i < tileSize - 3; ++i) {
// I tried hand written SSE code but gcc vectorizes better
for (int j = 3; j < tileSize - 3; ++j) {
- const float val = c31 * (src[i - 3][j - 1] + src[i - 3][j + 1] + src[i - 1][j - 3] + src[i - 1][j + 3] + src[i + 1][j - 3] + src[i + 1][j + 3] + src[i + 3][j - 1] + src[i + 3][j + 1]) +
+ const float val = c31 * ((src[i - 3][j - 1] + src[i - 3][j + 1]) + (src[i - 1][j - 3] + src[i - 1][j + 3]) + (src[i + 1][j - 3] + src[i + 1][j + 3]) + (src[i + 3][j - 1] + src[i + 3][j + 1])) +
c30 * (src[i - 3][j] + src[i][j - 3] + src[i][j + 3] + src[i + 3][j]) +
c22 * (src[i - 2][j - 2] + src[i - 2][j + 2] + src[i + 2][j - 2] + src[i + 2][j + 2]) +
- c21 * (src[i - 2][j - 1] + src[i - 2][j + 1] * c21 + src[i - 1][j - 2] + src[i - 1][j + 2] + src[i + 1][j - 2] + src[i + 1][j + 2] + src[i + 2][j - 1] + src[i + 2][j + 1]) +
+ c21 * ((src[i - 2][j - 1] + src[i - 2][j + 1]) + (src[i - 1][j - 2] + src[i - 1][j + 2]) + (src[i + 1][j - 2] + src[i + 1][j + 2]) + (src[i + 2][j - 1] + src[i + 2][j + 1])) +
c20 * (src[i - 2][j] + src[i][j - 2] + src[i][j + 2] + src[i + 2][j]) +
c11 * (src[i - 1][j - 1] + src[i - 1][j + 1] + src[i + 1][j - 1] + src[i + 1][j + 1]) +
c10 * (src[i - 1][j] + src[i][j - 1] + src[i][j + 1] + src[i + 1][j]) +
@@ -221,7 +221,7 @@ inline void gauss5x5mult (float** RESTRICT src, float** RESTRICT dst, const int
for (int i = 2; i < tileSize - 2; ++i) {
// I tried hand written SSE code but gcc vectorizes better
for (int j = 2; j < tileSize - 2; ++j) {
- const float val = c21 * (src[i - 2][j - 1] + src[i - 2][j + 1] + src[i - 1][j - 2] + src[i - 1][j + 2] + src[i + 1][j - 2] + src[i + 1][j + 2] + src[i + 2][j - 1] + src[i + 2][j + 1]) +
+ const float val = c21 * ((src[i - 2][j - 1] + src[i - 2][j + 1]) + (src[i - 1][j - 2] + src[i - 1][j + 2]) + (src[i + 1][j - 2] + src[i + 1][j + 2]) + (src[i + 2][j - 1] + src[i + 2][j + 1])) +
c20 * (src[i - 2][j] + src[i][j - 2] + src[i][j + 2] + src[i + 2][j]) +
c11 * (src[i - 1][j - 1] + src[i - 1][j + 1] + src[i + 1][j - 1] + src[i + 1][j + 1]) +
c10 * (src[i - 1][j] + src[i][j - 1] + src[i][j + 1] + src[i + 1][j]) +
@@ -247,10 +247,10 @@ inline void gauss7x7mult(float** RESTRICT src, float** RESTRICT dst, const int t
for (int i = 3; i < tileSize - 3; ++i) {
// I tried hand written SSE code but gcc vectorizes better
for (int j = 3; j < tileSize - 3; ++j) {
- const float val = c31 * (src[i - 3][j - 1] + src[i - 3][j + 1] + src[i - 1][j - 3] + src[i - 1][j + 3] + src[i + 1][j - 3] + src[i + 1][j + 3] + src[i + 3][j - 1] + src[i + 3][j + 1]) +
+ const float val = c31 * ((src[i - 3][j - 1] + src[i - 3][j + 1]) + (src[i - 1][j - 3] + src[i - 1][j + 3]) + (src[i + 1][j - 3] + src[i + 1][j + 3]) + (src[i + 3][j - 1] + src[i + 3][j + 1])) +
c30 * (src[i - 3][j] + src[i][j - 3] + src[i][j + 3] + src[i + 3][j]) +
c22 * (src[i - 2][j - 2] + src[i - 2][j + 2] + src[i + 2][j - 2] + src[i + 2][j + 2]) +
- c21 * (src[i - 2][j - 1] + src[i - 2][j + 1] * c21 + src[i - 1][j - 2] + src[i - 1][j + 2] + src[i + 1][j - 2] + src[i + 1][j + 2] + src[i + 2][j - 1] + src[i + 2][j + 1]) +
+ c21 * ((src[i - 2][j - 1] + src[i - 2][j + 1]) + (src[i - 1][j - 2] + src[i - 1][j + 2]) + (src[i + 1][j - 2] + src[i + 1][j + 2]) + (src[i + 2][j - 1] + src[i + 2][j + 1])) +
c20 * (src[i - 2][j] + src[i][j - 2] + src[i][j + 2] + src[i + 2][j]) +
c11 * (src[i - 1][j - 1] + src[i - 1][j + 1] + src[i + 1][j - 1] + src[i + 1][j + 1]) +
c10 * (src[i - 1][j] + src[i][j - 1] + src[i][j + 1] + src[i + 1][j]) +
@@ -541,6 +541,7 @@ BENCHFUN
double progress = startVal;
const double progressStep = (endVal - startVal) * rtengine::SQR(tileSize) / (W * H);
+ constexpr float minBlend = 0.01f;
#ifdef _OPENMP
#pragma omp parallel
@@ -562,12 +563,24 @@ BENCHFUN
// fill tiles
if (endOfRow || endOfCol) {
// special handling for small tiles at end of row or column
+ float maxVal = 0.f;
if (checkIterStop) {
for (int k = 0, ii = endOfCol ? H - fullTileSize + border : i; k < tileSize; ++k, ++ii) {
for (int l = 0, jj = endOfRow ? W - fullTileSize + border : j; l < tileSize; ++l, ++jj) {
iterCheck[k][l] = oldLuminance[ii][jj] * clipmask[ii][jj] * 0.5f;
+ maxVal = std::max(maxVal, clipmask[ii][jj]);
}
}
+ } else {
+ for (int k = 0, ii = endOfCol ? H - fullTileSize + border : i; k < tileSize; ++k, ++ii) {
+ for (int l = 0, jj = endOfRow ? W - fullTileSize + border : j; l < tileSize; ++l, ++jj) {
+ maxVal = std::max(maxVal, clipmask[ii][jj]);
+ }
+ }
+ }
+ if (maxVal < minBlend) {
+ // no pixel of the tile has a blend factor >= minBlend => skip the tile
+ continue;
}
for (int k = 0, ii = endOfCol ? H - fullTileSize : i - border; k < fullTileSize; ++k, ++ii) {
for (int l = 0, jj = endOfRow ? W - fullTileSize : j - border; l < fullTileSize; ++l, ++jj) {
@@ -576,12 +589,24 @@ BENCHFUN
}
}
} else {
+ float maxVal = 0.f;
if (checkIterStop) {
for (int ii = 0; ii < tileSize; ++ii) {
for (int jj = 0; jj < tileSize; ++jj) {
iterCheck[ii][jj] = oldLuminance[i + ii][j + jj] * clipmask[i + ii][j + jj] * 0.5f;
+ maxVal = std::max(maxVal, clipmask[i + ii][j + jj]);
}
}
+ } else {
+ for (int ii = 0; ii < tileSize; ++ii) {
+ for (int jj = 0; jj < tileSize; ++jj) {
+ maxVal = std::max(maxVal, clipmask[i + ii][j + jj]);
+ }
+ }
+ }
+ if (maxVal < minBlend) {
+ // no pixel of the tile has a blend factor >= minBlend => skip the tile
+ continue;
}
for (int ii = i; ii < i + fullTileSize; ++ii) {
for (int jj = j; jj < j + fullTileSize; ++jj) {
@@ -687,6 +712,10 @@ namespace rtengine
void RawImageSource::captureSharpening(const procparams::CaptureSharpeningParams &sharpeningParams, bool showMask, double &conrastThreshold, double &radius) {
+ if (!(ri->getSensorType() == ST_BAYER || ri->getSensorType() == ST_FUJI_XTRANS || ri->get_colors() == 1)) {
+ return;
+ }
+
if (plistener) {
plistener->setProgressStr(M("TP_PDSHARPENING_LABEL"));
plistener->setProgress(0.0);
@@ -771,7 +800,7 @@ BENCHFUN
}
array2D& blend = red; // red will be overridden anyway => we can use its buffer to store the blend mask
- buildBlendMask(L, blend, W, H, contrast, 1.f, sharpeningParams.autoContrast, clipMask);
+ buildBlendMask(L, blend, W, H, contrast, sharpeningParams.autoContrast, clipMask);
if (plistener) {
plistener->setProgress(0.2);
}
@@ -820,7 +849,7 @@ BENCHFUN
}
// calculate contrast based blend factors to reduce sharpening in regions with low contrast
array2D& blend = clipMask; // we can share blend and clipMask buffer here
- buildBlendMask(L, blend, W, H, contrast, 1.f, sharpeningParams.autoContrast, clipMask);
+ buildBlendMask(L, blend, W, H, contrast, sharpeningParams.autoContrast, clipMask);
if (plistener) {
plistener->setProgress(0.2);
}
diff --git a/rtengine/color.h b/rtengine/color.h
index 633d33013..81c82ad79 100644
--- a/rtengine/color.h
+++ b/rtengine/color.h
@@ -1373,7 +1373,7 @@ public:
* @param HH hue before [-PI ; +PI]
* @param Chprov1 chroma after [0 ; 180 (can be superior)]
* @param CC chroma before [0 ; 180]
- * @param corectionHuechroma hue correction depending on chromaticity (saturation), in radians [0 ; 0.45] (return value)
+ * @param correctionHueChroma hue correction depending on chromaticity (saturation), in radians [0 ; 0.45] (return value)
* @param correctlum hue correction depending on luminance (brightness, contrast,...), in radians [0 ; 0.45] (return value)
* @param munsDbgInfo (Debug target only) object to collect information
*/
diff --git a/rtengine/dcraw.cc b/rtengine/dcraw.cc
index d5348286c..812f122b3 100644
--- a/rtengine/dcraw.cc
+++ b/rtengine/dcraw.cc
@@ -4433,6 +4433,10 @@ void CLASS foveon_interpolate()
void CLASS crop_masked_pixels()
{
+ if (data_error) {
+ return;
+ }
+
int row, col;
unsigned r, c, m, mblack[8], zero, val;
diff --git a/rtengine/dcraw.h b/rtengine/dcraw.h
index 0265219c7..89c1fcaff 100644
--- a/rtengine/dcraw.h
+++ b/rtengine/dcraw.h
@@ -184,12 +184,12 @@ public:
int32_t mdatHdrSize;
// Not from header, but from datastream
uint32_t MediaSize;
- INT64 MediaOffset;
+ int64_t MediaOffset;
uint32_t MediaType; /* 1 -> /C/RAW, 2-> JPEG */
};
static constexpr size_t CRXTRACKS_MAXCOUNT = 16;
crx_data_header_t crx_header[CRXTRACKS_MAXCOUNT];
- int crx_track_selected;
+ unsigned int crx_track_selected;
short CR3_CTMDtag;
};
protected:
@@ -563,16 +563,16 @@ void nikon_14bit_load_raw(); // ported from LibRaw
// Canon CR3 support ported from LibRaw
//-----------------------------------------------------------------------------
void parse_canon_cr3();
-void selectCRXTrack(short maxTrack);
+void selectCRXTrack(unsigned short maxTrack);
int parseCR3(unsigned long long oAtomList,
unsigned long long szAtomList, short &nesting,
- char *AtomNameStack, short &nTrack, short &TrackType);
-int crxDecodePlane(void *p, uint32_t planeNumber);
+ char *AtomNameStack, unsigned short &nTrack, short &TrackType);
+bool crxDecodePlane(void *p, uint32_t planeNumber);
void crxLoadDecodeLoop(void *img, int nPlanes);
void crxConvertPlaneLineDf(void *p, int imageRow);
void crxLoadFinalizeLoopE3(void *p, int planeHeight);
void crxLoadRaw();
-int crxParseImageHeader(uchar *cmp1TagData, int nTrack);
+bool crxParseImageHeader(uchar *cmp1TagData, unsigned int nTrack);
//-----------------------------------------------------------------------------
};
diff --git a/rtengine/demosaic_algos.cc b/rtengine/demosaic_algos.cc
index d547d3431..538858a9a 100644
--- a/rtengine/demosaic_algos.cc
+++ b/rtengine/demosaic_algos.cc
@@ -21,11 +21,9 @@
#include "rawimagesource.h"
#include "rawimage.h"
-#include "mytime.h"
#include "rt_math.h"
#include "color.h"
#include "../rtgui/multilangmgr.h"
-#include "sleef.h"
#include "opthelper.h"
#include "median.h"
//#define BENCHMARK
@@ -39,16 +37,6 @@ using namespace std;
namespace rtengine
{
-#undef ABS
-
-#define ABS(a) ((a)<0?-(a):(a))
-#define CLIREF(x) LIM(x,-200000.0f,200000.0f) // avoid overflow : do not act directly on image[] or pix[]
-#define x1125(a) (a + xdivf(a, 3))
-#define x0875(a) (a - xdivf(a, 3))
-#define x0250(a) xdivf(a, 2)
-#define x00625(a) xdivf(a, 4)
-#define x0125(a) xdivf(a, 3)
-
#undef fc
#define fc(row,col) \
(ri->get_filters() >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3)
@@ -210,628 +198,6 @@ void RawImageSource::border_interpolate( int winw, int winh, int lborders, const
}
-// LSMME demosaicing algorithm
-// L. Zhang and X. Wu,
-// Color demozaicing via directional Linear Minimum Mean Square-error Estimation,
-// IEEE Trans. on Image Processing, vol. 14, pp. 2167-2178,
-// Dec. 2005.
-// Adapted to RawTherapee by Jacques Desmis 3/2013
-// Improved speed and reduced memory consumption by Ingo Weyrich 2/2015
-//TODO Tiles to reduce memory consumption
-void RawImageSource::lmmse_interpolate_omp(int winw, int winh, array2D &rawData, array2D &red, array2D &green, array2D &blue, int iterations)
-{
- const int width = winw, height = winh;
- const int ba = 10;
- const int rr1 = height + 2 * ba;
- const int cc1 = width + 2 * ba;
- const int w1 = cc1;
- const int w2 = 2 * w1;
- const int w3 = 3 * w1;
- const int w4 = 4 * w1;
- float h0, h1, h2, h3, h4, hs;
- h0 = 1.0f;
- h1 = exp( -1.0f / 8.0f);
- h2 = exp( -4.0f / 8.0f);
- h3 = exp( -9.0f / 8.0f);
- h4 = exp(-16.0f / 8.0f);
- hs = h0 + 2.0f * (h1 + h2 + h3 + h4);
- h0 /= hs;
- h1 /= hs;
- h2 /= hs;
- h3 /= hs;
- h4 /= hs;
- int passref = 0;
- int iter = 0;
-
- if(iterations <= 4) {
- iter = iterations - 1;
- passref = 0;
- } else if (iterations <= 6) {
- iter = 3;
- passref = iterations - 4;
- } else if (iterations <= 8) {
- iter = 3;
- passref = iterations - 6;
- }
-
- bool applyGamma = true;
-
- if(iterations == 0) {
- applyGamma = false;
- iter = 0;
- } else {
- applyGamma = true;
- }
-
- float *rix[5];
- float *qix[5];
- float *buffer = (float *)calloc(static_cast(rr1) * cc1 * 5 * sizeof(float), 1);
-
- if(buffer == nullptr) { // allocation of big block of memory failed, try to get 5 smaller ones
- printf("lmmse_interpolate_omp: allocation of big memory block failed, try to get 5 smaller ones now...\n");
- bool allocationFailed = false;
-
- for(int i = 0; i < 5; i++) {
- qix[i] = (float *)calloc(static_cast(rr1) * cc1 * sizeof(float), 1);
-
- if(!qix[i]) { // allocation of at least one small block failed
- allocationFailed = true;
- }
- }
-
- if(allocationFailed) { // fall back to igv_interpolate
- printf("lmmse_interpolate_omp: allocation of 5 small memory blocks failed, falling back to igv_interpolate...\n");
-
- for(int i = 0; i < 5; i++) { // free the already allocated buffers
- if(qix[i]) {
- free(qix[i]);
- }
- }
-
- igv_interpolate(winw, winh);
- return;
- }
- } else {
- qix[0] = buffer;
-
- for(int i = 1; i < 5; i++) {
- qix[i] = qix[i - 1] + rr1 * cc1;
- }
- }
-
- if (plistener) {
- plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), M("TP_RAW_LMMSE")));
- plistener->setProgress (0.0);
- }
-
-
- LUTf *gamtab;
-
- if(applyGamma) {
- gamtab = &(Color::gammatab_24_17a);
- } else {
- gamtab = new LUTf(65536, LUT_CLIP_ABOVE | LUT_CLIP_BELOW);
- gamtab->makeIdentity(65535.f);
- }
-
-
-#ifdef _OPENMP
- #pragma omp parallel private(rix)
-#endif
- {
-#ifdef _OPENMP
- #pragma omp for
-#endif
-
- for (int rrr = ba; rrr < rr1 - ba; rrr++) {
- for (int ccc = ba, row = rrr - ba; ccc < cc1 - ba; ccc++) {
- int col = ccc - ba;
- float *rix = qix[4] + rrr * cc1 + ccc;
- rix[0] = (*gamtab)[rawData[row][col]];
- }
- }
-
-#ifdef _OPENMP
- #pragma omp single
-#endif
- {
- if (plistener) {
- plistener->setProgress (0.1);
- }
- }
-
- // G-R(B)
-#ifdef _OPENMP
- #pragma omp for schedule(dynamic,16)
-#endif
-
- for (int rr = 2; rr < rr1 - 2; rr++) {
- // G-R(B) at R(B) location
- for (int cc = 2 + (FC(rr, 2) & 1); cc < cc1 - 2; cc += 2) {
- rix[4] = qix[4] + rr * cc1 + cc;
- float v0 = x00625(rix[4][-w1 - 1] + rix[4][-w1 + 1] + rix[4][w1 - 1] + rix[4][w1 + 1]) + x0250(rix[4][0]);
- // horizontal
- rix[0] = qix[0] + rr * cc1 + cc;
- rix[0][0] = - x0250(rix[4][ -2] + rix[4][ 2]) + xdiv2f(rix[4][ -1] + rix[4][0] + rix[4][ 1]);
- float Y = v0 + xdiv2f(rix[0][0]);
-
- if (rix[4][0] > 1.75f * Y) {
- rix[0][0] = median(rix[0][0], rix[4][ -1], rix[4][ 1]);
- } else {
- rix[0][0] = LIM(rix[0][0], 0.0f, 1.0f);
- }
-
- rix[0][0] -= rix[4][0];
- // vertical
- rix[1] = qix[1] + rr * cc1 + cc;
- rix[1][0] = -x0250(rix[4][-w2] + rix[4][w2]) + xdiv2f(rix[4][-w1] + rix[4][0] + rix[4][w1]);
- Y = v0 + xdiv2f(rix[1][0]);
-
- if (rix[4][0] > 1.75f * Y) {
- rix[1][0] = median(rix[1][0], rix[4][-w1], rix[4][w1]);
- } else {
- rix[1][0] = LIM(rix[1][0], 0.0f, 1.0f);
- }
-
- rix[1][0] -= rix[4][0];
- }
-
- // G-R(B) at G location
- for (int ccc = 2 + (FC(rr, 3) & 1); ccc < cc1 - 2; ccc += 2) {
- rix[0] = qix[0] + rr * cc1 + ccc;
- rix[1] = qix[1] + rr * cc1 + ccc;
- rix[4] = qix[4] + rr * cc1 + ccc;
- rix[0][0] = x0250(rix[4][ -2] + rix[4][ 2]) - xdiv2f(rix[4][ -1] + rix[4][0] + rix[4][ 1]);
- rix[1][0] = x0250(rix[4][-w2] + rix[4][w2]) - xdiv2f(rix[4][-w1] + rix[4][0] + rix[4][w1]);
- rix[0][0] = LIM(rix[0][0], -1.0f, 0.0f) + rix[4][0];
- rix[1][0] = LIM(rix[1][0], -1.0f, 0.0f) + rix[4][0];
- }
- }
-
-#ifdef _OPENMP
- #pragma omp single
-#endif
- {
- if (plistener) {
- plistener->setProgress (0.2);
- }
- }
-
-
- // apply low pass filter on differential colors
-#ifdef _OPENMP
- #pragma omp for
-#endif
-
- for (int rr = 4; rr < rr1 - 4; rr++)
- for (int cc = 4; cc < cc1 - 4; cc++) {
- rix[0] = qix[0] + rr * cc1 + cc;
- rix[2] = qix[2] + rr * cc1 + cc;
- rix[2][0] = h0 * rix[0][0] + h1 * (rix[0][ -1] + rix[0][ 1]) + h2 * (rix[0][ -2] + rix[0][ 2]) + h3 * (rix[0][ -3] + rix[0][ 3]) + h4 * (rix[0][ -4] + rix[0][ 4]);
- rix[1] = qix[1] + rr * cc1 + cc;
- rix[3] = qix[3] + rr * cc1 + cc;
- rix[3][0] = h0 * rix[1][0] + h1 * (rix[1][-w1] + rix[1][w1]) + h2 * (rix[1][-w2] + rix[1][w2]) + h3 * (rix[1][-w3] + rix[1][w3]) + h4 * (rix[1][-w4] + rix[1][w4]);
- }
-
-#ifdef _OPENMP
- #pragma omp single
-#endif
- {
- if (plistener) {
- plistener->setProgress (0.3);
- }
- }
-
- // interpolate G-R(B) at R(B)
-#ifdef _OPENMP
- #pragma omp for
-#endif
-
- for (int rr = 4; rr < rr1 - 4; rr++) {
- int cc = 4 + (FC(rr, 4) & 1);
-#ifdef __SSE2__
- __m128 p1v, p2v, p3v, p4v, p5v, p6v, p7v, p8v, p9v, muv, vxv, vnv, xhv, vhv, xvv, vvv;
- __m128 epsv = _mm_set1_ps(1e-7);
- __m128 ninev = _mm_set1_ps(9.f);
-
- for (; cc < cc1 - 10; cc += 8) {
- rix[0] = qix[0] + rr * cc1 + cc;
- rix[1] = qix[1] + rr * cc1 + cc;
- rix[2] = qix[2] + rr * cc1 + cc;
- rix[3] = qix[3] + rr * cc1 + cc;
- rix[4] = qix[4] + rr * cc1 + cc;
- // horizontal
- p1v = LC2VFU(rix[2][-4]);
- p2v = LC2VFU(rix[2][-3]);
- p3v = LC2VFU(rix[2][-2]);
- p4v = LC2VFU(rix[2][-1]);
- p5v = LC2VFU(rix[2][ 0]);
- p6v = LC2VFU(rix[2][ 1]);
- p7v = LC2VFU(rix[2][ 2]);
- p8v = LC2VFU(rix[2][ 3]);
- p9v = LC2VFU(rix[2][ 4]);
- muv = (p1v + p2v + p3v + p4v + p5v + p6v + p7v + p8v + p9v) / ninev;
- vxv = epsv + SQRV(p1v - muv) + SQRV(p2v - muv) + SQRV(p3v - muv) + SQRV(p4v - muv) + SQRV(p5v - muv) + SQRV(p6v - muv) + SQRV(p7v - muv) + SQRV(p8v - muv) + SQRV(p9v - muv);
- p1v -= LC2VFU(rix[0][-4]);
- p2v -= LC2VFU(rix[0][-3]);
- p3v -= LC2VFU(rix[0][-2]);
- p4v -= LC2VFU(rix[0][-1]);
- p5v -= LC2VFU(rix[0][ 0]);
- p6v -= LC2VFU(rix[0][ 1]);
- p7v -= LC2VFU(rix[0][ 2]);
- p8v -= LC2VFU(rix[0][ 3]);
- p9v -= LC2VFU(rix[0][ 4]);
- vnv = epsv + SQRV(p1v) + SQRV(p2v) + SQRV(p3v) + SQRV(p4v) + SQRV(p5v) + SQRV(p6v) + SQRV(p7v) + SQRV(p8v) + SQRV(p9v);
- xhv = (LC2VFU(rix[0][0]) * vxv + LC2VFU(rix[2][0]) * vnv) / (vxv + vnv);
- vhv = vxv * vnv / (vxv + vnv);
-
- // vertical
- p1v = LC2VFU(rix[3][-w4]);
- p2v = LC2VFU(rix[3][-w3]);
- p3v = LC2VFU(rix[3][-w2]);
- p4v = LC2VFU(rix[3][-w1]);
- p5v = LC2VFU(rix[3][ 0]);
- p6v = LC2VFU(rix[3][ w1]);
- p7v = LC2VFU(rix[3][ w2]);
- p8v = LC2VFU(rix[3][ w3]);
- p9v = LC2VFU(rix[3][ w4]);
- muv = (p1v + p2v + p3v + p4v + p5v + p6v + p7v + p8v + p9v) / ninev;
- vxv = epsv + SQRV(p1v - muv) + SQRV(p2v - muv) + SQRV(p3v - muv) + SQRV(p4v - muv) + SQRV(p5v - muv) + SQRV(p6v - muv) + SQRV(p7v - muv) + SQRV(p8v - muv) + SQRV(p9v - muv);
- p1v -= LC2VFU(rix[1][-w4]);
- p2v -= LC2VFU(rix[1][-w3]);
- p3v -= LC2VFU(rix[1][-w2]);
- p4v -= LC2VFU(rix[1][-w1]);
- p5v -= LC2VFU(rix[1][ 0]);
- p6v -= LC2VFU(rix[1][ w1]);
- p7v -= LC2VFU(rix[1][ w2]);
- p8v -= LC2VFU(rix[1][ w3]);
- p9v -= LC2VFU(rix[1][ w4]);
- vnv = epsv + SQRV(p1v) + SQRV(p2v) + SQRV(p3v) + SQRV(p4v) + SQRV(p5v) + SQRV(p6v) + SQRV(p7v) + SQRV(p8v) + SQRV(p9v);
- xvv = (LC2VFU(rix[1][0]) * vxv + LC2VFU(rix[3][0]) * vnv) / (vxv + vnv);
- vvv = vxv * vnv / (vxv + vnv);
- // interpolated G-R(B)
- muv = (xhv * vvv + xvv * vhv) / (vhv + vvv);
- STC2VFU(rix[4][0], muv);
- }
-
-#endif
-
- for (; cc < cc1 - 4; cc += 2) {
- rix[0] = qix[0] + rr * cc1 + cc;
- rix[1] = qix[1] + rr * cc1 + cc;
- rix[2] = qix[2] + rr * cc1 + cc;
- rix[3] = qix[3] + rr * cc1 + cc;
- rix[4] = qix[4] + rr * cc1 + cc;
- // horizontal
- float p1 = rix[2][-4];
- float p2 = rix[2][-3];
- float p3 = rix[2][-2];
- float p4 = rix[2][-1];
- float p5 = rix[2][ 0];
- float p6 = rix[2][ 1];
- float p7 = rix[2][ 2];
- float p8 = rix[2][ 3];
- float p9 = rix[2][ 4];
- float mu = (p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) / 9.f;
- float vx = 1e-7 + SQR(p1 - mu) + SQR(p2 - mu) + SQR(p3 - mu) + SQR(p4 - mu) + SQR(p5 - mu) + SQR(p6 - mu) + SQR(p7 - mu) + SQR(p8 - mu) + SQR(p9 - mu);
- p1 -= rix[0][-4];
- p2 -= rix[0][-3];
- p3 -= rix[0][-2];
- p4 -= rix[0][-1];
- p5 -= rix[0][ 0];
- p6 -= rix[0][ 1];
- p7 -= rix[0][ 2];
- p8 -= rix[0][ 3];
- p9 -= rix[0][ 4];
- float vn = 1e-7 + SQR(p1) + SQR(p2) + SQR(p3) + SQR(p4) + SQR(p5) + SQR(p6) + SQR(p7) + SQR(p8) + SQR(p9);
- float xh = (rix[0][0] * vx + rix[2][0] * vn) / (vx + vn);
- float vh = vx * vn / (vx + vn);
-
- // vertical
- p1 = rix[3][-w4];
- p2 = rix[3][-w3];
- p3 = rix[3][-w2];
- p4 = rix[3][-w1];
- p5 = rix[3][ 0];
- p6 = rix[3][ w1];
- p7 = rix[3][ w2];
- p8 = rix[3][ w3];
- p9 = rix[3][ w4];
- mu = (p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) / 9.f;
- vx = 1e-7 + SQR(p1 - mu) + SQR(p2 - mu) + SQR(p3 - mu) + SQR(p4 - mu) + SQR(p5 - mu) + SQR(p6 - mu) + SQR(p7 - mu) + SQR(p8 - mu) + SQR(p9 - mu);
- p1 -= rix[1][-w4];
- p2 -= rix[1][-w3];
- p3 -= rix[1][-w2];
- p4 -= rix[1][-w1];
- p5 -= rix[1][ 0];
- p6 -= rix[1][ w1];
- p7 -= rix[1][ w2];
- p8 -= rix[1][ w3];
- p9 -= rix[1][ w4];
- vn = 1e-7 + SQR(p1) + SQR(p2) + SQR(p3) + SQR(p4) + SQR(p5) + SQR(p6) + SQR(p7) + SQR(p8) + SQR(p9);
- float xv = (rix[1][0] * vx + rix[3][0] * vn) / (vx + vn);
- float vv = vx * vn / (vx + vn);
- // interpolated G-R(B)
- rix[4][0] = (xh * vv + xv * vh) / (vh + vv);
- }
- }
-
-#ifdef _OPENMP
- #pragma omp single
-#endif
- {
- if (plistener) {
- plistener->setProgress (0.4);
- }
- }
-
- // copy CFA values
-#ifdef _OPENMP
- #pragma omp for
-#endif
-
- for (int rr = 0; rr < rr1; rr++)
- for (int cc = 0, row = rr - ba; cc < cc1; cc++) {
- int col = cc - ba;
- int c = FC(rr, cc);
- rix[c] = qix[c] + rr * cc1 + cc;
-
- if ((row >= 0) & (row < height) & (col >= 0) & (col < width)) {
- rix[c][0] = (*gamtab)[rawData[row][col]];
- } else {
- rix[c][0] = 0.f;
- }
-
- if (c != 1) {
- rix[1] = qix[1] + rr * cc1 + cc;
- rix[4] = qix[4] + rr * cc1 + cc;
- rix[1][0] = rix[c][0] + rix[4][0];
- }
- }
-
-#ifdef _OPENMP
- #pragma omp single
-#endif
- {
- if (plistener) {
- plistener->setProgress (0.5);
- }
- }
-
- // bilinear interpolation for R/B
- // interpolate R/B at G location
-#ifdef _OPENMP
- #pragma omp for
-#endif
-
- for (int rr = 1; rr < rr1 - 1; rr++)
- for (int cc = 1 + (FC(rr, 2) & 1), c = FC(rr, cc + 1); cc < cc1 - 1; cc += 2) {
- rix[c] = qix[c] + rr * cc1 + cc;
- rix[1] = qix[1] + rr * cc1 + cc;
- rix[c][0] = rix[1][0] + xdiv2f(rix[c][ -1] - rix[1][ -1] + rix[c][ 1] - rix[1][ 1]);
- c = 2 - c;
- rix[c] = qix[c] + rr * cc1 + cc;
- rix[c][0] = rix[1][0] + xdiv2f(rix[c][-w1] - rix[1][-w1] + rix[c][w1] - rix[1][w1]);
- c = 2 - c;
- }
-
-#ifdef _OPENMP
- #pragma omp single
-#endif
- {
- if (plistener) {
- plistener->setProgress (0.6);
- }
- }
-
- // interpolate R/B at B/R location
-#ifdef _OPENMP
- #pragma omp for
-#endif
-
- for (int rr = 1; rr < rr1 - 1; rr++)
- for (int cc = 1 + (FC(rr, 1) & 1), c = 2 - FC(rr, cc); cc < cc1 - 1; cc += 2) {
- rix[c] = qix[c] + rr * cc1 + cc;
- rix[1] = qix[1] + rr * cc1 + cc;
- rix[c][0] = rix[1][0] + x0250(rix[c][-w1] - rix[1][-w1] + rix[c][ -1] - rix[1][ -1] + rix[c][ 1] - rix[1][ 1] + rix[c][ w1] - rix[1][ w1]);
- }
-
-#ifdef _OPENMP
- #pragma omp single
-#endif
- {
- if (plistener) {
- plistener->setProgress (0.7);
- }
- }
-
- }// End of parallelization 1
-
- // median filter/
- for (int pass = 0; pass < iter; pass++) {
- // Apply 3x3 median filter
- // Compute median(R-G) and median(B-G)
-
-#ifdef _OPENMP
- #pragma omp parallel for private(rix)
-#endif
-
- for (int rr = 1; rr < rr1 - 1; rr++) {
- for (int c = 0; c < 3; c += 2) {
- int d = c + 3 - (c == 0 ? 0 : 1);
- int cc = 1;
-#ifdef __SSE2__
-
- for (; cc < cc1 - 4; cc += 4) {
- rix[d] = qix[d] + rr * cc1 + cc;
- rix[c] = qix[c] + rr * cc1 + cc;
- rix[1] = qix[1] + rr * cc1 + cc;
- // Assign 3x3 differential color values
- const std::array p = {
- LVFU(rix[c][-w1 - 1]) - LVFU(rix[1][-w1 - 1]),
- LVFU(rix[c][-w1]) - LVFU(rix[1][-w1]),
- LVFU(rix[c][-w1 + 1]) - LVFU(rix[1][-w1 + 1]),
- LVFU(rix[c][ -1]) - LVFU(rix[1][ -1]),
- LVFU(rix[c][ 0]) - LVFU(rix[1][ 0]),
- LVFU(rix[c][ 1]) - LVFU(rix[1][ 1]),
- LVFU(rix[c][ w1 - 1]) - LVFU(rix[1][ w1 - 1]),
- LVFU(rix[c][ w1]) - LVFU(rix[1][ w1]),
- LVFU(rix[c][ w1 + 1]) - LVFU(rix[1][ w1 + 1])
- };
- _mm_storeu_ps(&rix[d][0], median(p));
- }
-
-#endif
-
- for (; cc < cc1 - 1; cc++) {
- rix[d] = qix[d] + rr * cc1 + cc;
- rix[c] = qix[c] + rr * cc1 + cc;
- rix[1] = qix[1] + rr * cc1 + cc;
- // Assign 3x3 differential color values
- const std::array p = {
- rix[c][-w1 - 1] - rix[1][-w1 - 1],
- rix[c][-w1] - rix[1][-w1],
- rix[c][-w1 + 1] - rix[1][-w1 + 1],
- rix[c][ -1] - rix[1][ -1],
- rix[c][ 0] - rix[1][ 0],
- rix[c][ 1] - rix[1][ 1],
- rix[c][ w1 - 1] - rix[1][ w1 - 1],
- rix[c][ w1] - rix[1][ w1],
- rix[c][ w1 + 1] - rix[1][ w1 + 1]
- };
- rix[d][0] = median(p);
- }
- }
- }
-
- // red/blue at GREEN pixel locations & red/blue and green at BLUE/RED pixel locations
-#ifdef _OPENMP
- #pragma omp parallel for private (rix)
-#endif
-
- for (int rr = 0; rr < rr1; rr++) {
- rix[0] = qix[0] + rr * cc1;
- rix[1] = qix[1] + rr * cc1;
- rix[2] = qix[2] + rr * cc1;
- rix[3] = qix[3] + rr * cc1;
- rix[4] = qix[4] + rr * cc1;
- int c0 = FC(rr, 0);
- int c1 = FC(rr, 1);
-
- if(c0 == 1) {
- c1 = 2 - c1;
- int d = c1 + 3 - (c1 == 0 ? 0 : 1);
- int cc;
-
- for (cc = 0; cc < cc1 - 1; cc += 2) {
- rix[0][0] = rix[1][0] + rix[3][0];
- rix[2][0] = rix[1][0] + rix[4][0];
- rix[0]++;
- rix[1]++;
- rix[2]++;
- rix[3]++;
- rix[4]++;
- rix[c1][0] = rix[1][0] + rix[d][0];
- rix[1][0] = 0.5f * (rix[0][0] - rix[3][0] + rix[2][0] - rix[4][0]);
- rix[0]++;
- rix[1]++;
- rix[2]++;
- rix[3]++;
- rix[4]++;
- }
-
- if(cc < cc1) { // remaining pixel, only if width is odd
- rix[0][0] = rix[1][0] + rix[3][0];
- rix[2][0] = rix[1][0] + rix[4][0];
- }
- } else {
- c0 = 2 - c0;
- int d = c0 + 3 - (c0 == 0 ? 0 : 1);
- int cc;
-
- for (cc = 0; cc < cc1 - 1; cc += 2) {
- rix[c0][0] = rix[1][0] + rix[d][0];
- rix[1][0] = 0.5f * (rix[0][0] - rix[3][0] + rix[2][0] - rix[4][0]);
- rix[0]++;
- rix[1]++;
- rix[2]++;
- rix[3]++;
- rix[4]++;
- rix[0][0] = rix[1][0] + rix[3][0];
- rix[2][0] = rix[1][0] + rix[4][0];
- rix[0]++;
- rix[1]++;
- rix[2]++;
- rix[3]++;
- rix[4]++;
- }
-
- if(cc < cc1) { // remaining pixel, only if width is odd
- rix[c0][0] = rix[1][0] + rix[d][0];
- rix[1][0] = 0.5f * (rix[0][0] - rix[3][0] + rix[2][0] - rix[4][0]);
- }
- }
- }
- }
-
- if (plistener) {
- plistener->setProgress (0.8);
- }
-
- if(applyGamma) {
- gamtab = &(Color::igammatab_24_17);
- } else {
- gamtab->makeIdentity();
- }
-
- array2D* rgb[3];
- rgb[0] = &red;
- rgb[1] = &green;
- rgb[2] = &blue;
-
- // copy result back to image matrix
-#ifdef _OPENMP
- #pragma omp parallel for
-#endif
-
- for (int row = 0; row < height; row++) {
- for (int col = 0, rr = row + ba; col < width; col++) {
- int cc = col + ba;
- int c = FC(row, col);
-
- for (int ii = 0; ii < 3; ii++)
- if (ii != c) {
- float *rix = qix[ii] + rr * cc1 + cc;
- (*(rgb[ii]))[row][col] = (*gamtab)[65535.f * rix[0]];
- } else {
- (*(rgb[ii]))[row][col] = CLIP(rawData[row][col]);
- }
- }
- }
-
- if (plistener) {
- plistener->setProgress (1.0);
- }
-
- if(buffer) {
- free(buffer);
- } else
- for(int i = 0; i < 5; i++) {
- free(qix[i]);
- }
-
- if(!applyGamma) {
- delete gamtab;
- }
-
- if(iterations > 4 && iterations <= 6) {
- refinement(passref);
- } else if(iterations > 6) {
- refinement_lassus(passref);
- }
-
-}
-
/***
*
* Bayer CFA Demosaicing using Integrated Gaussian Vector on Color Differences
@@ -849,7 +215,6 @@ void RawImageSource::lmmse_interpolate_omp(int winw, int winh, array2D &r
// Adapted to RawTherapee by Jacques Desmis 3/2013
// SSE version by Ingo Weyrich 5/2013
#ifdef __SSE2__
-#define CLIPV(a) vclampf(a,zerov,c65535v)
void RawImageSource::igv_interpolate(int winw, int winh)
{
static const float eps = 1e-5f, epssq = 1e-5f; //mod epssq -10f =>-5f Jacques 3/2013 to prevent artifact (divide by zero)
@@ -918,9 +283,9 @@ void RawImageSource::igv_interpolate(int winw, int winh)
for (col = 0, indx = row * width + col; col < width - 7; col += 8, indx += 8) {
temp1v = LVFU( rawData[row][col] );
- temp1v = CLIPV( temp1v );
+ temp1v = vmaxf(temp1v, ZEROV);
temp2v = LVFU( rawData[row][col + 4] );
- temp2v = CLIPV( temp2v );
+ temp2v = vmaxf(temp2v, ZEROV);
tempv = _mm_shuffle_ps( temp1v, temp2v, _MM_SHUFFLE( 2, 0, 2, 0 ) );
_mm_storeu_ps( &dest1[indx >> 1], tempv );
tempv = _mm_shuffle_ps( temp1v, temp2v, _MM_SHUFFLE( 3, 1, 3, 1 ) );
@@ -928,10 +293,10 @@ void RawImageSource::igv_interpolate(int winw, int winh)
}
for (; col < width; col++, indx += 2) {
- dest1[indx >> 1] = CLIP(rawData[row][col]); //rawData = RT data
+ dest1[indx >> 1] = std::max(0.f, rawData[row][col]); //rawData = RT data
col++;
if(col < width)
- dest2[indx >> 1] = CLIP(rawData[row][col]); //rawData = RT data
+ dest2[indx >> 1] = std::max(0.f, rawData[row][col]); //rawData = RT data
}
}
@@ -1190,42 +555,42 @@ void RawImageSource::igv_interpolate(int winw, int winh)
temp2v = LVFU( src2[(indx + 1) >> 1] );
tempv = _mm_shuffle_ps( temp1v, temp2v, _MM_SHUFFLE( 1, 0, 1, 0 ) );
tempv = _mm_shuffle_ps( tempv, tempv, _MM_SHUFFLE( 3, 1, 2, 0 ) );
- _mm_storeu_ps( &green[row][col], CLIPV( tempv ));
+ _mm_storeu_ps( &green[row][col], vmaxf(tempv, ZEROV));
temp5v = LVFU(redsrc0[indx >> 1]);
temp6v = LVFU(redsrc1[(indx + 1) >> 1]);
temp3v = _mm_shuffle_ps( temp5v, temp6v, _MM_SHUFFLE( 1, 0, 1, 0 ) );
temp3v = _mm_shuffle_ps( temp3v, temp3v, _MM_SHUFFLE( 3, 1, 2, 0 ) );
- temp3v = CLIPV( tempv - c65535v * temp3v );
+ temp3v = vmaxf(tempv - c65535v * temp3v, ZEROV);
_mm_storeu_ps( &red[row][col], temp3v);
temp7v = LVFU(bluesrc0[indx >> 1]);
temp8v = LVFU(bluesrc1[(indx + 1) >> 1]);
temp4v = _mm_shuffle_ps( temp7v, temp8v, _MM_SHUFFLE( 1, 0, 1, 0 ) );
temp4v = _mm_shuffle_ps( temp4v, temp4v, _MM_SHUFFLE( 3, 1, 2, 0 ) );
- temp4v = CLIPV( tempv - c65535v * temp4v );
+ temp4v = vmaxf(tempv - c65535v * temp4v, ZEROV);
_mm_storeu_ps( &blue[row][col], temp4v);
tempv = _mm_shuffle_ps( temp1v, temp2v, _MM_SHUFFLE( 3, 2, 3, 2 ) );
tempv = _mm_shuffle_ps( tempv, tempv, _MM_SHUFFLE( 3, 1, 2, 0 ) );
- _mm_storeu_ps( &green[row][col + 4], CLIPV( tempv ));
+ _mm_storeu_ps( &green[row][col + 4], vmaxf(tempv, ZEROV));
temp3v = _mm_shuffle_ps( temp5v, temp6v, _MM_SHUFFLE( 3, 2, 3, 2 ) );
temp3v = _mm_shuffle_ps( temp3v, temp3v, _MM_SHUFFLE( 3, 1, 2, 0 ) );
- temp3v = CLIPV( tempv - c65535v * temp3v );
+ temp3v = vmaxf(tempv - c65535v * temp3v, ZEROV);
_mm_storeu_ps( &red[row][col + 4], temp3v);
temp4v = _mm_shuffle_ps( temp7v, temp8v, _MM_SHUFFLE( 3, 2, 3, 2 ) );
temp4v = _mm_shuffle_ps( temp4v, temp4v, _MM_SHUFFLE( 3, 1, 2, 0 ) );
- temp4v = CLIPV( tempv - c65535v * temp4v );
+ temp4v = vmaxf(tempv - c65535v * temp4v, ZEROV);
_mm_storeu_ps( &blue[row][col + 4], temp4v);
}
for(; col < width - 7; col++, indx += 2) {
- red [row][col] = CLIP(src1[indx >> 1] - 65535.f * redsrc0[indx >> 1]);
- green[row][col] = CLIP(src1[indx >> 1]);
- blue [row][col] = CLIP(src1[indx >> 1] - 65535.f * bluesrc0[indx >> 1]);
+ red [row][col] = std::max(0.f, src1[indx >> 1] - 65535.f * redsrc0[indx >> 1]);
+ green[row][col] = std::max(0.f, src1[indx >> 1]);
+ blue [row][col] = std::max(0.f, src1[indx >> 1] - 65535.f * bluesrc0[indx >> 1]);
col++;
- red [row][col] = CLIP(src2[(indx + 1) >> 1] - 65535.f * redsrc1[(indx + 1) >> 1]);
- green[row][col] = CLIP(src2[(indx + 1) >> 1]);
- blue [row][col] = CLIP(src2[(indx + 1) >> 1] - 65535.f * bluesrc1[(indx + 1) >> 1]);
+ red [row][col] = std::max(0.f, src2[(indx + 1) >> 1] - 65535.f * redsrc1[(indx + 1) >> 1]);
+ green[row][col] = std::max(0.f, src2[(indx + 1) >> 1]);
+ blue [row][col] = std::max(0.f, src2[(indx + 1) >> 1] - 65535.f * bluesrc1[(indx + 1) >> 1]);
}
}
}// End of parallelization
@@ -1240,7 +605,6 @@ void RawImageSource::igv_interpolate(int winw, int winh)
free(vdif);
free(hdif);
}
-#undef CLIPV
#else
void RawImageSource::igv_interpolate(int winw, int winh)
{
@@ -1283,7 +647,7 @@ void RawImageSource::igv_interpolate(int winw, int winh)
for (int row = 0; row < height - 0; row++)
for (int col = 0, indx = row * width + col; col < width - 0; col++, indx++) {
int c = FC(row, col);
- rgb[c][indx] = CLIP(rawData[row][col]); //rawData = RT data
+ rgb[c][indx] = std::max(0.f, rawData[row][col]); //rawData = RT data
}
#ifdef _OPENMP
@@ -1482,9 +846,9 @@ void RawImageSource::igv_interpolate(int winw, int winh)
for(int row = 7; row < height - 7; row++)
for(int col = 7, indx = row * width + col; col < width - 7; col++, indx++) {
- red [row][col] = CLIP(rgb[1][indx] - 65535.f * chr[0][indx]);
- green[row][col] = CLIP(rgb[1][indx]);
- blue [row][col] = CLIP(rgb[1][indx] - 65535.f * chr[1][indx]);
+ red [row][col] = std::max(0.f, rgb[1][indx] - 65535.f * chr[0][indx]);
+ green[row][col] = std::max(0.f, rgb[1][indx]);
+ blue [row][col] = std::max(0.f, rgb[1][indx] - 65535.f * chr[1][indx]);
}
}// End of parallelization
border_interpolate(winw, winh, 8, rawData, red, green, blue);
@@ -1553,357 +917,6 @@ void RawImageSource::nodemosaic(bool bw)
}
}
-/*
- Refinement based on EECI demosaicing algorithm by L. Chang and Y.P. Tan
- Paul Lee
- Adapted for RawTherapee - Jacques Desmis 04/2013
-*/
-
-#ifdef __SSE2__
-#define CLIPV(a) vclampf(a,ZEROV,c65535v)
-#endif
-void RawImageSource::refinement(int PassCount)
-{
- MyTime t1e, t2e;
- t1e.set();
-
- int width = W;
- int height = H;
- int w1 = width;
- int w2 = 2 * w1;
-
- if (plistener) {
- plistener->setProgressStr (M("TP_RAW_DMETHOD_PROGRESSBAR_REFINE"));
- }
-
- array2D *rgb[3];
- rgb[0] = &red;
- rgb[1] = &green;
- rgb[2] = &blue;
-
- for (int b = 0; b < PassCount; b++) {
- if (plistener) {
- plistener->setProgress ((float)b / PassCount);
- }
-
-
-#ifdef _OPENMP
- #pragma omp parallel
-#endif
- {
- float *pix[3];
-
- /* Reinforce interpolated green pixels on RED/BLUE pixel locations */
-#ifdef _OPENMP
- #pragma omp for
-#endif
-
- for (int row = 2; row < height - 2; row++) {
- int col = 2 + (FC(row, 2) & 1);
- int c = FC(row, col);
-#ifdef __SSE2__
- __m128 dLv, dRv, dUv, dDv, v0v;
- __m128 onev = _mm_set1_ps(1.f);
- __m128 zd5v = _mm_set1_ps(0.5f);
- __m128 c65535v = _mm_set1_ps(65535.f);
-
- for (; col < width - 8; col += 8) {
- int indx = row * width + col;
- pix[c] = (float*)(*rgb[c]) + indx;
- pix[1] = (float*)(*rgb[1]) + indx;
- dLv = onev / (onev + vabsf(LC2VFU(pix[c][ -2]) - LC2VFU(pix[c][0])) + vabsf(LC2VFU(pix[1][ 1]) - LC2VFU(pix[1][ -1])));
- dRv = onev / (onev + vabsf(LC2VFU(pix[c][ 2]) - LC2VFU(pix[c][0])) + vabsf(LC2VFU(pix[1][ 1]) - LC2VFU(pix[1][ -1])));
- dUv = onev / (onev + vabsf(LC2VFU(pix[c][-w2]) - LC2VFU(pix[c][0])) + vabsf(LC2VFU(pix[1][w1]) - LC2VFU(pix[1][-w1])));
- dDv = onev / (onev + vabsf(LC2VFU(pix[c][ w2]) - LC2VFU(pix[c][0])) + vabsf(LC2VFU(pix[1][w1]) - LC2VFU(pix[1][-w1])));
- v0v = CLIPV(LC2VFU(pix[c][0]) + zd5v + ((LC2VFU(pix[1][-1]) - LC2VFU(pix[c][-1])) * dLv + (LC2VFU(pix[1][1]) - LC2VFU(pix[c][1])) * dRv + (LC2VFU(pix[1][-w1]) - LC2VFU(pix[c][-w1])) * dUv + (LC2VFU(pix[1][w1]) - LC2VFU(pix[c][w1])) * dDv ) / (dLv + dRv + dUv + dDv));
- STC2VFU(pix[1][0], v0v);
- }
-
-#endif
-
- for (; col < width - 2; col += 2) {
- int indx = row * width + col;
- pix[c] = (float*)(*rgb[c]) + indx;
- pix[1] = (float*)(*rgb[1]) + indx;
- float dL = 1.f / (1.f + fabsf(pix[c][ -2] - pix[c][0]) + fabsf(pix[1][ 1] - pix[1][ -1]));
- float dR = 1.f / (1.f + fabsf(pix[c][ 2] - pix[c][0]) + fabsf(pix[1][ 1] - pix[1][ -1]));
- float dU = 1.f / (1.f + fabsf(pix[c][-w2] - pix[c][0]) + fabsf(pix[1][w1] - pix[1][-w1]));
- float dD = 1.f / (1.f + fabsf(pix[c][ w2] - pix[c][0]) + fabsf(pix[1][w1] - pix[1][-w1]));
- float v0 = (pix[c][0] + 0.5f + ((pix[1][ -1] - pix[c][ -1]) * dL + (pix[1][ 1] - pix[c][ 1]) * dR + (pix[1][-w1] - pix[c][-w1]) * dU + (pix[1][ w1] - pix[c][ w1]) * dD ) / (dL + dR + dU + dD));
- pix[1][0] = CLIP(v0);
- }
- }
-
- /* Reinforce interpolated red/blue pixels on GREEN pixel locations */
-#ifdef _OPENMP
- #pragma omp for
-#endif
-
- for (int row = 2; row < height - 2; row++) {
- int col = 2 + (FC(row, 3) & 1);
- int c = FC(row, col + 1);
-#ifdef __SSE2__
- __m128 dLv, dRv, dUv, dDv, v0v;
- __m128 onev = _mm_set1_ps(1.f);
- __m128 zd5v = _mm_set1_ps(0.5f);
- __m128 c65535v = _mm_set1_ps(65535.f);
-
- for (; col < width - 8; col += 8) {
- int indx = row * width + col;
- pix[1] = (float*)(*rgb[1]) + indx;
-
- for (int i = 0; i < 2; c = 2 - c, i++) {
- pix[c] = (float*)(*rgb[c]) + indx;
- dLv = onev / (onev + vabsf(LC2VFU(pix[1][ -2]) - LC2VFU(pix[1][0])) + vabsf(LC2VFU(pix[c][ 1]) - LC2VFU(pix[c][ -1])));
- dRv = onev / (onev + vabsf(LC2VFU(pix[1][ 2]) - LC2VFU(pix[1][0])) + vabsf(LC2VFU(pix[c][ 1]) - LC2VFU(pix[c][ -1])));
- dUv = onev / (onev + vabsf(LC2VFU(pix[1][-w2]) - LC2VFU(pix[1][0])) + vabsf(LC2VFU(pix[c][w1]) - LC2VFU(pix[c][-w1])));
- dDv = onev / (onev + vabsf(LC2VFU(pix[1][ w2]) - LC2VFU(pix[1][0])) + vabsf(LC2VFU(pix[c][w1]) - LC2VFU(pix[c][-w1])));
- v0v = CLIPV(LC2VFU(pix[1][0]) + zd5v - ((LC2VFU(pix[1][-1]) - LC2VFU(pix[c][-1])) * dLv + (LC2VFU(pix[1][1]) - LC2VFU(pix[c][1])) * dRv + (LC2VFU(pix[1][-w1]) - LC2VFU(pix[c][-w1])) * dUv + (LC2VFU(pix[1][w1]) - LC2VFU(pix[c][w1])) * dDv ) / (dLv + dRv + dUv + dDv));
- STC2VFU(pix[c][0], v0v);
- }
- }
-
-#endif
-
- for (; col < width - 2; col += 2) {
- int indx = row * width + col;
- pix[1] = (float*)(*rgb[1]) + indx;
-
- for (int i = 0; i < 2; c = 2 - c, i++) {
- pix[c] = (float*)(*rgb[c]) + indx;
- float dL = 1.f / (1.f + fabsf(pix[1][ -2] - pix[1][0]) + fabsf(pix[c][ 1] - pix[c][ -1]));
- float dR = 1.f / (1.f + fabsf(pix[1][ 2] - pix[1][0]) + fabsf(pix[c][ 1] - pix[c][ -1]));
- float dU = 1.f / (1.f + fabsf(pix[1][-w2] - pix[1][0]) + fabsf(pix[c][w1] - pix[c][-w1]));
- float dD = 1.f / (1.f + fabsf(pix[1][ w2] - pix[1][0]) + fabsf(pix[c][w1] - pix[c][-w1]));
- float v0 = (pix[1][0] + 0.5f - ((pix[1][ -1] - pix[c][ -1]) * dL + (pix[1][ 1] - pix[c][ 1]) * dR + (pix[1][-w1] - pix[c][-w1]) * dU + (pix[1][ w1] - pix[c][ w1]) * dD ) / (dL + dR + dU + dD));
- pix[c][0] = CLIP(v0);
- }
- }
- }
-
- /* Reinforce integrated red/blue pixels on BLUE/RED pixel locations */
-#ifdef _OPENMP
- #pragma omp for
-#endif
-
- for (int row = 2; row < height - 2; row++) {
- int col = 2 + (FC(row, 2) & 1);
- int c = 2 - FC(row, col);
-#ifdef __SSE2__
- __m128 dLv, dRv, dUv, dDv, v0v;
- __m128 onev = _mm_set1_ps(1.f);
- __m128 zd5v = _mm_set1_ps(0.5f);
- __m128 c65535v = _mm_set1_ps(65535.f);
-
- for (; col < width - 8; col += 8) {
- int indx = row * width + col;
- pix[0] = (float*)(*rgb[0]) + indx;
- pix[1] = (float*)(*rgb[1]) + indx;
- pix[2] = (float*)(*rgb[2]) + indx;
- int d = 2 - c;
- dLv = onev / (onev + vabsf(LC2VFU(pix[d][ -2]) - LC2VFU(pix[d][0])) + vabsf(LC2VFU(pix[1][ 1]) - LC2VFU(pix[1][ -1])));
- dRv = onev / (onev + vabsf(LC2VFU(pix[d][ 2]) - LC2VFU(pix[d][0])) + vabsf(LC2VFU(pix[1][ 1]) - LC2VFU(pix[1][ -1])));
- dUv = onev / (onev + vabsf(LC2VFU(pix[d][-w2]) - LC2VFU(pix[d][0])) + vabsf(LC2VFU(pix[1][w1]) - LC2VFU(pix[1][-w1])));
- dDv = onev / (onev + vabsf(LC2VFU(pix[d][ w2]) - LC2VFU(pix[d][0])) + vabsf(LC2VFU(pix[1][w1]) - LC2VFU(pix[1][-w1])));
- v0v = CLIPV(LC2VFU(pix[1][0]) + zd5v - ((LC2VFU(pix[1][-1]) - LC2VFU(pix[c][-1])) * dLv + (LC2VFU(pix[1][1]) - LC2VFU(pix[c][1])) * dRv + (LC2VFU(pix[1][-w1]) - LC2VFU(pix[c][-w1])) * dUv + (LC2VFU(pix[1][w1]) - LC2VFU(pix[c][w1])) * dDv ) / (dLv + dRv + dUv + dDv));
- STC2VFU(pix[c][0], v0v);
- }
-
-#endif
-
- for (; col < width - 2; col += 2) {
- int indx = row * width + col;
- pix[0] = (float*)(*rgb[0]) + indx;
- pix[1] = (float*)(*rgb[1]) + indx;
- pix[2] = (float*)(*rgb[2]) + indx;
- int d = 2 - c;
- float dL = 1.f / (1.f + fabsf(pix[d][ -2] - pix[d][0]) + fabsf(pix[1][ 1] - pix[1][ -1]));
- float dR = 1.f / (1.f + fabsf(pix[d][ 2] - pix[d][0]) + fabsf(pix[1][ 1] - pix[1][ -1]));
- float dU = 1.f / (1.f + fabsf(pix[d][-w2] - pix[d][0]) + fabsf(pix[1][w1] - pix[1][-w1]));
- float dD = 1.f / (1.f + fabsf(pix[d][ w2] - pix[d][0]) + fabsf(pix[1][w1] - pix[1][-w1]));
- float v0 = (pix[1][0] + 0.5f - ((pix[1][ -1] - pix[c][ -1]) * dL + (pix[1][ 1] - pix[c][ 1]) * dR + (pix[1][-w1] - pix[c][-w1]) * dU + (pix[1][ w1] - pix[c][ w1]) * dD ) / (dL + dR + dU + dD));
- pix[c][0] = CLIP(v0);
- }
- }
- } // end parallel
- }
-
- t2e.set();
-
- if (settings->verbose) {
- printf("Refinement Lee %d usec\n", t2e.etime(t1e));
- }
-}
-#ifdef __SSE2__
-#undef CLIPV
-#endif
-
-
-// Refinement based on EECI demozaicing algorithm by L. Chang and Y.P. Tan
-// from "Lassus" : Luis Sanz Rodriguez, adapted by Jacques Desmis - JDC - and Oliver Duis for RawTherapee
-// increases the signal to noise ratio (PSNR) # +1 to +2 dB : tested with Dcraw :
-// eg: Lighthouse + AMaZE : without refinement:39.96 dB, with refinement:41.86 dB
-// reduce color artifacts, improves the interpolation
-// but it's relatively slow
-//
-// Should be DISABLED if it decreases image quality by increases some image noise and generates blocky edges
-void RawImageSource::refinement_lassus(int PassCount)
-{
- // const int PassCount=1;
-
- // if (settings->verbose) printf("Refinement\n");
-
- MyTime t1e, t2e;
- t1e.set();
- int u = W, v = 2 * u, w = 3 * u, x = 4 * u, y = 5 * u;
- float (*image)[3];
- image = (float(*)[3]) calloc(static_cast(W) * H, sizeof * image);
-#ifdef _OPENMP
- #pragma omp parallel shared(image)
-#endif
- {
- // convert red, blue, green to image
-#ifdef _OPENMP
- #pragma omp for
-#endif
-
- for (int i = 0; i < H; i++) {
- for (int j = 0; j < W; j++) {
- image[i * W + j][0] = red [i][j];
- image[i * W + j][1] = green[i][j];
- image[i * W + j][2] = blue [i][j];
- }
- }
-
- for (int b = 0; b < PassCount; b++) {
- if (plistener) {
- plistener->setProgressStr (M("TP_RAW_DMETHOD_PROGRESSBAR_REFINE"));
- plistener->setProgress ((float)b / PassCount);
- }
-
- // Reinforce interpolated green pixels on RED/BLUE pixel locations
-#ifdef _OPENMP
- #pragma omp for
-#endif
-
- for (int row = 6; row < H - 6; row++) {
- for (int col = 6 + (FC(row, 2) & 1), c = FC(row, col); col < W - 6; col += 2) {
- float (*pix)[3] = image + row * W + col;
-
- // Cubic Spline Interpolation by Li and Randhawa, modified by Luis Sanz Rodriguez
-
- float f[4];
- f[0] = 1.0f / (1.0f + xmul2f(fabs(x1125(pix[-v][c]) - x0875(pix[0][c]) - x0250(pix[-x][c]))) + fabs(x0875(pix[u][1]) - x1125(pix[-u][1]) + x0250(pix[-w][1])) + fabs(x0875(pix[-w][1]) - x1125(pix[-u][1]) + x0250(pix[-y][1])));
- f[1] = 1.0f / (1.0f + xmul2f(fabs(x1125(pix[+2][c]) - x0875(pix[0][c]) - x0250(pix[+4][c]))) + fabs(x0875(pix[1][1]) - x1125(pix[-1][1]) + x0250(pix[+3][1])) + fabs(x0875(pix[+3][1]) - x1125(pix[+1][1]) + x0250(pix[+5][1])));
- f[2] = 1.0f / (1.0f + xmul2f(fabs(x1125(pix[-2][c]) - x0875(pix[0][c]) - x0250(pix[-4][c]))) + fabs(x0875(pix[1][1]) - x1125(pix[-1][1]) + x0250(pix[-3][1])) + fabs(x0875(pix[-3][1]) - x1125(pix[-1][1]) + x0250(pix[-5][1])));
- f[3] = 1.0f / (1.0f + xmul2f(fabs(x1125(pix[+v][c]) - x0875(pix[0][c]) - x0250(pix[+x][c]))) + fabs(x0875(pix[u][1]) - x1125(pix[-u][1]) + x0250(pix[+w][1])) + fabs(x0875(pix[+w][1]) - x1125(pix[+u][1]) + x0250(pix[+y][1])));
-
- float g[4];//CLIREF avoid overflow
- g[0] = pix[0][c] + (x0875(CLIREF(pix[-u][1] - pix[-u][c])) + x0125(CLIREF(pix[+u][1] - pix[+u][c])));
- g[1] = pix[0][c] + (x0875(CLIREF(pix[+1][1] - pix[+1][c])) + x0125(CLIREF(pix[-1][1] - pix[-1][c])));
- g[2] = pix[0][c] + (x0875(CLIREF(pix[-1][1] - pix[-1][c])) + x0125(CLIREF(pix[+1][1] - pix[+1][c])));
- g[3] = pix[0][c] + (x0875(CLIREF(pix[+u][1] - pix[+u][c])) + x0125(CLIREF(pix[-u][1] - pix[-u][c])));
-
- pix[0][1] = (f[0] * g[0] + f[1] * g[1] + f[2] * g[2] + f[3] * g[3]) / (f[0] + f[1] + f[2] + f[3]);
-
- }
- }
-
- // Reinforce interpolated red/blue pixels on GREEN pixel locations
-#ifdef _OPENMP
- #pragma omp for
-#endif
-
- for (int row = 6; row < H - 6; row++) {
- for (int col = 6 + (FC(row, 3) & 1), c = FC(row, col + 1); col < W - 6; col += 2) {
- float (*pix)[3] = image + row * W + col;
-
- for (int i = 0; i < 2; c = 2 - c, i++) {
- float f[4];
- f[0] = 1.0f / (1.0f + xmul2f(fabs(x0875(pix[-v][1]) - x1125(pix[0][1]) + x0250(pix[-x][1]))) + fabs(pix[u] [c] - pix[-u][c]) + fabs(pix[-w][c] - pix[-u][c]));
- f[1] = 1.0f / (1.0f + xmul2f(fabs(x0875(pix[+2][1]) - x1125(pix[0][1]) + x0250(pix[+4][1]))) + fabs(pix[+1][c] - pix[-1][c]) + fabs(pix[+3][c] - pix[+1][c]));
- f[2] = 1.0f / (1.0f + xmul2f(fabs(x0875(pix[-2][1]) - x1125(pix[0][1]) + x0250(pix[-4][1]))) + fabs(pix[+1][c] - pix[-1][c]) + fabs(pix[-3][c] - pix[-1][c]));
- f[3] = 1.0f / (1.0f + xmul2f(fabs(x0875(pix[+v][1]) - x1125(pix[0][1]) + x0250(pix[+x][1]))) + fabs(pix[u] [c] - pix[-u][c]) + fabs(pix[+w][c] - pix[+u][c]));
-
- float g[5];//CLIREF avoid overflow
- g[0] = CLIREF(pix[-u][1] - pix[-u][c]);
- g[1] = CLIREF(pix[+1][1] - pix[+1][c]);
- g[2] = CLIREF(pix[-1][1] - pix[-1][c]);
- g[3] = CLIREF(pix[+u][1] - pix[+u][c]);
- g[4] = ((f[0] * g[0] + f[1] * g[1] + f[2] * g[2] + f[3] * g[3]) / (f[0] + f[1] + f[2] + f[3]));
- pix[0][c] = pix[0][1] - (0.65f * g[4] + 0.35f * CLIREF(pix[0][1] - pix[0][c]));
- }
- }
- }
-
- // Reinforce integrated red/blue pixels on BLUE/RED pixel locations
-#ifdef _OPENMP
- #pragma omp for
-#endif
-
- for (int row = 6; row < H - 6; row++) {
- for (int col = 6 + (FC(row, 2) & 1), c = 2 - FC(row, col), d = 2 - c; col < W - 6; col += 2) {
- float (*pix)[3] = image + row * W + col;
-
- float f[4];
- f[0] = 1.0f / (1.0f + xmul2f(fabs(x1125(pix[-v][d]) - x0875(pix[0][d]) - x0250(pix[-x][d]))) + fabs(x0875(pix[u][1]) - x1125(pix[-u][1]) + x0250(pix[-w][1])) + fabs(x0875(pix[-w][1]) - x1125(pix[-u][1]) + x0250(pix[-y][1])));
- f[1] = 1.0f / (1.0f + xmul2f(fabs(x1125(pix[+2][d]) - x0875(pix[0][d]) - x0250(pix[+4][d]))) + fabs(x0875(pix[1][1]) - x1125(pix[-1][1]) + x0250(pix[+3][1])) + fabs(x0875(pix[+3][1]) - x1125(pix[+1][1]) + x0250(pix[+5][1])));
- f[2] = 1.0f / (1.0f + xmul2f(fabs(x1125(pix[-2][d]) - x0875(pix[0][d]) - x0250(pix[-4][d]))) + fabs(x0875(pix[1][1]) - x1125(pix[-1][1]) + x0250(pix[-3][1])) + fabs(x0875(pix[-3][1]) - x1125(pix[-1][1]) + x0250(pix[-5][1])));
- f[3] = 1.0f / (1.0f + xmul2f(fabs(x1125(pix[+v][d]) - x0875(pix[0][d]) - x0250(pix[+x][d]))) + fabs(x0875(pix[u][1]) - x1125(pix[-u][1]) + x0250(pix[+w][1])) + fabs(x0875(pix[+w][1]) - x1125(pix[+u][1]) + x0250(pix[+y][1])));
-
- float g[5];
- g[0] = (x0875((pix[-u][1] - pix[-u][c])) + x0125((pix[-v][1] - pix[-v][c])));
- g[1] = (x0875((pix[+1][1] - pix[+1][c])) + x0125((pix[+2][1] - pix[+2][c])));
- g[2] = (x0875((pix[-1][1] - pix[-1][c])) + x0125((pix[-2][1] - pix[-2][c])));
- g[3] = (x0875((pix[+u][1] - pix[+u][c])) + x0125((pix[+v][1] - pix[+v][c])));
-
- g[4] = (f[0] * g[0] + f[1] * g[1] + f[2] * g[2] + f[3] * g[3]) / (f[0] + f[1] + f[2] + f[3]);
-
- const std::array p = {
- pix[-u - 1][1] - pix[-u - 1][c],
- pix[-u + 0][1] - pix[-u + 0][c],
- pix[-u + 1][1] - pix[-u + 1][c],
- pix[+0 - 1][1] - pix[+0 - 1][c],
- pix[+0 + 0][1] - pix[+0 + 0][c],
- pix[+0 + 1][1] - pix[+0 + 1][c],
- pix[+u - 1][1] - pix[+u - 1][c],
- pix[+u + 0][1] - pix[+u + 0][c],
- pix[+u + 1][1] - pix[+u + 1][c]
- };
-
- const float med = median(p);
-
- pix[0][c] = LIM(pix[0][1] - (1.30f * g[4] - 0.30f * (pix[0][1] - pix[0][c])), 0.99f * (pix[0][1] - med), 1.01f * (pix[0][1] - med));
-
- }
- }
-
- }
-
- // put modified values to red, green, blue
-#ifdef _OPENMP
- #pragma omp for
-#endif
-
- for (int i = 0; i < H; i++) {
- for (int j = 0; j < W; j++) {
- red [i][j] = image[i * W + j][0];
- green[i][j] = image[i * W + j][1];
- blue [i][j] = image[i * W + j][2];
- }
- }
- }
-
- free(image);
-
- t2e.set();
-
- if (settings->verbose) {
- printf("Refinement Lassus %d usec\n", t2e.etime(t1e));
- }
-}
-
-
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -2505,9 +1518,9 @@ BENCHFUN
*/
for(int y = 0; y < TILESIZE && y0 + y < H; y++) {
for (int j = 0; j < TILESIZE && x0 + j < W; j++) {
- red[y0 + y][x0 + j] = tile[(y + TILEBORDER) * CACHESIZE + TILEBORDER + j][0];
- green[y0 + y][x0 + j] = tile[(y + TILEBORDER) * CACHESIZE + TILEBORDER + j][1];
- blue[y0 + y][x0 + j] = tile[(y + TILEBORDER) * CACHESIZE + TILEBORDER + j][2];
+ red[y0 + y][x0 + j] = std::max(0.f, tile[(y + TILEBORDER) * CACHESIZE + TILEBORDER + j][0]);
+ green[y0 + y][x0 + j] = std::max(0.f, tile[(y + TILEBORDER) * CACHESIZE + TILEBORDER + j][1]);
+ blue[y0 + y][x0 + j] = std::max(0.f, tile[(y + TILEBORDER) * CACHESIZE + TILEBORDER + j][2]);
}
}
diff --git a/rtengine/dual_demosaic_RT.cc b/rtengine/dual_demosaic_RT.cc
index 69d1a189a..93508808c 100644
--- a/rtengine/dual_demosaic_RT.cc
+++ b/rtengine/dual_demosaic_RT.cc
@@ -105,7 +105,7 @@ void RawImageSource::dual_demosaic_RT(bool isBayer, const procparams::RAWParams
JaggedArray blend(winw, winh);
float contrastf = contrast / 100.f;
- buildBlendMask(L, blend, winw, winh, contrastf, 1.f, autoContrast);
+ buildBlendMask(L, blend, winw, winh, contrastf, autoContrast);
contrast = contrastf * 100.f;
array2D& redTmp = L; // L is not needed anymore => reuse it
diff --git a/rtengine/eahd_demosaic.cc b/rtengine/eahd_demosaic.cc
index c470eb297..ad4bda3cd 100644
--- a/rtengine/eahd_demosaic.cc
+++ b/rtengine/eahd_demosaic.cc
@@ -400,11 +400,11 @@ void RawImageSource::eahd_demosaic ()
int vc = homv[imx][j];
if (hc > vc) {
- green[i - 1][j] = gh[(i - 1) % 4][j];
+ green[i - 1][j] = std::max(0.f, gh[(i - 1) % 4][j]);
} else if (hc < vc) {
- green[i - 1][j] = gv[(i - 1) % 4][j];
+ green[i - 1][j] = std::max(0.f, gv[(i - 1) % 4][j]);
} else {
- green[i - 1][j] = (gh[(i - 1) % 4][j] + gv[(i - 1) % 4][j]) / 2;
+ green[i - 1][j] = std::max(0.f, (gh[(i - 1) % 4][j] + gv[(i - 1) % 4][j]) / 2);
}
}
}
@@ -421,11 +421,11 @@ void RawImageSource::eahd_demosaic ()
int vc = homv[(i - 1) % 3][j];
if (hc > vc) {
- green[i - 1][j] = gh[(i - 1) % 4][j];
+ green[i - 1][j] = std::max(0.f, gh[(i - 1) % 4][j]);
} else if (hc < vc) {
- green[i - 1][j] = gv[(i - 1) % 4][j];
+ green[i - 1][j] = std::max(0.f, gv[(i - 1) % 4][j]);
} else {
- green[i - 1][j] = (gh[(i - 1) % 4][j] + gv[(i - 1) % 4][j]) / 2;
+ green[i - 1][j] = std::max(0.f, (gh[(i - 1) % 4][j] + gv[(i - 1) % 4][j]) / 2);
}
}
diff --git a/rtengine/fast_demo.cc b/rtengine/fast_demo.cc
index aaa5ceb02..772096b87 100644
--- a/rtengine/fast_demo.cc
+++ b/rtengine/fast_demo.cc
@@ -452,23 +452,23 @@ void RawImageSource::fast_demosaic()
#ifdef __SSE2__
for (j = left + 2, cc = 2; j < right - 5; j += 4, cc += 4) {
- _mm_storeu_ps(&red[i][j], LVFU(redtile[rr * TS + cc]));
- _mm_storeu_ps(&green[i][j], LVFU(greentile[rr * TS + cc]));
- _mm_storeu_ps(&blue[i][j], LVFU(bluetile[rr * TS + cc]));
+ _mm_storeu_ps(&red[i][j], vmaxf(LVFU(redtile[rr * TS + cc]), ZEROV));
+ _mm_storeu_ps(&green[i][j], vmaxf(LVFU(greentile[rr * TS + cc]), ZEROV));
+ _mm_storeu_ps(&blue[i][j], vmaxf(LVFU(bluetile[rr * TS + cc]), ZEROV));
}
for (; j < right - 2; j++, cc++) {
- red[i][j] = redtile[rr * TS + cc];
- green[i][j] = greentile[rr * TS + cc];
- blue[i][j] = bluetile[rr * TS + cc];
+ red[i][j] = std::max(0.f, redtile[rr * TS + cc]);
+ green[i][j] = std::max(0.f, greentile[rr * TS + cc]);
+ blue[i][j] = std::max(0.f, bluetile[rr * TS + cc]);
}
#else
for (int j = left + 2, cc = 2; j < right - 2; j++, cc++) {
- red[i][j] = redtile[rr * TS + cc];
- green[i][j] = greentile[rr * TS + cc];
- blue[i][j] = bluetile[rr * TS + cc];
+ red[i][j] = std::max(0.f, redtile[rr * TS + cc]);
+ green[i][j] = std::max(0.f, greentile[rr * TS + cc]);
+ blue[i][j] = std::max(0.f, bluetile[rr * TS + cc]);
}
#endif
diff --git a/rtengine/hphd_demosaic_RT.cc b/rtengine/hphd_demosaic_RT.cc
index 5e05b128e..936c8fa4f 100644
--- a/rtengine/hphd_demosaic_RT.cc
+++ b/rtengine/hphd_demosaic_RT.cc
@@ -217,7 +217,7 @@ void hphd_green(const RawImage *ri, const array2D &rawData, float** hpmap
const float e4 = 1.f / (dx + (std::fabs(d1) + std::fabs(d2)) + (std::fabs(d3) + std::fabs(d4)) * 0.5f);
- green[i][j] = rawData[i][j] * 0.5f + (e2 * g2 + e4 * g4) / (e2 + e4);
+ green[i][j] = std::max(0.f, rawData[i][j] * 0.5f + (e2 * g2 + e4 * g4) / (e2 + e4));
} else if (hpmap[i][j] == 2) {
const float g1 = rawData[i - 1][j] - rawData[i - 2][j] * 0.5f;
const float g3 = rawData[i + 1][j] - rawData[i + 2][j] * 0.5f;
@@ -237,7 +237,7 @@ void hphd_green(const RawImage *ri, const array2D &rawData, float** hpmap
const float e3 = 1.f / (dy + (std::fabs(d1) + std::fabs(d2)) + (std::fabs(d3) + std::fabs(d4)) * 0.5f);
- green[i][j] = rawData[i][j] * 0.5f + (e1 * g1 + e3 * g3) / (e1 + e3);
+ green[i][j] = std::max(0.f, rawData[i][j] * 0.5f + (e1 * g1 + e3 * g3) / (e1 + e3));
} else {
const float g1 = rawData[i - 1][j] - rawData[i - 2][j] * 0.5f;
const float g2 = rawData[i][j + 1] - rawData[i][j + 2] * 0.5f;
@@ -275,7 +275,7 @@ void hphd_green(const RawImage *ri, const array2D &rawData, float** hpmap
const float e4 = 1.f / (dx + (std::fabs(d1) + std::fabs(d2)) + (std::fabs(d3) + std::fabs(d4)) * 0.5f);
- green[i][j] = rawData[i][j] * 0.5f + ((e1 * g1 + e2 * g2) + (e3 * g3 + e4 * g4)) / (e1 + e2 + e3 + e4);
+ green[i][j] = std::max(0.f, rawData[i][j] * 0.5f + ((e1 * g1 + e2 * g2) + (e3 * g3 + e4 * g4)) / (e1 + e2 + e3 + e4));
}
}
}
diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc
index cb0834570..59fb0f016 100644
--- a/rtengine/improcfun.cc
+++ b/rtengine/improcfun.cc
@@ -5590,7 +5590,7 @@ void ImProcFunctions::getAutoExp (const LUTu &histogram, int histcompr, double
whiteclipg = CurveFactory::igamma2 ((float) (whiteclipg / 65535.0)) * 65535.0; //need to inverse gamma transform to get correct exposure compensation parameter
- //corection with gamma
+ //correction with gamma
black = (int) ((65535 * black) / whiteclipg);
//expcomp = log(65535.0 / (whiteclipg)) / log(2.0);
diff --git a/rtengine/ipsharpen.cc b/rtengine/ipsharpen.cc
index a35476d3a..7198b76c5 100644
--- a/rtengine/ipsharpen.cc
+++ b/rtengine/ipsharpen.cc
@@ -256,7 +256,7 @@ void ImProcFunctions::sharpening (LabImage* lab, const procparams::SharpeningPar
// calculate contrast based blend factors to reduce sharpening in regions with low contrast
JaggedArray blend(W, H);
float contrast = sharpenParam.contrast / 100.f;
- buildBlendMask(lab->L, blend, W, H, contrast, 1.f);
+ buildBlendMask(lab->L, blend, W, H, contrast);
if(showMask) {
#ifdef _OPENMP
diff --git a/rtengine/lmmse_demosaic.cc b/rtengine/lmmse_demosaic.cc
new file mode 100644
index 000000000..f4af1b801
--- /dev/null
+++ b/rtengine/lmmse_demosaic.cc
@@ -0,0 +1,818 @@
+/*
+ * This file is part of RawTherapee.
+ *
+ * Copyright (c) 2004-2019 Gabor Horvath
+ *
+ * RawTherapee 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.
+ *
+ * RawTherapee 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 RawTherapee. If not, see .
+ */
+#include
+
+#include "rawimagesource.h"
+#include "rt_math.h"
+#include "color.h"
+#include "../rtgui/multilangmgr.h"
+#include "sleef.h"
+#include "opthelper.h"
+#include "median.h"
+
+using namespace std;
+
+namespace rtengine
+{
+
+// LSMME demosaicing algorithm
+// L. Zhang and X. Wu,
+// Color demozaicing via directional Linear Minimum Mean Square-error Estimation,
+// IEEE Trans. on Image Processing, vol. 14, pp. 2167-2178,
+// Dec. 2005.
+// Adapted to RawTherapee by Jacques Desmis 3/2013
+// Improved speed and reduced memory consumption by Ingo Weyrich 2/2015
+// TODO Tiles to reduce memory consumption
+void RawImageSource::lmmse_interpolate_omp(int winw, int winh, const array2D &rawData, array2D &red, array2D &green, array2D &blue, int iterations)
+{
+ const int width = winw, height = winh;
+ const int ba = 10;
+ const int rr1 = height + 2 * ba;
+ const int cc1 = width + 2 * ba;
+ const int w1 = cc1;
+ const int w2 = 2 * w1;
+ const int w3 = 3 * w1;
+ const int w4 = 4 * w1;
+ float h0, h1, h2, h3, h4, hs;
+ h0 = 1.0f;
+ h1 = exp( -1.0f / 8.0f);
+ h2 = exp( -4.0f / 8.0f);
+ h3 = exp( -9.0f / 8.0f);
+ h4 = exp(-16.0f / 8.0f);
+ hs = h0 + 2.0f * (h1 + h2 + h3 + h4);
+ h0 /= hs;
+ h1 /= hs;
+ h2 /= hs;
+ h3 /= hs;
+ h4 /= hs;
+ int passref = 0;
+ int iter = 0;
+
+ if (iterations <= 4) {
+ iter = iterations - 1;
+ passref = 0;
+ } else if (iterations <= 6) {
+ iter = 3;
+ passref = iterations - 4;
+ } else if (iterations <= 8) {
+ iter = 3;
+ passref = iterations - 6;
+ }
+
+ bool applyGamma = true;
+
+ if (iterations == 0) {
+ applyGamma = false;
+ iter = 0;
+ } else {
+ applyGamma = true;
+ }
+
+ float *rix[5];
+ float *qix[5];
+ float *buffer = (float *)calloc(static_cast(rr1) * cc1 * 5 * sizeof(float), 1);
+
+ if (buffer == nullptr) { // allocation of big block of memory failed, try to get 5 smaller ones
+ printf("lmmse_interpolate_omp: allocation of big memory block failed, try to get 5 smaller ones now...\n");
+ bool allocationFailed = false;
+
+ for (int i = 0; i < 5; i++) {
+ qix[i] = (float *)calloc(static_cast(rr1) * cc1 * sizeof(float), 1);
+
+ if (!qix[i]) { // allocation of at least one small block failed
+ allocationFailed = true;
+ }
+ }
+
+ if (allocationFailed) { // fall back to igv_interpolate
+ printf("lmmse_interpolate_omp: allocation of 5 small memory blocks failed, falling back to igv_interpolate...\n");
+
+ for (int i = 0; i < 5; i++) { // free the already allocated buffers
+ if (qix[i]) {
+ free(qix[i]);
+ }
+ }
+
+ igv_interpolate(winw, winh);
+ return;
+ }
+ } else {
+ qix[0] = buffer;
+
+ for (int i = 1; i < 5; i++) {
+ qix[i] = qix[i - 1] + rr1 * cc1;
+ }
+ }
+
+ if (plistener) {
+ plistener->setProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), M("TP_RAW_LMMSE")));
+ plistener->setProgress (0.0);
+ }
+
+
+ LUTf *gamtab;
+
+ if (applyGamma) {
+ gamtab = &(Color::gammatab_24_17a);
+ } else {
+ gamtab = new LUTf(65536, LUT_CLIP_BELOW);
+ gamtab->makeIdentity(65535.f);
+ }
+
+
+#ifdef _OPENMP
+ #pragma omp parallel private(rix)
+#endif
+ {
+#ifdef _OPENMP
+ #pragma omp for
+#endif
+
+ for (int rrr = ba; rrr < rr1 - ba; rrr++) {
+ for (int ccc = ba, row = rrr - ba; ccc < cc1 - ba; ccc++) {
+ int col = ccc - ba;
+ float *rix = qix[4] + rrr * cc1 + ccc;
+ rix[0] = (*gamtab)[rawData[row][col]];
+ }
+ }
+
+#ifdef _OPENMP
+ #pragma omp single
+#endif
+ {
+ if (plistener) {
+ plistener->setProgress (0.1);
+ }
+ }
+
+ // G-R(B)
+#ifdef _OPENMP
+ #pragma omp for schedule(dynamic,16)
+#endif
+
+ for (int rr = 2; rr < rr1 - 2; rr++) {
+ // G-R(B) at R(B) location
+ for (int cc = 2 + (FC(rr, 2) & 1); cc < cc1 - 2; cc += 2) {
+ rix[4] = qix[4] + rr * cc1 + cc;
+ float v0 = 0.0625f * (rix[4][-w1 - 1] + rix[4][-w1 + 1] + rix[4][w1 - 1] + rix[4][w1 + 1]) + 0.25f * (rix[4][0]);
+ // horizontal
+ rix[0] = qix[0] + rr * cc1 + cc;
+ rix[0][0] = -0.25f * (rix[4][ -2] + rix[4][ 2]) + xdiv2f(rix[4][ -1] + rix[4][0] + rix[4][ 1]);
+ float Y = v0 + xdiv2f(rix[0][0]);
+
+ if (rix[4][0] > 1.75f * Y) {
+ rix[0][0] = median(rix[0][0], rix[4][ -1], rix[4][ 1]);
+ } else {
+ rix[0][0] = LIM(rix[0][0], 0.0f, 1.0f);
+ }
+
+ rix[0][0] -= rix[4][0];
+ // vertical
+ rix[1] = qix[1] + rr * cc1 + cc;
+ rix[1][0] = -0.25f * (rix[4][-w2] + rix[4][w2]) + xdiv2f(rix[4][-w1] + rix[4][0] + rix[4][w1]);
+ Y = v0 + xdiv2f(rix[1][0]);
+
+ if (rix[4][0] > 1.75f * Y) {
+ rix[1][0] = median(rix[1][0], rix[4][-w1], rix[4][w1]);
+ } else {
+ rix[1][0] = LIM(rix[1][0], 0.0f, 1.0f);
+ }
+
+ rix[1][0] -= rix[4][0];
+ }
+
+ // G-R(B) at G location
+ for (int ccc = 2 + (FC(rr, 3) & 1); ccc < cc1 - 2; ccc += 2) {
+ rix[0] = qix[0] + rr * cc1 + ccc;
+ rix[1] = qix[1] + rr * cc1 + ccc;
+ rix[4] = qix[4] + rr * cc1 + ccc;
+ rix[0][0] = 0.25f * (rix[4][ -2] + rix[4][ 2]) - xdiv2f(rix[4][ -1] + rix[4][0] + rix[4][ 1]);
+ rix[1][0] = 0.25f * (rix[4][-w2] + rix[4][w2]) - xdiv2f(rix[4][-w1] + rix[4][0] + rix[4][w1]);
+ rix[0][0] = LIM(rix[0][0], -1.0f, 0.0f) + rix[4][0];
+ rix[1][0] = LIM(rix[1][0], -1.0f, 0.0f) + rix[4][0];
+ }
+ }
+
+#ifdef _OPENMP
+ #pragma omp single
+#endif
+ {
+ if (plistener) {
+ plistener->setProgress (0.2);
+ }
+ }
+
+
+ // apply low pass filter on differential colors
+#ifdef _OPENMP
+ #pragma omp for
+#endif
+
+ for (int rr = 4; rr < rr1 - 4; rr++)
+ for (int cc = 4; cc < cc1 - 4; cc++) {
+ rix[0] = qix[0] + rr * cc1 + cc;
+ rix[2] = qix[2] + rr * cc1 + cc;
+ rix[2][0] = h0 * rix[0][0] + h1 * (rix[0][ -1] + rix[0][ 1]) + h2 * (rix[0][ -2] + rix[0][ 2]) + h3 * (rix[0][ -3] + rix[0][ 3]) + h4 * (rix[0][ -4] + rix[0][ 4]);
+ rix[1] = qix[1] + rr * cc1 + cc;
+ rix[3] = qix[3] + rr * cc1 + cc;
+ rix[3][0] = h0 * rix[1][0] + h1 * (rix[1][-w1] + rix[1][w1]) + h2 * (rix[1][-w2] + rix[1][w2]) + h3 * (rix[1][-w3] + rix[1][w3]) + h4 * (rix[1][-w4] + rix[1][w4]);
+ }
+
+#ifdef _OPENMP
+ #pragma omp single
+#endif
+ {
+ if (plistener) {
+ plistener->setProgress (0.3);
+ }
+ }
+
+ // interpolate G-R(B) at R(B)
+#ifdef _OPENMP
+ #pragma omp for
+#endif
+
+ for (int rr = 4; rr < rr1 - 4; rr++) {
+ int cc = 4 + (FC(rr, 4) & 1);
+#ifdef __SSE2__
+ vfloat p1v, p2v, p3v, p4v, p5v, p6v, p7v, p8v, p9v, muv, vxv, vnv, xhv, vhv, xvv, vvv;
+ vfloat epsv = F2V(1e-7);
+ vfloat ninev = F2V(9.f);
+
+ for (; cc < cc1 - 10; cc += 8) {
+ rix[0] = qix[0] + rr * cc1 + cc;
+ rix[1] = qix[1] + rr * cc1 + cc;
+ rix[2] = qix[2] + rr * cc1 + cc;
+ rix[3] = qix[3] + rr * cc1 + cc;
+ rix[4] = qix[4] + rr * cc1 + cc;
+ // horizontal
+ p1v = LC2VFU(rix[2][-4]);
+ p2v = LC2VFU(rix[2][-3]);
+ p3v = LC2VFU(rix[2][-2]);
+ p4v = LC2VFU(rix[2][-1]);
+ p5v = LC2VFU(rix[2][ 0]);
+ p6v = LC2VFU(rix[2][ 1]);
+ p7v = LC2VFU(rix[2][ 2]);
+ p8v = LC2VFU(rix[2][ 3]);
+ p9v = LC2VFU(rix[2][ 4]);
+ muv = (p1v + p2v + p3v + p4v + p5v + p6v + p7v + p8v + p9v) / ninev;
+ vxv = epsv + SQRV(p1v - muv) + SQRV(p2v - muv) + SQRV(p3v - muv) + SQRV(p4v - muv) + SQRV(p5v - muv) + SQRV(p6v - muv) + SQRV(p7v - muv) + SQRV(p8v - muv) + SQRV(p9v - muv);
+ p1v -= LC2VFU(rix[0][-4]);
+ p2v -= LC2VFU(rix[0][-3]);
+ p3v -= LC2VFU(rix[0][-2]);
+ p4v -= LC2VFU(rix[0][-1]);
+ p5v -= LC2VFU(rix[0][ 0]);
+ p6v -= LC2VFU(rix[0][ 1]);
+ p7v -= LC2VFU(rix[0][ 2]);
+ p8v -= LC2VFU(rix[0][ 3]);
+ p9v -= LC2VFU(rix[0][ 4]);
+ vnv = epsv + SQRV(p1v) + SQRV(p2v) + SQRV(p3v) + SQRV(p4v) + SQRV(p5v) + SQRV(p6v) + SQRV(p7v) + SQRV(p8v) + SQRV(p9v);
+ xhv = (LC2VFU(rix[0][0]) * vxv + LC2VFU(rix[2][0]) * vnv) / (vxv + vnv);
+ vhv = vxv * vnv / (vxv + vnv);
+
+ // vertical
+ p1v = LC2VFU(rix[3][-w4]);
+ p2v = LC2VFU(rix[3][-w3]);
+ p3v = LC2VFU(rix[3][-w2]);
+ p4v = LC2VFU(rix[3][-w1]);
+ p5v = LC2VFU(rix[3][ 0]);
+ p6v = LC2VFU(rix[3][ w1]);
+ p7v = LC2VFU(rix[3][ w2]);
+ p8v = LC2VFU(rix[3][ w3]);
+ p9v = LC2VFU(rix[3][ w4]);
+ muv = (p1v + p2v + p3v + p4v + p5v + p6v + p7v + p8v + p9v) / ninev;
+ vxv = epsv + SQRV(p1v - muv) + SQRV(p2v - muv) + SQRV(p3v - muv) + SQRV(p4v - muv) + SQRV(p5v - muv) + SQRV(p6v - muv) + SQRV(p7v - muv) + SQRV(p8v - muv) + SQRV(p9v - muv);
+ p1v -= LC2VFU(rix[1][-w4]);
+ p2v -= LC2VFU(rix[1][-w3]);
+ p3v -= LC2VFU(rix[1][-w2]);
+ p4v -= LC2VFU(rix[1][-w1]);
+ p5v -= LC2VFU(rix[1][ 0]);
+ p6v -= LC2VFU(rix[1][ w1]);
+ p7v -= LC2VFU(rix[1][ w2]);
+ p8v -= LC2VFU(rix[1][ w3]);
+ p9v -= LC2VFU(rix[1][ w4]);
+ vnv = epsv + SQRV(p1v) + SQRV(p2v) + SQRV(p3v) + SQRV(p4v) + SQRV(p5v) + SQRV(p6v) + SQRV(p7v) + SQRV(p8v) + SQRV(p9v);
+ xvv = (LC2VFU(rix[1][0]) * vxv + LC2VFU(rix[3][0]) * vnv) / (vxv + vnv);
+ vvv = vxv * vnv / (vxv + vnv);
+ // interpolated G-R(B)
+ muv = (xhv * vvv + xvv * vhv) / (vhv + vvv);
+ STC2VFU(rix[4][0], muv);
+ }
+
+#endif
+
+ for (; cc < cc1 - 4; cc += 2) {
+ rix[0] = qix[0] + rr * cc1 + cc;
+ rix[1] = qix[1] + rr * cc1 + cc;
+ rix[2] = qix[2] + rr * cc1 + cc;
+ rix[3] = qix[3] + rr * cc1 + cc;
+ rix[4] = qix[4] + rr * cc1 + cc;
+ // horizontal
+ float p1 = rix[2][-4];
+ float p2 = rix[2][-3];
+ float p3 = rix[2][-2];
+ float p4 = rix[2][-1];
+ float p5 = rix[2][ 0];
+ float p6 = rix[2][ 1];
+ float p7 = rix[2][ 2];
+ float p8 = rix[2][ 3];
+ float p9 = rix[2][ 4];
+ float mu = (p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) / 9.f;
+ float vx = 1e-7 + SQR(p1 - mu) + SQR(p2 - mu) + SQR(p3 - mu) + SQR(p4 - mu) + SQR(p5 - mu) + SQR(p6 - mu) + SQR(p7 - mu) + SQR(p8 - mu) + SQR(p9 - mu);
+ p1 -= rix[0][-4];
+ p2 -= rix[0][-3];
+ p3 -= rix[0][-2];
+ p4 -= rix[0][-1];
+ p5 -= rix[0][ 0];
+ p6 -= rix[0][ 1];
+ p7 -= rix[0][ 2];
+ p8 -= rix[0][ 3];
+ p9 -= rix[0][ 4];
+ float vn = 1e-7 + SQR(p1) + SQR(p2) + SQR(p3) + SQR(p4) + SQR(p5) + SQR(p6) + SQR(p7) + SQR(p8) + SQR(p9);
+ float xh = (rix[0][0] * vx + rix[2][0] * vn) / (vx + vn);
+ float vh = vx * vn / (vx + vn);
+
+ // vertical
+ p1 = rix[3][-w4];
+ p2 = rix[3][-w3];
+ p3 = rix[3][-w2];
+ p4 = rix[3][-w1];
+ p5 = rix[3][ 0];
+ p6 = rix[3][ w1];
+ p7 = rix[3][ w2];
+ p8 = rix[3][ w3];
+ p9 = rix[3][ w4];
+ mu = (p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) / 9.f;
+ vx = 1e-7 + SQR(p1 - mu) + SQR(p2 - mu) + SQR(p3 - mu) + SQR(p4 - mu) + SQR(p5 - mu) + SQR(p6 - mu) + SQR(p7 - mu) + SQR(p8 - mu) + SQR(p9 - mu);
+ p1 -= rix[1][-w4];
+ p2 -= rix[1][-w3];
+ p3 -= rix[1][-w2];
+ p4 -= rix[1][-w1];
+ p5 -= rix[1][ 0];
+ p6 -= rix[1][ w1];
+ p7 -= rix[1][ w2];
+ p8 -= rix[1][ w3];
+ p9 -= rix[1][ w4];
+ vn = 1e-7 + SQR(p1) + SQR(p2) + SQR(p3) + SQR(p4) + SQR(p5) + SQR(p6) + SQR(p7) + SQR(p8) + SQR(p9);
+ float xv = (rix[1][0] * vx + rix[3][0] * vn) / (vx + vn);
+ float vv = vx * vn / (vx + vn);
+ // interpolated G-R(B)
+ rix[4][0] = (xh * vv + xv * vh) / (vh + vv);
+ }
+ }
+
+#ifdef _OPENMP
+ #pragma omp single
+#endif
+ {
+ if (plistener) {
+ plistener->setProgress (0.4);
+ }
+ }
+
+ // copy CFA values
+#ifdef _OPENMP
+ #pragma omp for
+#endif
+
+ for (int rr = 0; rr < rr1; rr++)
+ for (int cc = 0, row = rr - ba; cc < cc1; cc++) {
+ int col = cc - ba;
+ int c = FC(rr, cc);
+ rix[c] = qix[c] + rr * cc1 + cc;
+
+ if ((row >= 0) & (row < height) & (col >= 0) & (col < width)) {
+ rix[c][0] = (*gamtab)[rawData[row][col]];
+ } else {
+ rix[c][0] = 0.f;
+ }
+
+ if (c != 1) {
+ rix[1] = qix[1] + rr * cc1 + cc;
+ rix[4] = qix[4] + rr * cc1 + cc;
+ rix[1][0] = rix[c][0] + rix[4][0];
+ }
+ }
+
+#ifdef _OPENMP
+ #pragma omp single
+#endif
+ {
+ if (plistener) {
+ plistener->setProgress (0.5);
+ }
+ }
+
+ // bilinear interpolation for R/B
+ // interpolate R/B at G location
+#ifdef _OPENMP
+ #pragma omp for
+#endif
+
+ for (int rr = 1; rr < rr1 - 1; rr++)
+ for (int cc = 1 + (FC(rr, 2) & 1), c = FC(rr, cc + 1); cc < cc1 - 1; cc += 2) {
+ rix[c] = qix[c] + rr * cc1 + cc;
+ rix[1] = qix[1] + rr * cc1 + cc;
+ rix[c][0] = rix[1][0] + xdiv2f(rix[c][ -1] - rix[1][ -1] + rix[c][ 1] - rix[1][ 1]);
+ c = 2 - c;
+ rix[c] = qix[c] + rr * cc1 + cc;
+ rix[c][0] = rix[1][0] + xdiv2f(rix[c][-w1] - rix[1][-w1] + rix[c][w1] - rix[1][w1]);
+ c = 2 - c;
+ }
+
+#ifdef _OPENMP
+ #pragma omp single
+#endif
+ {
+ if (plistener) {
+ plistener->setProgress (0.6);
+ }
+ }
+
+ // interpolate R/B at B/R location
+#ifdef _OPENMP
+ #pragma omp for
+#endif
+
+ for (int rr = 1; rr < rr1 - 1; rr++)
+ for (int cc = 1 + (FC(rr, 1) & 1), c = 2 - FC(rr, cc); cc < cc1 - 1; cc += 2) {
+ rix[c] = qix[c] + rr * cc1 + cc;
+ rix[1] = qix[1] + rr * cc1 + cc;
+ rix[c][0] = rix[1][0] + 0.25f * (rix[c][-w1] - rix[1][-w1] + rix[c][ -1] - rix[1][ -1] + rix[c][ 1] - rix[1][ 1] + rix[c][ w1] - rix[1][ w1]);
+ }
+
+#ifdef _OPENMP
+ #pragma omp single
+#endif
+ {
+ if (plistener) {
+ plistener->setProgress (0.7);
+ }
+ }
+
+ }// End of parallelization 1
+
+ // median filter/
+ for (int pass = 0; pass < iter; pass++) {
+ // Apply 3x3 median filter
+ // Compute median(R-G) and median(B-G)
+
+#ifdef _OPENMP
+ #pragma omp parallel for private(rix)
+#endif
+
+ for (int rr = 1; rr < rr1 - 1; rr++) {
+ for (int c = 0; c < 3; c += 2) {
+ int d = c + 3 - (c == 0 ? 0 : 1);
+ int cc = 1;
+#ifdef __SSE2__
+
+ for (; cc < cc1 - 4; cc += 4) {
+ rix[d] = qix[d] + rr * cc1 + cc;
+ rix[c] = qix[c] + rr * cc1 + cc;
+ rix[1] = qix[1] + rr * cc1 + cc;
+ // Assign 3x3 differential color values
+ const std::array p = {
+ LVFU(rix[c][-w1 - 1]) - LVFU(rix[1][-w1 - 1]),
+ LVFU(rix[c][-w1]) - LVFU(rix[1][-w1]),
+ LVFU(rix[c][-w1 + 1]) - LVFU(rix[1][-w1 + 1]),
+ LVFU(rix[c][ -1]) - LVFU(rix[1][ -1]),
+ LVFU(rix[c][ 0]) - LVFU(rix[1][ 0]),
+ LVFU(rix[c][ 1]) - LVFU(rix[1][ 1]),
+ LVFU(rix[c][ w1 - 1]) - LVFU(rix[1][ w1 - 1]),
+ LVFU(rix[c][ w1]) - LVFU(rix[1][ w1]),
+ LVFU(rix[c][ w1 + 1]) - LVFU(rix[1][ w1 + 1])
+ };
+ _mm_storeu_ps(&rix[d][0], median(p));
+ }
+
+#endif
+
+ for (; cc < cc1 - 1; cc++) {
+ rix[d] = qix[d] + rr * cc1 + cc;
+ rix[c] = qix[c] + rr * cc1 + cc;
+ rix[1] = qix[1] + rr * cc1 + cc;
+ // Assign 3x3 differential color values
+ const std::array p = {
+ rix[c][-w1 - 1] - rix[1][-w1 - 1],
+ rix[c][-w1] - rix[1][-w1],
+ rix[c][-w1 + 1] - rix[1][-w1 + 1],
+ rix[c][ -1] - rix[1][ -1],
+ rix[c][ 0] - rix[1][ 0],
+ rix[c][ 1] - rix[1][ 1],
+ rix[c][ w1 - 1] - rix[1][ w1 - 1],
+ rix[c][ w1] - rix[1][ w1],
+ rix[c][ w1 + 1] - rix[1][ w1 + 1]
+ };
+ rix[d][0] = median(p);
+ }
+ }
+ }
+
+ // red/blue at GREEN pixel locations & red/blue and green at BLUE/RED pixel locations
+#ifdef _OPENMP
+ #pragma omp parallel for private (rix)
+#endif
+
+ for (int rr = 0; rr < rr1; rr++) {
+ rix[0] = qix[0] + rr * cc1;
+ rix[1] = qix[1] + rr * cc1;
+ rix[2] = qix[2] + rr * cc1;
+ rix[3] = qix[3] + rr * cc1;
+ rix[4] = qix[4] + rr * cc1;
+ int c0 = FC(rr, 0);
+ int c1 = FC(rr, 1);
+
+ if (c0 == 1) {
+ c1 = 2 - c1;
+ int d = c1 + 3 - (c1 == 0 ? 0 : 1);
+ int cc;
+
+ for (cc = 0; cc < cc1 - 1; cc += 2) {
+ rix[0][0] = rix[1][0] + rix[3][0];
+ rix[2][0] = rix[1][0] + rix[4][0];
+ rix[0]++;
+ rix[1]++;
+ rix[2]++;
+ rix[3]++;
+ rix[4]++;
+ rix[c1][0] = rix[1][0] + rix[d][0];
+ rix[1][0] = 0.5f * (rix[0][0] - rix[3][0] + rix[2][0] - rix[4][0]);
+ rix[0]++;
+ rix[1]++;
+ rix[2]++;
+ rix[3]++;
+ rix[4]++;
+ }
+
+ if (cc < cc1) { // remaining pixel, only if width is odd
+ rix[0][0] = rix[1][0] + rix[3][0];
+ rix[2][0] = rix[1][0] + rix[4][0];
+ }
+ } else {
+ c0 = 2 - c0;
+ int d = c0 + 3 - (c0 == 0 ? 0 : 1);
+ int cc;
+
+ for (cc = 0; cc < cc1 - 1; cc += 2) {
+ rix[c0][0] = rix[1][0] + rix[d][0];
+ rix[1][0] = 0.5f * (rix[0][0] - rix[3][0] + rix[2][0] - rix[4][0]);
+ rix[0]++;
+ rix[1]++;
+ rix[2]++;
+ rix[3]++;
+ rix[4]++;
+ rix[0][0] = rix[1][0] + rix[3][0];
+ rix[2][0] = rix[1][0] + rix[4][0];
+ rix[0]++;
+ rix[1]++;
+ rix[2]++;
+ rix[3]++;
+ rix[4]++;
+ }
+
+ if (cc < cc1) { // remaining pixel, only if width is odd
+ rix[c0][0] = rix[1][0] + rix[d][0];
+ rix[1][0] = 0.5f * (rix[0][0] - rix[3][0] + rix[2][0] - rix[4][0]);
+ }
+ }
+ }
+ }
+
+ if (plistener) {
+ plistener->setProgress (0.8);
+ }
+
+ if (applyGamma) {
+ gamtab = &(Color::igammatab_24_17);
+ } else {
+ gamtab->makeIdentity();
+ }
+
+ array2D* rgb[3];
+ rgb[0] = &red;
+ rgb[1] = &green;
+ rgb[2] = &blue;
+
+ // copy result back to image matrix
+#ifdef _OPENMP
+ #pragma omp parallel for
+#endif
+
+ for (int row = 0; row < height; row++) {
+ for (int col = 0, rr = row + ba; col < width; col++) {
+ int cc = col + ba;
+ int c = FC(row, col);
+
+ for (int ii = 0; ii < 3; ii++)
+ if (ii != c) {
+ float *rix = qix[ii] + rr * cc1 + cc;
+ (*(rgb[ii]))[row][col] = std::max(0.f, (*gamtab)[65535.f * rix[0]]);
+ } else {
+ (*(rgb[ii]))[row][col] = CLIP(rawData[row][col]);
+ }
+ }
+ }
+
+ if (plistener) {
+ plistener->setProgress (1.0);
+ }
+
+ if (buffer) {
+ free(buffer);
+ } else
+ for (int i = 0; i < 5; i++) {
+ free(qix[i]);
+ }
+
+ if (!applyGamma) {
+ delete gamtab;
+ }
+
+ if (iterations > 4) {
+ refinement(passref);
+ }
+
+}
+
+void RawImageSource::refinement(int PassCount)
+{
+ int width = W;
+ int height = H;
+ int w1 = width;
+ int w2 = 2 * w1;
+
+ if (plistener) {
+ plistener->setProgressStr(M("TP_RAW_DMETHOD_PROGRESSBAR_REFINE"));
+ }
+
+ array2D *rgb[3];
+ rgb[0] = &red;
+ rgb[1] = &green;
+ rgb[2] = &blue;
+
+ for (int b = 0; b < PassCount; b++) {
+ if (plistener) {
+ plistener->setProgress((float)b / PassCount);
+ }
+
+
+#ifdef _OPENMP
+ #pragma omp parallel
+#endif
+ {
+ float *pix[3];
+
+ /* Reinforce interpolated green pixels on RED/BLUE pixel locations */
+#ifdef _OPENMP
+ #pragma omp for
+#endif
+
+ for (int row = 2; row < height - 2; row++) {
+ int col = 2 + (FC(row, 2) & 1);
+ int c = FC(row, col);
+#ifdef __SSE2__
+ vfloat dLv, dRv, dUv, dDv, v0v;
+ vfloat onev = F2V(1.f);
+ vfloat zd5v = F2V(0.5f);
+
+ for (; col < width - 8; col += 8) {
+ int indx = row * width + col;
+ pix[c] = (float*)(*rgb[c]) + indx;
+ pix[1] = (float*)(*rgb[1]) + indx;
+ dLv = onev / (onev + vabsf(LC2VFU(pix[c][ -2]) - LC2VFU(pix[c][0])) + vabsf(LC2VFU(pix[1][ 1]) - LC2VFU(pix[1][ -1])));
+ dRv = onev / (onev + vabsf(LC2VFU(pix[c][ 2]) - LC2VFU(pix[c][0])) + vabsf(LC2VFU(pix[1][ 1]) - LC2VFU(pix[1][ -1])));
+ dUv = onev / (onev + vabsf(LC2VFU(pix[c][-w2]) - LC2VFU(pix[c][0])) + vabsf(LC2VFU(pix[1][w1]) - LC2VFU(pix[1][-w1])));
+ dDv = onev / (onev + vabsf(LC2VFU(pix[c][ w2]) - LC2VFU(pix[c][0])) + vabsf(LC2VFU(pix[1][w1]) - LC2VFU(pix[1][-w1])));
+ v0v = vmaxf(ZEROV, LC2VFU(pix[c][0]) + zd5v + ((LC2VFU(pix[1][-1]) - LC2VFU(pix[c][-1])) * dLv + (LC2VFU(pix[1][1]) - LC2VFU(pix[c][1])) * dRv + (LC2VFU(pix[1][-w1]) - LC2VFU(pix[c][-w1])) * dUv + (LC2VFU(pix[1][w1]) - LC2VFU(pix[c][w1])) * dDv ) / (dLv + dRv + dUv + dDv));
+ STC2VFU(pix[1][0], v0v);
+ }
+
+#endif
+
+ for (; col < width - 2; col += 2) {
+ int indx = row * width + col;
+ pix[c] = (float*)(*rgb[c]) + indx;
+ pix[1] = (float*)(*rgb[1]) + indx;
+ float dL = 1.f / (1.f + fabsf(pix[c][ -2] - pix[c][0]) + fabsf(pix[1][ 1] - pix[1][ -1]));
+ float dR = 1.f / (1.f + fabsf(pix[c][ 2] - pix[c][0]) + fabsf(pix[1][ 1] - pix[1][ -1]));
+ float dU = 1.f / (1.f + fabsf(pix[c][-w2] - pix[c][0]) + fabsf(pix[1][w1] - pix[1][-w1]));
+ float dD = 1.f / (1.f + fabsf(pix[c][ w2] - pix[c][0]) + fabsf(pix[1][w1] - pix[1][-w1]));
+ float v0 = (pix[c][0] + 0.5f + ((pix[1][ -1] - pix[c][ -1]) * dL + (pix[1][ 1] - pix[c][ 1]) * dR + (pix[1][-w1] - pix[c][-w1]) * dU + (pix[1][ w1] - pix[c][ w1]) * dD ) / (dL + dR + dU + dD));
+ pix[1][0] = std::max(0.f, v0);
+ }
+ }
+
+ /* Reinforce interpolated red/blue pixels on GREEN pixel locations */
+#ifdef _OPENMP
+ #pragma omp for
+#endif
+
+ for (int row = 2; row < height - 2; row++) {
+ int col = 2 + (FC(row, 3) & 1);
+ int c = FC(row, col + 1);
+#ifdef __SSE2__
+ vfloat dLv, dRv, dUv, dDv, v0v;
+ vfloat onev = F2V(1.f);
+ vfloat zd5v = F2V(0.5f);
+
+ for (; col < width - 8; col += 8) {
+ int indx = row * width + col;
+ pix[1] = (float*)(*rgb[1]) + indx;
+
+ for (int i = 0; i < 2; c = 2 - c, i++) {
+ pix[c] = (float*)(*rgb[c]) + indx;
+ dLv = onev / (onev + vabsf(LC2VFU(pix[1][ -2]) - LC2VFU(pix[1][0])) + vabsf(LC2VFU(pix[c][ 1]) - LC2VFU(pix[c][ -1])));
+ dRv = onev / (onev + vabsf(LC2VFU(pix[1][ 2]) - LC2VFU(pix[1][0])) + vabsf(LC2VFU(pix[c][ 1]) - LC2VFU(pix[c][ -1])));
+ dUv = onev / (onev + vabsf(LC2VFU(pix[1][-w2]) - LC2VFU(pix[1][0])) + vabsf(LC2VFU(pix[c][w1]) - LC2VFU(pix[c][-w1])));
+ dDv = onev / (onev + vabsf(LC2VFU(pix[1][ w2]) - LC2VFU(pix[1][0])) + vabsf(LC2VFU(pix[c][w1]) - LC2VFU(pix[c][-w1])));
+ v0v = vmaxf(ZEROV, LC2VFU(pix[1][0]) + zd5v - ((LC2VFU(pix[1][-1]) - LC2VFU(pix[c][-1])) * dLv + (LC2VFU(pix[1][1]) - LC2VFU(pix[c][1])) * dRv + (LC2VFU(pix[1][-w1]) - LC2VFU(pix[c][-w1])) * dUv + (LC2VFU(pix[1][w1]) - LC2VFU(pix[c][w1])) * dDv ) / (dLv + dRv + dUv + dDv));
+ STC2VFU(pix[c][0], v0v);
+ }
+ }
+
+#endif
+
+ for (; col < width - 2; col += 2) {
+ int indx = row * width + col;
+ pix[1] = (float*)(*rgb[1]) + indx;
+
+ for (int i = 0; i < 2; c = 2 - c, i++) {
+ pix[c] = (float*)(*rgb[c]) + indx;
+ float dL = 1.f / (1.f + fabsf(pix[1][ -2] - pix[1][0]) + fabsf(pix[c][ 1] - pix[c][ -1]));
+ float dR = 1.f / (1.f + fabsf(pix[1][ 2] - pix[1][0]) + fabsf(pix[c][ 1] - pix[c][ -1]));
+ float dU = 1.f / (1.f + fabsf(pix[1][-w2] - pix[1][0]) + fabsf(pix[c][w1] - pix[c][-w1]));
+ float dD = 1.f / (1.f + fabsf(pix[1][ w2] - pix[1][0]) + fabsf(pix[c][w1] - pix[c][-w1]));
+ float v0 = (pix[1][0] + 0.5f - ((pix[1][ -1] - pix[c][ -1]) * dL + (pix[1][ 1] - pix[c][ 1]) * dR + (pix[1][-w1] - pix[c][-w1]) * dU + (pix[1][ w1] - pix[c][ w1]) * dD ) / (dL + dR + dU + dD));
+ pix[c][0] = std::max(0.f, v0);
+ }
+ }
+ }
+
+ /* Reinforce integrated red/blue pixels on BLUE/RED pixel locations */
+#ifdef _OPENMP
+ #pragma omp for
+#endif
+
+ for (int row = 2; row < height - 2; row++) {
+ int col = 2 + (FC(row, 2) & 1);
+ int c = 2 - FC(row, col);
+#ifdef __SSE2__
+ vfloat dLv, dRv, dUv, dDv, v0v;
+ vfloat onev = F2V(1.f);
+ vfloat zd5v = F2V(0.5f);
+
+ for (; col < width - 8; col += 8) {
+ int indx = row * width + col;
+ pix[0] = (float*)(*rgb[0]) + indx;
+ pix[1] = (float*)(*rgb[1]) + indx;
+ pix[2] = (float*)(*rgb[2]) + indx;
+ int d = 2 - c;
+ dLv = onev / (onev + vabsf(LC2VFU(pix[d][ -2]) - LC2VFU(pix[d][0])) + vabsf(LC2VFU(pix[1][ 1]) - LC2VFU(pix[1][ -1])));
+ dRv = onev / (onev + vabsf(LC2VFU(pix[d][ 2]) - LC2VFU(pix[d][0])) + vabsf(LC2VFU(pix[1][ 1]) - LC2VFU(pix[1][ -1])));
+ dUv = onev / (onev + vabsf(LC2VFU(pix[d][-w2]) - LC2VFU(pix[d][0])) + vabsf(LC2VFU(pix[1][w1]) - LC2VFU(pix[1][-w1])));
+ dDv = onev / (onev + vabsf(LC2VFU(pix[d][ w2]) - LC2VFU(pix[d][0])) + vabsf(LC2VFU(pix[1][w1]) - LC2VFU(pix[1][-w1])));
+ v0v = vmaxf(ZEROV, LC2VFU(pix[1][0]) + zd5v - ((LC2VFU(pix[1][-1]) - LC2VFU(pix[c][-1])) * dLv + (LC2VFU(pix[1][1]) - LC2VFU(pix[c][1])) * dRv + (LC2VFU(pix[1][-w1]) - LC2VFU(pix[c][-w1])) * dUv + (LC2VFU(pix[1][w1]) - LC2VFU(pix[c][w1])) * dDv ) / (dLv + dRv + dUv + dDv));
+ STC2VFU(pix[c][0], v0v);
+ }
+
+#endif
+
+ for (; col < width - 2; col += 2) {
+ int indx = row * width + col;
+ pix[0] = (float*)(*rgb[0]) + indx;
+ pix[1] = (float*)(*rgb[1]) + indx;
+ pix[2] = (float*)(*rgb[2]) + indx;
+ int d = 2 - c;
+ float dL = 1.f / (1.f + fabsf(pix[d][ -2] - pix[d][0]) + fabsf(pix[1][ 1] - pix[1][ -1]));
+ float dR = 1.f / (1.f + fabsf(pix[d][ 2] - pix[d][0]) + fabsf(pix[1][ 1] - pix[1][ -1]));
+ float dU = 1.f / (1.f + fabsf(pix[d][-w2] - pix[d][0]) + fabsf(pix[1][w1] - pix[1][-w1]));
+ float dD = 1.f / (1.f + fabsf(pix[d][ w2] - pix[d][0]) + fabsf(pix[1][w1] - pix[1][-w1]));
+ float v0 = (pix[1][0] + 0.5f - ((pix[1][ -1] - pix[c][ -1]) * dL + (pix[1][ 1] - pix[c][ 1]) * dR + (pix[1][-w1] - pix[c][-w1]) * dU + (pix[1][ w1] - pix[c][ w1]) * dD ) / (dL + dR + dU + dD));
+ pix[c][0] = std::max(0.f, v0);
+ }
+ }
+ } // end parallel
+ }
+}
+#ifdef __SSE2__
+#undef CLIPV
+#endif
+
+} /* namespace */
diff --git a/rtengine/myfile.h b/rtengine/myfile.h
index 7c498e556..423edea9a 100644
--- a/rtengine/myfile.h
+++ b/rtengine/myfile.h
@@ -56,28 +56,26 @@ IMFILE* fopen (const char* fname);
IMFILE* gfopen (const char* fname);
IMFILE* fopen (unsigned* buf, int size);
void fclose (IMFILE* f);
-inline int ftell (IMFILE* f)
+inline long ftell (IMFILE* f)
{
-
return f->pos;
}
inline int feof (IMFILE* f)
{
-
return f->eof;
}
-inline void fseek (IMFILE* f, int p, int how)
+inline void fseek (IMFILE* f, long p, int how)
{
- int fpos = f->pos;
+ ssize_t fpos = f->pos;
if (how == SEEK_SET) {
f->pos = p;
} else if (how == SEEK_CUR) {
f->pos += p;
} else if (how == SEEK_END) {
- if(p <= 0 && -p <= f->size) {
+ if (p <= 0 && -p <= f->size) {
f->pos = f->size + p;
}
return;
diff --git a/rtengine/rawflatfield.cc b/rtengine/rawflatfield.cc
index 05b3be408..cbc5e6bd6 100644
--- a/rtengine/rawflatfield.cc
+++ b/rtengine/rawflatfield.cc
@@ -263,10 +263,9 @@ void cfaboxblur(const float* const * riFlatFile, float* cfablur, int boxH, int b
namespace rtengine
{
-void RawImageSource::processFlatField(const procparams::RAWParams &raw, const RawImage *riFlatFile, const unsigned short black[4])
+void RawImageSource::processFlatField(const procparams::RAWParams &raw, const RawImage *riFlatFile, const float black[4])
{
// BENCHFUN
- const float fblack[4] = {static_cast(black[0]), static_cast(black[1]), static_cast(black[2]), static_cast(black[3])};
std::unique_ptr cfablur(new float[H * W]);
const int BS = raw.ff_BlurRadius + (raw.ff_BlurRadius & 1);
@@ -292,7 +291,7 @@ void RawImageSource::processFlatField(const procparams::RAWParams &raw, const Ra
const int col = 2 * (W >> 2) + n;
const int c = ri->get_colors() != 1 ? FC(row, col) : 0;
const int c4 = ri->get_colors() != 1 ? ((c == 1 && !(row & 1)) ? 3 : c) : 0;
- refcolor[m][n] = std::max(0.0f, cfablur[row * W + col] - fblack[c4]);
+ refcolor[m][n] = std::max(0.0f, cfablur[row * W + col] - black[c4]);
}
float limitFactor = 1.f;
@@ -315,16 +314,16 @@ void RawImageSource::processFlatField(const procparams::RAWParams &raw, const Ra
clippedBefore = true;
break;
}
- const float tempval = (rawVal - fblack[c4]) * (refcolor[m][n] / std::max(1e-5f, cfablur[(row + m) * W + col + n] - fblack[c4]));
+ const float tempval = (rawVal - black[c4]) * (refcolor[m][n] / std::max(1e-5f, cfablur[(row + m) * W + col + n] - black[c4]));
maxval = std::max(maxval, tempval);
}
}
// now we have the max value for the channel
// if it clips, calculate factor to avoid clipping
- if (maxval + fblack[c4] >= ri->get_white(c4)) {
+ if (maxval + black[c4] >= ri->get_white(c4)) {
if (!clippedBefore) {
- limitFactor = std::min(limitFactor, ri->get_white(c4) / (maxval + fblack[c4]));
+ limitFactor = std::min(limitFactor, ri->get_white(c4) / (maxval + black[c4]));
} else {
limitFactor = 1.f;
}
@@ -361,8 +360,8 @@ void RawImageSource::processFlatField(const procparams::RAWParams &raw, const Ra
const vfloat refcolorv[2] = {_mm_set_ps(refcolor[0][1], refcolor[0][0], refcolor[0][1], refcolor[0][0]),
_mm_set_ps(refcolor[1][1], refcolor[1][0], refcolor[1][1], refcolor[1][0])
};
- const vfloat blackv[2] = {_mm_set_ps(fblack[c4[0][1]], fblack[c4[0][0]], fblack[c4[0][1]], fblack[c4[0][0]]),
- _mm_set_ps(fblack[c4[1][1]], fblack[c4[1][0]], fblack[c4[1][1]], fblack[c4[1][0]])
+ const vfloat blackv[2] = {_mm_set_ps(black[c4[0][1]], black[c4[0][0]], black[c4[0][1]], black[c4[0][0]]),
+ _mm_set_ps(black[c4[1][1]], black[c4[1][0]], black[c4[1][1]], black[c4[1][0]])
};
const vfloat onev = F2V(1.f);
@@ -389,9 +388,9 @@ void RawImageSource::processFlatField(const procparams::RAWParams &raw, const Ra
#endif
for (; col < W; ++col) {
- const float blur = cfablur[row * W + col] - fblack[c4[row & 1][col & 1]];
+ const float blur = cfablur[row * W + col] - black[c4[row & 1][col & 1]];
const float vignettecorr = blur <= minValue ? 1.f : refcolor[row & 1][col & 1] / blur;
- rawData[row][col] = (rawData[row][col] - fblack[c4[row & 1][col & 1]]) * vignettecorr + fblack[c4[row & 1][col & 1]];
+ rawData[row][col] = (rawData[row][col] - black[c4[row & 1][col & 1]]) * vignettecorr + black[c4[row & 1][col & 1]];
}
}
} else if (ri->getSensorType() == ST_FUJI_XTRANS) {
@@ -404,7 +403,7 @@ void RawImageSource::processFlatField(const procparams::RAWParams &raw, const Ra
const int row = 2 * (H >> 2) + m;
const int col = 2 * (W >> 2) + n;
const int c = riFlatFile->XTRANSFC(row, col);
- refcolor[c] += std::max(0.0f, cfablur[row * W + col] - fblack[c]);
+ refcolor[c] += std::max(0.0f, cfablur[row * W + col] - black[c]);
cCount[c] ++;
}
@@ -430,14 +429,14 @@ void RawImageSource::processFlatField(const procparams::RAWParams &raw, const Ra
clippedBefore = true;
break;
}
- const float tempval = (rawVal - fblack[0]) * (refcolor[ri->XTRANSFC(row, col)] / std::max(1e-5f, cfablur[(row) * W + col] - fblack[0]));
+ const float tempval = (rawVal - black[0]) * (refcolor[ri->XTRANSFC(row, col)] / std::max(1e-5f, cfablur[(row) * W + col] - black[0]));
maxval = std::max(maxval, tempval);
}
}
// there's only one white level for xtrans
- if (!clippedBefore && maxval + fblack[0] > ri->get_white(0)) {
- limitFactor = ri->get_white(0) / (maxval + fblack[0]);
+ if (!clippedBefore && maxval + black[0] > ri->get_white(0)) {
+ limitFactor = ri->get_white(0) / (maxval + black[0]);
flatFieldAutoClipValue = (1.f - limitFactor) * 100.f; // this value can be used to set the clip control slider in gui
}
} else {
@@ -458,9 +457,9 @@ void RawImageSource::processFlatField(const procparams::RAWParams &raw, const Ra
for (int row = 0; row < H; ++row) {
for (int col = 0; col < W; ++col) {
const int c = ri->XTRANSFC(row, col);
- const float blur = cfablur[(row) * W + col] - fblack[c];
+ const float blur = cfablur[(row) * W + col] - black[c];
const float vignettecorr = blur <= minValue ? 1.f : refcolor[c] / blur;
- rawData[row][col] = (rawData[row][col] - fblack[c]) * vignettecorr + fblack[c];
+ rawData[row][col] = (rawData[row][col] - black[c]) * vignettecorr + black[c];
}
}
}
@@ -488,8 +487,8 @@ void RawImageSource::processFlatField(const procparams::RAWParams &raw, const Ra
}
#ifdef __SSE2__
- const vfloat blackv[2] = {_mm_set_ps(fblack[c4[0][1]], fblack[c4[0][0]], fblack[c4[0][1]], fblack[c4[0][0]]),
- _mm_set_ps(fblack[c4[1][1]], fblack[c4[1][0]], fblack[c4[1][1]], fblack[c4[1][0]])
+ const vfloat blackv[2] = {_mm_set_ps(black[c4[0][1]], black[c4[0][0]], black[c4[0][1]], black[c4[0][0]]),
+ _mm_set_ps(black[c4[1][1]], black[c4[1][0]], black[c4[1][1]], black[c4[1][0]])
};
const vfloat epsv = F2V(1e-5f);
@@ -513,9 +512,9 @@ void RawImageSource::processFlatField(const procparams::RAWParams &raw, const Ra
#endif
for (; col < W; ++col) {
- const float linecorr = SQR(std::max(1e-5f, cfablur[row * W + col] - fblack[c4[row & 1][col & 1]])) /
- (std::max(1e-5f, cfablur1[row * W + col] - fblack[c4[row & 1][col & 1]]) * std::max(1e-5f, cfablur2[row * W + col] - fblack[c4[row & 1][col & 1]]));
- rawData[row][col] = (rawData[row][col] - fblack[c4[row & 1][col & 1]]) * linecorr + fblack[c4[row & 1][col & 1]];
+ const float linecorr = SQR(std::max(1e-5f, cfablur[row * W + col] - black[c4[row & 1][col & 1]])) /
+ (std::max(1e-5f, cfablur1[row * W + col] - black[c4[row & 1][col & 1]]) * std::max(1e-5f, cfablur2[row * W + col] - black[c4[row & 1][col & 1]]));
+ rawData[row][col] = (rawData[row][col] - black[c4[row & 1][col & 1]]) * linecorr + black[c4[row & 1][col & 1]];
}
}
} else if (ri->getSensorType() == ST_FUJI_XTRANS) {
@@ -526,9 +525,9 @@ void RawImageSource::processFlatField(const procparams::RAWParams &raw, const Ra
for (int row = 0; row < H; ++row) {
for (int col = 0; col < W; ++col) {
const int c = ri->XTRANSFC(row, col);
- const float hlinecorr = std::max(1e-5f, cfablur[(row) * W + col] - fblack[c]) / std::max(1e-5f, cfablur1[(row) * W + col] - fblack[c]);
- const float vlinecorr = std::max(1e-5f, cfablur[(row) * W + col] - fblack[c]) / std::max(1e-5f, cfablur2[(row) * W + col] - fblack[c]);
- rawData[row][col] = (rawData[row][col] - fblack[c]) * hlinecorr * vlinecorr + fblack[c];
+ const float hlinecorr = std::max(1e-5f, cfablur[(row) * W + col] - black[c]) / std::max(1e-5f, cfablur1[(row) * W + col] - black[c]);
+ const float vlinecorr = std::max(1e-5f, cfablur[(row) * W + col] - black[c]) / std::max(1e-5f, cfablur2[(row) * W + col] - black[c]);
+ rawData[row][col] = (rawData[row][col] - black[c]) * hlinecorr * vlinecorr + black[c];
}
}
}
diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc
index db640c64b..d5322f8bd 100644
--- a/rtengine/rawimagesource.cc
+++ b/rtengine/rawimagesource.cc
@@ -42,7 +42,7 @@
#include "../rtgui/options.h"
//#define BENCHMARK
-//#include "StopWatch.h"
+#include "StopWatch.h"
#ifdef _OPENMP
#include
@@ -2413,11 +2413,10 @@ void RawImageSource::HLRecovery_Global(const ToneCurveParams &hrp)
*/
void RawImageSource::copyOriginalPixels(const RAWParams &raw, RawImage *src, RawImage *riDark, RawImage *riFlatFile, array2D &rawData )
{
- // TODO: Change type of black[] to float to avoid conversions
- unsigned short black[4] = {
- (unsigned short)ri->get_cblack(0), (unsigned short)ri->get_cblack(1),
- (unsigned short)ri->get_cblack(2), (unsigned short)ri->get_cblack(3)
- };
+ const float black[4] = {
+ static_cast(ri->get_cblack(0)), static_cast(ri->get_cblack(1)),
+ static_cast(ri->get_cblack(2)), static_cast(ri->get_cblack(3))
+ };
if (ri->getSensorType() == ST_BAYER || ri->getSensorType() == ST_FUJI_XTRANS) {
if (!rawData) {
@@ -2425,11 +2424,22 @@ void RawImageSource::copyOriginalPixels(const RAWParams &raw, RawImage *src, Raw
}
if (riDark && W == riDark->get_width() && H == riDark->get_height()) { // This works also for xtrans-sensors, because black[0] to black[4] are equal for these
+ StopWatch Stop1("darkframe subtraction");
+#ifdef _OPENMP
+ #pragma omp parallel for
+#endif
for (int row = 0; row < H; row++) {
- for (int col = 0; col < W; col++) {
- int c = FC(row, col);
- int c4 = ( c == 1 && !(row & 1) ) ? 3 : c;
- rawData[row][col] = max(src->data[row][col] + black[c4] - riDark->data[row][col], 0.0f);
+ const int c0 = FC(row, 0);
+ const float black0 = black[(c0 == 1 && !(row & 1) ) ? 3 : c0];
+ const int c1 = FC(row, 1);
+ const float black1 = black[(c1 == 1 && !(row & 1) ) ? 3 : c1];
+ int col;
+ for (col = 0; col < W - 1; col += 2) {
+ rawData[row][col] = max(src->data[row][col] + black0 - riDark->data[row][col], 0.0f);
+ rawData[row][col + 1] = max(src->data[row][col + 1] + black1 - riDark->data[row][col + 1], 0.0f);
+ }
+ if (col < W) {
+ rawData[row][col] = max(src->data[row][col] + black0 - riDark->data[row][col], 0.0f);
}
}
} else {
@@ -2559,12 +2569,10 @@ void RawImageSource::scaleColors(int winx, int winy, int winw, int winh, const R
for (int row = winy; row < winy + winh; row ++)
{
for (int col = winx; col < winx + winw; col++) {
- float val = rawData[row][col];
- int c = FC(row, col); // three colors, 0=R, 1=G, 2=B
- int c4 = ( c == 1 && !(row & 1) ) ? 3 : c; // four colors, 0=R, 1=G1, 2=B, 3=G2
- val -= cblacksom[c4];
- val *= scale_mul[c4];
- rawData[row][col] = (val);
+ const int c = FC(row, col); // three colors, 0=R, 1=G, 2=B
+ const int c4 = ( c == 1 && !(row & 1) ) ? 3 : c; // four colors, 0=R, 1=G1, 2=B, 3=G2
+ const float val = max(0.f, rawData[row][col] - cblacksom[c4]) * scale_mul[c4];
+ rawData[row][col] = val;
tmpchmax[c] = max(tmpchmax[c], val);
}
}
@@ -2591,10 +2599,8 @@ void RawImageSource::scaleColors(int winx, int winy, int winw, int winh, const R
for (int row = winy; row < winy + winh; row ++)
{
for (int col = winx; col < winx + winw; col++) {
- float val = rawData[row][col];
- val -= cblacksom[0];
- val *= scale_mul[0];
- rawData[row][col] = (val);
+ const float val = max(0.f, rawData[row][col] - cblacksom[0]) * scale_mul[0];
+ rawData[row][col] = val;
tmpchmax = max(tmpchmax, val);
}
}
@@ -2620,12 +2626,9 @@ void RawImageSource::scaleColors(int winx, int winy, int winw, int winh, const R
for (int row = winy; row < winy + winh; row ++)
{
for (int col = winx; col < winx + winw; col++) {
- float val = rawData[row][col];
- int c = ri->XTRANSFC(row, col);
- val -= cblacksom[c];
- val *= scale_mul[c];
-
- rawData[row][col] = (val);
+ const int c = ri->XTRANSFC(row, col);
+ const float val = max(0.f, rawData[row][col] - cblacksom[c]) * scale_mul[c];
+ rawData[row][col] = val;
tmpchmax[c] = max(tmpchmax[c], val);
}
}
@@ -2654,10 +2657,8 @@ void RawImageSource::scaleColors(int winx, int winy, int winw, int winh, const R
{
for (int col = winx; col < winx + winw; col++) {
for (int c = 0; c < 3; c++) { // three colors, 0=R, 1=G, 2=B
- float val = rawData[row][3 * col + c];
- val -= cblacksom[c];
- val *= scale_mul[c];
- rawData[row][3 * col + c] = (val);
+ const float val = max(0.f, rawData[row][3 * col + c] - cblacksom[c]) * scale_mul[c];
+ rawData[row][3 * col + c] = val;
tmpchmax[c] = max(tmpchmax[c], val);
}
}
diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h
index 34d27a325..636609d6c 100644
--- a/rtengine/rawimagesource.h
+++ b/rtengine/rawimagesource.h
@@ -133,7 +133,6 @@ public:
void flushRawData () override;
void flushRGB () override;
void HLRecovery_Global (const procparams::ToneCurveParams &hrp) override;
- void refinement_lassus (int PassCount);
void refinement(int PassCount);
void setBorder(unsigned int rawBorder) override {border = rawBorder;}
bool isRGBSourceModified() const override
@@ -141,7 +140,7 @@ public:
return rgbSourceModified; // tracks whether cached rgb output of demosaic has been modified
}
- void processFlatField(const procparams::RAWParams &raw, const RawImage *riFlatFile, const unsigned short black[4]);
+ void processFlatField(const procparams::RAWParams &raw, const RawImage *riFlatFile, const float black[4]);
void copyOriginalPixels(const procparams::RAWParams &raw, RawImage *ri, RawImage *riDark, RawImage *riFlatFile, array2D &rawData );
void scaleColors (int winx, int winy, int winw, int winh, const procparams::RAWParams &raw, array2D &rawData); // raw for cblack
void WBauto(double &tempref, double &greenref, array2D &redloc, array2D &greenloc, array2D &blueloc, int bfw, int bfh, double &avg_rm, double &avg_gm, double &avg_bm, double &tempitc, double &greenitc, float &studgood, bool &twotimes, const procparams::WBParams & wbpar, int begx, int begy, int yEn, int xEn, int cx, int cy, const procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw);
@@ -274,7 +273,7 @@ protected:
void hphd_demosaic();
void vng4_demosaic(const array2D &rawData, array2D &red, array2D &green, array2D &blue);
void igv_interpolate(int winw, int winh);
- void lmmse_interpolate_omp(int winw, int winh, array2D &rawData, array2D &red, array2D &green, array2D &blue, int iterations);
+ void lmmse_interpolate_omp(int winw, int winh, const array2D &rawData, array2D &red, array2D &green, array2D &blue, int iterations);
void amaze_demosaic_RT(int winx, int winy, int winw, int winh, const array2D &rawData, array2D &red, array2D &green, array2D &blue, size_t chunkSize = 1, bool measure = false);//Emil's code for AMaZE
void dual_demosaic_RT(bool isBayer, const procparams::RAWParams &raw, int winw, int winh, const array2D &rawData, array2D &red, array2D &green, array2D &blue, double &contrast, bool autoContrast = false);
void fast_demosaic();//Emil's code for fast demosaicing
diff --git a/rtengine/rawimagesource_i.h b/rtengine/rawimagesource_i.h
index 47c6b5bab..9dfc87985 100644
--- a/rtengine/rawimagesource_i.h
+++ b/rtengine/rawimagesource_i.h
@@ -90,7 +90,7 @@ inline void RawImageSource::interpolate_row_rb_mul_pp (const array2D &raw
}
b = g_mul * cg[j] + b / std::max(1, n);
- ab[jx] = b;
+ ab[jx] = std::max(0.f, b);
} else {
// linear R-G interp. horizontally
float r;
@@ -103,7 +103,7 @@ inline void RawImageSource::interpolate_row_rb_mul_pp (const array2D &raw
r = g_mul * cg[j] + (r_mul * rawData[i][j - 1] - g_mul * cg[j - 1] + r_mul * rawData[i][j + 1] - g_mul * cg[j + 1]) / 2;
}
- ar[jx] = r;
+ ar[jx] = std::max(0.f, r);
// linear B-G interp. vertically
float b;
@@ -115,7 +115,7 @@ inline void RawImageSource::interpolate_row_rb_mul_pp (const array2D &raw
b = g_mul * cg[j] + (b_mul * rawData[i - 1][j] - g_mul * pg[j] + b_mul * rawData[i + 1][j] - g_mul * ng[j]) / 2;
}
- ab[jx] = b;
+ ab[jx] = std::max(0.f, b);
}
}
} else if(pg && ng) {
@@ -150,7 +150,7 @@ inline void RawImageSource::interpolate_row_rb_mul_pp (const array2D &raw
r = g_mul * cg[j] + r / std::max(n, 1);
- ar[jx] = r;
+ ar[jx] = std::max(0.f, r);
} else {
// linear B-G interp. horizontally
float b;
@@ -163,7 +163,7 @@ inline void RawImageSource::interpolate_row_rb_mul_pp (const array2D &raw
b = g_mul * cg[j] + (b_mul * rawData[i][j - 1] - g_mul * cg[j - 1] + b_mul * rawData[i][j + 1] - g_mul * cg[j + 1]) / 2;
}
- ab[jx] = b;
+ ab[jx] = std::max(0.f, b);
// linear R-G interp. vertically
float r;
@@ -175,7 +175,7 @@ inline void RawImageSource::interpolate_row_rb_mul_pp (const array2D &raw
r = g_mul * cg[j] + (r_mul * rawData[i - 1][j] - g_mul * pg[j] + r_mul * rawData[i + 1][j] - g_mul * ng[j]) / 2;
}
- ar[jx] = r;
+ ar[jx] = std::max(0.f, r);
}
}
}
diff --git a/rtengine/rcd_demosaic.cc b/rtengine/rcd_demosaic.cc
index 4ceb92b26..5a86aec40 100644
--- a/rtengine/rcd_demosaic.cc
+++ b/rtengine/rcd_demosaic.cc
@@ -275,9 +275,9 @@ void RawImageSource::rcd_demosaic(size_t chunkSize, bool measure)
for (int row = rowStart + rcdBorder; row < rowEnd - rcdBorder; ++row) {
for (int col = colStart + rcdBorder; col < colEnd - rcdBorder; ++col) {
int idx = (row - rowStart) * tileSize + col - colStart ;
- red[row][col] = CLIP(rgb[0][idx] * 65535.f);
- green[row][col] = CLIP(rgb[1][idx] * 65535.f);
- blue[row][col] = CLIP(rgb[2][idx] * 65535.f);
+ red[row][col] = std::max(0.f, rgb[0][idx] * 65535.f);
+ green[row][col] = std::max(0.f, rgb[1][idx] * 65535.f);
+ blue[row][col] = std::max(0.f, rgb[2][idx] * 65535.f);
}
}
diff --git a/rtengine/rt_algo.cc b/rtengine/rt_algo.cc
index b02e75461..a5b48af95 100644
--- a/rtengine/rt_algo.cc
+++ b/rtengine/rt_algo.cc
@@ -299,7 +299,7 @@ void findMinMaxPercentile(const float* data, size_t size, float minPrct, float&
maxOut = rtengine::LIM(maxOut, minVal, maxVal);
}
-void buildBlendMask(const float* const * luminance, float **blend, int W, int H, float &contrastThreshold, float amount, bool autoContrast, float ** clipMask) {
+void buildBlendMask(const float* const * luminance, float **blend, int W, int H, float &contrastThreshold, bool autoContrast, float ** clipMask) {
if (autoContrast) {
constexpr float minLuminance = 2000.f;
@@ -403,7 +403,7 @@ void buildBlendMask(const float* const * luminance, float **blend, int W, int H,
if(contrastThreshold == 0.f) {
for(int j = 0; j < H; ++j) {
for(int i = 0; i < W; ++i) {
- blend[j][i] = amount;
+ blend[j][i] = 1.f;
}
}
} else {
@@ -415,7 +415,6 @@ void buildBlendMask(const float* const * luminance, float **blend, int W, int H,
#ifdef __SSE2__
const vfloat contrastThresholdv = F2V(contrastThreshold);
const vfloat scalev = F2V(scale);
- const vfloat amountv = F2V(amount);
#endif
#ifdef _OPENMP
#pragma omp for schedule(dynamic,16)
@@ -429,14 +428,14 @@ void buildBlendMask(const float* const * luminance, float **blend, int W, int H,
vfloat contrastv = vsqrtf(SQRV(LVFU(luminance[j][i+1]) - LVFU(luminance[j][i-1])) + SQRV(LVFU(luminance[j+1][i]) - LVFU(luminance[j-1][i])) +
SQRV(LVFU(luminance[j][i+2]) - LVFU(luminance[j][i-2])) + SQRV(LVFU(luminance[j+2][i]) - LVFU(luminance[j-2][i]))) * scalev;
- STVFU(blend[j][i], LVFU(clipMask[j][i]) * amountv * calcBlendFactor(contrastv, contrastThresholdv));
+ STVFU(blend[j][i], LVFU(clipMask[j][i]) * calcBlendFactor(contrastv, contrastThresholdv));
}
} else {
for(; i < W - 5; i += 4) {
vfloat contrastv = vsqrtf(SQRV(LVFU(luminance[j][i+1]) - LVFU(luminance[j][i-1])) + SQRV(LVFU(luminance[j+1][i]) - LVFU(luminance[j-1][i])) +
SQRV(LVFU(luminance[j][i+2]) - LVFU(luminance[j][i-2])) + SQRV(LVFU(luminance[j+2][i]) - LVFU(luminance[j-2][i]))) * scalev;
- STVFU(blend[j][i], amountv * calcBlendFactor(contrastv, contrastThresholdv));
+ STVFU(blend[j][i], calcBlendFactor(contrastv, contrastThresholdv));
}
}
#endif
@@ -445,7 +444,7 @@ void buildBlendMask(const float* const * luminance, float **blend, int W, int H,
float contrast = sqrtf(rtengine::SQR(luminance[j][i+1] - luminance[j][i-1]) + rtengine::SQR(luminance[j+1][i] - luminance[j-1][i]) +
rtengine::SQR(luminance[j][i+2] - luminance[j][i-2]) + rtengine::SQR(luminance[j+2][i] - luminance[j-2][i])) * scale;
- blend[j][i] = (clipMask ? clipMask[j][i] : 1.f) * amount * calcBlendFactor(contrast, contrastThreshold);
+ blend[j][i] = (clipMask ? clipMask[j][i] : 1.f) * calcBlendFactor(contrast, contrastThreshold);
}
}
@@ -473,8 +472,18 @@ void buildBlendMask(const float* const * luminance, float **blend, int W, int H,
}
}
+#ifdef __SSE2__
+ // flush denormals to zero for gaussian blur to avoid performance penalty if there are a lot of zero values in the mask
+ const auto oldMode = _MM_GET_FLUSH_ZERO_MODE();
+ _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
+#endif
+
// blur blend mask to smooth transitions
gaussianBlur(blend, blend, W, H, 2.0);
+
+#ifdef __SSE2__
+ _MM_SET_FLUSH_ZERO_MODE(oldMode);
+#endif
}
}
}
diff --git a/rtengine/rt_algo.h b/rtengine/rt_algo.h
index 5485346c7..81147fd75 100644
--- a/rtengine/rt_algo.h
+++ b/rtengine/rt_algo.h
@@ -24,5 +24,5 @@
namespace rtengine
{
void findMinMaxPercentile(const float* data, size_t size, float minPrct, float& minOut, float maxPrct, float& maxOut, bool multiThread = true);
-void buildBlendMask(const float* const * luminance, float **blend, int W, int H, float &contrastThreshold, float amount = 1.f, bool autoContrast = false, float ** clipmask = nullptr);
+void buildBlendMask(const float* const * luminance, float **blend, int W, int H, float &contrastThreshold, bool autoContrast = false, float ** clipmask = nullptr);
}
diff --git a/rtengine/vng4_demosaic_RT.cc b/rtengine/vng4_demosaic_RT.cc
index 47982b6da..ef456af3a 100644
--- a/rtengine/vng4_demosaic_RT.cc
+++ b/rtengine/vng4_demosaic_RT.cc
@@ -45,12 +45,12 @@ inline void vng4interpolate_row_redblue (const RawImage *ri, const array2D &rawData, array2D firstRow) {
vng4interpolate_row_redblue(ri, rawData, red[row - 1], blue[row - 1], green[row - 2], green[row - 1], green[row], row - 1, W);
diff --git a/rtengine/xtrans_demosaic.cc b/rtengine/xtrans_demosaic.cc
index c1a526535..cb1315ed0 100644
--- a/rtengine/xtrans_demosaic.cc
+++ b/rtengine/xtrans_demosaic.cc
@@ -939,9 +939,9 @@ void RawImageSource::xtrans_interpolate (const int passes, const bool useCieLab,
avg[3]++;
}
- red[row + top][col + left] = avg[0] / avg[3];
- green[row + top][col + left] = avg[1] / avg[3];
- blue[row + top][col + left] = avg[2] / avg[3];
+ red[row + top][col + left] = std::max(0.f, avg[0] / avg[3]);
+ green[row + top][col + left] = std::max(0.f, avg[1] / avg[3]);
+ blue[row + top][col + left] = std::max(0.f, avg[2] / avg[3]);
}
if(plistenerActive && ((++progressCounter) % 32 == 0)) {
diff --git a/rtgui/adjuster.cc b/rtgui/adjuster.cc
index 2267a9fc1..142374213 100644
--- a/rtgui/adjuster.cc
+++ b/rtgui/adjuster.cc
@@ -230,22 +230,7 @@ void Adjuster::setDefaultEditedState (EditedState eState)
void Adjuster::autoToggled ()
{
- if (!editedCheckBox) {
- // If not used in the BatchEditor panel
- if (automatic->get_active()) {
- // Disable the slider and spin button
- spin->set_sensitive(false);
- slider->set_sensitive(false);
- reset->set_sensitive(false);
- } else {
- // Enable the slider and spin button
- spin->set_sensitive(true);
- slider->set_sensitive(true);
- reset->set_sensitive(true);
- }
- }
-
- if (adjusterListener != nullptr && !blocked) {
+ if (adjusterListener && !blocked) {
adjusterListener->adjusterAutoToggled(this);
}
}
@@ -380,6 +365,9 @@ void Adjuster::spinChanged ()
if (adjusterListener && !blocked) {
if (!buttonReleaseSlider.connected() || afterReset) {
eventPending = false;
+ if (automatic) {
+ setAutoValue(false);
+ }
adjusterListener->adjusterChanged(this, spin->get_value());
} else {
eventPending = true;
@@ -419,6 +407,9 @@ void Adjuster::sliderChanged ()
if (adjusterListener && !blocked) {
if (!buttonReleaseSlider.connected() || afterReset) {
eventPending = false;
+ if (automatic) {
+ setAutoValue(false);
+ }
adjusterListener->adjusterChanged(this, spin->get_value());
} else {
eventPending = true;
@@ -459,21 +450,6 @@ void Adjuster::setAutoValue (bool a)
const bool oldVal = autoChange.block(true);
automatic->set_active(a);
autoChange.block(oldVal);
-
- if (!editedCheckBox) {
- // If not used in the BatchEditor panel
- if (a) {
- // Disable the slider and spin button
- spin->set_sensitive(false);
- slider->set_sensitive(false);
- reset->set_sensitive(false);
- } else {
- // Enable the slider and spin button
- spin->set_sensitive(true);
- slider->set_sensitive(true);
- reset->set_sensitive(true);
- }
- }
}
}
@@ -481,6 +457,9 @@ bool Adjuster::notifyListener ()
{
if (eventPending && adjusterListener != nullptr && !blocked) {
+ if (automatic) {
+ setAutoValue(false);
+ }
adjusterListener->adjusterChanged(this, spin->get_value());
}
@@ -571,6 +550,9 @@ void Adjuster::showEditedCB ()
void Adjuster::editedToggled ()
{
if (adjusterListener && !blocked) {
+ if (automatic) {
+ setAutoValue(false);
+ }
adjusterListener->adjusterChanged(this, spin->get_value());
}
diff --git a/rtgui/cropwindow.cc b/rtgui/cropwindow.cc
index b00032191..0a9b81112 100644
--- a/rtgui/cropwindow.cc
+++ b/rtgui/cropwindow.cc
@@ -1492,9 +1492,9 @@ void CropWindow::expose (Cairo::RefPtr cr)
const float kernel_size2 = SQR(2.f * blur_radius2 + 1.f); // count of pixels in the small blur kernel
const float rkernel_size2 = 1.0f / kernel_size2; // reciprocal of kernel_size to avoid divisions
- // aloocate buffer for precalculated Luminance
+ // allocate buffer for precalculated Luminance
float* tmpL = (float*)malloc(bHeight * bWidth * sizeof(float) );
- // aloocate buffers for sums and sums of squares of small kernel
+ // allocate buffers for sums and sums of squares of small kernel
float* tmpLsum = (float*)malloc((bHeight) * (bWidth) * sizeof(float) );
float* tmpLsumSq = (float*)malloc((bHeight) * (bWidth) * sizeof(float) );
float* tmpstdDev2 = (float*)malloc((bHeight) * (bWidth) * sizeof(float) );
@@ -1631,7 +1631,7 @@ void CropWindow::expose (Cairo::RefPtr cr)
&& stdDev_L2 > stdDev_L //this is the key to select fine detail within lower contrast on larger scale
&& stdDev_L > focus_threshby10 //options.highlightThreshold
) {
- // transpareny depends on sdtDev_L2 and maxstdDev_L2
+ // transparency depends on sdtDev_L2 and maxstdDev_L2
float transparency = 1.f - std::min(stdDev_L2 / maxstdDev_L2, 1.0f) ;
// first row of circle
guint8* currtmp = &curr[0] + (-3 * pixRowStride);
diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc
index 1b5ed3fa7..806af8b2e 100644
--- a/rtgui/editorpanel.cc
+++ b/rtgui/editorpanel.cc
@@ -2067,6 +2067,7 @@ bool EditorPanel::idle_sentToGimp (ProgressConnector *pc, rtengine::IImagef
{
img->free ();
int errore = pc->returnValue();
+ setProgressState(false);
delete pc;
if (!errore) {
diff --git a/rtgui/editwidgets.h b/rtgui/editwidgets.h
index 55b4ca3cc..0fa7a91bf 100644
--- a/rtgui/editwidgets.h
+++ b/rtgui/editwidgets.h
@@ -55,7 +55,7 @@ class RTSurface;
* - drag1
* - button1Released
*
- * Actually, only curves does use this class, and everything is handled for curve implementor (as much as possible).
+ * Actually, only curves does use this class, and everything is handled for curve implementer (as much as possible).
* See the curve's class documentation to see how to implement the curve's pipette feature.
*
* ### Event handling
diff --git a/rtgui/options.cc b/rtgui/options.cc
index 24549d820..8abbf5e0c 100644
--- a/rtgui/options.cc
+++ b/rtgui/options.cc
@@ -225,7 +225,7 @@ Glib::ustring Options::getPreferredProfilePath()
*
*@param profName path + filename of the procparam to look for. A filename without path can be provided for backward compatibility.
* In this case, this parameter will be updated with the new format.
- *@return Send back the absolute path of the given filename or "Neutral" if "Neutral" has been set to profName. Implementor will have
+ *@return Send back the absolute path of the given filename or "Neutral" if "Neutral" has been set to profName. Implementer will have
* to test for this particular value. If the absolute path is invalid (e.g. the file doesn't exist), it will return an empty string.
*/
Glib::ustring Options::findProfilePath(Glib::ustring &profName)
diff --git a/rtgui/rtwindow.cc b/rtgui/rtwindow.cc
index 5ab3ab85d..514685a16 100644
--- a/rtgui/rtwindow.cc
+++ b/rtgui/rtwindow.cc
@@ -383,8 +383,13 @@ RTWindow::RTWindow ()
iccProfileCreator->set_tooltip_markup (M ("MAIN_BUTTON_ICCPROFCREATOR"));
iccProfileCreator->signal_clicked().connect ( sigc::mem_fun (*this, &RTWindow::showICCProfileCreator) );
- //Gtk::LinkButton* rtWeb = Gtk::manage (new Gtk::LinkButton ("http://rawtherapee.com")); // unused... but fail to be linked anyway !?
- //Gtk::Button* preferences = Gtk::manage (new Gtk::Button (M("MAIN_BUTTON_PREFERENCES")+"..."));
+ Gtk::Button* helpBtn = Gtk::manage (new Gtk::Button ());
+ setExpandAlignProperties (helpBtn, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER);
+ helpBtn->set_relief(Gtk::RELIEF_NONE);
+ helpBtn->set_image (*Gtk::manage (new RTImage ("questionmark.png")));
+ helpBtn->set_tooltip_markup (M ("GENERAL_HELP"));
+ helpBtn->signal_clicked().connect (sigc::mem_fun (*this, &RTWindow::showRawPedia));
+
Gtk::Button* preferences = Gtk::manage (new Gtk::Button ());
setExpandAlignProperties (preferences, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER);
preferences->set_relief(Gtk::RELIEF_NONE);
@@ -392,7 +397,6 @@ RTWindow::RTWindow ()
preferences->set_tooltip_markup (M ("MAIN_BUTTON_PREFERENCES"));
preferences->signal_clicked().connect ( sigc::mem_fun (*this, &RTWindow::showPreferences) );
- //btn_fullscreen = Gtk::manage( new Gtk::Button(M("MAIN_BUTTON_FULLSCREEN")));
btn_fullscreen = Gtk::manage ( new Gtk::Button());
setExpandAlignProperties (btn_fullscreen, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER);
btn_fullscreen->set_relief(Gtk::RELIEF_NONE);
@@ -414,6 +418,7 @@ RTWindow::RTWindow ()
actionGrid->set_orientation (Gtk::ORIENTATION_VERTICAL);
actionGrid->attach_next_to (prProgBar, Gtk::POS_BOTTOM, 1, 1);
actionGrid->attach_next_to (*iccProfileCreator, Gtk::POS_BOTTOM, 1, 1);
+ actionGrid->attach_next_to (*helpBtn, Gtk::POS_BOTTOM, 1, 1);
actionGrid->attach_next_to (*preferences, Gtk::POS_BOTTOM, 1, 1);
actionGrid->attach_next_to (*btn_fullscreen, Gtk::POS_BOTTOM, 1, 1);
mainNB->set_action_widget (actionGrid, Gtk::PACK_END);
@@ -422,6 +427,7 @@ RTWindow::RTWindow ()
actionGrid->set_orientation (Gtk::ORIENTATION_HORIZONTAL);
actionGrid->attach_next_to (prProgBar, Gtk::POS_RIGHT, 1, 1);
actionGrid->attach_next_to (*iccProfileCreator, Gtk::POS_RIGHT, 1, 1);
+ actionGrid->attach_next_to (*helpBtn, Gtk::POS_RIGHT, 1, 1);
actionGrid->attach_next_to (*preferences, Gtk::POS_RIGHT, 1, 1);
actionGrid->attach_next_to (*btn_fullscreen, Gtk::POS_RIGHT, 1, 1);
mainNB->set_action_widget (actionGrid, Gtk::PACK_END);
@@ -913,6 +919,12 @@ void RTWindow::writeToolExpandedStatus (std::vector &tpOpen)
}
+void RTWindow::showRawPedia()
+{
+ GError* gerror = nullptr;
+ gtk_show_uri(nullptr, "https://rawpedia.rawtherapee.com/", GDK_CURRENT_TIME, &gerror);
+}
+
void RTWindow::showICCProfileCreator ()
{
ICCProfileCreator *iccpc = new ICCProfileCreator (this);
diff --git a/rtgui/rtwindow.h b/rtgui/rtwindow.h
index 100ddf636..4791ac6c1 100644
--- a/rtgui/rtwindow.h
+++ b/rtgui/rtwindow.h
@@ -90,6 +90,7 @@ public:
bool on_window_state_event (GdkEventWindowState* event) override;
void on_mainNB_switch_page (Gtk::Widget* widget, guint page_num);
+ void showRawPedia();
void showICCProfileCreator ();
void showPreferences ();
void on_realize () override;
diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc
index bcf578143..5295b9d61 100644
--- a/rtgui/thumbnail.cc
+++ b/rtgui/thumbnail.cc
@@ -341,34 +341,31 @@ void Thumbnail::notifylisterners_procParamsChanged(int whoChangedIt)
* the Preferences).
*
* The result is a complete ProcParams with default values merged with the values
- * from the default Raw or Image ProcParams, then with the values from the loaded
- * ProcParams (sidecar or cache file).
- */
+ * from the loaded ProcParams (sidecar or cache file).
+*/
void Thumbnail::loadProcParams ()
{
MyMutex::MyLock lock(mutex);
pparamsValid = false;
pparams->setDefaults();
- const PartialProfile *defaultPP = ProfileStore::getInstance()->getDefaultPartialProfile(getType() == FT_Raw);
- defaultPP->applyTo(pparams.get());
if (options.paramsLoadLocation == PLL_Input) {
// try to load it from params file next to the image file
- int ppres = pparams->load (fname + paramFileExtension);
+ const int ppres = pparams->load(fname + paramFileExtension);
pparamsValid = !ppres && pparams->ppVersion >= 220;
// if no success, try to load the cached version of the procparams
if (!pparamsValid) {
- pparamsValid = !pparams->load (getCacheFileName ("profiles", paramFileExtension));
+ pparamsValid = !pparams->load(getCacheFileName("profiles", paramFileExtension));
}
} else {
// try to load it from cache
- pparamsValid = !pparams->load (getCacheFileName ("profiles", paramFileExtension));
+ pparamsValid = !pparams->load(getCacheFileName("profiles", paramFileExtension));
// if no success, try to load it from params file next to the image file
if (!pparamsValid) {
- int ppres = pparams->load (fname + paramFileExtension);
+ const int ppres = pparams->load(fname + paramFileExtension);
pparamsValid = !ppres && pparams->ppVersion >= 220;
}
}
diff --git a/tools/gimp-plugin/file-formats.h b/tools/gimp-plugin/file-formats.h
index ac8c2fa54..1956988d8 100644
--- a/tools/gimp-plugin/file-formats.h
+++ b/tools/gimp-plugin/file-formats.h
@@ -39,8 +39,8 @@ static const FileFormat file_formats[] =
{
{
N_("Raw Canon"),
- "image/x-canon-cr2,image/x-canon-crw",
- "cr2,crw",
+ "image/x-canon-cr2,image/x-canon-cr3,image/x-canon-crw",
+ "cr2,cr3,crw",
NULL,
"file-rawtherapee-canon-load",
diff --git a/tools/osx/libiconv_1.16_rt.patch b/tools/osx/libiconv_1.16_rt.patch
new file mode 100644
index 000000000..470f7780c
--- /dev/null
+++ b/tools/osx/libiconv_1.16_rt.patch
@@ -0,0 +1,31 @@
+diff --git a/lib/iconv.c b/lib/iconv.c
+index b7a04f8..41c5896 100644
+--- a/lib/iconv.c
++++ b/lib/iconv.c
+@@ -610,5 +610,26 @@ strong_alias (libiconv_open, iconv_open)
+ strong_alias (libiconv, iconv)
+ strong_alias (libiconv_close, iconv_close)
+ #endif
++
++#undef iconv_open
++#undef iconv
++#undef iconv_close
++
++LIBICONV_DLL_EXPORTED iconv_t iconv_open (const char* tocode, const char* fromcode)
++{
++ return libiconv_open(tocode, fromcode);
++}
++
++LIBICONV_DLL_EXPORTED size_t iconv (iconv_t icd,
++ ICONV_CONST char * * inbuf, size_t *inbytesleft,
++ char * * outbuf, size_t *outbytesleft)
++{
++ return libiconv(icd, inbuf, inbytesleft, outbuf, outbytesleft);
++}
++
++LIBICONV_DLL_EXPORTED int iconv_close (iconv_t icd)
++{
++ return libiconv_close(icd);
++}
+
+ #endif
diff --git a/tools/osx/macosx_bundle.sh b/tools/osx/macosx_bundle.sh
index 2501e936b..3958326e8 100644
--- a/tools/osx/macosx_bundle.sh
+++ b/tools/osx/macosx_bundle.sh
@@ -99,6 +99,7 @@ MACOS="${CONTENTS}/MacOS"
LIB="${CONTENTS}/Frameworks"
ETC="${RESOURCES}/etc"
EXECUTABLE="${MACOS}/rawtherapee"
+GDK_PREFIX="/usr/local/opt/gdk-pixbuf"
msg "Removing old files:"
rm -rf "${APP}" "${PROJECT_NAME}_*.dmg" "*zip"
@@ -111,13 +112,13 @@ install -d "${RESOURCES}" \
msg "Copying release files:"
ditto "${CMAKE_BUILD_TYPE}/MacOS" "${MACOS}"
-ditto "${CMAKE_BUILD_TYPE}/Resources" "${RESOURCES}"
+ditto "Resources" "${RESOURCES}"
msg "Copying dependencies from ${GTK_PREFIX}:"
CheckLink "${EXECUTABLE}"
msg "Copying library modules from ${GTK_PREFIX}:"
-ditto --arch "${arch}" {"${GTK_PREFIX}/lib","${LIB}"}/gdk-pixbuf-2.0
+ditto --arch "${arch}" {"${GDK_PREFIX}/lib","${LIB}"}/gdk-pixbuf-2.0
ditto --arch "${arch}" {"${GTK_PREFIX}/lib","${LIB}"}/gtk-3.0
msg "Removing static libraries and cache files:"
@@ -129,50 +130,56 @@ install -d "${ETC}/gtk-3.0"
# Make Frameworks folder flat
mv "${LIB}"/gdk-pixbuf-2.0/2*/loaders/*.so "${LIB}"
mv "${LIB}"/gtk-3.0/3*/immodules/*.so "${LIB}"
+# the print*.so lead to errors when running gtk-query-immodules-3.0, just seeing what the app does without, since they are not in immodules
+# and including them leads to errors and a completely empty gtk.immodules file
+# mv "${LIB}"/gtk-3.0/3*/printbackends/*.so "${LIB}"
rm -r "${LIB}"/gtk-3.0
rm -r "${LIB}"/gdk-pixbuf-2.0
-"${GTK_PREFIX}/bin/gdk-pixbuf-query-loaders" "${LIB}"/libpix*.so > "${ETC}/gtk-3.0/gdk-pixbuf.loaders"
-"${GTK_PREFIX}/bin/gtk-query-immodules-3.0" "${LIB}"/{im*.so,libprint*.so} > "${ETC}/gtk-3.0/gtk.immodules"
+"${GDK_PREFIX}"/bin/gdk-pixbuf-query-loaders "${LIB}"/libpix*.so > "${ETC}"/gtk-3.0/gdk-pixbuf.loaders
+"${GTK_PREFIX}"/bin/gtk-query-immodules-3.0 "${LIB}"/im*.so > "${ETC}"/gtk-3.0/gtk.immodules
sed -i "" -e "s|${PWD}/RawTherapee.app/Contents/|/Applications/RawTherapee.app/Contents/|" "${ETC}/gtk-3.0/gdk-pixbuf.loaders" "${ETC}/gtk-3.0/gtk.immodules"
-ditto {"${GTK_PREFIX}","${RESOURCES}"}/share/glib-2.0/schemas
-"${GTK_PREFIX}/bin/glib-compile-schemas" "${RESOURCES}/share/glib-2.0/schemas"
+mkdir -p ${RESOURCES}/share/glib-2.0
+cp -pRL {"/usr/local","${RESOURCES}"}/share/glib-2.0/schemas
+"/usr/local/bin/glib-compile-schemas" "${RESOURCES}/share/glib-2.0/schemas"
msg "Copying shared files from ${GTK_PREFIX}:"
-ditto {"${GTK_PREFIX}","${RESOURCES}"}/share/mime
+cp -pRL {"/usr/local","${RESOURCES}"}/share/mime
+
# GTK3 themes
-ditto {"${GTK_PREFIX}","${RESOURCES}"}/share/themes/Mac/gtk-3.0/gtk-keys.css
-ditto {"${GTK_PREFIX}","${RESOURCES}"}/share/themes/Default/gtk-3.0/gtk-keys.css
+ditto {"/usr/local","${RESOURCES}"}/share/themes/Mac/gtk-3.0/gtk-keys.css
+ditto {"/usr/local","${RESOURCES}"}/share/themes/Default/gtk-3.0/gtk-keys.css
# Adwaita icons
iconfolders=("16x16/actions" "16x16/devices" "16x16/mimetypes" "16x16/places" "16x16/status" "48x48/devices")
for f in "${iconfolders[@]}"; do
- ditto {"${GTK_PREFIX}","${RESOURCES}"}/share/icons/Adwaita/"$f"
+ mkdir -p ${RESOURCES}/share/icons/Adwaita/${f}
+ cp /usr/local/share/icons/Adwaita/${f}/* "${RESOURCES}"/share/icons/Adwaita/${f}
done
-ditto {"${GTK_PREFIX}","${RESOURCES}"}/share/icons/Adwaita/index.theme
-"${GTK_PREFIX}/bin/gtk-update-icon-cache-3.0" "${RESOURCES}/share/icons/Adwaita"
+ditto {"/usr/local","${RESOURCES}"}/share/icons/Adwaita/index.theme
+"/usr/local/bin/gtk-update-icon-cache" "${RESOURCES}/share/icons/Adwaita"
# Copy libjpeg-turbo into the app bundle
-cp /opt/local/lib/libjpeg.62.dylib "${RESOURCES}/../Frameworks"
+cp /usr/local/lib/libjpeg.*.dylib "${CONTENTS}/Frameworks"
-# Copy libexpat into the app bundle
-cp /opt/local/lib/libexpat.1.dylib "${RESOURCES}/../Frameworks"
+# Copy libexpat into the app bundle (which is keg-only)
+cp /usr/local/Cellar/expat/*/lib/libexpat.1.dylib "${CONTENTS}/Frameworks"
# Copy libz into the app bundle
-cp /opt/local/lib/libz.1.dylib "${RESOURCES}/../Frameworks"
+cp /usr/lib/libz.1.dylib "${CONTENTS}/Frameworks"
# Copy libtiff into the app bundle
-cp /opt/local/lib/libtiff.5.dylib "${RESOURCES}/../Frameworks"
+cp /usr/local/lib/libtiff.5.dylib "${CONTENTS}/Frameworks"
# Copy the Lensfun database into the app bundle
mkdir -p "${RESOURCES}/share/lensfun"
-cp /opt/local/share/lensfun/version_2/* "${RESOURCES}/share/lensfun"
+cp /usr/local/share/lensfun/version_2/* "${RESOURCES}/share/lensfun"
# Copy liblensfun to Frameworks
-cp /opt/local/lib/liblensfun.2.dylib "${RESOURCES}/../Frameworks"
+cp /usr/local/lib/liblensfun.2.dylib "${CONTENTS}/Frameworks"
# Copy libomp to Frameworks
-cp /opt/local/lib/libomp.dylib "${RESOURCES}/../Frameworks"
+cp /usr/local/lib/libomp.dylib "${CONTENTS}/Frameworks"
# Install names
find -E "${CONTENTS}" -type f -regex '.*/(rawtherapee-cli|rawtherapee|.*\.(dylib|so))' | while read -r x; do