From 35da4bbfb70807035e89a9cdd0ee180bd53b1e70 Mon Sep 17 00:00:00 2001 From: ghorvath Date: Fri, 1 Jan 2010 11:52:33 +0000 Subject: [PATCH] initial import --- CMakeLists.txt | 5 + authors | 9 + clean | 17 + clean.bat | 17 + compile | 35 + copying | 674 ++ header | 18 + lib/libiptcdata.a | Bin 0 -> 98862 bytes lib/libjpeg.a | Bin 0 -> 145886 bytes lib/liblcms.a | Bin 0 -> 1145390 bytes lib/libpng.a | Bin 0 -> 275108 bytes lib/libtiff.a | Bin 0 -> 1554768 bytes lib/libz.a | Bin 0 -> 79218 bytes lib/readme.txt | 2 + options.lin | 94 + options.win | 94 + rawzor_lin32/librwz_sdk.so | Bin 0 -> 431280 bytes rawzor_lin32/rwz_sdk.h | 81 + rawzor_lin64/librwz_sdk.so | Bin 0 -> 443296 bytes rawzor_lin64/rwz_sdk.h | 81 + rawzor_win/makeimp.bat | 2 + rawzor_win/rwz_sdk.h | 81 + rawzor_win/rwz_sdk_s.a | Bin 0 -> 5272 bytes rawzor_win/rwz_sdk_s.def | 7 + rawzor_win/rwz_sdk_s.dll | Bin 0 -> 435712 bytes rawzor_win/rwz_sdk_s.lib | Bin 0 -> 2698 bytes release/images/addtagl.png | Bin 0 -> 917 bytes release/images/addtags.png | Bin 0 -> 653 bytes release/images/cdrom.png | Bin 0 -> 4102 bytes release/images/closedhand22.png | Bin 0 -> 3168 bytes release/images/crop16.png | Bin 0 -> 140 bytes release/images/crop22.png | Bin 0 -> 1047 bytes release/images/deltagl.png | Bin 0 -> 1068 bytes release/images/deltags.png | Bin 0 -> 691 bytes release/images/deltags.pp2 | 124 + release/images/down.png | Bin 0 -> 449 bytes release/images/edited.png | Bin 0 -> 790 bytes release/images/fileopen.png | Bin 0 -> 663 bytes release/images/filesave.png | Bin 0 -> 378 bytes release/images/filter.png | Bin 0 -> 214 bytes release/images/flame22.png | Bin 0 -> 1273 bytes release/images/floppy.png | Bin 0 -> 3610 bytes release/images/folder.png | Bin 0 -> 381 bytes release/images/folder_open.png | Bin 0 -> 437 bytes release/images/folder_open_r.png | Bin 0 -> 849 bytes release/images/folder_orange.png | Bin 0 -> 1060 bytes release/images/folder_orange_open.png | Bin 0 -> 1081 bytes release/images/folder_r.png | Bin 0 -> 819 bytes release/images/gimp.png | Bin 0 -> 890 bytes release/images/grayrated.png | Bin 0 -> 384 bytes release/images/green.png | Bin 0 -> 3625 bytes release/images/gtk-close.png | Bin 0 -> 889 bytes release/images/gtk-undo-ltr-big.png | Bin 0 -> 1249 bytes release/images/gtk-undo-ltr.png | Bin 0 -> 920 bytes release/images/gtk-zoom-100.png | Bin 0 -> 784 bytes release/images/gtk-zoom-fit.png | Bin 0 -> 750 bytes release/images/gtk-zoom-in.png | Bin 0 -> 785 bytes release/images/gtk-zoom-out.png | Bin 0 -> 772 bytes release/images/hdd.png | Bin 0 -> 4026 bytes release/images/head.png | Bin 0 -> 595 bytes release/images/horizontal.png | Bin 0 -> 819 bytes release/images/horizontals.png | Bin 0 -> 899 bytes release/images/icon-gears.png | Bin 0 -> 1182 bytes release/images/info.png | Bin 0 -> 1652 bytes release/images/left.png | Bin 0 -> 525 bytes release/images/list-add.png | Bin 0 -> 323 bytes release/images/list-add12.png | Bin 0 -> 2979 bytes release/images/list-remove.png | Bin 0 -> 247 bytes release/images/list-remove12r.png | Bin 0 -> 2901 bytes release/images/logoicon16.png | Bin 0 -> 804 bytes release/images/logoicon16b.png | Bin 0 -> 898 bytes release/images/logoicon32.png | Bin 0 -> 2597 bytes release/images/network.png | Bin 0 -> 3941 bytes release/images/notrated.png | Bin 0 -> 199 bytes release/images/openhand.png | Bin 0 -> 3345 bytes release/images/openhand22.png | Bin 0 -> 3300 bytes release/images/processing.png | Bin 0 -> 865 bytes release/images/rated.png | Bin 0 -> 706 bytes release/images/red.png | Bin 0 -> 925 bytes release/images/resize.png | Bin 0 -> 486 bytes release/images/saved.png | Bin 0 -> 587 bytes release/images/splash.png | Bin 0 -> 91814 bytes release/images/stock-color-picker-gray-18.png | Bin 0 -> 518 bytes release/images/stock-flip-horizontal-16.png | Bin 0 -> 387 bytes release/images/stock-flip-vertical-16.png | Bin 0 -> 407 bytes release/images/stock-resize-16.png | Bin 0 -> 286 bytes release/images/stock-rotate-270-16.png | Bin 0 -> 405 bytes release/images/stock-rotate-90-16.png | Bin 0 -> 418 bytes release/images/stock-tool-color-picker-22.png | Bin 0 -> 627 bytes release/images/stock-tool-crop-16.png | Bin 0 -> 367 bytes release/images/stock-tool-crop-22.png | Bin 0 -> 811 bytes release/images/stock_clear_24.png | Bin 0 -> 791 bytes release/images/stock_down_arrow_24.png | Bin 0 -> 589 bytes release/images/stock_left_arrow_24.png | Bin 0 -> 583 bytes release/images/stock_right_arrow_24.png | Bin 0 -> 581 bytes release/images/stock_up_arrow_24.png | Bin 0 -> 613 bytes release/images/straighten16.png | Bin 0 -> 2918 bytes release/images/straighten22.png | Bin 0 -> 2931 bytes release/images/tail.png | Bin 0 -> 608 bytes release/images/trash.png | Bin 0 -> 810 bytes release/images/undelete.png | Bin 0 -> 914 bytes release/images/undo.png | Bin 0 -> 194 bytes release/images/unrated.png | Bin 0 -> 707 bytes release/images/usbpendrive.png | Bin 0 -> 1385 bytes release/images/vertical.png | Bin 0 -> 777 bytes release/images/verticals.png | Bin 0 -> 967 bytes release/images/warnhl.png | Bin 0 -> 600 bytes release/images/warnsh.png | Bin 0 -> 578 bytes release/images/wb22.png | Bin 0 -> 1253 bytes release/images/wbpicker16.png | Bin 0 -> 317 bytes release/images/wbpicker22.png | Bin 0 -> 1566 bytes release/languages/chinese simplified | 579 + release/languages/chinese traditional | 577 + release/languages/czech | 581 + release/languages/dansk | 577 + release/languages/deutsch | 584 + release/languages/english-uk | 577 + release/languages/english-us | 581 + release/languages/espanol | 583 + release/languages/euskara | 577 + release/languages/francais | 579 + release/languages/greek | 575 + release/languages/hebrew | 577 + release/languages/italian | 580 + release/languages/japanese | 576 + release/languages/latvian | 574 + release/languages/magyar | 577 + release/languages/nederlands | 578 + release/languages/polish | 583 + release/languages/russian | 579 + release/languages/slovak | 577 + release/languages/suomi | 576 + release/languages/swedish | 577 + release/languages/turkish | 577 + release/profiles/crisp.pp2 | 124 + release/profiles/default.pp2 | 125 + release/profiles/neutral.pp2 | 124 + release/themes/dark | 194 + release/themes/default | 151 + release/themes/gray | 230 + release/themes/light | 150 + release/themes/test | 259 + rtengine/CMakeCache.txt | 401 + rtengine/CMakeLists.txt | 49 + rtengine/Doxyfile | 1356 +++ rtengine/alignedbuffer.h | 40 + rtengine/bilateral2.cc | 35 + rtengine/bilateral2.h | 750 ++ rtengine/bilateral3.h | 536 + rtengine/colorclip.h | 132 + rtengine/colortemp.cc | 87 + rtengine/colortemp.h | 57 + rtengine/common.h | 76 + rtengine/coord2d.h | 33 + rtengine/cubic.cc | 82 + rtengine/cubint.cc | 75 + rtengine/cubintch.cc | 61 + rtengine/curves.cc | 678 ++ rtengine/curves.h | 147 + rtengine/dcraw.c | 8784 +++++++++++++++ rtengine/dcraw.cc | 9374 +++++++++++++++++ rtengine/dcraw.patch | 727 ++ rtengine/dcrop.cc | 386 + rtengine/dcrop.h | 74 + rtengine/ex1simple.cc | 83 + rtengine/ex2simple.cc | 140 + rtengine/gauss.cc | 49 + rtengine/gauss.h | 624 ++ rtengine/helpers.cc | 67 + rtengine/helpers.h | 67 + rtengine/hlmultipliers.cc | 352 + rtengine/hlrecovery.cc | 287 + rtengine/iccjpeg.c | 256 + rtengine/iccjpeg.h | 80 + rtengine/iccmatrices.h | 74 + rtengine/iccstore.cc | 314 + rtengine/iccstore.h | 82 + rtengine/iimage.h | 96 + rtengine/image16.cc | 244 + rtengine/image16.h | 86 + rtengine/image8.cc | 109 + rtengine/image8.h | 71 + rtengine/imagedata.cc | 418 + rtengine/imagedata.h | 70 + rtengine/imageio.cc | 759 ++ rtengine/imageio.h | 87 + rtengine/imagesource.h | 95 + rtengine/improccoordinator.cc | 577 + rtengine/improccoordinator.h | 152 + rtengine/improcfun.cc | 2085 ++++ rtengine/improcfun.h | 113 + rtengine/init.cc | 68 + rtengine/iptcpairs.h | 47 + rtengine/jdatasrc.c | 413 + rtengine/loadinitial.cc | 43 + rtengine/median.h | 222 + rtengine/minmax.h | 76 + rtengine/myfile.cc | 133 + rtengine/myfile.h | 92 + rtengine/mytime.h | 55 + rtengine/pparamsmap.cc | 166 + rtengine/processingjob.cc | 39 + rtengine/processingjob.h | 45 + rtengine/procevents.h | 114 + rtengine/procparams.cc | 657 ++ rtengine/procparams.h | 346 + rtengine/rawimagesource.cc | 2377 +++++ rtengine/rawimagesource.h | 143 + rtengine/rawmetadatalocation.h | 32 + rtengine/refreshmap.cc | 106 + rtengine/refreshmap.h | 53 + rtengine/rtcmd | Bin 0 -> 31928 bytes rtengine/rtengine.h | 386 + rtengine/rtetest.cc | 71 + rtengine/rtthumbnail.cc | 890 ++ rtengine/rtthumbnail.h | 99 + rtengine/settings.h | 45 + rtengine/shmap.cc | 135 + rtengine/shmap.h | 40 + rtengine/simpleprocess.cc | 229 + rtengine/sizes.txt | 24 + rtengine/stdimagesource.cc | 546 + rtengine/stdimagesource.h | 73 + rtengine/updater.cc | 106 + rtengine/updater.h | 57 + rtengine/utils.cc | 144 + rtengine/utils.h | 31 + rtexif/CMakeLists.txt | 10 + rtexif/canonattribs.cc | 812 ++ rtexif/fujiattribs.cc | 263 + rtexif/nikonattribs.cc | 617 ++ rtexif/olympusattribs.cc | 673 ++ rtexif/pentaxattribs.cc | 556 + rtexif/rtexif.cc | 1384 +++ rtexif/rtexif.h | 244 + rtexif/sonyminoltaattribs.cc | 391 + rtexif/stdattribs.cc | 486 + rtgui/CMakeCache.txt | 503 + rtgui/CMakeLists.txt | 101 + rtgui/RT.ico | Bin 0 -> 127737 bytes rtgui/adjuster.cc | 273 + rtgui/adjuster.h | 83 + rtgui/batchqueue.cc | 403 + rtgui/batchqueue.h | 84 + rtgui/batchqueuebuttonset | 27 + rtgui/batchqueuebuttonset.cc | 42 + rtgui/batchqueuebuttonset.h | 38 + rtgui/batchqueueentry.cc | 156 + rtgui/batchqueueentry.h | 66 + rtgui/batchqueuepanel.cc | 241 + rtgui/batchqueuepanel.h | 78 + rtgui/batchtoolpanelcoord.cc | 295 + rtgui/batchtoolpanelcoord.h | 76 + rtgui/bqentryupdater.cc | 137 + rtgui/bqentryupdater.h | 62 + rtgui/browserfilter.cc | 26 + rtgui/browserfilter.h | 37 + rtgui/cacheimagedata.cc | 138 + rtgui/cacheimagedata.h | 67 + rtgui/cachemanager.cc | 279 + rtgui/cachemanager.h | 64 + rtgui/cacorrection.cc | 103 + rtgui/cacorrection.h | 46 + rtgui/chmixer.cc | 151 + rtgui/chmixer.h | 45 + rtgui/clipboard.cc | 21 + rtgui/clipboard.h | 44 + rtgui/coarsepanel.cc | 148 + rtgui/coarsepanel.h | 49 + rtgui/colorboost.cc | 191 + rtgui/colorboost.h | 53 + rtgui/colordenoise.cc | 120 + rtgui/colordenoise.h | 47 + rtgui/colorshift.cc | 108 + rtgui/colorshift.h | 46 + rtgui/createicon.cc | 200 + rtgui/crop.cc | 973 ++ rtgui/crop.h | 100 + rtgui/cropguilistener.h | 36 + rtgui/crophandler.cc | 328 + rtgui/crophandler.h | 94 + rtgui/cropwindow.cc | 1030 ++ rtgui/cropwindow.h | 146 + rtgui/cursormanager.cc | 68 + rtgui/cursormanager.h | 49 + rtgui/curveeditor.cc | 194 + rtgui/curveeditor.h | 43 + rtgui/dirbrowser.cc | 384 + rtgui/dirbrowser.h | 103 + rtgui/dirbrowserremoteinterface.h | 31 + rtgui/dirselectionlistener.h | 30 + rtgui/distortion.cc | 83 + rtgui/distortion.h | 45 + rtgui/editedstate.h | 25 + rtgui/editenums.h | 25 + rtgui/editorpanel.cc | 801 ++ rtgui/editorpanel.h | 141 + rtgui/exiffiltersettings.cc | 44 + rtgui/exiffiltersettings.h | 51 + rtgui/exifpanel.cc | 568 + rtgui/exifpanel.h | 97 + rtgui/favoritbrowser.cc | 112 + rtgui/favoritbrowser.h | 58 + rtgui/filebrowser.cc | 581 + rtgui/filebrowser.h | 116 + rtgui/filebrowserentry.cc | 555 + rtgui/filebrowserentry.h | 95 + rtgui/filecatalog.cc | 799 ++ rtgui/filecatalog.h | 191 + rtgui/filepanel.cc | 186 + rtgui/filepanel.h | 74 + rtgui/fileselectionchangelistener.h | 31 + rtgui/fileselectionlistener.h | 33 + rtgui/filethumbnailbuttonset.cc | 68 + rtgui/filethumbnailbuttonset.h | 45 + rtgui/filterpanel.cc | 210 + rtgui/filterpanel.h | 71 + rtgui/guiutils.cc | 196 + rtgui/guiutils.h | 31 + rtgui/histogrampanel.cc | 464 + rtgui/histogrampanel.h | 98 + rtgui/history.cc | 326 + rtgui/history.h | 105 + rtgui/hlrec.cc | 131 + rtgui/hlrec.h | 48 + rtgui/iccfromwindows.txt | 21 + rtgui/icmpanel.cc | 290 + rtgui/icmpanel.h | 70 + rtgui/ilabel.cc | 63 + rtgui/ilabel.h | 36 + rtgui/imagearea.cc | 418 + rtgui/imagearea.h | 125 + rtgui/imageareapanel.cc | 173 + rtgui/imageareapanel.h | 53 + rtgui/imageareatoollistener.h | 38 + rtgui/indclippedpanel.cc | 51 + rtgui/indclippedpanel.h | 41 + rtgui/iptcpanel.cc | 600 ++ rtgui/iptcpanel.h | 91 + rtgui/lcurve.cc | 143 + rtgui/lcurve.h | 53 + rtgui/lumadenoise.cc | 149 + rtgui/lumadenoise.h | 51 + rtgui/lwbutton.cc | 179 + rtgui/lwbutton.h | 74 + rtgui/lwbuttonset.cc | 169 + rtgui/lwbuttonset.h | 53 + rtgui/main.cc | 88 + rtgui/mountselectionlistener.h | 30 + rtgui/multilangmgr.cc | 97 + rtgui/multilangmgr.h | 45 + rtgui/mycurve.cc | 467 + rtgui/mycurve.h | 69 + rtgui/myicon.o | Bin 0 -> 128280 bytes rtgui/myicon.rc | 1 + rtgui/navigator.cc | 114 + rtgui/navigator.h | 45 + rtgui/options.cc | 411 + rtgui/options.h | 137 + rtgui/paramsedited.cc | 328 + rtgui/paramsedited.h | 250 + rtgui/partialpastedlg.cc | 315 + rtgui/partialpastedlg.h | 92 + rtgui/placesbrowser.cc | 294 + rtgui/placesbrowser.h | 67 + rtgui/pointermotionlistener.h | 28 + rtgui/pparamschangelistener.h | 34 + rtgui/preferences.cc | 918 ++ rtgui/preferences.h | 141 + rtgui/previewhandler.cc | 234 + rtgui/previewhandler.h | 76 + rtgui/previewwindow.cc | 212 + rtgui/previewwindow.h | 68 + rtgui/procparamchangers.h | 24 + rtgui/procthread.h | 78 + rtgui/profilechangelistener.h | 33 + rtgui/profilepanel.cc | 385 + rtgui/profilepanel.h | 70 + rtgui/profilestore.cc | 105 + rtgui/profilestore.h | 42 + rtgui/progressdialog.cc | 56 + rtgui/progressdialog.h | 126 + rtgui/quickzoomlistener.h | 34 + rtgui/recentbrowser.cc | 52 + rtgui/recentbrowser.cc.old | 59 + rtgui/recentbrowser.h | 44 + rtgui/recentbrowser.h.old | 33 + rtgui/recentselectionlistener.h | 30 + rtgui/renamedlg.cc | 215 + rtgui/renamedlg.h | 83 + rtgui/resize.cc | 346 + rtgui/resize.h | 60 + rtgui/rotate.cc | 157 + rtgui/rotate.h | 64 + rtgui/rtwindow.cc | 225 + rtgui/rtwindow.h | 54 + rtgui/saveasdlg.cc | 141 + rtgui/saveasdlg.h | 58 + rtgui/saveformatpanel.cc | 132 + rtgui/saveformatpanel.h | 58 + rtgui/shadowshighlights.cc | 254 + rtgui/shadowshighlights.h | 57 + rtgui/sharpening.cc | 461 + rtgui/sharpening.h | 79 + rtgui/splash.cc | 97 + rtgui/splash.h | 50 + rtgui/thumbbrowserbase.cc | 545 + rtgui/thumbbrowserbase.h | 118 + rtgui/thumbbrowserbase_old.cc | 360 + rtgui/thumbbrowserbase_old.h | 71 + rtgui/thumbbrowserentry.cc | 63 + rtgui/thumbbrowserentrybase.cc | 406 + rtgui/thumbbrowserentrybase.h | 125 + rtgui/thumbimageupdater.cc | 166 + rtgui/thumbimageupdater.h | 66 + rtgui/thumbnail.cc | 447 + rtgui/thumbnail.h | 130 + rtgui/thumbnail_old.cc | 1080 ++ rtgui/thumbnail_old.h | 121 + rtgui/thumbnailbrowser.h | 95 + rtgui/thumbnaillistener.h | 34 + rtgui/tonecurve.cc | 363 + rtgui/tonecurve.h | 71 + rtgui/toolbar.cc | 195 + rtgui/toolbar.h | 60 + rtgui/toolenum.h | 24 + rtgui/toolpanel.h | 58 + rtgui/toolpanelcoord.cc | 355 + rtgui/toolpanelcoord.h | 161 + rtgui/utils.cc | 39 + rtgui/utils.h | 27 + rtgui/vignetting.cc | 90 + rtgui/vignetting.h | 46 + rtgui/wbprovider.h | 31 + rtgui/whitebalance.cc | 297 + rtgui/whitebalance.h | 71 + rtgui/windirmonitor.cc | 80 + rtgui/windirmonitor.h | 53 + rtgui/zoompanel.cc | 121 + rtgui/zoompanel.h | 50 + rtinstaller.nsi | 135 + rtstart | 4 + tools/createicon.exe | Bin 0 -> 315654 bytes tools/edited.png | Bin 0 -> 790 bytes tools/editedb.png | Bin 0 -> 732 bytes tools/editedw.png | Bin 0 -> 791 bytes tools/head.png | Bin 0 -> 595 bytes tools/headb.png | Bin 0 -> 640 bytes tools/headw.png | Bin 0 -> 672 bytes tools/horizontal.svg | 202 + tools/processing.png | Bin 0 -> 865 bytes tools/processingb.png | Bin 0 -> 860 bytes tools/processingw.png | Bin 0 -> 856 bytes tools/saved.png | Bin 0 -> 587 bytes tools/savedb.png | Bin 0 -> 676 bytes tools/savedw.png | Bin 0 -> 687 bytes tools/tail.png | Bin 0 -> 608 bytes tools/tailb.png | Bin 0 -> 659 bytes tools/tailw.png | Bin 0 -> 689 bytes tools/trash.png | Bin 0 -> 810 bytes tools/trashb.png | Bin 0 -> 844 bytes tools/trashw.png | Bin 0 -> 902 bytes tools/undelete.png | Bin 0 -> 914 bytes tools/undeleteb.png | Bin 0 -> 935 bytes tools/undeletew.png | Bin 0 -> 975 bytes tools/vertical.svg | 201 + winclude/cderror.h | 132 + winclude/cdjpeg.h | 184 + winclude/common.h | 49 + winclude/deflate.h | 318 + winclude/icc34.h | 1027 ++ winclude/infblock.h | 39 + winclude/infcodes.h | 27 + winclude/inffast.h | 17 + winclude/inffixed.h | 151 + winclude/inftrees.h | 58 + winclude/infutil.h | 98 + winclude/jchuff.h | 47 + winclude/jconfig.h | 45 + winclude/jdatasrc.c | 408 + winclude/jdct.h | 176 + winclude/jdhuff.h | 201 + winclude/jerror.h | 291 + winclude/jinclude.h | 91 + winclude/jmemsys.h | 198 + winclude/jmorecfg.h | 363 + winclude/jpegint.h | 392 + winclude/jpeglib.h | 1096 ++ winclude/jversion.h | 14 + winclude/lcms.h | 2052 ++++ winclude/libiptcdata/_stdint.h | 2 + winclude/libiptcdata/iptc-data.h | 106 + winclude/libiptcdata/iptc-dataset.h | 92 + winclude/libiptcdata/iptc-jpeg.h | 45 + winclude/libiptcdata/iptc-log.h | 70 + winclude/libiptcdata/iptc-mem.h | 54 + winclude/libiptcdata/iptc-tag.h | 171 + winclude/libiptcdata/iptc-utils.h | 66 + winclude/png.h | 3283 ++++++ winclude/pngasmrd.h | 11 + winclude/pngconf.h | 1348 +++ winclude/tiff.h | 647 ++ winclude/tiffconf.h | 101 + winclude/tiffio.h | 516 + winclude/tiffiop.h | 322 + winclude/tiffvers.h | 9 + winclude/transupp.h | 135 + winclude/trees.h | 128 + winclude/zconf.h | 279 + winclude/zlib.h | 893 ++ winclude/zutil.h | 220 + 511 files changed, 109473 insertions(+) create mode 100755 CMakeLists.txt create mode 100755 authors create mode 100755 clean create mode 100755 clean.bat create mode 100755 compile create mode 100755 copying create mode 100755 header create mode 100755 lib/libiptcdata.a create mode 100755 lib/libjpeg.a create mode 100755 lib/liblcms.a create mode 100755 lib/libpng.a create mode 100755 lib/libtiff.a create mode 100755 lib/libz.a create mode 100755 lib/readme.txt create mode 100755 options.lin create mode 100755 options.win create mode 100755 rawzor_lin32/librwz_sdk.so create mode 100755 rawzor_lin32/rwz_sdk.h create mode 100755 rawzor_lin64/librwz_sdk.so create mode 100755 rawzor_lin64/rwz_sdk.h create mode 100755 rawzor_win/makeimp.bat create mode 100755 rawzor_win/rwz_sdk.h create mode 100755 rawzor_win/rwz_sdk_s.a create mode 100755 rawzor_win/rwz_sdk_s.def create mode 100755 rawzor_win/rwz_sdk_s.dll create mode 100755 rawzor_win/rwz_sdk_s.lib create mode 100755 release/images/addtagl.png create mode 100755 release/images/addtags.png create mode 100755 release/images/cdrom.png create mode 100755 release/images/closedhand22.png create mode 100755 release/images/crop16.png create mode 100755 release/images/crop22.png create mode 100755 release/images/deltagl.png create mode 100755 release/images/deltags.png create mode 100755 release/images/deltags.pp2 create mode 100755 release/images/down.png create mode 100755 release/images/edited.png create mode 100755 release/images/fileopen.png create mode 100755 release/images/filesave.png create mode 100755 release/images/filter.png create mode 100755 release/images/flame22.png create mode 100755 release/images/floppy.png create mode 100755 release/images/folder.png create mode 100755 release/images/folder_open.png create mode 100755 release/images/folder_open_r.png create mode 100755 release/images/folder_orange.png create mode 100755 release/images/folder_orange_open.png create mode 100755 release/images/folder_r.png create mode 100755 release/images/gimp.png create mode 100755 release/images/grayrated.png create mode 100755 release/images/green.png create mode 100755 release/images/gtk-close.png create mode 100755 release/images/gtk-undo-ltr-big.png create mode 100755 release/images/gtk-undo-ltr.png create mode 100755 release/images/gtk-zoom-100.png create mode 100755 release/images/gtk-zoom-fit.png create mode 100755 release/images/gtk-zoom-in.png create mode 100755 release/images/gtk-zoom-out.png create mode 100755 release/images/hdd.png create mode 100755 release/images/head.png create mode 100755 release/images/horizontal.png create mode 100755 release/images/horizontals.png create mode 100755 release/images/icon-gears.png create mode 100755 release/images/info.png create mode 100755 release/images/left.png create mode 100755 release/images/list-add.png create mode 100755 release/images/list-add12.png create mode 100755 release/images/list-remove.png create mode 100755 release/images/list-remove12r.png create mode 100755 release/images/logoicon16.png create mode 100755 release/images/logoicon16b.png create mode 100755 release/images/logoicon32.png create mode 100755 release/images/network.png create mode 100755 release/images/notrated.png create mode 100755 release/images/openhand.png create mode 100755 release/images/openhand22.png create mode 100755 release/images/processing.png create mode 100755 release/images/rated.png create mode 100755 release/images/red.png create mode 100755 release/images/resize.png create mode 100755 release/images/saved.png create mode 100755 release/images/splash.png create mode 100755 release/images/stock-color-picker-gray-18.png create mode 100755 release/images/stock-flip-horizontal-16.png create mode 100755 release/images/stock-flip-vertical-16.png create mode 100755 release/images/stock-resize-16.png create mode 100755 release/images/stock-rotate-270-16.png create mode 100755 release/images/stock-rotate-90-16.png create mode 100755 release/images/stock-tool-color-picker-22.png create mode 100755 release/images/stock-tool-crop-16.png create mode 100755 release/images/stock-tool-crop-22.png create mode 100755 release/images/stock_clear_24.png create mode 100755 release/images/stock_down_arrow_24.png create mode 100755 release/images/stock_left_arrow_24.png create mode 100755 release/images/stock_right_arrow_24.png create mode 100755 release/images/stock_up_arrow_24.png create mode 100755 release/images/straighten16.png create mode 100755 release/images/straighten22.png create mode 100755 release/images/tail.png create mode 100755 release/images/trash.png create mode 100755 release/images/undelete.png create mode 100755 release/images/undo.png create mode 100755 release/images/unrated.png create mode 100755 release/images/usbpendrive.png create mode 100755 release/images/vertical.png create mode 100755 release/images/verticals.png create mode 100755 release/images/warnhl.png create mode 100755 release/images/warnsh.png create mode 100755 release/images/wb22.png create mode 100755 release/images/wbpicker16.png create mode 100755 release/images/wbpicker22.png create mode 100755 release/languages/chinese simplified create mode 100755 release/languages/chinese traditional create mode 100755 release/languages/czech create mode 100755 release/languages/dansk create mode 100755 release/languages/deutsch create mode 100755 release/languages/english-uk create mode 100755 release/languages/english-us create mode 100755 release/languages/espanol create mode 100755 release/languages/euskara create mode 100755 release/languages/francais create mode 100755 release/languages/greek create mode 100755 release/languages/hebrew create mode 100755 release/languages/italian create mode 100755 release/languages/japanese create mode 100755 release/languages/latvian create mode 100755 release/languages/magyar create mode 100755 release/languages/nederlands create mode 100755 release/languages/polish create mode 100755 release/languages/russian create mode 100755 release/languages/slovak create mode 100755 release/languages/suomi create mode 100755 release/languages/swedish create mode 100755 release/languages/turkish create mode 100755 release/profiles/crisp.pp2 create mode 100755 release/profiles/default.pp2 create mode 100755 release/profiles/neutral.pp2 create mode 100755 release/themes/dark create mode 100755 release/themes/default create mode 100755 release/themes/gray create mode 100755 release/themes/light create mode 100755 release/themes/test create mode 100755 rtengine/CMakeCache.txt create mode 100755 rtengine/CMakeLists.txt create mode 100755 rtengine/Doxyfile create mode 100755 rtengine/alignedbuffer.h create mode 100755 rtengine/bilateral2.cc create mode 100755 rtengine/bilateral2.h create mode 100755 rtengine/bilateral3.h create mode 100755 rtengine/colorclip.h create mode 100755 rtengine/colortemp.cc create mode 100755 rtengine/colortemp.h create mode 100755 rtengine/common.h create mode 100755 rtengine/coord2d.h create mode 100755 rtengine/cubic.cc create mode 100755 rtengine/cubint.cc create mode 100755 rtengine/cubintch.cc create mode 100755 rtengine/curves.cc create mode 100755 rtengine/curves.h create mode 100755 rtengine/dcraw.c create mode 100755 rtengine/dcraw.cc create mode 100755 rtengine/dcraw.patch create mode 100755 rtengine/dcrop.cc create mode 100755 rtengine/dcrop.h create mode 100755 rtengine/ex1simple.cc create mode 100755 rtengine/ex2simple.cc create mode 100755 rtengine/gauss.cc create mode 100755 rtengine/gauss.h create mode 100755 rtengine/helpers.cc create mode 100755 rtengine/helpers.h create mode 100755 rtengine/hlmultipliers.cc create mode 100755 rtengine/hlrecovery.cc create mode 100755 rtengine/iccjpeg.c create mode 100755 rtengine/iccjpeg.h create mode 100755 rtengine/iccmatrices.h create mode 100755 rtengine/iccstore.cc create mode 100755 rtengine/iccstore.h create mode 100755 rtengine/iimage.h create mode 100755 rtengine/image16.cc create mode 100755 rtengine/image16.h create mode 100755 rtengine/image8.cc create mode 100755 rtengine/image8.h create mode 100755 rtengine/imagedata.cc create mode 100755 rtengine/imagedata.h create mode 100755 rtengine/imageio.cc create mode 100755 rtengine/imageio.h create mode 100755 rtengine/imagesource.h create mode 100755 rtengine/improccoordinator.cc create mode 100755 rtengine/improccoordinator.h create mode 100755 rtengine/improcfun.cc create mode 100755 rtengine/improcfun.h create mode 100755 rtengine/init.cc create mode 100755 rtengine/iptcpairs.h create mode 100755 rtengine/jdatasrc.c create mode 100755 rtengine/loadinitial.cc create mode 100755 rtengine/median.h create mode 100755 rtengine/minmax.h create mode 100755 rtengine/myfile.cc create mode 100755 rtengine/myfile.h create mode 100755 rtengine/mytime.h create mode 100755 rtengine/pparamsmap.cc create mode 100755 rtengine/processingjob.cc create mode 100755 rtengine/processingjob.h create mode 100755 rtengine/procevents.h create mode 100755 rtengine/procparams.cc create mode 100755 rtengine/procparams.h create mode 100755 rtengine/rawimagesource.cc create mode 100755 rtengine/rawimagesource.h create mode 100755 rtengine/rawmetadatalocation.h create mode 100755 rtengine/refreshmap.cc create mode 100755 rtengine/refreshmap.h create mode 100755 rtengine/rtcmd create mode 100755 rtengine/rtengine.h create mode 100755 rtengine/rtetest.cc create mode 100755 rtengine/rtthumbnail.cc create mode 100755 rtengine/rtthumbnail.h create mode 100755 rtengine/settings.h create mode 100755 rtengine/shmap.cc create mode 100755 rtengine/shmap.h create mode 100755 rtengine/simpleprocess.cc create mode 100755 rtengine/sizes.txt create mode 100755 rtengine/stdimagesource.cc create mode 100755 rtengine/stdimagesource.h create mode 100755 rtengine/updater.cc create mode 100755 rtengine/updater.h create mode 100755 rtengine/utils.cc create mode 100755 rtengine/utils.h create mode 100755 rtexif/CMakeLists.txt create mode 100755 rtexif/canonattribs.cc create mode 100755 rtexif/fujiattribs.cc create mode 100755 rtexif/nikonattribs.cc create mode 100755 rtexif/olympusattribs.cc create mode 100755 rtexif/pentaxattribs.cc create mode 100755 rtexif/rtexif.cc create mode 100755 rtexif/rtexif.h create mode 100755 rtexif/sonyminoltaattribs.cc create mode 100755 rtexif/stdattribs.cc create mode 100755 rtgui/CMakeCache.txt create mode 100755 rtgui/CMakeLists.txt create mode 100755 rtgui/RT.ico create mode 100755 rtgui/adjuster.cc create mode 100755 rtgui/adjuster.h create mode 100755 rtgui/batchqueue.cc create mode 100755 rtgui/batchqueue.h create mode 100755 rtgui/batchqueuebuttonset create mode 100755 rtgui/batchqueuebuttonset.cc create mode 100755 rtgui/batchqueuebuttonset.h create mode 100755 rtgui/batchqueueentry.cc create mode 100755 rtgui/batchqueueentry.h create mode 100755 rtgui/batchqueuepanel.cc create mode 100755 rtgui/batchqueuepanel.h create mode 100755 rtgui/batchtoolpanelcoord.cc create mode 100755 rtgui/batchtoolpanelcoord.h create mode 100755 rtgui/bqentryupdater.cc create mode 100755 rtgui/bqentryupdater.h create mode 100755 rtgui/browserfilter.cc create mode 100755 rtgui/browserfilter.h create mode 100755 rtgui/cacheimagedata.cc create mode 100755 rtgui/cacheimagedata.h create mode 100755 rtgui/cachemanager.cc create mode 100755 rtgui/cachemanager.h create mode 100755 rtgui/cacorrection.cc create mode 100755 rtgui/cacorrection.h create mode 100755 rtgui/chmixer.cc create mode 100755 rtgui/chmixer.h create mode 100755 rtgui/clipboard.cc create mode 100755 rtgui/clipboard.h create mode 100755 rtgui/coarsepanel.cc create mode 100755 rtgui/coarsepanel.h create mode 100755 rtgui/colorboost.cc create mode 100755 rtgui/colorboost.h create mode 100755 rtgui/colordenoise.cc create mode 100755 rtgui/colordenoise.h create mode 100755 rtgui/colorshift.cc create mode 100755 rtgui/colorshift.h create mode 100755 rtgui/createicon.cc create mode 100755 rtgui/crop.cc create mode 100755 rtgui/crop.h create mode 100755 rtgui/cropguilistener.h create mode 100755 rtgui/crophandler.cc create mode 100755 rtgui/crophandler.h create mode 100755 rtgui/cropwindow.cc create mode 100755 rtgui/cropwindow.h create mode 100755 rtgui/cursormanager.cc create mode 100755 rtgui/cursormanager.h create mode 100755 rtgui/curveeditor.cc create mode 100755 rtgui/curveeditor.h create mode 100755 rtgui/dirbrowser.cc create mode 100755 rtgui/dirbrowser.h create mode 100755 rtgui/dirbrowserremoteinterface.h create mode 100755 rtgui/dirselectionlistener.h create mode 100755 rtgui/distortion.cc create mode 100755 rtgui/distortion.h create mode 100755 rtgui/editedstate.h create mode 100755 rtgui/editenums.h create mode 100755 rtgui/editorpanel.cc create mode 100755 rtgui/editorpanel.h create mode 100755 rtgui/exiffiltersettings.cc create mode 100755 rtgui/exiffiltersettings.h create mode 100755 rtgui/exifpanel.cc create mode 100755 rtgui/exifpanel.h create mode 100755 rtgui/favoritbrowser.cc create mode 100755 rtgui/favoritbrowser.h create mode 100755 rtgui/filebrowser.cc create mode 100755 rtgui/filebrowser.h create mode 100755 rtgui/filebrowserentry.cc create mode 100755 rtgui/filebrowserentry.h create mode 100755 rtgui/filecatalog.cc create mode 100755 rtgui/filecatalog.h create mode 100755 rtgui/filepanel.cc create mode 100755 rtgui/filepanel.h create mode 100755 rtgui/fileselectionchangelistener.h create mode 100755 rtgui/fileselectionlistener.h create mode 100755 rtgui/filethumbnailbuttonset.cc create mode 100755 rtgui/filethumbnailbuttonset.h create mode 100755 rtgui/filterpanel.cc create mode 100755 rtgui/filterpanel.h create mode 100755 rtgui/guiutils.cc create mode 100755 rtgui/guiutils.h create mode 100755 rtgui/histogrampanel.cc create mode 100755 rtgui/histogrampanel.h create mode 100755 rtgui/history.cc create mode 100755 rtgui/history.h create mode 100755 rtgui/hlrec.cc create mode 100755 rtgui/hlrec.h create mode 100755 rtgui/iccfromwindows.txt create mode 100755 rtgui/icmpanel.cc create mode 100755 rtgui/icmpanel.h create mode 100755 rtgui/ilabel.cc create mode 100755 rtgui/ilabel.h create mode 100755 rtgui/imagearea.cc create mode 100755 rtgui/imagearea.h create mode 100755 rtgui/imageareapanel.cc create mode 100755 rtgui/imageareapanel.h create mode 100755 rtgui/imageareatoollistener.h create mode 100755 rtgui/indclippedpanel.cc create mode 100755 rtgui/indclippedpanel.h create mode 100755 rtgui/iptcpanel.cc create mode 100755 rtgui/iptcpanel.h create mode 100755 rtgui/lcurve.cc create mode 100755 rtgui/lcurve.h create mode 100755 rtgui/lumadenoise.cc create mode 100755 rtgui/lumadenoise.h create mode 100755 rtgui/lwbutton.cc create mode 100755 rtgui/lwbutton.h create mode 100755 rtgui/lwbuttonset.cc create mode 100755 rtgui/lwbuttonset.h create mode 100755 rtgui/main.cc create mode 100755 rtgui/mountselectionlistener.h create mode 100755 rtgui/multilangmgr.cc create mode 100755 rtgui/multilangmgr.h create mode 100755 rtgui/mycurve.cc create mode 100755 rtgui/mycurve.h create mode 100755 rtgui/myicon.o create mode 100755 rtgui/myicon.rc create mode 100755 rtgui/navigator.cc create mode 100755 rtgui/navigator.h create mode 100755 rtgui/options.cc create mode 100755 rtgui/options.h create mode 100755 rtgui/paramsedited.cc create mode 100755 rtgui/paramsedited.h create mode 100755 rtgui/partialpastedlg.cc create mode 100755 rtgui/partialpastedlg.h create mode 100755 rtgui/placesbrowser.cc create mode 100755 rtgui/placesbrowser.h create mode 100755 rtgui/pointermotionlistener.h create mode 100755 rtgui/pparamschangelistener.h create mode 100755 rtgui/preferences.cc create mode 100755 rtgui/preferences.h create mode 100755 rtgui/previewhandler.cc create mode 100755 rtgui/previewhandler.h create mode 100755 rtgui/previewwindow.cc create mode 100755 rtgui/previewwindow.h create mode 100755 rtgui/procparamchangers.h create mode 100755 rtgui/procthread.h create mode 100755 rtgui/profilechangelistener.h create mode 100755 rtgui/profilepanel.cc create mode 100755 rtgui/profilepanel.h create mode 100755 rtgui/profilestore.cc create mode 100755 rtgui/profilestore.h create mode 100755 rtgui/progressdialog.cc create mode 100755 rtgui/progressdialog.h create mode 100755 rtgui/quickzoomlistener.h create mode 100755 rtgui/recentbrowser.cc create mode 100755 rtgui/recentbrowser.cc.old create mode 100755 rtgui/recentbrowser.h create mode 100755 rtgui/recentbrowser.h.old create mode 100755 rtgui/recentselectionlistener.h create mode 100755 rtgui/renamedlg.cc create mode 100755 rtgui/renamedlg.h create mode 100755 rtgui/resize.cc create mode 100755 rtgui/resize.h create mode 100755 rtgui/rotate.cc create mode 100755 rtgui/rotate.h create mode 100755 rtgui/rtwindow.cc create mode 100755 rtgui/rtwindow.h create mode 100755 rtgui/saveasdlg.cc create mode 100755 rtgui/saveasdlg.h create mode 100755 rtgui/saveformatpanel.cc create mode 100755 rtgui/saveformatpanel.h create mode 100755 rtgui/shadowshighlights.cc create mode 100755 rtgui/shadowshighlights.h create mode 100755 rtgui/sharpening.cc create mode 100755 rtgui/sharpening.h create mode 100755 rtgui/splash.cc create mode 100755 rtgui/splash.h create mode 100755 rtgui/thumbbrowserbase.cc create mode 100755 rtgui/thumbbrowserbase.h create mode 100755 rtgui/thumbbrowserbase_old.cc create mode 100755 rtgui/thumbbrowserbase_old.h create mode 100755 rtgui/thumbbrowserentry.cc create mode 100755 rtgui/thumbbrowserentrybase.cc create mode 100755 rtgui/thumbbrowserentrybase.h create mode 100755 rtgui/thumbimageupdater.cc create mode 100755 rtgui/thumbimageupdater.h create mode 100755 rtgui/thumbnail.cc create mode 100755 rtgui/thumbnail.h create mode 100755 rtgui/thumbnail_old.cc create mode 100755 rtgui/thumbnail_old.h create mode 100755 rtgui/thumbnailbrowser.h create mode 100755 rtgui/thumbnaillistener.h create mode 100755 rtgui/tonecurve.cc create mode 100755 rtgui/tonecurve.h create mode 100755 rtgui/toolbar.cc create mode 100755 rtgui/toolbar.h create mode 100755 rtgui/toolenum.h create mode 100755 rtgui/toolpanel.h create mode 100755 rtgui/toolpanelcoord.cc create mode 100755 rtgui/toolpanelcoord.h create mode 100755 rtgui/utils.cc create mode 100755 rtgui/utils.h create mode 100755 rtgui/vignetting.cc create mode 100755 rtgui/vignetting.h create mode 100755 rtgui/wbprovider.h create mode 100755 rtgui/whitebalance.cc create mode 100755 rtgui/whitebalance.h create mode 100755 rtgui/windirmonitor.cc create mode 100755 rtgui/windirmonitor.h create mode 100755 rtgui/zoompanel.cc create mode 100755 rtgui/zoompanel.h create mode 100755 rtinstaller.nsi create mode 100755 rtstart create mode 100755 tools/createicon.exe create mode 100755 tools/edited.png create mode 100755 tools/editedb.png create mode 100755 tools/editedw.png create mode 100755 tools/head.png create mode 100755 tools/headb.png create mode 100755 tools/headw.png create mode 100755 tools/horizontal.svg create mode 100755 tools/processing.png create mode 100755 tools/processingb.png create mode 100755 tools/processingw.png create mode 100755 tools/saved.png create mode 100755 tools/savedb.png create mode 100755 tools/savedw.png create mode 100755 tools/tail.png create mode 100755 tools/tailb.png create mode 100755 tools/tailw.png create mode 100755 tools/trash.png create mode 100755 tools/trashb.png create mode 100755 tools/trashw.png create mode 100755 tools/undelete.png create mode 100755 tools/undeleteb.png create mode 100755 tools/undeletew.png create mode 100755 tools/vertical.svg create mode 100755 winclude/cderror.h create mode 100755 winclude/cdjpeg.h create mode 100755 winclude/common.h create mode 100755 winclude/deflate.h create mode 100755 winclude/icc34.h create mode 100755 winclude/infblock.h create mode 100755 winclude/infcodes.h create mode 100755 winclude/inffast.h create mode 100755 winclude/inffixed.h create mode 100755 winclude/inftrees.h create mode 100755 winclude/infutil.h create mode 100755 winclude/jchuff.h create mode 100755 winclude/jconfig.h create mode 100755 winclude/jdatasrc.c create mode 100755 winclude/jdct.h create mode 100755 winclude/jdhuff.h create mode 100755 winclude/jerror.h create mode 100755 winclude/jinclude.h create mode 100755 winclude/jmemsys.h create mode 100755 winclude/jmorecfg.h create mode 100755 winclude/jpegint.h create mode 100755 winclude/jpeglib.h create mode 100755 winclude/jversion.h create mode 100755 winclude/lcms.h create mode 100755 winclude/libiptcdata/_stdint.h create mode 100755 winclude/libiptcdata/iptc-data.h create mode 100755 winclude/libiptcdata/iptc-dataset.h create mode 100755 winclude/libiptcdata/iptc-jpeg.h create mode 100755 winclude/libiptcdata/iptc-log.h create mode 100755 winclude/libiptcdata/iptc-mem.h create mode 100755 winclude/libiptcdata/iptc-tag.h create mode 100755 winclude/libiptcdata/iptc-utils.h create mode 100755 winclude/png.h create mode 100755 winclude/pngasmrd.h create mode 100755 winclude/pngconf.h create mode 100755 winclude/tiff.h create mode 100755 winclude/tiffconf.h create mode 100755 winclude/tiffio.h create mode 100755 winclude/tiffiop.h create mode 100755 winclude/tiffvers.h create mode 100755 winclude/transupp.h create mode 100755 winclude/trees.h create mode 100755 winclude/zconf.h create mode 100755 winclude/zlib.h create mode 100755 winclude/zutil.h diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100755 index 000000000..937aa517b --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,5 @@ + +add_subdirectory (rtexif) +add_subdirectory (rtengine) +add_subdirectory (rtgui) + diff --git a/authors b/authors new file mode 100755 index 000000000..6830e9047 --- /dev/null +++ b/authors @@ -0,0 +1,9 @@ +Gabor Horvath + +Contributors (ideas, mockups, testing, forum activity, etc.): + +Patrik Brunner +Maciek Dworak +David M. Gyurko +Arturs Jekabsons +Karl Loncarek diff --git a/clean b/clean new file mode 100755 index 000000000..51f1d2ab8 --- /dev/null +++ b/clean @@ -0,0 +1,17 @@ +rm CMakeCache.txt +rm install_manifest.txt +rm -R ./CMakeFiles +rm -R ./rtengine/CMakeFiles +rm -R ./rtexif/CMakeFiles +rm -R ./rtgui/CMakeFiles +rm ./cmake* +rm ./rtengine/cmake* +rm ./rtexif/cmake* +rm ./rtgui/cmake* +rm ./Makefile +rm ./rtengine/Makefile +rm ./rtexif/Makefile +rm ./rtgui/Makefile +rm ./rtengine/librtengine.so +rm ./rtgui/rth +rm ./rtexif/librtexif.a diff --git a/clean.bat b/clean.bat new file mode 100755 index 000000000..2d6d5d5e7 --- /dev/null +++ b/clean.bat @@ -0,0 +1,17 @@ +del CMakeCache.txt +del install_manifest.txt +del ./CMakeFiles +del ./rtengine/CMakeFiles +rm -R ./rtexif/CMakeFiles +rm -R ./rtgui/CMakeFiles +rm ./cmake* +rm ./rtengine/cmake* +rm ./rtexif/cmake* +rm ./rtgui/cmake* +rm ./Makefile +rm ./rtengine/Makefile +rm ./rtexif/Makefile +rm ./rtgui/Makefile +rm ./rtengine/librtengine.so +rm ./rtgui/rth +rm ./rtexif/librtexif.a diff --git a/compile b/compile new file mode 100755 index 000000000..aae0b9540 --- /dev/null +++ b/compile @@ -0,0 +1,35 @@ + +Windows +------- + +Requirements: +- MinGW + MSYS +- CMake +- GTK and GTKMM development environments + +Compile: +- Start MSYS +- Enter the root directory of the RawTherapee source tree +- Type: cmake -G "MSYS Makefiles" . +- Type: make install +- You find the compiled program in the release directory + +Linux +----- + +Requirements: +- CMake +- GTK and GTKMM development packages +- libtiff, libpng, libjpeg, lcms, libiptcdata development packages +- ...did I forget something? + +Compile: +- Enter the root directory of the RawTherapee source tree +- Type: cmake . +- Type: make install +- You find the compiled program in the release directory (you can copy it +anywhere you want) + +...If you have problems with the compilation, identified the reason and fixed +the bug, please send me the updated build scripts (CMakeLists.txt files) to: +hgabor@rawtherapee.com diff --git a/copying b/copying new file mode 100755 index 000000000..94a9ed024 --- /dev/null +++ b/copying @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/header b/header new file mode 100755 index 000000000..c887c8cb5 --- /dev/null +++ b/header @@ -0,0 +1,18 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ diff --git a/lib/libiptcdata.a b/lib/libiptcdata.a new file mode 100755 index 0000000000000000000000000000000000000000..311687c60295a6b778c5f8bf02db3220e6eb9a08 GIT binary patch literal 98862 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

MbmA2&D_0xl1ZlP&f}bt;6U>frf?3lr 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⁢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 BR;vI2 literal 0 HcmV?d00001 diff --git a/lib/libjpeg.a b/lib/libjpeg.a new file mode 100755 index 0000000000000000000000000000000000000000..27431b9387ee953690500076e4d264d425d397c0 GIT binary patch literal 145886 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%0DXzh+$xA-E* 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 literal 0 HcmV?d00001 diff --git a/lib/liblcms.a b/lib/liblcms.a new file mode 100755 index 0000000000000000000000000000000000000000..2d44b534d5de8305aa594df5e157f7ffc915ced4 GIT binary patch literal 1145390 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%0A-{bqXvhlP*x`xmJ56out7-(JtA6N?_+x_70 zCD%bD8aQwQh+y=dc0>)(tGZqIHXJmz+UBG!x9UHG>%`^8;X9zHy{E4wTE z#k~(BA}9|q!OsTI&O`Lavp?UrYwynNg?ZUI5(jl%1$!JpyB^FnwG8SFc-_x0?J8_C?@ zn_%jz8x2=q-AJ~OP4#ESLk87X=K)W+noWlsFTQ$wd09WjHSq@e8$*K+;YPpm{>nG| z&wZo!p4$)rLNEZ11|LQ?8%fD-=oj|3frrPz;^Sb7JOHG=erVsXvjc-W2e0oJw*CO= z-gwJ)3Dx|x-ZqJ3DAl}P>b&p3zL${XtGE1$#pPX{O?~YU7`|SMM=id72*pgeF8erq zp^ao*>+zLCmc_iU`}}R&_fu2UzUO?to`Z~TyhXT%IKIX_uZFyt@xI@Pa9+$#{z`U( zus(PhvIi5w)V>4Ri@$Q{;Atp@$p=4nT{d-H9_mX0Aux5_c>JJ%@Z*H*=5E}1<*%;V ze(``ErWb8#0hU2ix*K{!-*H#HPM>Px4acLe9Ev~DpLYwS9`uTIdbjpJ$h_&N?SA== zzJ9hr|AQWF!e8IA*UoeLkui8%W zNVk!(z%qQ`1Bb;s=8$>+-4qV9#CM=6;sY9e)1ob$F?jM_G(LW~Z`KlyuD!e04>(V3 zkmh++`*w`%i=|g7R3+$@a|08_I z50^bNvHxp8w$y`B=*ETzA3%<(Ds(I9eeAS8=3sW~&=DN0W%NPpTW(_HTdu`lX~67* zKLmtTpLpL!qU=VAu#pk6kEEKJLxT^a zxIp#ms_mi=ujOh}<(p2M9@>kzydN)TVl(w{G(6HXB+saO-yO&NcR+^mCm@1%AL@H&@3y|R zd3~$%>{JC4UCeebKh*o&vPa;LiTkKUViuO~QN|J&6^16~1F{)vmrpyU^a4n7u>+jw_2z-1q_znzFxY zKYhvms$o&053^a4pbjc^w@@d6x}$14iih8b%qBt8A)B&A+lNk^*nc(2=jQd#I^1`B zZ`EUv*tuxWJyqLbR)4}Y(lz!EKD+PnJynnG``f;)SDZ3bVJ2DVm8*}Xd}fvX@``tI z&~%;kk3*?nyoTBgrJj5(yLIoBU+~Y9eT%m5dvWjM`+f$81#b9Lv&y#hF4}$>`rjb> z1Saac@s)=PbLv;}0_R7&Y!5Sfv89805zZ1N>cxnPc;WcR`G5XU)p&H+p(;-AIM>f4 z%sjvIT{Iv=gQ&I9!)1?TcjDLJukCMPbLYNiF`DzgW!dLtAt3CZ(q2=s!hjin3A^C6 ze`IUzN2h4(yV5Q+SbJ49VGGxo<2%9maq$7R58VF=sO_Yoyk}@O=AxPQ9&r;YXN^eq z@|XG+?Z-s&B{PwHA=~=Go@LKvTVLv{dJgvf!iy`*UcT&`eO3F{Z=Y(E>26tOLVsTW z+-WczbTXDrg5iJ#p|e1>nke)A7cl#_ls9nwF~{289hg~Q@j}GA3febx#AZtSQ6yu- z>`%Qa8kT)tsxV>8@Zmp|GXM!D?Z4)Ew$}?RVizD6LALWdIYnaUNo>}9|AXkMAoo79 z|C@|3$Wsa0QKUcjhdxp6XLH@8YqqYL+=B+Mw6p(t&CfG zGVr1JtIjQQ4rz{CwDDECq6Z)~-z^dsYRg%N4>P!H3KddPI933Jza6 zr(Zm4bufGH+550{Gkc%uz55n=$!trroYXr({m$>aNaHBpQtub(FI=&#_nr;-#x!~( zzm0evIF)s`{u6smuK&c(hUNTANtXjkf9)JI(@qA^`5aqjQr-#s!V&E6@A#Kmgr&HI#i zQr(BulX?hc8Ba?6pR2Zu{=6WH<-GHwpw`Ap{rGkyaf`w^(J7tys|O$O7ucCUZkNyF zI{pNpM)@5Cr5>&X{+OXJ#CMOumwEV09{#C^=_mByA3rltSdSoBeh=^U@R87U8>iUA z%RSud;ct5QArC*};p4D!;qvtGVh?}X!#8;NE)R2Lz1r}f_3%k~A^j7;J;DD-tWLpI zBI0WVuMo_@TTMPUgKqO2lsHpONEqkOLRa#CVhOb;xKV!GFZdkE^S^;@KF5y>@e<&k z;LD@(Y!~|RLSHX9U+~R>KP>qBf=?H`O>kWBlY(`}>VV*n3;hkj6@n*WjkhN_TksUY z=L#+rOf3q6^8_yv+$i{B!IufH6MUoKwBS1guM)gXaGT();EZ7Yv9k5?pAg5&r*u4d z>lV4S3tlbw+k&qXyh|{3VulNRKa@% z7YhE1;Dq4G*y-;Hl7b5a7YUvxxL9zrV3px#1k;*9-h#^nKP*_S+Eaqh6#5H-%LR|e zS%RLRLNNc>Ha$t`THjK^8s!*FU3wG--|_G{{}$3;_wc{JE2J}-&ELl}-_1B&1w?=G z@FxY!lsLG|!(SFWAo0KB;YS5;6?#_iHo<=s{D|PAC$p^Wf=?05b%P+N0KQtNK~O97 zugI@U1>Y?Avx2`W_zuCh2;M80BW)1;Met_9@5b?up5PmTrwi8FFBh!kUMBb*!o$}E zA0>F3U`ZPM_WjJ~OrakEb?;Gf@DxGN`fWmgU9i%>4At)mz9;kt1S|ao!7_gdCPPJflpM4R-X`(CL~!L9jPo(UeS&8T{<+|4 z!IP#j&Pu_TOegLU{KW!dj`%?^9m7vg@O{C56g(jKGcXf9!J~rzNAOdE^An`+6WlBK ze+9>qq#qC*7yKu|pBDUv;5!88VU!PolZqJsD8WsFPY}Fa@X3NF!u0e6rwLvnc$(mE z2~GLd`0j%f^QZ4Wx@9f zeopWM8V4q|C-{ZncbrB1tl$>GuL=IS;5P+R*0=HxJ|~tl{%q0Pdj!`C?yn$S{iyUT z;`@Z&BY2D8TLj-5Wj+%s8AoxE;75dhyWpP+-X-|wg5RHF{QnkQF8E2omkAye{1w6U zFoWPp!OseQMerX4pH;n+cenar>O0Q;o#nE}hS)tDq{H)*x53d*elF;uG z{HEZ2g1>nLc{u4j=5vSO6@q^x_)~)S2>ywO_X>VS=pUHRw2IFX{LXRAvqdlw&S))Q zoMVN4zK2%});QlipK(4Sadvq4kAgMM)>_87U-MrS;?E1#IA<&+{ewsH*E|oe6+B1i z-xGYU;HL%CqsB?T3z>F-;H2PM!F7TeBM5%-3C8(`(6b(9*sc77Pppn{(4p};19(a> zTks6v@}LTm`SsI`@{Fq|!b%;MDXb3v+``f^qgB6~v8cb}~ zt4U-_LJILixixsQYVzc>GEgs`@mB?Bn4D5Lnfq~vTLY-6d`J)LehDOD>8$}&Ft|tR z)hIj+2wtIv31I^oRsIg+FH}lCtRwM%NgXc@b_4&f)Um^>KQ`NaqJ76>Rd#`kb8GX2ewR`QSv8A{BfgfNL0Bww&dD*73~x&ceUzK%Wxa91Nh` zuK{lkzT%a8Gh*l`6@1;(+s(lVj(%HkvctCqA9DCMGqWT=w|e?;TL2eRKB?ea=KL(< z{6|pc=(h!x!2h|NJbyKa0^cL}7N8*5D)=i-<^v>}&oI6*T*-%ZB;K{0b^Km12^l>L zycwt0Y3p7Te5cnpzXz&*Qiwmn;k&)Me@{-fGbk0@Ehpa<-{aZ3`$XnS-(qIHjDMe3 z-z~vejDSxn_=#uh9(4SZj$u+hso?$q!;ir~fz`BltJg2Kp;v`;tF5VEThQm|+XIy% z%YD#|8L41LaEFWYSa2tBw4U<+zUa)+z&*iT!R=V!e4oLqfKL2!F&l-Vluht01*?A3DfYZ%|RdU%V$Y+vF}Bkh#n_ULZ3?@hp) zgKtOKzPB38cKn{flY#k3A-*Ew??%Hub$j$^6F~aEIsCn7zQcD#PjUDM(a^sAD2i!} ze4raqxZnog8x8H=ccbN?{sjD#2j7XtfFBY3?I;=gxxpMyvj!gn%+G-Q4T9ea{d-ZX zpQPuTuwi_cd$`(Q%8K|;NINB16U|4#N3Wo)R*S3{Ed@Hi`5_KvvNjspv~|(L)3Yasy}lNSU`i&RRB%M3+~IMNaNIm15{@t9B5=jzlM0TEv^X4z*wHT)935Hh z=o2DqftR6P<-x0>+fBed!C$10bP0YfxDEZHN8y1jkxdSt9{IAvr$)Zw@ad7SJN%uPe+ zBDXm_GjhMf-I0eKUK`ov@EMU`I$Rjh)g$s#8PQog@!E*a+KE3M(N!Yijgccv$HN>X zamAUeYwLoM$!)78d(SYjt2JK z<022hR=gLuJa}J(_CMdlQw?T+EHjwnLZ#sMN5%nH17q(X@)+{T2>rd080h>A$Y1?4 zjIXbmfGGxFjrdc7t&!z0`Zob@hDS)dal65x9oTBLfpy##u|HBsOCI-AXaYFlMwVC|vi-dEQUq((ue11|W>tuz%Peo2~_?MAW9ey%GUz#7rKSLq#U}U<( zPel?AXFc1vFB1BDPe#smarQ;darnu|Jcpl-gmd1fys>G}vyD$i>b>|Y9eyfuiNk}D zjKkT;ryYJea)rZtA{!hYihRc5Y~)&ppN{l7yeD#_!%s)P=J1}#e>l81@?D4bMDB8U zZ^Zg5M~8_y;WN1k`|XCsr1BBp}j$Z-xo8~LEa!;w=R zem3$^hleB69ey@a>hN%c``-Mdf?r1}9DX*UJHtvp&(VJqxxnFlkxL!^UF1rKf9u)j z-$iuClKK2TvdP8yUF3@n|331x!}}w{4*x##JBRm2j&?TiK;$%s{}B0z!}}w;y3exy z5Gi%^gON^$pNm}Y@beMt9jAgnM!2dv8GWie_?7hc4;W0@oa)izz}Q2N@Ic87gL$O6 z(qJBEsRk}b|7B5&4W?g_HaNyi@fnc6`eztlx@xQTfw&FvVXvYca7?cUhP@I$_9lZp zd&Q#UlL~$s4Q;{>@nac~3U)GzUlB#bdqb+J<<0&{Ojn64i869aroEKk2w7EXsE-FML*`~ zzmA^o@XlzcpTCYS1^wHQRZp-j%J#a;V7Awf4Q6|711=99k-5pw3}zc;1rOxRL0Faj zLVqHMzL^2|4C9}b1Mw#eZ&M6@6=|mge~IkIfN@NkZTe>!N8V>}*rtCmDcN?1B4L}p z8Hpn=eo~memM8>1B3kM2xabmxkBo-?{5zuIy!hzoH(Z={n+RN;M35)J;7^YH{u3U4`&!mJ*)&S5B@4XK()ct!wU^2 zJ1Y$y2izt2&u;!Q02)8*h5n%&{j@R}MmX!+KSmr|cgC@GC$_#Wb(r|eNINAcjPi`b z4}muaaj{F=4WDGw5&8-E7w0Ukb#hfJCj4+2jRoQ&=Ueh+YYkc`q-Kha>e#p!~J zr0og?$7L-gWw5nl1BOR_4db7+=hP+Q3lM)wuq3*CVi0ryZw@Z-+I@+qGfO?)SmJaW z`z%o;l}{?TP}=lU!ovk(&l$k7PQ||sQr3#-CM5WVlvVGQwZbba?Ul8{)4g=`easM_ z6wU+W3nFgv^r|`fVMlN0wzPawL5HV5ozc)A&P1zSoJ*qN`bEEUmE*{!;P`q9KJO6AHc_~r2bzV<671Uf|td(4tyGLdGLuC z1r!%tC$c)r!}A1R7&{ViE;4wW$$!9n^J^IY?jXR2ZAAP@#Geve6}<~>v=MkS&X$CB z?zD`e zw}j74(HFqyW5VYR!sinPQP@@)H8q6tU8+3TCPczyG0(Q{p#FGa&Oy>CP>aP(WFp&ouS z`WevwfV!6lpOe1%vfvxU{=8u@mF69*80UsjGJlWIZ*q2K0C5ZOkDp=uvpf*@;U7P2 z7vd9f&?m-rfxbcTq!|5yO$O5k z_^QGCfp0gMe!|_r<-xzjs8!4t%m?l<_Y?4(_Dpq>-Ig!of} zKSXy!DLFW7#u>Ts2s_4L^6)-`j{`o%;Cx_yuqMFj%7@r?fK>3jxBvC0XgIFD8V%=J zFGh=8+E=3$4!;Ey^m3s9s({8=88V- zFqr!Aq~O^yo-+9W|CrA(zHc&^btL{B;!g>(!EV&?4dBheQ?eg-42;TV%*I*A4;oB8 z;U|Uo_Jj3OZ*MN^?TPP`H^FKAXHbTIu>KY#9Dc^z?;iH{_kR?}#o-Z22=79br z$|?`ul)nFr;MZMQ118-8p-0^~NP4~r8^$;D;b$2C*njz9-HBgD+9|=h*bAuG#7kKB zwbIv4FgWaM+!4`F3h_goyfOwAmQO0UIyTkeYhtAiUmKh6aIZI3_IcxAf9ysV=d-a} z9qy0a>2P1{Zihb?`?13}#vXF`bFs%AzA?7j;hSPlI{f*VY6|6lV=P?v`*Q467w4wf z-yHsO>F^z~dmX+rw$mKXAH>QXzBV?`;q|c#9sWVA z-QlmsdVr@wA9{jM#keL}WH8r)K5j7Ag60612cH%jxWHhtvrOWAI>v_;n}xns>?h?m zz(4q`6Z-8rI&9@IjBwU*{TOj3qXsX8Nj? z^?3K^^qThW&W3bmdTVp0VLD&)c}9F%ym)%1vthcQY-K}3VO>LeYX{yP-Z(A5n-uYu zYQ8k|Onu+z%ro#B*Al$AycjnRI9M_>XjoO>DN*s7XGSeNeP+Q-T;DP?XlZX-nQt?~ zn@ky+IQ=a%>Tct$+37}?1g|w^k|Z+pKlqg>aUWC6sKj{hD-##}BZ+eu#rv?!GkhB@ zQWqn2+%MbVnFWpm9~f>V!%-~Z4cji~l2Lrc{d^pr8Dv)B1+GpecsX}D?xhy)N+C=F}}2<%QB1$#c*-s z%(M`<*91*1?RdMlD2`DFge4IgG`4s10!#@qx`3ck28p!%aMSPz$8{cvK(%a1uXRGe zJC|{v5#CIXm%&p-^+n>%xZ>Dexgsw%4ikE8p?Mc3v|O95Uo_eX!4R-l>?r=w2#AC$ zfe~qSdvl}KiZ4e8H+GqJgdFEMLUg=;~6M2 zm^N*Cb6Z18cVk*Q>arHl~}9nD?jDu?~DoKI@3;co!!v*erBQl zGd1u^uJ2rllI!YLwskjnQsgDW%owr^_{P=lCfuxq8yw^f^K~6vcpow@JFs$Ay{K#8 zg=(TF`nK)56?mPtM&yNZcm;MHZ@VyY^sUo%O>&2Vq%tp*uVa;2qUL4p#6VLwK|q$M zuhg#VYVBxhlgr@9j(v&z%wYChxn&aSiE5DVpsAxhBQnE1Oj0#oOZl(1`nt^Yu5}&h z%)i?55NKm_QrcCbSxzCj)EfCaS%5>(M+#AJqSs( zbBM=|+KN|jn~1#l4H<&!6Il<`5|yrlxy0r3Hnvs<^jxx52yZnLcE9q}My>+toG+Z_#wuRlvNI@#+b#AR4 z43@s3AN7S%0YjkRx&sIf6q*qF6zMM9b?S&P7Q(prT^QhC%kT<)sqNd|7yQpvb(B>N z2cl&j4X!}rKWUT4%IKdS(#Oh#u0dNDxWV62Z81B(^Fn}bpG+$V znL|xLjThV4Y6D?{895~DI0i!sYNF6aRttzM7&#=<1d6o>)tI_?g605J3?GaflGOsj zz=K-XlCIB$oEtlDI3E!x7T;As14DjMFP3KNF)CCmuhr4OkbCrPk&H4rDpVzbq0I3c z*2N47rjDA_3st$8sy6vGHKPOEND8MeH%ujDT1vvada8_UJ((~Jq<0D-m})XCtR*iT zMVM(j$<+%~`It&FVOR^ffYi04B=iDRI$A||8dg!{&QVvIAK>dsYyDc6AV*vL0H-f? z^wD&r$F(zB9l8@u&25d1xFZ-@!9a=Yn8AHDdeIsCzg)(N-Y+gsgItC+gARcm)P!E& zfC)Bk=MlOwRdkWo=yh8{R%=BraKQ;#kTC%{>qx@OaKc+WFm(mt?@W9#`zS2Jjbb#b zykmC$=;WadGu%#ge96h*~IEoazN3k=6+p zi)-cxn>BxawX&kNSXim4U8pqjM+1c{7SG4EhQhP*$5DtY3tW5Py>w?+oQIo=H3s=a z<=})dq;BB_)$=RQt*g~QHzs>t3htv!Bfgyg**Cp@4Tnj30(<4ad}Cs(i-kF9}kDX1o1Bv)VOa>Dz=U6e)f;<2JoD#!(m zlh5%7`9c(FDXpTmeO3W3lbnG&%oC+pg~N?(E+C#0P!t9f<^&XLz^s<;wA?X=o8=|E zI9XO!R8k0sTykW1?ZQeMR9u!QEQ*_;+V%?N0=GmJm6ny@CNE8c0Oi647%pZZK)J91 zhKtI2%sD&jyPDhEQn*sG76YV~SX`1QEQ{loHp#dWi!8O6I;EA>vZBJGWFnC;xmUJ# ztiz3Xt4uwLOB1-I8#mHv($2=YZB6Ya*V1G%j(fs1Nbhr-*R(Q~&NOI*(qt(rYNcu- zU^$>AH%dVXu0oUS<>EIVtf-_ckubuq?#863zO6y!giLXFb3w993!Mk=7wXuWHf>s(z}3bD#f2p{ zxUso@R!e=uC33m4RvA|d6_h4$Ri3at;)Yd5!HuL8S~0G(lPKq539C`qmkdgaa1U}p z0@wVF2-OB>Z~+>uP=n3gda6F9rNu=_hUbK-2H7xEZIjOAY0|ko+qp2uChBaKIl9&i zBE{vMB}VGzCdQidrQK4sHp?Jeyq*J)@Goa1=0?W>C# zI%lnvfa0QpQdY?bVsUdCYr(itx2-WOwzMQ!P=s5ywOB7oGi^df3!u~xky4vizqYEa zyOs1a;!|hB2m_9^!!qQG-E<}t!-Ja86t2$fs&A=;5_i_mz@4f72dy2U9DT3IK~rj|4=30$3aG0J!acoOlH{kd(IoRh{~p_qY5`r^`}(t@PzH?^zM zxaPFwg8H>CMp;p!th9hvE{cLxG5^l?j#cel?JGO$J61I}xTqxsacF&!RUH#G(*@h< zM=C5RF2W^=nqO*Nx&|98*aM+3T~=TVzK*jt3;g1EO{I%i7B4G<;V&~vPT|Nkx+j<|Y+MG3@={;zlk;3i0-BaA;B}@FQW1v0{uGtM5ZE5c3Rk9P zpk)(9Me&5QKcvsahEW>VyV(}Rrdv^|VHWq9ujXhUFG0FwS)#yXsFyWYH+QYlW&@k0 z;IR}+YxJt7x#bdACv-YUCs7RXyP(-v<8#TNN{Ny(UVt2`y6bID;~izB;?vQg!+`Yz z>pQ@|QN@=#*K4_A8HXt^PR5~nMolo+H36kbn8HM<;o1$!nyM7-T~JbN0_DzoO@?76 znJ6eLHsU}?X>Nc~Ab)t0EJut_-pHcCxkJlX7F^@yn()x|s_5h>EO8)p?9RfDXq`g? zXF|pNS&2Bgy0kE!U`EsOMotqz(}yv}WXb@46q2lAVfEs0r27 zxi*yEcf2?^Wocn)+@%!%c2sz=?Was%oE#Zmmb5hx?|x)(iRvSSGTJ_?^gIKNSWA{( zsN!J{hQ?TT3Un{)5rJXb7i!`WjzgvK<5VgTs&(Y-h`@kwNMIhW6^(mt-Ff)urgs#= zv)A4M-k|Lm5Js?t`)`#FAt#Fp(B7&8)!nNt9oy{132Wq+R<5Y*G&z;Qa+Jce(-ceB zu2Xsu+@<1@B5REnt~4biFjinVk-iVsVQfqS_+CXNiGsMXLT6`e(eXqQ{<qW$U_2GywE?5+15?KM>&4G5JFCOR=6(YOFz#7s5_h2*aqk6^9{Z@F3wtz;=o4F7ZN8K5CyZ9F%$?$wXNqS(G%x zbD0-{t{%rl$A*J=K^TOIQ?d+0h;_B&aW5>6L};1?V`fs zc-*#h+!IDTUR;Q(!9Z%w;+{BA8fFDWMJ248QDbQkqsEnN2DyuVgeJ?Qy3Q$R_1!Evkjw%jYct&;GNet1cP%j9K9-5 z;I`NLhAtCY%!v#tY|@1_FyT-D%oaKI@>etO049&{E$eH>ul7nBOBSVBA*R z-0Ui#ZY%D2?@SlWpqdE8>7yAOQjx#>wsy}OUzIM)5{1SqC=9&)Nl zbai9@leJrzhG^hmi{4-@psTaFK^UmvGK+YzQaH4(y`{S=H=Z{=z$nMYF!CNTlhV;3 zVHRt^h~vrhp^kRFuiY0*jU^iAIF)Xy?`}bRgKHPIu)VvjQ5bZjRC7IcA{%Fj$+dY@ zwX`&M;IxS-k0qjyrDuq5Whph6cB9>Ah@x6rC6qNYgCl`aE|z2~>Pj_Lv@1zrk4Tsv z(bYJAMJA_yLV>}E*RE+#rB}jLh32zzCZIT3n{KlKMgcU;mEKj~)>z-koYS4F?ebv4 zXf;Z9a#pRL+tQ+I8C^ajAvI-`&!ZF1YXbG+m$+cgFK zXqr*^V8tEF$i>1BdRA^erp`%J&(8<79FNzSS zdzgd*8kLVx`XW@&&j-KdL!mUTE$}1H;YkK zKR48PbZ(*ra^#`8A!XKT{q_1{qu|A&;DvhD0u5@l2WGHqmFPSuSe=DJ$sr4kg7Y09 z@NfsVOqGNcMUb%C2}AFQ*y{rkCq-aX9T5w3AW~>><9(h=j8c_Qsp5r8Bx|g}t6Y}4 zpL)9FLiby@YfXlp_)CoVODO($*lkM2l0OPZIc3V2%)V9XB}VEclsf#`Zk|L$m2Go5 zRZGGSs9eYiWL|GFFnz9seNHqJqdiV4j+qCTKptuZWXf*xFj`qktxT3Sw{>)PVU-nXEV(y@* zfYSvy3uP#}6`qcVsm!^ZbUaLEPVJ=QVLEeWCtVmOG$(e_g<(Roznd-$6LPx`>MS*{ zGEE@7iZW^4eL8$nC|Pdfz{@j=$2AX?Y^kx(rL@q=)#*0)zoYtEP7hX9hoiK*xdHAe+-2=15P|A^M`yaJ z83*}Lv(j8Uo502*sOUiG3sBgZneHYpDg=R@UXVk%LI}m!xY5qdg{PXX&h7>t%4Y7y z9+%P{7bbCT793%-ONz!;r3%%Mxy9uIv<`Ysz}a35ai{>sxGuN)s0k=TtcpN}IgC-_ z%GemocFJLyvCd_*&Tnf7MS)CqBNo|AR>m-w(J;SlR=z!Si-0L-Tg#w?lwKK{9u~f- zQ@4w7ybwe;a@4o2#A6GVr1HvG7hUKH*Wk3>t{}s$aV^T|S`-%O!Z1{Ov}(a3x20R0 z3Ta7B&ShiyBB%jd%8WadmMPR&d`uo$HJ1rIP^f}&6S;Te4OQ_1W6a_Ov}R)nwxJuY zzSKB(w2~!EEf`BXDpPEwy=BQGR~Btj(*v;*K~a^C=)i7>#jaD!T+QQ7ZiY2wNE8B=JrginT2pdqd`0Rl6IxH`k%F2P3(oD1IaN^pblXRwK zcBF$P7MyZit%S7z+R#*;aM@n-wthR4PLzy>L=O$y1g?hZwbp}>wN;ao zQT4byIWuNXPDx78%eDKPjC8A>Ypy0UqtaN@VnY>-!4@)8O@XKAX{b0QK3m3aVapjg z6^&Ivcp%aYC8#m2YAFwTH#cw$_A=t)u69w{m!iTkSh5*m%$AIbc%l~*K5rX6tRfbc zOn#JnVl2j5!-T?MsagRzB$BT;!1#RHcHkMuOlj#De74CVrDkcHl;^y-^(TAZIlI~( z%eGax1~j&^IGu(y_L_KvmG#-R?SsMg@8+qlo|zeqn1gtEay3YrimNg(yJLvJsUjvV z(pK73&a(Qs*@l7a^?l<)(+-lN(%=HMV0T&v^uBu~> zhMl4_+=WX69%o#q(EP+)y)9>0lhBqB&GuFZ{QPWF$il_jYYLVWJWXMK{??bNuWgLv zTlWyVR)ZA*=4Z5-`IXAt&}Yv!L{d7(+gDeWM5Q-!{PXg(Dtj5s_QD&US z5+1F^v0HIkSuUnXV-!ipcnc$~3sactva)vi>g~Rnylg`hNuL*BqeFTHN9N-p?B=d&W*12|sx6@y& zh|1vxrgYAsy5G9R!2q0%r|W_`iN%-AAE`aIe5{+@(V&bA30^iL=M1f!(SU87W5D9M z@QJi$wu>_qx)mXXLCTz$Ap^{oj5sJ}Of*1it#9jY!qyH>Jm9GrN)`EFtd%e~VL*Hw znk8-YgaJD}>@A&`H>GhXW+i$Im*trklHuSPla1lh;gm9KASdf_p2U{TBSuJ&>p>Mm zmA%$WIv1)K=Z;Vlf0Q&@$JH{)lj~oZc%pcfwyx4pNvr_i_z9Z8Tbdz-r910KzZu<) zYacYE;n;3VvASKXy8VyO9&?It_BAZPvki994co@3%9w7K=R4rwM^2}P!xYXKF#=L7 zQ;h?+va`9-E%Qu`qd$34ju(les-nX4;F#1JRZ}gM9{^ zJkV|}>Vo>t`c~S)sdR5W^_1sdxcrUggV8|$tX?o?fig-=r6cqmxoF{HJ;JZsYE!Y*1X;Ds?MhP+!h_hz#q~J8 zEux{5DUSiru$!f>>II|oQ&G@=lrr(;!Q!gQgtUwLgfR1>tz06WO1I9dQz4J#>wW`9 zACY&MT5H1%C+3XIf_W9SCTDGNEFGMgDJfhnIp;Pda+WlZcTowK(yJGQsg-BCT9Pw( zhR#*at%BDhjH~CQTS|pVto~ajF(_g2Uw?^?%*5Ki{$xKE53hQ`h|ExB@Iu##r6F%q z+S+wXwKUak@rMeNZ~LsSD|}RGE;BX8^oyi4?N6v14kT%5T6ytr3X|2AeOUm22j|yq zh5b3IG@BV+Ak>MDjg*FcdaZnQNkzn=QOd!#tZUNRg>%uNq;6O)V&!Fzs07EZrHga! zfNDUQ<+MIElO+09B=YG9OQTCHz1j4#coFszWA zkZJ0mPPui|HsriG+`x+-I=%fJwpmC`8(V;EQ2Pw^m4 z!OR7fHDpzm**y+)Aj3oqaZufvc83T@{P6gOrhu@$6yjvlQz)d}=FX2%i4iQx+Psu# zEDV^-<-B@sjd`|@EASGPRwhwWtdAk(xDFL9cv}OOYSCP#(?U5QY-Q94T|(43#*;a^ zONA;!f?frX3|XMTxt|4@*Vz3mi3#5YfgsDYU6_L8z2u^s*y6wd!HKaf@=BKo>+e-e z+eMb&*?L?Ep%ALDFVJ~54kopvJ7;&d$&&`ska!SHMZqO_Nx_wM^SY7hMMhp+WM^)C z1aEDoj&Dkk2mJ{gy>e7@CkC{hnFZrZZg?IC$6=FV;F)?;A%5;TGybj@z_?wPv4`zAn4g zIa$c=HHtFTP$zuM9Mu2jWKEu4gp)2)HG9kuruhQr{6TY7EV@`+D9$6ExX5W}=^A*L zkzGjETk!O3n1deF!$@Il5RPf01m^_CxyVbA(p|=?yf~3@y2qX>nG)o@4^~2?Bl%fq z&&N}Prd4=YjnYZriP?n_6U3TG~L(J<6uOcmmVAu(Re!BVK5+(Sl=sQt(sWqMJVgukq|vy;1* z5*5opw0~kzJMnrdLzVZ%xlyOoo04IouF^$KsO`C7Mpx**i!w8kkwm<>LuO|=(tvp3 zPPEn3^UZBJMyG9V8;+V-lFn1w^hB~HsrU2 z?g(AwaA8OZ8w;W}q@*F4Gb2n`WJwr_O{`)|(laBBRboiSry;4-l63uyt6iNPiIj*L z+GE$wIuMV7=V-4hXRzz>;vA_PUBjX@r9L7MCW9GpcB5iPtdXWk)Q?sxgJ+xy*KlVU zg2V{QPKH`xjiXbJA)w>v%#i&;T0xHiiCUVzARp{gF9Yn34o%W8K~lS-DawbZD@3m#TWA`Xq-61| z0gNtWJHIKTRG36?1RaO1t5y;!JvD*njpsjLXS;>cwz(N zsurkJ7AXD^3se#dOmekCM4B8?U{Rr|e04Inz@lR9g)sblJf&i-t}$RJom#{PSJ;fQ zVV$u{C0N(XF;HBdh2(RsmU=o|Re{YyRq>n+ogLVCytQC~9SwP+Qxe1MWbkxH<3Fm^ z9T*;&kd02^h$w}^GoHTnBy->b53sOtItuH&lz3!LQyK-tQffSb1~((tNM>Q{gjqY# zV_Cp-QoKu{Lw9Y}ILcdQAQN#Zu~rJ-B3+NStFb*zZ#B-MJk%kBxOQ2HTl})zZ31l~ zbwkw$*OnQ13|^KvX&|9@$SG$Fz!=RDOZq64qY}H5e~?OM#+h|6e&wo8 z7;ZeOTG3b!OUdUwSwY%BZUb;>XT+1|43-%;pKoHu5*|Lh?!xf|o`jp7aJ&SAk{hw9 zqZ-D_@^NI;cqaCX!U+Ve0iI_fr=ZiR7h@?qJ)VA)VPTQ`Ahb1jUJua=3Yee<`#&Z@ zuC_A)-=78R;H-hG5 zAvQ@=wCIO2?r;I8N$ZE_s8#LI?=R6<)+yjZ4t-YTfR7Tgl$LhBZIcaUI|!F)!gyt> zlz1qZ=hCn#VFx=d)3`$U7%*}RYsmw;!W&mxyxdf4@e1Td(^sTbkgIO$U;xH?^xVoy zexndb~!bX2ZNH$XSlPc&wXUZ*h} z%%9t@#uHR7M~10OXkJD!GEkjEj+pDlFv}cyP@gKi>vF76^{5)x%*UHd@PdyP-(#cG zkEE^YAad8} zFw@d((&@001dF3SDnoP_(jblnctoFxYPztJqlH3kXsykD`Xz z;KeB#pfV4O#sUQcG=8C7SP}D^)a4$~3cc(!NVkcl%_T3Tayz(irfIs6ZhS_~gwHv8 zLFzjC$^&spZgd@y+uSy|UNx)u(gaC{<$72&9Y|1_u>y^%x29Xh3^s%JDjX<;L{(Rf zXSIMt$Ww_WY9NJ}a70!3aH}|6TVd1lMHAqdZj%d@>u{;=4qKeo2WH-u z1(#<`wh_f+;GA~6?VKB{uJUuuZ<`NPP$O7^Yoh9Su?{Po18}l!wUs~Twvhn{6dpS0 zmK*#ErD=<@{J5elVGVX%4ZmnQws#9wIdr9?QKm#rVjWs>lsvE5XcHuchYVG-fF0k4 z0TWeP&qTF&wP*`E70YBB{hcDi91(wEnun5{9%#d~Efnpyi!?^DtN{LwXnk3R(i@Sb z(L$T$TZ(WN-k0CFfXhhoAaHKuJDoNR%IN@uB~3=fjJ1()Cmv#2=mdrqbGQ*ZQtn6E zA=eO^<1Brb2sEF|q~63pmhsT(O~Fzl6bund9p0XEtF!1&;Lp{|NGa3W-rlvUaEA5J z)`(f+@~rIY!@8^!y#XcoltWOy6^-?(P>9m1$kVLmxKqAHhiM4HNxr$1(flHO#l|4U{GbBH&hr07qu{~QYw)5=Cf2MesjRV6y>vk z40JQmGUWIOg^mF(WB>{NWd<%x<0)(_wFT{5%X|ygl#Z&HehLHzt1@^eDaJ!#v1+Ya z1~4YS!|?zX$Z3Psa=b$-jT=2$8ns1{Xr3mDTB{s^w9X+X zX0LpzFv{mUt4w*egpvF^?z^;wk+lwj{-`xdDX0jhRZZ18Xp^Pqgh58CC=zcCgRN5g zUfVuqcEY{mq0Ou@n%qqant2wDAwb*?+J9I5HRpG8D~>$ChUZ#z&0N@{I8Ejue;D7! zWGXcF?OyeAtZ-FZV+Y2zuFU+V5n1R68)l*71!@4>qT_{PSA#HLMip*NREu-Q3l6D% zkr^FYA(JJpw=Q+aSaF==%oT03=$7vXsVhi1gN-Ft^?>cU7jhrc>(@GZsGe($fug2{ zu-+-{5~nLm9m0FrTGBM@Vl0tzHJDeuSJ4^l4YjruGO&c-Pt5(Af;vBUzOE@Mlu8HZw7h{vYTFuqv+31`UWXBc&I33WYeDmvOa3b{@t zDs4spxUH=I79uWjzz`r;0g5WOvyB)U+uEO^h@ZE@iGx6_4{4+P-4&Z9Ma$JFi z?}2hB%$%0X?`m()$Jy|8`D(SMQ3X}#s=%WofDywF5kA9b+27BdzvY7)5B}gRl=(12 zn&k7lvykW8nEa7N7*#*RXC3;_7oV87 zV!>HsY0${hB%#XJr3ZKk|C0DOIVi;~Zl?i_3wS>s?<3I$!_5bt2-O{SBB z{{-UQoRfn%?jPh0mXmRFwoP#Z&~%~Q4y5rK(TG~cXB@f#NK1PNs8~|$aiPC;XbKcU z(@t~fY#>$)yZ~w1L5IE$6;awR9eT;3V~(_;XE-#^p<94HB02vQNXz|=L#K_mw6sH) z9c5G8eY6dI5J>B`7fAE_Gte25^CP&xQFAWCRji7d9J&HX>lS^d4Lur2^IPX=Uv}tG zAl~sfIe5~cYFwK8QK8iWX&I{=`VNq`{#J+n2&8R!DlU@L)}IeFU2;hSY3ttzr1{+f zq+B)po27jh_v&isJwO`Ti_0jL_Bo(wlHdC$TiPKYmC&U3SP5PIUK{!&hjs#K+J(3; zQ1iP8NXxhwx~trO%;_XD4nBx~}dMGUk?iEc2 zr;5tKm7>iK(|!9JmAzU(2Wk=`mIg|%L zSq`hBsp`zMd6S_aDn38MzmB7998!Lbf4gBt!m?fhg&G}F#-Rqwq1hqjI8Zj_P^N(r zO!DK*1Ldw9Nd@wE2Khk%+MV}SEn`nlv%ud223dyFZOw(p49i$tEA;kyCrJ2i$ZQsBS==D8*-S;W;S-2UwBz@gN5 zu>_7y#jOhsSOL-1N{NRP+t_oI!?JYeSGIOdYoDI4AM6bl@~xbOW%>C9LejrD;fz{|mnZ%_ zf9aofchWuI%Xk>am_(XkcM8dJ{L9nZZDCZOPEfPZ} z!36$hPY{$I)Ohd1S2_M))cf0-zN+zkizf8Vn{?*ViiLCfmQC)uXw9)_<}aOBIdQ`e z5%0`%0lQi*iVrM%u=YRBo2u!jOxWJ)-gHzajp(9T7?nv4(euftFYY2Q?DL9}{W3M!J7TjAmLR{iwg| z!+}PG!^Mc7-w|PwgV!lFU#Jr|tUY}A@Qw(79cTsYzZb~zhx+$d9a{g~3B9Q)6Z)%O z!`Jx!s#oxp2eIs^dWCU!RK3Qp-n=RMcfEP|@Wz3kl;dYttZ&gPJ9~FOVltE|;i4^v z;m`E`wr|n+tNupVHR-Cq1^C{=KUc;k-nVVpBV^pjXLS7c#s@Y&u@a~HZj?v z?DM_9UH{x^ee>96Ly_#xp=X~N{@TQAcp3Uo)cu4?2mgn>cY&{~sQQNYKIfzaX`fUC ztO{B%Knn$Ot~qJJ=5o>tBs4VX4H`nL>r4(M4=WQc>n)3vuE#q&fF z(z_*nB2o?_{psNahqrXK5)Z$)rR&PUXH^|NtH8Fp3tX&nwJ*JV_{E{*p~0tv&+mI> z@aduC;lZbOaFyL#m76{I%HSUM1U{c89@stjG=AiB-_CtIhfmHufa0t@yM_luAHxIQ ze}kN$B@xuY;X$yyIJgHz?K$`b)l2B_;nM8tf!(^-M4t;Q*S@|L8T&f2`>Mwej}v`$ zBu)sS94-A*yIk0nZ&%VcTH(b3**Sn9>s7kw8>2ti_%<%($5*`C#=rKj;Mt78M zWqHDTkL2Bi`^|040PZi6)Wf@dZw{4q8wpqcN5}Z#!L?6pg*=yCUX8vaH*PGK=IGZX zjf7CnCSeV}^g}V2rMcO?Wx3-e=g3>EZ1CW>bw+1=$!Hn2hO;K4cnF8lGCa7YbM|1? z6cG099EeWC=kN)+!_@~4?E4?K^uWG70~6?$2C@p7rezzNFb8)-6Ds)o^u_qSXV<2o zXdK|5Wv}04?ClV;^;Kv0K@?JZ=!3GW-XTk@ogJ-1hK5@4$fw8sB>e zMt0yVprPb;Wn2R=F7%*ifOeN@Zo{SfNgUicz+rWAE_)kYy?dzi0K07)yE^L%2r{&1 z-_yLW-g@A!cU9m0;yrwBZa`(j{-JZJgPlUTf|SxtBy1<4M_77D9^hC}`pwx;DUxHX zya5BIy=@zs(1xl6Gyu@}U=~>`NrVZNZey8CStdTK@Hv>(jkJNC`~K!w&hX~Ns0S8a zfYNh%!m5tatwX2hVPFnLZ)91>jSqCxCf;f5-8#@ed|L&DJpE24j$+*k+F;f;W`IdQ zJ#;@!eDLXgd(a{&VX%MT^!vz!`#DG(UBGsobg=1vy zN9thKZvM{54_Wr@8NMwpVn2)I(Y5YnmIK2*)QThZP}Tsb=+Dxv1E=pN14nrlRRflL z6)RM_XQ;dz0-cq;G_fRndS=mV6_oh<|To?I!L<3oqfT9jj1OE_IuZq=@|U7}w;)HmYBY^J$|2{v*>aX-;y2^3Xy9gkH2%sz z%3nRm?ix^@h`vc`9z73^8#-H0fADAUQA5rBa6Si4eFt)2@Gd!wPctQ5#5>PCI79B? z#cs@SH{82MBgEZcLOd{-6&D+D{Lu|$7|c4KY?MCdhA1E$Jbn*F=a6jtMg{H$Um40; zOls+V46t#7j}J{)N%Bs(6@JPrx@%}cH*N-Y4PATZP}YrP$J`2*JB5mIkhPUW<IL@ICnVct+ApUsh+O04z%(!BOh!Co~5BQMkorH64`jXVNku|~0*ugZj zp(KM0H<(x}Tx*1DFUFsP;FoeKFm%L!xzMVtm2Zk4j zEmuK6iHAiMvqan*onqh}Ah9hay&I6Gm+qGiQQrFZ4CB1kr|gW#9q)!fc0Q*>}0>rpK(-87iBAC0BG3~xR_C1fpT z)f)w?K&rHR;2>8uj#IjRJp&j}cMWf*TX(VuR+Q52eXqhfFq62g>uZ?hMMhwyhlY~7 zQQvQdH&-w-M9>4Q``%?BT(@se_q~eLkn|$LpM24Ci5*gUs}b1M4->5gR;^ z70|Ws$jFmTj*L9qlONhBc}_n;=UJbTXA-HRe~kJ23#A?Mo3Za9#8eA*51c+(XB~MH zB4$m&-2eoa$vZ0#cb=&@=cX74IXxsJK6p%+4q*M$!`>a55C@&DjJvP8} z&hx4&rbD)kl#1o3))eY;CX??rp+ys{6B;arn1eDJsP%yf>9B;-WkciUm@KPtgC)T7d z(5z%d4k>VGBRM@Cx_Wj;DJMNTV(dxD7#ujA2N5Gz(~<@Tvv|Wzh<$$;xf!IR*Q39} z4oyaU^|&`Q^Fc-!YEba60w$9Ag{=Ri(Je z*k8k}{*0t`L|2DV8p`8tla7c!4sBdEQB|+9A?;HK`yk$B6A%6#VJM>q?^1U+Cp4~9 z)tVR5p+Lk0!=>0M+V|Gr8|ZRbg2H8Q;hM7a&eVj#tTYD^cdfcUJ(#tUEqqp*lFA*- zx`t_Vt|^M+{Hx4{RbMu7WErhhW>2fshOZ}6FsH`v*dlSOUmtTRktn}`8$S@uY?vKmK{fsv&ophA|fIs@BL zsW_Ud^w{+TOL;1g%Wdc%T>&ntOw4O!GV>xf8JW+9Fi3ff%m;sF_QMc}tUElZ>zEI6 zdu~M5>K$PGU|01HZU*CH)|`@Ze3Yt>g!(8^AI0jUNPQHjkGT5CS06F;F?rR>B`9Tb zW!W5lEUe_mMV%dGyu+3-ImT3*5o+WB6ap#Sx|ab z*F|fOkbei_11p{1b=}${^UF#Ka@N0!`IX%Y%@4#uP zrN_hCBWz>N`UgPjO0GS^R^_aJOG?@xC9x4Zc+{7EHfO`-%$_ZDwqxWmfvA2~dO^;H zFF1FJob?N&>KyX(6k_cWwseHS_}U{>dHVF64GhrN9-+!})^nKUZ1_DW)jRO?ffH3$ z@0i4!wMVG@oF1B8^^W7c=_jak$WWYqGiL+$2Bon@2iu@0^v8|~AmyxQ=-pYrW4xrZ zgTx=8tuP=liE8x2L{%8OYR9pX?FA%vUb^-O`)kKBLfXk3IF&{{?Dm5{O69ISLL2FL zxO&IOSi%m(A4sKz9o#I^#5?Y)-htC)HU*-Vc6_0F2abKgiU5oSq31_hA>!I2w5XB! zs6#k$Msd)QaAXM>s(0W)45&x#&mta|t#~#lUEDQWH9coNcT>7jau>~6|0M2mHvCFz zLha%7q?`?Lb`8dZ(pD(_5z&W8UJW7H9(4}Vb=le@QMtQLis3>E0;BuWKkxi+bSzNE zQ`OQC)jD)PnYxxZE#SUG&W4{$Ms`%koz-GeyEbWK$nUyg?GX;Tob~MD)P7|a>87kSIaoqwW(UHUR5)zqpDhLS>5KRYjQSx*{K7zo+sL(^?`wgoi0rMY3&h?-!uk| zvM8EGwe&T*pO&(#t3<>u&FT3Q6kjbpjWik#K4=1}zR1Wp=`VGVv`acnjGWoH4uh6x z0V7|RB(yu8#-Ry53l46mmQl2e>nY4;C-m-uce9a4oLa9x*pHAWfMv&_nT&lh5=#Of znws5rT=4ncxAp!o&SQ4&&pviR8uY2MInH-HhE#h$j zHxl|5OyrJ;uctq!=gYX~w#Sdyu8r4jg99GFv3fT?a85I^uQ=e{4EdojRo}?X>)vZL zN4AF}`w?<*?S#p7QLC$&}TFPdOM4lTTWZcA42aql7 z2eWX6Fq6;}qP|g_9dypcHZmZq>ongJ=PE z`-{=g?|zWe^KnQ7cpu<+z`jz{gGVb5-j3F1|3s8|4U~xvaWkQ2Q3c9= zFtv5?8~grz@MiHZ3*PH}ZP5=oCKqnJb~jAFskih2*z>R6`X1+ZT&lxLx8oM_=-a2n z$d8#2ufsK4Jlk?<6$Fw$eF_bH{dbne97U9PR3hO9s4FGo_* zaJFOeTGge`x;bE~WOhddy*s@Q+v)6vm+p0Rstop+zUsX_FLfk?Z^I^MiuHC(a@4=> ziKV@V#4a=K=O3jXd|2`Sm?Dk5YwS-o^vNI6#2?`=&Otj)1)v?^1m5dEdY^=4tUf&2 zGTaG7O6wb^@)#Ryo9wYMv{8nNiN|*GiIc*`IS(%_x^&$E-@)-Y4_6f}EqL*|3BA9V zv+B>6Nq1K7lBZ3uzbpN@_I1WHE1V*aqNI62Fpa#8QR4i>}MuE&+;%P(%{>D#Z%}uI9CNT>^u1U4n8^= ze4BPSf6>d+a@Rd!_JRAVC+0ld-&Z+h-4W~H1Q{=gD>`nRRq*Gox0RWeXK!3^Bkf7e z+{%5RDEiwz+YxI<_4sS^BtHg|;*^erDaimp0fD~2S4uqm*ZdOAg5Zm%tb5lwctXy@ z>pM72_fnmPdzwVmiOFu}%xAaO% z?+MDc4<2}tOY}~Y&?m{WIK|ycu@PilI;G&PoDDNjo=Rle#YmGj=G-ueY>;AO#nP7w z7Y|K1jK=idRt5Hg_i zTz54Q<|W!Z_(?sUsnA)D8KM&kQd7DPjJ@g#x!uom8v`HpDNw!_IQ2otZ_0tH!c|9*z7}zY`Z61>?=j^`s_Pg zCtSL;q~P6azC|YO()$+dcI*`H4lY~VkTYN6bgH-dFW8Uk?Ks?f?R#t2OyMf1 zb~%w9)ug91CxknE;CjsPJ^j5$I&O8eb?}Bwn_wBZ5Gv~n1HT*pKv18G%yiIjVGQB= zdKRBMF|HggAaLd0k&_t<;@w(nkV>V zDX3oXDT1#N{As~o68ss#-w`}naKGSF1^-I$X@dVK_;kU?VjHR3Iz#Z8g3lD35IjZj za=}vtUnlr1!J7r2E%*_^(*zF)4heosa9Hp}>_c|TyKZ<#PB2$>mNi#!OmI@L(&6=j z<3isexIpla1S_xh3&9r%{dK{Gf&&Pxx~(F?{N?oNDMDB6jR;mO$6`M2R?zyE2hYMj zs6&6pgKsgRSLm>j}Z93eFb$zX14pq2jG8p>xe`S{j3O-h3xJxj1HsFf{OIGWZPqLf~gl@x~bt|&<3z&GfwOHs! z1gnIQmi%DGbTe&N5_L%$3|tJ``*=&J<( zP4G_yzb|+khFrJB85TZ4Fwf#K2ML}ac)#G|1y8}S?6%ZQ8*}g zm(af{_@{z*3;vnllM>|rZ^7pa{*~aBf(HcOF8F1^&kKG<@FBr}5Im!l<#3haEsv22);wG zvdO;+K1=AIo8}W0=E2tq{h5lW^7YY8A;EM$ZE@j>d!FhtK z1YagtmH*J?x zw}q_bf`fwF1&6FjpsyDkwk8ALCO9JaTY{saw;h6G@|_G%0~ZRyqbeHHAbzj04g6QZ zQ^uy`KK9rt$b&QL&wx5SHh~XFfD1EMBDI2IArLymRfiy^@AB2W0U-YIfAP#Y<_)E z1w6&NT=ptj5>}Jmk5P2D zy;phoo6LLY39H5Wn9iJl)lN3J&H60x7e&r1E%p~L%5yq??h<)At!~@0z6ZS3>hP4` zNmjWMR+mSfPVCV+^iB_dmq(se9(h(YZqpyUu z&C`$H@W}8D&%ChBV`JZiF4UDk56v?8yB0zgxk#@t_^SqXmwn6+W@aI}Twe|-r z>kpFm38bhi0lIS~tlb{l+vD*k&sb`AhdTV3$DcoERhx32v92)qXYj1*N?6Zflv~!@ zQty+-Zu@mQKlbD2W&&K4nb@u+e!*(XvaFMUw_3jtd;YA(u06lNY;q;67d`g;g2$d; z@YwT<9(x{=Z$Dz@gf(pT+!NN2^*L3f(2ES-=dt&tlwHUdFXc<{9Eg*2EPUmq^<4XaFByE;`ijBt>lHa=IBYff9eLijRvP?)^-Y6qd%M8_ zJBV??D`EY?Dm3_gYq`O;&9_+;PrzPn@F8ox!GEy60-RS%pYTf=?-yvy@jh2$j`sz? zh2WtLU!mz7?=6CVWpTV;qw$TvH)-4r{AG<-0&mf{4S1X2UyCn#Kx6u%e&9lk9Y5;& znZ{0B(a#3yYd=1}rQ4FL@r&TkwT`tXV}kh;@K!6^W*qgN#_kwYdxl7Y4ktM77Wi1( zPa-a2cdaqOcH^iVJE~Z~Gto{M{4u-I;FIh{27k=PGD)t4b%I@E@JaTS27lak*A$<$ zw;TG&w!0QM#olM=r`nF=NLZ)YS;o#!wcQxtG@B0_^GaB!+U~eG%?=rQuKhWKPq*h8 ze5TFEl~vxU_U8?rVy`oJs_o7@Q|yf%I-iYHd8gTYYenHn_MZ*@jQue)7S6QQZXe~G zYP;iZntiR|nPjUSKJuJw-(u*Wv~LGKwvIOQ5u5#c0x%gCDh3tL^ z`eop)R#5D7i^i0PR{}f=5l21t8S>a?Nb)NFsI*1lm_3;Q7xSK`Ancbv}OV$IllDaOL8M_(|~RT666R zWcW4kR%?z&{<)s^Ug&A#MN%)z!Ft&<9xpQEk>zvW;8iKV(r!cf?@9TWNcqPmS=S{} z&Pjsji>^-9m}}l?8czo1l`u1h!i-mWC9Eoso)_5e{zH}ham50jh4v>6USNO5;Dt72 z<%K;2`%DFam)LI1d8x-&EMZ6?7uLLXy}_5-&We!qHbY-(w;R07zSrOy`(!ijYHh9s zcqObldy&B_>?VU7J>&gK`yoSbv43uGoBg7}E%t8=ZnNJrIAx!w?LT3q?b!ym+ZP&~ zw%vKT)4tTu+wElrciQ}ZF(q@_ZZWvi<11F$4;lKk_LX`-Cajfq%HV75&l`N5{hYzq z+Cv6kXaC0FZu<>`ue0AXxZCyx9C@y{PcpdM&NcXY`z(Xk+ZP*ryLyp?8t~^@x7++a#SY-D z)|bVnt<{+G-OU=)2i_(4Hv44YZ5p#IUI~<=5b;+%bIR==e|x*_?wftp@OSoL-yAV-fur(@V)lq20vu)Huw?y1%n^8 z|77rE_FoO&X&*NDQTu-k-f6q*>*wt`#z+0azR2K*YyuY|S7;~V$dDMNqWc4M1g z*moHE9{ZaH58CpOr(WkVBof^|VpVOG}z)ON}vp))a zKx583e+BNg?vwb$TETMe7yJK+#+;*h_2b9U`F>#Pc@lV>yr1>tJ!g!(j{ceVEFXU1 zqD>Lc0DrFad)qn*Z!Z9EwSMQB(?Qo4)^Q#iJ0P(WlM+_8&z(cZ`P>*g+sApCSHe2z znNPEQ?tB{XovK)*oHGpe`=%J2?Q`wZ=R40sj~HzGVg_gX+2KTDc<5^l{;R#t;B4QG2LHu&*X-H8FBHg`~iNh5j!03>xUiQ zE_QgFFWclDudSB0bdt}>oUq3G#(8*L{t3S04E>|NPZ>PHH`(A*d{qXY?{oWcg6|4L z|G4i4gD3d<3_ij4C4(pUTwNXS+vTC}Hu!wsTLz!!`-{Qn`~GHd+~+v-1fHW9ryGg2 zt9DuXBcS`0ql*KY6xU)takeX9+g;JeP?kNMp7<^+G(f7$%IL_x7H^;&!aPzo~g+kwcIM4wZ3o|`q zq0nJRnT0;iJG>HBv1csI^0|A7#l8~70-lu~pSH%gz|f05K5dP!*U%UET)(l#<2QU{ep38D=>?V)x-Q+vQ^ud%N9tg@@j3@K=1Dz%!)YJ|kPdPUpvd{M<-@i{phj0sdU;zkGa8ZZYsyYrBk> zT8$ZFw`$CIj8_8u3K2i2{0rZ=4Sq@HO5WmJ!1s`c{;0u2zNZa-+4n1hf8%@6;Fo>-4SvP< zs=+UN#@#EP`RF&EarBz+cw;jozE2zchVOF*XZhW6@kif6Lx0nkGWZw1O$Ptk_br1T z_xSL`9^dcymVX@WE zY0UM)C4#q`xu9RE%vvh+>$3E%MY^N6{lL`QEo1OFIwX%Xml0nEeqJ1d#9NRz*E-3+ z2|9TUc&l}y{{hJVtdx18Y()%fdbZ@GZJ*@07U0Q#-Hk%m#S7gLn*1Lzc_;hb81E#% zvsNOHJ7y>QPc-}|`CY#>+5ZVcKh5vPho}3`GW4_kaf9>x?pzu2yW=?Y_ZgmY|MLb{`W?k#AJQK&W1-s5 z_w{*U@6OM6>J;wsyD{EM|7C{0%3p8r8h^9F*ZEf(TZqOEA&qZPekaS z^4|w~LgQ_~3k9F--vQhu{HI7c)PFyJ>1#he@6z&c91-_{KiBH<=S{}`5AarNy`SUd zhZ?){RF7xu++fO2An!Qv^GaAZ_>WZ(c!Ot*+~DUN_ms%C-cJz*G}i1gu1~D>{yqL63&EAJ z?)6vT^D@-cZGFu@fPQQOF4WJ{c6snRjUAo$vjBbV$LBJQ*}ufMfIrvzu7B@j%lba> zR_i;`#$6h_{rg>yZolj4#|Ql`&km1&d&Ga5t_x2b`p-4^5x*OQ_51S;eV6}ygZur3 z2JiA08@xyKz}tki%i{z0_|t~xzy0?b{Jh^?@4xK-k)i*_|CqtA`ga=qnt!*!2mE^t ze$~I<;Me>I3_jpLWH5I5jjwpfKhfY{`X?LwE5Ezu9q>>0(AC={Y}bI_Ju@BjyD`j* zes`TanskcU^ox`3~B$%TD`fEy275TH-v zh4pfPK8IJry4cg+KJzC*$P-a4;3*AUVDPNKY=dV9oH5RFFonpKu;vF+1}_L)Z}6hP zCWDs*+!$a{;42=wJB}6wwtMJ5F!<6yzrjlaKQ(x1;Aw-a11}rAH1J!4s{`(u`tpD~ zj;aHvXd_ElO9O7qUmZBZ(60!bZE#H>ZtxX>guyj|*#=(`C^L9Lz>Pyz1l-u8A#jD^ zSrJGY+z@cb;2-^08~U4mcP;!!|7s7t$Kbd8w;KEx|KkR?1@;(xb>Mk}&kVd^@YMl# z4KgM0J42ru_@lucfx`x`3Rpg++=R6{@KJ*s0^HBxm9Rb^h#A}+NErOSCsz5uztBT> z&rd(_Ck@>nSY_}Be)m}>f8aZYJ}&UT4E6`M8ypDyz~FHK_q^2~c+}7XfyWIV7kJL# zK;Q*~j|mJJJT4H^gFIn%2Z{`?49qonen7p|L_MqztT6Nqfm;o}F|gI(4FUJLsT%|L zdg%8X+#Glu_&NB5ZYw{)xa$ybp%oW@_&1Fi%lWXuKsx*3IKc%07IOk{w>3R*Bl3Pm z;|Acf1YW;g z$Fbr4Akc<;J^Z(h!SC2M`5hZ}@D}iQTkre%1sF&c85je9Ps;f~WOz_`tiT-bJTBM{ z@Y^aJe#iD$CT;I&Pu>?id0!bLuVbIg>)60({NK9oa=}A9f^u@LTLW!p;MvO-_R%fU zcgJhYzB?6oE9jgH&ePcS^S4UBAPIJLYhVHaE}WAF+&SWoz-JU0^vwY`#=9dBHuSFr z78<-cP-F1cK%2o|4|E!QPv9DZ?+$D*_@2N;~=KL-hLv5$zq4*p#0!N3(~VqFis)p|hsVz0(-Up(mPi$^_k?sNDO6Llr5 zUj)$AawV*t0XHsvJW%eTR~YAfV+7^%$ zXOd{ko31+^>A?^gXqHXMl|~6cbZ&b*m8@x+E+#rHZ(2Asqp`VWg}x7mNN_WH#6tJZ z5372eV!c(PkB|%nd#XK3K6C<@Lej3z*2X&3DyWime*K3v|>*pzN;S=L#ztf{eG zX(R;oo&}B&7>Zk4o7AAudOQbJTIZg7USmsbQ%7A=hUvKt9LiN-Z9lKPv1Rt6^OiTZ zoCl_+#^vW>ykbDNtmq1d&I_L#IXB7#^WQ0^Jzdw>`Y)E_$y=AKN9K0?`Nm~zLl}QP zo^8aRCG4UlXd-$VM6|mLgI&|m#ftW?w7^qyO=<;dUbbvSOGm9oixDjWbZISXY+c?_ zKfP*7h{X1AXjxl2H63@5N9kGF#j;wsAP5tj3ZtN1EL&dFo>Yv}ViBR#HyPV0h$#yE zpw5M1AS5=KHL9|LF|j&ybv+d15DQcd>E^cjmYQa#mQYBlnPJVETUH81f(iPe+*W;C zYrE(y1hrCU_?z(miq1@z0~r0SYCkW%sx8_6@AfLGKwu~`{JRMWz= zc~WB$;f=BnR9lv{>ikh@Gjul9a!G756Rc%*$xfXWgBw|4V=f7U7Hm=Wc}uHi!$<{N ze5&P=FfPHC54N_(I?bj>BoHb zT6_HJj#g*9h=r$;%^AZ74%^K~HRRKB-F)GxYTW63xOLp|veuU5%0{Kad~_$XLIr2x z11+vcHYDU<<-oh~N@;VSc6c#j()lu{ITe(WatIin>1J$eYzP<1A%P| z$I{Kq+LN`?ByB37U@p@XrB9F=5VvZYa?@n1t5M3BI!!rh($G_4JJYnM25lAo0I@?< zjvB-+H#2pQseqg=QM+jn8{6wJYpX&-QJE3`ef#QYK`2o7FZ$%M{QJK=rH@qzLxYwy zq`~jF>M>`2hl8{_ykvSobSKON)L_ivRz46en9MF&&0}z+pkh{LR!2}KKLK*$gZgOdy8#q%%?nnpEBM@YM%QnV}nf4N-@PNZ3w)jZ9TiOvzu zNaqTNZfy@0#QvdhXr`L~Mk$@mSM#eR7_F18rdY4qwLAC92hAAeb&WO&7*~5V^8b!W zz1sUD4aHJK_n^&epQNCD2sjQl>X!OB!P$**IytztjrlMaBpt1dp``>DeU1Xff0@08KR3A}Lb{ zrD(1SnU*Poo*Q*qrU;xG*+OW3v<&Em#@b5kmDQv>Qry8JAA19zQc-0vI;(MIvMy5+ z)i;`DK`=HJ3$=n$&^ePi|Dar`A}O^MRkar9Rbf{mm{$;vV?Q+>nPw7#83|E0A(W92 zQwhaQ9m$f`rq)zVOIp%nk%EF~eh2}%l*sg|`6W(LtRNhU26a+ZYmt&77|e^t3-Tjc ziee-vDVzi?1rwAMPJ))Aqy}rwR1Mcv3CyBZm>^Y+vHWnTAQ;iYlwgyk3hR`l615;2 ziblfWur9r%wQW_ZaYch}M=Tx=hVz3?4XL`hE%mLs)OaKk3>Jh{I}*vx#@b|g{fb1g zy;d>ABXKm;(W+*^c0f}mOI|+qZbVJ9YnnS$z4_rtBpeT6%2f%enpKYe;(2+ocsy93 z<(-{MCR;LepC1m#BWSS63kD}M(xUkV;jmVISqBzHH7&JDPbf4Nj^;%QRHfyJeqoNy zN!_RMa5Nmti-q!?ooc4yt*R^^_dPuMX?})B&VYGP|5s+kq=3cxFeq= z8Sx}3BbSj*k{szIS6Jyv>cV-6ZZMK6i=32bL4JNj_f$oDXnwM#E}6n+E?k!BPc$4{ zVa+vP_k%Np3xe@*K`0i}rjKODh>(J4C_hhUtVGb7Y(d#Z3k6{gFBt zRO?}Bq)%v96;Nwnq}Ix7R+hGOG?RW#aM}zwVZhOTSf*U@o5qD=dQdJj(YT^9UDH$o zBTm&!560q=P&g9H(?&9@v8lPTwx*>8vs;krpqDl3tZz!zrW-qxhNA$cAB%ubi9fgH zstc3p3Updp^2g%QcwWRAH&qSERC7(!qMDV4qaYeCi09=a9+l>oviwwQTSIHQbw#SC zt)a2ju;%9l(fLuwbTn&w8otxZ6v~T5LykL0tV&kmfCXnDRHi8kVjY1=`4|oJCx{DBZ*&I55&JU)WfeY%OnXX-u~wu|PU3lCP~z5*>x>w3uV) zsn#p0)Yg`&WD{INJJ59KJ(d@W#2u$mGQTR(*xuHJU7lbtQ~-?@IBvG0+@yqIX_34F zN0~)#3j9wr4oBdONH(}6F&#Y{jz)uF<9|q>ivy!%WisvbAP(K4aV_lZR81#m`(Qru zMGC@sy1;q$_1FY1YfLw&ZiAR{$QXywYP+gzY`O~G34;#W3CEy*lQau^d?p)ADV$$` z=6Ourj5cHOhBDgl8R#%zz}ni09T49r!!PMbbtbF0V;O`ik41toJ!N*7d24h+JOWo3 zj%%sSl&o^a(cgLbF`Zb}fhbF5!!#2K=M}`XI*=02Owb18ot~t~QS*~$W>LwRQ_EN$ zT=8YPa5wZSN^uqz9%vn>v+yIT&8~yfsp9?|jTpU}yl|cnM&+$au1xC$x<1S?x=zNjxj~;-xEQAKP+nA5pj@cRo#{gveFtNiIpd*t(BwpVICNBc%o(T5AB&7m zFNioTkm!DNa=x-hDCKDXthDEG(BN9U$_mY1Y-Nd@p6aYS}1$C8z+6g`S?DV85~ywUs>x`r_33QQ+5_8~f) zjn07BE1Dn93u-Skr`@SK7>*!bcjoLlP3>AF_{bRMR9$gN^Qx;<0_edAB2*oIAi+z= z;#)}?s^z*sk{Ffd2hoWtCG1IwAuNnXoLD2`Nx{Ph*iVUTZxHpQa1e&z7*%O8H>Cg( zB!UR|E}01PJt?Rktq*Gn;+~X9xF8&fM)dSt;7P$y4+irce-zAfldy1#6krN*LhWGC zlNLlKbWNTvG3ZeQ<{hjJ5MAk31wE>O*wIid7<76%=ut*67z?3kaFD8HL61668&(C; zXg=Gf%~-Uq&A5c!P}x>fJKBlM0!`5H^cLR(q#+?KYEbV*YU_8u|Sz^%nljjCKv zl{yhZVO|V7I-l2(b~8%!jZV>;C~IuF%E^VvIpWS z$3u~PEn<0NZK}1swLXn-pa7#R9CVg;m90%RsYYm#F&fs!5`Uu7%Gq;C!&D8|ue-Gh z>(~{D(&0al6fFqJ=+-T$XsSuqx2BpM_vGAldYSdgsKo=i``%^02}VL zB0wd#StN>;%3*b_O&#e>KF{(1vm84^8_lSdl$s5~db0+C7@71KYHLkbHXso8s-@B) z>fkt$tgq>4LVrVQlQzG#qoqy+G^9jh4NfBKri;sU$|!AWYHY*PCSp7e5o0VlU1BST zQh9X;`hB_>szWP*v9?d=OrVX6H8~A6wdy81J4x<{2fx`$^b+smv zD-f!}^4U0@5Q|hLTbu-K04mMYo~~)ZVKPfjBGlB|gJEsesM+XQS@qneCbgH5_6p)s z6WaJZlvq@>>!B2cMYS$vR!G$95)#pst@BFb10JG{z;|(TTFLi)}rOh4x?_V-1Gtk<7itycs0Q(+qL!w-|J_XNyu5gN=L~V47ld+^EEf=svPXNW1l-F1z}`m zmZRGoLG!%jpp{3JlkX{qfu;^rl|WG_f^CnYf$b3^P!#PvsvzfK5-RAZawH37eix@Dh%8EZu3U1iF9dtY{t-3Z)s@p(WQwM$ODv(wF$jf z>)o%9X#8!R{;!N*=OMEO@>H1U}q>BU44fjv`3d?S!K@ zM4a`3h$lthR1FaubRe=95ypFE%GXAfPooNk7E96CgI9W4Vs6#bC6}6ebzG|p^o+iI zt^RzfKj;pd{IT?p%27{&5=>U#O6&Pr>-p3=;@J*9iHIgU-DONI0zaViLP?xG(D&w@uNW4*k#)cX^GlNpJ<7ib8p@$krL3k83 zEqlXC{XDadf!tP8CwU<=0;u?mBw`dP3))udP3GZQD3%V2QgAX4&q8U6Itot)-CX)8 zJQ;Me>BlRRK{ua%W+xePGwLUHk|8&vKHp7-+>AW#gE>pfOLZ5BtYS>6?Or-!QW#lg z=OD_{hQ~b*rP;Xl&~bX`NaX*&nsrqL%f{}8HbPI3suiX^cAOqN6vrb-CW4@GAb?QA zbve#0uzxHT!?6Xc!r)q=V^|@F;6Sz6)H7yQM9e$da2id>At_;|sAs-7!rawJNK2+i zYFtKYUMF_sTT@4kwTuz0OdWv|kCsYW5iYA?0u?BmZ%ZZX8}T3?S{Bdrvtb-=f{Foz zu>gae(cV$-VTB@a(hIVyS12KdgBvxtx$#t)PIc7Eqg5zf`{OwMaVUc4X4PSrRE?ub zrBqGk5tm6&ZBWk%7~hL24h_KEls3DMDg$+hT@ehW48f>zCD<6-c1pbk+B+A}JAbGn z6a&)5joM_>MQO)eK*#){MS1<9*#t}&-&z18WG@t;>*3++Q|h<~j~9YyW{#Sc6?_m} zla#*Noe*8me_F02(`kF2T&bN z({Z=$Rr$^n1lVq(GGpqs1zI9%Mim&LZl563(4*FgAY^YKhQ<)dDF}166cpwAL0Is4j?vvFVq-~{N6m-F60F(HC<4Zn z7eGKF<$5LaRj8*|G^5rao-(-`BwfW_8MxgsRA5XorWBx8BF3|NOLIC3PMA(( zjM9|L6@?aH!i5p32j^t>Sv}L^Ezs#9Zf1-v9>%$T6iC{k?Mayvb?Gh5=@dAlzf+oN zY=N?H?VZi@Lhdn&8hv4>Pt@+hhwIOT-?Sh1s7aN?{Rn9RHyXxnsu7NkovPE)xmyFC z#&VxRl_&1%LnXtWgz5>gY|jpXw>+mSWaHw)Ed^T&EKges%kv(6>GnFE5&8Qg#M!Hf zDob(J=O|BY@OZ^@IwB&23)7cpb%GSu3ey0B z$)n|9R036{D!dPlMXfe9Wu>wmq<3FH!PbdT^yUjF=wP9QRp){Nn^TH}P(|t1VrmhK za}kM=9G0;E!d41)qulC8*Dm{0%Ci(Z#;5{rMJ&hL>a+zjN;TObssXBqB@R)qffcpL zP}TUPfuLQ*>DD4?mpZ`ZQRV;F+l4QVm{T!-o_>WnNCzfHgwq}-Rn0HDxN_FK`Q@tF zGVu63vpjb`yQsXpsG?|oQF*0G#&ATZ={~cNo3w5sqgwe1j-oZ75Q<(UmG4 z@~n1-x;&){#*b1b-aJ@XS`wCiQ86LhyjUx@h^H~E^Ry|%$MV&A17;u5x0_qFh6he8 z8HHKpMOC_F)#KPYxS%~h)F~xrb|p%dJkWPEpIhl=6>e@NGea#Y88XA>O6Ha#>JhU z3PnEjU0qZ8QMH-Elrv^rB(%5NSPzPYycpF^R`XiS!3@URhv^7 zLm;$?fsNFLb9&YIvXTa=O`SVU<75j*oLL)Optm-h@%$Z4n!=Q#IQz0Tl+D^MbgEJ< zmsv9uxzH(18urgsWlB;i;?yYh;8@mlY1RC>7*NtSY!|Wdaz>Po$F60FbM1g;z?kJ} zeOe|-jIBuI+Yt_pA(3PCW0tQBhi66<1J${P;}t_`g{MOp3yv6Y6r;re=_oNkJ6a6b zlDB-NSM1~{F_cA(UU#%Bl_hcKM2E^iD=JGbNt9NWh|D~1Aq!0uJB|P5hW9j{ zMtD4&+M9Q#ln>biFVBpcr^V5qo^ql=d4&m!D{heEapl;Iave*P6^<2}6Ea;L%qg>t zstT1VxPjcje2b)kARx=VHVnQrW;?ZceAX0VV)NDaJ z9<)|$Xttd7dY+x7tkeg*vuI->%~Ron0M!u&6}^9t8|Qg892g%ID>KshIy6aR9HaP9Cb>CCPRas z1|Shdpu>5d1)Wzq=UKvu*ae9o%d%aBg62Kh#Wr!ofeC^OW7*`DA>p>)(=gR9+ys~2 z<3OSb)EqpR)Rauk>S&QS4WuLSBAQYKx8T{|c*4_s-ALI2tuOc|(HCFATiL#h z-;=fsiOcZNV@K_Dj8K;o8kJI@163UCXBqfasHLn&cE^Pa;wmo4tH0v}yo{8Ks;Wvg zx7xwRwC#w<1w%dZW8Aaos$_e*2oD~%1Y@dAPV|jO2oV;ljU01m1#itUDPvtutuu;{ z(`!_vo1ud6F-uVKHy3O2_9B9GS*kgY8NxL$GQl4#SE)s97KbEw#2XhG9W6rxFEero z$$ksoo^?x559(p2&^`!{X`%)b1O~auOO-NQ#;&{skwJ#X9#hga$n!qf36X*1Ekcca zyfvtMg%7JyJ7K&rJHJA;Pwlay9>>BM7E9Mb9%UI#@z%Dqwv8&vBq1|h(_%iIfP1vT zD;B;T4I@P6c)ZCMnz6*NVXDKND#S}&Vlc+ZQm84OA)`dJesqblya+`QFDu`f;_0QZ zVjGD5PdsW0Ur(i}@_lh;)`@$TWLT&x?V=^L_RKVGD-7Son8~Cy5sbCT>MTPWP%pxX zmdYA_b6bYfX_?!ChmReSTBo$ACz2ha@-~Uq<{Ew}jI~W;zF$5SiV=z2gfN>$cfR}A0a$roU0yh0w)U*w@Q&P~4t{<}|D>WEKhwB+@ zw6O4XBCIpfV_QHEQhb*}n>w{s&QZQ)20Fp8ZVzFv6tP9J2H&p6{?wyY2aEDjhfLyX z$U@x`mt`Iks4h}rsEWZ=&y0QyUbZ;tAYpeXDdPx0JIzsB`lyw&5{HxbK`L1pbKSxz zY+>dx2XsyTl7{QfL>FAw`XIn**4rr~uMx2%e^JORrJj;s}z?L6mTPlF{_e*uM)DB zrdEF2COgU*Al#;L`3jU#;-z3dmxe!Y!+czu@Y=pEncEv)UbVBXOXj8rOXjA9$iZC)FL%ks z3+L-44IgF{UPz;OA&!@K*4)KL3LR>2*Fbo=A3(KY%Z|;&t6wece6=aVlX15I-;S6k z(ZnpI%6WHdUOc-58@z?KoIIk6(2psH7a7rb0sfWfY?mRdC1|bJZAbnKKXCQ;P4p z94l2tRCQhR@J%N8f{!L|#Kxc>S({aa#HfO?6bEIqnv6)|Y)(>Zy<+36&j<2oPdQF$CJyA}Fj3ACAhT*r*65WeT=X3?Re*La{Vl?xF9N}Jn)&`aJGOG!3t*TbW! zi3E)qD^Z(zbFyj7WIcH|;DJJDRN1PItSU%^J{2)vIY=Rf4N)1qdsOW1t+4C)MH7&^ zNqTr;guDMV0QMQ)h?FGN1*6iG)tA)NHt5mG=R%PO2G4CNNkB$b7*g;}@UTUsxU)Ts zflvQIb`CMlP}uoNb@7WqmF7rQV;f&z2G^2#a)=kxl-Gi9v6jg$&}atjtoh)sa#i4z z?Y)vYMRVyVF`vOP@dIVy6r;fyI<`yHs;B{8sSB^LQ6v&oXEn@E^5G4!SW;CV@#{R2 z_;U3oaI0p~59zJN(G^oTR4lTI0Mf?N7JbBCyh=?=vs8Cj>aI;fJ*=rEDw^KL5@e#m zr*_`hr;w1yNwmzOS-54Qp}ko1XBRK$7ynFO$Wq|eJzzQR@MO`fF(l?2Y=4R}oh$@{|KNm`8LARqs!_z#?ZOh80vooPp>{g&7 z;T7dOEvKUe3M)1Y!GFL9*%NRUHKkw_JF_rugHk4fT;7DdH$kbvq_8^PR9>B$E|WaA z4m-tKFc5*LA|lj+!^MKgKVMZzgSdR2-r-;H&@fVnSK*tb}P4omqu$?5eaW80`WV-fsBk6xg)9o)3;F zQHt;)vIiT%yiH`mZZmmjvPh+FCeuP!1u2sX4UVZz>1wCh89HExm6!a}4fD$E%InH% zBx!Flx^p|l)#tx1C=O&=LUqX%rl*!0^Q$qa!Bo23pc;eb7bWHvU0hmeiePbcaIWQI zC6@P3+wMh8Cig|PE^IK6dr_)%y|aiBf-&b9CRR;4)u81D%{Gb4+8o&6!kT4mh85&? z(?~o!-csW7@z#?~I(nI_CUx)jBrR{5+nsVd$Em)`0hLV#8FQ>OU9ZYa;h9aAv<6W2<>bb0hUHO)0EjaqB?ecn#LE%&A@_ogtvWAl>VaZ-}sxsm+t4N7)y z_?!W&hc|K+*51^Lmlgg67ET&i5!RY7;h>{dlh3@4)WxlO7ekse)$)?05;f~^(U?&J zG&|MO3x`p&dA7J?{##i81>*K^2J3yU;1oO2ojKL?lKI~rSY$0=^= zSbw>sxqU@*`rO(NOM)6&@#i!cmqJx~(WdVtO)V)*qI-*`V4Ig&@%S&T5Tbc+=e7v1 zn`mz9O3mP|D-9Vdk;B9J)R!Tl;p|>E9M4>}$qi4aI^v%1@Rw&*8fuz4WmgCrMu@P5 zHX|bwdQs*vQSc&sdzcDH>)Cd!GAw;hbs}W78nl7PG)ID7>uL*ZK!YW2MT%Pca12R7 z*eO-3a8e*S>2R%~t!VwMQs#V1I3 zZ&l)JU&N&TPpn(oh;Lprrs^>bjtR$1)R>UIfVMqaFtvZUCU7(+XAItMcGO^sKy6x+ zAKtg#p0k{iwHD{L;|u)o4R|ehY+P&*?mI2U#xB+F)#Dei8?EDljAo7YG~!*_xqYx$ z9t3q}2{qfIXz@7gm==+a`x5QqQ84^zddi=0K)BLlJ>^-zsNG#ksRUxwE&2ygAuhm` zLP446Cn}2$#ItC%n&!4wcHpZa^;4S|v*1LSxtL=|>6ed$Aj{E2{j8_*3&wHsujDwD zj!DeOR%Db}DN_}O7sH!IJqrIpvUVjGRkfD2r}0-V*nw2YQBI>ppS@ME{LwzdIa1*$ zgr8_tYkHPrl&lG~M$g&O;Th?y;SXMo+>0bc7epg zm7K4zT+x@J56*-Tlw{_MpSq?dv|#(p{@1raBR9?b`Drix?ekauc4qPC4h-IR*H@le(K$_l$_94_a76ycj~jO2c-T<=On7$J@wc^%Zl(G`8Iv}iAUc?Ufz@E zkd(9QuT!AmpUzZzdJcTlYk#5A^9!sG_tz9V?SNf~{El9sXDLUu_*sUZ#rU}dKNsSs1V88FC;GqHdl&eqs%wAz%mavuPE^|3mey$F zBMKq&$YchzCS-!3iKHX}wZ;&V38aQ3CKDd5)L5YHbefj-+SXpRrIp)DD_-m^6JLMOELZFYfUROk44W=@VvvvYW=#@UpqAzuhv*>%if_@Jqp?_4A@mtnR=KGPN zUjs>cF9Au6cNFJc#2Jn1BpGjN>PJ`u2l4b zqRN0B_ZmfCS9D6Q9r{6_%ee%FO8X>`)H0#81xjmITCbw7D!NVieyFq!iux7pRKBN_ zwpYXs)7^qOU3Xp`r~yv$(#$RNAvZpJJMInvF&SNqdwjx*SMk zb@J(U=tmSqfu!}PDY{D00!7OdeOu9w6m3wnRnckV?A-1Hs^*gZL1}L)@_oSOD^PTi zqAEp;6y2rhNkw~sF5^5-!2m2W_~}P1YX;LE1Dek0prVBzwX92-_H{-7rszpUZvjnX zKJR!NO;GenMSlX4^v?a5U4jXU7AyK0Pz9&A1t`I24^TOy!$9y`Fn;8H9N%1L^l6|{ zMqgEQzoP9xk_vqiJ8-S$Do0PUoX|DlE zNk4qHUD6UDDb*!FQmR@YDSbVVl>Qy%^L@hRn*kK#QhgIh>aj&pb-o?C1}MsW?*NI0 zjXB3g0iY5N{fg4QskGOCL=(?H*DmP{pkj{kWuOX1zXB>{^bnB5@SJCtARkD|R|X^! zsss|LJq{G%xX%Dd%Kxe8h$3`6BbPiy7r_FHtnP-jodEi1YZK4~jJ7M`&>JdmV!1CZoa1RExNZ9qbMSJ5r7Tta&jRz=WU6kpH{=;wlpK4hZ}=-ooA zML!Z$js79%Zbd85zCz1~oCU4JA3^tCXroA>jrJ?rUS!j9gElHvbfuy;sEDMu0gWLj z0R<9tx1yV&HbUEkh7`08jVow%sf`j-ZFFiqp5D1&FXc`gTKHJZ`Ms|A!IjNA?-1H$ho#C{oir{ON>RIk^WxnG35- z6t7j7!W)Y$xe(d%dEP_VSb};L(pxIbFG|(tA#KaP3g>lq+Z5Ix&s_Vb{w>6E!zlL+qx@zVg=~&ocJ6Nuqj*Fiz-IG&U>Ie} zFiO=hO4Be(_b|$rhf!`HM!9PkWz#Uq!&wx3OTFE$r_`c>&koo$suwVKWz}oLtgr|CU&PKn(lXRAEq0M-_&gb5Vt1=R{OtgfJgt zDl8$$XPgRS*uyZVn+oHM`6N3UM`&kXTGiJ8-vXan1?7UeGu6?g8uAxQc-5O^j zOUr8Sxk%(8n;9&=%dmNh8ZB((U(@hzedkw2H@;6RdzKVV?fR)6Y%AiC0=&e-NFRsg z%?>CN(C|roEYUuE%`~ZJI6*sR+1b?Mqj+#nC}n=Omp(K=pHsv}mqT<#6ef}kVo1Ze zvLYfL1?cW*rv#j>;i+=wxtl&$!Z9yRy3RQ>Wk$Db1=aL)c6M~(31g=6CVLq_nCr@s zRfS(|$VB|Cz>AEUlg*)NZ5@p%CMG&uFJ0|7Pg|pBh`U*)nl9yM+6!{msT==wJUS4rH5{xl@?unHi8fz@;^+zo06O8;G z_vlHaQp^(k7(4fGV+M;nygUrI?h#Z%hW}d%cf&o34(AX`FY&oXQlf4z#a#CTmUVDD z{j#iU<&W1rniA=T>oK;^mO$6PUiXMf^trgdj5^$cy3&QENvjn9*QI}-smRIHjZJ%} zx1^_z-8MA`wY9cQrAk}%0|=ipyJq>p@ysFKq40~;R>tl!@E(_=Sc zpX1Qsm(qteA34+W`sSm7f-Rnhg8k{oH@}_RvizN6nR>)~BJiz#&-QfPp-fF~@K|8| zLxJ^MGBr6XpZNTgOkHkYba$9slWT8|nwrZ}n}0mt$FWd22I0Ihm?)U<_>hWMJb}V>6{l z@ptKp-GTK_-b=+#*R8#23zxla&Ec0a6>HLudp6_G=C=c=M*-kk&*pU1uE54Cyn&62 z{4MFK#{wI71lB*?lJ0q=?Ap+c&PJZ|vpix_dKqgXyYGo}GQ;VxB`p^_QnB z?#|S&M$B~G2G1LPzD&jLmh`yG z%i?JBeSxpm9y@ky`PN!iE|fN2fr6rphmcVmg(rMu<>6Fbrv7d&+Uc444S|hC>E9Ln z1}a?eV0z%dOeC=i#kBeR(-k{cZb_Y$soRjL-!9e5)c2>i1vZA$PZs>H;NgM?4~$17 zj&qRn=wJC@>ccDyWUwjyJEWa{uwYxkV+US-@7S@G^*ejcS$QNiHB*l!f`Gt;gk$Na zs0_bL4-`CD@bG~h;LOya&9(+MPG+7>1)R{6Nb0eIfdgy75PT;1R`A$?+X4ITAsw;% z6ARlIfi^M%J?K#|0@KEt{{IV>>Jdow2uby*>Hq1SfsIEqv&Tb?MQ6*?RclgXN(1Y6 zrt8*ho8~8%4n03ppOa4IkL~kcX8L_!#dhlS>GApdC%t>@82)Ce)&!p+CNdQM%g8wN zRjehZ{U?J1Y0=yxGc9Lj|L3DGpS;R_1vVz?*QPJZr$~f3Z80TPWJ<0ok6)W}*aZ$FJ`~aG<_4kNTfc-~9KjFPHJZsJ=8#|IeuJ`R`j_ zF5_QU-@06*&sA%N=(B0xF;w5#G&ufu>+^*7tuL4HudDC-_g_=r9IEdXIV*Sk)jw#$|fWNY}rKu`0dn-ORGFX}A$7@+NY~oA4bzc8si8`r4fIwYllf`(c@O zr>~`vG=1$E{O@@FH;@0#=YP+~zsrvy!i2?Rj^*EfK8l@Q1{3yXrsv4E3M^Wo8q40@ zR*^%icj<%m2Z*w5TG1ecC1zE4!GzEOgyezY<(D$`hgLq5nuy;!>G#tV0DJNB;{dtn zNH1>(u%KZt{|ev`fqMW-PXV|q+g?-s&p_p2@N(gUC15o%1jG7eD#qfEUHx4!Bs&IL zR>5CdesC;|4v8jx1K4`V%my}AvH?k>+J)Q=4=wP}GLuf_Lwu;^4 zYPT%E#M)M|i&pW{6??Z;kRn(;w_8Z?^xg&6M zfA9%7czdnD&0B(Rt=t({`7rr(6)-S?jipF`C-~ zmJ@ca^`x$a8;6+vffe6CFr{_u0dB(;H{mzj&j-@mHxK3(Z14NB$HMRg7k-wMD@$9(#XY1GUn7?P)i{O3n*^0F-CtDc) zEA~A*K7Y@`eb3Yn?pgSv%>tj7xB?q{cG_&p14lRhWU3YI+hB48oP%8Vo=jOnC#W3b z>~b)1&qI5A`uFVE{hthWzwq4A-8-IpY0oPt-wV$Ve($s1)YZ>a?0xP(pF8^O0sLNc z&9l3MZyB|LW0F3^uF3MFR^V$FquciR=RlA~pO)|UmbWaA9Sf{H8$t1>Z+zvzhXL+` z8+q)&KA>lJ(|=Af&yF&pLDtXi`CfN$_ozw~9CEO$Pjw$&?+VD|(1C?W_SxMJkb)d& z1Sb2z^TTSIZ!MGg)&~O{8)UxqdARVH=sldSIM|Y|`*)f~*%POAX5zFiQ?afkz3gt9 zJgsvkPds@{SM3dK{0-vUX63!W`sdSi`$tM6UBC9G0kTe+Wow6}#d%30>AHP~U&h2V zy*ph+(*Vr+_F&3au({74#}q5Q$axr`a$2BuIS%ZaR{=uGCc?5 zJ%&d8wbT7H#<{x$OBt)5o`(i-KI?4F3)S3 zo~?cUQ+-vKYZV~|vGD|~-?NjgPTfw=lj({LnL4nY9@rR}hUra3f4Xj+X8;`wM*2!b zsZOJe{RQuM@CP)1S*B`J!DE>!Oq5;&yy-!<&F|%Un6~k)!1_H1ylH^R@8o*k$t=4! zu<@CKqk;9017@l=+_Z(l3bsRR_~kj8S+*aO{({#7>$hc=?F+2`-6#sjFbs?D*)H7Z z(9AxF$z;#Ig59)Au>QeJ&mra|Mv(dob_UjOR?1E|?TaxBo0jf56n`-A)%&31%ePi@ z7eTkM^)W$Hm1W}s_gv}8%#38__1a(WiN~Vq5S3VwC@pBY7 z)3Y1Wr#XJrpyzO(|I7@mCNhIu$4%?=2QpQ=uogkOz`E0OZvlqh(U=!v26<}17MfG@ zM0*qF(*2lP@8*g2R+?n@`NNo4ldW9;RNq)hc%Nra-)*_#Bk;hgb8UEGJTXKzms9tI z@g3Khse1&?xG(-x;HwcBljU0zGT*M>Pd$Xz254Czj_Etky;nY$s>U>(DpZAal3dR= zj9r>k?ez*V%k9rklDt2OYsl!B_RJ}UA1=He(4&)(6 ztVcNW^CK&dBK;~(A6kL*e?y7;KZG%h`WBKOS0astW=TIx5-S+s^%BWt7xkcA&lUuH zDpR-pz$U0>)?9udHN}*_2kSQXqWtxnq{vte!OYxq2yKIMKS@br-9uJAa#7fBB(?H4 zJyTa6N-Z^Q3XQ1S>N$)e@_hV6PH1Pr!!EOc;_NDTO8fYM3#mX@38>fvBNEv75$c#5 zb5W$g##4}vXPXoT3lWcVQKT5@hp;a3I>z5j#lGMZ!M7ly;4^&}_aD5whF9BS?#@$N**Pn6s62LVXne{S)V!QBO z7aoJXHJc~u!gF0X?ZS7s@B=RVybGU!r3y{cg=f3)=Un*fE_}BOZv*~ct6A^#Y&iC*hw{&64U%Q(&7 z0Nd$&6!QxkUkTi6eP>vj9ZbizIIiW4^BCXC_*};885c0#!Z^s7PB!=Q87FuVjOmmZ z+M010<6O*`dikUs9$R2cCl8@lj7f`dKAUkJ<7UR!Fus9t1LK<+CmG+#cmd-rjAhGm z4`XL*(v~eT+W1xQ*fNP>fatY)SZ*DR7cu@<#$RFl2xIo_IX^p{(O7u5)2RaP82^Crg^V9yJc03E#v#Us8HX8Vv!)(-}Fm7h|z%zhitc(+@E&Wt@WpLcM(Ql7FiF&tkgNH^x}PPlmhD zE71Ch3tx7sLx0DGzk8ZPr)aj$xbc+JiRS@M^$HjM4C7xh{RS8Q4N|HOqKWW1T_ zdl+wF{71$Ej8DQ|S+BK~@i~lnFUcwcw)L}?>Ho|;*E7DA@z)sN#`sRgw=>?$`1_0x zGhWU3^bb&8KVUqGvDAJpW6Adh#wU1)>HCaNWW0qjN40*B4ZU9LVy2IRy7vm%`W;lf z*SeDF?=hBuBY8xZ{yzRJhyPcfAbbn+zsOklpU5Zr8m7}}&t4&0-+}7)TK~rMO^hYr z5M!FD<8&)jq*usR2jeYF|F(-h23@7sqDeo_L^75LhZu|fIT>B3SIAa7<3Z;Crily!%aX;fP!c6p94>JBO*Q#Oq*BM_WJdCep9DzCOwVD}!iScI`|AuiV<4;T`o<)ooGQNTF{fxiB z_~a?XBWH{18GnuGcQU@2u@~mD*ZOD1mofe!wQ zw=q7#_)*61F(&!`kp97SW-0McW4--3<66djWkeT0Dmj(#MyB^NzL)XsjPLPMI%CU; zM{qIY0j95I{As}<4Y9JJc3_j{3_E+E+e|&IgC&7Q#sGP zoalnf8Q;$IT`v4*#%qOMN&JGnRfP92eG20j7&p1_a>lPS{cgtZF@BEm9iylWXI(+* z+{t(zh84J(mTH?7+(yw#yHyI1h#H)z@@iFwP%7vFOzLe?z#`to^PctTu8Yh^q zrnuFNBaCYqH!vm+%lah_q+tAI`W_diupiPtxO@%p-L3JA#{;j1KbeDH6AT{9A@od# z@X$}ftSF2>#^+Ro{&9LFj<1AuCZDM;K{}l-}AW) z%M7M6e9hoo;O`qe4w$Zl@j2Ilz5>579P*X021cC#^njs5e1;z4rzq%0!kWZSiwF*( zta2sbeQ;$jQUW9TJTz2dml zsknsa**j3?QtLwOG+5Se4JMWsfO|ndgq4wlE}kPU9{*g5JHeucKb`UUKyvk)zxi{C zXJ8Z?Q_zS`vZ8AccbovOLEQgJ02j3v;fZqzFY)aJt^{6frF^6_S2OPMQG2yAUgV?p z`W)lMKBv8w*y;mWE%8ylUjz@e-Co>uQQJ{Ex6Bp#^F+jzuzGy~{JmqY(EkINF5-u) zZT)<%&<_w17x8}>fBWYO{U8x>5kG146LW?BDiLuJ|C#vv>|CM0PDEV9e>VQUI#=k+ zjNlShpYJZvj~Y5{$k0XnKgHj%jl%y$rDuHiFbDB`-FL6zv`=OLME{C!v(huZt&016 z+Z3mL4=MhN?@`5H<94B+l>YCO{te&Liofamz2cjFuPOeP@2KLNeI70Iw|som3}FfD zJ3jH&3E$#7O?htjeO&SPeXAA!z;}n@@B4nN_y@jqitq4kRlLTxP4OMRhZL{zJ*xN) z-%iDAd`~F8!?#QE8sAfj@Arw9O=W(@w@>N6^&L?BjPD~}seHn^-4|EUS~J`eCbgU0~38%#W(HJIXl5xCd-yl)@UznSSba@^HSztJ}c z`ke;v1-{4dkZ89UOldx5Fy-|$^Y{98gZ}{2Q$FIMtDpb1ti#MRFlsG$Y&zLqx(0ER zy*)Mp57}F~262;(9W#&0pPi2FH4qQk)xZcmXM;}HAnsYXKLnnkV-wNo8pJ&tcisp* zM5k*IH;uCeBk`cPE;qWJZ}0-d%|~y@^J8rvc(ql|zE+>X z)b8Iin8xn)20LSS0#wV|1o{g6Jqzj3MdO_Ze;+gSbCsT;Gcnd4LoZbNz^GF|f7#H3 zN>5m)g8r7FN0dG=ipr4FB>7&Y^efa?Nx&P!RF1V>K zb@^$t?X%pVUui-0`AR_Z>~<&mbxNupf7TH)&s`G+zMybjYEUpHxS`GI$K=7c#z-{l;S8UU;r+(62wq^y!@9rHp5= z4`0nZms#7vQ*SWYfzL2cIkz1}>gSl2wV3JIej~LzU4yu(t$Rn{p|+-L5I41NdITO@ z$A~A6o326Jwr`ei@HY`R-)ghy)YXrGSED6z5Vp}^(&6m}lMe4O*iJuzxOBY;`U?C# z73t7r>+lgn|De*_xL&?y;s3bOMTb9N=w~Utjq8|a==n+)9S#}#45cs9`X;Q!E*)O# z(&0re9bSsE%9XG_>(b#HTsr)Dmk#&3bolcw9qx7M@Cug>f5D~0Uvla23YQLl!KK41 zTsr(kmkxi)rNe2}p#)MS9ljWHD7D(TA~Oso9j;^C!8+Uk+-r5P4liJOC-Yy=_+qKhCLO++d9E9#!#`m9@pbqoBk&B>;h&AbW9!%;N_jjT-h{aM);GDs>;zs7 z>rXoTg2AN2uNzD{>`MxdoqmGi;>rbm1^$}HWK@UGHuTZdA#o8u!HI@0D<7isRIf`6 z{Ztn}_0!7?eVo!ohp#d8xYBRa`od3k>G1bmI((Z;hrf?9$(68HyL9-6E*)Ou(%~Pu zba;(RhkxYK;h(s4c&$r^?{ewzPh2{@)}_Ngap~|nmk!_M(&6=1zn1wf*5Ub(L#f%T z?KYTn_(sOxVjWHc_gdd#9sVZMzs;%K%J@61!)uu57S`dP8caI;0P}ofm<~V8^yBOB zt`T^K>hQB8@Yp&wh*BO;hhIe8e0Upl*7YdxYU}5$!zZ-}CLJDcFzN6_gYEPa##5OL zI_dChqwx7v75H1qsb4*v|e*ZKwP@Fu4J zl2iFL;W6{6{MqT)IyQ(>9#4mJ z5jWp@+8RWK^MO}edsv5y4JI9)W-#gS9E0uj6NpP!Gw7tlFO1=zs>6#6{Y9le&2qTO z&|guy=F`094!`2k;e#$6e#NE3ue)^kkV}XECZPB&sJFKg&A&EO4*&EbH)#On;73d6n_=tiwl`XOMMx)B@rk zv`B|f11^Pbj5hi9o4;o=JzMvN`orgsz%x{bgCp?RIyQ*Bj;F(u5jWrRc<7yXR|2oL zj#0$Es^==jr+FF_f50z=LN-QdtL(mH&m$9@^TyXGv*~5Yp20u z!1IE^KHxWid*L3^TGolJ6jxnE?L%OLmV=i7u6*2tKLGxGtIV_W1j`BnueM4(IiQyr zOnNoTVA88*gKfP{ATG#!C9J9JqIQ6%6zLH0Mi*Y?!asCj;-m5u;=T*?d@JR#PPD8Y zz^kopF3;}_rt<7Jn94&}g80ovn0#8g64s5Lj|v37$#XXF8;H9Cf6qnwbdeu&F8+@C zjL0kFO)pTz0^eVp9vt02lo-ZlB)st3yi^o}uxYe^t={I`5qxe?O zt%`5-{7~_&o*w~UX3BH7mSX3wJ<_gkJ_!1KXVYR>6hZ!qcY=NK>M zw)>(BuVTD}>9-r~1^deTL(OYCtB7iSTtH~?Pt9mZ!qcYM1vi@wRa{+XAXEy z2M=8dywUfA0)gN3d<-~-xTLq9lO%xj@GQW~44vLiN*D2yKGzxg2}&OrRRH>YLqALD zhh6shZI=%J*>f2sh$~?o^;8Q4{;WSUKMF1Ok81OSXlsg!NHxr9j~E-cKw3sMpz3&hsXf{&6pc0lpGeo)_w9@F%>z ziqH4TiUOry;QhYRCwkW_F7!UAc%pZQ;zI8uiYIy>Q(WlXskq4dgyKT)lZuPHPbn_+ z?ok}{KCigKdr0vVFFlq)SHg;WPggv}o3A+TJx}oz?*)o4_R{k_5;x(UuDHTmrMSvl zr+B8fTXD5_rQ(_1FDtJ0u2MYH`%j9iy|*cz>0P6^+WW7HXL;{bTH())YGb>6oWU+sNI@s(clfB@uqwbyGjI$?dZv^gzeV{$K0jB%CV?d{?pZ}GA2JuHunTeetybJvK*8N_3 zEci9x)z&ZB&Kxs%EaIH9km&b$DX%jPc6=&(*OugbzxM?2TmYUG_*+R8!$tO=(z(dc zXDa=jdnM@KGxXI;9~drq4hccnk>?E-zb zq5oXz1EYFCf637IDgC$JHK6~=&|g&gz^EUAKBisd{Ib%Y^4r$(g#Lu06pK( z-%|Q-y)+k?Waw`zePGltKrb`&ca;8H?|qbO3#jkkhD?aG` zjN(_k3l+cN6)%#~f5rPbrN8R3?XP+1for-F)~nucD}K%UUBz#B?@;`@_g@sh;a#iv zb(fug!@EK0Z+hi4E2V$Ld%uhRE5(Ps+Z7-2zM%N9cc0=T-ajaQ+biCar1?h|{fOct zF8lwsS5A%-|52CCf7^QkTUnt86u<2~Rq;{pIK^+f#)YHa54-4cqMXus*L$YYk9y^F zxzO`n^a~Vwe3KL(^@bF`>n%}y)O)ewcfF;Gk9o@#zw4FL=#UpJV}c-&$zo$L4k z<6rZb@)Lt;9Q+w@sr73fmhWf!gFGfaXfTb5zcKg`;N1pq2Y$iet-voC+z=7y^J5?I)2q)qTj;!mz)m$?x%ln{fOz=^EDdp=o-Wwz`cG19^3aO9`e2K z9f8MvUL_Aan@8XwI$eXf&&B=F2s||2(KU#BBJL-_GxTf>(din*O>1b+jF67KwnjV^ zxc7~~Lv*?ZanHd0#}RmlPS+rA8gt(ofoCr0bPeKe!F>!oL(5F#EM0@RX>1+SNxG5U z7BsffHHbTnI~P1d(;+%tgSfwi`-~CNAv#@yxYyu5YlL)u1Ug-VxM?gd7=eezV!8%# z)A$=4frrLlx(0F6m>VB~hsIpG265ZtEa5&tp^;C?4-WNAV>8d5X{SJ9Ddif2q>X@uw7@>;J6cbNtH`pX-A65KGKX2YZCy3u(d`VcPe&_7yC3qo+ zC=Jn1R~+@9rMSeOuQ=*IPjQLgIWHRZM_u%|;;28NIOd zjxhh9_^j#Z>nY8*_HO-D~xQ?h%~!q)DlNo`=97%U7%Cv|r#$@-_#VsE3OxI;(G$kh49!?lT-Yi z#*5|aiBl$qf{~I)EF6u*rYJ0#Vl^$mHy?>LRKTpEf+cu#J!S)<@fn-nF21l<>Yg-i4@*$j(ZERl=k8*Tnu&*w>BWYJBq|(oHp>3iNR1zT2hmAc=6$3D2S!y4mS;t@L-4-NG;ovOH>H>AnV25F}&AX zz9~*$I1Y!V;9b`9<%^~GMFc0Jt5|5>Sz*c7PS%|@+6ciAuq)eP(&QTVIVam8&;wjgphUI^YmbqM3LtyD*R#&j`hf+3=%L8OneqO%(snpkLmXU_PV zH*#)hnBU&h>w1QFAIy7|)1Y{HAta%No zg`F+!jSKBuLLts(iZyLUWd#HYCRBsUZMAfEbhFGt5G%ZbXHSIV5yiu;DYz4Xy1Rh7COxZ1~!`Lqfj<8-3chv$ffSZ5bt$2j6u;XP~AkT2Wp8*;~Nq4yOW~dpooHlo=uht(btn3y0zbcT`C1~7FFs+ z-S7Fe zcCn)7gZ3tQ{6rtdcnxd+HyF8*x(&XCuz-wCa!FINGu7JB4%-qV$-uTycQR67p}0D? z)D8wK$PB2j6bO`%O(7FPK1DKxuk$Jq#)1pZeisHf&X3w47+qpBp}`|lmfFAmo~o)< zNHvR9bq1w4w>ufte^_|b`^nt2bu?YaJt|18NeT<4Pc1~%K%lyXqp5`r-N`1dl2H{< zFqRpL$P=Um@LUZ|%rvnzH;OO{CWxUX8d{2VXM(ZRpe@CBCTyY@Y7iGYk%MBWiPIq( zGYw*EcQZz9NiwfUp?(`1)Bdxn>>=D{>?-BNQsbZ(4InR@NZ07%pTwA1N1#^ zGFd@1C)5PgVASRo8we9j%nn(`F&I)%F)EYi5Das7=MGNH4w+0KTYFHAsROebKw@^t zVgX^`L2YQmr$C&N8#`}GJ|vJWzE(g2o${hyR0dOzVWCoasg49XrFVt_D(J9KkpzY^ z4Rq>ah6EUSC#ow{At~Y()vlSZQ)|2e@@*VdD~wkfkl|0M(ZU z^3i0Z53;+6s**d=(%RlkAMZj^Fi`9|c86j`jj2>u>pbfJ5!*tM%hSZ45}Hg7fjy|P zE7aJ833j)k8&gI6i@RD=7&Vw(tQD1FGG&AWjIolD1SH6+v5UeW7xVYH6JJbGLdEeZ zC?q^x@6;k0y4;n1wzp?LH! z77o>v@o$LGsroX$a)3&m=rY8*#cs^GyL^z0mT&P;m4I?}7f1ekR08^ItAyR!VY{^> zXmV<8EwHP($zv*xME;^g|1mWlvAJU+bh~s;@tpQ1YusHN{mUZ#zti9-AvL%u;nb^Y zX+{<_&I(!1%4#K&Z3|M*qzNU3&6znX!R$K7RaPsF3|CM*TDGJK4G{|ki&I(c5Xm|P z$-AY*5jJ(^%t|SW*kUe9P3O8ICM;sU~Y)928pmtB$Ic_wN_ z<-{L2VHDCZYfk0N^2-})B~7)ouE}F-Q&TuXZb4Js40r}t^emj0qy@g9J@@9pg#&|8 zcc?Q?a$q>*4wQj_1_=&~M%;m1#t3-`E^QBzW#b4#iy^}RB+=T0pzK13plMb}VcBIc zW1|VnE&>gWR6|I9Xc^E9txYxb39nR77p-6sAGHSlaz-`5;%Ti*lFivAk+v}`b;0OJ zEF=}Ag2u_C@dxQb6iLplthQrnQ7u*_f<^Ig4C|?}$OH`tW(5>G0impbs02)H>q(Y( zv~}R4Z7B|qM&j|}k`NqnPLaZEXO-JQ(Resi95g|-9c5CAV6dn-7B7jIQcOjFl)?@$ zrJw*Qg&kl@QQn9-XICT5s}lI=TrCDj$uU|I4#k5JQf_4sF%`@6tI!vmuNF*4Hhov5gGK&?5 zupAza3=5S8r{E$qSV+>xM+_IWCKrqP#A4Cn2!&^bi3ZtWrrIW+Nz=sBH2K4P)I|8S zAnB6bnBkJ5P>GSc`Cws9^7@`6#HS64jG{sKA$CUHq4HS?Egym+F}r*mq{ZW)tXNt) z4zf$fvBDxN&I|h`rosrSDYHY0<0T~#(^A#lp;^iH=42NZb78WyJyCIRg$>s%(++kQ zjt67mI6f6p)i{Tsxqjq1dYwDUhp97-BMKP+95yWh?JF+bAXm571jg>@-ii4O;bG9y)R%*v? z$$+E=Mv_`p>PI8slj6^4zwWYRsv3=! z;`q^6ajYm}_nX=U$*zTsZF3rzC`Y_F9FG;1z#rx6S5W$09i0n0QXTWV8ao%XHYsaK zQ4oz^Y^#o8?M}gVx|u>n(c+M84iZa~HP~RG?|DL)niPr!Uq`J?wL81U&SaM|#)I)V z41e4xISFSD&0a({(Fit-OwDJvHYYo(I@()P9SDqbgGEY=wsD{>a1$1_6}_wDGbB{> zS$srvQENBQWXL^Q6pG-pmm-()S+$AQ?#?!>@&tpSI3yak&1`j*hJ>MMk)pUQ%rYkg z_NO=oLtytvs&IK?GFmoVTpSFm{UQ1cY#1eLk}10dvFTPEGlj*Ma~IKQA1pzL6Y*l?Z8QO~2uxu(W=gF? zvc!s^y^BhsCa|&xUY10|FcS$E#iK?X2#I9}7zJ_kNL*b%9-W8h3En?GA3Dp!pQ2nt@ieWrdRBSR36DqN@Z76x)!Dx2OSSS|Mm&r8i+HF9Lt|`r3UpV}Ljs+)4@u-9jzhWe<3uVDs_n?x zBLW3DLjt9tt!UhH+ntAhZhA)up1t%Al#RN<X3aM_gfUiNIN`pJqSI%(B?5e} z;*xMt&{(1A-FDW&a0LFkJ!VgD>o!G#jf`SUH5r#LTzZ{Jh+JxTsK)(3fSZoVx0E#0 zMDqd;BCoV0h(?ro)R!} zjalkOjmxPSYUl&jLo}I}ULh-}uWB+T+M>xb+Bg<7?vr%k%)vCk(eQXX+wo#=FK6j0odJJC(c!kO>oLOx);#Qxws@2ij>nza`5*!l3% zVLuR591n5tHZ`bjYfQCtbS<>all^;W1&rGo!up0?0dZTWp&-ek$)qL>ar$U74XH?< zf7=PW##f>9vP8&u1tG^P2#Hs4X|iKsGS#)TuKl|9j>YYqflVul6nAvN;&DbwZ0_i4 zE}Bez0D0Tg5wh1HDS@%P$kwh|SS)XK635UwQ$5)Kq}t6&LR4_DS#PiwfCcv^EqclTiQZgEZ&0-A-qGd9DsIwzgvjC2;TP!s;(KyG6 zWJ_aD8`>MC*05O}J?+h0KqVzw8?h7FJef_dokm4lTWcpyo3QfOMD(%bWcICWO3n2> zX!psis5Y$}%Gy1dMgpT;l#^Xi&DB)VUP*F#MA-C*RP)Sv-C6Zx3JgZDc5z1{IUlYn zG@mMG0-}-HWV;<;6hOi>_f%s$Hj^pkBwS6iJQy}wjht1^qSZ6n+GH&w`8{amPA$loLYF%1+1B zIfClB(?KnVrBmWcha64gs7ir~Aqc8_F)G*{(E=5tp2HHd50j99hNWYaz8DpBr-OP9 zO9zYod~U-QwDF8hfglPl5Ng;Ra|(ot4oiqP1o_kk7brU&WBj71pevmy>NzZ(I2FjG zGi0J5g^EHPtRbkSt9DUTc35Iq-gl}uWKLvKGkr6Ps=8A{jfbbkTEGV=TbmMQt=7F> zA2kXdWd#q(Sqn6%tvxVLny~__IB95)oCln@d$K0y`jbp^`x6jV1xp=Sry0 zv1Vel$0^ql(?B7RhFAffvYRxFR>nvxBe7O?8W%L;%nVX7hND9~LKiiLgm8v5#cRVN ze%iB+g525I%yCg>I8d=EN%$z77NjlWO%~xS6r~P|2sl}UvrvX2Tj9x|6U%IcCxcEj zbG$McbmEyaJIRm}(VW;xhMb6Ie>WL&BGPsr9T29PSC}T?va&Ks-Q9Hfq)@W##(|e- z6pz+CM6xksp<`sBBa#3AO4bn-G#jfMMhRU`su7s6*fFx$p%{)JsRu#I0S7|5>pbjR zVEvdihWZw?3Y}}d@nM-9f&n#Z(?UM85Hao;#c5TSgG0g;g7rdU)tuQ#$dt_V)EM{F zqD5Gd@8}xV*Rp!Bs5%@a+FB~_fV(W+1R@Zf@9avpwBjHiY8K13vtev*f{G4=z5s=t z(%sYIVuc{E(+jdAR|p}BjT`CQwD44u>gs9Yqg6=V*y9-4<4^?WW@WRBv&L4X2-T2j zi%SEf4suRFZ7+s6Q~+aBN>?8x0?81oB9LKL!ARm#uo0H+M7(iho#SMkk8227flP8k z7THWv#xTdpFdsK5w>{KFz=Yb?IFyiDA&#bpg>UJS?IIj61W`wh#`gJi5ZsVNUfs5f z&h)T0IN5H^$duN&7IAVdLPfGL4Ama4TClzC$u?CX$w}oLAITR%4XCBexI@x1nHr0a z$s<)w6M+W`RWNQM?cKPBs$h{ZX2Bw|W+Mo;iB^@l#@VA4FJVf?SlSVpVk_-^a~`^~ zXh$_Y5GxTRs@RYYtV1kzJ-c}FMQuVHgwgOp>TX2g_KNlMVmrTd$NWUHRm zTuov|rLm?(4OKKkv5=T(3Oq%ZhO$%QE|#%d*m6cn#UoV^9tbx>32IDMHAV-$TbpPM zb|plMyV6C;z7&T>D3YBJ#%xZgn4S;9gwM5&?o<&AOC~*%e0ZdSEp#Gs0b^nX;E-^- zt^vkfPP-lGjAM5!HbObud680*w40R9dC}G%?|oF$JAw#Q6{8{mGiIx0b*E-G6pSz#jS*54 zlgk2)W59(H$-y~ZeU>vl?gZ@?qQ#7ni-&%0jskH#j6R7vku2S**^L5Y^ggL+W#gjZ z#yabHA!i#!dSBRX6Ioq2zWmhvCjD`?nj|G!kKh{6Lc_>a)xwcsC()VGIZFes%F;T8 zq{rs!xFy4ygtP=}wrhpJou1tkyl`=RO~H}^rDrsS(sOTpnfls|5qbX}Vz1Q{i>BD~ zbEGE=JnrJz4H4naas29vl8E$%j(@H+?Uj)rFO7_7cNXDj1uHYoV{x5ri(_xaNo8p< zg&U)oJI4DMX<3-URF{NjPhVZTZze6fA&R+AjARX4aqh~LDr@+l!y6_MTl&S)6?C*j zEqG-Hk2+yzof8os5RGZh?V@4b&5J}U<)KO%3ybY`C>A4?<)d@TsmA$c0!s@s!N^apFx27tXLpczgPb6;VFiKryxC;(p5( z2L<44Jh?8YC0l&n{NdVT%g1)JJDa57OoEpU=B%NWW;7@^&M{!|oXd&0X10qn6tWe; znL)}lFGB*DEg5l;m@&}+ZDC`3PYbqoaN+?^&5%@)4#rvz(+LCkBUk_c|L_R|c6y*g zc)%&^B$M5mICw_UMsVqHN||cFC+l&Z#Lkslfj!+Z#C~3E! zt-2UW(0<|Q0%={&2aOBWgTD(u%Dps06v|z#ANkGbZnXA6hSV9`?Obf#j*4#o^|QyU zEY!X_8MthNz37H*V^n2Cx69=_;NVAAr-sAi%os5Ol3GtN4&3~%)@EJinGi&Oa!EN@ z%#Nyv3eSUMQfpLAw3L^F%<2m$SUO>fS$qKn4a}6VG%hI6IT0iZRhH_QN>Zffrm0Be z$zclnH!P)KHOk3;Xzsi|C6;BXt&HMu3$Y4MtCKEhFEwPFC>>OYnjWs?8mb z1L@rPrDauBWz}V~%BpH47~PRt8+r&gxV)<=425x?wqdoW6Zf`7t#0gUTu8QX0=c&? z_2lPYX!#qR2Sx+^v$A@`40)88K#uGMlCi~Qsx6ypPRfg8I)UBNc(f*&B&&{97_t%A z{GHN{6~eAoTAt=|(S9&&1P%o+Y^-ghR~vvkj8=9Pj`n8g38E5NP^7XA%~WJadv#PS z+M%o|tE#T7NR-#jnk^3|$hO)9Y&Ahv?K4tI5(JllZRG4m9N%Wqkdw)e0gz!gOI?-K z!_yN{kpIYe;>m;A73E=W7x4*U=2=^5iFg9Jb*?&v=vcn&H(>N(c{{PCHnibHDI+nf zs;t(eEG>?ugNwUMLW?-%?50G@90&3)E}^CL%4#RJl$l&DP8nr}&Xv!ofY-wX7tcwy zltK}#{@aDbpoGPL`NcXi1#AEElln1xc$L*d5<`_y7IK{^H>7QHTe9>j$xXDI{h?6g zxXzg5d@4~hG3du2Gq?(_;(v1Mn>L?&S5}ukQ@ySI1eVK+m$3O z%~LGMmNUe&WC+E0RaaYaC1*-2?!*Ccb>rLh~C{J}oji|0ylvQEeomn|^mQ+_{jCC0p!g!3Fauf{XD)m!-oVB{V zhKkC|?5+~XK!%AJ9yLLAr`S70@&uN|fUsRL*vTeOAw+hYc7BXX3@H+?&2x^%!k}>3 zC9j-OW1j7!6?kSPD-$k>%40}bu0vTH-qwJnS~QpGv``KRTMBA~&LL*`-32 zAwgFK5Qrqu;Iy9wnb+9+SZON`_J?;FY0XHNbL=#ca56kk zN`iN9vApSQ^*7)f~IO#l9vyU0VG|y4z51K1tk;UQ=JCAtcBCDafYv5r< z>O#EUf~RMl6y%^DMhatta7+_9s1q2ZMP3pqxyx9UXD2d9?y*aiOb&eB2P+}mk=#j0 z&&N}Prd8;$8c8RNCuV0=OZ{Yx75Ug2Ms6`T9m*q`(H86IOc~v%r82S0Os45dI-P*u zsDry$csm+;2#@i2k}ovnDrLh^hcT6jS3AUDlm<(tcF`U(Qbg^CrpVKaPz3(6*v>B6 zy<}D_1Cjk>i`s?PQyD71FHT3Dm}^RgiMmJ^H6d-!4l}w!?mH_pF&Rk&qn$iE%aR7f z3wNTurjg#XSCxOhE0-rO1qp$wuxeG5*-U0>7_7SN7xl8GGyL}$v>vXn48 zMB=$4bd`n+Lkinm5Un9a49T1sp@_vc2_v!LirOSOGeTS?hGcviBE@Wyte;_hIN8-1 zPOzAvJ@(pJC-_M4G}_C`8SHv6nk9A9Yp^IyQXdis1*8OMb|Yd3*HF{M>PJ?q8_zg} z7Sql$1c?!pIvHw(HI6Pmh5&^o9}Gte&@Z?Z@USg=4&+mc!)A_#yXbZe;sIDneFki#Xe39+aYeA>2?=r}P}pIC^kAQO87S`X&4#q(&#+TTNO5s~18}W8EYERQ! zjkCxPb?_iAT^8bIzbt#3K$=M0Q1QW~WriMu=Os=ukkC7%l(hw5jOLIfedJ1`5_Ko{ zK`NdZ)4YX-u-Vz$9FR5fmoMmo;l`t?WzCJSl=QqORgi2TZ3EEKPE`^Qr#nxcQ!vlC z>G>u~n8Tfi*EJkZ;BmOw3CBw?NOD6qbwtCcvh+AIYCHw|Ma~3*tO1^9qLPA6PCXmT zAT5ZvM%OqN7HJ=ZYz>~*1A9>sMX164kBN}2?G%CDp9SmXVxP&IS{h*j9*1$#s!s6< zSju2{-Y7Y;4wCWUysH;1?QU&qY{QeeIt{^)jbNUN%;=sYFB^hDXz?OSvPK?+gxih7WURhGES<~0i*cx>OKOv@W?URhZ;Dbu0{ zrA&(!Tn<`waC4VmF?*Jo($HZ>=0$0Q7sYY&PMdM1mcqCiv}(Y-v>rfW#gZLW6OVqi zchjRyS(c1e3-ETtBK9VxA(Z!1)b$YGAdAlWJOz7Ec#M1oTL#%MCS7GB;*c7ED*BT( z?ivFI1JKcu9U$tF=-{_>lrKm&K{v%uG-iyvPGdMIecFCCo}iR+XqdQ!=4BK^1I0O{ z5p(GXW|>AF)TaXPx*RD~JgVl!Gw~)9yx^nF?Xi*5kEjd9Ln5z&d@1Ub3uQ1O5{>3W z>Sz%*8uiIT!uZtDB5XwB=S4wV!cU};BGB2cAXJC4mU4DN+R@}qZ7rrj&9|FxFi-l1f({j z9j+HYE7rx)uv`y|CIbm7Gg6>Y^@Yi{5rfU(y#NOaAyLs)<5^V`5%Lsbi5N&GhLtD^ z?`#!2Yb(_B^r8urx{X_Sc7#^{Ndc(M@I)jBNfQhS6Rj_AY+7J?C!GsL94I_3OK|`q zN@57Xo8X~~2ysSxCU;v zt3X2;jIpMJyJD(jTLEtvYO2HpO7;q;Q3+t9bq?Ce;x!fZSRt{l3p%(p-kcl+TsMP6L{CAEI96N)szT%6+wqUfY2;*l>sAVoKvUO)6Q* zUJNzy(BGzZ+V=k-pk5K-GIURVzi#ng+8_RYt#S7x^d1#1cORA|I**8}mP0XVYX#t- z+J&9cVlaLde#p>9Kd7gukvNVtNm9lCD=FKY{sl=z|5s9frKC#!S5kkaq+dM)ubsnK=|47AL75F=f+v$uNC>Ol|qOnU{FP1zCM%x_LY&tC=&J_lm z;f~~A=|=wj!{%{gE)~ZFON{S>*rO)4W=!KWVJ(Lo8Xin>h&N?pjEdwiF`esb z|In&ZAi1k9fejx#hKP_iCs~BFwfO&u5RE7}KO+prSvCK=YKywfO414PE<_}W<$f35YwawL2{?)WoFS7Fnr?}@VHa8e zrdkZ35(1zm0-R|UCQ3r0SrT(!Wm7Oi5(;gMa}ef60-EtrHV3LsHsg(JN~YHdaI9u} zjgrx4V22w=LmWETZJs4A{v|H{B`*FYZhl++@ztUwY#TUV9>+M*tQq)lgEkUHiat_^ zDWxlD81MTM?11dQ)Y*ov3B+`?lxqBiC4rH8TbC`+`8F_S044~^f+3si^~iJcziY;A zC;7e;ZkvG=%4AO}W#ABn#`e8<6PO!jH>GQIs%!7=>FmTe`tapK8tU+xZQAq7JO7;K zye9KdH+@I8>;%hNhMWF=5%;%oe;@Z++&{(Lgd5i-^v~e2S4-(HUG(kVvvH5J-tyb% z#ZfkT3ZJi(&tD?P%-c&U9R69n#qKg#ODr!@-LeaQ0?6}t`N-6rP zqBV*(DcYrI_ebnh@;+*#n4)S$3l#M#x<%1#_{6cuV4tFQ6^%o)NazGb2}Rc^nhTK| zIV1;9kZNp*n{gVY!a&c3p2@=$I7$39`j?! zANneI9&Y0CaTr<5ordCN%4GbThr}G7OF_wn?R6-%#0eYhP#QrvltpO=Wf0cc;rSdW zJ9C60d3}>8C%7s93W{~2n{q!0gISa(LFt73rIaO|L!gwx3Obb09;6K0CX~Vyo=^u5 zT?nvz9{PST%#G_Rq^A~abO!Gh;X{0m{Zu7;*$Yn%QiY2cflcqfldvgPwJsx)6V z<-B2(k}L{+2c7r%-MdRxgR?;-dssugr(jfg%yPN>Fe}3H!z_Br53{Z(Kg`mVW}Ce_ zGa{LZ!zPTws610<>if+xIdIs-OQ=KZ7_%BU!K$7%X28P$*v{s2*d~O|)bjpTM^RzN zq&&H>10AAwzlLLZc|}Z;f8nI#g9dqdc-?w1&h)t_R(hz#Ei1CovZ@*RJ#HN)QZKv+ zKU!(UzcYh16@T(9Ypz?5C1m)&rIyw2*5%gY7MR%@C|9<(w^V9Wj2JWfPN%tH{FMBs#aVTAP zaGO6L9oyPZQQl2I_zUV}!T$8&-gmm*xHEPBwrOK2Bm>^j+or+X0M{K%A4<>mXX@X~ z^c=|`p@a1UnTmsHe?F&@9=)spx_A+c-`le=Nv>^$(^K`8ixLWbyL9P(k`OokyHpo*d+n zsT-TI;?@4Hlhf5X!TucsefLl}C0=A%zeoV5D^2Zo+)I@kF!e#?`izw+%^B!hBRD(~TuqW@NpZ(7NuJ>0`bvBV^#F+0%O|gLUv(@V&N5Rq zHdB`aiH!Apg=Kfz$|rifI|k75V}*-KjW)|vDx?s;wR zNam@i$f%Mh5PZAe3N5>Lc?Q~&;F^oyF#m5B}c znZpc&9_xa%taGqG8&RJXG*LX9i-bo}(hGA4FB(Z?oviTg#wTSUaI6w!Ad zbc7FQu`ql~nt1yT|H>Z^^e*(I+2U2RF!W||=!p<^(8*l1VE7RAwS{#IQ(uWKtQ0=g zxKsGU-4Y_aT}Had;bIClPH%5l(D>`AFiH%)OsEfkSjeiRk}=NI zA$@9E`m_n@)134v!)Sn+?@jwN5*tZO&dE${d_+K2V&jN_?8L@h0Jgl*|1@+t^);Q} z)K{JW=qq0U^ff~O^i?2WYI0MdfN9B15dqVao5}^`nXa+(M`iW|`Lk{Pj8_n?jMqQM10qqHLwqXUE*g9L3iieGy)&;$DEsXg!c^WjZb4} z5#GbunNEPyz&?1K#N+hXPX^)Uwk5-Rr$If>UrsMIJ$#V9l7p)^mqU~N8qd$B+x!ZP z?@rF0f!Skra&AHRAi$dB7WP2+VDhW%668aP)Kbon*OQ=O!Z%i7AocH>e&y8-2ynNs ztCID1To4*D`DZYH^cxpcS6n?~&0UjZIK|1Z_R+%|lUv?Y9vgffzkN%1YygjfoGmRV zFiEDzoJ?yU8oLO&(4X*soY@eq4MP<&TLh67n|=%YiU~=5|FeuUW(wKqTeB;T+N{n{ zs0oGOa6|)$KAd=n^)0~=TgpIcFzQ`BvG7?zjpO69GJ|ob2+`R1Fv#(%sc{!>jE)Q`^xGkG0{ z!4En3po6DkhO%Xg9K6`UYaN_)@V_{CC-5dC+b?+~?h_h4I(&yhi9)PRHkSg7XC5Ech(J_X@@`GCq$A#-ac|`vjK>eqQh=1^-EK zm0*TaeICaX))EANN^nH*V!;;+ULtt8;Hw0$6Wkzpo8T6~cMD!6_))=Jee}Fv2=hpRAb?{3LuE=Ix+P{kgPZvh5g0WG8 z&j!KR48i9sfnc@?VAbI!!R3$2^Y;*NYw8D)=#>uXFHM1dj;)pB%hH@Z&=Nh2R~6#{};be9BbT zwM+2F1oK+Q^DYG5Bvhe7oTNg1;g74}ymT=e(bF{e$37 z2-enLC0OfSC-_v6;p>7=6a1)PDeCw-1ml|0gQ zyifaBkpJP26W=2Fe|G;x zhvdJ(p`V1I(&zn1=w}Hwd<3iiITb_5^7)M5Lz4fC4*g0Dtv>JfLSHZVPl6v4{FdO8 zG35F@&aj@hNN|?mn+3mH@FBsc3!Z^t+2?&w@U?=c3w}`W#{{2(;fk>@c!}Ub!M_(= zCitTBnCAk)*9)F2c#q&3!P)0C&q~27XA<`b{&FF4LhvUr{q%YF2_6&7^#<4`+(e)E zgy5$H|5EVuV$z=#JRtbDf{zIv6MSBTd0rH}R`8z%-z_*3v%KehxP*C56TCw3bipHn z&k+1BxSl?5hTwX^=L`M^!4biS1s}r0Qe1+x_ ze6`?0xU)X5S#ZDL&j|jJ;4Z-*oy9zB1h)y^AoxMSn*^Uan|ZbhzC!R91>Y_BM!|0h zzE$vCxXwQBn}WY0_yNHw!H;MjxYR!HDZx`NBL21DRf3NS-Xr)e!PNCP`3Ij5RWkov zvDg}y=Xu;8x=ejtNu>A{G!l{FD6}ao#6LmQiczGigd*n3BFzEdma2I!S^V=hWQo0CHR2Q z%NCOUYrzc;{+!^Kh5j#s-xB;Q!FNuf3?IIPW$zVywczgvUL*LR;0GMMU+{B6|C>cD zt9Z8H_nb_gs{|8yUU4n+FuL}dS z(ESEin*CRnje2!HJ?t&_agn#$$K~F&KCbYt_i?ee&Bqb%7T|w^PAYL@4Lkcm!RMNL zGO+1t^788t{%Q0?JuChJ^5=UCpli?jrRa9PN8P?)a5nJE2Im4FGk7X6KT(vmpQv}S ze^)`&tMOQtALhwX2z;?O&BrzVofA=Sk%tgUK2h&-^t{DOdCQP|NH6s9Qr-?^=vVj= zbkw^Fby)ghN6(jf%N%+maQ1TQ?PAf@bip;E!?Oj$QQ=c+Fpap{U_kkdm~Va^!oL9m ze5hOE+U3M6Jg&+&0S|eNqT4Qm1O2S<>?i6qi46Q5McGqL0_j2i7VkYi{WFfuU*mni zr?)$LZuRmUIzkHhM7@=cZMS=vdcDssr%swA{fmOBDbM@5!5Q*vqFrH1mJi!b{LjnT z_HNmee;9ZO)*Ou4ZsgEU)a&tWHR`Q#+TP<)=ln#yUPljWL=R6cr<^^KzF)8%EfZyX zx8%}(A$}hD^S$dlZaDl2c*xrzvYm{k5>wBo8%&$$CyM;`Lmb$1pWLIRc|MD~O!X7> z`kcPl<>8N*uceamj^k(|_s~)eC zc|%ks_;Z5aEcgp1$He}+(4VNFTe{z1_SYi@v%mHj9Q4JV zpz0^;-Q~3XPVZd~{k=Z^N5}ts%ke+|=$-H9`6tI0-R=09dp%6C-qVnw5_R$Oyx?yN ze#Kz+BZfEfd{cDtZi6Kg{)||F??d>9X;MDa3Gv?|f4+CW$Gy@|01tWhNxRAo4t&M^ zS`dGu-nYGw`4vT3_60wr2V--)mnT%EpW)+SXWsmd)AnI6=I8mYH`m9*G7rv$Je81* zpE?Kgx3y2+YWUKUk;AH^+)L{1GL4!?pX)kB3{{lVVd)ni6@1KB& zuvQ%O@6$FrrHPj>bh0xdPC~E*Wh3b zzUh~ZdT%=Q9&_fkj8I@R$DFw%BNW6-q0q++rzq~sodNtk)K%%dA-3^^!L~B$xFYxiyP}s*G43+zMTFCnUsQ3O*HRyi>*(yCn~%#v-}G@s=q?}6 z3he-X9=fXZ&K0|TQSjNJQ$T;yV3U2qoV(8?eV~r;tuEfwBFJGryc!Y87lP4E(?|VxG{8*kC%m_KE671nU9yt z9pC(kYl_e^haU7xQ)rb>Zw;;XadW8G$Jd0``nWN)-p4CKpYw5((~r%eq)%@Tec8vC zh3@e2<)Q7smqVYG-lbxzD+MnWy{#3zNcxLKM)=2k4&nP@gV{&KTah2v9ihUL;TwT* z-64In%iv&)cRT&n?et@BD2NHW9iP_g_~&(@>84&>n>b^CT`13|e=c-}kNccH?RUn` zKq!clw}c{o{((?%U2whAzgwOD-4e1_-cj5#v&b)-3|;EuFNUu0@g`?HUhj;@txmru zLLGkoFNNYh{=3k1KK^?dkNcp{N-r)t{EgsV>ARN&Un}%bEAw3I+y98+!LLL3cPjxt z>^tHdB{W=gv^0l0pB5#}!#3WBe=VTrd-sO= z;D9y)4|(5`Hh$4yw()j@>F4>0BEKTV^j-W!y?=G)>+ghux!}8w?G1;{((K6ppfl&* z7n@Y9!5{dr?Kk1yFF?=t zc82mWalQgPM`gf<(-kr|;^@C8b9#xD)p|Gx_&72{++?&>rH~5@9hhXpx(Qr zuBW8lZyOxcyU%IwKBwNFJM}&tDu7%&q^_r=-k%!m)?17`hd|Hw4ulw7z9n_-mwL5b zpqo$BJLuH)j6Y6EKgG}UOz1S=oK@7b?iDhLeM&!>2YSBuTqqZHeG+)cdsgaNWN^^N z=bU{IXH(htmEt+NhtyLVusZ%i6XyN?k`owWzC4>UvG;`m(`6TaNl= zqu%RM?;Xff>AfcO`wSl6mPbI(_l|{@p9)<84|#7nZ8_%f3}sj!h-;RNlc6hqqFyK? zu(6B`D-Y%8HP@@ce@aFd_`e$$c0*ofMi%HFG1%shdQ+@u;5o&q>y!)>^=2Y}CCXBu zN`q|y*2VRlOF_@~vNMKI;9BATE~#sa!9iWwwkYb#cItYM)CE?c=Voxuy;13llHn!%gmo&+B9-Y4}U34A~|pQ!f%r>+k=I{bj6!w+VFjduWiD#6E= zwf68k(DS_yW#l5$o4`Zf-%4HYzD9A-#t->rquz(5-oHhjO5`WcPZ(@7kw3?2Iq3P` z$20Q4f3fg9!)eRMZFaQlOs6epIc+)9Y0FvCmL{p|48N>xOI+&uL`EU%8kD-umAdXQ zIB3f!{Ib~7k$UeHp63ev5rb_e+m=0`=i|=6O7Q=!@C-X`;T?neiFy&IEhSD{B2HUM zq%E&XU17hhZOh5+tgAeu7ImEoJmi%*b(Q=1quwm1uGvmqvz)qSOI@YlQwcs+PFvSJ zsq3PQ<)~|=)b&ZJYn{Q_e!DL6%SOE_srP#1sq{W6^ji$JnXKOK20h=Ko6!aSj{^^R zG2y?@;B242-kZUnQE$HRe-3#nk)O1e3?9$_&!FdfpU&t5|M%bmrP8}X+WsMf>1WOX z9s-@df}bezDGv*2{?!?7+29&;b;jSa zAU;v76wg!$9M1@@AJ=6B*N=an5%cq`%b4fm>oV+GO4R%Nj3$Q;H!Yv2cWuVCKJLo+ zf{(AwxWUI=8UO0z-i+`0IG(ZB$GsW9@^L)lRp5=#PbKc#;e7FB!K=h(ZWY`ty1Lt7 ztN#(hgI|aE$IM95hrr)K{(Ns^#@=^fzW{g$_X5#oeq}KG<-ZILbi2{%m(5OJY!Q1n zse^L%NuH?={+NR)3T0qloCkWo_xTJiwnl-6a1Rn?SYj|`SYdD=1M-_s6lH@sbWp}V zlcL_2GS0(yC(2fu`X~qCF%wAUU%>*ol3WrQD&|m=7FB?eLbTO z!d(PB8SZjqxXY2@Zbxt5$|ykD7f`kmJXz;!4$kZf=uD$LjQ`&Y zdcOB>884yY^MQxFe-(KyGMMtz7@P~tPZaqTDYoMXdqa*q-w}D1qHHC2GJl(c*EpDI zl&28?Hi4e+ZO_PiH?D1ghj6bH?fl;iraTWDoD0lP6!{eqKji4=5$U5JBY&m2=W5i! zzjH9lQwHkr4bbzk!&D0yJ_JWKtJ&w_CF5l{R-+W> z;`p#^wuiSXbxT&fi<` zpx)V~B_+ir$gb-4I}mT~M84>9Y*-!Z7^2VKObk*=io%_JOk}#Bhu` zAT5Gauer0A$1_Wku>~ZRGfA}NrkjpOIu4sc2AXAi%Q{~PI1vD+?cv-M^JYaoVXJL* zBTm7j$>PQOe7Am3&=CvWySP~EwQSw0(ML#zf}Lt7$cIiqCLCCgOlvyZnzdCtx&yWI zK$30FBwho-T+R)yH7jLrJJY0|mL*uoY4Rbm>+m&eacpj?sCVA1|teN%5+B0)u zTgSZ1XRc`Ln2Aj7Z7XJCykbCitXx}MG_&~p$oVBq@c(b?!0TO`TW0peo7+11a{Ir4 zk5jg}r4@yFx>p0+z%yLfM!b4-EiJ(i(bFKJ-D@#&4UMM<2L=6fiFj&cXXO;Jllsp& ziDCx6^1|9SXb+kSsBE6-^sly$cr#oG##eKjD!oklv5dXeQ+{o4Cr%a-8<%5cx?6BI zTAEvJ56V#uWwhL&9L^hY%i*VW#|@nwEjW!w6kdkzWKpQ#TzsL$a+JY2Uc1AcEiOZs z;P|;xD;AD{lcULvSon!CjQJYg{x2}~$%YM%OQ#eDsY3dlPW7)=9!Ecv*Te&6q=RvsnT{wJeS9^VCg+>+#Mn4auWG^Z z(t(MAg1Ics%0OC$xYf|qO*30_qj{~ZIhcwxo^2=0jHd=|J>KkXiR!39TpJWN$LcX> zKr|;&f!Nm5j9FWm@}ND9CjLtM>g_-%&`c%$m5l!4DSa|)XK2t7hcx(Gu03YwcfP{C z*Cnerrxye@TxxTx4}=S5=76m87#u06#YHx=dO)yX=73BWDBd1aX+bM_ z9JY*wphhQA^cw2_1WInwlQN$?-2oMPu|!$kQZ8HO^u{U?(-9 zH#Xt&8Yepn-MA`-NNe>lNFi%jNh$E2V~QYi0yyhT!lT-P<0o35PO+}qjXQVcgJ$&nPAG4!)t)s87*|h8Zfp|fG(;MSh^0!y%|D6tpgzRu5;hZb# zW4N@%tH;&H!R^%4`b7G+Fh?dY-04*>U$i(X+5Jhbrq-u%iVJH*E1op!r>KX5$Em3e zi1bcjMz>^+v^k3w)u<@EKoJjEQ(ITRSZS1x4hk$TTZBV*MP`+cvycdgNs6bY&ab*8 zD%Y8473IVif-t5uEWW&EQT3-9>b1B(Cp#C9I4!w2!myxe$pSRoErjNs5hpT8bL;q0)p&0=SFo6ms=&8YR2MFh7qF&Ff|G-TEK96gc3hZH2y-KZ>I%>oGxUjiqJ9ILIAmhzjFsEV9(&I;BNLttcrf zi4+$X8}8MeUF&gP>nhWZ((>YPaT(4_)uP?a3p!dm4cGEWB#cumHAzn!UD&!Z+S1dc z8OkH&XsFey$$;g6_Vg@;WjLr)*vqk`Qnm~Ss1}zO;krT-a5B5qUpd~MTV5WnF!Ijp zZfWUA(|uVn4wprP{j$hl3nQ(htfIKsD8Hr`7e$R7O{ym_EiK03sTEr3LPWnX$JH&S zPs@vOdTL>5QJGD~;oiaF-P&ZFMqOB5jDuW7>~ZIRGYgK_rqW7r*s5f?1WQ=WBEB#v zFDb%ucrgy49ha&d&g4RLSdk{1LwnVH%F9bjB1}(9Qwy?brrD;P;c3eGJUh8C$1dt_ zlWTNs8B~g+rOS-g%{jq!E!Xz8Kz)9PqM}k9$6IJC>M5#T9QEZxQUnL-O4Dj3$rn$O z(n|T#Ns^ULN)@ZFq%Q221Ptq{Y)VN*Sy{yN6sj6`P`sO~*yLJl`oRw2ig0;x1zz85 zOdrYCh>(J4sI1TwtV7V+(t(9yUkeq*9LP9KRweT@NVO)h!X(zWG_C6BZ0}sTUQV(F&+F zWTe&>Hm-|x^sXlTyl}y6cyz$=epsel@teL2#q^*qG>U_rac*ZdjJUfIUave-R2(TS zG)96W+*j8%HFk7hb_-J-^s>G>TiaWj;%#eM{2Uc9{n7~XsrU;zuDQ4cCt0`g;8v6` zEiWlAjM#Bgzp4d?aJOIHxX#Z}QBqt{UdRK1rTH=P@9ykc)fw+x+1=Q+s;$Y-T2>f_ z)t6Y)F92sVsN%P+%`;hhURJKAu@%B*mObXcU!SeqnTg`2ceYv|pbpP^Da zJ8;N6PNePungzX=;!JqFid@@Ky|_Nw*3;FFRi1FTr~(@0k@Gqx7y2p1u(U`a58IZM zsvrgar=%Q?z@$intE02fv&AJP;bPzaP!S8TVboIB61P2w?YEM0Bka8H#xyi0*i~Iy`!(=R7bRaer1LzFz&ZaGnrG%huzZ29rS7hdIVD zWr8~k32S&5cNz+UK36y#E{>DwOVV7ZmQMGfjK0IA=_SjH%5i?WipKQfq6z7xcAPT3 zG%`NDB4S%0(f#=3GPOr2Wukvp?Kut_xt3n>X;lwLFf7J~Q=mJn$0Y`RU!;Y{1rF6F zj#I5bsWy^N{*BiqQ6zq zHN9&r9oy`s#n#DRQN5zN+ig^(0=`RpcbSud`qBDgBSE>75-F}Ij+8{q^jzVjV5o;N{Td0vg+UT7oFWyNLTsoV z4m)XK6hhY&8jfK{5tw&yZGh;?@^n-Iu}g|d!(rRgVMiI^aA^^m1_!Av3p?sSZMZ5Z zDJf&yj2TOZ7&ESBH`H}CHjTGrS$c)8V7|U3-bB?P?V}y-PF`B^XCD+(en4BZQ>{Z1RVj7#`Cbg6oGH9?V7qq~n!vJu# zSZ*ya81$Aq6j_RCndOZ}G{vaIOaVe0H@sz8nM%PLfF0ich4aG3CIn@jJ*#--TvAqE z6e%+zE^KS+?(FGojUybWz$hyY+e^E;&i2OcHfWJC8m^5c{zRp9^A?bXsT!`|bZb4X zV^`v;3;qL1B^5<7x=jme+Z*Gpo!zUgd$PaBH^79gMOfdk4bZT4E(B>QoJBJc$RiUu zrGmfwwv3(mRq3)Ufph#MDkut~f+CFy=CyRL#=$Y`mvmgy(YdxmDzLP|NJ(cmJf2kK z6Pr7`n+s=g44`gHouqm{NhL6z7uDL96|3j1ZNW`wUGZM*f3kIpTc9cg*kU(W3y62O zHHiRqTxO9dRw{?pb+-4$)AKo(2bks98OCVFT}kO|P;3@!Ac!xM8ADy2@w!zAgk81N zS)vJ!qb;qCz3u34NbRRB?(FSo76E-yw5<_4k(_Qh zTUH`eh2^txCZRM^-_l_di~(qxUwgcdKLpj#* z&2p>5CSuGs0$X+2psSrFN@atEd~9I)Y)ss!;zZ2yY6RWWQxu4Uu9?6GEACi#E)_-? zS?PRCnWIPze;lwwIuRJrQ4^60~yyBe?@YcHhl{uA`t5WAr6x zpvwpCoWKW*{&G`_RkVqWjX+R^2!s~)lm`N#p%WO%hM?TFAp)iIG0v|P4RrXFqMZ}? zR8SzpXWWH?3RMbqh=rh)PU}k1*a^(AydN}g+%=KmX2xbIn(A^xizjjuD=;`PlS2++ci_*gPm$orOWkO%|F3_sf95n>(;&swAu^f`rvhIC`Im zy*?0erwE*?Ps9Qpi0nm#@vcl|#;D3@RNr~Ti$U27OR##Lt2 zUqZwq{8a zamQ zeLF2YD%z6tuAP=}P|n=5(^3=^G|bwFlT9b%yfasD#oO3cj<^p zVPxr@gDB4!9@jinv*pG^m(xQ>BLDx@Y@jMwHdZ%`5jsJtQJC@A<@DG^<+ugOk099Z z2q1L0u4rt!2J6RS3>;gqDh#fbCWaMq5ge#7n^wlmO2oWl?#pfSLk>wPW(w8|jaLh< zMv9DNW~7$ONG)8`(t-GQ!dOci!D{LVl-9I0Av{I6tiuE3+5t z8;hV~0AVb^U}yLAwmMm%2<-HN9OxBFD8?t$vP+O)_h}xMnZp52KMO&Gf zSFxlvd1IR~#I&uh6=4Hv4xb&6QHSLP(^$EorM#!j3^)nxFi3C?J+F>*vc!T@TBucQ zJ%E}NO($5kSN`@60xUOCnWg&J0xc0Wqa!gwgFZp1VMeWuAY^UTa5APImM3Q><>VVl z8AiDdf5S+(>bd4>m>HACnie~%a1yb=Of3bGqGO>Fl(=FUzlAMla4MOsfrvn)8_LjP zdew5?=-t-DIoM&u#a$hu^e-hvlZa#)Va^stC44>z7kth(deB5HEE#^(eDP$0tqux` zfaU515ReF8XM%C%wEe()9DB;kCy}#57Acjb?NZ+7#jQWt`%c@{c0{(l!Zo1Djm5WV zcw?uF$9Y*-T-!gGY~PkA0;<4l#$AIrJh>VqUBy)yxZO!q;G1HpD!|OyzGrp0*^Yt} zrqh^&o4Q<4Xay!*$f!5Y$?CJ-)8jIA`H`^(2M#tgi zH?~48+<0gIej&Leaar0v(ba_$>reZ{=uda+1B>B$gtUMQ4U;$37mkjdsx#6BO9PH% zT&GZe;;v388P+7UC&aRy6#|!^?Fw1AII*Q*NrC)qOCg`T^`(9bvzC$X_#?!w)s(2E z*z0rf(*+(^Jlhcw85}2Wt{RDIZ~Xk{@U$xJL__FyUt;d#+4YRwN%)$prdO@5vwepGvV&gsrES`&;$Y`#1aSw%VMM!1P zGOx=}8?Kg&I;dt`Xn?l5v7@&YTRXVp0Z+|PtKfsVR?_?n2IP-m0RZ_YUNB&%2R4L| zrvu7Ee2WpoWqI;KG2D2@Vv~e)xJ#KWkUQ&fKZ&iIw-}*7dIVJpQ+9eU;)hVBxbFxp zac4aWJ>rTC8oC zs%^jXtH-n|eE%9$;P?i+=!R|M1W&xTrOzrdBG;L1y&@6fB(x#Vo#nf({l+v34#fusKyEgsO^n&Y>1@ zaV{b;lEWqJU$B&d)u^EQ@wLnPlzNsq))+P5R^mcDt!`{orw>E6L>-_?thPjR4Xo5E zpQ_{2M5lA&omJ8<-N5Bm<^R{)g%?N6uU)*zJi;8N0}~^{ZV!{{7gt?UH+RwEh1zTx zc)Xuk?mM4XwQyloZPntcg>{;Y;fPMhJ|)B8>h7ju7)$@zH}cg6U|Wn{c7)^J44)t>(*;G!Hoj8T zA@}Mi7I!G?sutGP#G=(p7GI_hCg`?W0k)c;tBwWn7Aity5FdG2BW~Xo)iB7E#{lTq zMQyBcB0p6H<436zPaa$rt1gy)(U=f!UaXZ%#03oNoHiBlwtU@h!0aRX4oYilxZy<3 zVCF5XsyCdq#~Fn6lohQJ&goqV&Qb>YE-B+udQELmT4iRaC7dBMY_57i3{j5=u91^& zDHTPq`fr8Aq=dzP{UtUs8*BgiljB$-yqel^%+O@W!qADefw!q`-TEuEHnnbvhl(O6 zd{)=5d_rwLGj+y{i=;LkPiPx%NYdK0@e02s5}t#3(;tw`k4 z5thb~$XflR{MB%{XGAejU0^t_7^)TS4q+@KDV4JKWT@e@-)Pg}%;~O6LTR;ew@9q%& zfk>|e{RJa#a)G!_1>JFPMRceJT3Z*pG#aa`7MZ!1%Hj}PJEilIAhS1z5s(8SWr3dah~37M`A=9Jz>?L%%HPz`7+ zO$l014QQ{)fcM?avgLsrn@|_7W+Xtwgt)K;w?^v)k=BJ>vn4&a(OR>i*|OK` z+&fEIsSkK((Z*$rFAK2a$*T=04)2?)cEfYr!Y_LeQN37~_51X8s9(IU3>lB$K6cNf(xTCB}g9b;Vvj>Voo#oBaEl)v-_R0Jwo^iaY(@%2^xNF|F(xriBw3r68jXj6aOslQET}Wj_HhMX zveL^GmzC;cNNJ%%RXg6+fTdb=ml?D$4k%j%HAoNX-(XFD|l^8y~@2*VDlFq%|P10XIGN zHqF8a4RS)Gk`p>mcCeoYuBxw(ncTX9jq83ZA}<(P zQ6A%-tm|8P;#Iiuup?ZmZL-lfZXrZis0%s%rWL$3$E1vP*|kn%A-mV8$}~fR@JTs{ zBbSRcd3q5+x?HN++YI5FFZY8#Sgxu?7mJG|c*GMIX&o&?0}nHD2+4X2o}LXj=#6@q zDU1)oZJMaT4+6tn&J7H%Zs82;$`)n-Q2yDtXKx3{}Yeejn`8d zs=P1GpLNQeOEO%jt9H>6T6=n$u@#2zV$95BG!ZWClB=^cZ9u&UCpzjH`R2AXr_-^Z z1Gk!3l3u5D=pD(HsNN>pxw?@rg^@PGufUL@^G00ki%X)XgxeuWt{q{kW{HfXVw(%9 zHMt^&WbPSZt`bYaOl)$MT9V!~!dzvBWMUeU$}LIP&$!yv-BlbFHN$%B+F2L!QSqGZ zb>$3xJzScmbz^H0yaxkXAD0N1K?c0KQMDu2c-JK6N3Yd`XPk=Ga%UNe#0<(ohE`#X zqg!r6z`)TfLyimS1-%VO%+fT@+!`*o2PxgQ5S`{+0h=fk?6pLCl4&fr>FmOiFyksA ziqvqy2CbTG5~QjyZDPf6b`2MiBwGO=^&+XB6l8%$;PEd?_v<0=*6pz!WS=B{_uwzppp4h;=sue1g6-s=> z3YEkPBV4Tzl}5%@SW;vfUlU2Mu%uK+Asjy+PpMj`YYdo53rhIl3cFD@tb6QI3D)(} z92A#lq4{*LrI8L-Rp7JGR6J+HUh9|=C5AW4abc~RjZmC z;VI=kYG@#RAh!Xyv@`C>bGDxs;qrVF8B2Qb@VcLlC-9_VvlEV&U{G`8Hg(j(*jPS} zj26$veo=4%L2rQPnJ6jf4C=*M%1)0nyH;Rfk^3O@HF#bR*$WF5_1Qg`jD^*wD(jqP|c*S`$Gl#OJ$ z6j{)7xxQ=&3ZW`XscW>cu5nFERZsbxHo1q>rom6Kr{r};yjGLY9c2(k(48#CCW)#R z<51=uF5t9k`|upKnjOadHJZx?1zgBs%&HRbQ9{;40J+(W73mdl)lD5tz*rt$P+jdVWrulJ zFYCt0QBwRL?cKpy+~VZlexYk!M`b06}{Nz zH47eiY~OI^@`jsNSJn+@E_#qN7cE2%t~$86t1r21vALw-&5V*4(r8|Y-A5d!CKGC_F~K zK%zU{Fs7{v5oKrwpsM|(&AY~d!2xu(rYER*L_6gz9o4H^nqZq6CmJ`#sM9zO^5^!e zi3C;3@o5?onwL?GPt@R$Gv@k9+%jh#v?qplT~3y&5mocrMR=15UhvWGMr;iFQFOIN zNQ^2NOL0)H*2#z@&gLX_wrV!c`izh;KXtZhHj>1jg0@bcNTVU}-mWlAhgHmlo0e{q zL5GzjcpQyUnWEE>CUGvnBl;{|32@EP*!DkDHiLneaKs zpoj?_UE_hev=kx)a9hxU&`X{b>y~0zu7^j{i3E+AEYXX!CNlg;G43O5u&qiU-r zvZ^H!`cz_>I!GZRh%`hs_+YCzSX*J&^F&u-D~+`P}Ll%I=1op zGOlf;?HuC4H1%5WEnb7H0*%jLoHcLURab?a+?HGzS@!GWS3Nt*48=1-p2x zqf2H?kE_1GEbq0hp2b(UbJd1hb&yn(g$OKcW&YKf&%^7bTOk_RA|jA?aa+E6(}JmF zK~s}v!UW|lZqet%O;uhy#OzjK3_rYJQ1~eilSUqrKprZJO!8)S_0sCl?Qbi~_!`q# znXIN3Wh~RZX=57S6LQkB8U#!#m0S-Rl_0)Sm0%6+gj}VNk&cB#2PmYqY4=ZB+X=Zc zQafHxg1IZ{@q4m^9I!w;N$*)6Ch7P+NkQIeKc1l9$mY1cmR62A|I$8!ZKv^=v`>(U zyid?0X*?u6>u!NNGV?bc$8Ks_)!EJ)yykMCLWe;KT}GZKZyu|b9S7vW8r(VFDm(wn z=td!*KvN+XxG^n=4H0v9s1(K&5@fceJ7|{aj4dCIQ%$1qb$E+$(<)qcP+BSA3KGT! zB40nQ+*nh))ZQ*D;cEKWfo$_x+QMSrwy@O4!l-Y7yoHIH!Avnx?zFllsDPu%*%{zr0k>j8-Sj$+*9yrAUDh{V(=vX+z*;DF5os$}K7jIkgCv1tQc|gov{Vwzi1k@J zYYqR4tb^xK{uh~!U)qsgouu);Hk|gN=O!(Vf#qkn${U~2#4mn6%XWM|S_-<@be!Hy zs~0#_0u0mVU~BRTmLsM69?XzXol9RwuMyRh3?jesV&_Ad9HZ$zhchTygo@1|lw5&Wwo=HCX_J?G;3_MaK_1)3K1-(%>_ZD3NB6vO z8s*1vv<#REtf?x3bDjPdOOjUhI0E@oCpLJ4CR%~~sgtQHkY1(g?cyqt8+M#XH&m!D zI%Ac~-ippnbBD-@7*M&BFgQ-j>?$xhx;5Cg*>wKaVF>=|tve3qKxb~#E#E+AboISm zdim8#wuBn?+qTlrF4i2h zRQ#~KAQ!h|zw_GvXN~1`d0s0*`@Ge%W|P;#+mFuAo7Wl7JF_`&#d^HSq#$nv*Pill zE?;juXf1i2t$rd-Y&7dmT6A_^S9j+M+)2JZuc@=UySEGXW##cw14m)AuKxjlUi7~m zbLc7W>@(Zfot@VK$y@nkwTC0;^6*H|`n))9CCHm`X7f2-_X@f4M%ErTr|029xxKmL z?08Rq@3ba7DECy1} z4M58I3qbQF^&UU<+kWbYa7^x8No@eqc6=6Sq0st)qJrjUTFy&>l=Dx4w8Vb_sic21 z#Yz~apMLzlzkn+0{$jIWSUgM*? zee~}>+T)|2`{)Re@_Q9X`MvI^PQk&lD$9Ftr0X2$V5;|%49}Y<=tA^XOc2i<)_i$B zDtwQn-IZgJ_g;(M^wBM+TiVw5Su`IEmETqGw`j%(EZXX$bvT?`^X>Oh90!go?U0YQ z{*9$=!x7$^TJRx@_D;7b{t=4`(Gbly^adUU&#|;^K6=SVwddN@%uiT!TY*J+=UH^W zk8lvK(MHNg>til;CxxQ6ix9rBSLt*_%e8U&)1K2Yi;2Pa0(fC?jc< zc2EwbQPzS|c#_L!6DYNYf~@!q;onFa<$h51rcri*;z1>pM@#(-gym@zdiZT=l;45U zHN`EJi&hrGw*-7jK-rr{nGZ_eDQ=!+pyXlf2c>#J=}Myvf-;gu`35N7scxz5pyZ}e z{sWY}G|F#4DNLih3QA=f(pzKY{^KK;UeU~fq zbY_J=4tl2m6rM95Q0SX^ihDp=0t(Mm4=8a^c&d3o`8+5*S3IEH0SZs~R?7Ktyw^eG zB*nux<%!#K3`M`rZ^rWohJwaSI+o90(bHoKp@PZt;6?u{OePpP^5hwxVoTyYcILq? z8Kl7Mk*D+8AXU-%-GM+bd*oR~(bGP>mjio)hQ<*`N=H-IdL`L0xShhvNAk2b@t&SE ziiC7&lsN9^F$7Ob^&lKgr(kcU*`*NgOs@-Jpf8T$gPmDhNGZtE(_;Ha>cZg*h`dcM zt-TX_wYC^3KSMnY3;k_eiy3QM%=p=2?tED+dt3I0Y({wvTq@VHL|T$a%MqDUgr*Fy z(9*UFoIL`$nsWA{oZoeJiwTGBf`h+FBw1t&M-$Bci~dNfXObO}h9D1C3BxLZhcwkSU{SL%nF@VW1Dq6DaaPA;-=>vM`r=M zAQrVb(+SKnexX!y>guLnsJhNlgGED|IF5pn&MKKLW~=pA_H60nCZsX3>txz%{%V*1 zQuq{#BKFo`?5$J> zGURNJy|riOw!!b7CFwcaN4D;GJe8GrzBT88k=9!L-SJ#zek&@%SO2bz{g{_MZ`ret z?;MPum0sUPTHk@xz{t9@z82nl&fdfh@O%7sxwQu~^Y@n^rt=b0^MU(!W$tCHAN8 ze~Zn3sef1gmCJV8_9dRbEb&BL;%7PAD^E-P9yuUj;-sAIbF)&1%&+Q9{5(1Jl>M27 zpP8v0_GdPJW~9EOKj$Z^b91(zoVp7?cUMn?0?6>Zb_BhN>Z!Y{r<1a~IuF8nS6+?& zllpVEXF!BhCknMD=AM?by*e|sLVuvL>a5ff{c$pWWT)oqkIZCsZY7wf%Jp|fvU=(i zRzzApXjir-PDT}K2)4fuOhFvxC3cKLX`{b>?$8};I!EVZjsAwHX>?BR=zkJjeqai( zfDUJm9>9MG5B%`Jo&!I6=8XeC8vX5ahYtMkj{Sc)um}HktSLY6!_nta;=st7FyIRU z*X|kJKl&^DcMwJQjD9+of3imZb{V=?|06nl2>*UHiM{t9sZZ=o#yvJzQNn;L1Y_;IRXG^!79=G z__9O4HYeszO~$q* z=1xn-ZcDuzjY-CaMz79GWeB`$^y(R@*Mt={Hu%+Pka+a!!o=M2!GSJNQlCdY5iXgV zxGXPOo0+&QKUtfVxNJtUHal@yL9!O~!er&t#N0?S_AiMo!w@wYyFamoZAr$yo7gfU zU^ua57r@}$ywq8LrtDN-|Iy~0FKq-lvE@np4Iix7dEKhP>-JlJ=4)H@EJJ~MzQE{t zF!oF;@j5&1P--K-6Gu~jhp%L8e`50;KbC5r0XhP2o{Sv=x(XK_)w8ANHr%P|PP`=Q zmI`8&1Qi&yOS{L4FgC3`OA?PKo|o<)*mwBk)@?cWJ$`ZT>+CG!e-qDdJVFg5dXFZa zNGy9LaowA#Q=nfwTGQB-v-!V~v}Wdo-tX7l7@x^1ALMERoM2j&;gRIBSCYL)lh?hO zII?W#g=_GDZSPaQE(ULBUx~mIEDx5k?oZS%vkZ*Hm-ZhGEbqGAcmLIC+y)v_BOC%f!(%p`apW78NPWoXvAlXY1~HSAoY-d|!R+ z*jO=0yJMoUhnfE|4xQbxN6;hq8ln8VW4orv*OM3=9tXwX?X7Ge1cc3J`J;*inLi#9 zF*$R{kT>4NcLtXqr57I{kJkR9Q*y5V1NaWt;!pS>wH6*>69;w77_XGG{U+wm*}fyW zVPLr8jq7S<{2}WAosTpiP2+;t|zD|2O}e~ zHyE(6VeLOrzj61OgRv*6-LG)UO3o`lT6S{Y3}(rB07(}x`cY%R@BJ5G*bYKb7i7fG zGwuih-GleApHPG@!x~O_pRGEv7u|%)AEm)0uODINcz)(nDHcgyPmdgka5IyY_|)%G zD_%WzOcan7e~fFGvJC(6sZ{?_@9=`wZRsuL*k&UJW4rxoavoT+JNYHnj7aqHLsI@#wY6Z0=L3ikH@Im#PnMLwt4lWp({W+M)09YR(xzkniS#-s;{B z;|%|iIR<0*uo;elRJ_&mewuYsm>QpfGB1kU{kz&}Hkh65KT)ba@=Txoky$i|^cmMD-@~0<< zdqO=Jjq}MnGe5Z`>(~t(4>=FqMAG0u4gMyz>Pu&Ux_}ukElAz@GE-~uD|L&&dcr}0 zO9?j#yozuwU{W|i7XzP$ze-9;{yJBFu`qvCz+J&>n_s8PFS20Tv;4IrYvbQ#=dEb0 z$r*SPjo5fyb{y}LjDIla`t4*C%RaAgPEl3=(TtqypFz4xz7b2y8Q$2BNVv{7x2$1N z1Bb`J4AcRIWYhd^*7gf6d6Ou84q85N4)e?@7#t`7NZtA0Y=0r)EdnEig96J5HwnCe za4ld`iVckPUYV3qY|*WdD>=Y|{Ph|6#j^ax?6!?4@;T5@*?8*s3L*h7h`^1;|6 z@EgMkn!u6=cUKj9V6wX^!Y^9GO)o(kv60lEeD6vP$oG?}>*V{#sb2Zsn_4a3KToyD z_x{u}`FklCftJ^YSs4upG}J1EF*nAhJS)F^~%_CS@!pYiIPo?&WN`0Zn603_i(e z`uPcr_C)m73x=g#zH6$1VZcln<$jsQ5#E#dqnS^09>}c7d0_A3zo8!;Idw;CV(KMT z8~=peGjGj*D%a$kLY7W~Z?zquA(ctSRr1mq6~7we#5nsVN}99z1=NAcR5F_7L^lKZ&YsB^Pn4sCGJ?s-ijKbUq0JjBX!HB$}Tq=0^wf{dKrz8TN8tx(Ksq z_M-x>%AX43tjV875p3fysjw7FPnEEEn*4=_-Ubewtmv}`Z=bV*ZK34%WT;KgM?A=xECqF$Sbslk%Eb9T)m{;6&-I@g!sww!AS+`x z$d`{&n5{Xhpjs^$XLy%Kc9LbfqD*-4PyO}4XP9>mmJ7DAZ4cZeWo7PeV+y?W?%#3lx&gmZj{xG*j9IPoEyQo8CFVs2 z2ilowyX5a8{1<_7!haCBj_|7jHxMQT_7V08+)UUja4X?w1b%_A0T2r$fXT~eB;fT2 zSV#Zs;`aww30?mHtDyHEUts)!Y663h7X4K^yj^pxP?AEv2_H0Cp087 zX+t*n4T-#ihD1_trGkb;IJ_`P1ui*g2;8wYnWq_lYfSE?XHcoUq7}3 zgonA{L6&f*DiI8WEKeiLIC4CeXL4*9SLsp&D`QbIm8OwNwiInZoHsTP34_xw!iA3d zKxY=cUpn-b5%AT89ZsUgVWPh@@>Zsa*OMEWJ9XuMImR;f3ancdz*j#RIW0_-(&xX9IA!>GhQ3J4{H>OouPxSn2aU-(Sb>SxB4gunH-cf7zpa*BxFRD znK&U0!c->BJN!X}0JE#pW1dZvk$ljYd;d*t{oy6(89QbZn`k;7b64L@i2NH>M|jor(u6fwsBvtJwgfUoKP zv;RDHku1()p2thG#_mSa=#--@ezbptD>VKx4`cPeLy*>=6B_Hr_i?lJ)*%bL-q;nK z`Dm@=9EEr)0>U!6MnC-C#1E_cAJ4!J$C(}iqSk~}E(&fS$1bGfNbOi>v`Be>3=bcyC?leYEsGHV(qyJ?|RAE{5>>a%_lEx>TSn5Knz~% z!uYzDc)XZ>@$e2L(l;4v6+H|?-N*WO)yT?*)_-BVyQ``9C$q21#;Prfcs+IK2))LG z%8YZtEQTmX*8~rL+|N+Wn*0$r7<(3dqnTze+ts}v)@|y7m7TMDUgEl4$?LKg9lnDM z9>(>hbn&7{WNn9 zW}Yq!>g=?0jO#=L2V*byznB3@7ikG*)irbRbX+r!Jtre7Xv`eyZYrdBcn)gx#Sj^+ ze;kaxksz7Se-aJR)aEF#77}d>tN%txKG01vi)-Tz*RhqEr?+R+CRAL=c%6` za#SZ3u_znrD-Fwd|At)s*Zn*@XW&K15k5G3+5VjVSDDdX5BtInF8RH%q0Z7&HW>ST zYOY(Gcx>h!j2+7s-Q`1dO>2`mGdvM9#aXj~?PIq~xwO|m-23EPisnm0fd1Jqy zJw=D@2-Yp(xNjWc;$<8w3qMYRe{2MKjwF^mGJ6UKb^NqywszBpV3Js!z(UT4IjWBC z&Y02BnYVjRCJ&Tp-90Dk9B=Fg@Df;=fDd0XGMHKU_@NA3MeOZQ}4a}`>`U@KSJA4FBlt6E*Tad!1c&i;NpF4Czm`TeT6}h#6GWWZF1Qo`1#b~ z#II8CL!(g~E>oFdZC-a*3%S5^ts=+#ZiYxE(#7n7V&tkU7{`SsO;_tdJ@6%T-%^CO- z$CLGORLU^cJ!PO`XFurp*#6YFM`?x6jD9qAx1d9#4Oyw%0A(zVHsp>|p{(B|Z@fcw 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�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

FTfOCunWy@0zU93l;9~ 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

  • @Jl3-Up{V+g%=*mfJm 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 bZ&%-G?n-feM}E*aW|+p?+Z8z|yPJOjf;Vb~ literal 0 HcmV?d00001 diff --git a/lib/libtiff.a b/lib/libtiff.a new file mode 100755 index 0000000000000000000000000000000000000000..e67da33918c4ca3e7eb0efe36c0319ed00ecf1d3 GIT binary patch literal 1554768 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
    ZLdtB1$%ich*V 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

    ~=BgkEhn;NpIhEeEU24$85iU9Nt6!kW!$0 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 D|A?R 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


    ~ib+VL9W`=E=7f?{^=YpF28;P9w>> z;mXR%bX}*}9)w(q8D;W$23O`rU_5vkr(HCa%^ovpSkBl9qr6_a+O;{dmo7|1+qO-h zE#{@G`;Tyc#ie(+m#%sEgonPlAG_BS@6Y&?p#JY(x>}pyNBj+|!@YF%9j4U$j_^*q z-vpuF4%=Z~y58!o)b5AOLC^1DUb-sKNS;Nd==p=uYKuQ9_(xv4R^v;-gMqT1mj%jF zS{3YRT5#aBi5DGgQPdMU1wZ=XwW=2!SRGfnl>Au1QPK}p=dO3X;6$q6r>o#cCx8EH zv|~7_;$4KPK$tfvOy17b)QCMt3V!st$0}A+Cd)^xKdm>g4=-TrB3}kx z+zMA<@P>6}i^zxMqbRa5@8rnlqz``BAK92x(diQ;k4&zM;`rt$9p5|HdI@7MVl5+g z{}R2sX(azZWbnS|V*1LgWMTrmN)^(_a9IUYhih(eky*>I&#rg^h4ignRwQj~bYOg- ztYS|t$}Bpt>z>>2_cc1fJ;Olc*epK~9lS468O=Wsz55qR*>#%~NgK_M&uR+p$~&0f zEb{H1sqj7&Ny|&g8?&kcQIw>$UW;o^ZkL)yu0^)3S0u#Qyx^K_&92ev9uJgt?_7I3 zrJvUGwT+}7Y!M%A5*dI{VsiR8< zwT`5AjfQsWib!h8JX9&Z-g1fs2jD90Pn6t&e+LSwv&I<|^@kuD+8s?v!L@lin%@*j zg{Q`;Xs^+c^zDIS`gnd*s0P1CW@o328uxqxCC`xz8S9qEnO=&4ADM2AOuzqiZ4bJt z`FrRhttD3?Toa5tup>F7n!bU`C8>hlfz2Z?XB=}+=b03^NH`G`R3xqi1?37*dn#p^3K9hoDEyx4Gtz!z z5#nDES=MIZ`!r3`P6r>u0*I+9JD)~M?CqB^Ra6*Y7rE!p2x7- z1MI???Ys@T))aU7+yw0NUCL z{(v)3=3E_3-&U~RcfmniiKu^iq)EXhf6)iizKn*d62FavDsA_(<|4#O7k}=1h$-?< z>qV{XbR9RO+mBy3PVmGHN0&_k?hsQa+ zn6u0|ec=S;bR{KRV$wJHUEwByq`PHNB0l8!3!CF|st8t}@>`6EkCfjPhvXNLrP|20 zO#3J?zdRZ$uUktw&NpRygIl(PQMOA1b9PXUe@5B|`A+!aJVu5Q#E zf9p=$Rb74%Vv2dAk8>KBy9pr!WsOnvOS#;u{nM+qR&Uw$*{3y+-SKYqmg>8|gU`J0 zvYM&5EO=|I9{25z!F#L6!Oh{`x|Q|H5Z5^{=V^>0Tyz~VyR#ShJIcgh797s)7%?1$I8xuX#}RzCh*T+ows1v#XnL`mrNBzRE^g8T7w>QO;?1!Y({ufr(wQ8gz7-#mMMUPK$hJ(Y zPRySZ4b7=rceFgt56pQP`QbeFjpcDdQ)w9W>f8LI=Xc@Z`MrV8^a%N#|6BQ87!55% ze$%%{L&edI?dY)^NArsVW&Qk-k}2pKaB@u}8R6ohyQrTCZ4a!BI|cICz3@q%oY#TEOCuhxN;C8Sb(wGS$Epg7e*Z7BHKAIX?g^g-2df)M~r5v z(`!nSdv^-eMDn-Smi|b6@%AW=htLzY$%-Te%C7chMSA+E9J3;Q;mmP+#Fh~>QW{4> zi?SlAD7~tJJ^o0jwC=`&aiw(f1)JcsGL~7?em<#nktVj>Ui4*73it?{}z)z*7 zLyMxJMXm@5l)~NOlac+=e9AoX9LbNXr3pr$>;#HAnmjv_zBw8-rRot3)r`7+o$hS+FTihc-t;CTG!PL_x)mC^m5V z94TERbiNfVsrJu^W>iKxAnu|M5b?AZ-E7UJY(0h%Wmna%Dk{i~s*|9yejcyOe->$QMWsFW2CySx$W}M-?`n!)ZT%zQ)r~Pg+_{{ zXbHEtS&4Ogo4MmdsH63LZfw(DP8_@}8d_FVQ8zbG))vv`@D;iSA^lfJGtje}>k}wz zo*Ln+lNGt%&lTN?WRw?uP&cArT)8R36a8Y^Aph*@t-HSXw5EFN zV^!M%Ge1X%RQ>i*M}v&LSrKmD)mu>Iql{UR_+6i47zxaLhyri@jlk7gY;aHDzCIp= z0yFQV&_^GLBx!G0v@bLyClXp#H)hwz)mz!YEik&mZ;PO};`BNV-_YOBV8ur#vOEA>~sZ5wfD zX_UJLIa>WT<-7WAQ^b5dE<%g_jWgKFXVAo)?yM7`j8fQQOTj&{SrmzFA+;UB8=GL7 zh<=|sebf*1>FMw^9Cy6w+I^;LM=^VPceh)I$5gk+>?=KHPxP4PGR&zPht3>51iG}w zluQP7>4$XJXfw9E#=ui(&K?5??(!UyB3cF}9>wN}DGYS~@#wGJw0k({u(_L_c2Dh% zKT(x$3zas-O*r%De^>gCk7mRbr)mhI8S`5<QM(-H zHLtb@&dc=RJiS9|tW+q^o@S72FM{mX{^2K@dT)M-8o5g*imcan&{*S`rN{al=<{ z^IXgQ80wFHEpZ`f#A;#+dR7h1vD_O&j0{{7vnUGhh+)rpR-9+VI19{;4DAHf>NwOq z%pQw*_K1eLJ(973=Y=VLWI95VzU^-1ql+C0t%+RCQ_42ggD|D^7j3B?6i2hlEX*oR zyE3!N`2YK?(sU1NqM0ss_Rx4#O=AxQ zs6gR-{CbR_?wbmAzUCuU8vR73g zIm&u8Z4&UDY0a(Q9lD#jOC0uf`%)*DU6;9rPRa(XP?ylTfOW)Rf<{kCxv|)``O| zpKDJ%)IJJhS;)1IzL`Ka(Cc6ytt$8l_R+#CBx)L%=c zXx!UxORR!zKeT9Sx5)lTb$$CnVCAX3Fx>XRxY;)=0t^6??pBe1dwj7}7u3}=lgzz5U5jt<_2H4X5K+d|w(>cQJf{5N#UKmlwH z%%NIAH{9Juqf{bktpyy!MtBB`*A z=6}SNP`=>CEFRZ_70JAb$Y-!=wp-We3|8ru;zpeR%%LXO_xJGn6viw_7q)0C9tzW< zhUNm`M(FO%(b@B`8z{>ei<{|4`kGGp+o}gI56of1IhjL0$63KL6)0SX>w$i;`Ww0y z>6=S}Gk!t;iBKg|uKSg&WEEs1dl|9qs;d4b@_pUd>PECe)vm93pt}S}1Kr=M(lJ$8 zgFDy1S*zXd>T$bw46dmj_qS-MhGrUlclcWrZ19V?VB7}WlGfl}6Gtb;F5|?4fB3M# zN;2ECLmRHCMgqn%ShTA;=>w}zp$`o+tuis6?()f8(hp4)xxLZmww81I9=hEBDz7*N zy7~TxkCH{^&ZqLSS)-`$Sh%Yyslux=Z5K)vWm?jFMg(xgx>d3SeKu-Uw0|BouA&#v zZBuQ4glyS(Xz>X3xY7L0ozk~O*m4ya48!Z=5aOX*pzt`dz`jnVC0xmgxYctT)HYoa z9UNDZ7yqldsVkXs+OLW4N79!SZJ8R1a!mZZAW+t%S9I`FoEW+UG^(`dqZHfGnpUN2 zcbK-?#EbA`#C5}a8Wrs4bk=A{SZ<^C7mVz5J*yj4P=(n_1OBd$AG;%NSM_Uji&}dj z4gFPB%@S~Gm}}DSmR)DI*!AcnWQSYIt|CHQz3OkOw@^L%1QuheYgLUlAWqncJvA<) zrgl5Z7FFjPJGE?jNU&o~GQYybx0flzoeisk&QJ(n|I1GS%lQ zQowb_6N5lm6%^Pc1qFX3y`q+$?9^);ndln-%eH}b5lt_TRKi%3=$hPcGr6G}(;Cwl z0yF8k05yn6Wuh@D(wq`Hk&miVkZ;cO9o>;%(lB#An(U)}L_Q>=!ObY3g3tyueca3y zjH|$X%m!&|ftg7tZHm5@9(C4hMK92a{x>ZiXH`oUqI#t?ov-zO9pA60IEU1#z|1$% z8@e@XMNEN9ZdWzt=UIN5#TST{qftA-gG-O38FA2?$WX!iCR(DL)=@{Jx;+VZi zkq;3G#&J5*2>1T>ps5Ct_i+%z&LWt4aC5fU3|+M;d;^axE=Ao$Q%1!^e$vq3G0Ned zD^S+Mv~b8wj>~%Zp;v^KME8K*VUD0HQ+F$ykv26(qek0CBBo#HMmb*+$uLuY#3>Or z$02XVQ4Sn4a@{S;CT!GVw#-RIrV_&a$+Y?Px`=AnO`?N$Vh(L)WBmM+CV%_@5Cd!d z2Y>aReIg?C3hp?8`%1ogzuDLuVftbFgF_p;xrLkIRiMUR-7SuL1HbJJP9_D@8*o?P zr~7m&P;@CPs6(hav_lwzvG)IAhcMKf^-((nb6&G!THa1!L*&Ei6r7+vxs4cEsOyNP zub^INMKq(rUcVxYz&#oV=AMNrhwdYux{s#lK5$XJ-G}3LA0Yq@h3N~UgEwQvG-@?j z5g19)hEll=;f}%=S&u!~z%X@0qe3%E#oPcEA$mMR%`O#(BB6Oy#N51K-dR*P8O;mH zdYVxE=H)h`!FzHmcn)B$@MFYK?Pc-O&E*QAE@YEx6P@ zYc!nNnW$K3r+yT?+fJJvOFKp5=GJf8se7t8{~m7hkEWMWH7HHQWPO>dK$ZO-nl999 z$0yRg>amXGwWpysIQCeU!E*Jx<`g`iIAk_a8$=DSH&k7E3Y~11aKbd}w^{pbPkKdn?2j#uYqlSp7G3D=<>flrLxh5fn@xW)$*b z3bBz}Q}UNH{j6to;bGnE4~)=8kFaf8E~DgFG3Fje58{h8{!C z+Q<5mSjBZvQf_bbK8Eqbx+{8*%~jZUB!zY!g_mOrvDWnwH6GhteF%kPzt+zlQwv*# z(8r#K^~aQlQ~xLJuHb*ta{l^1iN!&Ausy}tV+;14iT8``o5g9ZH>D+`7AU;PHm@Ax zpW==T>%H37d+~~CWaGrEqWx2%v&j0_>CL?J5-TIK`0d%Q)=W5y4TNc3jY=dfrFZ@- z^;UzeZ~3OTDA{UUgDTGH)q5EjA?;hEhuBAvf4pOhS8KC2rL=0Q@Ozn7c!hbteIE?R z2V#-gczV0^F@ED0Z%sc)i6z^NrcH^=tbia|5T;X|xrUjnkz^BX!+T`ZqP;75kIclh z7slUcL80BdkN1l0-V)xUckD=$EFb&RvUOfUv^%Eafucr;$n$gn%kSF!!hTK1>9sER z?N(T6XHw21`ArKp#NTww;94AX-v@QCiR7b@j83umV#jUH3bT%K+~&1#z!8tvUSY&; ze7~JJS1VdzORjJunh@F3+#|KGk^rY2dqh%83moHN#rLQItLCEK9saO_-`}R|nLsya zxTK-@=|447TA6E`cl-38PQhN@=~R{I5eKgF!TZA~u7V8-D7p3Xu#9oqB)$lF$$UjF zV2_@5Ou8jqpnR9T)EJ-ppT)GdP%kUS#H(biHg1i_9F0 zJq}p+7G9l>rw1hVSl#y3WIE*6g_B#XqBU*lMfyFEDSmsNUy@I5v6^1shL$-}cYiqy zd)!{?HY2L?1iM$x5x6$}awKGwUMD3^h#t(;S3+qUrG;*bH1A$Zi~QMbk@eoaPO7L~ zic5(0)t~RCVD^Z=f-gmsDr??_SMZgHkKpz9UQ=iVWQ#0T0ouDrqpc8Wn@MezvZ-U zRD|Vj9J?BYQ2}6+<}$0k`}68OJO9a+=+EsF4?OFr*)h1Xdfex`GKzPEDnI#g*WmK% zM#TuWGrimmxhqr*D@#TNM2G}8o}ce*HV-OpB)bML-xVsa`my>fs$tcQ7EL`hU3iR!Zwa2St?Qt+4#52Wm10-FOatqRMfEu~#t8GEG{Vb_n4ybJark;o={ za2W)&K$6{EibwrL712;BKG#7nYQ6!=zZ4b_-opam<`bX%KSlGG;VDAVe(2yc8Y2x9 zZlw&SFDcrRcLHK^bBLFx@tMd8_~Wj1&k>T&B3GyAU|!RRJM@vQko1?u^p~;(@3Psm z#`R6ANIICbKWRr~#ylj8UT6mOmGqa!m&j{0u0&ogrr(FDZ?-+p6#lH?wU#L4@~iRV z)*N)TRF7=@NfmY5De^A)m31fePcsj)cBU_{KC`TQm%)`&_C^O+)}4?3H+HN%lE1LK zd(C&IqZk)fpE+y#&vffMwW_+&A|#fyBRcDsbLb+MVz0W<63W0Vm4MgghnnYms3ACU zsw8gph*f}fpWx+!Dm?cbRP`o5!I(IZ)nT};r~c{SPf%YV{G`}_a@zEt6|V5KE35sB ztJha;san5lH_fddz|*~TNQ%4MPw>z~V!h)zyb7DKbos$p=&5h+s)p^93uIee%l@(Q z2$uP);>xPGRBis4AB*Yk(TpWok>o*XT?TKP@=zf{bkjN2=Byf!3!l@kWKv38NzfwaTn#Ll%qspUWLM3O)u*r`)=HBoZlnP zc*>|mxCK$Z>Ar7Ek$pyy;T34)50Rl(;LJEOdXAQk$HB|i?Kwwpe*ZvU^mXPeBlD;Z zp+F+#T&4KMf1G6XSrB9OcB*|;x93syL*$WpRR3yAFwaEmqNn+59rVAesng@nd)!fo z-y47s+Zj#iyFP0EBYD4JmG`hMhlW+&ui=tNz>@@b1?7fS-c99bSmhnPA-0B9-c5aI zSmnK8mG@&^<$Z>!O6s#qsJ~6Nd$ASkPsOc@t8;^g9|ngN8UK`eftel#I>!znRhdHW&Vo!I%b};^Zpb3iyI1-n?7M4a|$0>#cY($ zX-)B8&pRENZ)Coi`CcFGPfK)-jPzXhZSDHdp@%mVeCgT!Kr|Lfz;itsdYMbptc)V-OA#LK3ki?#T`fGx*GG7~Z-DRw-$>y}zA?hL`o;_2 z<_il?@)ZeZ`DP1`@;xj($+s9hh|hPB4^v7tiuoooMetT(|I(it{9i(Vtp)xQ=R?1R zn&MjyF5<9v`7otW_gJPlX$wNf5b@m-KgnY{casww-bjwy3(M1dc;C+Q6i+!%@!`JT z%BT5G6At^%6E5(f8K{RiKe2Qx>~Z>2ga4fgu+e!DKh5Vg%l9pK9k^7@^yFuj=UgJb zlb}OeP!)UfP~x+`HXvW%JKv~)@Ab75Uf?7D8MFn}gT7RQ;D>!fgdg$^6Mn&$Dg1~p zPxw*aG~q?Q>B5hB>cC=OROF>TGGx*gRL}V6zJj)(`m=A9LGUu)>%t3s8-$no-VuJ* z_mlABK6Pr*e z>FX~1sjsi_PG3LaPkkA}HNKmKKl6^Q51{f-&2DgO6-dqw_{?|b1EP7_;)gQ}GiTN(W#hfJch zk^Dm8J=~6ryv{dHQzP~EOBv^6ED z@>M6{+f`TLe07!ZL=_UAt$GVTp{^62t@;Z;fzi@U_eph^@H1+j@KcIDqB41V1~tp& zeX3IU2la*UKJ_=@A5^XIkLn-7jr9THQ#2XSP5h1ZzlBfH^dP{Gr}MbVuQkP7&^|2MS-UhYI)9#3*Vt17QRz27oMcch40k#POv%0QvDC%$MwI2OZ5Ta$MrA5rP{Fr zQcyjvn+ccdc;P4XDZ-EI(}kbVX9+*4TM9p+FB5)JCkrpp9fY6MR|+rDJ%yjr>B3Lz zzQWJwLBdP*NZ}QFobYoxPx#MzlJN8TF5zW*hVTozNced@OZWx-gz$^{RpI6OUE!DX zZsC`8o$yQg8{t>apO+O->s#ge~>Qo9(QlAM=R=b5KsXfAz)i=U-s(%VkR{s*dQymbVqUgzt zsh?AoU-&N7MEGuXobXf?CtR!o!c*0W!ZXw=sgn^aVIvnmnZqFxo=s@@Tf>fOR~ z^jE?q`fK4i`tQOe`k%sc^uL5l^e@75wPPpxL3NKlPPjzJ3D4Ch3E!j75uT^d6TVls z624Ej7oM-X2|u7i!V7dy;Rp3K!V7h8;fM4{;fM8I!VhWqz_WeS!@5xT5&ekpBK?@~ zqxvb~MS7|5qx#RnH|jFsLApZtCjGwf&ALu_gx)87i#{McME@c@Odk{;svB7YP*4ri zO@)W+vxGvZ7>y037y9wL0Z&K1tl z_Xs!9F9|o*8-$P39|<3?|0#TeKF;2>2US2f7jC9c6OPws2>(H!D;%#|2%o5vg-_DG zgiqF4!tbbv@cU|k@Vn{};dj(y!tbgj!tbf2!tbbM!tbgVgx^yy30JC>!tbh8!tW_^ zKS*0pRjT#E@2QQ#m1?u_`)a#zrP?98ZG=6^`P)4>RI7W z)l0%PYM1b5>Vy;BIIC5v@LyGT;g3}>;VRWf_+!;ic!#=0_+vF(c!wG(yi;Wh?@)Qd zJJlV+yVPvqoocS|E;Ud16ICj_OFbiu^A-M7y)Rs&z7qaS9TbkLQ><|?sOG5Cg`?_B z;W_F&;i$S$c#a}}+_VK%iMm{Pj%p)ZqS^`1RjI=FsNTYJ)pf%2)Bxf8)%C*ns6oQ_ zs+)!HS3`sstKq`;sgc6>t5L!as9fO%Z-b%@%%GEfRi2y&$|; zy(zp%y(Rpp+9bSKZ54h@Z4+Ls-Vz{Up3yHM54lpn6}OF8raoK==cd zB>btb3%Cq6w=isFd+>7DI_CAh-Qc&u7pe_Da!C3O%ir?VK)&DdPH?046!tA&6*!)G zqi;L-Pv8_)!8Svx4;A!-?E;p&77!!PHiuLV{*qm*%@K6S9!pyd{*&$Ksw3#Qwjk0W zThO(vbGst5#P#4XY($mF+Yl?K+o^Gu=~iQs)!7Ce>~fwdo(Rix)Mm)paEj zLd56g+Qdl5wTThCHZhlj9CjaHuRh?g+NbE1tn00u$}`h4U9W7bvjRHU<+Lcy8Laa! zF8?`}sT>|){eLNX6LYcU<({x^t*n7A+2xjc;(6H<&l*oWZyg~Xvg5tW`lo0hZx#4; zZFe9}@0V%Lu6axI5l&gHNV99GNKGMw)( zR!;5W_>NRhmMbdHGr^>@)KexD=cTOk5?_}NmZ?0uvHnY3o>yC5g0THr=Ve9p?H0>a z-^N&`=}(?zJB;&rxwgj|94Fi3G}bZcMl4gh_k+XAq`Sy6rTY}?m~@w0rgT?ZrgS%2 z_NGg=&G%WpyI%cw?U^+Q=h`!m#2<6mi!_zzm*B9vNS7i%f46d~w?A8^a;B{U|0&MK zc-WGnT58gXw@l~wCvX^Ys;lQ)UIfM=4of!GR;(YYSI1mCY7O+rj@s@BIw_FTR)ha! zQ@xUPde*CBu1%G6T$?JfYg2W(2Zt@>bMFTZt3o{o`5a{BbY7z^)4Atbonp_qP@ILV zQ^e&kmvxGCA#@(J90r$Ko&tWBd8Q_hxUYcm+>P_U*2<~eHe04|`;j!4n`;NI!9Ll6 zKj5$?-JPs&(*4phrTdL#O7{n5ldi_YF*n^fa2R=@bWgGDO_%J<39MgM?|QkmWy%lP zmJ^SlmZnjL< zYn0WQ4;}1s8B&~+SZ4rVuNju9-p*nD0bC9XEYI_Vb#2`>&?Q^}hSNyoK~6T7x?mp|pOrv85o zcI*FlR!-%qx==kS)Ks1)fJw(&|0&KhS;y4F3t7k1!^R~r#QxC5JyY+CO zl~X+&YS~*4z4>=-$aF5mw{kqDAIs;krXRc8%IRF9mg!t*tH6Jh&0KCT*qzJmvvRt2^iVwob38iVW?<4;fjncE z>lMX$4(ph?T%u*Z7OZdPa$PMiKO`*0Q-lAm4cX-o$78NVUk+>LMK@SEU5hNsl(*Zh zj`vznoHJO*T#GrDDQ^$3zPT2QEz`AF$~xv+ykeQI#ahdBEw)(pUJGyjU0Z7nbcwgK zzUhBH1-t#vS5{8t{4dLNF6v67*)50?KKbKmj{--^&>3>qd zZvS(Ql~ezdVcFaNc=PYtHfxYA;vpQ58Jlk9ux4z^v2r?>uw^=zsMYa~O%%@})-hw# z)0XMFEN6W)Hm$Pk9hjOIrLL7c2iwFhr^n(y2#2YKkY12ep0NCx2!0h z>sZH>)lHTuZ<(xb%4)o2Z&`Wsy7NwEZ_MQ{J|)zG?d(SoXGkZ+={xXAQy;@8Eb$+y5JfHEsVJE2r}O#WLlsNeW$~ z`u9W>&uNgS;2wnZ&$CQ z)46|Una0PxmgyX6tH6J6{#{#E4dlc>q)?pZy7;=8GN*gh(aKvu zPCOIwv{0=b`tb8{aH+c7v5#kAFNNH0LDj~=sqhw5NzQ4)?VU4(J3HqKcXe<}&s$Jk zgOE~1*D}1#xU%0okM!1htA>7&7 zBz%oiDSWN-Z{hBaUz?qvy4Inu!)Obt_D);y^WCTpB=Kt|<;-myDy;R)ZModGgD+Ic z4tcNrf#sJwR8MHD;9v7ogFn}4!*pGUom9FmH#qba?wR0Hbv<8~mX@hL(-wq|A;Z+Z zXv4eK4yFUV1=Y=tTTg;&uw$zLbZ&9Z6rCZ?1;Rs}*1|)aB;lbBZZ&zMIB`3nl8~Pi zq~!y5WxigPhpb>t^HYOAH`skTN8+B)Z=p``(>KMpfJ@c!{2IlrmgyYxEXRYVT5b-e zEr_s&h@1IiWfJF)o$m?$SiNoL|Dz2MRB`@Ty>0G4SLDs`d9K-lu!dYDe2PC-pU?5r zxziR@E&Z6v@D@}T`_qJ5`mYwg*ngdHOMk2_T@Gj?h;aX><@DI)#!UvqUgnw{03mrrK=`2ZSK%L>YT<*xBFID~0>{tAz*nzYy;4uN5BPcWwAVb%y_Ykze9hJ~wZpoa2N?IsxGc zPD|lY4!P!~EvP0qmkDP($-;L#R|uCl-G%2mv3EgB9M=XORCApS(J67qFY#{?UhI4z{EV|lc(GF_ z{EV|tc&YP~@CwJVEg0{dIPt>kos)$(IHw4|>Cn2tCJ*bKvxPS}=Lx^*v=rXpv=ZLx z&`QH5>_(@Z@Kz^Vc$;&laI)XEE8<%NXSv94cg|_##*^c;5x(7NC!FJS6u#ZLLO93i zE}ZL-t;ysk$06I1;an&7US*Cm!XuBpW0~jN;gL@k&U2;--{s5@&UFff^PFPg$<93C zJDtA^-{qWW2a+JH`OSsza$@gHPI6L2KG_KhPjtEq-{JHUp6tZlfxOEZE%G~^mBN#q z#&&=Vs=J(vgzt2E3V-5^5&qN}EBuKwLHJW=mT--;K=^Z~RQL;LiSTZxLikJPW8tqH z*M1UIUple(2ETHC5S_m{KM8;3{9Cw_KlXm$vrg>YzvrCTyMKRnPO_6NeCy%-QTWf! zX~NGsX9)k^Zf4#clCcKJiz~x@Kt_yx#yr7;CDY1396}16FXT6s%g$S!c!gBhC}iT zJo1Z$r#Wqf!%nL3G$$k+cCHbg=JXW~I|GELJ0pa{PL}X=XRL78xm|d=lP^5ODHNXW z%o3jA%od*RlnBpu?iHTy+%G)Cc}RGc^SE%a^Q&;gIZxi%D|RjrjyM+y&vtqWN1SVf zXFKV_Go5L|vz!9qBBw~W&?y$4<;)TO+IdE}&UssSuM>Np@Ehl#$p7Iu@*dr{&N;&W zbUF!t=kyoe=L{15&KWGc&&d(~-pLo<=S&jr>%1hK;~W&8>hz%-MQo(MSUAV25YBZz6MoQfKVAx|+0OZP z0*!C+oZE#X&N|^)&WSWB=lEwkZG?-R{=yL_PxwJ+fpAy}U&{Lm~CX99@9Ckhvp6Xm`Z+L<#?DQ6%=1dTt?#vUu-FZbg*ZDy>$LU~i zJc4SvbC>WmXSHzH(e?&|`m`S4S*c_u5jahqem*ckf?n!0!Fak$4BEJJKPW)t8pZX7zWDb0pghezr_ghQ>iUmyr(H zvari((LKc%N_Q)#Yu(qf10G~`$hJ9xd6eU|Rl4^w zHPEGdnH(FI%3+F!XL@*^haU#Jd3e&wDG$$EraY8c9m+!mbNxKfebalae=pZt1mQAq z?^$ZFPxmZUtn*+!9ryl)blm%wBk^Y(b}_e?y_|=|4%zqiSvibAe}7O7Aap**zTf33CmI(wP`m0quYzwbN0PV=9&*WP>Wwbx#I z?S0OijU;ZnU0YFGXl>PF@>0K?>)`h}c%y?q3~cMY*3hZmPa8Vbd$YlAy|i|_jrqS* zGG6Q&isYd+)VG-D2doE>SZ2GPA|AV*8V`Sm>y`2Hh`}^oe#vFZc=^4-G+v%FJnnem zHQKyjyzKAbsSZBE!P9}Qtws!eAC%u@FzKh&@Q|%8W?X8kRPR~LUuvr?5Au)VW7mv? z?fS*yZq6%y`&=$x{PsFSCmB9y@IJs-8XnhgQ<*m~kNE8`I{0f2{+5Fu0=EA15ksfC zeq}KE&nFCz>pxxj?HXqkyoCS6d1XxP$Vg2Y=teKL@rp`IwZ$}wS_ErgO?XBM6eUX2z z;c@Ma)()pKkJ#IL9GrG=*1_w5t-Zb9&`DR98BFc^sNo@dyMb}3y-~eiX8zK-*sdw4 zjkKn?eHO(GP9XH=FqC ztqz{%;G==9eoioS(oe0yq@R-w59wzC<5K zxnI*A4(?lJ!cEF^P8dU%uY}hZUaGi1Z0}Viyn%2^>F0&dQM@+XuXs&3r+966P;owd zzT&mv&nqs5Z&JKAd<*bY=%LwrZ7-#y~Vd|G9jL!^{4bZif|Cj$p z@#m}NJL#G5d%%x(3WcZ4LVO6k#e1Kl=L;M?ujhIxd&1l3===kGA8kF?yI%RX5~I0B z@fWx6_@a6VU&{54gsV~S7OwY0PQ4>qPQn{;=$D1xBE>+4%fn{554<^ih|;fg?$ccr zo}u)s!*z;38cry_CcI4Xwc)cBe=Izp_~YRV6kiwqkmBpZn-zZ|e4XM?g>O}SWB8kj zKNEgH@#n(dSA0!)RPnXpZHhk@o=6iOF1)8GOfPH}{ORyg#W#jeSNxgq*@{0G?p1ts z_&miQ4bx#OQqB#|eX+~Kw}O5P`l8vpjQjd_#vfw4BL1!PpSecy_eZ82>QllGfWN}K zIZUr%{x$Fx?h$j|VQW7L@7D0)k`;M>>)d;N zG8|X>e}tPAe=Xdq_%^4n9}f>H{mJk~#ou!J^nvh|4*hDy4}`B({G0H{6+affS@GlH zI~6|=-m3UF;fEAI9R7*o?}wjO{EP7OioX*M-d*!w;kRqw{URJZZ}6jVz0!Xiw$BM9 zykCS@D*YSbGZo(v9tQq9`l8vph5LHHHo{-xzBm~8IPc40`rSt(({ExMm}fA^-l+x~ zF~``(W>Xj02H`WoU*SC!rWbe*0&nrQabI6-@FehEW^iB|PdT>nRM>t=c-zBf3llc* zN9W%C_V6?#5Z*Q9_<e0W(-@quN*Ja|Oe`;>lU*^uG`$~G!~YuROr4=%e( z@wBo}Dn6v_i;CY_cAMfu%kEWtSlPphk1YGK;)BY5uK4J(M-?AdHmdmOvfnE{yet^A zN0dFM^rOpORD4WXFn%k`rkHV&@Qx`vSaC(!I~5;WcC6wVWhW>;wk)dnxU#t7*<~$? z|LUKj_yvEJ;+_5)#V`8jE8gk9U-2vcRf>1|*D8L=zfSSr{7))=$^We4zxg*Se#!ru z;#d4{DE^xtJYVsu{{x5q6UDFkzf$}+e^l|`{XZz)CIDc&b^vEqG0S1Fzt`mEypLbog4KlFg&w}gJKcv9#OiYJG* zE1nX1M)BK1I}}d}{aNt=q2S$FZw>K7gs><4);=_mfXQ1FhgiqMJ5b8P5cijN8{Q9M0#rsB%bdlk#{l=>3W-L&J(|LRToR4cXtdCA|937Ny5SKUZ8E`nBQ{L(eLHSLk`gCx?zUGf4u! z+O1SPHxxXV(i(b~L!YBK5n8BtZm3OhYsmgiD&frw1<$J_Lhn(Yd7+fz`Jv!>mAN7N z8>oagKa^9R1)<*zXz>7K~R2Hy(2nEC(2w{TBq{ESa)t84flfU(GbB=C?Y@<$kp{Bs$L{HHP&`IC%yli!RrlArp5t_pl^ z2JQp@bT7lS3mBi{QC#;SgUf-h1wPJuDNLBIE__Dn@n131oy=v{rt*E+o>`q=3!ySFFRk8@E`W}w(u zoL*fOsXQsqf0|}SBQ^Ck@mO6=yh&kwlh@gs$}?+JSfiCq)lHEoQu?w3J>|Bbn54!k zU$daWfkLKdAl;=|Y9vby3Un`gi`DC8su`2HRx;P_N#+tk>ncxbF4WaDQM2oiJL1-@ zxT#ttaDkDA3mhX-y;E}i7`Y;DIf|RSLT@%-RGq}Bj7S|z7l$rm(fYc06a5c`3+tGA z8=O21sJE%Ewl-D^c2T!>V5FKD<6Jgy)67UTEK#(UD?5ozO>ksu>~Z>DT%e^rkjpOdL&8=WR`vDwW@>&I=2wdr&E26Y@1cpRk3JO zra#qVzQ>|O2r@cip?jCbq+VOBTQ&L!$xyIU?HKvc31EtHyUxpIx};T5GfC4>=_QjL zgPFc!W*~W9D%qDQh(@AN?+kE6!7w+Q?UO-c^f(h$(va-VWOK86z0Stji!uZAPn+G5 z8JIn57LD537@@QKGXp(qV$s>LSv9k2DM9~b20Hr&yVA3}I|qt=dsRXvyI0u@>k6}r z>vHMB-j!19>PmO-aS^ul1)D8b%y&VXNm6|sc`-H=nEd%^LxX*SR#WM%A)_`#SSE<* z!eXXh7;8-C7uQ*{2K`99b)aWWMKx8DAG`qx#yp)8ykuAUJd+jnD|H7X*d^F% z!Il}w8a5as*y5F5K!WLktsZQ-OqXFZhF9qYBpS-#BU|jxc4sfKBkGA(R>4COWgykh6sRVZM+#3q^yhVFF8G*e zZ9@|Tq>}3Jr#fB@uchtDuwtl5&?1@?|0g$zG|x@K^cOSLxlW2Hnwjw3d6o5e`~W;nwVC2(YF?ZOy;J5HKW-A=pla+|tQ4 z=xOR?6*lN)8nqC(<_&eZca}R|H#dm3t#E;K+Rtzh5U%cxwfWEJXoyE0ZNz)?vtuEh z%6Il+T1gKS^XuR(>dCnj;;Yl^8iC;oWrh}iK|Y1Za41B^)Q-VUu*GY*ah>ouz@y+NhP zoJGDKq(~j}iJQkPLu`gdjpBI_q*#>M#JwXYu^AdQhUd`sh4bbu>>0@B)63HXg)}tL z0NGATw=Z0tT;9H9Su5H`xb^h*Wl#o`!rvAxZC}+GMY|~ff^>?MK%!IQ8ZdjIXQ)+4 zM0T0ZMv&N(BUEDQd06ITvIB-5!8C6Yx-xmpDny4rvpq&tBr^F{?s(P@&5=+O89*dj zM5bhsB1oqerXiLot%9hX*+Hz3+#0w5REr7J&}9;7;+{r5&^`1qZ(efolJ-?gMI-n& zcU5~U>jQYs@|J}Qp%7+UzF^6+cJw-bX*eq)W`Wpl`y=Cn1|8b&UnPQI*IoM?sp zwI&+tO{$a=H{ZCR2J=Nrict4JfO&08=Ad_|d+;r>WX0Sz2xkOZI4{u{AuFWB1ja@? zsfJZaHpETjG|=K~esIl|C#@||Z#8;FXqP8+OqtA%$zQb2{A6;ZdaqbWQMhkd$?Oan z(|OKN$?&LmQ7G1{hDafW5H(7O8&kq~E1C#_WTS|QhP79;aT??mbD%PNQv+RED%poH zQ?r-NpSv>EH%QG!mS8xsN-~99UuvBsQ4_&|Ru$qkU9ezS1-_#>&cx6}B($Z31V;lG zifAAnZ|X{}YFWmM8j#2X!ub$wzNN*Yy!Ij5T&2~rlj=&Y%&*B?8;x^B!!)*Wj0|{F zDGz*zlX$e$)Yv+zwceVzt)p7&t%XsDEY(^sW-g)ir26|)n!UE(RKsK~p|0B0#AGd` zu7)cUBU{zd(UNb^Lg}JZ>S1V%=JjYzXCLgOn1bXWp+{%XU)CH1Ysn{RICG+1c+sbLbqx?e=%N;M<(!3Z=Q4nzG`dj)hQQiF(u^;Yj`^%F-I5(BW_p%o2eFtoS;PjS zumS4uC_28IWaBkkAEuvNDv$Wy%@U)Ljqc(;rEUwd>{e&H5e7pRK8soxLw~VhnNGs= zoXZZR^H3A_oXjqnf(UAe(o?CvTra{0W|NLulj$n9rFEtpT9fj!dzT z!`#Mhkl3L~3WYJf35`;*<(J0x2Pb0PK#AFW24PLA7|e;(uSm$J&rOb#h>?cGTrYMA z`_pi)c7~-On{#z__NQQx&;sm%h64mKPN*lJP7gTAkXvMjZ!95;FY2L55#^x2Nt-cr zIQJT+XK_rqL194e4%Vaw5RHM$^l>ccV;L!(Y!$>3t+)MR`knJt8)B1naf_rG6u=n= zH}^Etv>F%(iBw}oJo!cOcT4BA1w2*8;jQcJ=;R?%11n;~fCR?zb!O6i;y!AO)nL$9 z8TXgZuAzMbjtosR)~FhJ+HJu~zf<^R zkkpW)j6`L%MA5CNuh7|>ru8cKCkz;Uok2aMI#gi1AvVw6^d1y;VfJP zf7T#I<){GD6wTip%kEiOx}yf*l$*-;yqVo7$(Bs^3=DQUyMYnfeIT(gH(|#o+cDUU zm>E$RsD)TGiMUlHGl}{VCoCOLc6xivKa*CP`ae zRF|QOzrk)L?Wk;~t@mUa`tD^q!`8RWGX zlx~(~SjU`3n?_6XSs9MCGR@UuxRT4L#pvwDUo5$(isk9_>VOqPmRL+YQwOn#6~U(&0#gGrPq^p`i6(>42aK!k9#7IGF*7eIPP{_Ee9oDkuP{ z7q6Wm1<+Sx3UR1-HGRhn#jOsiv5VaEcxA$i74_mJ#gp~M#b{6qTgl4hX?KQ+i*3h^ zZO5%`8|L|?%wpGI=AxG7;dPzaDlR=2N6(Q_#L+Ido6%@tE^t4`Wgs@7nV7TA!$irw zKq`Px(&Y0HM+8&^=MsM9sA8S7n%B}}Wp6Ex^hKo9}PDEvir@Xxp<241??lpZIXvq^pFfu11L6E|zqy3)BINt`W` zDB5)kH2&74l$2*SK~0idoC(g5QW)$Y_is%bN-+T%(#DG~V~EpW;*^ua&hBiUm#h*a z)bVIRBHc2}W1Bn(F)4nNjAH}Inre9xgt%B*>e)kLagO@o>w!TL!mI8rV52Pl!co%)}LDtQL?<#3^sw>v?zk< zHd04?zz$wkF}B!_b;Y#tzLr5&F=H4CxOboKvXNC(He9&&!H!Hf61exU8(_N+sF!>=M=6Dz@7#ISqgPipYCdzaW?9U@J<##4nI|q>GZ{b2IqG&@4 z$o+GaN~L3$fl7fFkoc9Xo5rK27&6Ut5ttCyk4;J{b|r58>vR{P{cczpf*MYwJN!-} zg>@0ycVziFsv`xNc{A;B@_r*kvu!O6>S&GUGLyJqhIm{s1au=nM3ycyNeE^R>hQNT zs9TC#4-PYJnt?gW5gq@@ke#M}sExOvkpe0vHqGQlT6&xVh zyn!`aiQVKn*#@BIiXx-~Oy)W>{UTK|m!_J@7pa}JjwSt4ztsnZT!6yGs)TyQRL?G}v@37MLyDhfTyb2NDCbCGBY%>^&9>Y!=~9 zF&Lqk#1L=>Cd*4a2^irh&0J+SrDIhsso(JWn;%C~HOIouZA z2Z^8`Xbv^=WZbZ4;lkOYu_4pA&?!+mjMhZPI-qgss2oLuG_pur(mmwD9G_t(Nb#GF zH!$}ri0%$_x>tdQ&|)1oW6)aG1C22030m7b2~e(C(eA#EH_O?vF4?SQ$2weE#XaXrO4io65vZxNgj24kO2>bRU&s5{kk!iaei| zXz5gcvOs}8KQ4mDizom?^bd37r$A;o`wfo`*@T=)A$ueabfvTlrqpvjZSoohYlzs1-mSIV zeWZs%P1j(5KknTHK4>p*Bgt6o%E*JWQ3M7M6MrCWA%5;)7X2I4l~4CuO&KqM?Iz7h zg9|y)j36g^nl){5k{32Plh~A4n~{4+$VCGVf7n~&F9w!bX7#yM@W|p-9v;!R(qUHN zO&?PSzQXMy#@`#wU~7&ZVoRpic49M;_K@1ANBK?{ZXU^=U!WFe`6R8wJ*fyQ3hfnH zK#5uk4GD;sPZzN$Rw7(F%gj4~cottOq;81Rt+ia-PU(Ivy2)EgKTc`O_Sm@#j*E;9 zf6yfbEd9;og&{$+8udsV4}G$8kfB5KKO#PC{WTT&?iD6VjGeeN$4+y+qM&^!>~)xN z%1WR|7BK7vF+!3wq`Ld9)zCu=NI7>f)t4z+v!y2%K-_Ki!X#z3rN+))yd{M!?Xp#gV@1MKoj$z31i2_uEwP#wZtQ|JMQ%mTciB?$20rE=3DP3~B?kx=Qe}Lu?n9`XGf@$O+^< z0yY_s`W}y{`xJ*{Gi4bhtvleTO-J{1MIH2jo zoGAd$0SVy8V34U;&G|7VykaDP(E!F2{%@C;k&;P=rZo!otlgp*+io4h)Nm>g%|pvA z8q@SW<5H2vf;|%w&H_^;J*z`E<#uyOdnoEZ*h{v_uhaN{q(p7`o;6r{<^N2(*w|FH zT4!CV*4MFpB+(+knm$39b_vCJXakkBWv@$9b&dslreF;BH*B*tfq$LVzp;#at;s!8 z*FR#9dsgEAk-yzjVc=hM1h~%M+Q7fk4OoZwk2>dnv$pT4IR7?AzgIqD&szIW8CP%K zvHc@L|9{OY|1YA$J<~r&L;n}v%C0Gv)B2`WZUNbq)f=sEUUywXck`TufL+&&yB5KM z=C!NVl}E6!8n=+wE}=sgG;d-(gQdRHjIrw(4t^?kU&x^UuwO&Jy~ElEwVLG&p68+2 zhTPxy>lC&Q&g{8sVJ~kM9a!8d>QIzYl$Wp!Y-VXv>2)Yd*~I_d(#FPT^w^S2{;$(Y z@r$L~1JX{~b(MB9;&w9Pb~2)N3LCXf*c4Ganbh4^l$!d{L$YxeJ*@WHk%|-IxO=MDR(E2MxZP7N*$*9W zqqv11Rz7Na_JB&q=bdG!ai_X8pI>1E{f_sxD?l9Bi^h5RQ74rzUeVS@i#GRte^wkLiRT^LMTM7V2Jn;G@_}rzyfB!{@nh(q zm0Nc3L0Zm)C&kP0gXV0$JOyU+;2UbKlEx6&Yc_Yx$_Mc%s1=N~F8lt^EJFt+J0WdciZ-0+A=*_tx4+qsqy>b#n$xs3EnzgZ~nd=e-~%V z3%OKhn#`r#7Fx~|Sa}DY&{@q-Tf45*^TctMpL9}r%aTP)m$fcmj+cidmo7Yg&a$>8 z^oDL+H$C^$MIBRioa{AU{~&$OoHli2|9i`t0r9@ji-_xF&%3C_d-bAuz~fzX?)kC! z?BgARv3epSdZ#|}c~d=lgSw=C3W(17p6byXj)nF!MZX7X;?$RwMsF<^z5{_I^%$i^ z6g2|T$>CGIKA;9h>oxU*iaw%z|EaXYVPNz|{HZvd(bjgIqPu{k-e;8dqN4p^c#=x* z&8_EBntMj9y`#|wk!H8km#y-knN*S0!iN6fNEL#$CUO5MK1w~^asGSCC5RErUOZ8ozj{W zEdr8yF9V{pMW%Y6(A1k1-KKnhQCd3&Rg8122Z}QKKG2as`*?Nlw6Z**C=a6)`K|yG zzH1bH9;lg1`Hu1}JKW}&afC%{6@6FHQ;POSu~Nr%6=!b*@*bS{uc zuo*~7`IM%9UeWE!_g~8Qq^3Tt=oRIgio&G4V-yt>-KXen$63CVqW3GhQPG2no>UY& z-sat)=sy)bujoL$QeR}LQ*;`T^v79>`hi3nA5gv<6y2+Q-&XWpbt9-+n`e8*kDBnHG_hUsrQ}i;B*a00SAoZ?LbfcnY6-_z8 z@A2ivC;qb}HX~Gi|+-6&(pA?R^)J$TtKep5Ze<;u(IassE$s zFF?{Ci)MKq=2Li|p90a@4pY5nf!@VvDh|C6RHLX}QBlz)iY`-hlcEO|{Q?O8P{;4^ zM`Zq!qL+chCw4;+hzP!~0Kq7L9srUY-v>fBf%XR=C<(|%BLq!Xv`Eo8K$5qhXd{s5 zz=xtv=2DIYIuvLhZ-$~65X={K%u!mKqEi)}sVJqWsOTa^A5wI+qAiMUR`d{%$oxAX z3~Na6il!cdZWc+82ZD=1>P#TXQ47?}v@WG(f#xvngG&1Zkl6E$O1oQWKLirJ{94h| zie6SU5!09O9jqt|B$jirqN^0$py;cL9#Aw9Q?9h*07b_DNpE!mNjuKh)JqjzuIT(a zTS{BKZDkHfNXDjMb)T^jZQBF}& z(ON|pC>m09iK0stU8ZQWqK_!LR?+o}wkZ0HqAw_#7P2imOi{U_3Pp6{u;{N!QMIBP zMR7$ZDr#1gQ1o3zKT!0DqMs@HrJ`ReqLYn97CQSw&@@GdDJoY~p=cJpNCB;<>+id8 zO0d7%5?qqJF#eX~vkyMVjO$?jALqD&t_S@Zn*Brm{#JaL$2BzU&$&J$YzN>Fl^3OmS_Ltn^(&W7M6B}eE~^&rB+5(y*Nk}G%Ftn#BKL) zL6w-GcDvp|4dRPhO4o5?D2-z%^T$x^8A+aJ%jp@zGdPBF$ry?~3n?h)t7CY+HHPw^ zB^3Pp6u<2*nt^HM`CSPQwe-0$lwD&ew67o+l|wHd7+dnuB|OAUzDzD#yFC{vXjfYa zPcn(O1EurE%xtb?2@jQcP6;K6gFQ?|_`?#W*XBwoYmh^C1$E2SOWHjm_mO|R65c$% zAEdjRnVLx-kPrCGE~B!z8*NI|=TL%tW(zG~(fc<658q~Szw%Fh146Jvrp4%u33-iD z$;KDISP7!g&nUBbN)o0;>3mPxQ4#a?r~3p+(p8Dq+)lA0SxQuDmN!9s5WUMHft zm*J;gkkr&o?Me#o@-?ZBIr)5Q-IDI*bY_Uwv3%V?r+zWnjg33m`Aui7@PX2f#aY^{ zwEfLZqu;HW)PDY9o3}sDgyyHJ+1cggkx0BgR$GtP7?hV+m(wNx;}Dg)I?(Vl-UgwZ zy?>ieKFjm+7s?9E!wl+rVM@!r4OEQR>(|gXY-Zw9jtR>3#6%zOYQ`kxdgJkUh&Dug zjz=ciVO2O-=j}LYh=MF!)8x-w*DDk0n}}RDQ@~$(&2>F9B`wAHJY~@H_FpfI75LMP ze=COX8-8-b_UXfeJ2&OZhtGO`c>Sv*chJ7+$iW+44i#5kc+!TKCrrNNv)~_Yub6Zf zO(p;n?uhby*$;EkO1d}Qm$;LeftuMTfN>w(Q1UiR-mvNw1?QUdzq z+uvK&z2TLKlds+y`6}-}=pV5pvS-nH3YCT8I;t04Ci-!RK%hlzLD$ z-F6(ldYkU1#hkZ-v@s2O7&&VqQ~|Y&e2ug*d|1V%_m%HjIep{S!O6Qda`>0qzW#R{ zBEPlx`;mP%>Z|gpLFNw9 z##^!S8`;o|Hs3pnrQe;mPV&6F=s&1(WWxf|)i)`1c;3{J4ND1(Fmc{AQP)*Od-{u3 zU2lcD2ET%Gr=Z-YKSvcz1o*`83xPeHwsQG~?ctHui6etkMpjH38RF4#dbr`S3zt+r zw&9ft#l;(52~WO+M(SpuO{cuNX3DOLPyCv`PyR+|p%;F~+>PJ6=y_m*f=cS>^_ssQuFw6~IdWP@c zxABEb-yOQ>QJXC^+`41(J?A6m8Q^^PgiYsp8}1KpcqUBwk@St$9i|8>Y%cibhPbo| zm!1)l(k5K=Ln+M+3-l+qe-gES#gvh=Z2NQJ;YaS7Fy^S^8IqqyqA!}Xa=GceQsFNgtbB2^X)nq9UXhpF{$_}B?kSURe;dnt z?uPq98y{tP&vj|U^pAWOd0Aanzg1*etrLe=>|ibL7+$e`WHTGu`t6f%Z*CjOha*3| zZ`*|7)@>uL+g}{qHr)Ee@QKDRwvKMxI{A{vq2GoVFFd8B{nVb7Y>!``#_jpWgm-)4 zBU(28l$S(5sBdt5w*RL2Io+_0#t$*Tzw~w@r4!5G~tEeqc zp?>)P9VPWgzSp#9TVcis#9r~lg2`V&k)!_0o2E`N`o>_mH2jv4)+gpv-Ve_Fv*4WX zKR~5FIJR_C(*rQObaox!BNgIDU z`I5^ZB$_e_c8XR_8m_6JhV5EDCGu0aCK&kh!;b{B%jVtLCV}BD6z*A`;YZGT;Gu9u z6=>gFj{okg$A2{447XK;c?=-6l~UVZE0tC?-&`?n>Sk*nhmEY5NDUfUKWXGjwu?cu z3g%MGjlgD>O{2CAnYQs*-9a-PjYdq(yOvF(<`o;!k0Yl~-1z8)=TWY?lhEYDpV~;- zz=&*>kCEs|^B?DIli-z};P!5K@UY=W*ko;M&ly)@q^?H79rPbGJMj+I2UKizF+{1^ z*GeT_+?&IH_i#RR5}F}-H*YE)NAolLqbbxzbk`#5kJuj%h(FGmzp8U)%8D6xPV(dwll1tKfCl`NL;D z5!mPCdrqA&{0dz7rH{;j_nk8VT?ShC(np4Wfxl(be|hN~e3{Yu#HDk}HrzL1;|s$p zp1A0HB_(g4e9tPBx^413b1)OEgO`6o=O-$Q%I7k+qbxWMDwm4fh9ZYoAls??nCkYW z>hOiD+jql#VX5veTix&r&@VLm#{P0s+q%C~e>nbf3+vPP%S!U^=Wck)^_NOB{&J7M zkK->7qyEQa#6EKJ?Q7dcTBnGQe0IW%FT#hyPoYoP=-@NSKaP@_pGjtpX?z>mruAhH zwQfh6hr!X%x_$k^k+Zg`ek0#&cnR)n#g0w$cd_@HG-1VdxGy_jkeST6G=!{`_cy$h z-?6K8yZ;K<8&+(;-~sqDjf<($NtHV`of+B%0UCA;w{E}i)ZrJ5e}+AN{WfEdN4$H+ zgiFImoMPFJJUI$eUZf_Xee$iJkO4%Y+e)OmDkFAr&x=6BG_L7jMICrE4{-C&O zq-6^JzSI?{|L zPQK)0_S-bH^jyp{;uIHdSijAC`kmx)Dj)a76=LEGSAb*J(n$z1Q0^1lYRtc+4Ky4z zVGg7+7ECkq6DxxJ+?_k|-(Bp<+F)+&ffpqAc+X$)-#0mxTs2J7`bbvO^GF?6i8R;T z@t1K^X};j~%g&KSG(Lt0UmdwZr;FmrBXi5q;*}S_auTu^rw+q|4!$~!adg(s;YAav z4@W28zR!k*)5F6d4wyGAoP=_A5*LK<+xWfW(u-d%m5)Ri1~=K*$U!4s_izXl7O+&ZJ7|||T%|ouN~5QC#-^GH zB3Qpnm-QdaibD!WX;y(Rv_LVfI|ds@7FTTi-r(D17}&Kg`NLt%&oDiV4YUvO2*L@J zLUKzj7*&(*z+EX312Pc^L$5CYbN9;_q)r;y2az6&9Txe;PM%tWW!Z+E z{@|lrC>E7t3Zf3Tcbk8!)ip83wh$OpEf+PkLUzlT~V-Me$jWN@_{c1P~5 z_{+&7AGjOo!!6}^JOUjJ^S6-?Jjk?)kq=Z5xLm$YANc@{gW-=dv8Cz`+Tj>x8fG&V zca?xzmR) zrV2;qRt;aw;}BoG@6o`ZYVPd8e`8I5b8r#6=iM@a_HEF7K1G=*aR<)>K9PvHa7)n} zB7o~6e1-_%A`do10M~c%86rRzDi~sbyQ>bq+`%*yEYJQB*y08UcRKho2Y=4N_c{2t z4n7py16rnoS2_4X2Vd#nuQ~W(;P;!h{LH}zg#-Eu2Vdvl#~gehhQ^RbMv7+@82_Ac zGh>=`_TF+UxhKEwzQf;zZwVnE*y_v9_lHypei`ze-AMOb~h_|M?6{acI8 z9Lqn*n4S&ryh|PWjg03q{dR}Go$*4Z(|@+EU7*|YC&J}eJQ;Y1pJl+qyNp{nZyn=S z#tRwGXM7gpcQej0Zex52V}{;?jJx^E@$g+k-a5vgVk|s)__-mE?sv;&<-DBf)0y}M z#?tn?8H>$4!uVw7`2*u-#(!fhw)A#5lp${}(~oB??K+Whg6XF+KAUld@gmj@F4IsQ_Hd%Q#5 z3ye<(wtew&2mi*wQx7Koj@KQVmEf`E^f~xO&RZoy;D4)UB3OJM^9V~8lj4v!!e2Hp zZW~kYwV>O&9(C~BF=GyS=SV?L`9!dFRWgssb;~N;ih4Bv=*D<~aZfl4H!F9x8glW$iPd_sjzt_Wf9@956mblliH0zLeCgU3zpT+oxj2ZHOwkN~m^7CtV&~m7(|8`)Hu2^?8Sc z*W(?bJU8<5RrECh&5Bnhd?P;(DfAw-lmy1UcxB?b)SIW}eA>+9k~iqzk9lI1L?8B2 z%73}jk018VRr+S{0>xK&8x>#aZB~30$Ak1W0TlG<$Gy)f&!@ec6@Q$c_!0iq-W^IG z^1h?E;61Fk=>4bSLGLle=XrlnyvF;p;?Bqv|o!so$$(J2Fx!19iA3ApOBgYSHb?oHZ zx=u)-hk`NwT`#NhKkOA1f7?VKr1OUy`}vN}VMM=F`M+moKjQzccZEa0M)425k1KxI zyFu|+pk28V-dDY^E56mc2lyrKuP<;vhG&ug{37?`WX7L+&3=5yltcYU_)zdyc)#}O z*5e7lTi{u!AL|W9_~p$t7~u@T+Ty` z|58$p_2*O$>4C0Md|o1ei^dM&pCE6Ax36Cw_PpN%Z-GaqvGZqxX)OHB;9%@X{D~y! zd7>YToqhda?Cj@b*}xa^1pae>|4^k*@{d(K)vr{10R41;uY~tjzgF=9e!b!;ezW4Y zIrjN>|MN

    XRP!olQ0{k)P-}knw&#*+V(w{b?!d&0s9EQJukLCvlg5XxQGC8e02lQI;bq8M;Z5^L(HEV-TfBq0FR})cZqGM3 z=!e{Q!Z?KUwjiK9(+gCA`D^qZJ?FAE&rnpBGJd zNBMzoIoc2Af(rjS@YAnPnjz0Vz*jPUC+qDKj1Og>-e6l~P zxW%{5DB+##%c_*}p5#w8nxnjjDPHIYG2Q~d(xJ}+{yX&F4E>NTO{yk;IMd$-e|QjZ zvp1V<=@`bn8e;n|KUn9f4%S8VW%Xq{d5EO zj>D64cqk@6mwDb*;wwfS9;*kU$%QyrUJ>e%6O|48L&_m5G$!k?k|G{^V8$A7m&Z&Q4xzf|$*j=i1f z2kVqozMa<+-kJV7b61In58N4s(zc<(v zseMY{NAY=_04^GHgr5a}1%5HH1)2B9gtNu#W<4KdFzNXygQoz`G&s<6@Ps+mgN`5Q zapu8Z{~gFn7uJ&gAp(KV@efnn>mQ-`9LGPbcKW5?nG@Ig3zfg$KSl9?GxoE-^?L~~ z=dV(pyx*(1;Aa)*o&GBNYaROeii`e`;`97V6yw1L#pn1}DbD$~C|>P zvErP+4Y&?^9)dn;oHheDqhF|hPcaz7!aL1ilU4irY^D#C%oo-lj)Ixw%#Ooj-|jjmyifW|lzzQ`s^U-j z?TSC=uLQmqHr5PVqOu=md=Za}Uosxzx#_ozFJPW$45sl#*H-@D^L8@*(B z-+B1>QL3wyXQ{)J1m2%{F6DBjI`{|&PX`{t8#!p~N0|O09{Wv9AMu}X=Ig7S@~KY~ z%zqV^zu3X2JGjHaeZWKBM|_F_1{q(?am9tq^HHw%Ql?*1Qm?g{QPfF#rfU?R_Zm!o zfbbQ_TjAa0)APeO0&nrY$bR4}29qDS%izEd++<22ySiEZSOVqPeo1&=a^m@$oOu3b z$3NWS%==$<{KKvO(WsX$?8!KO;6I%B^EM~W|GG2Yzv0CBcktMM5b`%ePAc!mjBjB% zf5Z4oY-7(d{xa+HCB|Q5{xSr!*z+l|D=KF)({IzZZv_n`zDDsst-Gg(le%)xcZ4d$?atG?@BjzQIAi-0Sqqy^eo=(DBb(9sS?u z=>L9a-rwrX`}aHk`98-#-|v&GbS1oRJAHJ&UnOLw2Y&k@XI=cTf3os?--!W!=;xIF z6MwVfANn6r{1d0If9PMY^zZvy6#tk1CB^^k-=X+dj^BRN@zuZbWras=`L%x}w0J6X z+w5&+J4rIWk8R@|;34k;9*^fS{Xw>Yi<$my9-Egj{T}U$t)~8Knf`;4c-yvj6g*q- z`3&UmAyp(&!q+#~u5}8!4!-2!8{4E4)#kethr<@D}fJwk!Ij zK4G$}-y2MJwZq^bo*dP7CA|M}#_XsQAO6li7J2DPpswQu0{_m5+n;dkO{@sIv#4n4RB@khVYp?53(qn}ayl;5ZLcg`N>lTQ5bgnyaxJjr`CFQM(tXd}h* z;Tpn^vpq}!9s(x+e~6*)3!Y;PefRYm6+4R0cM0I4z94)8_$$0;eERvvJm4+fpSUlU z8BBd~mci5)y#`MOrVIO@PG3CZjQ8i9etE`;wRSjt^o%o>pLP7|Uwl-i`tMczvfrin6(^p5)!9#e+3A;8{R@=;@BWbDUCx^8@6I0DPG=A8 zul~1{f2aSL;^+O}Dc1o{}bE5e;7>tez(E2_WzE-ZaiSbVS6AyLl@Zt;U9s&!h1`Io*kpNJZ$my49@s9EtlLUR>Q4YewM2Yyr}7u6N44G#$|b?EJi-x><+ zYI0}|==;}FA598T;}2xKKi^_K%3$iRDuZoIvK2IYjRJh!d?Ec4t_OdGcVvj3=Q|a6 zi+2R;|15(^|GfqW`ajaqf4QUoBOU!8?dbm)NB_q<`k&$Gf2O1V8IJyEI{KgC=zpf8 z{~4iX$VpeiJKoX%Oh@NOhfWt3@Ej957r20SHGAdUmJ1ml5h5La$Y4si+ThpH=SNJL zq))7EmxjXo$7frQJ|pxY#jBitIV1E@rN1ZiF~w(xKBIU(_gw>Y)eJq*SfKaqG(&H%W&b}ic}eGl zmx8~->k4^LTp#cjuhY>j=;p#R9$F@z>j>?q^qvrg4qpi`6MBc@b3(zs+-k@E`y89^ zcYH-I)U0`XLi2&wa$C~uKQ}P$w2!Eav8A-hOYI{3VelX4O$gEWrK<~{G#Q8cWA;w3 zt8w-UysV)xySFFRk_D0 z6uIk=8?OKu=W41}30z>L;R45qgm(yQ$@OF8in!${Zt~{A5bd+yl?@B3l;Y}fXTtsG|vv05~J-cAD<%;<(XfsKw zr+31eL&oVX>xL$0`QrWPYsjb#kq%qtLwkyueqqG1yiCKZ)sso0*3~d?4V~r8F2YM@ zO+__ypg3sY4M;HN>6AdPK9NJ6Yxr1ZK6x`B!7jmuBN*@+pRB0?#)#5z{Axg=qnc}Q zjx)VAr^~Pz!>jZH5)EbWkuBndRoW713aBoT+JRQ$z4sq6?Wh7Ia^-TPuti z{gcMJGXq`pMk%njPmfV26r%C!RI!-Pn3EmlxNPp!PWTNv3!OUFI0~kxIy>pyV4>qQ zW*m&n^fmd6vdf9gBts+Wp%aqjBxX6PI!1?do43Tn!NuNa@_~9Pa&mjLI$n+Q zwY5DNRtz->T11oL|Kui-=DA6j{(>gKrA4c(XeyhEhK?*m8|vOrG-yi>?cPn>MvJJj zRNX|E)4LsgM{D^^Y)3dch~5gfW;a8CH5F=W{uPFRAsHMOz?}@arIT^QJ$JGS8}u@t zMPFM}^M<p^~_HGu%7(9uw(S3bNO^O-<8fI3tS{#`b9WWl^*C47_GwDEZvPU6tr^T z@`deO4tdIYng}FlK$8gI4?Jfa91YfM;+Tp-rOBK{z8)kT2ts_~<}u3=+P9jm`8ZdjIXQ)+4M0Ob*ebNABqh}B*G4(vGaxz(*p~7@J z`o$!4W%8I+hz@@ii&9rg6^Tr~l{=pGLvtk5LPW9B2Wl8rGCM=Ybe=O*GCb;C6pHn#AyP;oM2!;Y z@OmO*ycJD^K(bN9M8n!E+BgmJiaAi3a@L6{mFz>9soBfs&s~}78>D6RC7D95 zFSSmRsEOb}s|xX&E?6+E0^iXbXJVjpWFlxw2?++y4hRmfsVljvWf?DOKq3!FUJ11M zmKKYOrvh!R(rVe{yOJyOYx34c;~dd2jcptw1Kw2110Uif9xXLBwvKA8w6Yw3G1IdwJBY=!$s#rog$+=LN73=Yk!5(@WjcqqS{Bo8mKcp} zbQkw2bz6{Sw>sOYL8Vs-t{340 zcd&HSnoL)**9|enmn)eQt7`M2s{f=6bO~*q?@TwKFUQ*_^AZvma-+krrSNG#ns^ zaY8+Kr{;i@46U;9cfdE6ki{4E(4>fR(BGuZ7qb;jT!Oe7scN#ozoWZ zR2hf2uCt?)he!>qhz$c07{}L%Gw{TH)EKM5pszCSFP~jQ`ve>vut^yI*O~3xjqW-? zde7;ibg?%}drT0LCQ1A;YOGN;^0eE6m42u2$snmAM;VFAYKfv-QJ*=IPWlrDjK0pG z9#S1DFy0WmZf`!y#exeuloZBhZMcd+Zq=RrbBQa6tgep~Q@)Ie7sFEwEC z6br_yYKP7jGbM=6+@O-OgvKuv4|DHsSI&C(o>o1$cExob;cFdK_Ky}QZBZs z0#@-Hb;fhlvF8ZNg@c?2YYEuJfz%lfTxUJ7NU>r7jT<<^&6v$pFYDltQ%LbSS@&KX6}#i0ix7oK#4h<&{-vn-=cQ&=l` zHc8`6JU0PwiOoJTf%a67tSTq~sTZ$}H(h7RCD$8Mz1(QT;P6=%Rp>EGcjkKhl!GVfm8sYq{-(YjtHm-&L#ZHQN>u5GcVL5 zoyhl7k|4uxlNJ)0e41XVP7AaM@B7dnv=?SoUF?FpglXYD_vm!cp@1L)j#2oF>flRp zOANepuPHrFIA@dk(gQs~s3&gLrpfV`us29bVI90Gk|^4B3pD=Lq?D9rHbG62Tbv2b zkWv`zAop)g8&#PA4Qb=Wmoda?FmcMsVW*tyX~M`@9gh|y(k(L_*z0V&Q2Ztt#|Dx$ z)le80TI@xx-rj5XMkGMuslx8ymG!{N@U}dn{ao&X;sVTpUKz zwgFWM9hk@t1!JpF8fwN2$F>yXN#6d{+HsPx#xYgzo*nIk^Po_V_OYSF-3t%~THFf5 zTIeI&hh+`zUy)f=R@GPY42#_B#z~CvA{vQ7+8_sQEIDoh8_}=>F@QbJ>_B(MD!N{~ zXf5^^Gj5%6^pM!!x-m&IwoqdZwmvY}-+>vEMh09$Fft-d(q(ZObKpimo6U3J3|=^h zfHz9p9au{6BC>()qBqsoUBr5-7XujgUbytC1|1aXwZ(kOta*&pM5<*?gPJ74`bjD{ zQZ4rfD3Q9I`k#j?c?KG8)v|?x^Z{Y83FM|l5lpv{I^qL%@Un`r#nNf9#`{_ZS;dTD zDDVNcHnNJ!h6~p|*pcb(vTce6Ms4V(T-?U8{X+{6jB0K)4Y3ZsU?Yt?QY4(VwV4Pib48|;^(%g#Pp!_rYESqg|b9>xj=h5+jzXFY?7 zG93i_^T?0p$5xxX^_tvkfgE_s>x(m5yBoDg|CZ;#ab68jqS{$TZVMU_x9! z9jc9DSK`*cPInR7?}n8jsNqDq!|x9m;+t$*cj@EcC zGl>gkh{pv(KsN$JWa%=Kgka{N4u4C7x}~`F;4sss8JMFS(cv$|aVPKPG`w7P3hBTG zc}Ni2*y(1U%PnljROB*KU;ri#4DiaA}GKJr?HQ~n&xyKWJn-G+bz*d-ja(S<{;5cP{!GfyAlrT zC}p$6_$otFWR2he5}qKCz|TH19+#0$jM8S8 zDGU-&*hI2n7X}fNNu^PTT<<7(^Inas-x(r-WoC=Z7*dGGXu0xS42K%I?4z zkc=oG8V`(ErjQ5)_XwV~v+Qy5t_?K=R;?-Pt#!Uu~=ZU2!D#f2*o6ZfHN>zUgAl>2uEq=D!VC73+q@-V8Mu>X+hYC z=f@D8$7%xW?M8&trRz{E(6O-{*f2IH`gzM1SV^#aGEFMhCK@x&K`{onZ|`qiPB-TCNkCmjY~)6 zC>o@ZMcR_?As6QO3^PHB-*mizxnDtacc7a^EiKk@GX||?Jyph{cC5ptWi0D3&=~piMiUgF0~(j2Q*c+u99h}85(=Z>CRnCKYG}1jH|l8m z#M7FETq8XUY+@VIJZ>fnN#ZWrOz=u;Ot5Qp>&=;ZgVLN*=-~~ND3XFkV)7x7xCJaZo<^}j=RYX=8WJ7qL}hDKURTMl*9uYFzo_!= z9J=hyHoGHdf?Yf_O%JHJ9SI9&Z__|Fjop266`+*%EsR2KLX1HBRsk)4Q8LBUfz^w_ zFGF-Wj-_S;Tg!HKlHG~50q`ow9TUz#U|!RN0=EUms-r_{Y^MP5%~dI5+9Toe(&%w3 zv_8`a^7>z4Ite`O@{bHT^)7oo`tlJpgcaJOs6$acDwBiP6SZs|mh}2LQ{$E)HK7Po zXUZ04bnp+2pVv|Xk7L*=FBR!owKp-GyK~efdo!ervFo0X^^Il#jX##$VWMM4fts=S z_tzLW9l3FQ^c##C?Wcfn>ya;rW-&!kyU!QwU22GTgmQ3UE^X^5=TY!XTW*cZsR7u(2qG*zO@uzjElm{>zha|fC+K}T z^pn52_|T>4%PES(Yxk9KbUAO_mmk|zK9DVz7Y1`V-fG29`spV~*!?WeWufkJH%kd; z`I=0zm-5rXrd;lKP@RZ8GUwv~lT=?h{emQo0Jf8gd&7ce;=W3`*{nu6m!csT<8wYf z1$_GO`F0qucf#kh_*{+8Mtla#@H0Mq=*Wmxd}{HThTl5A4Iet%VFEs{f>y|tA9Ygs z;uUReWZX%k=2@LcnE5Ufuqy}AIIb_D*g##0X4ICytGwE)$L}9!;&Ti>hu||ApU>ho zC|BdN5uZVP()c`t-==;GpReKbMSO0+hpG#rdM%#Gx(ZNodAW9DW4U+iVEOdwwa2cl z+}|6(oq%!=)5o|SAU`e(de&$ln=d!IsrI}G6n`{6`*`##c|r91VtOCSR6dV@er-S1 z`#%1scPCEex4jA9U-4Z~5vEAL;@`)6zoL&SqPOr!>g_;P%=d)Sb}E__vV8Pgb;(hs zs8$i3zAdS@D*C3Pt%|;_Xd+BWa=cB^dw`B+S>6MqIss^^w;D)jhr)maZ3UXasZT4d z7A987v<3K)v+ylblmt4SQ@fRxQ?y=FFHzd%imubtI{ds@N^VxP2KS;~gp}N+=v*Kvd9Bjkujs>?`cb8QM$wlv^){v5uju=l8o@gj zq~0b)3xK5FB}!YRs9RINueASG^jl4RN@*`DqE}=~$-_WW@8v)htmiK)?RKE!nD&^` zey4n4{B~aQ9;0Zbq9o916B&qak zcxlnEwY{T?o=~(+(RM{U6g{tKr=nLCAtErf(fjqJUOLxA5SnKkinb{FjG`|nx<%2gif&VMhoZX`ZB_K3qFMAP z2Q)(0-|^mw9=|jKkQ6$H9&f?L2L_2S3irbX`_i+j%asD)!F>4gy>h$<-F(^Y4@`nj z$Y35$I}!iWNohh!Vv44HrE<(U0S~>qqZ}dxl(Rt@RZ5a~Hau?#^G?8X4tTag;DB-= zC|fXU0?JjO&>J%Y$|pdfcjpNOCDRJeqqnvNJYN70y>Ba^+)d>`K>_6_pwN4N0?L!1 z(3@xi%1fZoyHo-SSslI6gD6l6E`FyFe1lMC6>%Gp=|n+a`1GEJf}zNtSrm2}3Y9Tl zU(D(#XeOw7d>-6U>M-R{|4;A_Gvm_`@n;tCU~7*kP(FC*9J$hKRz47j?Z>D7t|(zj zcJqe5q1m?AQWN;GZzO~9+FuJ-YLE)kX4`|NWvpnhM!@9FP({+uWG<~{4Iz4qE`uRWe~&zjgN6}e}2qZD_e zRCS{?cca|UjiT=qWFCI*5}TL=p=?G9e?slnEvCrLQg!vwxbR;>Yq_M=mT|SWA9N_YcJ7Ybk>ifH5nLPPJLl|&C*vAokxphP=)&Zt_E>BF=0sj9WkQb> zD#iG~N$H{uSP;}c=>KzSlApXM_tc0D zIbE3CRtvU0c}FHin~#NUkzY!paC62hiDg%Vo7uN5VNS4PC*R$icz_Ho`|Atf|48z1 z6W9{Vu4NucH-bMkv23M1IWIkVtVo9UvoW|9usP>Pl(Klkjw6GRv_MUdPL{CYF#o5~ z=4G%@dFzzj9W9@tY*FNAt$AI0##U?0>o&G*sh_pL1I ze#VT$>9P|X!tob zS^DXN(2{u+zSx@oY_z!$jWv2@1+-cEDLav9^ID-iBa}0RG7n2OSKkOKzB^+NqsHfN zNsLczEqn^OCAZxKPJnPtjcV8uZMuu~K$nFRurFxZcWAWvQUSfA%`F0YMVo&hAlU~= zJ~%Aee6w6S1TCUz-{H1FH1u!UcSL=9)4n64&Ht3^aI4~DDLy6I%&9J}qoV>PQTWtL zNo!t%UD|Hxu4C(-ME;fuIlC4Q97lDRoh2@u!tmsXV~oacV@Bt{3V&`+{bc|Cjyb3l zTpPfG<)@5ep|=B@jufPA-9w|JhP45utjOO@^Z1=c$HO1*-@o+JiOXr|UqJE2LzjNK zz6ob7x6#4!UwnY;EN1`6wg^*ptO6H&Ji0b-WO-};?v9W5Q9|97l+cFx`qEFo`2(ge zmGsXh3R7M)ZO_`0B43tV^&1ZTmVT=3TvMj8{kNR11^N_ekh%@)ZgI>FI5!y#sGS6T zQba}~e{*@$l99;zZ_KXn*@ur8cS?CF{&Es>N_#2kWx61ZfYZ=`vw6i>FS_={@|<%= zE`Ge@*GTR6Plc%vF9Fa|YFG|B@88n#I}}rkJ%DCtJ01DZ)SY?)9gmu8K9m|cLsi*; zWr=~-$@11@X#?n4RDH4Ipy=8yO&|4+Uin|B-~H*=B_*>aH>2z?!o#URz>>}D$rXy3)+(U*rP z@-TV0XddJt*A@AHr@R&UJ4GHlHp&xDw12sX|9bVV9&}2j}1m)Md9D(6BIlBB8n65yx4OSzmJ|<_IaU%_#2D1yyU7F*n z+{5WI)aQ+~-r0R_27b&rn!l!6<)~KcM3KqqN$X)5Bkc?&wDkuk7>(%wxglMS~N6N&tKje`1D> zDEJ%i`-ZAQ!RbEctEBZ0jM+ZbTypo0!U zyWc%Q3(dzEFk!$m@8o9(zdg^o;jah zxo>ztHJ{@*9sT|(ndE3D51^;#Xx@V*wI3Pkj|q<;ljt=sqo$fZ!hFb} zn?_a-ckNg(u6FKNI)1ZTGW?ci_^=cPH7~Z_FpHKt4{1V0ORV9NBf9q7ku9&(e{*H) z=ybNC+2r*5cy>#0L5@EU;jO?}#b!L=)~YLNycJ{jV=QlZrD0=WXqUL-NY&^()reWQ z@pa1pUEE$xkf~kilVFE2mVPw35uo`NtTC5AP4GssJ$F}bWK z^W8lafiog3-$&w_Up3uF`C}muSDynDGz=O72fPh$Q*4*kkjU$YMQF=|@J=qNujYTO zm5a4sQQhC^Q60{ge*6!~?gP!v*%DJrT2p3gD33pkp$>iwJxs&#egQ($o{me@6b~Op zyDeJ{KCbxKDj=eBW%~WWk0@^OlRNH)3nY?SaH6j08#|P$W17xZqLf~kvYuTrZQ)FW ziq!G8<3%l$aEgK{ZNkl(>C|ItFWa#e{NIYU^uzog+1fP2>2e?vGDJhP~Xq8VZ9T*Kk3WjB3Vcd5bjtzQqVz#d9uN?<7HAF)>P|9 zF%>$E9hee7g^s#*#~OkS0DlHpcP6eUlGd<8U@kj;1|rTM$YVOTNfNI{DaVm9KV^NN zuo<=5U2igK?u&K(!ux4#3lM^}1r$2g?S_G`_AND8Qb#d*7|m3QS%Q2z(zJKKka-rS ztV93F?KN(erO3uOg<2nbHo7*_v==kXx725`?Ld;qvPSM?vQOE>^SP?Vjsy!ylWO-! zi+8*(UBFYXCGFeF=X)vA-{a@n zsk=h6?6?$eA}qfH%Z67D$T!*Y!GsUIMlP5`*@Nzn^7?>J`kLcK@x9#zcH9cZ**4Kb zQ<_-1$04p`1*R1o&RR~?QSr-~1dKT$3mmdIcHlWG(umMpRIA`LU42x$4Shoa$cu;y8cL-kSvB!%PRBJ4$<>= z%b8{~)Fdbk?Y`reVz&pt)1?|Z>SeD&8`Nf8@A##7-Lq});^d_~ZXKk)#P-O_W1DjQ zTpjv3X{~v@jH$S`+Fn?Pb>u?`D&#m|BwLS3!-0(VN3>9Io~)do<-xPHpaZQ;>?a*a z=9B8;W0aH1wc*Z+={OnAg}lxq9lI;iTG%B>jlonqet@eBtR@GZEOcC`@~^O*$<(Ch zR<{e|g_xeZ>KzlXXN4SY)O4bkxRuiZR@O>A?p@)$Svl8BrNZ`Z@as4oqF`C{ysR33 zlG5=Mg4H00dzlU;^hZB&8)+5JZL)OGY`2{0EQ8a-x{d0xL}k9My0|%msPC`KmGgb{ zk;wghtF_oStTmG;=WpRVt$T341UE|3SdO{uD3aS^$xx$DI;d2r`>G%x5=d%vI9O=dTW?T%ETITE!&I2B8>1W}8qs6=h=;P}`_|Xvl zID~VMna}^-5Pl_udtb)k4XyXXNB+$A^dU(a~9udZV*BJ1V1NuwBUTL5>Rf@tmNCrX9*8( zgyP^MvyCPu_%gw#3I4v|{(^54oFTYP@NmJu7ksARKMNisc(>pQf_tNTZ8VbvpCEXK z;30ww1&X0!3zZ6Cb&xQdck#q`Q?}KX`!qB?+6|wJf8?w_CKHj zH!3s>(13h=2>Nj!uLxsAALzdPBy@E?J_5MWsQph8JXX?X3eFdtFL=D**@D?q;E`&l z7HHZ9m&?hiXxNSBV!=NVtUOiN7i=^)>IuGYvFN)(?i1HJbP2#KYLxX!Z!63GCO!^&$LH2&ZC} z)M(~;Dk-oP&wab~1&=RhK?wg;(hl&GI{t9lhlEF2F2WvVqe;lg6@q!IO%Fe>YeDz( zdLe|5!u^;=bD_`PV_toQN1wJT6wD_&@VLIp|iBm%Po=QBGm(57Q1%mlpXrq}a_}hZd7JQB1a|EvwJWKG~f@cdp zCY@=|75q)Xa|ACGe4gN&1kV-xgkXX4<(K6T-w4VQg}XGG2OX2oa~kOBh}6UjX9BNA z1SfQV<}8a-YzjtmvJla<%0khf$|Go^<|6Pnx-=nEqOu8Ld`qHFKY zXkB%Yg^pexX>_cjF&6g%{i}lKM|`8SgBHW5pU_w1_K6^Yv?mP$b&9e4${*ce$t?+Tl!OGsKc+? z5t3=&lKCw!#m!FFQsa0UQ(F(|y}fxZZE`4L=c(ReM<3v|IQ&iT8i&vJu6KBzcdNto z-WrFSy!8%$-+RL0)!tTzZ}nbw_*dTF9KJIY1^vEIQ!k}&@%W^c;@7@9TkPrM}#f9zf1@F!lQ!ykKm#zkd* z;w^XhQ;*MdD?KT4i^HFKKX*7O!ex!3MEs{mN#~Q>%6~{i?xN!) zZjvK>u1D!9kv}?oROD|C9~;@_aG%Hw+X&+ZWpQ{$5?4*$x*+raK&s%yRgc$UKKniqtrKO5{d| zPm8Q^xNqdQ4xbj`rnu%iJo1#oQzKkYC_OW>&EesZj~&jA?00y0q<50f-(XI6c!?S0 zaDy4@@Dg)|!+EC0;qj*4;XJd*;e2zc!+GWkhx5%chsT>AIXuDK>hQPBT@Ft%Z4OT} zk2rjmdD7tm^Nho1n^zs4Wq5BvZE~LZ*x~cdA-0o>W2JnQ!=>gphs#XN;fqYJ!{f~a zhpWvDho?limeRZ`<>!cs$D1oc^hSpdi>!2biCN?D9p)*AQzLIVyu|#=;oq8+-hN)F zFNc3%xR%mht- z@_z2{uf2O5zSDc&;oo>~IDD7a+YXR%v&Q?9!}obv4*%9W)8YHQ5{K7%RSvg#D;!?u z-Q@6kZ-c`RdXGE&u=lpZ8@xRZw|ggIeW`Za>#`~kg&w4L9{G9ii!_RnscKBJ3YhRV~ocEr?&wC#_{G9hyPDF6T&GR1DyNaLl zvK@Zi8|m<$y@?KQ^Qs(v!&~C;U%X`wzv*4+@EcyM!+-I9;P9K?YKPzQ?r`|8-me^f zOQNHzZh!Tjcl39>Z4Up{>wToJe~0%ahu`$R=5U7>bGX49LKZjYdVL(8<(=&CY;Tamb3Fd)QDx5dhC4jR<8L69ex8@> z@cG_2htKmSIXu^!>F^w{#Ni7(KE!Jjj!0k8mMwGCb}XC{K>}j>F&dQn1!n zdan0%hx5GC9UkKia5&e?a5&GK=*S(Dn zzh>TX_|GQAPMYK9FXk%_|G^A*_>X3q!+$U{9sZLkcK8`n?eGg`vBNK!D;)lZ_j8AL zdFvehhqvD0UEUuY-tE2Y@O$2Fhj)2jwv+X^`MGzx!>@X0IlR-m#Nkr!R}PnZYaFid ze&_J4$g2*Y zv*u`rx0r7@{InV6@D`Kn@HSK6@ZH`bhj*FP4(~O;aJawsjKgESeGX6clCZC)cF6Mv zI6TA4bU4o&?(kS|yu4O5+Tr)ja)*8l6?WgkV zwLc5q?@`VU;WrUH{;~fP!CvH5;3Ef7W+bvbB*$MDZ$mnN?MckFXCLtAnzJKz`6asf zYftiUo!D1os-6P{ch-~Z#~hKPdd3B-p3{Y2^_(YI^{f@#Sx?GYD)a{PBJ^Kn@w1__ z`0GLH#8$Q(okH1bN57&v$^}w?X zbROIA@z+^Ce%oxLojn+TJ zKdJ|QuHC)`dahaNZy|_%{Ph~;wD-mrj&1mS7A_F^-}P|A+WD}*4q{raeGr%)d7Wc_ zjR|?6`|~~WaDG)IJn3H8C;d4Oc{p$RuJCmBTYu~(56A9R;PKnnO@cf7Eywi#5;^L( zYXqy`J}ms|w_60O-)5T5A3|3@^oB6sJQJ>K@}z>^)elMMu?-)8toQL(M2^<= zH!Kd{#@eoaGS{K>`VSw&$JxtH;NA0zdb3qv!8J6 zdtT(IpS&Sh{p4NYS3lV=Sp6iLK_BSsCzNxN(A8E$EDqbsA7`nXKc4o4zbR=|=kbC& z>&$Vm0Q6j=I-f6Cb-qyeRp(0utIk&o?yNKA+$40>`A&<&I{RZT_4LQwp74W`R&{<< zaA%!4MsES#*ZCE}s`ER-uR4DySam)uv%8%s=Xjy3pPz1V*vH6|1A12<^XCcF-=8OZ z9?lc_TCQ&i?p!X;E6$d@v@VJTYq=H*zn1F?!CJ2G3GQ4MlykGtwOn^w94;4mHh|u> zT>jjKW%1`WUlb3rbDnghCEg7A>E_}H@0Y#_yxJ_0dvJfZm|F<@EKUXH5eL5_;_pNb zwI`(8Z62W?>FAe4PI36s2&&v1mc?={k-18m#bh}-gn3RqXX7&%^waS6pj_ZW!BEN` zrTAaLn>xWu1xifm$ianpl||j)1@nvNRo4zKN9e@CU??A$HE6`3Oa`Ln+2Brz5Scnt z0_Whp1*L-+co{En=36=uBcA_84a95khYuaW7eJ44a5w_+Ay}KR;`PMxlE40l7@v`e zE0xt%^JBgsyr`I0vkok%p{lN8epOkiOM*9FGs#d03?Del8tx98O}E5&=P?rx`yz=u zDT=qx=GGzn4O3?$HD1He!!c@z(;y72HX^W_N_ab{lRUheUKwFI4v#W*eDQ>{30_s1 zTZb?y)NTZ9nU#s4I-~dvgDY#dd=Ul0rO83Qqq2t$%NhoDHMgrk#um=48zHiRM-5~c zDXB>(GT?<{I9_1chzAKnYN2{(WNE&>*l^aUBV2}o zL)muI50wC>OexnQgjdm0!OYYK@3<^Ntip;)yxuVsOA#;4l;{}v4+h3v(MDtKI1pK~ zJ(gEg*L>j!jy**sEJqN=%7073zZ(?u;<~{S73AMi0`JF1%!Ds2A{3KRlOZ%E--{`6 zarh!tsT#bW6z^xTH25c~OWwSV9?TNqnINJH>nj#2BO-qY4KFt>Lin?VW!Xc8cPQU! z4_>@onvqd0P1A!nAiGanSR_~xMH=ycTqIgviiF`WD3XN#^Hp=YIn_{+b(uNYpQ{?I1*#O?AVD{wEv(V?ppDVX0&U=g~?=KtZWw zr)*HmY_(8$=;zw<-}Bs_su}S=Xl-A)BB!0JXLcTS!?Hi$n*SFS4fR;jR=s~CW^Wmy z4lcm3f_NVYu{jfQBUr2v7nLEFw}ja|9sLDLfSD@d&!bNv8667A49xA%Eb^z$oG}}{ zuLK$tDJCZ3&aN-a>xMiFk5Ptfmc~9_#zBy>GKEdMccdhnrLizFhVmU~6X#b|*CMoi6=EjM zgj^PF=EQ=cf|=81PUD&=_M>iG|DIxK=lUr7FVA z&c%I4JxGk2@}fmp<49ymiDKrWfdzrnB%YdIW6T1tHP4rd7yEFGgqi378JP^IrV)EZ zn&u)j8+Vt18*M01aN3vbhjI`B7|bw$+8|&$h>Vh&Mn14T>@jX!(bQ=(XHQp);4E+U z%zUv2@R)+J6DPtT!d5V0+Kic~bvc0dE_w5C?c};q;P6HAO4pg zA35A!RXHQ=j{YKPSWb>hL|ny4kKWYL zFi#R+X5d=QV~ESw#-l|ZLtMTLLTmY4z8JZbHoth`!eW=4@n(fp$WB7GMieV860#G* z;IrUXC!0NX-q_li)iAmml{E~Daa_+FT2hG^z<6b-*cCO(=*?<5q#s*b#O5p){e_ns zHOI~?nislgBTOL){L>~urJpW-V`EJrN%*47l90{pPy(64In~Eb%%5C5FVLOQo1h>A zHq~W}$jBUuAgA*&jYMtR(WVyB^AHq6t6zJq`C*cFCwN0@z@_uiS%^-dsqA!gc0ka0 zWakD14MJ9GU6m$dC_03^${vp5)MmnApk*+T#UvF0R1ph7a~Odv;SVhO{7g8K@Pd+q zsA!fxFH^0K4l^e^2MQ=%YZO&EW+KBi8OMTmon`7^2! zg1E{iQ6FG5PF6T0Q3S!4Dlz;ZW*6r7;Uo;}09Hn&WDR7gtFg(}b{r|NvlhmBnQ$?LBYKdA?#g#P+Fntgdhqj&)v!xY6(maXv%{lzi)Ky-PYoh|^BQ@8YH)q6!3Z0%tq8ymPGX zL*X1$2@#Z~i0l_N!s7HXlLMXsw!@R?#gsJ^Uc_{a0cktF5(E>`?qjI+8Z>$dw+#y* zhz0ivWOg7fVf#M>qV7TucYu7etqVzuOgTv6pEcu9XGR%z$6`@mBJFCZHj<(2C=r(! zk&EGP`S&TWVjNcfhIDX4q_TMT{aqay7$!?S;D=L~_ z)ld@J4b0%~1J%OVgdLyic@5>5Gh-G8YF$=l5%xa9HCBX8y-poYkp|V|ipAEK#1QV( z+hD2AsI%g1wznzb{w?#eR2?0#TgiPDpQs~55n`{EhdjqdMI2?uO~jNCu^qWgLTpEh zm#rN&HyljLg=y4(&fJTNizEaxwA8&nF}Ji4c?)K=7&O=lQW=7E5tk_VbAyNqFIo#ptCB^R?O zK!nkN6-|~bc0Q90waCg<9C^nwBCTUa$Wbz9+pZ`Z3TdyZaX5>%aFneR*=n*!f8oWi`<%6XICW=tTUJNxS z+aR&o$7-EfJYQE8oPZ41UR#5&;?%kVB2gjKC(bcKNvVTu{A~#dHl-UDt{3klp3aC! z_F_-#eSGzLXoMM|zCFVF_6Xm%wc;6sEX=Ha4Q6pTc{_Xfvew)P)Eu2+1j-ezW)xbP z>!h9$f|h#apqLo57^g{UfnzO{(jqfhYe1DSzMNgu@Lm2`s|zp8<1f51hhq?R^xL#T zyrQIu5C5UOaH}EprRXjhNLL1E&|!dJRhGr+FS0{thg)Lc<-Mk|9;S2t zrOL9Z`SlCzn#xY={A;CUHNhqAY;lRR-LOF0-`XpkqY6 z*a;f0^)$caJPj_+lvq_&mT9Che~y3<%zBZx%xbYs9&EdC{-)QuPb3*vT(8wHK&k}` zsw+z|d9YHs{M4(^v{JXabWSogu?y6`B_7^L{d5*C0 zvyo@FOS-f{VQS#(RSgU0m7#&5WuQw4T1Lhwt+El?=D>{!ZFQ|ooWY9@BH+#Bb_bRc zh&G*#E|qp#P+VDFkM-07G+^9&5$OYRT%#ykQeRta>)Cou#t>c8(8%Jcem_aU8AEJf zY+U4S5$j)?DtiXBfs7%#dO_kUW$-Vsn?_GUsZ8k4)Gk3N4LDjg^t5J24O{ zEPgcx?JOe;`!edcux3>qf(0^`wz`4T5u6vEt2I(lbrFZDI`lZc+CyzDcXWI9qMe&! zV?cI%katM~R>liu5F0BoeeDc$nDg5Zht{;64PiXOwwMNa$D*T>fya>%LNa1PEc0Qk zVBiRh#VHdV5_LET_UBdD^aK9T~Hr!t19sbZoPU|wb@5uDrY79-(5XU6MDf^A! z@yptIQpYu3n3?K=8S05(C>RpVnPr%n8iH9Sb@<VyaH z0=AMcJEwGDgFaM*8$0E2ZY%?20)n9^%*=@am}Fvr|DlP2Y!!1B#BmvYIfw92t!irk zjco_jV?kva-w4|LvoN* zBy%R?Uqsssu2QF=A!n8XNxh;`v;Kx*qS7hXP8UNCZB2ou%(80Qz?*%I!7;U$uiTu9k2e%RE_c!vjaILysk@2tDxH65Ii;Y7i~uO5nM8+($=p zc_;%d6aJn#!Va{^3D*N>z-7z=GDieXtV2i!C-;~n4yWpOq1EVKIgF zZCM$C^I}p~!z~FYoDC~xWdyFox0 z5gnx+tFmP9)P;4{(7=N+gXV&8WWQ_-M&J&-w;VH^QnwDp0-f93&Udgmv9PRuK{b=Y zHRLKhnbRxre9lFj4t7QXr{#mSY+C=$#%l=&0xWkI3(%I1_@8yo|7gqjk7n*F_5TemWH&q*p|C~V z!ysj3L1>33^;>_iVmB<^KDt}s^2Y#iNxg)ASGFpra+_mh0S5^zM1yUr5%NSXxODR| z#D;Zh4{SqX{e~>T{TWQM5xEo32MmZ|4-Bw!L0xxZts~B>uE&;%&wLRcy$TzLiU2{rXlm^grCp8%D#*#QJdq z7*b+q&^$}}OBrdK*f|xYxWynPlJm)WJAwqrmnw-Bg!U341R04sdeK*byNIw~1FH`? z$WPp2u?cq9Ha0=FZDW;uhJ}ih7S~>6ifM-v!;8U5nZ5wO-otvLwxR@A>+#@EZCS{yxU*VY>>HP+ z8g1}Cs~8IBZq&pI^mz|hn6AxSc=syoBueP)CGZd4L5j`f-BANo*!a}dD(MNR(uR3> zBs4ZnT4)`3Xd2VcwkWX7L;6K!m9b*{fQ?J$!;RE+o$1?P=uf6^DQg{{Qiz*1W%6{i zA2jxUv!+asVZX4Lv)KMlNTtdxZp8`Bf1nb~TY=a-Y)qG}Sj!6@U%Uw5V0e!Jy z(6z(rTeq+Qzt|ecdmXXT>XL?q@Ln?*Cc}qSWPwB*x`mh zGYeRPA4-S!qT60;aP5f;3DD2}o)m@d_t~Lzl3(WHvNyxIAO0%${_3*u>~Czdm5m*F%+q z2bLC?(Xd`aO^w{CK@V169OEh)KQ@fHrQewbPyC5?<>d`^%uG993`2G7cFkkQAZ9(@ z^fYrh(20Vs2jWkM(@Y$%sKASv zfo=j)c@H_ncVMapZ#f#@r>``=T?9YYM%n}re`1}6P*T3UwLmZjXpcHRzDrX1{^n?m zKc^bZ2T~0d0cjpb;LROMI{`>(V}R5KjIE-m6-cGr4WudFcjyrOSX8#V25K&t5=M`O@zO^fzv`7U*Q*E!m+ z9qmy^`wNh!{m9V{!@C7FkJEuP-yBCf*U>5*t;NxKTqU2S}yxy?QapZIQcr zy}SBrM`JW&mGY9KZFjWfqkTu3)-+LI2w0i=>YcC;go^=UC6 zkfBSaLo*z@(4k8lx(P_N+61JfeA8Y1heJnVSW>>hK$^#yK&s0$M?2rqE(KD%w79F+ zx~o5Pw6%`*J4bug(Y8CO2a znC@sErvPcbgMid(=Q>)E<3j~lK1@|C!r*KXh6;<&HCY7LwFrf@h%+zEE#^?JLve>D zI5gRz=?=|wXqH2aT%nRLaEKaE$KKM@Dr&>5MG^lgI^Llr4y|xwutQk3FQszYfG1se2mv_V{bKzkma;{9v$z3}ZKrSm(mS<{X3 zcsI(cohU`+_?eKiB6H`{dL;|Q7~u5v`CIo?B|b?~mCF`$xzhYpANnjJhxKD0Ka~v` zyl{g%F&1~(r`9{Go$nIjbs=0ocG}DatzuzK5sroP`1}lh7P`dIYUKW?O;(P_K`e~J zxe9R0+nz3zTYZ}2INqT?2TNvblq&@fXai5KsH@NC51qRb<=H$(l;pmos?xF3;`w8# zPMvCUxID{%+xvs62gi71WQ-V|HEj5Z;h8aPZ}ZS^ydo((J3AK38j_ivA@mClpKRZa zxV**~bA&vDV8zZhc`-Zc41-SOmb_zmlOxGPbs~*PqigDJ9mro;^(K-i)mu+4ICJDz)h{R%@_?)c-1`%Yu>6%T%$|HK|6I@=?0 zS<0T=Ba>STchyf%OxcyVekB+aN#9K*u0k%}-kiu-XHv_uolpO}&gl^9buHPOpPPEKiqvm43N&t^LarVVe1+}|-5Ur5p?k-zKVUsJ;9 zWr;#YrL+?Je+V(hBlI&0b^9}j6ACZAJaOgKNH!{e*P=;@ zE9r`f!d;1!l`T(P-q7^v{^)h>8C!Gy82$0amMsmZJ)WP+2$zZconUI6l47d{74{;% za_8KRcOkX)y&cbs`pAs>4?z-uWE7vS*2#=WCZ!K5874|?o5>`T5qI@*=U*#k#n9kd zA45U9`qwJozpe@VYYR#e@~`W~zqW`1U&Ozf!v3|~_pj^4zcf4RU)-&eeBfWoXZ`E? zkbfPYSe{0^iGTIkAnltzvYcMW)YjQj6TN9ME2xuq6sV`g;Ax3I%fRK!EKKeH5>9<# zlhgaGYgdC)ng-WapYw|m^50M3H{h|dLSpExqDxx}<^#BZkk|CB&qB}Cw#n4HUV~H9r8QFV zGFz2mgC3l3PoO^n&q8_8T>I<9WvS5im_1{Uj6_=!sJVgI zv7Vu#TJPnh#43Kb;bU61)*qv4+n#$R`!nr%sIfGUl(t4|@3u+>T^bDfzb1-@q>T1Z ztMR*Tt5U}T_{)kb8M~;jLC9rI)2%A%ULoH0k1#w%5X|WFQ^XcBi#TqHsHV(8O};jlxjD zUE5!R8)a-AmA^gOd=2QZOn7`mhV>_C3e;YzZvyD9_Wz#L++SF6iMc7QXQxo5DLZ>5 z{czNBb|;Ibu7`b)LF>&_yNmRd=w_wzw6Q#B74(kzr37A>D2jw#;5hbQ`E;AaJkGsq++9YJ=1!98p~Ihl1N$!fy>!TQRrIMCKU3g zA=h&n5_06$jjdZSQ(#ZOoyAB0jg#a=?~Z+_LHY)4P4_qjr4aY{3INQ&PR~`PHpsJ6 zIzC1sHVoe%wYR{et6u^gHym+pTF@>V`%st5k}uD>iyMhx!#KlnA$wZ7aX0X^q|RJ2j)s4%-qU=-=0qms;a ze4p|Qojpd-^=J<*J-b>N8;@_r@SL9(UE9zHZMF5q?H%t+@lHV|oZpCpONYKQ98epD zIu`168I4yyo}WfrvX8|8@R<@?5v?2j20Hq=$t)=PJ8G~| zrXNGw(4Ss2lNDQ_{R`%Z(Y0fwi)ln1!iO3z@yDB-d!=(3<~o-qgOt(c`@o3etytbu z*K!=fy`#dvP9In|g!cc4Bc+{|C#Az^=`b3cra6;(bna`>qeNRo)%;ycrQ>KVNJ*?> zXOXx{=MC$;T{&B#SKdY?M8U)=w(&&LI&X{iy08>7eUZbLn(9`Bj$g5evjKl3$faVa zs5a5Cr>RqT1n~P?>C@3eH=mDcbG=l4|pTJOT;hiUM>*yKitrIjkiV+M)7;vL&^RiKaZ1|~QlZJmNRbac*^^YC1 zI(ETJ{Q4|JBYgXuvl0CrlWL6aDNXI1wE}NH85VL)yB((Gu)d75*POl4<h(mtj4X}Tl;&6w-3R@LPqG*6E|?g$=O{$4)oSt{bi!P|AtvePlks6Zhq0S zwe^{Xks0kRuS9>^zG9}?-}LAJUsv{Tt!pVsIyth|Ki6e_%lR)xefr{+l~ix0=t8sX zzhN{9n_6C3G0tnfl5*;=w_MOlx;&;#+J6Hppkpy?yVBP@y8KLr8(Ys#6$nx#cE0TJ3+zV%y z=Ftv0sckzcdL~vnx4QM)+)d2bAOB>(for%aDSI}04PS1Bhi!Re``1<^MV{V^F87HJ zJYv&gdYW7X7u=D2&X0m^l2e{T?oGz z!clB;H<}wn&}o976FgF|MkFWU7NP2wkEaO_pLQ{(L~u;-C4yz9VZJB0ztC?HoFVvr z!NUbVA^1$euL&L_c$eS_f|GhvPwrsic^JVn1T%VQqbU>|7tDJ$#+)a(NN~O2GQkPK z3k2UHxJvLk!F7W9<(KhKLRbCY7R);uh+H68p!q$v{u>pV^5g*bIxN6$pm|tuxtyGgr!*Rk-s8AQu<}$M zMf#0;g6~@_x=QH%hTvSm9|+d6Fv23E?eI8Ru$C)Za9rq< z1YaPyL~ygNw$M+%TgvFSlg0~Iorql@nz@H~D>DBn|wr&5F&A-F*B48b!6R|`H{@YRCP z5xiFLEWvLIo-H^voifiAe1_mTf-e$$p5Pw}o-6oq!2;#WFU#-0!3Zh+BP6~7oNM|? zM3r|fMwcf?-16`wZcdM&$;m-Fnuo(_4iAXHl`VZ>1g5ljP^7QJ10!-n1LtuwID#zY zKm^suV23j!!yL|vXwO9cp^>v3Ju{-#B7ImyORPLPGALa~1LEP4Wk~yxl=1Wkx_CL- z?SKB;hR^p2aKLnek3@4yM|8Z^I6nnA*A&X_@Ie;$0-Z-3Jc<-!NRT6L&WRl1@SKp{ ziX(yD=0xE7mLCz@9WIK*9iA5%=kR%v=?>3wcA(Dl@EIjK|I+Xo)|sN`9de)l0^rr= z7Y6h0{R=I|kY<)xoC4fzF}gxI;^vnYv0T40fe-vro*Ljq@&skM)1ZrygLIuikmpW$ z9)%a;W}}G-2k}#G&KEa-GC@6VF+n}vZE76+MS`gd)F*rwt1i`l*&vY2)EgvG2o9&yM~L|pF${YITfejelr>UWVBw68iZXkUxGlaw9& z*LX39f9Q>N_$DuCUqAMO_I0sW<9L>NLHla*g7($y1?}qwPdY)QiJR|vDYgW0bA!jN z2p)*=<@vK1(r*U+MU*`kWn`cErr=tMWJ>;ae&P6s&=)(Kw1ejBwhfs1e%J$#pBH(U z7mscD++i{6j=0w#*4?dM><~P`54_sk;<1iSvzRu|w3u~thQ)#XZ?zIx#@j>ohfMJE zh$E*{6$0Pt^>g?RFBtEB=?!)CySy_UzT1mCe3z%QZ_2#eo8steJe?hoey=w_L|^Fe zy`ef?;{|Q-UT=}(S>s*o@I79m!@u&H9lqE5HSk2(;WTrb$D4zdz_}GS~}?eeW(+wjl#H`W*NZ^55#k|WztUt54zn?ohi z+^ZI|zW!=)(58~1r5iwWFULxx?X;BENF@4 z9~oKe@KKQs4u2`~l*3<+yyoz6k+&WGa%3m)ZrJTKb6A9TK)-~^S1xSJdO6u**4;NO zW?l1Wmv8;rhJPQ}bJiE}aPX&_2fb}bJPCNUSugGD9E(|BJmTO{MEppouY1so+6!^> zu!rTA9OMt`@e%KMN8ji%Zys^8*$e9KuikVegZ_@EGiCB@_bv$0OB~+rRXF^2uiD{V z-Zc*Y-CODKZtq%$-}i#L*zK)z^nIZ|^Lg)SM}NWF=I~42E{9+A_Bi~K_p!q-dix!I zDb)AA>>X>Zi1F7u-r<+M6CB>>#T@SN_>c$>^3QenHLuv=*S%7QU-RZW{JO_z)S5Og zveew8OM}Fw=_{dKjo)G!D!;>OUIy^PRgv@`1zCBF47nxY_4@-Qj7G zOo#V*Lml4ajc|C6H{IdA-U8qf_~B{hA&uokOUSyIEBz0ea{d~Rs0nd6=2=ySdP4xbxp7jr$RB1hbu?`1nY*Bj+Sz@bWEI!bf;?GZ5cf==wKiy3B8V|=<54_rZOX}`S!IPvfnrLw< z(#)`!bvMUi_CJi0yxL6if^}}Ne-bxSLUrmt(MelP_F_oOgFFx+N8Fqhnww1vjooK? zH#?qbp}E;v-hYMY92XWsST4#!J6sHmJyo$)lf@i=6Bg6wR|)?lvF(p7_Whr>T7%E+ zpr@NXCKrzQ0Pt$_zN|+cvzUI)BMu(_h+`EL^xJ#nx0=ecSAOrPcwcC3@-gzzBaRu~ z0EbTx_2J(L&3OidZ1oNA0>?kVD|a~4t8_TqTjB7T-hB?IdYc?RHsq7Xcz+7fUv&6n z?>&c4@%*tbZqD>{r;2ts!_yrp;xoOdZRMl~{qw+3pM0kGEyt7UUEuK1UX{b2xHV(k z9PeG{=qGtkIeez~w8JNP&p3Rh$NL^U;wH!YtHYx_FJjCysK?VVa`Sfd9^gjQ9orWd zf4SyELw`70@cXic`l`hTnhzWgnLJpZ#HWKl-CSZWIMSGLz^l!7#D8X3O#dmeI2D+Y zsmT-clb3+1N8BuxH6735km{p2N~J&H?1dlXAU`x48{$sw6RpV?#r-&34ED9M#+49vsv!&&#)un z({C{y4&RQ|wom_wYk6^V9UkuW>CGmX8{BSk9sM>l*5TXD1mH!mc_VDddT#{IHJ2Gy z;|jr-i@=)&Um-TXPw;nSt<8(=!l7T=@Nb%xPahzD1pMi+$lVygUIJci&KDne+hY2_ zE{o{{`z#K8z+b7d-sky61TG5sKvBpC=7sv1l2BdGgRkp>{YDe4%Z8e7IC_o=#>6}` z#?i-y_C4ZerlU_Y7dSj4RKI7tb!*%VF)JNUt-0ReI`cD!XPLVlo^9@Tc!*i=@B+6N z5jR!lpN?LMURe*)KXte|sU)?Omg;Bjo21H`SrN zHajx-E(vgX=uvW^rh(y(j_|%{a)H&83mlqtRc9 zK9`7|%PgjzD=ZH5yfmcer6Jue59xMAB;dbX?mOH7Il1N%vDGaWL%bZcTLC`520h(0 zM{1zY;{P^g<8PMLQIT+6#?`L7Ob-bI)&ut`xg=Iy>B_(*Tnx*?MlLuX1MqtVM8hL$>{=st{%K1Pr=13gE$b_Cc_FKL*ypc=ilo1`jzH&mKW) z5I|DmW9c01U_5)q8q%0l2jkfz+Ci7N^%}aK`M)6|FF#{>E1pvw2vSjpjWI3-v1Gyu-x;#=sGWZu(mo^|2qK!1H zp}w*2bP=*aeBnS(O~e50NL0d@)?E-S5Y`Amjh#ZwE3m;AQs`_dfSs>kL65y3((nXc zNGmsM_Z4FKC8E4DIr6r}2l7jA)ekAn2%0@wk#>iD5Sji98ZoS&n7W&-0{eAQpeLh! z@%+VRn5TtoHtdVq%+`=(MtyBz4{Wl$hH}INMxfG$8jWAAzUNonZE7!K`~rhMhuNXJq;r1}>yJhCRryp8Tqk>e8}O zn`1Y>4(E7)b{6tka_duFRuGC|O&)d^Kkox&8p>!1Y@I_dzt{)g@j)Gc^cdk{F{#>h z2{%zCq5l64G!a6bs5DG_8d_UBwsCQMM61jcdlpD4{g@in*lQREZx`ghTT8%K+_3<*g zx3(oTHdcdQyQ+Q$Ge)mvo3SJyg$FekKPz%ynu}~R^3n^t1gcr!1esH0Wrjv5+z|L z;h9*44c-bwR~B9tCstD3P*oomPu_0!K!byz(g9$vB>3;zq-**CQmvmaNpS{VBQ}H`u>ZS2Ug#UkvKN%C z^Vx8Fjfx;jH$MEWVQ;ey-~82Pn!MpuX?t<5r~*IS93oeD11T*DKU~xlCjcpp?`2V1 zouggtX#82R^6@>&iY5VRigHJL0!VXXAxhxmMar*S%T?rnbI z&}MhF7(Zp!s~0+SDUjxI6VPBO?;}9`6?vLzz{?Rd#iKxa^`vB<_H~DHfKv=s3LaV1S^lK+1O!esrp+-l63{nsyD4>he2x^$myq z>QFM?)SxM*0jVx80O3dZDBBYJhF|lz0Z94YkNUKu@l#i&O$SoGA31cJL-zokF7n=Y zwEYgH;5V##bpnt|IoqKkcl8cOyWgP=?&>PY;~Q|&%-@0doANX>7+1e8XpBSO13FD; zKXZt09>5D_;Sn*1u0>rctsV8Is2;VYXb5US(Rt32&jKlJC2XZ=v$It$v{KrSk*}6= z7m!T>6_oZOkka_hU`6f6`Dpc5d_G>%t4VkvjiLun@=@y7e6-r32`HTMz39+_lYLsx z(L_1y<7dU8BgtY9w$gX~hAvu2d#=Vuc!YK;zWIJqrRem2&``d~5zWZH)q(F}SdBh` zJotxW0zQ1}Vy9G@d?#Iy>Rj-|(0VnMl{|#MpbvO10?)RtJQ;i^RKU|n9-IcbUjqu? z_Y_cW1%+=B>XcU&-=z}Bxd%Ladrpw59TdI~C7?VH3g321Qfno zhQHenD5rwLU&sd(z6+nfQCCVhiX<+ezW96bNkG97jvz^^_f)6h=#eOF&pe^Xk@S&X z9%Dz+--06?H4@bU9>xdge1s!LidDU{e3$FQIEe+4!}k{dosh=(l;FLRKIMCzQWX^y z*VUEP)_0b3dnX=VThooQsT*Z$H_DscD1Yxp+1HJ71S>%f>iiX)>8i%<3hKGrVV+;?5P5PnRyl4VX?bU2y@1`8ZuEi$ z)$kq-UmK1#JGOcu;_sFP7Ln=-PG^)YDyyw4!{VxqDH*P()`EHskZ@w}^rx z7hQB=>z3BH5g2T)w?zWOxCn)<&w$FPUoS~i%;;TDBE;aB))!hgBVx}7i1a!P5yI9{ zm;{4i$Q(wg>l%~piLMcL5RYne5Xwm-2ub+0l-7oi5f-p@?%wFyxv49r#t_m*A_dhS zk(i5sffA2)WpwRXBg=DMUi77ehDo~XbzJcfAapOo)go|AN_6c;iG9O&)iL}_k7~8= z_?3%@!-%^Qkr46DB)}8$X7I4HMmK%5zy2r$E^2*2L*aeUx=A&PBDNNiASjiF$!#0S z%wA^s8KMV~dk{JB9>n57&)KuCrgS% zfdt`TRBY09uc!$}IL>??Hh9uz{4l5-QwrX#M#; z7HJwTqC6|6d+U}k$LCvjG3;M-E#k*M^TQAJJ-|Uk<)pJHN$C#=-(HF9w0rx0gqZ5s z2)pzs{XIsu-1x}fdhPfbLZ^iz2940za_Tir;F|ld73aq^OsCf6=?H1KJr$B&p1UN^ zkG9_gshuiIYM|jyd&a@QPaxT6892I@!RqpNNAG&1r5*A2;1kZ&J+;2}9oHrjTlxG`E$w3Z!-SGHVVhTm)jr zE36YH>X!d`Ota~c9lbg(g%h=EMAhRN*$`n{m)*xCNmn5@+M!Qul89xHn!4^Pkm=);10v_3yMk&9HH3Dz81!hI9s@uzmk(YVe@ z))}ZvS)a6(YI~|f!F0!=kajd!Az;NAj|s?6!uDR0Tq0XhTdYq!jysslyNFg?wUqJ_ zjy!xu3&NYN@W0VwzWL9`cxRu(kB0EaA)JHEeE#o-@GBwQ8%^Bj85Y7tA$(N`-x9(P zh4AYkd>khCPG$%fhVXYn_?i&DD})~dUWW4U*b>6WBn5QN>V2LYLiptnJ{pSzKcZDX z!Ow}z(Sq}}NH^ zJVx+t!4m}c##{++Uln|U;2DBBhw>v@jT3yH(9ajFZ#i5fxJ>9P1TPSLo8T(J>jl>d z=9gc_r-iQizaw~%@O&az+5dpKRHH((AUVK?U}fvm*M#sitZ#ifllggt@!!F-j07AR zM+E%e7Od~lY!1K{fJgS5v)8_n1uEe(dxTG?~s&wmr2O^+?p>0&014czf$xHyz z04Gc`Ndkz9AtWad4N1%(prS_tN;;s3I8QVVt#&K61Cvt#TO7L;ah`%h3xa)d0v!3) zyWSe!0QT*^{oVib{GadCLpZ;BYwcaTs&?(#r%vrvYf9IAEagjc@=pd^tJsrTIG-#b{h_o_*a}sz+I@A=Q&yc_K(F4hTk#V z5%;S8yEj@L3yq)86vKBiZFemM{$CPM$WKwD3ohs^>uTi8<>b(j*-yI&aerNJ89o4a z(*Cs?l2@w;_K@);C&p#CH?_jaH|U^^I2NllP^$qh2*j1tI6ZYE6Hb(KO>JPADAL}o=rZTd=7ak`CRg?# z$VC3D(?#otH6;56#} zIGROH65rorS*zr8Jn~Gz`z&$Fxt`!$m&v<;13Yex_$csV#H9>H9=8X}gtu5Jkh6_* zahAiW$SDGET2xt&bBu#_FXLd_+qe>+<|aa2$ueZ)E}(Olk~48H367Z_135K$pYqX+ zze)j2vW>#GLZ1TP&=~kp@M4r&w&fX*+k;>9SoVWV5&De!JcMQNjtu%Tga;3 zNsjQCCY~&s2y;yG*x!~WZ$0wSjK7NoFv&g?J`(yAhkA~K(G$EF^N_B^Et-Jx-ht-8gWHtKSW*6KtBmv6<-Z~6TyEnCmVW~8xlbUU&25wv zP4b^NHRH3&W7!trGH%PKbPB$L+wzIomQOvkY}aST5q^_#gl}iu^Y=}_PZOLX@afmq zLelP=5H<130^T>_ih$djH`eT%Fwey22fW$1Ft<*)(Zp8-{AKV4nh36U9|ZBQu?0Fs z+_&b9VmnYeKmI+u*?r#Ox&-{aO9}WVH!k4s-MIn(gm*FcX}@QnuOd>L5PH9P6vRo{ng$@ZL9_BJOv1XPnQC{DoWQB(C2ogd6dGF<&#^=~Y_d z*YMXX)z3Fh>(>~U?FCNWYOk7WTt>hPTvou1?tJi%*w49cDvx!WQ-m+zu|Ck_-H-Lr zi2IK1J;^hjyxrk+>Sr>akzQQh^dMzu!k>P_&~{1o!z7c>#U`IwCZC0S$;aPs&B)_w zZ(A%&y^{DnNSosBbWMqPOA2_gyMy)W1&_mebth8j6oI}?z`r-w=(|iE`=dKF(A@2k z1OB6_OMfu!-XHmG>`kmU*ZrRA&&hYVR+#(7V{cP}b4rBG_!}mGNw$mJLwLFCxR1U$ zX)*lT!!~?5wenvCns8fIxUm1Q(rni%)6PHP&~@g7Hy)Yu=qavS-^`?~Rd9*>F3MjBUX0o=<-fq=@VKn=Qp&chW4)3<#Jym)>v^_C z7qbk{1$tRm68_{ZJ1OoJHwx>zi}}CIbuINcT-Pf>+6eUFe*3H0Z}0M6iwGlb1N&Oa zZ#Z;eIYsb>zwQCQYp#iJq1WbX-lfa`3X~xiZ=jUvS;Mc8H*nv|vL^ib{h4NPD*is$ zi^k7iG}-u*N%n(Wi@$_E#T}fm0Q+HoWU$yBln~aLgZ)E??K&*MpNT*p?uUaDI!K0? zBJPj`zdWK3`-ev)gzf5K320V0McfeySiQ$x68v(a-)r9Jb7aEAKy$QtGu)90mzem> zfKw7K5BTVWSplac%nkVHgzExMNw@)g2(~>J<(K|aS8``=ue^yT7yHED-X<@dd^F?l z76DAMKYcC%pC}3B$tL~r>)*6I_Y=iE&*PrwaQ(}z$?3yqrc+Pob8=dGPTcc6?s?wh zl(^?PP0I^w%ce%NGYjSA2$>kh<@s}qXPFm+QwjzgV2D&0ihG`mNi#+zlvY*N1UoMc zqm;0xFz^F=DvZWG&-?UoFe|Glk*CJvp6BV^vorf}@KCo5oN#f^^V+!Qc^_BYyT|ad zib3OgOe(ARH!n`nqUz!)@KTIc)K<^vUC>R22=}eYxga{DHyBO&i86-mgzjj>)BDId zC}Fhf5>D&oTg~@zc_Ru&kH=-8C*EAqm$|rPW{07*(SbuoM0%%ohbC`y@3iiHT)zPY zLq?9ET)S#GOe&mQ823Eyo`c;14}4US@srcx@tqU* zJjcE$s~J#P5%)aDo|sf#7cHJz1m_;KBXQ4j^dz%-W=o5TfycXfo5wxRGfv4oB}+Q+ z!N0PK;_|wZxaT?E_om-R^ovMgF>X%FHxT~|Na3WS8hjI!Z!GwREcL6fw7kfF=Yn3c z;-2Sm&-1wFd1+a+yhLCBMz;z%jdJ8IEpg9tx=)OS)70>2?UYLKW`*yM+#$dRZ+YMo zcQ-uGH5qI-c2G;Pyt|WPW;LoB_Ze(na<2o6agXCf`NS;?<^?Al$*iDgvWjbT&9F6s zsuzBQ!Yjxws)^R}&`C!Eh0=ELBD^~#jG}X{Z~m*26_=Eu$%GbPVzfoKnhLXKW{lCVXlW6Td!A1%!k*}b`&->JvU#@9(0VHF zR@Ky$RaW@Ra&UK_M&MObDr+mJM&S-q>@CYo#U+c&YNsI86mc+tWsbizE!$gK3L7lF z)urpp#9`HRmDOdqQ&&_Qu1~(8>M}JQuYr$LRoV1txt}WzzAi_POBV76ZdoYbZgY5F z4;!+(X*stuE6raoyl+}~n(N~9VAZ=P$9Bd&&(RBsd!Dnp1qN(27!4hzFB-aTY3Zo( zx|1qu>L!(yVgV~wT6$Qiy?9RdOr{7b?2O_`#nni~YRQubjTFw!v3a|)TD8BNQ;my}*SQ_CtYs3@8mttpS<3}=rsEwiV; z27jT~^GwT1W#3bddL3?DPaRu?uYUu?6v|H<_dJh#p5syvJB6TQkk&o!d5%j|-19u{ zc`h9tX}j_89=cUgnxUfiDevLMeO2woav^>e442~TOM0e$$CrgAG?_$ihbeJMNY6q? z#miPxwOE*~eV`zv*FnNsnYLF@Bu(3Ladx`4_(AGgoZ7*Pv$OO9hozdh<SoE}( zWIa*bp6Nk};-2Sm&vU8M|4)0K*VIj&T2u{(8+eb?LKk}^v^$rD6(wm1WaG=Lqqw3Z z9Tu{jpEf00?b(j|Pcz`FtY}$U)kGXW^J~hEj*ZiZB@8r;Eo9@k!OAD z7t{ZeQ3SU;Px5~u3)y$RCD*U*J3YFd>2>fm$}gAQz!vp@hec}FujOm@Qgu~Ob!~o< zMI>5Ugj0l-#LFo-0fV|4y|6A?Q|s4Pn+1KV{*^q$JUqzQuMa_~_Ba~59Ua||=n+)^ zU#f{iDr%#X;Z9o#53bU3*sYdTBp+Mj*{|mRGkaAjO3PD=)z_BG`M$y92TU4Joov3s z?pD*i_4#rh-xi*>8WG>wz3%}GgE$?3o$=R(<46w&b#m_pv9CcIlab-7TM*EL0lgVe zyH>t#2fHc2`Aa;L1&j++EptczFq3bOP=mC)CygG=z1Jay#1hK;t{j}l~ zqPdg?G&`VM1NtnW1dO@S{1$>V?Q;Qr6_AXvJpg~|`>7~dah#K55KepgREq0Q%V|%a%I8}Oyt!~h zoxkV((WbJ6t=uQj6$X7ESLk7H5u6b9JYSS3|P<-}fr)jsbd^I6p?CY%+PZXb-PK8DBdQ?Z9qRe_MyR4BPRs z+QtOZT%1hs)`Fc@(z3w`Ny|FUZ8vvR0z9ggiDdpW@_(?rwYMCfgIgsn8ZYGRc28 zJ#weMRsHJLd)1H8{JUuWLs6nubN8FuAD=^!wtvFhp$T*Qx2j*0$kZQTZN^({g|tx( zpTP>OUE_py;@JhewN3Y6XmjIl8wVsd2i-_{0d}15cuCcB?nuh0&1&icB2R-jpOEy}}1Fk0I(gI;3Tmio;& z9x+Kamz(3y^v90ukBBZ3l1=vJK>ZVgIZ*$7f;mwCHo+XIf7@WLZT*^d_20LfcGZyj z?|0R9T7dQY%Ubo9SlyR6SmA`?W9pnB^-jjymT=zDam43b#7_0%Bk>vYc!uHY46iZ# zgJE$Tj$vM=xrW~{oQT62qr$li!xIc&X?U^WCk(%D_#m8jL7s;54No^b&+vnWp9RnI z%Jx^o9TUU&NW<3~e%o*ou4cYh*>PlT=X;aYvqx65#9No;k<>_!#kpc~GFhDJV;sTl z+%@DA7+*rxQN7E^>i+QpSsRcK$o;6_MjlK~#Ff?eD(g%h&G;$gG2{qY{dmqL7cyQ; zj*=V6Q^-rm737s<=@sbYZ|~n2*YbZxM&-oxBU!aCq3;z_bfxHX`P>=<>3x3K@bG`Z zt8A+ud*&=-L7nMg!(hc6UoKo+2qT~i^#9xdgyzV z%|p-F_bR*VK;Z|eSx;U?ZjD}=?^TvfX4tJiNa9~{W*2!odGx{Iu@EPH|G2zm_<%zs zZRi{B?<>i`=VPGp)0P^(ooTysT~=@T32IbQhOZ&MSJ_PRo?c}O5%<^ihT-<;zW;Y# zWyesXUS;`Y^(woPyboGqc)yU>3(C!8^(tFO&Sst~ z&}_wY6J2L|kDbbRCRy9PBC>jwT~1c7vWLifdX;s8xr4tSjsow^t886Yv)*HbN3aw* zl5ZwYAg?16`QH)`Uph%V z436d8M(|?Hp=sk330$qjfzZqzuB@EW@d86gZz{=)*Fc=W%Mi{Tg}`)8TQ?ZGmMXP7@lT!ATD zzA0M)%O<{Pxu}Oywin1}uxuMV_V;s>pCLY*@wa=~K7c+29$*h++4tbZxW6N16CX0+ z_F$RBC(NHBE^5kFY|2*RdAy50$~UcaKt8$dJeKVc@;NMXSC4j7UR>(7Ori<5|Kh;&FXCqU-|e8eoadAzilFwKh|gPD zwu@P|d&!ru%uC7Bc`l2-N&fSuW_#7*Kg#29pS≪S_-@TE~FjH{OIF81JGF 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 literal 0 HcmV?d00001 diff --git a/lib/libz.a b/lib/libz.a new file mode 100755 index 0000000000000000000000000000000000000000..86f2f0513f7ee4ead9a6aafb5414532781630122 GIT binary patch literal 79218 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 literal 0 HcmV?d00001 diff --git a/lib/readme.txt b/lib/readme.txt new file mode 100755 index 000000000..9a7bce67e --- /dev/null +++ b/lib/readme.txt @@ -0,0 +1,2 @@ +These files are precompiled libraries for windows. The corresponding +header files are in the winclude directory. diff --git a/options.lin b/options.lin new file mode 100755 index 000000000..e33a10c45 --- /dev/null +++ b/options.lin @@ -0,0 +1,94 @@ + +[General] +StoreLastProfile=true +StartupDirectory=last +StartupPath= +DateFormat=%y/%m/%d +AdjusterDelay=0 +DualProcSupport=true +MultiUser=true +Language=english +Theme=gray +Version=231 +FirstRun=false + +[External Editor] +EditorKind=1 +GimpDir= +PhotoshopDir= +CustomEditor= + +[File Browser] +BrowseOnlyRaw=false +BrowserShowsDate=true +BrowserShowsExif=true +BrowserShowsHidden=false +ThumbnailSize=240 +MaxPreviewHeight=400 +MaxCacheEntries=20000 +ThumbnailFormat=5 +CacheMemPolicy=0 +ParseExtensions=jpg;tif;tiff;png;crw;cr2;crf;nef;raf;pef;dng;arw;sr2;mrw;raw;orf;kdc;rwz;rw2;mef; +ParseExtensionsEnabled=1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; +ThumbnailArrangement=2 +ThumbnailInterpolation=1 +LiveThumbnails=true +FavoriteDirs= +RenameTemplates= +RenameUseTemplates=false +ThumbnailZoomRatios=0.2;0.3;0.45;0.6;0.8;1; +OverlayedFileNames=true + +[Clipping Indication] +HighlightThreshold=253 +ShadowThreshold=8 +BlinkClipped=false + +[Output] +Format=jpg +JpegQuality=100 +PngCompression=6 +PngBps=8 +TiffBps=8 +SaveProcParams=false +PathTemplate=%p1/converted/%f +PathFolder= +UsePathTemplate=true +LastSaveAsPath= + +[Profiles] +Directory=profiles +RawDefault=default +ImgDefault=neutral +SaveParamsWithFile=false +SaveParamsToCache=true +LoadParamsFromLocation=0 + +[GUI] +FileBrowserHeight=250 +ToolPanelWidth=270 +HistoryPanelWidth=230 +LastPreviewScale=5 +LastCropSize=1 +ShowHistory=true +ShowFilePanelState=2 +ShowInfo=true +ShowClippedHighlights=false +ShowClippedShadows=false +FrameColor=0 +ProcessingQueueEnbled=false +ToolPanelsExpanded=1;1;0;0;0;1;1;0;0;0;0;1;1;0;0;0;0;0; + +[Algorithms] +DemosaicMethod=hphd +ColorCorrection=1 + +[Crop Settings] +Ratio=3:2 +FixRatio=true +DPI=600 + +[Color Management] +ICCDirectory= +MonitorProfile= +Intent=1 diff --git a/options.win b/options.win new file mode 100755 index 000000000..2b0d27458 --- /dev/null +++ b/options.win @@ -0,0 +1,94 @@ + +[General] +StoreLastProfile=true +StartupDirectory=last +StartupPath= +DateFormat=%y/%m/%d +AdjusterDelay=0 +DualProcSupport=true +MultiUser=true +Language=english +Theme=gray +Version=231 +FirstRun=false + +[External Editor] +EditorKind=1 +GimpDir=C:\\Program Files\\GIMP-2.0 +PhotoshopDir=C:\\Program Files\\Adobe\\Adobe Photoshop CS3 +CustomEditor=start + +[File Browser] +BrowseOnlyRaw=false +BrowserShowsDate=true +BrowserShowsExif=true +BrowserShowsHidden=false +ThumbnailSize=240 +MaxPreviewHeight=400 +MaxCacheEntries=20000 +ThumbnailFormat=5 +CacheMemPolicy=0 +ParseExtensions=jpg;tif;tiff;png;crw;cr2;crf;nef;raf;pef;dng;arw;sr2;mrw;raw;orf;kdc;rwz;rw2;mef; +ParseExtensionsEnabled=1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; +ThumbnailArrangement=2 +ThumbnailInterpolation=1 +LiveThumbnails=true +FavoriteDirs= +RenameTemplates= +RenameUseTemplates=false +ThumbnailZoomRatios=0.2;0.3;0.45;0.6;0.8;1; +OverlayedFileNames=true + +[Clipping Indication] +HighlightThreshold=253 +ShadowThreshold=8 +BlinkClipped=false + +[Output] +Format=jpg +JpegQuality=100 +PngCompression=6 +PngBps=8 +TiffBps=8 +SaveProcParams=false +PathTemplate=%p1/converted/%f +PathFolder= +UsePathTemplate=true +LastSaveAsPath= + +[Profiles] +Directory=profiles +RawDefault=default +ImgDefault=neutral +SaveParamsWithFile=false +SaveParamsToCache=true +LoadParamsFromLocation=0 + +[GUI] +FileBrowserHeight=250 +ToolPanelWidth=270 +HistoryPanelWidth=230 +LastPreviewScale=5 +LastCropSize=1 +ShowHistory=true +ShowFilePanelState=2 +ShowInfo=true +ShowClippedHighlights=false +ShowClippedShadows=false +FrameColor=0 +ProcessingQueueEnbled=false +ToolPanelsExpanded=1;1;0;0;0;1;1;0;0;0;0;1;1;0;0;0;0;0; + +[Algorithms] +DemosaicMethod=hphd +ColorCorrection=1 + +[Crop Settings] +Ratio=3:2 +FixRatio=true +DPI=600 + +[Color Management] +ICCDirectory= +MonitorProfile= +Intent=1 diff --git a/rawzor_lin32/librwz_sdk.so b/rawzor_lin32/librwz_sdk.so new file mode 100755 index 0000000000000000000000000000000000000000..c6dd8f6f05e07037e7cb89a4e6e072ff0680f782 GIT binary patch literal 431280 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

    GgMFDVkup*Z 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 means other errors) +*/ +_declspec int __cdecl m_rwz_check(char *rwz_data,int rwz_size, int *raw_size); + + +/* Decompress a rzw file to get the uncompressed raw image file. + Returns 0 on success, a positive error code on error. +*/ +_declspec int __cdecl m_rwz_decompress(char *rwz_data,int rwz_size,char *raw_data,int raw_size); + + +/* Decompress only the raw image's meta data. Recreates the original raw file + except the raw pixel data and the embedded thumbnail. Use this function to + get quick access to raw file's meta information when the application + doesn't needs access to pixel data or thumbnail. + + Returns 0 on success, a positive error code on error. +*/ +_declspec int __cdecl m_rwz_get_meta_only(char *rwz_data,int rwz_size,char *raw_data,int raw_size); + + +/* Decompress only the raw image's meta data and embedded thumbnail (if any). + Recreates the original raw file including the embedded thumbnail but except + the raw pixel data. Use this function to get quick access to raw file's + meta information or thumbnail when the application doesn't needs access to + raw pixel data. + + Returns 0 on success, a positive error code on error. +*/ +_declspec int __cdecl m_rwz_get_meta_and_thumbnail(char *rwz_data,int rwz_size,char *raw_data,int raw_size); + + +/* Returns the version of SDK core. Can be used for diagnostics or to + verify compatibility with SDK when manually parsing .rwz files. + + SDK cannot open .rwz files which need a newer version of SDK, this is + also checked by m_rwz_check above. +*/ +_declspec int __cdecl rwz_sdk_get_max_version(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rawzor_lin64/librwz_sdk.so b/rawzor_lin64/librwz_sdk.so new file mode 100755 index 0000000000000000000000000000000000000000..9f07a845d0fcd3057c01263f0c9a65bab34bf5ca GIT binary patch literal 443296 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%0D5cM#5)fOF33G9(*Wl(m}zYN8({;dZcKO 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 T1(S%KmB+(M{s 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≧}oL3_g0~!{3G&N=XqXlp4B}vh(E|Fgs`doCoKLFzB(E3+VkFXkB&`Ye(1wM z!u{1^aXI`Ni>LwzRwvwF4lvFA?JUlQ_OuL{c*u2hs%@uf#{M}6TAd56W9~1vZNmNi zItNL}^ux6i}4;7C!d$l!tMS6SJ^!r7rqRDlM zJ*?UEyI2JUZF+lAdVSaY)pdzs$T_(XWz+8$r?(g6!#QIJsOwKymIRy@_O@_k=Q?BjMBi5W= z;RG*tGNB3k!y15E0WZL4a@V0H`Lm zx*pHC{t8MmgNMb5a6E9Z+XvjA3J+*+y6hmJKxddREVug#AY(6oiGXVGmk6lO5A?wZ zsuBJYLABCfBBaXwB|_?9lxW|Huq(P$BB>w>^c#i&Dt855Jh{izi55lf?!a6 z9>jZ)0ht!Cm){T&5fpzyZcZ7QT9KO4EQ&&i}i2A4CN}cX0kUUAdfHgK!y}wBPJHn*?|QYtKXhM-3K2 zzxYR7U*dT#GtcVDUL2txgzE{LIG(WhOZe*7ga^&ScUpY$>s*9?7FLmi@L5Fd?E-W$ ze!JSV9Eck07w3RnAVVl^bWO&06Ql?=pDD<0<;5P54({JgkQ)EzfDC#-Is{-hK?)JD z08-3y92r0)B+A22eu@c`If8+fN5UrNBd3HA#*q=460c|9xOWBUg*E5*LbgdEAPNB4 z0AC+V6an)`3AHzTR_GX*DxG9*l`BkdAU_=&`yzDIiO=NBJ^-pbo2kaNboIY+?zY-j zJ|6jVM9Y)Q-PY{K_0$xW#RjB*lR+~&4P+n@@L@w0)IwG4VDbfKVrlgfhokT zR?`jGDGW#q3;tT^Pc-p$H1U4ov$fygA_qePDt^p<&eAQiNx-1)9Bb@K&;Tm*JYrZi zp-&|KdG~9c0x_wEM(Qg_7hr!HfRR)|G}SlI_6Jvb5a5$YJ!;Hl67*| zwl1(C>_hltJD2b1>X`C!HW`h0LO`-gsxkXFh0;7?;f9M}i@d~h}1IfP*n84kV# zVVLT9o@t)do%<8w42H(DrqqIW%B5plSRMXxWE= zwon$Y#miM$$d%d9e2b@o5O#1Z1+(1NXt)=b3UED?VN^_t=SMLP2V)>ZB40%e%|4MW zSC}q04HWdcKO>-)`7?s*8GlAd-H!}uIw%f+*5lSKEe1vfkOZfCBoOvKHg*M_p2)r% zbern=dmJE0IVx9KlLwVDFUy6THh{*HXyW(V`BhYUz zioai27fG;0RRJ8xd1i?uA_Yt%(a1y*6FALGVS@MJ4e!RBE(siU*5G?I03{Qv@vEUl ziuoS3_%gdQa}NWv2NT6L@s{qU#=UCd>A+9~T5moPf*3o(ZT(5~ZYUO|U=wE~k6OXa z+TZ+72Xmxm>1lBM%^v}&;{ZY04W9-cO}IsjzquB5FDsDKT%>YY)Ef2`Y)N|M!-%Ap zHG?J*?nG9oVOzWtTcKKieA)h0$6Sq({2TZ@UUu{z81I)8m?dRBOLrb`W41MAD`7Gu)Kic)bF9& z<7U+m`Yp~X5LB1j%0D0!MEgKT!L8D0X5E3@6><79JzC{b>y0uLJ1Z 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 means other errors) +*/ +_declspec int __cdecl m_rwz_check(char *rwz_data,int rwz_size, int *raw_size); + + +/* Decompress a rzw file to get the uncompressed raw image file. + Returns 0 on success, a positive error code on error. +*/ +_declspec int __cdecl m_rwz_decompress(char *rwz_data,int rwz_size,char *raw_data,int raw_size); + + +/* Decompress only the raw image's meta data. Recreates the original raw file + except the raw pixel data and the embedded thumbnail. Use this function to + get quick access to raw file's meta information when the application + doesn't needs access to pixel data or thumbnail. + + Returns 0 on success, a positive error code on error. +*/ +_declspec int __cdecl m_rwz_get_meta_only(char *rwz_data,int rwz_size,char *raw_data,int raw_size); + + +/* Decompress only the raw image's meta data and embedded thumbnail (if any). + Recreates the original raw file including the embedded thumbnail but except + the raw pixel data. Use this function to get quick access to raw file's + meta information or thumbnail when the application doesn't needs access to + raw pixel data. + + Returns 0 on success, a positive error code on error. +*/ +_declspec int __cdecl m_rwz_get_meta_and_thumbnail(char *rwz_data,int rwz_size,char *raw_data,int raw_size); + + +/* Returns the version of SDK core. Can be used for diagnostics or to + verify compatibility with SDK when manually parsing .rwz files. + + SDK cannot open .rwz files which need a newer version of SDK, this is + also checked by m_rwz_check above. +*/ +_declspec int __cdecl rwz_sdk_get_max_version(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rawzor_win/makeimp.bat b/rawzor_win/makeimp.bat new file mode 100755 index 000000000..b1b8c4e75 --- /dev/null +++ b/rawzor_win/makeimp.bat @@ -0,0 +1,2 @@ +pexports.exe rwz_sdk_s.dll >rwz_sdk_s.def +dlltool -D ./rwz_sdk_s.dll -d rwz_sdk_s.def -l rwz_sdk_s.a \ No newline at end of file diff --git a/rawzor_win/rwz_sdk.h b/rawzor_win/rwz_sdk.h new file mode 100755 index 000000000..ac5dbcf71 --- /dev/null +++ b/rawzor_win/rwz_sdk.h @@ -0,0 +1,81 @@ +//Copyright (c)2008 Sachin Garg. All Rights Reserved. +//http://www.rawzor.com/ sachingarg@rawzor.com + +#ifndef _rawzor_sdk_pub_h +#define _rawzor_sdk_pub_h + +#ifdef _MSC_VER + #ifdef __export + #define _declspec __declspec(dllexport) + #else + #define _declspec + #endif +#else + #ifdef __export + #define _declspec __attribute__ ((visibility("default"),cdecl)) + #else + #define _declspec __attribute__ ((cdecl)) + #endif + #define __cdecl +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Checks if the file loaded in 'data' is a valid rawzor compressed + file that this version of rawzor can decompress. If the file can + be decompressed returns 0, a positive error code on error. + Also gets size of uncompressed raw file. + + NOTE: You don't have to load the entire rwz file in memory just to check + that if its a valid rwz file. This function needs only first 50 bytes, + set rwz_size to size of memory buffer. + + 1 Not a rwz compressed file + 2 A rwz file that needs a newer version of rawzor SDK to decompress + (>2 means other errors) +*/ +_declspec int __cdecl m_rwz_check(char *rwz_data,int rwz_size, int *raw_size); + + +/* Decompress a rzw file to get the uncompressed raw image file. + Returns 0 on success, a positive error code on error. +*/ +_declspec int __cdecl m_rwz_decompress(char *rwz_data,int rwz_size,char *raw_data,int raw_size); + + +/* Decompress only the raw image's meta data. Recreates the original raw file + except the raw pixel data and the embedded thumbnail. Use this function to + get quick access to raw file's meta information when the application + doesn't needs access to pixel data or thumbnail. + + Returns 0 on success, a positive error code on error. +*/ +_declspec int __cdecl m_rwz_get_meta_only(char *rwz_data,int rwz_size,char *raw_data,int raw_size); + + +/* Decompress only the raw image's meta data and embedded thumbnail (if any). + Recreates the original raw file including the embedded thumbnail but except + the raw pixel data. Use this function to get quick access to raw file's + meta information or thumbnail when the application doesn't needs access to + raw pixel data. + + Returns 0 on success, a positive error code on error. +*/ +_declspec int __cdecl m_rwz_get_meta_and_thumbnail(char *rwz_data,int rwz_size,char *raw_data,int raw_size); + + +/* Returns the version of SDK core. Can be used for diagnostics or to + verify compatibility with SDK when manually parsing .rwz files. + + SDK cannot open .rwz files which need a newer version of SDK, this is + also checked by m_rwz_check above. +*/ +_declspec int __cdecl rwz_sdk_get_max_version(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rawzor_win/rwz_sdk_s.a b/rawzor_win/rwz_sdk_s.a new file mode 100755 index 0000000000000000000000000000000000000000..30eb551d8ac88f39626219e07509197bbafd20d0 GIT binary patch literal 5272 zcmdUzOK;Oa5XZ+(`XH)+q6!KE$)Iuqg}j>NP*vpu5<-Fl2S5ndNt`C+RVAT>3ZWi2 zaO{B()Q`mhQD$cSSljEwJ&-CZdA*+fd)GVj^Z0Rp#~RjKyO}3Ou;dHHVx?Ryl*)#Y z<1V>2jA9Wxxa?;DU=2X~1(3c0u>41CSIz)vTbqdO+6w^M)_>Dxn!_*0=BUvzN2X=A z`&Q2e(`?yRL+$|Y;J_Z6J!@hf*~3wL&_`{%cjyli>F)8FY_`XiIp}x4y5}gnLPo3K zFvqRWy;|RDcVkWrX~YN(yFTb04(-t>c$RDz%6iMLcY-2eg2q9!HqH*bki^9zpUaiY z7>4ai)r-YTZ5hJ>a92Zbb8AVk)xqNUkbSd+T~jpd7m9vLyBZwCIdVrQjSibw z`!|q(7ZQD~3(!}tZb#_bMXzBhz>>af`U-p*SZ(mt02oe0DJpUFZHA&Q=>jyFf`BZ4pg2sD%3_y3HuG={rsU4-Eywa#PsCdMZz!zl>8HS$~LV)J{OFva5Y z>$woEIy}ePR4vZ7kL2E;7|U7Q?o08WC%2!Zd8ctZR_i>cQ--13 z`(3T`xHV9hlv_Q_ZSYG5qb!~ci=A-#{f)SiW>uV{>^Q85?H19N88){vI*1lTj(Mn%+NofU# hR_AxmLX%40uvC0fw}gRf9q2XNAvN}gm*RUZ^AAih!H56= literal 0 HcmV?d00001 diff --git a/rawzor_win/rwz_sdk_s.def b/rawzor_win/rwz_sdk_s.def new file mode 100755 index 000000000..f2313db92 --- /dev/null +++ b/rawzor_win/rwz_sdk_s.def @@ -0,0 +1,7 @@ +LIBRARY rwz_sdk_s.dll +EXPORTS +m_rwz_check +m_rwz_decompress +m_rwz_get_meta_and_thumbnail +m_rwz_get_meta_only +rwz_sdk_get_max_version diff --git a/rawzor_win/rwz_sdk_s.dll b/rawzor_win/rwz_sdk_s.dll new file mode 100755 index 0000000000000000000000000000000000000000..13c5d24f9d3830ee02af9fae18fe823f303140bc GIT binary patch literal 435712 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Μ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

    ??7*j^{}i5IW&g`Q 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 literal 0 HcmV?d00001 diff --git a/rawzor_win/rwz_sdk_s.lib b/rawzor_win/rwz_sdk_s.lib new file mode 100755 index 0000000000000000000000000000000000000000..6e5f96961dd527643f51e1d87a058bb82b732173 GIT binary patch literal 2698 zcmcImOHUI~6#k~=(Ke!_vNOhtBxqu=^Z_;+Qv`_(<&jd{UWaz14SkTdD7w%cD|hbM znwYp@MdF5k;KGGJz(2r0z;kBiPUp5|Xo=qBKF+!4p6}fAm^*i$>WxC_S?EzjZL_g> zJQ|-*rRG(B)F$JPWA^HG2*4QNKLmzPfRQsGIBEAInyCkltsV*k+yl$pg~+UKtmpD# z>BZ(^F0+we&xyvn529Jz6-@}Sww29xi{O(ZV@c#+Zmq3|rG@+goheuMgs7Toc8r#& z8ZBMuwW4U1_N&`9yoUz0T4?Yg zfDsH~7^AM0pFDo07%G9XFXg^xx8J;D>OSkl-5sC{-EQes{OShxhV9t3055{_$Xj`& zIa91uD4>^BUotxDR9{x}R5*>* z)o(~uXB-Fc@9#Y4p5r;>RV!1&(5d8^f0oV6Xsp^F5DGn(HF1t=!Kkrd?akQMMlr&d zMU0I_|Ja5M!jQvOFl!=pv9-2_jq+L3>e_@hll02H$8+v^&e%zEJ)wd_~y&RWIAS; zEEfQ1>M9JA)dAq#64z$|Ns_UPh+1CUuvA_4Tsg(PVf@lLATFHw^|I##D<)yXWV)=- zXCO2I==Yr98Ey%08Z=8*=|t*WZP{zv>vc*W#X#aRg1|@VoV7T*zug`h9N8yLJYLEa z@Vv5ljqkR+p=9NS^I3>mra{-S5dBuUdhyD)KisCr!+jWZu0UZric?=g^u}$B43GIl z$e`jnX#)#UYfV#?T2WO(!|qL_dqp^~_jtm!{TgnGh+#5KR;5ou3Tt|GN3EVykcM0K zk4XCC2(uh43@yPo?WdAG=c6&<2Cr~SbV>j&0)aa(b1vO=Z(=Cf4<}^^=GN6ZQ>e`_ z+4Hh0@xrp~=J#86>S_5NqT?4qAmnSyp~v!YaNn``l}PlgaD&C%5}lLf876Dc!t$59 z_Pnk~MK_X&qa?KkC%-!F^j`Xd>bI;3RaP&d+s;q0{V`~ihDB;6&UHonvu!^ogy+B0 z+b)jWf40f;N;k=^PnFMaXxe6~JpMg27Dl163UYK>uALt>Yh&8)h>1TTk%Ua82n(2jlP4_a>JI~>o*Oi9OGIYc z`2#Qjlr*s28QJ;=Z@sr!zhOs^t5sm+j*ZsOzm3~tZinXtTe&4-v!T<%hRH})sr%U% z3aV=BYFS6eccS|gw?#78!7b7HPvDI31fDB}a4jQSlSls==bjU+=az{6TXaTv0&kRL rJnehL zQ(Z_?VHkeD^L;yKbN^db8|fBe?Uc%aOt6cL^hQCCEVCRXk@SDrRaf0~5$Lr+L>FR( zWXscqLMgkEC?i{-?L>bt8m(Ge&b717&hhK2SfN7hxqqIQ_xVATQYZ&ZS?rAn1Vn7% zgZS)*1o&>;WU`T0-WtbHeIGdo0Dyjb5D>8)A?S!r=yz7R%5WCuirr;Cb7-K|Wv~E@ z4n9hylRugfr4;xeZZTTOEwhcaW|GR`#c}On3Ax&2BM%x|0z3A!)|leTJect&P~JE} z8jZ}Oh7cZdZnh5eoNRLtmcWgx6CZPFwLzBjOntB6xY^DP9y!&q1yz29Ofdl-b~h|O zPN=g}(YTV;MM43J+jn`nyfF!dl_e1S4|u~jXU2tNY>sdA?eFY6==h{Z0Z{_gs2Rqt zO@058$lNO|ubh`9T}3;)7{+L2o`){93ySM4xH&&WrxSUfe;e!N&E%W@0bJM*$=3?K zKQfan{qsz7*UV*PejCq6sou9CW0D2MaKHHKLZ*U+5Lu!Sk^o_Z5E4Meg@_7P6crJiNL9pw)e1;Xm069{HJUZAPk55R%$-RIA z6-eL&AQ0xu!e<4=008gy@A0LT~suv4>S3ILP<0Bm`DLLvaF4FK%)Nj?Pt*r}7;7Xa9z9H|HZjR63e zC`Tj$K)V27Re@400>HumpsYY5E(E}?0f1SyGDiY{y#)Yvj#!WnKwtoXnL;eg03bL5 z07D)V%>y7z1E4U{zu>7~aD})?0RX_umCct+(lZpemCzb@^6=o|A>zVpu|i=NDG+7} zl4`aK{0#b-!z=TL9Wt0BGO&T{GJWpjryhdijfaIQ&2!o}p04JRKYg3k&Tf zVxhe-O!X z{f;To;xw^bEES6JSc$k$B2CA6xl)ltA<32E66t?3@gJ7`36pmX0IY^jz)rRYwaaY4 ze(nJRiw;=Qb^t(r^DT@T3y}a2XEZW-_W%Hszxj_qD**t_m!#tW0KDiJT&R>6OvVTR z07RgHDzHHZ48atvzz&?j9lXF70$~P3Knx_nJP<+#`N z#-MZ2bTkiLfR>_b(HgWKJ%F~Nr_oF3b#wrIijHG|(J>BYjM-sajE6;FiC7vY#};Gd zST$CUHDeuEH+B^pz@B062qXfFfD`NpUW5?BY=V%GM_5c)L#QR}BeW8_2v-S%gfYS= zB9o|3v?Y2H`NVi)In3rTB8+ej^> zQ=~r95NVuDChL%G$=>7$vVg20myx%S50Foi`^m%Pw-h?Xh~i8Mq9jtJloCocWk2Nv zrJpiFnV_ms&8eQ$2&#xWpIS+6pmtC%Q-`S&GF4Q#^mhymh7E(qNMa}%YZ-ePrx>>xFPTiH1=E+A$W$=bG8>s^ zm=Bn5Rah$aDtr}@$`X}2l~$F0mFKEdRdZE8)p@E5RI61Ft6o-prbbn>P~)iy)E2AN zsU20jsWz_8Qg>31P|s0cqrPALg8E|(vWA65poU1JRAaZs8I2(p#xiB`SVGovRs-uS zYnV-9TeA7=Om+qP8+I>yOjAR1s%ETak!GFdam@h^# z)@rS0t$wXH+Irf)+G6c;?H29p+V6F6oj{!|o%K3xI`?%6x;DB|x`n#ibhIR?(H}Q3Gzd138Ei2)WAMz7W9Vy`X}HnwgyEn!VS)>mv$8&{hQn>w4zwy3R}t;BYlZQm5)6pty=DfLrs+A-|>>;~;Q z_F?uV_HFjh9n2gO9o9Q^JA86v({H5aB!kjoO6 zc9$1ZZKsN-Zl8L~mE{`ly3)1N^`o1+o7}D0ZPeY&J;i;i`%NyJ8_8Y6J?}yE@b_5a zam?eLr<8@mESk|3$_SkmS{wQ>%qC18))9_|&j{ZT zes8AvOzF(F2#DZEY>2oYX&IRp`F#{ADl)1r>QS^)ba8a|EY_^#S^HO&t^Rgqwv=MZThqqEWH8 zxJo>d=ABlR_Bh=;eM9Tw|Ih34~oTE|= zX_mAr*D$vzw@+p(E0Yc6dFE}(8oqt`+R{gE3x4zjX+Sb3_cYE^= zgB=w+-tUy`ytONMS8KgRef4hA?t0j zufM;t32jm~jUGrkaOInTZ`zyfns>EuS}G30LFK_G-==(f<51|K&cocp&EJ`SxAh3? zNO>#LI=^+SEu(FqJ)ynt=!~PC9bO$rzPJB=?=j6w@a-(u02P7 zaQ)#(uUl{HW%tYNS3ItC^iAtK(eKlL`f9+{bJzISE?u8_z3;~C8@FyI-5j_jy7l;W z_U#vU3hqqYU3!mrul&B+{ptt$59)uk{;_4iZQ%G|z+lhASr6|H35TBkl>gI*;nGLU zN7W-nBaM%pA0HbH8olyl&XeJ%vZoWz%6?Y=dFykl=imL}`%BMQ{Mhgd`HRoLu6e2R za__6DuR6yg#~-}Tc|Gx_{H@O0eebyMy5GmWADJlpK>kqk(fVV@r_fLLKIeS?{4e)} z^ZO;zpECde00d`2O+f$vv5tKEQIh}w03c&XQcVB=dL;k=fP(-4`Tqa_faw4Lbua(` z>RI+y?e7jKeZ#YO-C1tUpBK~#9!j8$2PTU8kT&T^BxNV31b|L#JeaI0yWIYNkNHk*~{>FMtp zjmA#^I{z4ZrAJj&uiZR6{PxJ!t#=kzua2jZNobk|MNt3%wryi-YRVcPAKx=MIXMQP z^`F4&*IxhXTRV0jc6a}1fgkcCm2)1n5VjMVd zVAtT_;3HQAUcceSH=cU`fst_R(7!7hO^#=tqhyt`{~aF9++OnlJS z*LTknVAD*lzyE=Eo;0dAfR=hNpNTNLLZTA~Oxpzy0!S$#r39rEl+wTTWzCv3Z0F9M zUja}7fC0eB$bGwSx%t5r?Rf%bnV<~tG9Cy7_<08n*T=l;!nSQlDWR$=R8<8bOItKF zG^8Frd^k}ml@2n-X!e-EU< zJXO;)=(-L<2&9yVq6myJgkgB?zJ2>%=c`s-bMJN6U9C`BgTfhHPlx9u&^(=h6{y0@ z7?u9qK%}W^3jk@i+sR6$;s_!76-9xr>kvX93_}PZuy*a*Wrks_LWl^8vH;FmplP~w=FFKh<#Kr&rL>Q8{%InS$jr~ryY+hA zjK||3gj~*;5Q3hbo+780$lt9IV+>IgK~Xq5od5tJrCf4$h2{G`JkJFH2yu}$-G=gJ zvw4AY4#O}mlOF)G*&JqOX1L=xMn0dG=ZcEFdhI9AVi|m z2~n>%PVF%UvfC=^hy*E8jE*~{ni1KDggC#95a%Vw27Dv1T? zNjQC|%*CN;7BtO)t_##^=f&JyeTLXx%}qv@UYS?2LSZ+^k8Uch)zvS4b08W zH5p^#k^^xWZ>1AM65MXWt@gvVGKj@>^!8F5KmOwd%d&o90Bl{?@7lC!Q*p7PD5cPK z9jR1`a7EF=DAGA0dM*sr<>27G46XbH&{zQCY3SH#_`Ztq@mD^nR?GVt0GvE|^4Q48 z$V0hYj{e1u!5Bj<7K5&7&JdU*GA<>qw(h*t%4KUq7I+nrDNA@m!z308V07UeX zzaAeO8~d=;T579ON(dpAeB{UDaMU==R*2;@6bT!^HBFor2gI(AU)#CBd-%1-&z`P+(Zyqn zGn}5D-Zwcp8Eo9R@wQwpN2Qc-90#uJA_xM6VTecwfH9bgf<&i-Lr0F=FF(I?+uUsB zv;Q1ThGDE89UXmlbaeE#l`B`qx&rESI&eJ?3ylVTKXJmIn3(wH`=dvn5JEKn*UVeQ zjAWru*iW8_0A~|S^gR{)wg3PC07*qoM6N<$ Ef?1)^$N&HU literal 0 HcmV?d00001 diff --git a/release/images/closedhand22.png b/release/images/closedhand22.png new file mode 100755 index 0000000000000000000000000000000000000000..d4b275d2d9ae721c7960d4e542cc448bfe566eba GIT binary patch literal 3168 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 literal 0 HcmV?d00001 diff --git a/release/images/crop22.png b/release/images/crop22.png new file mode 100755 index 0000000000000000000000000000000000000000..5e6af5f824215c4a5cb5eb77b9d60738c40096e1 GIT binary patch literal 1047 zcmV+y1nB#TP)DP*7-ZbZ>KLZ*U+M0J?qQ#%T5?q9j>cy2=`d5 z#2_Vxi!`-#WNPDMCqg`(%GXp>ROlqYvLynrXjoOOdW`=@X`;2Gg+PeFtVDY%LD5_! z677iu#XSj>XY1-42#!Fgt&qnf)Lh7u5Xw%R5G9yFSz95`L|Jno&qCSsTqZ|w4ni%N zY>wbPh)!#1%Mn~o_liP4pl>{#%7<&BvBr2V(HM(Vu4=m9ik0HhQu4xTM8!0U%SmVy z6H)n(=ezj#tmdOzJe|s~s&`+_!C&|O#~Y=8qpSCdm1~w}PDY1-yQZOSFnsqpYfWMsHDok&hjwkE<;JCdoka8)AR+!`L&)ZX4i;lKY$aX?{y z1r#Y#tXNPt-E`MOPd%-tmtIPg>aCAH)>o#le)`!!NPhziu%V3%w6Q@38*CGs+DzEy zwlKsHTiVLjwlUPUwzIu*<%Ze8jw%edlS(7(Y!|y4DI#K&(RQ=DJ?v>ORjNhBj4{?Y zIiEKl?ktfhLHX=pY9>M4fsK4mHVP4%g@iO`5exXf;`zDUyzKl%usvNy|7! zR)?IarkQSryki~bcqcf~OeZqna_RUOJ7;)Yv1_R zcfR+dpDgpU<$m$2-~4WcmAd?Q`S0?-Zu?&|e*j47nk00d`2O+f$vv7TW} zLH7Uv03c&XQcVB=bk+a>dkg>o@qqvUg+>4XWbXg~_l5ufN#Xzi9#~uBcuN2P0Axu- zK~#9!?3KX^fG`Y0_lp1j%kknsgA|eVAU3y>5w`H?kTfb3qex}J+j#)w)c}_{^CfW` zd>kaZNn-0;9eYKQng7CVS+LU*4^irlo8uMu+4J>wW%}Brzow}j009600{~56Cneft R<_Q1*002ovPDHLkV1jV8@38;? literal 0 HcmV?d00001 diff --git a/release/images/deltagl.png b/release/images/deltagl.png new file mode 100755 index 0000000000000000000000000000000000000000..694043073b0b0543387e94e953420ace868d6922 GIT binary patch literal 1068 zcmV+{1k?M8P)b z)XQ%ZR}{zb@11x&k7VLS-hpiR1B~RcjpKlnc7bRjpg0hJBFWW|3FK}<>(Nt$_h?73agxQ^qdoAyX&bC2$4^*cvMDfvH2X@4jR zarurA555#a|F_SxLd5R~u~HP`@`-R!i0L@|Jg8|O8t~*Kd{&5fA3PjV)r&g(R1{*m zBYaDUsW>cLPbQ7e&Y#!Dy1O&~gwF~QAAm<=nl}FF#h;8uK8 z(>^HV^Tz)AI<>t$Fiij=*G28^#jUMB(~K&jV}jRuNxY-x|wvFV%;S_qF$8%FkOHf!uV z4h`2uNhA=71flD)?>Jn^X7y7oQ9Kcz6(U}Thhv6uu8_?d2aZGJy2N^Wu~I1#wvC!d z5Vg>2Sv9S3=c+BOf$W$%|#$?Hj_i1qd&UH4edTXE$O z?R$@oAEJ@#60U6evXC8?=nz)``e0#L)ABPD6HTmAg`g?a8UbqfuSY&0M&kZ*6UH@6{`>4xfB4 z<^3Zt{C$)ARJH3}7(N|>D_=`l@08QSOE;jZx!=PuYDEE%QXc7>aOpP8e*>}hS$ls4 m+HH7n6E3&UIsRVUp1q`5L zS&*8B<3?jh{12f2-^}{l+@9ff%Vwzr1~46opm25N6h_1VppNMlK~Zqq?cx@|4S<_Y z2T+tTSAn5ulE{4O_eY-zA%9sGT$+ZdwKZH@7B(g)<>sHlnqvV2@wO1MV_6WIhJ3y5 ze80SOL^zDj`8o8732BT#lyPF0rr}$?-a57IgHzi+C^Q<5SY1W8Qh~0jLl8AiG%JW+ zMgjrZD;6=OY4}>Nw@z&PfcHmh= zA3(qXuzS1N6biLUk=S~R#_s!d=i?4vF`g>eOy5!*3 zeyvD-0f1%I9RtvmPNzF!vDov-^Fo45Ci4X7H^y8_+AEbxJ61lQ?~Ety#dy+Qh$roZ zL?Uqm7;`Oq&RJ^N8o zR?^)shb6)3nS9?@ann;_-Bb2;9XLvI^!r#B7w6h27L*$tZVX3B%H^_hLl1z%lCJI^ rHG*pzCG`R?fFHnjV~p;#{h{>_Za>`B$w_gV00000NkvXXu0mjfTLsG1 literal 0 HcmV?d00001 diff --git a/release/images/edited.png b/release/images/edited.png new file mode 100755 index 0000000000000000000000000000000000000000..bbc0dae98b842723756288079b08363d34e59ba1 GIT binary patch literal 790 zcmV+x1L^#UP)O2UblHX2o&5-2L_ZLg z1fmy;sb!+r%+l#LvrW^Dqt4Cc-1O|6(?yd+LSJ}!c`lyk<#``oqIsGFTLehCWyL{N z)W8($vec~-2_x~bzUH7WJajf0E0P0Q(aO7lcx_r-eRai!LV1jonYK^1*<98aZ+`k7 zP=}H0>OjY-q?HB6(ke}&l8MB6NvX*ktBO+_V&qU9DlnUhB)vg*^O(Vy<`j<$ct9{gOxDOT(L6Q>{SMm&nr=%*7An%8Q({cTyz1?1S@D%{=K!M^$CRd-4e#d0W zm9w0KWW^NW<7AI}!@JoIU?&>CdlNM-KT1W9r8WX#dmddfHz)+QmLjJ%_V0w z>%0pJIswbSSZ;cDrb9N)4{n+ME}=vDQj;+|v-Mo%#Y-}UqfV}o zO`=e0G;0^P$DkxB;*UAkhI7t!uUZ#&56=CwDd7apxfWngXtz@70OKacquFw8Qd*u6 z5wIy=qQxB!R6xzyoFCqMgW&;4A?&>qt;`Eg`g|7p0VguQ16-7$fQI;d^x`7mJMdFtb9F}YrZ{wf zD`<%hB+&J_2Yhy7uc4*`DtJd22G_xQ#xw zHgL1gZApG81v0eO0Wgy$R;2SLurGddd`q5^=lM9#^F-rGlJC5!zX^2~nB@IeV>nHr z6>21eEal5aY#I4T#oE_>Uf+MtK-i)l+`3Mv_B1muIVxmzEh*-NqJTjb_uj|rKrGGc zTa;$v=p^5pd|-EbtFrStoQ#+mHVPnA6v@$@?{04q^_Dw=PtSt&G6SJH-RKgnC2%w< zOWm=FJihwf`(-vnp$WbWTJg9!Cu+3ya?UlxyOnSr&ix=0-Z zNBac^)6JNuH!gSNeROs5xY}1RFy;jP4FgYmV+wgzqKA**+dK3VqRKc^Fqe51UcRff xA1?mD>|2Ux60S8G$ zK~#90?Uk_#!Y~kq|B5&%)}im8q7HDeyNRk+KtmUsDON9S`eiP@XO27z2tDK9v%%+ukdgjm8}_004wx zADnYA#z92M%E1^Vt9b6ZmeNNH004h^$>RB}ZQMy-jY?U6fUIt>RT&^$eO=FH`m+6o Yp1$r97W;)XZ2$lO07*qoM6N<$f>5rQxBvhE literal 0 HcmV?d00001 diff --git a/release/images/filter.png b/release/images/filter.png new file mode 100755 index 0000000000000000000000000000000000000000..d21c939a9ee5019b636e4b42d52411063f5f3625 GIT binary patch literal 214 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPHV5AX?b6=YyIcI?>y|Nnsk3@t5{ zyJemL8H^=Ce!&b5&u*lFI7!~_E({&4vK~MVXMsm#F#`j)FbFd;%$g$s6l5>)^mS#w z$|K4vYw}AVEej~*;OXKR!f`!0;Q+&#V+jcd4!l{hL__0I(t!gBN-97G&!plI5f)B{ xRs|*pMMpvA4magQHj}naW2?hAW-#hAFckb_XKa~2e+tkn22WQ%mvv4FO#s9UJ3{~f literal 0 HcmV?d00001 diff --git a/release/images/flame22.png b/release/images/flame22.png new file mode 100755 index 0000000000000000000000000000000000000000..a1029fc866241f184dbd29eecd1feace4cd5e258 GIT binary patch literal 1273 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 literal 0 HcmV?d00001 diff --git a/release/images/folder_open_r.png b/release/images/folder_open_r.png new file mode 100755 index 0000000000000000000000000000000000000000..9e523b696a25f047412b7b36b5623dd661e1d381 GIT binary patch literal 849 zcmV-X1FrmuP)Xv@O$#kmP!XvTks^rVN+>M|y6B>c+b#sR zBBEP`LJ+ZCSQ{&in^esuDIEo``JEP*tX;uI)YZ;m5C?yD(nbt?{>uv!myG=a=ip)4t)6dLqvc z#&hq6iQBCEeJ>=rj*)tp9&qhPO!H>>ICs1D1u8V1aj=_?`F<^ z`OVdHs=Bp7p-@PI?tNYy6d-e8%$8VEq`pdjK4GZ8i$|V%n%+IHzvrCQpRbO6wR3`> z3p5wBRJ5hoku|CW^+kqCK12OIJT~|W#r6_O)F6&RqNquuUSn45`sCg6@4rOfj$NK_Z)Yr|QKF&;*I z8np_u(^u^5^u)$OdG3!aO=f`^;D(4aime5Fpb5;Sn}6@$SXp|Up1_P>JZ~o_F0L;v z+`N^<(T)3}IbaE>0!~%=X>tlaIP<<3V@kkVt!*8bd_Q*u_zXA!90p4Ff!m#)F~*#F b=cN1t2<2$*3#u^000000NkvXXu0mjfP!)(u literal 0 HcmV?d00001 diff --git a/release/images/folder_orange.png b/release/images/folder_orange.png new file mode 100755 index 0000000000000000000000000000000000000000..db12f5cfb27b98666ca8cd0bbdc075382307eaf6 GIT binary patch literal 1060 zcmV+<1l#+GP)z@pKp+j|%K!iXAY({UO#lFHl>h*A4gdi0fdBx7MgRb0 z?EnDxh5!Ib;s5|1SjEu{ZvX%Tnn^@KRCw9|K>)u00hO1T0Q&m-0099300{{Q07phe z00ssI0RH~|0QdO#5DN(jqt({f#@^rGhyDHh000980Nvo@0NLBy0Nm8i00M}K0SWy7 z|DWOS-@jlQXaFxSH}@=I5n(qAbJI#m3GvL|K#R};KmfrF0J-4jj~@&-Zr)<}`t2JC zt8#O5x&Hd~>oo%-!xw8S%T@_ViJ0HN|DYHE5I`s{02%V^*;9rupT96LGcm~mUBmR} z_aBiTKYnrnrT^I3+4YG@NQVCU^B1lMAb^;Voeu;&|Nj1EWnyA76%rEa2b#zS6k`X< z@&EqEAo%;oH(uSZm*+{a{tWs3pBbzVAb?mv#6O^BW=2LSU3HapENpBn!a{-qtgI}G zfB*gihY14{GsDlXUsyixox{TM<~D^BFikJ!JUD!Nb7y433^M~O-Fv`AvdB^bk*g^)jH@6u60A2L|%{7L%>|$T{ zy_N0#^W**}fB<4qSCXHpqA2IU#L2_J&d$N`4QLz4fPaiE3}4>9WcahQg@N!*(ljQd*|_&;4`VCLax;AZ>7@RL{i_p&!?O}h>poBZv= z+h6}6iH!jufSA62{lfX;#WSFn|Nayd5o7rL{uKlJkroEQFV`5Dx%n8lSbsD8<`w_9 z{Iy2c&i%(He0lrgC&*?{ngIcT0Ad#4!&x*zcDkjprk~A0Adyv5@KLxW@dQt^x2~W`}VDT{OZFk zUTqIGMb^h+3_!*69_#k6+jX+(KR200a<<0ssF01N-g&zrPHBfic0x&cXWc=hxpb eP1pz@pKp+j|%K!iXAY({UO#lFHl>h*A4gdi0fdBx7MgRb0 z?EnDxh5!Ib;s5|1SjEu{ZvX%TuSrBfRCwAH!O;zXAPfb-*M`!6!7=d1Fo0`20C9&d zLTO@*cht|0vR9;(QOgF^3^PNlfV+c;up%HL+KzTTW86OH%gp$F0tiB40ssE}WBBvu z55wQTe;NM${mT*?7uVd=)4NGSOWO`;09YJ^0Rjl80et-Y3<`>h3@ogy4E7EVo=HiG z`9N3v3k?g)=iuUIX88Y~0ptpR0KzcfKav4r5)up!4i14@+FAiX@BIAm@xw=R3kw%x zQxgx6w?M802q0!@DQN~SZZ4o{%nWQm|AUz$+jKVgCWz%*e{{ z?eSFxmR)TOyc`S+I~nx%tUvd#^xw~~?*RgcSwdV~L_}0nhMkRFnv08*^C!?nyaK`u z|H0`1=yagXzurD(;Mm{Fz{l{3VcT!LQ%jCM$oTm3@hxUxzykyjGf?5{KmYz;v#_y? z`t$!k@25{6K~W5jk>CGW7=C?v&A@fIjX~(oONL#446ZFW_B{Ljvj^u`n3=)R4G=&q ztZZz+^05J>l3ozWjckkN4gNJrgj2+bMY{Ic>SC~`0`W+@gLV1j{ebm zI`Pn_+_z63>|h0I1|=X+9$^F;01!aTLV|(}%)li1=Jo66hYlWCb>rsEYm#y*Y7)P0 zN+`cs&v5Fm?u)Md-}B!*d9Z<#gB_UZSQ*%Wu4ZFn2YQp80U&^wg@B>W2=NQpN%!vD zxq9sI;nm;&v;F(WAs{mO(2u%D_wTLX0OkosCPuItu00000NkvXXu0mjfZ|e6g literal 0 HcmV?d00001 diff --git a/release/images/folder_r.png b/release/images/folder_r.png new file mode 100755 index 0000000000000000000000000000000000000000..3f7d2a6aa5fc538927f8740584fc525f10cf69c3 GIT binary patch literal 819 zcmV-31I+x1P)DW` zK~#9!jgw1gTy+%2f9IdM_s*S}Wb$fe8cb`8m|79CP_TlOLMiCVl?dXZ3thW+WtXKz zQMxHbx)BOOTPao%U$GTis}y3iYNJ>yiJ4|5ndxM1=048pVn}gf7oOEwobNl2?>ln( zN zI=1IfE6VomiavOKBW0}}R1YM%;(>M)Ph0s(r#Ba#dkH@6BQP_X>)mIQnb(eXQYXX_ z3$5xY^#?&Sll7WRmJ=Qx9mMa3AD+KB`_v21@1MU<&}ue=MtSck6<^HrN!qK71u$J1 zV0wF1c27Nx9~4+`xAM?Xw{Z}v?P77DRfuF90(WM=1frXPBS(eX)4Gm<1Gj=RL& z2ob?l86Fu)`UpJFvjNN24jhr^7Zq?ifO8HJ5D_xXD3wOyEjK_s-@EIF z1-u}SNsOwJrr=!K>ufz$92Ql^ORHN{FmggG42y(?5Cf7lMNN^+fe4rZhMA@Lz*j)- z`#?m@G;IzK53y}z5Z}w=TyJ#ffek~=06JzS|1px&q&`*-sSXNW;3GJ&-hO5VrkE;D zlkW#4>tVdeVO&u=a--MS_s-ok^^F3 zQQIra-(J2rQ5(x=XD@tIyFB~Juk|~N*MRSVdEjp|>ummAqp>RQpE+mp#N&J9ryIX* xQ`LRIqkxIXf|>mcECL%3`fTT%y?Xd%y9fR7UMQQX4{-nh002ovPDHLkV1jEvb`byo literal 0 HcmV?d00001 diff --git a/release/images/gimp.png b/release/images/gimp.png new file mode 100755 index 0000000000000000000000000000000000000000..e57f56fe1eea59bd721887343b2b45e8fc6f8fed GIT binary patch literal 890 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 LNkvXXu0mjfhBZjf literal 0 HcmV?d00001 diff --git a/release/images/gtk-undo-ltr.png b/release/images/gtk-undo-ltr.png new file mode 100755 index 0000000000000000000000000000000000000000..56cc85f52ffe9d5e60f668b556b98f7e87dc7b3a GIT binary patch literal 920 zcmV;J184k+P)Px#24YJ`L;xZHA^;++>lASS000SaNLh0L01ejw01ejxLMWSf00007bV*G`2iOA+ z6$KdKFf@q(00S6FL_t(I%Z=2}Ph3?L!13?B@4cDfSD3alfc%t{R6(N#CS~gjA@K9@<8oELn#JO%P?i2?Z8au2lIw`@7?Rd zX+vo#JtD30GVs)!n6Zwg=Ng6Fa^P1o%PQg>+aV)7mtHBE?S10af%L%B z)?Vo%I@&?V_U63;ghUv}k>+EViE&EXS=JZ7V|c8Ucw2g(Ussuh>6(h7XT{tUE2$xS zBt86stmeN!g%z|0DZwXxz#Jw)Ionq<}+8)rtNUq za~m(_S7&BV42>U8^}cOX3zz6fzlGKsts}H*5cpa4>etvVY|x#qV-SHhNT%%jTx$|y z-&FKT$!urOV1L)}gr!NaIya?+kfAhNto9RwBH1$natBjvqSX-Vi@&J$)M!1~bF%eb z|Jl1c$F@UGDV{Ig%r0%Md|x-nBZLmMj{2gY`b_!OUmMwl8RD@tiMCO;uV3?{P<>Lm zx%6>%VJ5ueI~!}YDCEm~7Q}Was)&hdu{^)Nc*)lq({|Xl9j0K{crCRKiMOeF<>y+jrZ+R}rt*tHHN`^jxfFDs3gYg;pV(fB!*qUX|xE zXvVwxo9?TK)3$?p;9p@oguuI=O9qGofs}lj?CLgi|E$)dpf(K@0QP&>*ga!AY~J0x uqr!6;5z<<2O^z9UdGWJ}Np^+0000$PwB8rHq-?CZUEswf!zWB4nN}zogJOl zK}UN#09boAn;i~^gHlT6P&nc%1{ULq)iuU);M}x;LIqa0Z8qdKm=Hp604v47)ZF|+ zoO6b>k@~9w3y|!X`8fMc2r;RtiZwhW*wA>eqN4n1?EZiogiwdUC z{Q3R6x6w^=ke|dd0C%dZeW#+mT{fT3Tj?lsP?lq2W_IrTwHvo{X(RK&DVH{7jExn> z`3X%`rY)e5P&m?>|L3qQ%W^iG#Emr7k18G4tPmg-|*HK>H0UHY&EeiVmLu O0000beo~aE3kr4b{{_Mel!G2u3 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 literal 0 HcmV?d00001 diff --git a/release/images/head.png b/release/images/head.png new file mode 100755 index 0000000000000000000000000000000000000000..29b5b934ae070b73d9e09980b4dc4f78ac08f8c3 GIT binary patch literal 595 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 literal 0 HcmV?d00001 diff --git a/release/images/info.png b/release/images/info.png new file mode 100755 index 0000000000000000000000000000000000000000..22cd5420a9f8c0d951ea553b3a76b217121bb8b6 GIT binary patch literal 1652 zcmV-)28;QLP)z@;j(q!3lK=n!AY({UO#lFTB>(_`g8%^e{{R4h=>PzA zFaQARU;qF*m;eA5Z<1fdMgRZ>>PbXFRCwBA{Qv(y11$hR05PKQ#N!wkBpiT@KS0dO zz`)38%)rKC#LmlZ&cnkh^Z!5N-_LJfKm7gW*9nHF2QM(Z+k1(D@dpFL-!~Wr0|XEY zD)%1{{byoe;f$3~5zVnP6*IBW5@gVl;bsuzVPydM?#<`F43{2!$vk!4l;O}Jw*&9a zZko#QX5|`mg8>2v)x}~7YFvh43*$r7EW)fs7Cy{{tKKvY$Njp5tR z|6qfF<}kZE&|C(fT?}08j6ktJ3|%viKYX{X(2?QK-TNTp z00M{^5+L#t{GR=LN|TJFC3u+_-hcbc@Cz8szkwn1{r7){UqBb@$Z|2TGBYxK{rQjK z&Z}P#p8(}P0@aFgF)}EsN(r2PDrNoq;r`_e3_pJX1Q6I@CiUF*;21A=RWW9Uk3aq~ z{Ql3#@S6dM|1koik%{5LozDzXf-DTLKK)@>c_&2+h7c%Rm{@>9zyM?cVkRag21cMOL0;}1{)(4{OO40J6sBhX+V{pT+u!_N=j8QR07z@e76_z8oM7&kaF{{iKIW-|Qw z4a7i~1Kq?Rucj#TmR(sFAb?ny*tv!NFtIYc0wyCKE>>XJ0bTo-39OMB=weV%urVRx zm}` z%|`}qeomklfZk_gVPI!x0b9b$#mpee!w4)c5J3TyVi4wLWZ>oms^MS*s$~W1VP;`s z;1lLy`1IuYPlj)I?f?W3Fm~==es=2kMOJ1u1}<(^24-N`vVaWcU}gZ?#UR85^ybgM zh%g3*sW3MK0}lttwLrB%^`Hpl=H+1c`;(F3^`&E%8UDY&1rR{MKm?{nV2HnGH}x?# zmjnhBNFg%=A14zq(F2PQJ_d$2z%+d5;#-Ej*FP~Z@^UgrigN;!A<#llQUoS7c2-6P zE@1g_X5USQFDLri8Gb!I3J^e$2>!BH8H5FaE(gl+urq)S*Hz_a zP*CDwkXPhmkd)+N_yNrB-+%`G1{y8|ECT-h_|0(Y*i(iVyC$vr^I}Ug$V7kuf~KVZ ze;Gbs*!SfVugT*t;)+6oYz*qs>U62kW1oKyUsB zMkX)?{QU)VYc>fEe-DTuds=oKjjG{4xq`e4?UEz^wi2^UF6sK0JN&`|Fb%Km~Wv4TJ%J y0AeJvZUlxjFat7x^8hf~fW-y49>Wa)0t^5Y5gdwst9xz$0000!DryW7y#dCK6CDSzM=k5(S$ksn;4J!4UHx<49?%P6tx+RBP{QcLoy;fKzwj~DzJlN z5bTo}N}?zVLI|Yn(CKuu-ERK{sJ#xd+3fdS->+V|dTr+M;zJEZ@^iNl+QHaqYY zl|I#KwdCu~&G_{F%AMtfId%Bd2*G}Ushc1Mx0p_+wIf^bJnyaV`>|9i6~FsnuKcK4 zQO)5YZrr>@v(*{^xUL&J0st@!V_Qmz8jo|YGGAV*R@7#z#pn0$uJ`#nz|H^wKnSrd zr37GRcD@X#2leM+Z!!Srhdg=uY#Io{bP(~!0i=}YfC*qn2=OsW``_^g&+Vf4t?V|{ P00000NkvXXu0mjf@_+IO literal 0 HcmV?d00001 diff --git a/release/images/list-add.png b/release/images/list-add.png new file mode 100755 index 0000000000000000000000000000000000000000..1aa7f095c6c282262390748ab2e596a3fc15c228 GIT binary patch literal 323 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE7hmi)!cT|6FkAON{jSt(_u!Lq7!B=^4B;IBq%dL`6}O%gpGjO3}J1 z4Y?KfzQ;%l3Rp(0FF*F|EI&io>j^)N99Xu9ZE@HjcqrgTrepSr)S!;v7$d z7#j|r*sm7k|1`qSzwL6X$#3JGkN$s>{Cx9Ec6v|es;&OpMC)hUh7@^ocW)~11Nx1@ M)78&qol`;+0M{XYA^-pY literal 0 HcmV?d00001 diff --git a/release/images/list-add12.png b/release/images/list-add12.png new file mode 100755 index 0000000000000000000000000000000000000000..cdca728930713e7b2db1f97e1611a71b132e5d13 GIT binary patch literal 2979 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 Z+W`CLOgeMHmZSgx002ovPDHLkV1gl9i>d$s literal 0 HcmV?d00001 diff --git a/release/images/list-remove.png b/release/images/list-remove.png new file mode 100755 index 0000000000000000000000000000000000000000..00b654e8ca567c380fa477d4b32f808c3b5500d3 GIT binary patch literal 247 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkEZLFV~EA+w-YyVHU|i_?Pt%tbHGab z1&5^a+FUmdNd@kXwZ%tROFFJ>Q*!zI&R_A==FP^f@-i~)|I20A*?&KNrgrv}l!w`~ zS-W;DV_2Rr!zN$cO_)z&Zy0B$7WFVdQ&MBb@09MjczW@LL literal 0 HcmV?d00001 diff --git a/release/images/list-remove12r.png b/release/images/list-remove12r.png new file mode 100755 index 0000000000000000000000000000000000000000..dc12f415df7d298ae08cc4e08081fd9db70b75e5 GIT binary patch literal 2901 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 literal 0 HcmV?d00001 diff --git a/release/images/logoicon16.png b/release/images/logoicon16.png new file mode 100755 index 0000000000000000000000000000000000000000..91aa647bfa6e90251bd8eca4fd42e23652ab7b69 GIT binary patch literal 804 zcmV+<1Ka$GP)dSL znw5+3TsTkTkt)h{9VcdHaWV!#Ita#vP-7#1r;C;cQ<%q-M1YI}2onVdE7`Yal%UY@ zkWUdQY5|ad2m&sU4k)NbeXyOwUX5MZ34BY~e65s#9%lg-Y!s1~xx&*YXLxb#I`mDr z(Lz2-WC_CT1*?MMP*~PE%1vRyery%TPq}d7!hw!4bDINg?|6F-Nc>sRvckv7-m@Gs zPa~Lswe8+V*t$Mpu3>5gfiv#rE-z#e0LUtyuXqXslb;g zg&C+8ut|Z2mCbVes0F`Gq1*~W6>1>kv8}&bYg$97r3$Bzh?kQPn*qZQQaiS@ zKOSe`cVX$|FtHJh`i2##CWW~)#<>pE%rG(z##yidQwiuFA=S2<6XPGboZEPs_;iG! zo+x>iW!Ous262`CWuI+I1;1NMHpCwmEtA}nmXMd&o*~{=lp)Z=Xt(e7zw@ZK78&zeB{`^ z@%LNki-Mp4A)r1$@alqNYA}#VAkz#N98Mk1XPSjf3SIe{Z5i{*%OfMNnp_SI0Sy7X zN4-N5N7(66=g2}z7BbS1;e19ty~o)bXCfQYG^lf6BP0aSfTD;oNMwl&sDVI05D+k8 z&_wa#)%r#Q+tWj#w+GYK2CBHmDyzT$LA1C)>;UJ8U4zkeV@%xs3Xfyg`rZ6C^DD;H z>vZiLpuPVIe5Jxtqd`(Euzu`KlFkmAE@mZL=5{iBH@oKYS9gt0dl&oOztefsa|Z^(YGT_0QyOGi~5k7T8ef z#x8o^?%l`e=X>!z3FR1CHi3K#p9YfD)3?3I?0kXO zT&C$AssRuHRFzGeE2uumK7i4n5D5!mo+=f64$4yb<}cenHB<&0JwxpPAeyN6$@4X}L{mwaXGkMshYXmoLrB)oXKN z3?c$a>LTgczvXOreqpc}mq=_&G^dJy!$Bb-8$Ur*Xdr?(m#Hy=NCXIL+b`BEi3kQ- zWen4BYs`EP?L%JYyA)LX0hj#~7yR)S4)537F_ij*q9h~!%QpNNKy8#uK)l507*qoM6N<$f~^3gs{jB1 literal 0 HcmV?d00001 diff --git a/release/images/logoicon32.png b/release/images/logoicon32.png new file mode 100755 index 0000000000000000000000000000000000000000..3639139da83870018c9a2346b830e16412f6ab1a GIT binary patch literal 2597 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 literal 0 HcmV?d00001 diff --git a/release/images/notrated.png b/release/images/notrated.png new file mode 100755 index 0000000000000000000000000000000000000000..cd6d36e2849ae21861e48c3ff3076730f3a1d5ad GIT binary patch literal 199 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmPmrwoTMOZi{!??9mtPZ!4!i_^&o60FSp5+6@|G&V4h z0OAfK1A{$j2?-Xb4;=U)7%ONj$Gm3YEJ+Coi5&~s?zx8_X*tdi$W+tBwny!N`is`` lfb?SJ)`RCSrZ_V*Fhnlk;@c>iF&k(;gQu&X%Q~loCIGKGIpF{R literal 0 HcmV?d00001 diff --git a/release/images/openhand.png b/release/images/openhand.png new file mode 100755 index 0000000000000000000000000000000000000000..9fb695def9c1767638bb047e6eaac5f492639cc3 GIT binary patch literal 3345 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 bP2leU-*U3!`KzN>00000NkvXXu0mjfObj^v literal 0 HcmV?d00001 diff --git a/release/images/openhand22.png b/release/images/openhand22.png new file mode 100755 index 0000000000000000000000000000000000000000..e87604e7731052e3ae982c9e8a6dbaa8157025ad GIT binary patch literal 3300 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⁢N02srC2m3_74uo+x^>EeM18W$ZN;vUzh$f5JHf#u`&7iUERwT zNqYR~_=j?9s|$Kr$F-~1J!--N=;08P5t28N!^~!TS z-Q1?y+Pq$`H5ly0^|>3^)Yyp4&71MWlUt==UoUgHTnqrh;o0(1a``*P`2jjHG4X&g zx==9;box4(v(Aa4UPL;RhN?b-P-q4#sT2SpaVLRjBqmxOZI&fj+5-TLO5z^pQj^=` zw#c%Kxw-54_s;XFDFJonSMJ^NyhlLP@qsKnNTZi5tx~}7sk3WON`Nh+xCbw&uTs?qW06>k3 z@z?otQ>9!k2a82Ui>pOf6y-~g$8DpOBDt6}e4W0s|7riX00sdF0LI4mc-16Z3~KyY zEEZesb~|=-b*cZ~MJAK27!~t#%IL9Lqodhub`t@bIcK;X|J~3u4FHf#-V@2iWL34> zC5uHGt_5!_akZ$IMrUWPo-j@GVk(si?Cj~b$09ME5OP}x(Xy7!kEl-Np$7n95`Zn6 r&dH3jI~S&YQ9#J|1bFjd%^Ud#4ct3n5&tpY00000NkvXXu0mjf`dFzl literal 0 HcmV?d00001 diff --git a/release/images/rated.png b/release/images/rated.png new file mode 100755 index 0000000000000000000000000000000000000000..07a8a95f1b1262917ba1b060384ec38448ba4a88 GIT binary patch literal 706 zcmV;z0zLhSP)1xC0@#evaCXXyL!zT2XjCY@RI z;4B`TdpP&pdx@D*>AilWt^(wCo$+o~;!q`lOp0oxG}b@}wC^=0l3Xaq6BU&S=UUp% z%9i-BK}4hf|}=}A|6TO_2|AfhaQWiUUcxd-wt zLnh;WS47R8OAxBLQoBI#9f9{1TdULfkeLYt@h#>1`n-_*ZE-#HpAT@ssUsZ zAY%YDptHZgdARwH_&k5V01j?+4eNW9=qjLhQN#*DU}Hn012y`-n7mTAR5qJpks* z3MfMjRM$3GI*?fTlya6ApA`V0Y5xhkwd1m7hwDvcr~v?z#cWD9aqgkY)<+v6xwV`F z@a;hBYXBgmoB(h!(ik<@v)T3TVL!SMoO_eNw6EKH ojuelJnTvRF58={(Ic(?r1i#V*XGaeiZ~y=R07*qoM6N<$f}<=mE&u=k literal 0 HcmV?d00001 diff --git a/release/images/red.png b/release/images/red.png new file mode 100755 index 0000000000000000000000000000000000000000..a95830d23feff594419729f269ac619385cfa8a7 GIT binary patch literal 925 zcmV;O17iG%P)tfx-KLBKaLBNS@KF|T0K=(o5Iba%i8TbUK0zstJ z$oBmGW-tys1iYWLt+Ovac9gkPoFi6%1ivfB*YzGNm0d>0CO)rJDyRMlAO{=^3#e0q-5lBu>6P zk!JR#H^@CPhm%NP`963)vA9EOe2VPEBaHuanQtrA^ivCquWfB@eXt*3?>lFJV@Zp} z*GE%Ko;XQrB!`-H)Tp6G4b!NhW*wR}(nlX=^28}#85!i#>dJVjR9f8+i0?ZO0xz7+ zA0{c0&gBVrZ(su^s;2-6LP2Omb~H~S6wi$vVQp<~QBu*etgr3_aDd~pgK=VE0NpM@ z@8+%G{pcVG0iJ{m#6t0S(&pm&I>0h;M*u)B?Ri)hbbk364GdtTzDIwl0YU@qP6t9m zveoA5ZXIC$pc452L0||hsBK>%9L^E5!1^1*7-0}bP`kF%zpq;la_S&J2iV!Qo%|uM zM`PzYrr9Q$On`)?e*J|A1>K&vuw6WbpieZV=KkqAmEr3z$DM4{-G$Ko|J1d}Hs-Y&roz2pqCP9Q-H)5dxlpu0+c~ z$A-^-tMldZGQj#la{#b1JevQa)bZK#4fRMHo}uN3w0uLuH`M)*hHuyl3?KJGUUglH z#Uj8*_q0uCW@f74){mnLahrq@j)W7s@P)>LGVP0XzY3zCNlt zQ>*&fY&Of{zra244t$m!9BNNhRcEuAhOt~OOMk9@@@KC#5dk2}GK!+WTFZPs2grcV z$!2>`SS%Lgd5&`q5kW*438mVD$U_2%ynuP_Ngq*8U2_7h{Rz80Q?dTJ2XL4fgD4`~-5qbvfb# cH6OtCKYIPATp%fVEC2ui07*qoM6N<$g6XEr`~Uy| literal 0 HcmV?d00001 diff --git a/release/images/saved.png b/release/images/saved.png new file mode 100755 index 0000000000000000000000000000000000000000..556a93fb5c968f4f85dbf041448b82db51b36053 GIT binary patch literal 587 zcmV-R0<`^!P)$r4k8~~{e#(+{O z(PFeEVAsywQTbpn*)#k(IIAE~gnvL67kiP!*I8>ZgRBb9CgQmJ|R`a2U(p5rfl zK&OpOZ+E-`ao0iI@*pFFeI0;Qp|rwZ{>ZtrXQ)*6VT{4^Jc1zjH)dvMxOuxu)EFR< zvJFV2LMe?&*68ma;Qqr0{0e_kES4C*QzZxj(ln*qQ${vx*p@|-X5F%~Cn%K6Hf-Bw zWqAerzmm@o`C00huV)69WU^?S3^U&e-phkSs1KF{6i zIE_Y~dc95*E#kT^y}iB2^}=-rUDRsL47TUUWq`-R_AeePeFn983;%`|9-mf*vpiY7 Z^#}Fz@0W@8dK~}&002ovPDHLkV1h@q2>}2A literal 0 HcmV?d00001 diff --git a/release/images/splash.png b/release/images/splash.png new file mode 100755 index 0000000000000000000000000000000000000000..3eeae46c8b25d8c6bc53d022037efba1090a473e GIT binary patch literal 91814 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 z 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 z%0A2IKmYkXC+^v{u&r7D!YODiY2}SEJn*=6zrvnnlA#>9j3yw1AP1XQuWCyf)NOHs zb62H}E5clyQS9Q8Gh%JL!sE{LlCjvCAweddgp~l~QD#=sd%79CgVg?YfIg-`XEf7f z0vaQUu~J~#R+}nXgnh*DzOS|(VDT?OBt@LAx5H;AH)(*JSeqjiX<^Jpl2QWLI!hAUEYWB*s#nL==EJt_+jdr3pvNCynL<}z(!^gETyQ~U zi?O=0TIMp1aJM9yqi_PLHbkn-o4~{ZwQFK+eawN1*6NmOR>LO0R3w}iHDnbI^mpD< zalOF_gH6Bat&oq69uB6}GyRiI)k;tfoD}Z>j{~*Mk4qhr>YIsFOTNuD;^J!JTIS)Z z(l&;JRW^0h_HQHDj_OxcmipKfq*X4&7*GSChcc3=LzH&R(*)(gI$X@lijHEuF4b8> zN6rj2ir8v6I@i`84dftdC27OjoLz~26k&x8$&~c2;S!)yTZe-dvSHJ$iI#A`B2-)3 z!po!_Y@xKMJ6Mx(-p16b;b#W#y2fWo3DW2SwN1BdI6WH2Q(AOa;qH|VIibCygnJz= z(CTE(O4`q2aE0r=i{lEpjLqQJTyIM{-B4VT)Ugv(PBji&V&xq+W>lLfe0}J99Qw(Ig4SFN3_C3$7&6DjT=xdrlWG1lGfaA(O0V z#hsVS_K6w_hwjoZT8+WW`dn#fh}FU$eJM%DS4~0OUE$8IWnoDI3@7Co9gZzwTU5|; z3T8*?a(0gT65gw5mc15W35GPDFdPsVq)Er>6xMML`pBTJCU2A0#72N}gw?U3P*UE| zVW%&Z0xdRap5dhIjssE~Ey3v4sW@xX1}Q_Qj!od(dOkL47=k3qZ8HWCn%kr~K#e-c zNHx;B;`Pq(Bc%q8fg6+lfX$?Esi_3 znrz}Q22Xn1%)@E25qm2=(64{}YcZ2*`(kx%t#NEt^Rd>@n$gZv$Ujy!tyL1kR3^re zBCpM&Dqhh-Nh%hMw5Ca?KPPmwbkb9-M~L2a5gc+qs$bgZP$HOQ4TbO^Z53&%07AEK z6mq3*LTyE2leAWdrHEcF_iD1Hjl;^do}CM3HYJ$xVOMoy=Qd(ODoYKo>F7z`?- z8;B}RM#lWTzWQ4acv^~$T#cyBw!B;1P4FJlF^tSikVeJ?jBjmrgU33nC+$;7Fo-s@ zp@B6>D+qQuN75{sAX(BLs39`pj9M`eJhSvIFDdp@4eKhV>q<*(~g4a)ui#N`{&*&mb9QmI=)5+=EP`HX_Y6V%L73)UhF!Wk6XbVxJ^E_|MK8$Y!c zgr6j;z}#eAuCM3XXKnpUcR7>pgj%uwAn`(~*kw~lRhICHe*`hu$cOM+v0VRaD!^sU zvyqW8e#M(tJS_lcD9#TcAGwI-d{+CCuWy^FQ=ItSaT9yQ2@m%^IHO`kS>>$I1R%<(G~-BJC;bxWN^(*yn@pD(1!Ut8kN~j|KnQ#JOCe0@&UIn~|wUOZ4^-`lsl{<`YasZ;0IIJ*eR?ZB7yw z=H3v}+i{TUaZ71=gqE^K0pzxNK z)sfe-N~M9fXrVP%=9zD`K<;PqA^^-tOp1AB7TO9PE&fm%pI=bVq$%djCFvv%g)|r> zKRqm(n%HwuTWPft@F=K90Ay6a%h*F1#M#e^Q%nEFCBc~o54N?a#Ua3&GmZp=DG^r~=TZY;2P*H2I zw}E-qwR4$S)AY9e?QbmJ$F|tfZc5kHF>h0Y$+aiz8C}_`S!{`xomnkZ*%>cpPj1o& zR55#i8J7OdEc^HGU$<^uLCT9>Q)2dSSZd*U7L5p8&{8d+h_wYaZ)gzXQj$8%Z=GRk zpm2J6>iF>!KqNOYsKW~n7ujeAtR!2DLoh1}9azkrX@y3~hVKYU(UxoymOXIr$-~l7 zC1nZ%uhy|VdUv;pj`j{&W1y=3xf)wyeU z<3g#;K7NuJ#$IK0nsj#9LZ_yt$%Czj+2HlZxlD(SE$!s_cpht`6)Iu;`2=gU=IMT! z^j&nHP!tAs7>h}F0v?6aeBVTebxY>GfI|a9U~i&?!VVSc+x51RQoZaF=Te;B@=1k; z<2sUThfs7z{n}f4&P{8=X39oefmTOS+v){0R05tv^^-|q`6!gKQ$cU&5~FWgj}@(( zmw7#-%*f>Aq}C&1iICm;nbpk7`q+Q>$5dGYr(UFgszd&u{dTRtnksn1+NVzVdU6f+ ziW+~_+EL7)Y9r~5*WA@Fw)=$~x6WIJw0H^@kRVLw1s7aUEB^7vA2VkF7aOm!1-x5{ znk-2Hi>ZC#g%{FFaPPoL{jDB6mP_^XAQW-+i~ymq`06ti~iTGXrUJ_d)30dM8ht#!mI zWsmGy_O?(q%R-)+SN{Fnk9eW1LomXILBn)474%3FK) z?%%iX(@#HLAqkX$Z61VgqN3bHF>Zkkuu%%|s2R#D5Yiu%@T82}rln9VVA-L!;Lt0t zyprCoS+mA^TeAXXfxQ3z`&`gB#gF2{WQ1X~0|xM?6bZgio_p@OrHWN4x$& zcl1uxL48I4pYPP!aN<~#AEp}7iKpPawnEh~%L!~70axLc&DNBv+scIQFC(uSQ@g@5 zUur2ldwLe2y!z^^Yelzj-_B0X;RIk+F+uc?sH{fkW`ejm*qu0e;>H_qtW|RP<(Fe~ zp$^nxB1k8+vPE72QhV>-y(!woQ~T#fj{?5z_R4eYL?#_n155YR%nbS!hI2_*TyX`< z^{i#f#uvxKM0vD;47gXHHIVIA+T3)b#xG z&x7cX9{v2g-(9t0Vg+4A&00}ad7zYC2e=(rdV(Rtzm6K^$oU3(`J2oLD^2($Ca&Yd zLDdl{PYoTVz8o^UX$#EdI+C+$iJeQOJc0(jh0o-UJmoar^|H9BP$7;G8^h60l>h7DVOx z3`#&AK71Ie!SX|1;Y7IADwTzE$w5vXZzX52;9z~$eD^>=K{zjz(abv4xYr%{$0e{% zpGx`LGo%fUz9L>c|=ABD^-m#GZrb!YHpOB6A@Y`ujN^KDoBDO`P6s> zE%^SYmrxZ*ZR^&px7>2e7hinAmI-SVq~WFw9`@Pwg*XYFo|_f4dsD5pEnBvnJUKNx zH;Xc4v~x&QX$`T2ZGMs7f_cxpw|Cxo=eBLzHf-2f_I7#-=w(w>h$-=k@MPz{(FPV3 zBy-_@0RP`~Mig=AhpIvFqZzc`2gZ4rZk*t_D>tyM#yHmkZp)>Os9LjIS46C;@F>gA z^?U|Rl{Vq9o z3n)UIciwsCRTAeCg>Yh&vC9Vo#oZBWxiS^B1=2UuIM6*}7dn{@hfWt6 z*|YZCBJ>yQVdKV)wcf7(!TSCGwIB44cz!S|bm%C&AmQXd`dHtlhs4)jdu{!?bsV_h zpCs$9A;7ZOpF!IsPhvLHfStUeZ6+z423+@|oMtV-|NhL;)Lnu75*jBtFS$WZV{ZBmcgvn~s`*u^Av*14DqReiVYdy5J zz?{~qV!Kr@cl3wz&BYgAeA{ierH)DOzyE$R;OK&A);MlCD>t)Y#w`6N?33| zU$F5#az#*5k$VA1{n=P7V~YWoX9E4I=q@dWhC>6+-^jyA^*EliM5cSXC14%nq6u-z z;jz_%06cc=E5fNg@bjNvbImn1m%DKE@XkVfwczPIBe_RLIu3NIEnjP~LrbS-PW|Mj zpI8k9svr)6USEIx^>{mDmtNM!Z;a{0Aw9=N8JHM*@4ffZlctK!Rcj}{bie`&!VutB* z3gj3%d-TyqZ@>L^kT2Pg>B}ljV`2mr5hv)m*4)hO%*{97+!Y9~yY4#NA_J(v|6n$# z^+ZRkaiq;zf-aS`w_AS+y92=#?uw}4v(Jv;H;#}lcinXtO{A>YpZ)C5k;ILTjgNGO z1`5XC>FG2*{q)n5W%>@dwHt9-42=xY7E(3-;7OY*adSq9tvC4{smDEAWM0qkFpm&B zGbuyEgV7*9IFC&-JH(l}z4@vkzY`@&f>w16+;K(-)Kf%GTyD%>VVb$~I778rtdNI_ zcAaqc19AvUo~pOGVvhi}p?He9*L-P;$FZ77^BU*SJseuqzCb)0vAXbaa<<1}o+`!t z$JpOa&z?55Hi2)jZVSQGi4(_HpL6!MXP&V$yCnk2v8k?DIf;xG#x6}*JQf+A_r&9n%)wghT%$6GnT0id$jP6`|6y?ic(9c!b7l&gw>1RjXDr7t9)`5@>{zQztoyAX|I+<(JbV{6BBowsO8T9;6B$QcON_N<-#D%tA>( zFB=eYY%(AOIA4DG74ncX8xG^+DpWD)&@}fYaMn3zpTj<(FAk)Uz?#4QmtRApn2ZZT zd&`#1ufP8KisciFqhn~S2giX8yh}ab``)={uU^GP%?YNqUJ}-#83LKlK-OaFcs zx#u#H>~sRZCY*A+Zs;4Shl++WQk9YwOlWhMA~r1_VJ=VN5<9AL$jpK#SKs$N{<7C= zwFC(j1MaHe#$>QCoOv1-&Ruk;4O?N?y;c#N-Oz>|USkD`TRQ#%!&G0?RFJIOzViC2 z?E)Ex4jb7IO8EuC{dr z0#&q2StwUna%3_gi7HFL7K8{&3FLkI_7U@3FvDOPO~xFUT1w-`a_!&oLrFr~(W80d zwoyRa3M38+x=vQ)mD@-sTKP$D>@nbxQ>3x!x^f=4CnlCdh$%q;=A~LD1vLhQRA5`reu?D!38!)yk9*h->iH?eYZk_!3R4=AD}rh7eTPp(+O20(>= z0&pjiamFitQVbXI9RakaBO6_+c~-YciA{LiZ>>rx+NvQ{kj3Xl`gR48{nf9!_H@&xO(4Nu;d~x@?6HFf z4?@w%=}&}dy+a`hG_*Om!Ma6iVfU$lN5DN0Z$~^ZDFlL?GzU%Z4X8y^0+>!SBOg-( z3NqWPiIQ(AeBZEPLlBF-^G+&@yX>;dKKke*)#}&%SV?=TT6_Lldu58S8qsP1 z%dBUl!pttak42;$qeUIbsngJT$B%u*YG3qAwz0ETi!!-U!u^wwS5y^sWVnSUKw6RM1*N?kj4>@c(oerKB(i=mDl zV$5u>87^cwG^y?6Sr5aDJnA;A`aSHD2mD(mowZ#cNQY#$m9kkOKhsb_b3ddd(B+p3k#->eW^EdFI2_jNKx{mVEak zib)9*8L$~0E)5WV_q&RRkP9!okeGGWM{8HzIP2zmhCp~a1;S=H`Ivg3uILw03Q!54 z3%LrPmpiEvWUGW;N8$ZX2Cjz~{+1RdF3!1@PeIo&BS#@cHBF3Cjow`K15Alpq#zUW z+bZcTH1M~o_Rw?N^E~7+A7vFUY37;D?6K`e#W`*hnq&5`S$iRKz-zgZ`Ws1dYld%^ zIMCg2!wvV{cOQ6dwMse0$3;V11jo8p%Y`Mb#nrcR7-mxOF^oC7M687W_;(NNsC)+K zf|j_EG?zlO0NO=#aNxk(WJ{?VC>T(!IaE=W^dDYwNkYz${wGD&U|6Mzw6Cm4J$t6A zW9YZTVNmI?TB-9<_hD%OWH;z-Wun8xnit&!5v6Ww?92V#^jl6g>E_hOU0!)T;X!vX zU2?zTJI6oM9yYt7MM5&9&}g7A)wqOl?e0Vij+$RCgPlC}GUPu0Y7UC3*h+J`{%qYnn@qhv@~T{)wu#03%H7Y_ zz{JpQ;stELaIG&1QgBb`%_N@H^kH74?U{o-d$)xBVydGeV39}Gk67AY(C>VU1dRZn zS0SK;BGs!33aBS9||VrNcqd`ksZD^^loxA$5tEouC?V9K) zi<=ldrlgq<95{dhU0``tD4mSVYI$4%!aaKe5Ec%E%IpGMk+H&pk`4zg>u_B-54!7q z#&h4aoI3AjQ?|ncr0;nOmu%LS`hmij3|B)cj&vhKLWUJ{eSw@4@r5(L$nY1pB2d zdFPn96R>EfI!MmoHPx~hb&dOpK}arI7E!us;&dx$SYhDXBuIbSOvS3Bpo@vEkZ7z*4T@ z_t%#xv1wnrBR~L>2tW`4Baf@JI`?c&kaDHdACxpGk)9A^pBPM(I~b*!2577> zC$(ubH%AtmY?+`XpjH;gpR4Bi5d=tl>|(}ztrFz zJ_R}b5$`Z_C7TQGlLO)I-4Zjq1j2XUeHS1!KEw9y{|eBe7mi+~VFq8=jCI%KivIl2 z7jKgQCscGeBUUzvw-5aA2R~FbW43?u_FEgtd7Om+qN2_$wMMnDKa99a<|~BlQcrgJt@V0XOOJydbPk;7 z5LyU&NZuvYs?_W>YJ_}Lm(a#G@S@rns_4*RNj>K%kfY(>s6K6t$r@hQiITu=Hc1R(%FE z40TDfi>vmouy+ro=fRg=dI=mtpF8095>vF`W*CMANAqeBZz+2hw-UQ|zp+@RHa}5o zU=61PGKA0aWhG-5%85l0)~|^vMe3kvPWLo(2oY^#B9JMu7a__d5r(Z5fm#5$%&FwO z7l*;(5hfqKb{p*JYAKFYp9IiX`1`Hc=-?3X299LEXgX?xwi8Re%t&!h$bU zqeiu-N>Qt02b4rG!&T5R61?7+c$O&ti&`%`#`MfIHk0_=z=we40utb#;){#-qLQEx zEh8d^TZ^Yrr1`xv8JfoQ5tu|JoD48tF}pAzpO`51833n|_UO={B7tg9jBdstMgz-R zC{bQ+att{3Z)%)rO8_fmxL5#Kn7c6Zjgg$19vwLjWuUDF^i>KV&BNJ{D1I@l%$j5G zG~uxaqkKS`(Mvof1(Cf5JyqEq7YWxWd^<7TNdPZGdS*MT%lVb0RCRKl47rkiTM%P2 zqX?MQBO*pyz^o>U^%om7ce@UMO2j(JDZ2KyLOM}--YSt5Y}LkvnJWA`!VPbyB|H#W zP!n#(rPC_=2x`v%{qt9eV&H%}!v(VE=1@w1bI+UGp4mpsU?Uz4C?9(0p~wF2F_2(6 zRpo?-VRs*l3_v@$)}5P&!!QGtk>WM9f>3IKJ4}ZE`{I8gc){{^#M{05O-}uENkz%( zp&Z|K+VTmH zO9G_pL#LlQX&$}O2?o{k7pSTSfKA80+rd4HEXu!)9>w=uxnk%^JH1K0Pp1z{skEnM{E&K;@!P?(F4%vUzi5 za|H;;$0-8vAd5Tr&N~-x+7y{xe*_Tn3W^G}UuLw#b=Uo@ElH^S1v(6k2@`B;`sA0A z?zrO)%lYbWUzJS)nQck$b{4ujpJNKJRN`F1TC>%x2U~Mi`TwMyTd*e8RmacQea_5* zxpU@10ttykMFqhbizIldvQQI^FQh=80tE$xhgepr_~46{#hal73aVnbBs{4p3wYBR zMl%?1%rKNr)Wo0`Bx)EmB!Gm;IP`kQHvg70q2@{=gw3$MX8OZ$*9r6m2@ zJ1-+i3Pcd_4!U!USEo$6E5qAwWR_?LmMFQT%?16q1$C6*T1+hhN{PNimU_r=( zqyu1j(uswoWg~C$t1o|byMXg9ic7rbo_oG)JD>T?XI_5!WxB0n>x4ag#!0ur#otpZ z9{Ih+modzKs;A2;UZK?Oc4HXp1xfn-*Q}QZ6HuoSDAVSqpN4!ku|MMTJm_ORmq4j) zh+lJYM~BJ-mloA0G4GE(_E>o#6nyZ|p?~|@*DwUjqTLSQUpvoDK%T4NG|?5^O^ zN`#8M&WOMA$}38Q0dJ;6$d<0H`=-*sn7iF|*In3Sb=waA!bzOgoa)lG<_|yjIke0> zqystuOP7I7yhdFHGMCw=+F=M{MABGQ5*VKsP-ZekC?x|C!N@)m4C&haO^8vZFRM8TFu56b{ zRjPN1VM7(jRrHb`e&B-{C~@kGU)+w2zqNNB3jhudIrwTD^^xSOC&#K-s$l}y5^7tc z+5})IWr0d;{;lhanOYJH-w4;gma#e(;<w{4>H%}tDmMgxjpTROgOuALPdkwi0u zffVStP%Iq{Nir?N)OB-P))$tSm|o$GU@8X}43gveZF1*q)fy*p*}aFftM{|^itGZ~ zyy&83(89*3eYalndl=gIYm{R*bD7fFWlmVPoINVyxlAu-0VN!OvQJBkzkcfA#uX>_ zzD*CgGFt(wLE`K85QrI66?FOOPk*{+jtYiGFA^r8f#5j>QzM>@{at8IA?1tKE@GWW zAuyA~R&Vy@zf~tt=^5VcF~(s1L@X$m!(|Nyih7qFqP8hWS9_QKrDOT z<(G3KE=1k-A`wkR`>5?uIx~OJX282cdV2GXH}|dW#eAoU+y(C2Y@Cs3pg;jL$36#h zv@vxY$iz2rKu}le>m?{LjEi$d;6L4~aq;RnlaxdyE_CPjNpiC7hWWs^LwA&`u4IPu z>X@$U$WYjGuz(Z1_sAoU*3_ah6%;zJpm6f_Udcm%7O?Mq&Lob?zrO)weG?|X~9#_`wSIgQzj&NYuw}0P7d)Bt^*oF*Y2+>s%_^QDxuDAkv z*uAUQ0_#E&C|YR1)H1n83UPZH>TN4+U68wZJIoZ^fyO2^+CkBH(M2?~dy6<%7$#~f zH0B0>_2q;x66l-~+(=)$akH>M2Sk{*WfY`*&F4x4fCfls6ZryE!c^p2Z!o3ZrV`3I zly(fCk_oum=+twhGlxD4jk8_f&3z3Bpk02K&(^4{MhaPhLnF_JwER?7~^&FW8cl2-2h5F;dF7?#Hg#y)u4sxh+E^kG*LUkaEN_IS0;{cI^|q-t>S6Jo79{vOb)RL&HM2gtzP^HV&DFK`@o2FFQ_g| zVCWMecpBjk#i9p5hE*yTc9T4Vq*dB<=q=mQg=py_BF~k;Woeb8Msb-VM7PG2_&lUkC~6@9b*6gAsVVrmIcKHEb7?Rxi)BW;!;T&v zw@x}an@535tn8m6DiLM{0x!FDG-xhkX1V(6t6^~Xa~q1L^jVpZ1dR2YxN>v%K`E0R z8AJUadFGij-y!xFPs1(B)FBS!R_F}Ru&8Rc zNc!A!&&Ayllu$eHa&Y4<^b-HVlX4Zg>BU3H^{?%+8&XV+^#wnLz@c3I(}|j|>+J8FffCRiA`-vRe_ZuUj^?Y{%)EEA;cWrH-w4bX>pqptpT)WJr@~Kfb9Q`&9cw>#Ew+srFF&x@RCxNVb z-+lMNi&eS*k&pcR7ryY9+zZ$auwqSOnMr;dLEC@`KlI^*zxjZajSwOGxo3_Zr3FOh zm2L%bGB(pKe}SzY@HB6kdE#lZlREAcD7molQx*D6ID% z*njbX11N&KF}RXvgU{66=iO_#rXWOnEO=NQc}wX(xW7JQ!v`muEx*#(W$ahK-lh13+r*0hw%}4u`(bxz+w(Bq=weLLUc@z>Co=iK3HW_Mpj+r*_(zD z4-sF4Ena}+rfxsMl)Tv_apz@Y_Z9qCDjBMt)#oMaJ>qJz-7JYt&`e=6;BW$q*^%vM z!`W-c0gOx}Gux02`3~N=Y|QD2`UcP}%RiCF<7+gRA+a9$6ZGVS9cZ^Yerld_c2zQ5@{p?IQ@1U9W`|nrIxKO%%0wb0dH7sDjBUeT`Qia({$JTA=`IH^syc)>y9B) zyJ9LsOz1k9LhR01{|C&GtYw<2IvU{;qzpE9_%M8k$ehg+?&Qfp>LX)K~77#vCGW{<_9;U8-2)zV!N#hCjI1L)ts$C%IO9;!oW$Wd0 zU7)2{c*6{U)UxoJzGTvPUxw={)!i+53S|*`8EeJ@kZ88^(;Pg=#T=-X~#Spv^ix9(QdM!XMivu zLT*|-T~3+tB7w$CxtrDrXNh>mF*;qNOU0COAW)Xl57A4|V3vhxrz`lLfir6ki*qL} z*~xkF-tZb3bRgiQ|+rzD6+0|sb=?ye4*}g?Lvkp5{q+aDg&-1u|3ZeN( zzl>(=gBE#gX|ox-It`b;4b6}$=ju$A?&y8og&+%z4?R3YiLY3^HO=FV=M6p#CB@%= z|NVHOsiO}!EkW*)tl-hq$1Q>AqtG+pZ(ul(Vx)%j1$(!jig0A^9s)0O1O8hwPz|D^ z^PN~}bpmrr`7B4C9BG|N8=|hLgIBqQgFWUL@i*Kl)nnTlLC>jPWzesKxP#~BY1>fs zYPlGZ#kk-l1mbi~^4R(;;$_Y@>W7F2&WlauJcYzq0)|c1S+b~#5~_5{&&aLF3p`=N zhp&|~Z`++acCxb}Pz_bXZMWT~)eas!c=F^)euwZFKDmmu-yCMjsN4r0c!1@WL5Do# zZrLd@4}2RU{GCsJ655O8s-*g-WsjR^HSo1@)&F>rfagMf?tUZ;GsmSwL$tG&dvSUJ z%Y2UR^qq$^CMAz>K&7dsf^nIh$}O-dqjsh{NJ$ns(o25`PF*12ur)?6Av?h$b<`*VqSO-Eve^0i7Lu9^#Y8eQXWwS| zjQvg~OYzk>6#{ihNTb%0`gA5;N3x5UfIeAjaK?$PsC3=%SFHj4Xk;8^QBH%XH12D{ ztaY``&xt#xi}z+yQgf%e#&EG(#%61Wbrik{-dMSJdEkNjvF@_`Hy8BxB{~;17v3_| z6rtD(Uf!2o_MW|a*OCZp7z(V2&=PDniExJ|SA_^K5PLj>5OE@93ofv#a+#x>=qs{m z7&@Q6O?aa=lW~2sfU4l=*fg2Mukl^7udNWCX)6}7Z@rHv{YpG72UJP`E_Wqx_M=bd zAlf1!&c++JW$6LXRZb6y>6J8DXN^tWZe1&##9~5pw(dy{OIoQ< z3WdgkmEp*4vol!UE;C&O%~IPsq+V+C+Cs%5*{#Ft zC?+k|zA2|p{aueo!zG1G0O0S(PaH2B z=UxOL;YQXIRA*9;#;T!cE`@GtmMU7T2Y~xvr&f(WKp*&Za$nTDC9`Hyg zu0=WnEpS7>PDkiAhTkU~T$lAsBBc@TiYhh92U`gZ=8r0qthtfCs@N5RRO13fVv@-x zrSqIB@>t&Z+ z=3X4BgI68By75ACRivB{p%^earaRM>sC5(ib54!0L95+qt?W#>Qp&-n%P^DtPZ|c#?`Fe2%F_yJ&LJON5Zmzeu~xG`N2mXcux2&!vi8Tyks!-Zf5t zk?E}1fM+mFPNzr(-I?u|_ZR2mpnsDt5Ef#zumsPo+lfzliaJ3xW0j)$3!3fQudl3d z1}6$*odi`VExuy_7u)Ut2h(S8K5Nd!#v=yXUA;Q^#5g$Ee&QH&sqLxJR7Q+-WN*6a zhp#&E{0Z2u-U0T@CW*DbBtmpn&>yME)MvRBsWl9m`~wlv^EcmkgPj?)R}!J*wLFJ2 zO%pkNM$3|E9=z8yTUf6OTH;e_$XBblICTU)q+t_x3@Oa*a>H&@Cx9_+u=vuB{q)b# zkbrTrc$Aq=Q%9`&q}J3Eo|RHGDgi;`0!YHk$S-m>Fe&4mq)0mt4%dv7!A*FvH@@h* z;jFKm0s+OqPD;F8BQ39!v#l#LNv6CkOUWSW*pr+)H&Phg8YVfBu@es{@1X3po3fwC zaa>#zH=w*wxMsxR}AJ7W1xI#{7pJ;(PGJcgMYKssFDKpU&2iv6uC<>)n zPlQVs^di%Ik#9Z zYS2)W1K-@GhJk^{nT$bg-5(pqRqoEz@taxk{PWM3jl&t$T0+Z;)*4ndbhuIN)?05a zVuH8P8r0*Kv6)hpCVuA;bShqZ?X?_(Sz~~X82Q1_O@#U7_qH+(Z?Gs%SZ%~i9Gt}^ zyC;VYRh~`%o*STbDPuBkd|ReC%aUvtEGw8)4KtY33a^df=BVf#`uGd(I4cZ^#%NH) zhssDt^T7unM7~y8TXRY9W2s@_7r^#dlG{v6YRbQ$bH!$Y4b#A%kmi47+hDMkL;_3-L zFH4!G&n6{nr%54zzHA++cQ1M8C6cj85spxE4T+G%@9-2s9?)&jG@7F341VgVr*636 zh9tscMub$LFOwP=d)J|XFW;%Nr(_ZJa82Sa;i^%d9dXQ*hgcOvZ*-v!%EsGCxoRsy ziMG?~K1A-2AyB>xOuwF-4$eTuM@!Wy!HV??GYs|HU6C|Go*H0Y!Nkj_a0W{-F`r!?>D}tjq55@y8%JYyKcKj{bHj>a?=LIx+o&j{ zp;>LxAn<3g~WVt%EwB z_{1lcHdJ`?&$5tr_6}y_Jdbpp#<`2CtX*bNmDDyKp;Yf)^CQ=sJo$nIr}gQbuq1G* zT#tb_mH5|Ioe&}`eI{>~;2`J+1Ss4kgYD7|t-*6?SzcNbD1C$c>Xz?RX(bI*G+dYh ze8&4U=FdQkX>$Oty1_U3=g&TS769K>)Xwd=V-i}jp>j;-f?+sCb_WZ;?dn(pNsD6c zVD6gH@*~%UV5+=~Y2gB4uuviWc4qJk9`CMnt3RX^oI+2=-z!CAuFW$4o8Q`T8!}m; z{SqqKnP1GG=Cy0Ib>GZ1nVyp`k^e3YR}IA9)SoIIEL8KG+be9K-GA5gC52 zPur)Z4TSn>f*}bguTs#!>&xv1oo0xLvxp?55@B{JE}zHCRjFy{ek)|h1`y89TtYcm zq!j!K_nnbyZG*A`s~RXcgUujQg)Ba3{g{>_lSzGf&wNw40GS1ITzM4${!BC8&oWK7 zHWKdk58?d;z^B(hiJg{HY$-NmB~wI#@F`UXqNSgmgQXQY^uN^H7pI)S&9Bdn@tiTVgovmHIs7OS%+#az~r*!Ym`qKD|5dFK`A|3k4zLDH^?9&+UveP9-~a+F2`0S%E7hpBPKOGLI`Yzpu0`m z-&9fSmcG#5oF$ols@v__y((QD7$+eWe&4-&*FP41gy7F%KhWh4brD2Zin?oi_tLsb z>rUOWM%ieX{KC~ZQEIFl%SNa^xt-0IIgo>RqTqPL z8iNG0**7WpO>M(;W<)mM&gxb*iYTj<(iB;Ou~56Rcl zyS;cfqa($9MWm)ee=cpZr15GazfU{#EVfX0QqGD#|HsXje8W5xua1Y}1J9_>Mfd2WzC$|se`=87&<1IZ3Ba6O+*FRn_}X4^ zSYI1;$__&k-}RkvEiFJ8(HeB3P3eH@gEKUXx~d7-h=~ z9ivywAm)+kqZhRkzw7d>!Od!&?b_DFD2{VxRzwJ`AjWnA0WM+@37ouCz0pGW`!lD^H2R%e^qV6M*C@2+MPpBO&_YOtLu0%b<)j?@2Cgn zQ094kxnun1H~)F1gdJg}62Oz$oP4qRVA5huWRn z#qwpC@k@wcmD0+D3|B4f=o+e(?r$P@B4?eh0S;aS5(7H{+*9CPMf4NQ4Tz7K&~yd< z;ptu&oRullaI@#X&`_mBo!$_ynTQQo4hVp@Yx6A24&GO^0A4_$ziHfLE5MOquZo*j z3kLWxC^c% z-o1vg=DXIx*X&&y1}A*zvQS|Rnd&i=&Z_B>P^$%41Evz&YHZcnr~>NR9(raqbplq< zt6rd_Y8k7UzA)zqdJIBWj1GjhK!%ra-*iL=Ms0~g_=-t&U&2?KAN;Jpv3JqR14BF* z`NHCrNQe)i2k?|KZoI-egRaq3hJi*=fXrU**%Jds3elN4cl9%=@=#BB8)2{@UN7?< z$I8KJT3F+|nRUh0$jgFF1D646xzPg`({2U>FxM{!=9sbw@2KO%f2vrK0cVD0A;$7}^b^h(1~44j=1@z^3Ilh@?) zQQ=$q&w<+Zx$q2wf$TNI4w+xxy?1Y?kxF@+$qCd--rWlT3K@-e-gz4#lL1Ffz(NgG z8wQ*3vE7q&34+u|j~<0sC)b@(vm~qSfNmL#-+KFPNCUX!AkYo`kJpenM!~%-6dmw- zkUQ4LpL~qi>cs}H(KR+5G#a+XSk+k-;N^n{_p!CSL{xq$2U;{_qsXFKq{e}D(sOAd z1t47KGqfB(7^yv8`(S@Fjr+b$MkTqgW8?>euK^$D;+YJdShDlO>#y9peOtZsUw7_6 z+(!$&mJn(HHr zyy7`I(Dt|AGCTyt#S?yr_89B{3#d?8lBHsPr!w*Sze+S5ltSr@X(D@NeQO{AI!P8n0wwMl! z-);f53A2VNrYv(Gb0Lyy3!o>BNjHXAuywHbul?xTl~?6%%_OtOjbbMa{? z32CqS$JRdeP7u9+@7M2x`_@|j#TS1#{mbcShL)MB+8uE&g(XDEoN_TPd>A9Bu=y+~ zE(noS;HG>IBtj5e>ialUaWH)~q4Lqu-Ri=bu0}mIHp?Kl>CKz(UR({pSA{P=gtr6^ zI+aLk4-d~*^{D1SoDT?d5lL3*&1I$nXoyt%=9~XaG&{qi&p!3_QRvcwx%T`Vb_FDq zxZumLzI^!gBlQxy36aszaIL)e?%vH%%7h`b7s_WmL``rR1CARuNu9u5+>JpDIWHdk z{=uTfe8EC{<5$1>m$Hue`OXl!~&OhaP+iC)|7;XcS*YKxdi!myvX({uj{<{}F-{gvH>ZZjUK zW^lT4aL$TG$|SRCc1YVjwO?b$iC^K*y8lmmZl#19tW)9=6f(XVZ$mQEKY#mYth83o z4P{RrKYrtlf8wZPzlM!G-E0(dEV2}dB_+GQtG!!WR|7bFT-bCfz-m16)Cc zEmn&~U1uhQt*jsMgjz+`43}8@NtP@e-Blr>e_FN4u}J4h;5in4RR-Q->zbXN=243H zX;H)`2HM`~k(G3%IbYhf0$%qjR-vK{F@t>3OGUI|%asE|yE0iRL<5#BW9&z1N~P8X zaHRpufZhg4@RcLd9fpTzad2wKFnqPuqfCZM^E9?1JsJn009S;?Nkk3&D9jO{`B>(Q ztXTIj#gVsFvY(I?G=J3oR8Am*Gp0S@Vu#+JYdFUbfNW2@Dx6S?LRr)JORnLiFplA&l-K$BJ1{o3r- z-zy(w$v*bW{PyKFZ@v6PqGwd910m+(Wyp)E7W?OZ95Y=M z4s2A`VZ*~!HKS%sNQhA;5@r)7*tORWuO|{hF$HL)LUV1$MN)u^wc_oh&CsvD{(1&D z>#RB@5z1|`Y(mdn~$FkBrShJb*!3e zq901@=H%-&N%810d#3M%WQD)v0k!1*rPijsuI#n*+{dE6104!^BmWBXJJzQxhJ{>Jk zwUS2#_f0_CvuCTxF{q1Rr1n}HovPaMaNsKAN`@vApAWg8Cbm~3m^H7XERd4^knUFD zKc8kGGTm-6M1wRaC%)_vqH7!xdZlfA6nd(0#N+tUabeoUTB|d=BVG576PES@8q5}n zmCG}W&<2K`q~Z(>L3mjEiGRRVB=lMV5v66JR6CDLdqwZ;sV^0#|u}cUDmQ21VbWCi^$X-#Cg0PeeDyM(9Dp@iV1iSCW(}TkIB7 zYI|PKj-JAO-O;r=b(tI|h5QA5u2gRfLc&jM&Q~FS^&n%lcrhX&o+^?{O@zEzS9)|D zY?gFNUDgx2&wTMr07h;8NG4vQ{~-^zB|^zjuCm(XMwV%lnGY-D0WJ{dDZ^eZ?k$H1 zWU!iG_kynNv7Mg&O?l*)v$G4ld~0lEJ*BuO`}UtMUk8k+AtZ+$JYq*JFqgqRK`~6T zlao^b@G1|h(8`M)E*1llB1HJ5!6`oqdn4TRp=-f(KUOk|Kt7};`SP=p`KNG`gg&hH%Cya$q8 zVKJ(ZAyT)5VJgtEHUBck9bPy4OS~p#sI`e}9Hky?OfeZG2643Yz=p*QBEG2A2tOHG zHz=FtrgsIOi+L~9Sb`anzmzafvGznNh81ph9Fk7o3x)q1f5=(w>@y}Q> zW(|msXo+^@FiW79DV3HjDp}yi^4Ba9sdzbK#;RkZ*zPOKOOhwOA1tx7(gDoMNJ%XA z)ooQcpjvjQd&tmV@m7*XqLIMLgO(>TTP1^Z-y1xTH@Q$yF3f%Ajg8^=W0n_{?T999 z67xpK$vN7U2T@bG&zF#xV&jc5A0ld2qbdQ9xW@+b`ktA1qjMxilatbDi$i_3%Nd@) zzKWCORqVRH{kF+kGoA@8WxN^?_p?PfhdCGG_FM1!lV#ftXK!7Qj=DC9ftB$&=Q_ZWy3BlTz% zvDZqg@NrA^m{xb>umls21(4mUnVckbl1t9odkS{7U6uN{4ya(!0Sx?wBxO*$g|=o% zDyxaLc=Ck9!|S$CFPkx>hP5JRq@KgP_4i$S&SY~fmHRI_A}>;oJCT~Z8PwHD{sgxlILTaWNO6VLg>lu&VoXr4$F2)K)Yfo z{^!dusGT%BD=(7_K|6im#|FUjR~MTukUo zT%j1WQv`Au(-CABl2*CX;Gj)q%LCFggGrgjni|=ab~`z8njg5>(%gzr4PN3YfMBZB zuc-fE#DMzq8gcL}GW-bT%vI2Cr+m0MNg{hTr+(chql`%iCk=#Z8mqy_lQQoASEume zk_`z@|ML3JUXRiLdm&+}EBXv{jjqeG_CHC`Td)?@R%!>ey__w*hZQ29uyrgMOrP`X z#Sg&YU~Sd%wn=1r4z`Br4WmV3WbxlSZ59W|n9oi^%RGhhWG))4Q-Z20HT|$umC|l0 zyiF;bl4!{uhJsWfEzd?=TLFp}`F!K9D2Xtx{mQ$hICb!^cCM-X@TY3PL6|r5sf>;p zrx*#zaM?MLflXWu1zruJ_sOukW*+bcya1pdv!dP+b6(m?*5T8PkY>Wxw1Ko=m_jUx zyPR_1yLZ-g49qP_x#UH{_wZJvAscXQf;Ui5c`)(}COu@u0{CRDdmQIcO=EbGPB>v# z)AoY2As0Rdd%Jcy<+!JjbYOLr*0yolXzLdVD4Q}EGat^WpxVQf zW=mV)lSdY@#w)mi90Xy&V7j=|6M0XOySG za#N6vj!PP<93}j)O}W%XW2XytDxuvF+cJ)ozF4-5^#g>aSo!JSkDGVuwN+TICRHp1l zIECZi^RS9SLVY+y;y5{9GLtYq{~^<18&R&gl0(>)gg_E{`IIK<=j|fvE{YtV?7|B}CWZwAcS&!p&*QbB5p#YaGjPXuNE5^QK+=AL$uF-# zZsP@fCwil24(=k=HPkx6q3DsCNgyrTMU(hSTvVstB=zZ@RW@?Et&wAV2HtED;!8N< z7(1Vq{@sWQ{E|^R%|IhwPs`R~6^G8zq17#8N;NkP6Wz`>k5csUI5VlSw1oB4!o{xK zMuBv)KOm~b9Yr*UrsDF!LJc6+Ec1rbYcv&^&?)z*#Kx8O(9 zk;Rv!;2JTFaD)a-0OUBZD2l+_nxXsLkPM;gv*@#L47(+02snoTMu@bt%2%h=@g%%!5zu zwq~lJvX97DOiaayHD^5^#7Y`<74KH4E3;t+uFE30;$hVcv8{lb`?4Y4ZaL>JF&*p& zx3-ys@u*?_W{b@;7131>{?9b$WD}$n27VWV0h9pdWI&x+(yh!&)+PTGfS5^Na zoh1%X$>$8*wfTE+xIhlXP1Os}bw4FnOB*&utHL=G{}4FIZtXNiYL|@!caAv4ThPpK zxq(3vMb#<4Yx%}y&c*9CUUD;U0}@AHbMv&Bf2pgx7E5=fKkpc)%H+`;nqqSykt&g) zDM{uu8pS;K2jj$=U)f|~ub%H}i;fdx(n-x7)rFgtr&dQIxYDljiZC-!nt}F7z!BvL z*~4xiO#YrmS~n>^CgjxkYs@o#8}Ou6rdK$8HMjnJsRp67@=~G*|3wx!D&kVRR_3Q@ zjP5CSRZ|bB(_@K}qd?z1NX9>k<8jB(%x)7v1Da%oY0{g()t%&Z^GU^yejy31498~v zQrxckxTNyohobPN2ScRpe4rHGkbK>-JtDZP`UI_+7$j1|ij5u3YGkf60^5cp8k_17 zy)7}{AjjenI#@--puP<7x%bb;NqMFsj2)iEIUTfq(G^n|=;nV!B53J{=B|{Vu3P~sJ z{PdAXhp@ItC))NHV5#awOPUq98YKgbFT67+#)gl;b*TyuYfb5 z7LXG)#1}#OgDv8F8Y{bM-sYMWi%adg^-pT{iqS692HI6J(Htk#kU&_v@n(TRi3+`u zxGd>a{ab~g@_{G-eZ_oH3;X6I%0bm?$fdeM_0>j=4L)5r(o3zl{;#R_SYmCXoit&v z%R1S2GpRMwus5GOypb|}2Tg9BO`FZYWRp~!rvV=!jtJJpw;QUr##EN<#@iRu%pE@v zI*+7Q8#0V0c!7YBJ;mRu6G$P%aNb##(lvV8>J%f5M;>;=Kp~J=-Kp`zQg^|6Ob!J= zZm;Jupd!PZ0c3^>Ghjp(TEtx!=e91ribB&i1-kU3@*hQ#TW~TQ z+c~f82^UL#>ID1= z*8mPc74Ayb$T9Q|wK<1s3F0Uk%~7V1CZD>;>(5|P#5Du}n+2w9i(=FUZ5{!k%B1|x zlkcCHcOvb>Rv=*%*3@2Y-8}#>>C>Km|I~A53af(*3pZGpp8^h7UiH8ZI0_*gB|VkF zcKhtM%7!RAb*DIum<+snibSWCr~#lJ!n;i0W41J&V?u(_Ab5&{<&(x3)iPtmeFb#} zG-{uC^xkMOr1H0V~G^vsTi zs22*=p-O}BRHltY!tR{37!tnhJj%8S35BKI8o$q}`J+nYOPar-J}HpgE>< z6E1;~$D)GLwFnppM2Y%8=FY8Ijv~3^+cif5o0af6ax8o#F6-R~BK87&J&;~_*bNr+ ziNJx-1+z9f(wS*zXJ-9>om0^>LLo=Ek2Kv~UH8hm4qU>L^fEFfBy5IE@};sffJ3QjzXpLkrpCQT^S+55kiGvXo2xg5O3Es zojGX?v{{&e>H>ttt!H=3U2n}`s)<8|e01%;N|)}-oMDGDU($DQc6qmU_EFZQ3t5o)AG7^hK!UKgtpuHSLX;jbU=rjnjwIqKHE9kk3w8DiWV`QpoO+U zx0P`Nkcn_s*8PoK+Zp~p%%8IYgi~fvEip9CZ^aQZrY+r#G9O@L%4X7;4F7f2hHL=I zZcf~1@jZN0Bper}e z4>I3DdxhsIW9ScB8)7wNIhsc`7y1w`lArFUsgXa*1XRQG73rxEHE=0>7*3aHEiii^ zKyYD`0l~CMcFJb#kQdckf7TDmN%>Z_dNJmb(1Ztsq-X|yO-HbxXRJUj`^HlVYuGaJ zu8gP{32=0FH!Y%Lsj!d(x1aZZmW0`o$P!w`7PAgGzbb0#*>GxsFsjj7gx#;xpw#zvCv=xwKKBJbJXb=LM!t%qKDjTrf5Yr*U zH?lT*RmEa|4IzJA6ih4)b3l%5oU(SjoM$r%nETrIlG)|><@y&>P>)(^z88|YhZ9VR2Es+c`z_U?B$HYdVNTr|4*ZMmgBovyvpUuxkgi>)mrBNSk9i zFRWP+cA~a5eMYzmK_Dlgbi!@UD4(_mo$1*1V+=3^6Ht&{I_Lf&_=JEX7)i4N(UiiN znGZ1H3Q&j93Oc$&rGaeDCK*1ETrnF~_Fk0UV1p^|>;`NIQFfIfSf6&A+eVOG$foTV z{WjE$Fr%BYGl&tfW`%#fYzs`owpMDVBwX0z-JmOuFYjH(kUw-2qbp(SA|mCwm0@d^ z!`k)p>z3;|=u|?03|4i#VejtN{d|$GDvj_YmX|M)7eUp{N}{rm^eQJd?ozs~83ac| zY^?Y3S&(J2@o!CU9l}$dqzT=hqZbh+AR}P~S>@)y1)TakIkaWx&j@-&(*UZRZoQj) z`T^wlHLK_T5cwQ@!?v#|g!%Zo zt&iI#&KNVXTWTEw|*pRMsQ53bP5h%eJ;c9kYp^14xC88 z`s%A!HmmA0^qgbLjj!heH|yXFia{#xh_8+pqljO!IzmRJ+B(H-kryQ=aN}ZS>m+NB zllI9XoTyb8{H^r|INek7ZP9Q;0BCaGYbPonehDKJrP>}%%6oH8Ey*vuz3~OP{nxt4 z5W4EwdYn&tG7ccRS;lKrl{{k=i-DF))1l`{bs7kPfnACW-S~B;+5j8m=95l&-_{I` z(*1QSL%{nL*NQP8LE}cn&eLtrxuhh?NY6c6%&%-3(LVX)lRWL>G7{TqQqL8Q5qFSz zB;=eXWQNmAJvkK_W9)YoimE?`YBL(2n57X3Vkxo8d?dbOp)?Pk!=S5xE3vp`9N;aD z<76L@+ftM% z!!9e}@AZeBs%d5GtgZSnn++hX0btVrQI4@=LY!Wi(B%S=S0h0hu?FSUVp5@GjdD5)Vjvlw|4*Pko~b7f?)OjR_l3ka{uuVnYpj2fK+`_Uid^6?_OyQ5WUzel!r^CXT8 z1rWP(k2dT4j`7A6^OysniLr+nwNKXupI+ zETf9*6cAlUN7q56f!)A|)NnC0oQAu0^6`|iLAk_8N=_Vtxf88iqId~{rq`yF(X%?n z#@1{w_KCoTx@{1-(*lkMM@q}nMY3{N*bA4@z)s@5U^H!R(KW)JSkbT|o51VgP0n}n zi@0%X-)}8V+$PBRR0>0ijC@q5cz5#pB*Ke8duTt|2edlF!ZP+%H77h0`go`fYg}g= ztl559H(QK>RX70=vg5R}AE9QZ4P$%37OkZOF4BOpj0H7O`&+heMuD-~{;bMD&VC&k)ZC1g`roxZitcWDj_iVM@q}X~@qq zEXDR3cd2n#*_hU;Gf*!AG7cDJ@LzK4vm8wqDbEDWCAB;vePZ`Jky;_YdOQ7FT3f&y zRZ9)QUAlB$e=e$rkhWqdrU6W3Yla@C)mlm zEjm}QBE(%DCp2B7Akx>zhqf9@s_LgeOFqZxwH-n+4)0R z7F9hym^uwwvjioG7E47$Nl~OG3Z2>vTRm=_4;>NU7hrc0A6;9zYgw%Sf<$sh^4uTr zyv&soyBix-{y^tU_K};q5Un1xNCD*7Rkg_huE)|{ao6`;pm(eiyQ!goLDR668LY(? zYjEzL!^jQB_47##w#W} zWla&1`*N-tEKnd89>hY6?VjC;Lck!x+&9_ZTeeROf;(-)O7 z<`W`uD%a!XgiL<6xB(1B02h)t^85|6HXc^B678#)s;X|4h9$eV zf<7;kiq7foFyb8vp@K^cz&-~}gN}+6Swl+hD-J!8e&Rit z5r`OczA{2H>9t7tIT7^0?!xyfk;dwwIXkH-80tctk#)qw0`PSn0r#z9Xl%i>r5-1$ zJ0EzKDiSK?N?}S*kPATf)q>PNr9s>ZkWpf=aP0qI|MC|LdHZQu*gCqJSQ9JBc5YC^#>u>92j#rTBk!ogCk9Zsy}E~n`D?lGl0)Q&dJIDWuQ$#BP=RF>?Q?H|Qd~|DX=V6pTzJN{q(OIS5KtzQPF;(D@|=0+lxv)~^J~wjl|6_CP+WC3OeDLF=54!e zg)}=TjnYA~g@6v{mAC5?vuR8;8nNVR;;(5M2{niz&(N+wDJKz%n8T_bCXQJJn#LPc zg7bJ5Q5(ps`jG6^k0bz=pj}ftZH@83o*DxfZv>8hJm_b-gU_S{wez2$MGOx_KHO&z zjW$($b+mI29fxE28a2bXLR3?DruvH=ihk@P*i@ZX0L}7CQk>vvw2XFvVx*N&(vEFxBy-)WM;6B0Yie1;ISkipW?3g_kUJ*U9`1T;RwjI$>Lt+cNgAcK=fr;HaAiC2UC<7vymyj}yqA(e0hB7gYfA9nWm>8GDg9CBC4 zF(Nyx-;HA^2i|ChjzP+!ky9d;nO6IkKd~Wz0Qe0GEyUucp6*tj7a^5n>3~^Q7q>zp)qgBEU%4{HE5hIh2L6J66l)%v|~p34h3iy<35pRdeWgEuM))hQlg_<8d{#DKozqcD9^4;*}UnLQzMH7hg~?kbYn#8kFZ>Oh*GV z4G4Ypa}T2d5}rXLA%(z^H~>~pt48YNn4C?Gsl#{PfJ+k8M)1Zvh1ZJIxJ&`sNG_!1 zivDH^DU>5jg!ae<$m(1w*gM-T^C-WtUL&Q@SdHun7-)8r3tcuiP4z(SwK@)H=l!*O~$qeP1H*S?C@0X-(wpCdYF!_!!QmKnYJ)WAYcQ4 z9C);Lglx5%;ISg<{V(q?Z(o1?_4;%@GoXQ z5ir~dF@e~!%z7FlNO$GB;HRIhJ2VGEYm!k=Ai*v$q6&M&J4JW_v)b-YFtTk#o^Ifs z??sDcD5nJAc&HrBUdOWMVUJ6-Vf1&O_9*q`a!1qVNH%nFRhOC$MxBgbLm=KSl)mSuh+nW;V~U z;_+HOrxX-L{_4*8{eS#EPP?D2Fi{bW;W>9|fzaIsiHzlcL{83o1hI9tIizdY zB;bc$&>DjL0Y7f?VTncJiCs2#aP_HjU&5&(Ru=~Ax=6oAA;4Jj&f<;ER8atIPzgMU ze{j4bLZJ2K*r@><7@ZN3v!!RwlqhaU=fc(Z#vXYU;o@A_A0Y_l*G zl1P;@>B3Kh6`7KW!=xyRqK9VWU5hZan1P^EEjr^V!e$fog&G0DYNec(LZM?)CDu>J zGVp%WSVcX|aXZ zYuHOKnU#V#{PGQ%ZFHd-qXOD9(6Ggn0r@2!Z;Z8rG2l9^UA3M69GGqCvaUb{U*s`X~5#IL!pou$VJ->Y=Je0 zGsjUJIK=8JRzzhWZWL%MHI5`ycOni45?~Q=z1nU{huIgz^F+ZQm2?UU1}o%C3eKR)lQ`lx)w$;0mLkJ&B3>#mb$mb!4ch=gnqoLfa`j_L<%kHXb?|?1Q*x4 zB3j~x%YHcF;s0~(RHhOz5?10ahpobN>LHy2&)`He3)GCkkO=%C0RxJ688-!MfYGUm z=Trcw&IeG}iSW2j;TqkUU)eI?=strvSve5^Iw>ozGU~`Co;6@!x`rxnAF&TU$+|oa zRu{)2*U#lBMS0)4SgcJhj(&f$SQED_F3dct+1PKp{eExeM9qAv<$BvM91NH1*sz0n zKQkBH;TCXhEzlgwzJ2?xW|`Dx6l_K}?lL6|{x@DV+2pPX?YglI|CV1?hjB2+kykC? zb8kf_PU^G{7$SoTgcOIOX4lQS>t&3K4TIVFHU|n(4I2*YKr;zw-(zT+TMIP%go`tg zzGImKXY+(_ZeuK!CAY7;i(QkOcq&2Dfy1E(_xq*auFU}LGJJb?=drVj1pv4&YWusf zn71wL)@`#Zra3^v!N@6kz(=W`NHm8+k7Lns>-c*EMf0y}PAK*-_i|}!aAm%x2H>2` z+|rBa*m(|*P+{ptz(7BoS_5bdpjo9dYB(>Y<7W;ZMB*^CHM0lkBQ5Hbz=S0M-9MQA5?&&9 zWRX+nOGRXhx;N*1OI=Srod3;6xH&0#^ytwKKm71tKmBCW>2OF}@3(JV{PvwY_wL=h zbN7zTH*>6QRkGL1tE+!`>usCKPaZFSR`IKQ_pUB44Zb&M7gWW}sy=@F_`C1Ed;0XL zJ%_5PCH%L`%lF@V@9Of(7T=0MtNRamb_CucbGo|Xcq67m#x^;BGPi3#J=-7VyLawf zU0vF$-vV{nq6pv)CSQt=r817P#-RwJ*CB->-e;w*WV2+i_Sw^CPo6%RTD$bidOosw z{>yW#|M%a0Z@=b6sqLDrGUkcy>gvkI$UJ)40&Thf&p-eB(c?#tfBbQOIJ|rJ-QT_U zp0(GUfleICF=~0t*)I~P;fwdV_1pK~|L3!3Pp_@e))wz!@BH@Ozc0nwX8iL%e>Qh* zmf+H1!hD-m*XUbxJYLF}>7}Y}2ocnX+D2dyWpMSx;cDliTLxE`23PODZ@=bXh4|jF zPyA}FS*NvT{dsMh+}*o(ttB$8yLI_TAsAJj1C+cfKopnCv~2l>d`Lc)1Bg-WFKBM# z4=78E5=SD!8vaU>T8(NhX!sHN z0|SXf;?A8PBav`xYa6a=EhFiV`7AfFhjI5^S(DEyD4{TbNqS1;o*%q}izRjCs95E! zbTNjgKNc27FJBhTCsWC`P^&mRntb{4<>^zWP&>hb%NZA+K7IP&!2?1`Je~-JLd*l+ zEWcS?T)cSkBFvKGf0^ zu6V8eVIq}G(FP4X#!JLDG>bKcLiWx+4bzg{KAfQ z6^{!eq>r1CF3i6`v7;m$*REY7K%YE$vZJE|V~9o~!C=FCNYzT)WbDvc2?M;yGCMem zYyhX6!kh0qs)u+1DDe&Msi$2Bs9HZIlnBw=_4CKg!sfeg z-@d7-DY}fd)gX6v07K)Xc13&At7%^-Q+R|PIdWwG{{2_4UM(Rtlabbvr1O;3N}cDV zCa-?R_3PyWjS;VDHepwQMC*E6%evwR$iR&|*%cQ!G{YbaL|);cpv{aT#9TB3UIN?( z{J?NRFQB-l83bjsr;G~KaI5z2f~=0oN|9cxe`x0{q|DtyRZ9@;;)vQ39-EV;R^r5t z-MX-V>sF-V=Hs1ZY#zk*P(<>Qu>HdLL-Q8KYH}&)vLwX*_lI! z4iR?8#>V>lzwGSnY7MnwyZD>nU+_!Q74j+IQD$?L2N(bRSgwXQ!Y}r zOQ_RB;+QN4@Gg+M@*9?*odhEwYEmXddWd77j<2~A$dM2A(_k*9TA;j}H*YeXL=gSu zK7pGBdh#JwFGALWRcz%0goV( znwj!56FPI|3??!5-B_w88H=@}1uxvcd%yK|6OHm%(KF9fnk36Me8`lyD(#9%7)oqz zX^zHX^niy!e+a1@7$;eII-QoL(oL!w_lB-Ibc^oOtC@kX2XKT-mo9a6b?@H28;kkKm~RK?4OYvIzjuVi+;TdZ8{rV*616A6zbmOBHm1u zjW+y3{~A9`S4nTA2EEsOT@Au&crv%$MMXIi6)M9A*Gg}tmvW5-A;^tVquHU$=(1w- zB>U%|@~Ngy4l;4VSwpY^BaXC%8P&mg#df>8y88OQ+|${?qT2HE8`fb&-3Cn&0gBTT zAc~utnRJFDpD$pS)YjV88VN^$6nAmEwa)5`_~MJcjzpX%hvU(aLKzvvF&cuw=Ef#s zEAGuHai0k+M!%L_Bi1kz6^w4nPdPi4jsQvWmq5fm9g4T0$YPZ!)QsmDS&WpF4N%9Mg!|*;(o#fHc$x z87Ba6X#;UV^cIcA7>dOEtZASoizVyjz<46Dw|8%`xH&yN&1p|h&%Jy1-g}Fr?*L)H zI&grPd;k7@f)Rm!J+~1Gwa|TLFkaH#5^8J=5;TC284(2?CZ?dVTt3fSpLCDhlfa~D zl?aW;_xARp(&_16IZdTfg+kHiH(Od-BBFu<(`zb>MWd_`AP#JVpjLiH?-<$`@WPRB zs3pWLC=EobzrUY*pZ)f%Jnq#pZljY-hFdn!C#Vc#Ml==$6bh2bR@GF{GO6kICE^L5 z1(gsPQQBsqKyHyvXRtAvL8^-si~P}pt?4geI$tQvy_h@y&3T^D%*+g51?uatVdS8? z)slX$7lwab2E`Nx0J*0qgUCMQnY=Nl_p|5;lQH<*AM3ukS5Sd0I z=Q_A(w)+=X=Nc176~%Fj)Ms_k_$a8DS`iu&S|GFrQqX>YPb6r85O+;j35^)S5+Hmb z282NH0|{t|L?R@BiMVSFk2Nu{7c5&TOsdwy-{0AHUt3nLD$y$?Tn( z`#AUBbN}bub6?t%glh3;JV4gm;WUv)xtLD)5Fz3_qN2cM%)+H5X0nkRK;9?49jg3o7OY`#{fULW_o0Z&~o11K-fezyJdfjd}iYhD)ItPO{ zPo8}B;>EY45ODY4n(x~5^z`5N?g4x>>5h&L9%Lmy9029*7QK=zq47cSV5b_7{mT=aN6k!K?4u+)27TblrMj3GD%1_rQOaOLFW zpu$t*BFN>-9*(|FNlAgtguZK>*$O`(O%Ec6Xv#o89_VAKDuk#oClv~B!$ST2{lY&| z98(M|hk{&JSC^KS=5o2jCukFOgop+GvFhZVJ^T8(b5KHb^et9aR_LVAfI_O;-rf!m zP-2Kx_`&P_0rCInIPxn7`G`#9_Tx`i*M$|`^K?#IsR_8R|;m4V@E=3 zHEPGkp<)T1CiszBr?}!r4h1~Muf#STGAt2HJGD~Y<&MfmlT>VJu!LAaili|1Un#5%K##yg&YfBMEql@=~41KQ*`BH)$r7aH_5IPGrg0BQg zh-MPkJZiZ&u?_7f%2HRauKRqrwbO!O+(_U7XcV9@endyLrlw|VYa7nC*=)c!>se5rh25~Qu&}nac41+G z#( zP?OPva2FL7m6n!b*G5{rXScVuwl+66(~!o;$58``js8DFHxP_ZyWLI}NDGt{X(FMc+RWgEz;1NInK!agHiAGPX`Zl+&Z*ODU!r|dz zGC~lCqft>6%7-QGblD*4NfCS*T392#2W@^5k$hN=izIVPs?kA;b`+$Pad2 zeY}BAj2OKXbp#pIQ8;?tQG!9Z>#edf${9+ymz9;3mzP6f2>uEx_@{W`8Mq7DFg3(l zv%ZzOY`l77=Mv3KUkoSOu5KpPjv|n=Z#9sS-?>Bx?#6k<+(lT^s`mtePy7tKl4}9A zrOR>icLlJ+Krz|hif~h+Ww&o=FTAc zwr4BF?R+4dvB~A~sbqR-q)A#mt3`r!dYE$S1nN>|rYkTL;orus4$t>i`jkj!sR)jSbfMrLH93f?}MbP389z00j zWVW`h0uK1uFJ8Pzab_8aMlnY7o|BJ)I8jAr-=-sQ5!*oqWn8T+SBvoWZQDrPd{Z2c zPLCcvs;n!oT%nDs_S&`GvLHy1f)~~>_5jCkyKT!;PyI}Z=sPC*`50h|f;$sAy+wkxk&NrW$6A>AH@LLApMK?>22&QbQI z-?L{A(9~~_KKgB1#qD?8p@BMWW@bj~ObnSH``%;d!>QTXjq2uE-MDMlE+Q?lk+s2~ z(*WWTS`KRx$FH`S9ye{c38$ezh#HP1QReXJGiT~~rJoI`){&0Q2X+{XA1mT3Iui61<{Y7q-0CKxuXICk<9 zMVd-yQ*(CMQn=fW!*J44YU3G)B{qjkcq?cB-3< zQ7}A800rMM=mh=1R7;BgCvHItJ@Fdo4U z!z)xBl&!vTEhQ2p2>4AQwLWgD-}%3lFGY?-%kq;C| zQq6`ZKU0n-zkB+5*y1tXYQ4VLq9H-e(ID^==Sbo zk@6#D;U{Zzw|qah5xZBK<+QF%S`Ip~d1}+h-rF!eQ9YKfYku?F7{$!*AX7WsME00f zxV^PRRN=fjckXP2J@88N-;e?2*}HddYbujfd7aBdD+}cK@#9ld>p+k7hKTrjzF+Is zpIEDs1M}Wh3#?QSI`gRTDJ>fuR3%Fks`_;c`m{=4j3QdHaQV+se+aJfCM=qydb9Xkf# z1_lS`&dhCo_hy;Nw$K@X8oo`NHW3CvHZL5qOM!TQUwCnYJqPonVq>vPw0r>LZysO% z`ZvtaU-G70R3816V`EU80VJ*jiiH(;-SXu+$C%;}NOebWF~TI`JtVy(LO_pUPEK`^ zfiNyQlVBc?h)gi!mM@Dt;)z>V;>d;ZNr`TQ)8Co&)*T4LY#9GhwGSR(T zC-5XrIaLiPuA?DAL0tKwhj0bw^V3iNBG_kypp*$Fna}mkk%2A&AFa=MM<_#FjMbT< zn;T`wJzQ;D(n;$?N~M`M)^#siZcU!1OoV!wayRKtFD4+>+_DLK*)`bOsrK_%r}kd! z4KG|XQntV=*lpUQa|hjaYR4Zo0^=PA@J0H7wP)+cCH!E^O|$Y|}TbMEd#ETZ>~43CJzr=G{f{!X9Z8*|RQ^cBtF z;V!g!mIC<36+_p*<$4H{q4K>VEa}maVauB3n&f|(lDHQCYW|YNOVV1^4_SLp`NfaPvtd8c!LTCZIv zrrAgYlEiqG&47zjyL;15F8ch-nkEf@uZyQnU>t!~ZzDlNhb4B@W<@?|~?---jSbfBG75j1x|1 z3`RsvOcOOGE?j7g2`r4POe8Vt#>Bk1a_7dV8*Mi#3llMM>c$!A1_#7}!E`&DIK)}> z{h<2Rxd)mB@AlU>C-lG;1{91l-s!UY`Fw#Zc-eY9Ic5LuzIz}sN0uKslTUKz7bs8IWq$yY<9XGW)5M5 z@3Qd74kIHY2<4I`7m`7UqUIvu!m&}-U?kYsn6z6+(XnIaP8zfAJ9e1U)WncbiW-E& z3W1T?^UBc9bbMl*PQx}l;4_4PLJwWG?8SuEAv(apkU%W}nkWsi0Mw8Xg=Ge1+n+;) zqH`#c<`iyvG6fDXJUqNdvRJg1zhp-bjNXGYoX>^?rv!iR zZpiA}-9eVU`Sb0OrCPrHa^1@g@2HtGQJi!*9ks|pNt8GZ%WjP#5vLdGoLmy+6C{!j zO<-_v@T09;H*MZb2M_{2%U?VgRW)YL=M!v%F___z5!vD>RBfYUV~PeEWL?_~7{kD=BTqzke0+ihp}IlsW9tB& z*tl_&A>fJ?gPy#zVS}2ed27^~mDvp8zGn^m=Za23RDDz@HDp2UB4zZkzuIF-mA;au z<8`DGrR^#v^AoPh_RA8A>&Z58%QaE=;MDS6U>K9lkxipgtDHmzvCq^YZXD26y1DwV z6}7Vs0PrF%j*D_hcSo zDGAQ;%@P?tFlY8`E1Uv{rXCV!*?SB2qSHWyExDM4_G{*JYF#`JLCixU9w7*XM`C3b zCKdZLs%HiROmmQl6etuytV81%6_I@qT=dtzSPl?j7zhdiZnl!;762T5demP*VYi=^ z7l^|S89|lY<1K;`@$FS(EPB0u#Iao#lh005mI!eUH4OV@CHu*&Tr*}Iy=xazLV|N# z!m38*G+%D8ROVBJG7CG$0tJ^Sb0a;cL8J)z3a!^b!-SdydW&PpP}p$>yAyD>w>JKm zoQKPnUB(8BMXiQ|aqu>MD8u>v{b7dT38f<8mrUw;?g-m6LFwi|TgfA4zGdr5#&m?m zlcwK#C>LUft!h3S2^gpm#1bghunmJW05 zvZm#{TC*k&eZ;(CAJW%1^VRk1FI~FSu?|egjWd+R)! zP=wVQOR4<|*95e7^qG15Usp6>U-`A=-@Q0?uiUZw75KHvp#b8w2ZgxTim<&t(U^rs zaf(eoQye_+(=(B-^hNw7WM0aYVFB1%94@;&JzDus_6E|jM~-DCU{MOhxgCgDtSiq0 zfFr+g7l z?XW)rd$yDu0I$_yzr9E@W5ES_2(9r1Um=4huOz4mm0+dq<%&5CfZUT;TrML-p%z^|EUgV?O z>5#=v*?pbNN-c$*R!k=*<{UR$Ok<=P#t3Ktix!FIaNYCkJXy7Bl|6w8U>Yo3uz<|(mkY!+ zNFi%)Z>}lercS)9$(9S)%Kch;t90An8DkNWUe#nM2~gSEie0FPt5W)*My*Oz;&Z0R ztn!{EG$j|$cG>jibjAN@yR#grVIT~^Z0Tm$_w@oiqB#Ml;3mUuc;O_>1%@{+00P90 zSd#QMe9k}eL@X^vEz(jev8&2|l^wTTwyO^WWk9s%I>LZ=ZP3V#OZks7QSzqopxHj@ zUhB!>{lvjaI`bvnAYx1`#XFxPp;B_5UGJ=Mn~HipbP61}M1{*{0N)0r1m^54cEs)_ z;&m@2J5Ti;-e-)ay*7&JcJ*}LSdtC#;Bmpp1%X)U=In$(1tdB84)Rm31_f&N67bMT zff;+$!5ae7s9bZ?@p%k^7Z?G0%BC#2DNC=RtnmI(6kazT4Jt9h51yWyE0Z*oU}KCy zD3~ntu{`8;t`M;`t19J^6&md6bmE1y+8!1QLJH7=IU6%p zL%CGVnq2DC6as;d-FWahm$eW-cuI*$)F1*)(_-%QBHMQa<>XV~-{ zc$rb9D4N-`Z<;;xGmwU-3JBEFVtkSjyMejZk#3osR9ujtCmbcC0gqlw_~ivz-x;7h z(olHwtHRh^=076;TR&+1wjkJjx|?Z!jjn@X6s505_NmU}JXZLJA;m_4lv8&2M(dJ@ zMtYd5H|rC%UW8#H<$C zYO(BW!s=(3j9^@Rlp>a*bq>7{H$D?hU5J9dYl#qy)uXZB)^tl?1buFnOSRWoH)~5^ z)ZRJWAokmISiHxWN5~7F`5e2m7<z?LYxNXvXFFbD=ZG!;CuZ^ z>$@I)2C=flBoPRhx1COqkOsNqu*{fvyR5HXJV9jPUn0rM5@UC;YY|1AVZL4bMMUX& z5y+NE7+!U#QY`&7(?+$<=Syb64l1#}N832n&SJ1bkC8em-D+w*r%nz4iol)-6_{qq z8$iNuaLO92MnYUqd{%KsWR5RXE_&Wr1u5DV6kaK?2TQkjIgqWAVUf#3_5X3uvj!rR zHsfWj-YAt)&R(O}_6tGD@3l8=Orc8D!f9!KvZ(RgHYs{L&5Op@eSiZD!t%$SVPzzhz80YZA{T?I+aWmvM5gt!WW z7#;`U0>Fy(12zh>%ZIQ2@a%Fc3Tx{{r_^0pG5HXY9e=ocMsRw>@z>;a*TG)^e~RVB z-~_Q8sG}a1c^WZAZu-rF4u?oZn&EHH#E%%fiGQ8UX-Ss9?)E^#F5h%pF02{5>EU=f6H(u-d=j_QUi`@QIaLCWcB;AH;ht`l2>5&rcSGYQhy75{o7{F+roG^ zAN^)n*z6b^ijkAeIs)_KZXrEkiWF|IL>O0Jm>}sHCB-@oH^Dt(F|(qfy?ruaGPP@G`6Iozv7w9&$G&*+>9(BQyg=LX zbAv+1qQqy27gbG7c5ze^R&SmOaba=@kg%bhLy`Cu^k`5t=8RBveWyli!bF--8E=u0 zEZ3up7;EY^hZpBJ>5-{oz-IN2L{ipU#^>n}pW-Z!`f(zyc^^iSMe5KF!+BT@FIw~f z=TQj0f*o;+sM6(tn_zYl0V~d$eAh|(8`SQgh_-uZ6gIPqPX+{V#$@#;-e*gY9VRLaTaFHD#o0DB;R=E9lW=_@< zOX>_-Au(s!>ZI6ANgY1$-R#d|V<;-}tZbM0UQ6$Py#UzdhVq-~?VrbMjDh*A)acMU z-zZ#jdca!%PYXqQL|Lgdxt9=XG|_QZCDk#|U^7Nk#ebDvRk9PS`^3&VuxPr0t(5=& zshOk4VWSeci;e~RR+V4S#n6}IefWl28ycia2a-|bazYTHAgZ=)RRrxGf^AdRWTIx) z;XY7cgfCC|qn{HrE%2d{UtVGg@V)JXnZRJ?)I{48A|QKt>lfG#7>` zf=6N5F5j*rE6hojz+L`01U2L#e1+k%0#Ck+4rzsM+C{=Jj_N2Sc$&2kETe2dl}3ot zzVx0*LkjY`|ARh*2Zp`0lgVQY=)e}dn%BXL`Z5Ip6IP4h4sH)LjaEZ@XcuS)uc4;$ z?Cu|T01stBaFh`BLRY|R;7E(Z2Hhej%T@@*FP3sXCB=P+VQer65lBwm6oQe6Vj)3c zT?z`*OpKJ1#mjp`yIZhGL2bM+)5T{D?wlNY9)Q&gU#RSAflLM12~WCg zg4`}JTlb!@#IH|i;7HO)` zrQ4%e4+_=X9KEk4AqK9w6Oz~Onp3q61zAmK86Ku+j+EBiD>(?!JS3r#Pd<5mM7u9v z0Zr6O3cLsjm_{eXNsj5p(*d%JDYV*&X+RA)M~RqBuw}7XBfA?@GPh@+$(EM~3k`$6 z2&+@7fWLr+r#2_~NW7j_Yl0_Cgqlw{ZuA`K6dM$-& zb9y8-wVZ&Ud|}Q%CdxtWlOcc^4X$-BDGZ>%N){#Zx+u|@C@**dtJC%j%8KO$V&Ui( z=LpaT6S$6Jg+{zjrvn#=lo#~<0S@8j}>kRnjl7PSmbq~^PhI`Fit#QcGw z0pNG!gx?6+raVrm_;`S}jW=&8*q;1n4lUM1(8WgwffzFOo9V1=%;fv?9mtf7i%of& zT^STS)7ptCt}-G^1E8Cu>&fY%a-N!00R;(dXa{@AS7M8v*g(Fq$RaKG-Brf~iA2vx zgK}W#tmsA%clpivEK~zgpX~wCIiI{@uJ}M6eV9&x2g-%M5DgpXwALD>m+UJ-a|oXT zIU5s4eirZ#e}$gQTNTxEOq+tF<+}Tb^#;6ZLAbJCk_=(?)aphv{qy|!vm@Gl^^$jO za8!dO2x$S@>ggBYGcgMlPoK`m`r0oEn7l|DhheJ*4jC#&8d$eV6o~(r>FVTa+hkHl z@GqDFQo}n%m`MNu{l$Td;xH47g_3sY6X9V6f&d|Iigu6)#(Kod=pol3wt56fstXrQCO)Cd}lPA_YMz-B^pv@Y)UxSK-P zs*m9~XT)#TU#s~OsKl3Jb(oMREDYsp!^B$3ipmPfuMh{Y3})wnVi=-Y*hWrnO;2jp z9|890>A-Z8zKuLA&uZ=kV0(J~iALzO&?X}ZSQB4ATLt+U+aB|eP@*}bt zI2d$^gwdX#j&?tM_;5|Aov3y?7ZN+8yCM~b+M;t*8C89k{nz)azg6ecD50(h>$0AO?X zQNR-z+!7&WcB*j2sQC$;Im5z*&MeI`#i~5nH93+aD*gYUd);D=eGu#78zS!Lf>qBtdqo%Mvj%MjTc{egDsJ7fbU<;yD)88k_G9#(VDHuXJ-JD>L+7)TVd@JHDnw}X(luW@1 z?c`0s{2_l*Y*#kZ;(fN?^lvxa?GUGnM;1n6c-PlhqfcOv^p;03Eu zufDOvd=FjtDOe@Z*cc<(LmGjj%AcFC#(*a@0)ilesXm#dsF>5KsSO~7glkX_1EF!p zDJHD`AV^n}=Te!8PSLLd0n{i%G_@rXs?-Wc#S0MDO=tdK_s)+qbZJAyU(L{N?@`V>A}J!>L#1a%-=0dn+ld_`vxDMC@XgIDc88Pv|8 zEt%+w5?FxiNVl~a9Nq=FNqtGfl4nTvZgYG>FO9{%do0P zPtq-Pf6{_SJDq8Iir@07L8;e4683$kL0ToTp{9kQ*w(7WYCM&{^Pu-vB+bo`e=# zf_jw|IY+Y=Dye2)W__TyVjJd2Qki9;sez^Alz8jQ>2pvDsdNZelJ#40- zo`hWLsXW)wp1c$^2$E23E`Mm>dE@KYxoQec)8W>W6$Q^W&_%zn1k zxzQ+9bnbXl_mi8dn8>~VtA~t}1Feec>3=jJ?bgoUMHCJ80jr@r4zF|l?G6PU289sN z)lv=&0tR9*f(9Ol33euG+wV)pcUI(atzB8+JOoiX2f*-zN2`<}%2_+IE+)7!`RXvE z{mN~9!g<_wmti$&z??8hxmve&K}2Hz_^G4a*B*mMzv)32N7RD7sW?o75O<#CwYj(L zwU|i!PVwkrjG&YCmV#TEby~%7E>H}WS@BUpJg2uoMyE!qpq#LBl4Sp@85(jJi&EW5 zc>vY~umuc3LY;Hywu;YTLVE~wEtyh+iWEXVwHyvw^B=UZ?8QF>6$oG$5ugn`bhPQ{ zlXTNPT|f$v1ChyQT}Z_WN351v2C*5!Ln1eG$utD{R5UbV+b7%2&CP4eUSB=M+MoyXB-SN9-^whz za-+xhv>f`U z(-B-2gUcVV7C;fr)Cj*fsJza-&2m(4;&WQGL8ic=EKEf}ddtQi=y36Sd27?dv zJHwufQO1Jz1hq|M;7jHNWp<0=m32H#CaA`P*$){p8yQXvI&_e?rREZ*GIka#FAK%c zLVG;B_}|4=HP?q}Drz{Gok~5FCXO)2e)KXjXxLweH>52Kf9U#RI|Ljf4}G6mn5}#! zT8X}0jWLKALT-O{ZwqawOLcL=HLkshOusVfsNa&Ut#vtRwhvK3`%5r0Hu-wxE{}Tc?O0*1#dJcIj%4#zZok(%b-U*4yFg8| z{cuBGt|C6k%?O37USdSPzSFhk?S#5pwEOd$8;zU+o3gPmz)_Yd{FDW2B#kl5FD$WL zH5v*a5ov-}vMkUFhxnI+uDIzLu@bwm`z@m6p#Ut{cYSyg@1<+`pRrv>i&|oGb(ZU zkxHN@t<+UBEK``0FfF)S?LKsO*^yCvEy(MsG=SpgQiw4D!iv3Pcx4DkPO}K5?!IB= zG*UB3M+I;){os_*Jz7w|wGbqgCywIC?ROAH=SdZ%qK@e|^)UGAGs_&FaCN)u3N81M zr~lV=V6w6L+!4;@li*vs-n@BpM7y7TcH;R^rxX6KYV5{ACYMZRfX9y}v^H{KJL&MN zKBrn=vZ|w|29=Q0n8{TKaWE8&QIkX7&P7ncJ^}{cx1ZsHs2p)3)WS8so@sTVBmL62 z&S?9JOB;bOQuQHZ++7sjRvl;fknENQ7LOlaOWYCPkwltmL#NKE7QfG7kbO3WZkN2c zW+7M{LS%8{bwz0+3cqoN3iBwk8y9&Gk?0}epZ2Tjv{ZGn(!Z2~0UU%i3{E}5>$gh( sPUkGQ+iA@A>ScYr9tgd6Y6G%YFKe`eo$8+KK)M)ra-W{Cj zM9z7Hp_9kMu_JxqU^Yra=5P%|z5f9X<88Cq6h%?`J&zrHL$Ay{2q zP5B zyu&9{lT1FNu^%XhO0if}E|=}@?pj(}QmfVGu!V9`mwF=SXOiJ>pi_tog@RJ4q*kk0 zUS77hw>K9;*h*@$jqhltIwuVpz?a3vMU_fLy<{a$j;$WE8vZs;{lWcYL!ir%XS2L#EeNx0N?3GSP=H&O z`~9>+XRdA$yBkUJpZDFI+xUOoq~{WH7dV<67y|b_iBn#`kzslS^OJ4!&oLa*(A+aC z?}g>VA8L|D9`U&W&4)A?J4BzXe$poImd~(eUC2l6REB%@c9k-cw=>g=WfPcp=rI&k zUQeF!GW`7Y;Q#X$?~M&`zLRzBdPSvQZeW_4&)JA&X*x4!M$}*E?*6c??blAldHsm(rxpv>M-Xz@cExh+g5O4Yh3it{nsMSDeBI7xw<+#F2Y%C fRjc`r-TN31Rb?~xsk!?CgNwn_)z4*}Q$iB}4vwB< literal 0 HcmV?d00001 diff --git a/release/images/stock-flip-vertical-16.png b/release/images/stock-flip-vertical-16.png new file mode 100755 index 0000000000000000000000000000000000000000..586a5547bff3851446b162ff6536773db84f43fc GIT binary patch literal 407 zcmV;I0cie-P)g0VGL8 zK~#90os+*yLQxoopL3NohZ6h?f*?4XO^rFXG`6<3HTEC01r5!OwK=)!5SW7mB3FZm zGB1H~L)?Nmr@_wkc+b6BzSH^fz0dc3=Le+A1NLL{Kg$Dl03Cy5{$+0Zflh!p!L|gj z1@xPKfIkSixTyow(;#s`8F(^gfQ@2lA!H69rEIr)0lh)UT6VUzSuAmR8$q0s?XfbG zyY7(3;U}Z_H+6P=;H7w?3Ix-`5+*=v4L~mIDJy2q?6k0o48UYJ*M<<&WMAJZW5sBz z8m9s+rKIybqWkiJ`fVY+?002ovPDHLkV1hcG BsyP4v literal 0 HcmV?d00001 diff --git a/release/images/stock-resize-16.png b/release/images/stock-resize-16.png new file mode 100755 index 0000000000000000000000000000000000000000..4666f5680682daaf4e95c4497398a7f885b85e10 GIT binary patch literal 286 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G^tAk28_ZrvZCAbW|YuPgf{W&r_75y|u?_kcpHJzX3_D&{Pm=*ZV>z{8@x@oe$0 zmVXQ4-%I9&*oHh}=1`m{ry#J^m9u2Y2|JZ<@7VqwVO;p(-1%1x7q;lX+U9&j`Cg*d zm%}ICR&_F$1vWgpSh#-v46bE$D}x>>Xf&)0nwg;V;?s>Q(|HQG7HrD(_21Z3C$ZAU zoLi}7!s)WGfM47bIX(8CUg3)&Y8Yn&wkN^?!}Tz=A25H dUa)N+{(`aB=_u literal 0 HcmV?d00001 diff --git a/release/images/stock-rotate-270-16.png b/release/images/stock-rotate-270-16.png new file mode 100755 index 0000000000000000000000000000000000000000..cbe3ef8bf1822dbf2beeab593aaadea828c353d1 GIT binary patch literal 405 zcmV;G0c!qP!W_6QYn_Y-wHjvH(!wk&%&gI@2`0pA9@_;9V z@PO7O0MrifVmh7P&h6w=dUCY!{A$}3!-@jx+UyiSA7CjV@O&nd+1x)knyB?AxV$se ziec$e!9hR?3mD(Z?M~lRO||yvpv5BXJW)V|wXlblaLuZz*iMuCt8;TByBwE1HsFQM zpk_IZkGc~9@ZnY97I*>Pfj7XF1H9l6k45CWLx0zRZ=eZyLJl}NyJjrekE#exFCKqg z`qS5ddQeOb7y%v%#qyt)e0T*o1`NOjkYC{mSn$m7)C0@`UZGeHe%(5d z0tVU??HmFu0h8UpffQf{7y|Te;XuL%MVR3S3V35Dq6!`f00000NkvXXu0mjfBw(xJ literal 0 HcmV?d00001 diff --git a/release/images/stock-rotate-90-16.png b/release/images/stock-rotate-90-16.png new file mode 100755 index 0000000000000000000000000000000000000000..cdac3bcd98ba7366b6ffd89abfca8d5bb4581d60 GIT binary patch literal 418 zcmV;T0bTxyP)q0;lI?q{LDLh7g#w%1t%3G=Ezt6t;lvZv}FCiHlMdfKV`ilveBEu3X&NNGqDA ztpa;q0p(L`0!)iwcYkzXHkGab6MlH%$)LS9cMs~Zp+xwpZeTVWwS}o<7tje9Zmi;Q z69Hnt$nxAwxHqEGY+0xsA=So&Jw*w69J~O}@6UL{)(taYAKkl(NxuwaJRT>fm(Yt9 zEGZo!fYINO-6G>apWR~RFP}`+K`X9J(r^_NDh#(bg#o~`eW+XLn(xzluv7}8~DkSf^d4ZwCnwdTr z2Ht~j?zwZ$ec*rf0pfaY0TCbwbohnt0OaMfVadI_EsyS=ZNdkD{rcR~>HrL&7m&&E ztPCX+?y4^VaUkFoDu9eVI4?uVgj~ylNfDKfD0#F51yG>32MWqxXLZMJ_pV>eT_ze66)&SKGGzN%L zO6v8x6pO{C^e6g#1vn1ucDvz!e(ME(D5WS>ep7KAPWATzi~@OJ0a(_R{sQXlfD=Gr zW_E#@N{w%3o_oXR&_BrnOx@Q%TK!&R%5Nv{_rkkriZ{)pkEJ{fS-vqkV>Uahe9C%?gLpMqhlQL3kA3{WtJrxjXno107>8o(4{Au z=eY`SAe~Nk9SnEkIF4u!H}k)$E#+(7D9tAM?Z+B41rgC&M9>r{)DTTUb6Z2p#p#X?4gLWlGzAh=G&Tu26wXp42sua! z7lbr0Q&O;NrcZ-J5^=rPcRB~2&--wW!T2*HsXsX;o|iNokH^QtE0R{j;qVeL=NAVg z?L;Dx4PY5q@Pm&e9a@&P2W$iDz^qrClw_Nxc>;uhePGcmzLwMn+CUyS0|I`qB=yrb zmpz~Z91I7hM&RASv1#0Aa{%YS#c*iC4L6=M0OT?c6iTgE!1^2fZ$VR_sXw(5Vy?&Uao}{{*T3#>qqkv;C&CTBhZAm@drLGhV z2A_bnkLm?i)K literal 0 HcmV?d00001 diff --git a/release/images/stock-tool-crop-22.png b/release/images/stock-tool-crop-22.png new file mode 100755 index 0000000000000000000000000000000000000000..cf23381b8659def3b80113c82a11e03276ec2af9 GIT binary patch literal 811 zcmV+`1JwM9P)HgziuC_-Jh zv#YNA=1VE1i@-Q6+$8r*ZtguVE?UPj zv^FzS&-U>9oaa1?AN)@zeo2l1UMm)h1C>f8Q!Ey%mxbQ0R;%yL&d$CM+`KIG!+O2` z@yyK3C%^~5n*h!WqMx=}t=E^Amswg`+64@7_@YVg20^esJw3e+d;`p!)R25GabjXZ z0Qa=kjrsZcBVZHw8h8h|3M8Hj?d$8ir?n2p$Hyhm1lEC%fLDMN5PN2HY;5elwN_0| zPDYO7w1p57_zbvllGZt?se5#8Ztgp4tr;C1)k8x=DwD}HlgZ@giA3TJAOl=EjmEn{ z)9G}6VPWA8z^%7#hzGwvWME+6tHHs+Z)368p)sZ@r3?Yv75p>`q1f5k;h<7m?Q}X{ z#^dpWbUIy+$Kye%R5GV$W8I*EUk2c?T&C9Ov?`U#7si-c7=~ULhV9MGP4o1;a~_&X zrE0aLz*)7Z=|>(Etdf$6p6EwY|Olz1F%B z1c8)Nsdlno!>-$eoEW{mpdXi|Z$>nlCNGS_i>qe*3>A0?I&#UrD;;E@AkxV9Y z*=+Xhf3G!gg=)3L>W_u8=Xv+F)<!)ob*;lp<{V z{Py4vy|S|MQ=`#XZMWOML{U_UqUfa7#SIf4G#}%$2opSDb$bJFsg&|s ztyatT{oo?>G;F1mvbVRlB!s94A%s0X${3@7&|2H6*Xw#~Ys+-IR{`kn?-xobkw_$j p5CUuMKebrbb?xr%u6>rJ^*4+YrOK#umHPky002ovPDHLkV1oTojk5p% literal 0 HcmV?d00001 diff --git a/release/images/stock_clear_24.png b/release/images/stock_clear_24.png new file mode 100755 index 0000000000000000000000000000000000000000..96b6d57ddf3fbb4f40d7beda569803c434c8b999 GIT binary patch literal 791 zcmV+y1L*vTP)f=2b2hBEh;V#a- z=lp-?fA4|+ZHejq*OrG?yf|+gEwvRhpuY|vDJcp6@EA(=rs*I`j}4`}73D?C;s9-J z?J6jCZ2%6%hSF;TAwUR(Shz7QKzd?-&HFdKtPGP$O^hH~Hi|uYhd6(+ioRD)0J^)L z{J8^rzmxj=4UD{1NKQ`1+si;n@hL(>{JC|rhA9IJbD;zDDK@FTrJIM3n*lhUZ6af5 zwrFqf;PRz1b;Rt?o8}Gh)CTKiBM!wTMaxFvhJD?VPH;#k&ZQG0ri@b)r@7hTOWh2p}svmz@mQvjl`uLZNYbWR5zvk&AL zBM5ljVU^7FZA?r~vN0-{xCE21SnIG@>sTEefE>FX0E5AUl$0cG=k5VhX;UL1!)iRI1Aw8yVVB|n2XfPpWf_16ch0Ei+qb9cT(||; z+Z_xI4(r69+56S|>Z)S0_m$#se&fdFqX78&hUxyo-4m&ubXY414O|Yufb%1r4kuCZ zv5bEiWnf^KqM|DloXltZ^C;D~8?^P3rwdVC0wA7t^)vG6D{^!MW8Z(_>$en>F^A$4 zyIHc#j|2HTxKL4}t-)pB&Pha6IO(Q10)tlZV*-ZW4Rh738v>VF^987&Mb`g=>o=P+ V8NO!a8@d1h002ovPDHLkV1k#0cDw)p literal 0 HcmV?d00001 diff --git a/release/images/stock_down_arrow_24.png b/release/images/stock_down_arrow_24.png new file mode 100755 index 0000000000000000000000000000000000000000..ce290ba8d6dfe56c3d6f70f7f7cafedf174fb1fc GIT binary patch literal 589 zcmV-T0oKD`k+7z+7Qn~dcO0L5CrJ~wHaF=fF=B;No$`G76>gn& zuttCoK${FyM06n_wm*n}_5c{fzls{t6fp895QVWB#u@^p8v8ibMCC-SwG$Z`c*jj- zB0yMCt~l@rZmq2Y6xZ6a7h&l+s}A}Qh58%ds3P9FY)~G{tH9xtH;=e^YaS&Etu?91 z2t-)>{FYw#c%+mksoy(b_4N+G4WI{{=9LsnGp>S}2X`K_zVm@3O$bDxBw|=$^5yAE zMe!N8-xS+aG+6_E-~?ztUUR0P literal 0 HcmV?d00001 diff --git a/release/images/stock_left_arrow_24.png b/release/images/stock_left_arrow_24.png new file mode 100755 index 0000000000000000000000000000000000000000..c60eb07c11a2b1cdd95df9ab7680c7a0b6a6cfcc GIT binary patch literal 583 zcmV-N0=WH&P)`87i#7!*3!ef4c&Z#>8g74Zy)`{{R zjvdemsCEMcVEuQWhlq9o1YkG*Zp8n+Ku5a(0TjSbtMl{g0@4Jr zeXqru9-sz9X}96U`DN)65d=sJQc6S+;EX|v0EDAjtFnFehvnH7fM383Pywt;bAEVr zNLSE>jv~NfBa62BH3d=;nTYHC+t~C2xNCI=BA3hA-Q#UeiYJ7G)O8(WB8)R=G)gLz zRD?2ohA4&Y)`>Ne6oFk_THyEY`g02Y!#ji%xcD21b%s)*lnEe!?zx%y%GC4(qhlkP zi=!pC40)&n z#(@E!ftFg7MeN>0;%#-m!=&!s^)mUnA@I{n^}W{{*OsTRVZH(af57_7-{enk{{Xs+ Vvnl-e1+D-9002ovPDHLkV1iXX2D1PF literal 0 HcmV?d00001 diff --git a/release/images/stock_right_arrow_24.png b/release/images/stock_right_arrow_24.png new file mode 100755 index 0000000000000000000000000000000000000000..1a2162688f35cda987c6ae005d748f2e21526ae2 GIT binary patch literal 581 zcmV-L0=oT)P){w(D%`vm?NhC#Hc-dz5_q<;- zFZ_=tx;ZSn6t}=jpxiB}Xyn%UD+l_k5DD11?=x*kUlEARiB@`?fx#MI7AFDfKoxkA z2a$m~XMpK&4WNYL-OvbA-^L3;ga>HW_I{8WjT8!{)E@`VF3*udk)#P5TR&O&y2!<8 z@&<^3mJ2W+u(G}ks*JJvJ}qm>$bLgb8ErMjX!Z|wm>!!2@It&jNLmTT8jLlhS&Fd+ zD=bPVq!1XZQ9x9R80fDtG5`AG{gdrY)}GYp-CX8imAT;1p;& zKzNGsBK|n>fl4*k-1q!3@ou-103z2T?J~#}=Lrj=P^T&)h$w^J7lQtfwTr9lJi0d% z;*|gb(7M!`Z1@K+2}S{V=qie;5DrGXcE zsZKH|*bQLp1jjCeGe81p5uk4K8}QRP@gq8(yiG+=(Mb=Sjop8745UsY$vagpQR19T z-XB%X7K)0X`o~ZtPW;G~SSf_yoiIgH4mluAQqoki5~-B^rLd;Vt2!s*C?<|#RFxyNMa{Gms>l+ZiqF$zOarP1*I`UJIwa?M*U;KHm^VO|*O#&rW&nIWLS zch~4s-A*2`ToFj(#yUCe^=B&lrl#({Eo{F45q0NC&XT^<00000NkvXXu0mjfUrY_` literal 0 HcmV?d00001 diff --git a/release/images/straighten16.png b/release/images/straighten16.png new file mode 100755 index 0000000000000000000000000000000000000000..06ed43f2b5c02db0b9114f1d72793e9d202ef536 GIT binary patch literal 2918 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 literal 0 HcmV?d00001 diff --git a/release/images/straighten22.png b/release/images/straighten22.png new file mode 100755 index 0000000000000000000000000000000000000000..9b07b6234bdf00fc0141d9e5d36ce77420a16247 GIT binary patch literal 2931 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 literal 0 HcmV?d00001 diff --git a/release/images/trash.png b/release/images/trash.png new file mode 100755 index 0000000000000000000000000000000000000000..c185c78e42b531040c42b88b8a0ec6543031d265 GIT binary patch literal 810 zcmV+_1J(SAP)1w!KZDNz_Gw&_CM0z_h$MBR2mz5;fJ6|i5LeJeHmz8&U_tKz5G%x@a0OgI z7i=g}QK=Ax66{!^aR@Xv>2ZRGRh?dMl*G~RNfdt;j*~Cy)oP972=5lmd~(GcDe-Y`B6lMU6Lb0M zqIh#{jY6ToU^t*$+T_mNZ)hAGDox5b2)du^YW#ksQi*kdk&vGjiwo;3%U6sjiYS*V zeE7jfC{iXTr-4jn47a%eQ6a<(|EkMN0P({ zDF}xHf^L^#7^0Li0OYYC?XtRkS-T+MO0b5YTKk34(wi2Gxh~Hk*T!4i3g?%Ib^H zjGfeHUODS27r8i0wKhI3xp6G<;s@w zJP+G;F-?>6=jYH3o%zB%`TSYt3k4oke^pY`H%_?Id*Xig+P!bT`?9|OB)fdIXkWT8 zuTM=rgB04)g!L!mo!#Bx!Qo*i?)9!oDgRYsxqaY2w>1dYcD8q3wjArVBpENG6hg{U o9EV?z0w_;De~BsH2;1PHDUTu+8H7lcq_Uq)G10&%L=nzO2;)=ka_TI7eW5gv%4NJdO)M zB9Z7;w7?62_TcM&)fWl`1A=8)=!W4~W^1Emx6a$H{n^@NaP|8f2)lr{$B)We`NBKx zp^iz%aeada2ZSfa$B4zcQGGHC3rqZRX@-q-##0s9tmw7R^+Nt-nY+s53-1o>Pfk8O zJfupp%x_nI=iIsXY1A8}Qc2>yaSja)V%xS5*%$V^u6J^7ZZW(EkRL>n zZ2?TnWNRynCNqY@kk1saY=T8NU1}yI zSh{63tCgrUq2T+=hvnvR#n^PU*rFZ^7)!|vj6}907*qoM6N<$g86#Ji~s-t literal 0 HcmV?d00001 diff --git a/release/images/undo.png b/release/images/undo.png new file mode 100755 index 0000000000000000000000000000000000000000..58665ccc6bce9f5c2a2edafc8921c3f613b06619 GIT binary patch literal 194 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 literal 0 HcmV?d00001 diff --git a/release/images/vertical.png b/release/images/vertical.png new file mode 100755 index 0000000000000000000000000000000000000000..1870ddc90d196de38a4fcecc9ce5155fcc243985 GIT binary patch literal 777 zcmV+k1NQuhP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L00E@{00E@|*Kxnr00007bV*G`2iOP( z2mlwVV)TFj00N0gL_t(Y$L*C*NRwe4$3M@Tv2>}JI(7Ib-JCX9WE!QVBq3ddFhmk1 zBk)iik`5M;7rR7}L2R{u&542DT3&hHi`U0ZgYZKb8b(EwtC&Hh=eYF zZ}0E@Jimwc`#j&@3+q}%8$zD7mK~fcDHT_;b3~m`&^l)52mER%QOE9Gd&KqP{o+D& z40~M;hP+;!zul>@n7e~^#qXAibW24(d#CvF3b+)4C7oyxlg{Pu%=8yUR#poepb704 z0UQKU0F6c?%3kzIp?a?GfN+Vx1xAF32@vWygjE+{JDUh`!!(Lbul#wKAeDxv*X&D(%JK=&_KQM(ya zz*?g^M43PrU`f`aBqWB1$mzhQ3Q?vZJ0wIBMy)a0CpfBsK_;owyGL* z>V>yjnQ}U0OECU%Tc|x&FAhX$e=^fk_-|g7y&ew+U^0;Up0yraE51mqGIG!4Y!l_) zC6=rsvU6mJcEB4ta?KXen3hhqeM}AxyyfD;0@n3E*#FlznPx#24YJ`L;(K){{a7>y{D4^000SaNLh0L00E@{00E@|*Kxnr00007bV*G`2iOP( z2mv>U7v%{600T!!L_t(I%jJ|yXk2v^#((EOkIXoCoI5wkr1oLkgk)%%l%#1UCN8n9_Qqe++~%@|GQk(oM^ z$)wJmdtD^KC|$S|{8oQBALpF!f4+0zzYfQmw`y)-Lua={wztZ5cNMPW9P@y^N~jGH z*x4zayL)A)=I8EQmRz|^`Hl%A-8AffOrC$ZU!H5?$ovK0eM*Yl}L8Hb5^F*j=e`*yFWB4hLu&_kb*btpJQ_nnLS1s%dt! z+l})1s120J`iMMV-sOLxZJg6LF_uIRAO)ZUMsJ@SI(uHG<4I-3Q_8+^Q~lA?D<=R0FhX^7zjInHU7J+q zL|WNHF?IW;S7p%QU;y|M=m(SoSOQ9VkXv)JVk#wp?7W?S|0Lgx{cIo4W%&^qOi z@~Gc)cy(P|gCE)74G-Dp6F0d4L;x@FqpZmG0~-NXKqoAMFQ4a{Rl&T2GXkMHx>89l z0cBt-a0EC7d?i35@FY+V6xUAdU%(4!zz@JVAn632UP(F#WPKX<3V4f)jN8`o@FHSN4B6DAB|%RsOZ0D$#^0?Aa@?uaY)zq2ax= z@_8(wmXal94UekAD{sgdhm#1<4tQ35*af_;`Dv_g#L)G>d^j2-lSvZ=EO!-k;cYbN zK|CVM@pOuXiE%Qfi3ThHuQ`D$z`o5}WtEH*7PWoIfJY|y!5$go-89+9} z*V%a-0bP#hL2Bk^?U_uPGfO4Tt*o87DtYa-Y1q;r5w{E9T61k`!p(C3 prcG>^nzZ9LMz~xoQsDoMKLL&IDhv)LK(+t?002ovPDHLkV1hcEvlsvX literal 0 HcmV?d00001 diff --git a/release/images/warnhl.png b/release/images/warnhl.png new file mode 100755 index 0000000000000000000000000000000000000000..5b907554e26d2562dd6a2180b850cb32bdd773ec GIT binary patch literal 600 zcmV-e0;m0nP)Ad}LCp=}+7v+`_y-6@qjRfE*ibY?R`z;7?o9L4GkfrX zcklCgAKtz1_s&E_Kmb1&bI@B$o+kK@eFy%+=fn%hQpLi5PJGlMA86ur!Uv9wpn!9& z4Ky+H$Akc+(;(nnYvv#mZ^&N9#}O+P1?Rf!jcyZnGae?~iX@xGMsTjiw~nT7<87g5 zW)Q1Yyu7-?^L$=%sj2yPzs944vd||dGN^6axV*BWQ=gu?#$`wA`|x%Nix7&qZkYZ z!8DuX%&~^G+SB#A%@Q7De-{_n9HmkT3xz^UO*Fde2dB5=jt>aa5RU`cb_?OILQdQb z*07d)wAXXudBPJK24b;@zax=IU?dX3TCLVfu$FtcS3TOU+nGFWZlYIIUtX~C_~^+= zkFMm*H8#ZEFqY`~hEB+Wd>&wR72xx;bx8sGMeyOhzqi-#?f{ZW=3c3?M$YAcLvQgK zpPv)o2=G@C3>eVp5Cd7!e;Q6@@e~Tf)tK-#J1?T)JjS{~8Xv{b4 mjd0Iz6KHznd-%ur7GMBP2JnXsLt?G~0000nz*7iE~et?!B4}v$3f*^(n1≥ubJI( zcU@Oqw;K4rot>HYT<8!`}TwjN-3P{G1qAgss zz%tb=4bEb^1B!x@f z2oD-=gjgo{8MF(@$U0-+%%34!A(q(+^mjmE+OZ$Q6E@T@rPi01w=&CP->j Qi2wiq07*qoM6N<$f-7+Rp8x;= literal 0 HcmV?d00001 diff --git a/release/images/wb22.png b/release/images/wb22.png new file mode 100755 index 0000000000000000000000000000000000000000..ad1097c1e2b9cdd181b3e58378708a277839dfa6 GIT binary patch literal 1253 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 literal 0 HcmV?d00001 diff --git a/release/languages/chinese simplified b/release/languages/chinese simplified new file mode 100755 index 000000000..e49c9a78b --- /dev/null +++ b/release/languages/chinese simplified @@ -0,0 +1,579 @@ +# 06.11.2008 +# Chinese simplified +# Yang Gao (grantyale) +# Added new translations for 2.4beta, fixed mistranslations(eg. Vignetting - æš—è§’/失光 instead of ç´«è¾¹ which corresponds to purple fringing, and RL Deconvolution) +# based on Version 13.2.2008 by Forrest Sun +ADJUSTER_RESET_TO_DEFAULT;é‡ç½®ç¼ºçœå‚æ•° +CURVEEDITOR_FILEDLGFILTERANY;ä»»æ„æ–‡ä»¶ +CURVEEDITOR_FILEDLGFILTERCURVE;曲线文件 +CURVEEDITOR_LINEAR;线性 +CURVEEDITOR_LOADDLGLABEL;æ­£è¯»å–æ›²çº¿... +CURVEEDITOR_SAVEDLGLABEL;æ­£ä¿å­˜æ›²çº¿... +CURVEEDITOR_TOOLTIPLINEAR;é‡ç½®æ›²çº¿ +CURVEEDITOR_TOOLTIPLOAD;è¯»å–æ›²çº¿ +CURVEEDITOR_TOOLTIPSAVE;ä¿å­˜æ›²çº¿ +EXIFFILTER_APERTURE;光圈 +EXIFFILTER_CAMERA;相机 +EXIFFILTER_DIALOGLABEL;按Exif筛选 +EXIFFILTER_FOCALLEN;ç„¦è· +EXIFFILTER_ISO;感光度 +EXIFFILTER_LENS;镜头 +EXIFFILTER_SHUTTER;å¿«é—¨ +EXIFPANEL_ADDEDIT;添加/编辑 +EXIFPANEL_ADDEDITHINT;添加/编辑标签 +EXIFPANEL_ADDTAGDLG_ENTERVALUE;输入内容 +EXIFPANEL_ADDTAGDLG_SELECTTAG;选择标签 +EXIFPANEL_ADDTAGDLG_TITLE;添加/编辑标签 +EXIFPANEL_KEEP;ä¿ç•™ +EXIFPANEL_KEEPHINT;输出文件时ä¿ç•™â€œå·²é€‰â€æ ‡ç­¾ +EXIFPANEL_REMOVE;移除 +EXIFPANEL_REMOVEHINT;è¾“å‡ºæ–‡ä»¶æ—¶ç§»é™¤â€œå·²é€‰â€æ ‡ç­¾ +EXIFPANEL_RESET;é‡ç½® +EXIFPANEL_RESETALL;全部é‡ç½® +EXIFPANEL_RESETALLHINT;é‡ç½®æ‰€æœ‰æ ‡ç­¾å†…容 +EXIFPANEL_RESETHINT;é‡ç½®æ‰€é€‰æ ‡ç­¾å†…容 +EXIFPANEL_SUBDIRECTORY;å­æ–‡ä»¶å¤¹ +FILEBROWSER_APPLYPROFILE;应用é…ç½® +FILEBROWSER_ARRANGEMENTHINT;切æ¢ç¼©ç•¥å›¾å¯¹é½æ–¹å¼ +FILEBROWSER_CLEARPROFILE;清空é…ç½® +FILEBROWSER_COPYPROFILE;å¤åˆ¶é…ç½® +FILEBROWSER_DELETEDLGLABEL;确认删除 +FILEBROWSER_DELETEDLGMSG;确定删除所选的%1个文件? +FILEBROWSER_EMPTYTRASH;清空垃圾箱 +FILEBROWSER_EMPTYTRASHHINT;永久清空垃圾箱 +FILEBROWSER_EXIFFILTERAPPLY;应用 +FILEBROWSER_EXIFFILTERAPPLYHINT;文件æµè§ˆå™¨Exif筛选开关 +FILEBROWSER_EXIFFILTERLABEL;Exif筛选 +FILEBROWSER_EXIFFILTERSETTINGS;设置 +FILEBROWSER_EXIFFILTERSETTINGSHINT;更改Exif筛选设置 +FILEBROWSER_PARTIALPASTEPROFILE;选择性粘贴 +FILEBROWSER_PASTEPROFILE;粘贴é…ç½® +FILEBROWSER_POPUPCANCELJOB;å–æ¶ˆä»»åŠ¡ +FILEBROWSER_POPUPMOVEEND;移动到队列尾部 +FILEBROWSER_POPUPMOVEHEAD;移动到队列头部 +FILEBROWSER_POPUPOPEN;打开 +FILEBROWSER_POPUPPROCESS;放入队列 +FILEBROWSER_POPUPRANK1;评 1 星 +FILEBROWSER_POPUPRANK2;评 2 星 +FILEBROWSER_POPUPRANK3;评 3 星 +FILEBROWSER_POPUPRANK4;评 4 星 +FILEBROWSER_POPUPRANK5;评 5 星 +FILEBROWSER_POPUPREMOVE;从文件系统中移除 +FILEBROWSER_POPUPRENAME;é‡å‘½å +FILEBROWSER_POPUPSELECTALL;全部选中 +FILEBROWSER_POPUPTRASH;移动到垃圾箱 +FILEBROWSER_POPUPUNRANK;å–æ¶ˆæ˜Ÿçº§ +FILEBROWSER_POPUPUNTRASH;从垃圾箱中移除 +FILEBROWSER_PROCESSINGSETTINGS;设置 +FILEBROWSER_PROCESSINGSETTINGSHINT;设置文件格å¼åŠè¾“出文件夹 +FILEBROWSER_RENAMEDLGLABEL;文件é‡å‘½å +FILEBROWSER_RENAMEDLGMSG;å°†"%1"æ›´å为: +FILEBROWSER_SHOWDIRHINT;显示文件夹中所有图片 +FILEBROWSER_SHOWQUEUEHINT;显示队列内容 +FILEBROWSER_SHOWRANK1HINT;显示1星图片 +FILEBROWSER_SHOWRANK2HINT;显示2星图片 +FILEBROWSER_SHOWRANK3HINT;显示3星图片 +FILEBROWSER_SHOWRANK4HINT;显示4星图片 +FILEBROWSER_SHOWRANK5HINT;显示5星图片 +FILEBROWSER_SHOWTRASHHINT;显示垃圾箱内容 +FILEBROWSER_SHOWUNRANKHINT;显示未评星图片 +FILEBROWSER_STARTPROCESSING;å¼€å§‹å¤„ç† +FILEBROWSER_STARTPROCESSINGHINT;å¼€å§‹å¤„ç†æˆ–ä¿å­˜é˜Ÿåˆ—中的图片 +FILEBROWSER_STOPPROCESSING;åœæ­¢å¤„ç† +FILEBROWSER_STOPPROCESSINGHINT;åœæ­¢å¤„ç†å›¾ç‰‡ +FILEBROWSER_THUMBSIZE;ç¼©ç•¥å›¾å¤§å° +FILEBROWSER_ZOOMINHINT;增大缩略图 +FILEBROWSER_ZOOMOUTHINT;å‡å°ç¼©ç•¥å›¾ +GENERAL_ABOUT;关于 +GENERAL_CANCEL;å–æ¶ˆ +GENERAL_DISABLE;ç¦ç”¨ +GENERAL_DISABLED;ç¦ç”¨ +GENERAL_ENABLE;å¯ç”¨ +GENERAL_ENABLED;å¼€å¯ +GENERAL_LANDSCAPE;æ¨ªå‘ +GENERAL_LOAD;è¯»å– +GENERAL_NA;ä¸é€‚用 +GENERAL_NO;å¦ +GENERAL_OK;确定 +GENERAL_PORTRAIT;çºµå‘ +GENERAL_SAVE;ä¿å­˜ +GENERAL_YES;是 +HISTOGRAM_LABEL;直方图 +HISTOGRAM_TOOLTIP_B;显示/éšè— è“色直方图 +HISTOGRAM_TOOLTIP_G;显示/éšè— 绿色直方图 +HISTOGRAM_TOOLTIP_L;显示/éšè— CIELAB 亮度直方图 +HISTOGRAM_TOOLTIP_R;显示/éšè— 红色直方图 +HISTORY_CHANGED;已更改 +HISTORY_CUSTOMCURVE;自定义曲线 +HISTORY_DELSNAPSHOT;移除快照 +HISTORY_FROMCLIPBOARD;ä»Žå‰ªè´´æ¿ +HISTORY_LABEL;åŽ†å² +HISTORY_MSG_10;阴影压缩 +HISTORY_MSG_11;影调曲线 +HISTORY_MSG_12;自动æ›å…‰ +HISTORY_MSG_13;æ›å…‰æº¢å‡º +HISTORY_MSG_14;亮度亮度 +HISTORY_MSG_15;亮度对比度 +HISTORY_MSG_16;亮度黑 +HISTORY_MSG_17;亮度高光压缩 +HISTORY_MSG_18;亮度阴影压缩 +HISTORY_MSG_19;亮度曲线 +HISTORY_MSG_1;图片加载完 +HISTORY_MSG_20;é”化 +HISTORY_MSG_21;é”化åŠå¾„ +HISTORY_MSG_22;é”化程度 +HISTORY_MSG_23;é”化阈值 +HISTORY_MSG_24;ä»…é”化边缘 +HISTORY_MSG_25;é”化边缘åŠå¾„ +HISTORY_MSG_26;é”化边缘容差 +HISTORY_MSG_27;é”化光晕控制 +HISTORY_MSG_28;å…‰æ™•æŽ§åˆ¶é‡ +HISTORY_MSG_29;é”åŒ–æ–¹å¼ +HISTORY_MSG_2;é…置加载完 +HISTORY_MSG_30;é‡å åŠå¾„ +HISTORY_MSG_31;é‡å ç¨‹åº¦ +HISTORY_MSG_32;é‡å è¡°å‡ +HISTORY_MSG_33;é‡å æ¬¡æ•° +HISTORY_MSG_34;é¿å…色彩溢出 +HISTORY_MSG_35;饱和度é™åˆ¶å™¨ +HISTORY_MSG_36;饱和度é™åˆ¶ +HISTORY_MSG_37;色彩增强 +HISTORY_MSG_38;æ‹å¹³è¡¡æ–¹å¼ +HISTORY_MSG_39;色温 +HISTORY_MSG_3;é…ç½®æ”¹å˜ +HISTORY_MSG_40;白平衡微调 +HISTORY_MSG_41;色彩åç§» "A" +HISTORY_MSG_42;色彩åç§» "B" +HISTORY_MSG_43;亮度é™å™ª +HISTORY_MSG_44;亮度é™å™ªåŠå¾„ +HISTORY_MSG_45;亮度é™å™ªè¾¹ç¼˜å®¹å·® +HISTORY_MSG_46;色彩é™å™ª +HISTORY_MSG_47;色彩é™å™ªåŠå¾„ +HISTORY_MSG_48;色彩é™å™ªè¾¹ç¼˜å®¹å·® +HISTORY_MSG_49;色彩é™å™ªè¾¹ç¼˜æ•感度 +HISTORY_MSG_4;åŽ†å²æµè§ˆ +HISTORY_MSG_50;阴影/高光工具 +HISTORY_MSG_51;高光增强 +HISTORY_MSG_52;阴影增强 +HISTORY_MSG_53;高光色度范围 +HISTORY_MSG_54;阴影色度范围 +HISTORY_MSG_55;局部对比度 +HISTORY_MSG_56;阴影/高光åŠå¾„ +HISTORY_MSG_57;粗略旋转 +HISTORY_MSG_58;水平翻转 +HISTORY_MSG_59;竖直翻转 +HISTORY_MSG_5;亮度 +HISTORY_MSG_60;旋转 +HISTORY_MSG_61;旋转 +HISTORY_MSG_62;镜头失真矫正 +HISTORY_MSG_63;设置书签 +HISTORY_MSG_64;剪切图片 +HISTORY_MSG_65;色散矫正 +HISTORY_MSG_66;高光还原 +HISTORY_MSG_67;高光还原程度 +HISTORY_MSG_68;é«˜å…‰è¿˜åŽŸæ–¹å¼ +HISTORY_MSG_69;工作色彩空间 +HISTORY_MSG_6;对比度 +HISTORY_MSG_70;输出色彩空间 +HISTORY_MSG_71;输入色å‚空间 +HISTORY_MSG_72;暗角矫正 +HISTORY_MSG_73;é€šé“æ··åˆå™¨ +HISTORY_MSG_74;è°ƒæ•´å¤§å°æ¯”例 +HISTORY_MSG_75;è°ƒæ•´å¤§å°æ–¹å¼ +HISTORY_MSG_76;Exifå…ƒæ•°æ® +HISTORY_MSG_77;IPTCå…ƒæ•°æ® +HISTORY_MSG_7;黑 +HISTORY_MSG_8;æ›å…‰è¡¥å¿ +HISTORY_MSG_9;高光压缩 +HISTORY_NEWSNAPSHOT;新建快照 +HISTORY_NEWSNAPSHOTAS;为... +HISTORY_NEWSSDIALOGLABEL;快照标签: +HISTORY_NEWSSDIALOGTITLE;添加新快照 +HISTORY_SETTO;设置为 +HISTORY_SNAPSHOT;å¿«ç…§ +HISTORY_SNAPSHOTS;系列快照 +ICMPANEL_FILEDLGFILTERANY;ä»»æ„æ–‡ä»¶ +ICMPANEL_FILEDLGFILTERICM;ICCé…置文件 +ICMPANEL_GAMMABEFOREINPUT;é…置使用Gammaæ ¡æ­£ +ICMPANEL_INPUTCAMERA;ç›¸æœºç¼ºçœ +ICMPANEL_INPUTCUSTOM;自定义 +ICMPANEL_INPUTDLGLABEL;选择输入ICCé…ç½®... +ICMPANEL_INPUTEMBEDDED;如å¯èƒ½ï¼Œä½¿ç”¨å†…ç½® +ICMPANEL_INPUTPROFILE;输入é…ç½® +ICMPANEL_NOICM;No ICM: sRGBé…ç½® +ICMPANEL_OUTPUTDLGLABEL;选择输出ICCé…ç½®... +ICMPANEL_OUTPUTPROFILE;输出é…ç½® +ICMPANEL_SAVEREFERENCE;ä¿å­˜å‚考图片用于生æˆé…ç½®ä¿¡æ¯ +ICMPANEL_WORKINGPROFILE;当å‰é…ç½® +IMAGEAREA_DETAILVIEW;细节视图 +IPTCPANEL_AUTHOR;作者 +IPTCPANEL_AUTHORHINT;作者姓å +IPTCPANEL_AUTHORSPOSITION;作者èŒä½ +IPTCPANEL_AUTHORSPOSITIONHINT;作者头衔 +IPTCPANEL_CAPTION;标题 +IPTCPANEL_CAPTIONHINT;文字说明 +IPTCPANEL_CAPTIONWRITER;说明作者 +IPTCPANEL_CAPTIONWRITERHINT;å‚与创作人员 +IPTCPANEL_CATEGORY;类别 +IPTCPANEL_CATEGORYHINT;æä¾›è€…所认为的作å“类别 +IPTCPANEL_CITY;城市 +IPTCPANEL_CITYHINT;图片æ¥è‡ªåŸŽå¸‚ +IPTCPANEL_COPYHINT;å°†IPTC设置å¤åˆ¶åˆ°å‰ªè´´æ¿ +IPTCPANEL_COPYRIGHT;ç‰ˆæƒ +IPTCPANEL_COPYRIGHTHINT;版æƒä¿¡æ¯ +IPTCPANEL_COUNTRY;国家 +IPTCPANEL_COUNTRYHINT;图片æ¥è‡ªå›½å®¶ +IPTCPANEL_CREDIT;æä¾›è€… +IPTCPANEL_CREDITHINT;图片æä¾›è€…,未必是作者 +IPTCPANEL_DATECREATED;创作日期 +IPTCPANEL_DATECREATEDHINT;图片创作日期,格å¼ï¼šå¹´æœˆæ—¥è¡¥é›¶(YYYYMMDD) +IPTCPANEL_EMBEDDED;内嵌 +IPTCPANEL_EMBEDDEDHINT;å°†IPTCæ•°æ®é‡ç½®ä¸ºå›¾ç‰‡å†…åµŒæ•°æ® +IPTCPANEL_HEADLINE;æ‘˜è¦ +IPTCPANEL_HEADLINEHINT;å¯å‘布的内容简介 +IPTCPANEL_INSTRUCTIONS;指令 +IPTCPANEL_INSTRUCTIONSHINT;å†™ç»™ç¼–è¾‘çš„ç‰¹æ®Šè¦æ±‚ +IPTCPANEL_KEYWORDS;å…³é”®è¯ +IPTCPANEL_KEYWORDSHINT;用于信æ¯ç´¢å¼• +IPTCPANEL_PASTEHINT;粘贴剪贴æ¿å†…çš„IPTC设置 +IPTCPANEL_PROVINCE;çœä»½ +IPTCPANEL_PROVINCEHINT;图片æ¥è‡ªçœä»½ +IPTCPANEL_RESET;é‡ç½® +IPTCPANEL_RESETHINT;é‡ç½®ä¸ºé»˜è®¤é…ç½® +IPTCPANEL_SOURCE;æ¥æº +IPTCPANEL_SOURCEHINT;å›¾ç‰‡å†…å®¹çŸ¥è¯†äº§æƒæ‰€æœ‰äºº +IPTCPANEL_SUPPCATEGORIES;附加类别 +IPTCPANEL_SUPPCATEGORIESHINT;进一步细分类别 +IPTCPANEL_TITLE;标题 +IPTCPANEL_TITLEHINT;作å“çš„åç§° +IPTCPANEL_TRANSREFERENCE;传输基准 +IPTCPANEL_TRANSREFERENCEHINT;原始å‘é€åœ°ç‚¹ä»£ç  +MAIN_BUTTON_PREFERENCES;傿•°è®¾ç½® +MAIN_BUTTON_SAVE;ä¿å­˜å›¾ç‰‡ +MAIN_BUTTON_SAVEAS;为... +MAIN_BUTTON_SENDTOEDITOR;å‘é€åˆ°ç¼–辑器 +MAIN_MSG_ALREADYEXISTS;该文件已存在 +MAIN_MSG_CANNOTLOAD;无法加载图片 +MAIN_MSG_CANNOTSAVE;文件ä¿å­˜ä¸­å‡ºé”™ +MAIN_MSG_CANNOTSTARTEDITOR;Can not start editor. +MAIN_MSG_CANNOTSTARTEDITOR_SECONDARY;Please set the correct path in the "Preferences" dialog. +MAIN_MSG_EXITJOBSINQUEUEINFO;退出时队列中未处ç†çš„图片将被丢弃。 +MAIN_MSG_EXITJOBSINQUEUEQUEST;队列中尚有图片未处ç†ï¼Œç¡®è®¤é€€å‡ºï¼Ÿ +MAIN_MSG_JOBSINQUEUE;任务列队中 +MAIN_MSG_QOVERWRITE;是å¦è¦†ç›–? +MAIN_TAB_BASIC;基本 +MAIN_TAB_COLOR;Color +MAIN_TAB_DETAIL;Detail +MAIN_TAB_EXIF;Exif +MAIN_TAB_EXPOSURE;æ›å…‰ +MAIN_TAB_ICM;ICM +MAIN_TAB_IPTC;IPTC +MAIN_TAB_METADATA;å…ƒæ•°æ® +MAIN_TAB_TRANSFORM;è½¬æ¢ +MAIN_TOOLTIP_HIDEFP;显示/éšè—åº•éƒ¨é¢æ¿ (目录和文件æµè§ˆå™¨) (shortcut key: F) +MAIN_TOOLTIP_HIDEHP;显示/éšè—左颿¿ (包å«åކå², shortcut key: H) +MAIN_TOOLTIP_INDCLIPPEDH;高光溢出æç¤º +MAIN_TOOLTIP_INDCLIPPEDS;阴影ä¸è¶³æç¤º +MAIN_TOOLTIP_PREFERENCES;è®¾ç½®å‚æ•° +MAIN_TOOLTIP_QINFO;图片快æ·ä¿¡æ¯ +MAIN_TOOLTIP_SAVE;å›¾ç‰‡å­˜äºŽç¼ºçœæ–‡ä»¶å¤¹ +MAIN_TOOLTIP_SAVEAS;图片存于指定文件夹 +PARTIALPASTE_BASICGROUP;基本设置 +PARTIALPASTE_CACORRECTION;色彩校正 +PARTIALPASTE_COARSETRANS;90度旋转/翻转 +PARTIALPASTE_COLORBOOST;色彩增强 +PARTIALPASTE_COLORDENOISE;色彩é™å™ª +PARTIALPASTE_COLORGROUP;色彩相关设定 +PARTIALPASTE_COLORMIXER;色彩混åˆå™¨ +PARTIALPASTE_COLORSHIFT;色彩åç§» +PARTIALPASTE_COMPOSITIONGROUP;构图设置 +PARTIALPASTE_CROP;å‰ªè£ +PARTIALPASTE_DIALOGLABEL;选择性粘贴é…ç½® +PARTIALPASTE_DISTORTION;å½¢å˜æ ¡æ­£ +PARTIALPASTE_EXIFCHANGES;对exif所åšçš„修改 +PARTIALPASTE_EXPOSURE;æ›å…‰ +PARTIALPASTE_HLRECOVERY;é«˜æ„Ÿå…‰ä¿®å¤ +PARTIALPASTE_ICMSETTINGS;ICM 设置 +PARTIALPASTE_IPTCINFO;IPTC ä¿¡æ¯ +PARTIALPASTE_LENSGROUP;镜头相关设置 +PARTIALPASTE_LUMACURVE;亮度曲线 +PARTIALPASTE_LUMADENOISE;亮度é™å™ª +PARTIALPASTE_LUMINANCEGROUP;亮度相关设置 +PARTIALPASTE_METAICMGROUP;元数æ®/ICM 设置 +PARTIALPASTE_RESIZE;缩放 +PARTIALPASTE_ROTATION;旋转 +PARTIALPASTE_SHADOWSHIGHLIGHTS;阴影/高光 +PARTIALPASTE_SHARPENING;é”化 +PARTIALPASTE_VIGNETTING;暗角修正 +PARTIALPASTE_WHITEBALANCE;白平衡 +PREFERENCES_APPLNEXTSTARTUP;下次å¯åŠ¨ç”Ÿæ•ˆ +PREFERENCES_BLINKCLIPPED;é«˜å…‰åŒºåŸŸé—ªçƒ +PREFERENCES_CACHECLEARALL;全部清除 +PREFERENCES_CACHECLEARPROFILES;清除é…ç½® +PREFERENCES_CACHECLEARTHUMBS;清除缩略图 +PREFERENCES_CACHEFORMAT1;ä¸“æœ‰æ ¼å¼ (快速高质é‡) +PREFERENCES_CACHEFORMAT2;JPEG (è¾ƒå°æ–‡ä»¶) +PREFERENCES_CACHEMAXENTRIES;æœ€å¤§ç¼“å­˜æ•°é‡ +PREFERENCES_CACHEOPTS;缓存选项 +PREFERENCES_CACHESTRAT1;较高速度 +PREFERENCES_CACHESTRAT2;较低内存å ç”¨çއ +PREFERENCES_CACHESTRAT;缓存方案 +PREFERENCES_CACHETHUMBFORM;ç¼©ç•¥å›¾ç¼“å­˜æ ¼å¼ +PREFERENCES_CACHETHUMBHEIGHT;最大缩略图高度 +PREFERENCES_CLEARDLG_LINE1;正在清空缓存 +PREFERENCES_CLEARDLG_LINE2;å¯èƒ½éœ€è¦æ•°ç§’钟时间。 +PREFERENCES_CLEARDLG_TITLE;请ç¨ç­‰ +PREFERENCES_CLIPPINGIND;高光溢出æç¤º +PREFERENCES_CMETRICINTENT;è‰²å½©æ¨¡å¼ +PREFERENCES_DATEFORMAT;æ—¥æœŸæ ¼å¼ +PREFERENCES_DATEFORMATHINT;å¯ä»¥ä½¿ç”¨ä¸‹åˆ—控制符:\n%y : å¹´\n%m : 月h\n%d : æ—¥\n\n例如,中文日期格å¼:\n%y/%m/%d +PREFERENCES_DEFAULTLANG;缺çœè¯­è¨€ +PREFERENCES_DEFAULTTHEME;默认主题 +PREFERENCES_DEMOSAICINGALGO;马赛克还原算法 +PREFERENCES_DIRHOME;用户文件路径 +PREFERENCES_DIRLAST;上次访问路径 +PREFERENCES_DIROTHER;å…¶ä»– +PREFERENCES_DIRSELECTDLG;å¯åŠ¨æ—¶é€‰æ‹©å›¾ç‰‡è·¯å¾„... +PREFERENCES_DIRSOFTWARE;软件安装路径 +PREFERENCES_DMETHOD;æ–¹å¼ +PREFERENCES_EDITORCMDLINE;其他命令行 +PREFERENCES_EXTERNALEDITOR;外部编辑器 +PREFERENCES_FALSECOLOR;虚å‡è‰²å½©åŽ‹ç¼©æ­¥éª¤ +PREFERENCES_FBROWSEROPTS;文件æµè§ˆé€‰é¡¹ +PREFERENCES_FILEFORMAT;æ–‡ä»¶æ ¼å¼ +PREFERENCES_FORIMAGE;用于图片文件 +PREFERENCES_FORRAW;用于Raw文件 +PREFERENCES_GIMPPATH;GIMP安装文件夹 +PREFERENCES_GTKTHEME;GTK默认 +PREFERENCES_HINT;æç¤º +PREFERENCES_HLTHRESHOLD;高光溢出阈值 +PREFERENCES_ICCDIR;ICCé…置路径 +PREFERENCES_IMPROCPARAMS;缺çœå›¾ç‰‡å¤„ç†å‚æ•° +PREFERENCES_INTENT_ABSOLUTE;ç»å¯¹è‰²å½©æ¨¡å¼ +PREFERENCES_INTENT_PERCEPTUAL;æ„ŸçŸ¥æ¨¡å¼ +PREFERENCES_INTENT_RELATIVE;ç›¸å¯¹è‰²å½©æ¨¡å¼ +PREFERENCES_INTENT_SATURATION;饱和度 +PREFERENCES_LIVETHUMBNAILS;实时缩略图(较慢) +PREFERENCES_MONITORICC;显示器é…ç½® +PREFERENCES_OUTDIR;输出路径 +PREFERENCES_OUTDIRFOLDER;ä¿å­˜è‡³æ–‡ä»¶å¤¹ +PREFERENCES_OUTDIRFOLDERHINT;将已寸图片放至所选文件夹 +PREFERENCES_OUTDIRHINT;å¯ä»¥ä½¿ç”¨ä¸‹åˆ—控制符:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\n这些控制符指å‘RAW文件所在文件夹åŠå­æ–‡ä»¶å¤¹ã€‚\n\n例如 å‡å¦‚ /home/tom/image/02-09-2006/dsc0012.nefå·²ç»æ‰“开,控制符的æ„义如下:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\n如果想将输出文件ä¿å­˜åˆ°è¾“入文件所在ä½ç½®ï¼š\n%p1/%f\n\n如果想将输出文件ä¿å­˜è‡³è¾“入文件夹内的'converted'å­æ–‡ä»¶å¤¹ï¼š\n%p1/converted/%f\n\n如果想将输出文件ä¿å­˜è‡³ '/home/tom/converted' å¹¶ä¿ç•™æŒ‰æ—¥æœŸæ‰€åˆ†çš„å­æ–‡ä»¶å¤¹ï¼š\n%p2/converted/%d1/%f +PREFERENCES_OUTDIRTEMPLATE;ä½¿ç”¨æ¨¡æ¿ +PREFERENCES_OUTDIRTEMPLATEHINT;å¯ä»¥ä½¿ç”¨ä¸‹åˆ—控制符:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\n这些控制符指å‘RAW文件所在文件夹åŠå­æ–‡ä»¶å¤¹ã€‚\n\n例如 å‡å¦‚ /home/tom/image/02-09-2006/dsc0012.nefå·²ç»æ‰“开,控制符的æ„义如下:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\n如果想将输出文件ä¿å­˜åˆ°è¾“入文件所在ä½ç½®ï¼š\n%p1/%f\n\n如果想将输出文件ä¿å­˜è‡³è¾“入文件夹内的'converted'å­æ–‡ä»¶å¤¹ï¼š\n%p1/converted/%f\n\n如果想将输出文件ä¿å­˜è‡³ '/home/tom/converted' å¹¶ä¿ç•™æŒ‰æ—¥æœŸæ‰€åˆ†çš„å­æ–‡ä»¶å¤¹ï¼š\n%p2/converted/%d1/%f +PREFERENCES_PARSEDEXT;已知扩展å +PREFERENCES_PARSEDEXTADD;添加扩展å +PREFERENCES_PARSEDEXTADDHINT;输入扩展å并按此按钮将其添加至列表 +PREFERENCES_PARSEDEXTDELHINT;从列表中删除选中的扩展å +PREFERENCES_PROFILEHANDLING;图片处ç†é…ç½®ç®¡ç† +PREFERENCES_PROFILELOADPR;é…置文件读å–优先级 +PREFERENCES_PROFILEPRCACHE;缓存中的é…置文件 +PREFERENCES_PROFILEPRFILE;与图片并列存放的é…置文件 +PREFERENCES_PROFILESAVECACHE;å°†é…置文件写至缓存 +PREFERENCES_PROFILESAVEINPUT;å°†é…置文件与图片并列存放 +PREFERENCES_PSPATH;Adobe Photoshop安装路径 +PREFERENCES_SELECTICCDIRDLG;选择ICC路径... +PREFERENCES_SELECTLANG;选择语言 +PREFERENCES_SELECTMONITORPROFDLG;选择显示器ICC路径... +PREFERENCES_SELECTTHEME;选择主题 +PREFERENCES_SHOWBASICEXIF;显示基本Exifä¿¡æ¯ +PREFERENCES_SHOWDATETIME;显示时间日期 +PREFERENCES_SHOWONLYRAW;仅显示Raw文件 +PREFERENCES_SHTHRESHOLD;阴影过暗阈值 +PREFERENCES_STARTUPIMDIR;å¯åŠ¨æ—¶è·¯å¾„ +PREFERENCES_TAB_BROWSER;文件æµè§ˆå™¨ +PREFERENCES_TAB_COLORMGR;è‰²å½©ç®¡ç† +PREFERENCES_TAB_GENERAL;一般 +PREFERENCES_TAB_IMPROC;å›¾ç‰‡å¤„ç† +PREFERENCES_TAB_OUTPUT;输出选项 +PREFERENCES_THUMBSIZE;ç¼©ç•¥å›¾å¤§å° +PROFILEPANEL_FILEDLGFILTERANY;ä»»æ„æ–‡ä»¶ +PROFILEPANEL_FILEDLGFILTERPP;处ç†å‚æ•°é…ç½® +PROFILEPANEL_LABEL;处ç†å‚æ•°é…ç½® +PROFILEPANEL_LOADDLGLABEL;加载处ç†å‚数为... +PROFILEPANEL_PCUSTOM;自定义 +PROFILEPANEL_PFILE;由文件 +PROFILEPANEL_PLASTPHOTO;上次图片 +PROFILEPANEL_PLASTSAVED;上次ä¿å­˜ +PROFILEPANEL_PROFILE;é…ç½® +PROFILEPANEL_SAVEDLGLABEL;ä¿å­˜å¤„ç†å‚数为... +PROFILEPANEL_TOOLTIPCOPY;将当å‰é…ç½®å¤åˆ¶åˆ°å‰ªè´´æ¿ +PROFILEPANEL_TOOLTIPLOAD;由文件加载é…ç½® +PROFILEPANEL_TOOLTIPPASTE;从剪贴æ¿ç²˜è´´é…ç½® +PROFILEPANEL_TOOLTIPSAVE;ä¿å­˜å½“å‰é…ç½® +PROGRESSBAR_DECODING;Raw文件解ç ä¸­... +PROGRESSBAR_DEMOSAICING;马赛克还原中... +PROGRESSBAR_LOADING;图片加载中... +PROGRESSBAR_LOADJPEG;JPEG文件加载中... +PROGRESSBAR_LOADPNG;PNG文件加载中... +PROGRESSBAR_LOADTIFF;TIFF文件加载中... +PROGRESSBAR_PROCESSING;图片处ç†ä¸­... +PROGRESSBAR_READY;就绪 +PROGRESSBAR_SAVEJPEG;JPEG文件ä¿å­˜ä¸­... +PROGRESSBAR_SAVEPNG;PNG文件ä¿å­˜ä¸­... +PROGRESSBAR_SAVETIFF;TIFF文件ä¿å­˜ä¸­... +PROGRESSDLG_LOADING;Loading file... +PROGRESSDLG_PROCESSING;Processing image... +PROGRESSDLG_SAVING;Saving file... +QINFO_FOCALLENGTH;ç„¦è· +QINFO_ISO;感光度 +QINFO_LENS;Lens +QINFO_NOEXIF;Exifæ•°æ®ä¸å¯ç”¨. +SAVEDLG_FILEFORMAT;æ–‡ä»¶æ ¼å¼ +SAVEDLG_JPEGQUAL;JPEGè´¨é‡ +SAVEDLG_JPGFILTER;JPEG文件 +SAVEDLG_PNGCOMPR;PNG压缩 +SAVEDLG_PNGFILTER;PNG文件 +SAVEDLG_PUTTOQUEUE;放入队列 +SAVEDLG_PUTTOQUEUEHEAD;Put to the head of the processing queue +SAVEDLG_PUTTOQUEUETAIL;Put to the end of the processing queue +SAVEDLG_SAVEIMMEDIATELY;ç«‹å³ä¿å­˜ +SAVEDLG_SAVESPP;éšå›¾ç‰‡ä¿å­˜å¤„ç†å‚æ•° +SAVEDLG_TIFFFILTER;TIFF文件 +TOOLBAR_TOOLTIP_CROP;剪è£é€‰æ‹© (shortcut key: C) +TOOLBAR_TOOLTIP_HAND;手形工具 (shortcut key: N) +TOOLBAR_TOOLTIP_STRAIGHTEN;基准线选择 (shortcut key: S) +TOOLBAR_TOOLTIP_WB;白平衡采样 (shortcut key: W) +TP_CACORRECTION_BLUE;è“ +TP_CACORRECTION_LABEL;色散矫正 +TP_CACORRECTION_RED;红 +TP_CHMIXER_BLUE;è“ +TP_CHMIXER_GREEN;绿 +TP_CHMIXER_LABEL;é€šé“æ··åˆ +TP_CHMIXER_RED;红 +TP_COARSETRAF_DEGREE;角度: +TP_COARSETRAF_TOOLTIP_HFLIP;水平翻转 +TP_COARSETRAF_TOOLTIP_ROTLEFT;左转 +TP_COARSETRAF_TOOLTIP_ROTRIGHT;å³è½¬ +TP_COARSETRAF_TOOLTIP_VFLIP;竖直翻转 +TP_COLORBOOST_ACHANNEL;é€šé“ "a" +TP_COLORBOOST_AMOUNT;程度 +TP_COLORBOOST_AVOIDCOLORCLIP;é¿å…色彩溢出 +TP_COLORBOOST_BCHANNEL;é€šé“ "b" +TP_COLORBOOST_CHAB;a å’Œ b +TP_COLORBOOST_CHANNEL;é€šé“ +TP_COLORBOOST_CHSEPARATE;分解 +TP_COLORBOOST_ENABLESATLIMITER;å¯ç”¨é¥±å’Œåº¦é™åˆ¶ +TP_COLORBOOST_LABEL;色彩增强 +TP_COLORBOOST_SATLIMIT;饱和度é™åˆ¶ +TP_COLORDENOISE_EDGESENSITIVE;è¾¹ç¼˜æ•æ„Ÿåº¦ +TP_COLORDENOISE_EDGETOLERANCE;边缘容差 +TP_COLORDENOISE_LABEL;色彩噪点抑制 +TP_COLORDENOISE_RADIUS;åŠå¾„ +TP_COLORSHIFT_BLUEYELLOW;è“-黄 +TP_COLORSHIFT_GREENMAGENTA;绿-洋红 +TP_COLORSHIFT_LABEL;色彩åç§» +TP_CROP_DPI;DPI= +TP_CROP_FIXRATIO;比例: +TP_CROP_GTDIAGONALS;对角线法则 +TP_CROP_GTHARMMEANS1;黄金点 1 +TP_CROP_GTHARMMEANS2;黄金点 2 +TP_CROP_GTHARMMEANS3;黄金点 3 +TP_CROP_GTHARMMEANS4;黄金点 4 +TP_CROP_GTNONE;æ—  +TP_CROP_GTRULETHIRDS;1/3法则 +TP_CROP_GUIDETYPE;辅助方å¼: +TP_CROP_H;高 +TP_CROP_LABEL;å‰ªè£ +TP_CROP_SELECTCROP; 选择预设 +TP_CROP_W;宽 +TP_CROP_X;x +TP_CROP_Y;y +TP_DISTORTION_AMOUNT;程度 +TP_DISTORTION_LABEL;失真 +TP_EXPOSURE_AUTOLEVELS;自动色阶 +TP_EXPOSURE_BLACKLEVEL;黑 +TP_EXPOSURE_BRIGHTNESS;亮度 +TP_EXPOSURE_CLIP;高光溢出 +TP_EXPOSURE_COMPRHIGHLIGHTS;高光压缩 +TP_EXPOSURE_COMPRSHADOWS;阴影压缩 +TP_EXPOSURE_CONTRAST;对比度 +TP_EXPOSURE_CURVEEDITOR;影调曲线 +TP_EXPOSURE_EXPCOMP;æ›å…‰è¡¥å¿ +TP_EXPOSURE_LABEL;æ›å…‰ +TP_HLREC_CIELAB;CIELabæ¨¡å¼æ··åˆ +TP_HLREC_COLOR;色彩延伸 +TP_HLREC_LABEL;高光还原 +TP_HLREC_LUMINANCE;亮度还原 +TP_HLREC_METHOD;æ–¹å¼: +TP_ICM_FILEDLGFILTERANY;ä»»æ„æ–‡ä»¶ +TP_ICM_FILEDLGFILTERICM;ICCé…置文件 +TP_ICM_GAMMABEFOREINPUT;é…置应用Gammaæ ¡æ­£ +TP_ICM_INPUTCAMERA;ç›¸æœºç¼ºçœ +TP_ICM_INPUTCUSTOM;自定义 +TP_ICM_INPUTDLGLABEL;选择输入ICCé…ç½®... +TP_ICM_INPUTEMBEDDED;如å¯èƒ½ï¼Œä½¿ç”¨å†…ç½® +TP_ICM_INPUTPROFILE;输入é…ç½® +TP_ICM_LABEL;ICM +TP_ICM_NOICM;No ICM: sRGBé…ç½® +TP_ICM_OUTPUTDLGLABEL;选择输出ICCé…ç½®... +TP_ICM_OUTPUTPROFILE;输出é…ç½® +TP_ICM_SAVEREFERENCE;ä¿å­˜å‚考图片用于生æˆé…ç½®ä¿¡æ¯ +TP_ICM_WORKINGPROFILE;当å‰é…ç½® +TP_LUMACURVE_BLACKLEVEL;黑点 +TP_LUMACURVE_BRIGHTNESS;亮度 +TP_LUMACURVE_COMPRHIGHLIGHTS;高光压缩 +TP_LUMACURVE_COMPRSHADOWS;阴影压缩 +TP_LUMACURVE_CONTRAST;对比度 +TP_LUMACURVE_CURVEEDITOR;亮度曲线 +TP_LUMACURVE_LABEL;亮度曲线 +TP_LUMADENOISE_EDGETOLERANCE;边缘容差 +TP_LUMADENOISE_LABEL;亮度噪点抑制 +TP_LUMADENOISE_RADIUS;åŠå¾„ +TP_RESIZE_BICUBIC;åŒä¸‰æ¬¡ +TP_RESIZE_BICUBICSF;åŒä¸‰æ¬¡ (柔化) +TP_RESIZE_BICUBICSH;åŒä¸‰æ¬¡ (é”化) +TP_RESIZE_BILINEAR;åŒçº¿æ€§ +TP_RESIZE_FULLSIZE;全照片尺寸: +TP_RESIZE_H;高: +TP_RESIZE_LABEL;è°ƒæ•´å¤§å° +TP_RESIZE_METHOD;æ–¹å¼: +TP_RESIZE_NEAREST;最近点 +TP_RESIZE_SCALE;比例 +TP_RESIZE_W;宽: +TP_ROTATE_AUTOCROP;è‡ªåŠ¨å‰ªè£ +TP_ROTATE_DEGREE;角度 +TP_ROTATE_FILL;å¡«å…… +TP_ROTATE_LABEL;旋转 +TP_ROTATE_SELECTLINE; 选择基准线 +TP_SHADOWSHLIGHTS_HIGHLIGHTS;高光 +TP_SHADOWSHLIGHTS_HLTONALW;影调范围 +TP_SHADOWSHLIGHTS_LABEL;阴影/高光 +TP_SHADOWSHLIGHTS_LOCALCONTR;局部对比度 +TP_SHADOWSHLIGHTS_RADIUS;åŠå¾„ +TP_SHADOWSHLIGHTS_SHADOWS;阴影 +TP_SHADOWSHLIGHTS_SHTONALW;影调范围 +TP_SHARPENING_AMOUNT;程度 +TP_SHARPENING_EDRADIUS;åŠå¾„ +TP_SHARPENING_EDTOLERANCE;边缘容差 +TP_SHARPENING_HALOCONTROL;光晕控制 +TP_SHARPENING_HCAMOUNT;程度 +TP_SHARPENING_LABEL;é”化 +TP_SHARPENING_METHOD;æ–¹å¼ +TP_SHARPENING_ONLYEDGES;ä»…é”化边缘 +TP_SHARPENING_RADIUS;åŠå¾„ +TP_SHARPENING_RLD;ç†æŸ¥æ£®-露西去å·ç§¯æ³• +TP_SHARPENING_RLD_AMOUNT;程度 +TP_SHARPENING_RLD_DAMPING;è¡°å‡ +TP_SHARPENING_RLD_ITERATIONS;迭代 +TP_SHARPENING_THRESHOLD;阈值 +TP_SHARPENING_USM;虚åƒå±è”½ +TP_VIGNETTING_AMOUNT;程度 +TP_VIGNETTING_LABEL;暗角矫正 +TP_VIGNETTING_RADIUS;åŠå¾„ +TP_WBALANCE_AUTO;自动 +TP_WBALANCE_CAMERA;相机 +TP_WBALANCE_CUSTOM;自定义 +TP_WBALANCE_GREEN;色度 +TP_WBALANCE_LABEL;白平衡 +TP_WBALANCE_METHOD;æ–¹å¼ +TP_WBALANCE_SIZE;大å°: +TP_WBALANCE_SPOTWB;白平衡采样 +TP_WBALANCE_TEMPERATURE;色温 +ZOOMBAR_DETAIL;细节 +ZOOMBAR_HUGE;很大 +ZOOMBAR_LARGE;大 +ZOOMBAR_NORMAL;普通 +ZOOMBAR_PREVIEW;预览 +ZOOMBAR_SCALE;比例 +ZOOMBAR_SMALL;å° diff --git a/release/languages/chinese traditional b/release/languages/chinese traditional new file mode 100755 index 000000000..252a41898 --- /dev/null +++ b/release/languages/chinese traditional @@ -0,0 +1,577 @@ +# 29.07.2008 +# Chinese Traditional +# Mingjui Liao +ADJUSTER_RESET_TO_DEFAULT;é‡ç½®é è¨­åƒæ•¸ +CURVEEDITOR_FILEDLGFILTERANY;ä»»æ„æ–‡ä»¶ +CURVEEDITOR_FILEDLGFILTERCURVE;曲線檔 +CURVEEDITOR_LINEAR;線性 +CURVEEDITOR_LOADDLGLABEL;正載入曲線... +CURVEEDITOR_SAVEDLGLABEL;正儲存曲線... +CURVEEDITOR_TOOLTIPLINEAR;é‡ç½®æ›²ç·š +CURVEEDITOR_TOOLTIPLOAD;載入曲線 +CURVEEDITOR_TOOLTIPSAVE;儲存曲線 +EXIFFILTER_APERTURE;Aperture +EXIFFILTER_CAMERA;Camera +EXIFFILTER_DIALOGLABEL;Exif Filter +EXIFFILTER_FOCALLEN;Focal Length +EXIFFILTER_ISO;ISO +EXIFFILTER_LENS;Lens +EXIFFILTER_SHUTTER;Shutter +EXIFPANEL_ADDEDIT;Add/Edit +EXIFPANEL_ADDEDITHINT;Add new tag or edit tag +EXIFPANEL_ADDTAGDLG_ENTERVALUE;Enter value +EXIFPANEL_ADDTAGDLG_SELECTTAG;Select tag +EXIFPANEL_ADDTAGDLG_TITLE;Add/Edit Tag +EXIFPANEL_KEEP;Keep +EXIFPANEL_KEEPHINT;Keep the selected tags when writing output file +EXIFPANEL_REMOVE;Remove +EXIFPANEL_REMOVEHINT;Remove the selected tags when writing output file +EXIFPANEL_RESET;Reset +EXIFPANEL_RESETALL;Reset All +EXIFPANEL_RESETALLHINT;Reset all tags to their original values +EXIFPANEL_RESETHINT;Reset the selected tags to their original values +EXIFPANEL_SUBDIRECTORY;Subdirectory +FILEBROWSER_APPLYPROFILE;Apply profile +FILEBROWSER_ARRANGEMENTHINT;Change between vertical/horizontal alignment of thumbnails +FILEBROWSER_CLEARPROFILE;Clear profile +FILEBROWSER_COPYPROFILE;Copy profile +FILEBROWSER_DELETEDLGLABEL;File delete confirmation +FILEBROWSER_DELETEDLGMSG;Are you sure you want to delete the selected %1 files? +FILEBROWSER_EMPTYTRASH;Empty Trash +FILEBROWSER_EMPTYTRASHHINT;Permanently delete the files of the trash +FILEBROWSER_EXIFFILTERAPPLY;Apply +FILEBROWSER_EXIFFILTERAPPLYHINT;Switch on/off exif filter of the file browser +FILEBROWSER_EXIFFILTERLABEL;Exif Filter +FILEBROWSER_EXIFFILTERSETTINGS;Setup +FILEBROWSER_EXIFFILTERSETTINGSHINT;Change settings of the exif filter +FILEBROWSER_PARTIALPASTEPROFILE;Partial paste +FILEBROWSER_PASTEPROFILE;Paste profile +FILEBROWSER_POPUPCANCELJOB;Cancel job +FILEBROWSER_POPUPMOVEEND;Move to end of queue +FILEBROWSER_POPUPMOVEHEAD;Move to head of queue +FILEBROWSER_POPUPOPEN;Open +FILEBROWSER_POPUPPROCESS;Put to processing queue +FILEBROWSER_POPUPRANK1;Rank 1 +FILEBROWSER_POPUPRANK2;Rank 2 +FILEBROWSER_POPUPRANK3;Rank 3 +FILEBROWSER_POPUPRANK4;Rank 4 +FILEBROWSER_POPUPRANK5;Rank 5 +FILEBROWSER_POPUPREMOVE;Remove from filesystem +FILEBROWSER_POPUPRENAME;Rename +FILEBROWSER_POPUPSELECTALL;Select all +FILEBROWSER_POPUPTRASH;Move to trash +FILEBROWSER_POPUPUNRANK;Unrank +FILEBROWSER_POPUPUNTRASH;Remove from trash +FILEBROWSER_PROCESSINGSETTINGS;Settings +FILEBROWSER_PROCESSINGSETTINGSHINT;Set the file format and output directory +FILEBROWSER_RENAMEDLGLABEL;Rename file +FILEBROWSER_RENAMEDLGMSG;Rename file "%1" to: +FILEBROWSER_SHOWDIRHINT;Show all images of the directory +FILEBROWSER_SHOWQUEUEHINT;Show content of the processing queue +FILEBROWSER_SHOWRANK1HINT;Show images ranked as 1 star +FILEBROWSER_SHOWRANK2HINT;Show images ranked as 2 star +FILEBROWSER_SHOWRANK3HINT;Show images ranked as 3 star +FILEBROWSER_SHOWRANK4HINT;Show images ranked as 4 star +FILEBROWSER_SHOWRANK5HINT;Show images ranked as 5 star +FILEBROWSER_SHOWTRASHHINT;Show content of the trash +FILEBROWSER_SHOWUNRANKHINT;Show unranked images +FILEBROWSER_STARTPROCESSING;Start Processing +FILEBROWSER_STARTPROCESSINGHINT;Start processing/saving of images in the queue +FILEBROWSER_STOPPROCESSING;Stop processing +FILEBROWSER_STOPPROCESSINGHINT;Stop processing of images +FILEBROWSER_THUMBSIZE;Thumb. size +FILEBROWSER_ZOOMINHINT;Increase thumbnail size +FILEBROWSER_ZOOMOUTHINT;Decrease thumbnail size +GENERAL_ABOUT;關於 +GENERAL_CANCEL;å–æ¶ˆ +GENERAL_DISABLE;關閉 +GENERAL_DISABLED;已關閉 +GENERAL_ENABLE;啟用 +GENERAL_ENABLED;已開啟 +GENERAL_LANDSCAPE;æ©«å‘ +GENERAL_LOAD;載入 +GENERAL_NA;ä¸é©ç”¨ +GENERAL_NO;å¦ +GENERAL_OK;確定 +GENERAL_PORTRAIT;ç¸±å‘ +GENERAL_SAVE;儲存存 +GENERAL_YES;是 +HISTOGRAM_LABEL;Histogram +HISTOGRAM_TOOLTIP_B;顯示/éš±è— è—色直方圖 +HISTOGRAM_TOOLTIP_G;顯示/éš±è— ç¶ è‰²ç›´æ–¹åœ– +HISTOGRAM_TOOLTIP_L;顯示/éš±è—e CIELAB 亮度直方圖 +HISTOGRAM_TOOLTIP_R;顯示/éš±è— ç´…è‰²ç›´æ–¹åœ– +HISTORY_CHANGED;Changed +HISTORY_CUSTOMCURVE;自定義曲線 +HISTORY_DELSNAPSHOT;移除快照 +HISTORY_FROMCLIPBOARD;From clipboard +HISTORY_LABEL;æ­·å² +HISTORY_MSG_10;暗部壓縮 +HISTORY_MSG_11;色調曲線 +HISTORY_MSG_12;自動æ›å…‰ +HISTORY_MSG_13;æ›å…‰æº¢å‡º +HISTORY_MSG_14;光強亮度 +HISTORY_MSG_15;光強尿¯”度 +HISTORY_MSG_16;光強黑 +HISTORY_MSG_17;光強亮部壓縮 +HISTORY_MSG_18;光強暗部壓縮 +HISTORY_MSG_19;光強曲線 +HISTORY_MSG_1;圖片載入完 +HISTORY_MSG_20;銳化 +HISTORY_MSG_21;銳化åŠå¾‘ +HISTORY_MSG_22;銳化程度 +HISTORY_MSG_23;銳化闕值 +HISTORY_MSG_24;僅銳化邊緣 +HISTORY_MSG_25;銳化邊緣åŠå¾‘ +HISTORY_MSG_26;銳化邊緣容差 +HISTORY_MSG_27;銳化光暈控制 +HISTORY_MSG_28;å…‰æšˆæŽ§åˆ¶é‡ +HISTORY_MSG_29;éŠ³åŒ–æ–¹å¼ +HISTORY_MSG_2;é…置載入完 +HISTORY_MSG_30;é‡ç–ŠåŠå¾‘ +HISTORY_MSG_31;é‡ç–Šç¨‹åº¦ +HISTORY_MSG_32;é‡ç–Šè¡°æ¸› +HISTORY_MSG_33;é‡ç–Šæ¬¡æ•¸ +HISTORY_MSG_34;é¿å…色彩溢出 +HISTORY_MSG_35;飽和度é™åˆ¶å™¨ +HISTORY_MSG_36;飽和度é™åˆ¶ +HISTORY_MSG_37;色彩增益 +HISTORY_MSG_38;æ‹å¹³è¡¡æ–¹å¼ +HISTORY_MSG_39;色溫 +HISTORY_MSG_3;é…置改變 +HISTORY_MSG_40;白平衡微調 +HISTORY_MSG_41;色彩åç§» "A" +HISTORY_MSG_42;色彩åç§» "B" +HISTORY_MSG_43;光強é™å™ª +HISTORY_MSG_44;光強é™å™ªåŠå¾‘ +HISTORY_MSG_45;光強é™å™ªé‚Šç·£å®¹å·® +HISTORY_MSG_46;色彩é™å™ª +HISTORY_MSG_47;色彩é™å™ªåŠå¾‘ +HISTORY_MSG_48;色彩é™å™ªé‚Šç·£å®¹å·® +HISTORY_MSG_49;色彩é™å™ªé‚Šç·£æ•感度 +HISTORY_MSG_4;æ­·å²æµè¦½ +HISTORY_MSG_50;暗部/亮部工具 +HISTORY_MSG_51;亮部增益 +HISTORY_MSG_52;暗部增益 +HISTORY_MSG_53;äº®éƒ¨è‰²åº¦ç¯„åœ +HISTORY_MSG_54;æš—éƒ¨è‰²åº¦ç¯„åœ +HISTORY_MSG_55;å±€éƒ¨å°æ¯”度 +HISTORY_MSG_56;暗部/亮部åŠå¾‘ +HISTORY_MSG_57;粗略旋轉 +HISTORY_MSG_58;水準翻轉 +HISTORY_MSG_59;豎直翻轉 +HISTORY_MSG_5;亮度 +HISTORY_MSG_60;旋轉 +HISTORY_MSG_61;旋轉 +HISTORY_MSG_62;é¡é ­å¤±çœŸçŸ¯æ­£ +HISTORY_MSG_63;設置書簽 +HISTORY_MSG_64;剪切圖片 +HISTORY_MSG_65;C/A矯正 +HISTORY_MSG_66;高光還原 +HISTORY_MSG_67;高光還原程度 +HISTORY_MSG_68;é«˜å…‰é‚„åŽŸæ–¹å¼ +HISTORY_MSG_69;工作色彩空間 +HISTORY_MSG_6;å°æ¯”度 +HISTORY_MSG_70;輸出色彩空間 +HISTORY_MSG_71;輸入色åƒç©ºé–“ +HISTORY_MSG_72;邊暈矯正 +HISTORY_MSG_73;é€šé“æ··åˆå™¨ +HISTORY_MSG_74;èª¿æ•´å¤§å°æ¯”例 +HISTORY_MSG_75;èª¿æ•´å¤§å°æ–¹å¼ +HISTORY_MSG_76;Exif Metadata +HISTORY_MSG_77;IPTC Metadata +HISTORY_MSG_7;黑 +HISTORY_MSG_8;æ›å…‰è£œå„Ÿ +HISTORY_MSG_9;亮部壓縮 +HISTORY_NEWSNAPSHOT;新建快照 +HISTORY_NEWSNAPSHOTAS;為... +HISTORY_NEWSSDIALOGLABEL;快照標籤: +HISTORY_NEWSSDIALOGTITLE;添加新快照 +HISTORY_SETTO;設置為 +HISTORY_SNAPSHOT;å¿«ç…§ +HISTORY_SNAPSHOTS;系列快照 +ICMPANEL_FILEDLGFILTERANY;ä»»æ„æ–‡ä»¶ +ICMPANEL_FILEDLGFILTERICM;ICCé…置檔 +ICMPANEL_GAMMABEFOREINPUT;Profile applies Gamma +ICMPANEL_INPUTCAMERA;相機é è¨­ +ICMPANEL_INPUTCUSTOM;自定義 +ICMPANEL_INPUTDLGLABEL;鏿“‡è¼¸å…¥ICCé…ç½®... +ICMPANEL_INPUTEMBEDDED;如å¯èƒ½ï¼Œä½¿ç”¨å…§ç½® +ICMPANEL_INPUTPROFILE;輸入é…ç½® +ICMPANEL_NOICM;No ICM: sRGBé…ç½® +ICMPANEL_OUTPUTDLGLABEL;鏿“‡è¼¸å‡ºICCé…ç½®... +ICMPANEL_OUTPUTPROFILE;輸出é…ç½® +ICMPANEL_SAVEREFERENCE;Save reference image for profiling +ICMPANEL_WORKINGPROFILE;ç•¶å‰é…ç½® +IMAGEAREA_DETAILVIEW;細節視圖 +IPTCPANEL_AUTHOR;Author +IPTCPANEL_AUTHORHINT;Name of the creator of the object, e.g. writer, photographer or graphic artist (By-line). +IPTCPANEL_AUTHORSPOSITION;Author's position +IPTCPANEL_AUTHORSPOSITIONHINT;Title of the creator or creators of the object (By-line Title). +IPTCPANEL_CAPTION;Caption +IPTCPANEL_CAPTIONHINT;A textual description of the data (Caption - Abstract) +IPTCPANEL_CAPTIONWRITER;Caption Writer +IPTCPANEL_CAPTIONWRITERHINT;The name of the person involved in the writing, editing or correcting the image or caption/abstract (Writer - Editor +IPTCPANEL_CATEGORY;Category +IPTCPANEL_CATEGORYHINT;Identifies the subject of the image in the opinion of the provider (Category). +IPTCPANEL_CITY;City +IPTCPANEL_CITYHINT;City of image origin (City). +IPTCPANEL_COPYHINT;Copy IPTC settings to clipboard +IPTCPANEL_COPYRIGHT;Copyright +IPTCPANEL_COPYRIGHTHINT;Any necessary copyright notice (Copyright Notice). +IPTCPANEL_COUNTRY;Country +IPTCPANEL_COUNTRYHINT;The name of the country/primary location where the image was created (Country - Primary Location Name). +IPTCPANEL_CREDIT;Credit +IPTCPANEL_CREDITHINT;Identifies the provider of the image, not necessarily the owner/creator (Credit). +IPTCPANEL_DATECREATED;Date Created +IPTCPANEL_DATECREATEDHINT;The date the intellectual content of the image was created; Format: JJJJMMTT (Date Created). +IPTCPANEL_EMBEDDED;Embedded +IPTCPANEL_EMBEDDEDHINT;Reset to IPTC data embedded in the image file +IPTCPANEL_HEADLINE;Headline +IPTCPANEL_HEADLINEHINT;A publishable entry providing a synopsis of the contents of the image (Headline). +IPTCPANEL_INSTRUCTIONS;Instructions +IPTCPANEL_INSTRUCTIONSHINT;Other editorial instructions concerning the use of the image (Special Instructions). +IPTCPANEL_KEYWORDS;Keywords +IPTCPANEL_KEYWORDSHINT;Used to indicate specific information retrieval words (keywords). +IPTCPANEL_PASTEHINT;Paste IPTC settings from clipboard +IPTCPANEL_PROVINCE;Province +IPTCPANEL_PROVINCEHINT;The Province/State where the image originates (Province-State). +IPTCPANEL_RESET;Reset +IPTCPANEL_RESETHINT;Reset to profile default +IPTCPANEL_SOURCE;Source +IPTCPANEL_SOURCEHINT;The original owner of the intellectual content of the image (Source). +IPTCPANEL_SUPPCATEGORIES;Suppl. Categories +IPTCPANEL_SUPPCATEGORIESHINT;Further refines the subject of the image (Supplemental Categories). +IPTCPANEL_TITLE;Title +IPTCPANEL_TITLEHINT;A shorthand reference for the image (Object Name). +IPTCPANEL_TRANSREFERENCE;Trans. Reference +IPTCPANEL_TRANSREFERENCEHINT;A code representing the location of original transmission (Original Transmission Reference). +MAIN_BUTTON_PREFERENCES;åƒæ•¸è¨­ç½® +MAIN_BUTTON_SAVE;儲存圖片 +MAIN_BUTTON_SAVEAS;為... +MAIN_BUTTON_SENDTOEDITOR;Send to editor +MAIN_MSG_ALREADYEXISTS;該文件已存在. +MAIN_MSG_CANNOTLOAD;無法載入圖片 +MAIN_MSG_CANNOTSAVE;檔儲存中出錯 +MAIN_MSG_CANNOTSTARTEDITOR;Can not start editor. +MAIN_MSG_CANNOTSTARTEDITOR_SECONDARY;Please set the correct path in the "Preferences" dialog. +MAIN_MSG_EXITJOBSINQUEUEINFO;Unprocessed images in the queue will be lost on exit. +MAIN_MSG_EXITJOBSINQUEUEQUEST;Are you sure you want to exit? There are unprocessed images waiting in the queue. +MAIN_MSG_JOBSINQUEUE;任務列隊中 +MAIN_MSG_QOVERWRITE;是å¦è¦†è“‹? +MAIN_TAB_BASIC;基本 +MAIN_TAB_COLOR;Color +MAIN_TAB_DETAIL;Detail +MAIN_TAB_EXIF;Exif +MAIN_TAB_EXPOSURE;Exposure +MAIN_TAB_ICM;ICM +MAIN_TAB_IPTC;IPTC +MAIN_TAB_METADATA;Metadata +MAIN_TAB_TRANSFORM;è½‰æ› +MAIN_TOOLTIP_HIDEFP;顯示/éš±è—åº•éƒ¨é¢æ¿ (目錄和檔æµè¦½å™¨, shortcut key: F) +MAIN_TOOLTIP_HIDEHP;顯示/éš±è—左颿¿ (åŒ…å«æ­·å², shortcut key: H)) +MAIN_TOOLTIP_INDCLIPPEDH;高光溢出æç¤º +MAIN_TOOLTIP_INDCLIPPEDS;暗部ä¸è¶³æç¤º +MAIN_TOOLTIP_PREFERENCES;è¨­ç½®åƒæ•¸ +MAIN_TOOLTIP_QINFO;圖片快æ·è³‡è¨Š +MAIN_TOOLTIP_SAVE;圖片存於é è¨­æª”夾 +MAIN_TOOLTIP_SAVEAS;圖片存於指定檔夾 +PARTIALPASTE_BASICGROUP;Basic settings +PARTIALPASTE_CACORRECTION;C/A correction +PARTIALPASTE_COARSETRANS;90 deg rotation / flipping +PARTIALPASTE_COLORBOOST;Color boost +PARTIALPASTE_COLORDENOISE;Color denoise +PARTIALPASTE_COLORGROUP;Color related settings +PARTIALPASTE_COLORMIXER;Color mixer +PARTIALPASTE_COLORSHIFT;Color shift +PARTIALPASTE_COMPOSITIONGROUP;Composition settings +PARTIALPASTE_CROP;Crop +PARTIALPASTE_DIALOGLABEL;Partial paste processing profile +PARTIALPASTE_DISTORTION;Distortion correction +PARTIALPASTE_EXIFCHANGES;Changes to exif data +PARTIALPASTE_EXPOSURE;Exposure +PARTIALPASTE_HLRECOVERY;Highlight recovery +PARTIALPASTE_ICMSETTINGS;ICM settings +PARTIALPASTE_IPTCINFO;IPTC info +PARTIALPASTE_LENSGROUP;Lens related settings +PARTIALPASTE_LUMACURVE;Luminance curve +PARTIALPASTE_LUMADENOISE;Luminance noise reduction +PARTIALPASTE_LUMINANCEGROUP;Luminance related settings +PARTIALPASTE_METAICMGROUP;Metadata/ICM settings +PARTIALPASTE_RESIZE;Resize +PARTIALPASTE_ROTATION;Rotation +PARTIALPASTE_SHADOWSHIGHLIGHTS;Shadows/Highlights +PARTIALPASTE_SHARPENING;Sharpening +PARTIALPASTE_VIGNETTING;Vignetting correction +PARTIALPASTE_WHITEBALANCE;White balance +PREFERENCES_APPLNEXTSTARTUP;下次啟動生效 +PREFERENCES_BLINKCLIPPED;高光å€åŸŸé–ƒçˆ +PREFERENCES_CACHECLEARALL;Clear All +PREFERENCES_CACHECLEARPROFILES;Clear Profiles +PREFERENCES_CACHECLEARTHUMBS;Clear Thumbnails +PREFERENCES_CACHEFORMAT1;Proprietary (faster and better quality) +PREFERENCES_CACHEFORMAT2;JPEG (smaller disk footprint) +PREFERENCES_CACHEMAXENTRIES;Maximal Number of Cache Entries +PREFERENCES_CACHEOPTS;Cache Options +PREFERENCES_CACHESTRAT1;Prefer Speed to Low Memory Consumption +PREFERENCES_CACHESTRAT2;Prefer Low Memory Consumption to Speed +PREFERENCES_CACHESTRAT;Cache Strategy +PREFERENCES_CACHETHUMBFORM;Cache Thumbnail Format +PREFERENCES_CACHETHUMBHEIGHT;Maximal Thumbnail Height +PREFERENCES_CLEARDLG_LINE1;Clearing cache +PREFERENCES_CLEARDLG_LINE2;This may take a few seconds. +PREFERENCES_CLEARDLG_TITLE;Please wait +PREFERENCES_CLIPPINGIND;高光æç¤º +PREFERENCES_CMETRICINTENT;è‰²å½©æ¨¡å¼ +PREFERENCES_DATEFORMAT;æ—¥æœŸæ ¼å¼ +PREFERENCES_DATEFORMATHINT;You can use the following formatting strings:\n%y : year\n%m : month\n%d : day\n\nFor example, the hungarian date format is:\n%y/%m/%d +PREFERENCES_DEFAULTLANG;é è¨­èªžè¨€ +PREFERENCES_DEFAULTTHEME;Default theme +PREFERENCES_DEMOSAICINGALGO;解拼演算法 +PREFERENCES_DIRHOME;用戶檔路徑 +PREFERENCES_DIRLAST;上次訪å•路徑 +PREFERENCES_DIROTHER;å…¶ä»– +PREFERENCES_DIRSELECTDLG;å•Ÿå‹•æ™‚é¸æ“‡åœ–片路徑... +PREFERENCES_DIRSOFTWARE;軟體安è£è·¯å¾‘ +PREFERENCES_DMETHOD;æ–¹å¼ +PREFERENCES_EDITORCMDLINE;Other command line +PREFERENCES_EXTERNALEDITOR;External editor +PREFERENCES_FALSECOLOR;è™›å‡è‰²å½©å£“縮步驟 +PREFERENCES_FBROWSEROPTS;檔æµè¦½é¸é … +PREFERENCES_FILEFORMAT;æª”æ ¼å¼ +PREFERENCES_FORIMAGE;用於圖片檔 +PREFERENCES_FORRAW;用於Raw文件 +PREFERENCES_GIMPPATH;GIMP installation directory +PREFERENCES_GTKTHEME;GTK default +PREFERENCES_HINT;æç¤º +PREFERENCES_HLTHRESHOLD;高光溢出闕值 +PREFERENCES_ICCDIR;ICCé…置路徑 +PREFERENCES_IMPROCPARAMS;é è¨­åœ–片處ç†åƒæ•¸ +PREFERENCES_INTENT_ABSOLUTE;絕å°è‰²å½©æ¨¡å¼ +PREFERENCES_INTENT_PERCEPTUAL;æ„ŸçŸ¥æ¨¡å¼ +PREFERENCES_INTENT_RELATIVE;相å°è‰²å½©æ¨¡å¼ +PREFERENCES_INTENT_SATURATION;飽和度 +PREFERENCES_LIVETHUMBNAILS;Live Thumbnails (slower) +PREFERENCES_MONITORICC;顯示器é…ç½® +PREFERENCES_OUTDIR;輸出路徑 +PREFERENCES_OUTDIRFOLDER;Save to folder +PREFERENCES_OUTDIRFOLDERHINT;Put the saved images to the seledted folder +PREFERENCES_OUTDIRHINT;You can use the following formatting strings:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nThese formatting strings refer to the directories and sub-paths of the path of the raw file.\n\nFor example, if /home/tom/image/02-09-2006/dsc0012.nefhas been opened, the meaning of the formatting strings are:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nIf you want to save the output image where the original is, write:\n%p1/%f\n\nIf you want to save the output image in a directory 'converted' located the directory of the original, write:\n%p1/converted/%f\n\nIf you want to save the output image in directory '/home/tom/converted' with keeping the same subdirectory of dates, write:\n%p2/converted/%d1/%f +PREFERENCES_OUTDIRTEMPLATE;Use Template +PREFERENCES_OUTDIRTEMPLATEHINT;You can use the following formatting strings:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nThese formatting strings refer to the directories and sub-paths of the path of the raw file.\n\nFor example, if /home/tom/image/02-09-2006/dsc0012.nefhas been opened, the meaning of the formatting strings are:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nIf you want to save the output image where the original is, write:\n%p1/%f\n\nIf you want to save the output image in a directory 'converted' located the directory of the original, write:\n%p1/converted/%f\n\nIf you want to save the output image in directory '/home/tom/converted' with keeping the same subdirectory of dates, write:\n%p2/converted/%d1/%f +PREFERENCES_PARSEDEXT;Parsed Extensions +PREFERENCES_PARSEDEXTADD;Add Extension +PREFERENCES_PARSEDEXTADDHINT;Type an extension and press this button to append list +PREFERENCES_PARSEDEXTDELHINT;Delete selected extension from the list +PREFERENCES_PROFILEHANDLING;Processing Profile Handling +PREFERENCES_PROFILELOADPR;Profile Loading Priority +PREFERENCES_PROFILEPRCACHE;Profile in Cache +PREFERENCES_PROFILEPRFILE;Profile Next to the Input File +PREFERENCES_PROFILESAVECACHE;Save Processing Parameters to the Cache +PREFERENCES_PROFILESAVEINPUT;Save Processing Parameters Next to the Input File +PREFERENCES_PSPATH;Adobe Photoshop installation directory +PREFERENCES_SELECTICCDIRDLG;鏿“‡ICC路徑... +PREFERENCES_SELECTLANG;鏿“‡èªžè¨€ +PREFERENCES_SELECTMONITORPROFDLG;鏿“‡é¡¯ç¤ºå™¨ICC路徑... +PREFERENCES_SELECTTHEME;Select theme +PREFERENCES_SHOWBASICEXIF;顯示基本Exif資訊 +PREFERENCES_SHOWDATETIME;顯示時間日期 +PREFERENCES_SHOWONLYRAW;僅顯示Raw檔 +PREFERENCES_SHTHRESHOLD;暗部ä¸è¶³é—•值 +PREFERENCES_STARTUPIMDIR;啟動時路徑 +PREFERENCES_TAB_BROWSER;檔æµè¦½å™¨ +PREFERENCES_TAB_COLORMGR;è‰²å½©ç®¡ç† +PREFERENCES_TAB_GENERAL;一般 +PREFERENCES_TAB_IMPROC;åœ–ç‰‡è™•ç† +PREFERENCES_TAB_OUTPUT;輸出é¸é … +PREFERENCES_THUMBSIZE;ç¸®ç•¥åœ–å¤§å° +PROFILEPANEL_FILEDLGFILTERANY;ä»»æ„æ–‡ä»¶ +PROFILEPANEL_FILEDLGFILTERPP;處ç†åƒæ•¸é…ç½® +PROFILEPANEL_LABEL;處ç†åƒæ•¸é…ç½® +PROFILEPANEL_LOADDLGLABEL;載入處ç†åƒæ•¸ç‚º... +PROFILEPANEL_PCUSTOM;自定義 +PROFILEPANEL_PFILE;由文件 +PROFILEPANEL_PLASTPHOTO;上次圖片 +PROFILEPANEL_PLASTSAVED;上次儲存 +PROFILEPANEL_PROFILE;é…ç½® +PROFILEPANEL_SAVEDLGLABEL;儲存處ç†åƒæ•¸ç‚º... +PROFILEPANEL_TOOLTIPCOPY;Copy current profile to clipboard +PROFILEPANEL_TOOLTIPLOAD;由檔載入é…ç½® +PROFILEPANEL_TOOLTIPPASTE; Paste profile from clipboard +PROFILEPANEL_TOOLTIPSAVE;儲存當å‰é…ç½® +PROGRESSBAR_DECODING;Raw檔解碼中... +PROGRESSBAR_DEMOSAICING;Raw檔解拼中... +PROGRESSBAR_LOADING;圖片載入中... +PROGRESSBAR_LOADJPEG;JPEG載入中... +PROGRESSBAR_LOADPNG;PNG載入中... +PROGRESSBAR_LOADTIFF;TIFF載入中... +PROGRESSBAR_PROCESSING;圖片處ç†ä¸­... +PROGRESSBAR_READY;就緒. +PROGRESSBAR_SAVEJPEG;JPEG儲存中... +PROGRESSBAR_SAVEPNG;PNG儲存中... +PROGRESSBAR_SAVETIFF;TIFF儲存中... +PROGRESSDLG_LOADING;Loading file... +PROGRESSDLG_PROCESSING;Processing image... +PROGRESSDLG_SAVING;Saving file... +QINFO_FOCALLENGTH;ç„¦è· +QINFO_ISO;ISO +QINFO_LENS;Lens +QINFO_NOEXIF;Exif資料ä¸å¯ç”¨. +SAVEDLG_FILEFORMAT;æª”æ ¼å¼ +SAVEDLG_JPEGQUAL;JPEGå“質 +SAVEDLG_JPGFILTER;JPEG文件 +SAVEDLG_PNGCOMPR;PNG壓縮 +SAVEDLG_PNGFILTER;PNG文件 +SAVEDLG_PUTTOQUEUE;Put into processing queue +SAVEDLG_PUTTOQUEUEHEAD;Put to the head of the processing queue +SAVEDLG_PUTTOQUEUETAIL;Put to the end of the processing queue +SAVEDLG_SAVEIMMEDIATELY;Save immediately +SAVEDLG_SAVESPP;隨圖片儲存處ç†åƒæ•¸ +SAVEDLG_TIFFFILTER;TIFF文件 +TOOLBAR_TOOLTIP_CROP;剪è£é¸æ“‡ (shortcut key: C) +TOOLBAR_TOOLTIP_HAND;手形工具 (shortcut key: N) +TOOLBAR_TOOLTIP_STRAIGHTEN;åŸºæº–ç·šé¸æ“‡ (shortcut key: S) +TOOLBAR_TOOLTIP_WB;白平衡點 (shortcut key: W) +TP_CACORRECTION_BLUE;è— +TP_CACORRECTION_LABEL;C/A 矯正 +TP_CACORRECTION_RED;ç´… +TP_CHMIXER_BLUE;è— +TP_CHMIXER_GREEN;ç¶  +TP_CHMIXER_LABEL;é€šé“æ··åˆ +TP_CHMIXER_RED;ç´… +TP_COARSETRAF_DEGREE;角度: +TP_COARSETRAF_TOOLTIP_HFLIP;水準翻轉 +TP_COARSETRAF_TOOLTIP_ROTLEFT;左轉 +TP_COARSETRAF_TOOLTIP_ROTRIGHT;å³è½‰ +TP_COARSETRAF_TOOLTIP_VFLIP;豎直翻轉 +TP_COLORBOOST_ACHANNEL;é€šé“ "a" +TP_COLORBOOST_AMOUNT;程度 +TP_COLORBOOST_AVOIDCOLORCLIP;é¿å…色彩溢出 +TP_COLORBOOST_BCHANNEL;é€šé“ "b" +TP_COLORBOOST_CHAB;a å’Œ b +TP_COLORBOOST_CHANNEL;é€šé“ +TP_COLORBOOST_CHSEPARATE;分解 +TP_COLORBOOST_ENABLESATLIMITER;啟用飽和度é™åˆ¶ +TP_COLORBOOST_LABEL;色彩增益 +TP_COLORBOOST_SATLIMIT;飽和度é™åˆ¶ +TP_COLORDENOISE_EDGESENSITIVE;é‚Šç·£æ•æ„Ÿåº¦ +TP_COLORDENOISE_EDGETOLERANCE;邊緣容差 +TP_COLORDENOISE_LABEL;色彩噪點抑制 +TP_COLORDENOISE_RADIUS;åŠå¾‘ +TP_COLORSHIFT_BLUEYELLOW;è—-黃 +TP_COLORSHIFT_GREENMAGENTA;ç¶ -æ´‹ç´… +TP_COLORSHIFT_LABEL;色彩åç§» +TP_CROP_DPI;DPI= +TP_CROP_FIXRATIO;比例: +TP_CROP_GTDIAGONALS;å°è§’線法則 +TP_CROP_GTHARMMEANS1;黃金點 1 +TP_CROP_GTHARMMEANS2;黃金點 2 +TP_CROP_GTHARMMEANS3;黃金點 3 +TP_CROP_GTHARMMEANS4;黃金點 4 +TP_CROP_GTNONE;ç„¡ +TP_CROP_GTRULETHIRDS;1/3法則 +TP_CROP_GUIDETYPE;輔助方å¼: +TP_CROP_H;高 +TP_CROP_LABEL;å‰ªè£ +TP_CROP_SELECTCROP; 鏿“‡é è¨­ +TP_CROP_W;寬 +TP_CROP_X;x +TP_CROP_Y;y +TP_DISTORTION_AMOUNT;程度 +TP_DISTORTION_LABEL;ç•«é¢æ­ªæ›²åƒå·® +TP_EXPOSURE_AUTOLEVELS;自動色階 +TP_EXPOSURE_BLACKLEVEL;黑 +TP_EXPOSURE_BRIGHTNESS;亮度 +TP_EXPOSURE_CLIP;高光 +TP_EXPOSURE_COMPRHIGHLIGHTS;亮部壓縮 +TP_EXPOSURE_COMPRSHADOWS;暗部壓縮 +TP_EXPOSURE_CONTRAST;å°æ¯”度 +TP_EXPOSURE_CURVEEDITOR;色調曲線 +TP_EXPOSURE_EXPCOMP;æ›å…‰è£œå„Ÿ +TP_EXPOSURE_LABEL;æ›å…‰ +TP_HLREC_CIELAB;CIELab Blending +TP_HLREC_COLOR;色彩延伸 +TP_HLREC_LABEL;高光挽回 +TP_HLREC_LUMINANCE;亮度挽回 +TP_HLREC_METHOD;æ–¹å¼: +TP_ICM_FILEDLGFILTERANY;ä»»æ„æ–‡ä»¶ +TP_ICM_FILEDLGFILTERICM;ICCé…置檔 +TP_ICM_GAMMABEFOREINPUT;Profile applies Gamma +TP_ICM_INPUTCAMERA;相機é è¨­ +TP_ICM_INPUTCUSTOM;自定義 +TP_ICM_INPUTDLGLABEL;鏿“‡è¼¸å…¥ICCé…ç½®... +TP_ICM_INPUTEMBEDDED;如å¯èƒ½ï¼Œä½¿ç”¨å…§ç½® +TP_ICM_INPUTPROFILE;輸入é…ç½® +TP_ICM_LABEL;ICM +TP_ICM_NOICM;No ICM: sRGBé…ç½® +TP_ICM_OUTPUTDLGLABEL;鏿“‡è¼¸å‡ºICCé…ç½®... +TP_ICM_OUTPUTPROFILE;輸出é…ç½® +TP_ICM_SAVEREFERENCE;Save reference image for profiling +TP_ICM_WORKINGPROFILE;ç•¶å‰é…ç½® +TP_LUMACURVE_BLACKLEVEL;黑 +TP_LUMACURVE_BRIGHTNESS;亮度 +TP_LUMACURVE_COMPRHIGHLIGHTS;亮部壓縮 +TP_LUMACURVE_COMPRSHADOWS;暗部壓縮 +TP_LUMACURVE_CONTRAST;å°æ¯”度 +TP_LUMACURVE_CURVEEDITOR;亮度曲線 +TP_LUMACURVE_LABEL;亮度曲線 +TP_LUMADENOISE_EDGETOLERANCE;邊緣容差 +TP_LUMADENOISE_LABEL;亮度噪點抑制 +TP_LUMADENOISE_RADIUS;åŠå¾‘ +TP_RESIZE_BICUBIC;雙三次 +TP_RESIZE_BICUBICSF;雙三次 (柔化) +TP_RESIZE_BICUBICSH;雙三次 (銳化) +TP_RESIZE_BILINEAR;雙線性 +TP_RESIZE_FULLSIZE;全照片尺寸: +TP_RESIZE_H;高: +TP_RESIZE_LABEL;èª¿æ•´å¤§å° +TP_RESIZE_METHOD;æ–¹å¼: +TP_RESIZE_NEAREST;最近點 +TP_RESIZE_SCALE;比例 +TP_RESIZE_W;寬: +TP_ROTATE_AUTOCROP;è‡ªå‹•å‰ªè£ +TP_ROTATE_DEGREE;角度 +TP_ROTATE_FILL;å¡«å…… +TP_ROTATE_LABEL;旋轉 +TP_ROTATE_SELECTLINE; 鏿“‡åŸºæº–ç·š +TP_SHADOWSHLIGHTS_HIGHLIGHTS;亮部 +TP_SHADOWSHLIGHTS_HLTONALW;è‰²èª¿ç¯„åœ +TP_SHADOWSHLIGHTS_LABEL;暗部/亮部 +TP_SHADOWSHLIGHTS_LOCALCONTR;å±€éƒ¨å°æ¯”度 +TP_SHADOWSHLIGHTS_RADIUS;åŠå¾‘ +TP_SHADOWSHLIGHTS_SHADOWS;é™°å½± +TP_SHADOWSHLIGHTS_SHTONALW;è‰²èª¿ç¯„åœ +TP_SHARPENING_AMOUNT;程度 +TP_SHARPENING_EDRADIUS;åŠå¾‘ +TP_SHARPENING_EDTOLERANCE;邊緣容差 +TP_SHARPENING_HALOCONTROL;光暈控制 +TP_SHARPENING_HCAMOUNT;程度 +TP_SHARPENING_LABEL;銳化 +TP_SHARPENING_METHOD;æ–¹å¼ +TP_SHARPENING_ONLYEDGES;僅銳化邊緣 +TP_SHARPENING_RADIUS;åŠå¾‘ +TP_SHARPENING_RLD;å·¦å³é‡ç–Š +TP_SHARPENING_RLD_AMOUNT;程度 +TP_SHARPENING_RLD_DAMPING;衰減 +TP_SHARPENING_RLD_ITERATIONS;迭代 +TP_SHARPENING_THRESHOLD;闕值 +TP_SHARPENING_USM;銳化 +TP_VIGNETTING_AMOUNT;程度 +TP_VIGNETTING_LABEL;邊暈矯正 +TP_VIGNETTING_RADIUS;åŠå¾‘ +TP_WBALANCE_AUTO;自動 +TP_WBALANCE_CAMERA;相機 +TP_WBALANCE_CUSTOM;自定義 +TP_WBALANCE_GREEN;色度 +TP_WBALANCE_LABEL;白平衡 +TP_WBALANCE_METHOD;æ–¹å¼ +TP_WBALANCE_SIZE;大å°: +TP_WBALANCE_SPOTWB;WB點 +TP_WBALANCE_TEMPERATURE;色溫 +ZOOMBAR_DETAIL;細節 +ZOOMBAR_HUGE;很大 +ZOOMBAR_LARGE;大 +ZOOMBAR_NORMAL;普通 +ZOOMBAR_PREVIEW;é è¦½ +ZOOMBAR_SCALE;比例 +ZOOMBAR_SMALL;å° diff --git a/release/languages/czech b/release/languages/czech new file mode 100755 index 000000000..78a2500b2 --- /dev/null +++ b/release/languages/czech @@ -0,0 +1,581 @@ +# czech +# ---------------------------------------- +# 20.1.2008: translated by absolution +# 21.2.2008: updated by mkyral (typos and some missing strings) +# 24.4.2008: updated by mkyral (for version 2.4m1) +# 28.10.2008: updated by mkyral (for version 2.4 beta1) +# +ADJUSTER_RESET_TO_DEFAULT;Vrátit se k původnímu +CURVEEDITOR_FILEDLGFILTERANY;Jakékoliv soubory +CURVEEDITOR_FILEDLGFILTERCURVE;Soubory kÅ™ivek +CURVEEDITOR_LINEAR;Lineární +CURVEEDITOR_LOADDLGLABEL;NaÄíst kÅ™ivku... +CURVEEDITOR_SAVEDLGLABEL;Uložit kÅ™ivku... +CURVEEDITOR_TOOLTIPLINEAR;Vrátit se k lineární kÅ™ivce +CURVEEDITOR_TOOLTIPLOAD;NaÄíst kÅ™ivku ze souboru +CURVEEDITOR_TOOLTIPSAVE;Uložit souÄasnou kÅ™ivku +EXIFFILTER_APERTURE;Clona +EXIFFILTER_CAMERA;Aparát +EXIFFILTER_DIALOGLABEL;Filtruj dle Exif +EXIFFILTER_FOCALLEN;Ohnisková vzdálenost +EXIFFILTER_ISO;ISO +EXIFFILTER_LENS;Objektiv +EXIFFILTER_SHUTTER;Rychlost závÄ›rky +EXIFPANEL_ADDEDIT;PÅ™idej/Změň +EXIFPANEL_ADDEDITHINT;PÅ™idej/Oprav Å¡títek +EXIFPANEL_ADDTAGDLG_ENTERVALUE;Vlož hodnotu +EXIFPANEL_ADDTAGDLG_SELECTTAG;Vyber Å¡títek +EXIFPANEL_ADDTAGDLG_TITLE;PÅ™idej/Změň Å¡títek +EXIFPANEL_KEEP;Zachovej +EXIFPANEL_KEEPHINT;Ulož vybrané Å¡títky pÅ™i zápisu do souboru +EXIFPANEL_REMOVE;ZahoÄ +EXIFPANEL_REMOVEHINT;Neulož vybrané Å¡títky pÅ™i zápisu do souboru +EXIFPANEL_RESET;Obnov +EXIFPANEL_RESETALL;Obnov vÅ¡e +EXIFPANEL_RESETALLHINT;Obnov původní hodnoty u vÅ¡ech Å¡títků +EXIFPANEL_RESETHINT;Obnov původní hodnoty u vybraných Å¡títků +EXIFPANEL_SUBDIRECTORY;Podadresář +FILEBROWSER_APPLYPROFILE;Aplikuj profil +FILEBROWSER_ARRANGEMENTHINT;PÅ™epnutí mezi vertikálním/horizontálním zarovnáním náhledů +FILEBROWSER_CLEARPROFILE;Vymaž profil +FILEBROWSER_COPYPROFILE;Kopíruj profil +FILEBROWSER_DELETEDLGLABEL;Potvrzení smazání souboru +FILEBROWSER_DELETEDLGMSG;Opravdu chcete vymazat %1 souborů? +FILEBROWSER_EMPTYTRASH;Vysypat koÅ¡ +FILEBROWSER_EMPTYTRASHHINT;Navždy vymaže soubory v koÅ¡i +FILEBROWSER_EXIFFILTERAPPLY;Použij +FILEBROWSER_EXIFFILTERAPPLYHINT;Zapne/Vypne filtrování dle exif v prohlížeÄi souborů +FILEBROWSER_EXIFFILTERLABEL;Exif Filtr +FILEBROWSER_EXIFFILTERSETTINGS;Nastavení +FILEBROWSER_EXIFFILTERSETTINGSHINT;ZmÄ›na nastavení exif filtru +FILEBROWSER_PARTIALPASTEPROFILE;Vlož ÄásteÄnÄ› +FILEBROWSER_PASTEPROFILE;Vlož profil +FILEBROWSER_POPUPCANCELJOB;ZruÅ¡ úlohu +FILEBROWSER_POPUPMOVEEND;PÅ™esuň na konec fronty +FILEBROWSER_POPUPMOVEHEAD;PÅ™esuň na zaÄátek fronty +FILEBROWSER_POPUPOPEN;OtevÅ™i +FILEBROWSER_POPUPPROCESS;Vlož do fronty +FILEBROWSER_POPUPRANK1;Hodnocení 1 +FILEBROWSER_POPUPRANK2;Hodnocení 2 +FILEBROWSER_POPUPRANK3;Hodnocení 3 +FILEBROWSER_POPUPRANK4;Hodnocení 4 +FILEBROWSER_POPUPRANK5;Hodnocení 5 +FILEBROWSER_POPUPREMOVE;Odstraň ze systému souborů +FILEBROWSER_POPUPRENAME;PÅ™ejmenuj +FILEBROWSER_POPUPSELECTALL;Vyber vÅ¡e +FILEBROWSER_POPUPTRASH;PÅ™esuň do koÅ¡e +FILEBROWSER_POPUPUNRANK;Odstraň hodnocení +FILEBROWSER_POPUPUNTRASH;Vymaž z koÅ¡e +FILEBROWSER_PROCESSINGSETTINGS;Nastavení +FILEBROWSER_PROCESSINGSETTINGSHINT;Nastavení formátu souboru a výstupního adresáře +FILEBROWSER_RENAMEDLGLABEL;PÅ™ejmenování souboru +FILEBROWSER_RENAMEDLGMSG;PÅ™ejmenovat soubor "%1" na: +FILEBROWSER_SHOWDIRHINT;Ukaž vÅ¡echny obrázky v adresáři +FILEBROWSER_SHOWQUEUEHINT;Ukaž obsah fronty +FILEBROWSER_SHOWRANK1HINT;Ukaž obrázky hodnocené 1 hvÄ›zdiÄkou +FILEBROWSER_SHOWRANK2HINT;Ukaž obrázky hodnocené 2 hvÄ›zdiÄkama +FILEBROWSER_SHOWRANK3HINT;Ukaž obrázky hodnocené 3 hvÄ›zdiÄkama +FILEBROWSER_SHOWRANK4HINT;Ukaž obrázky hodnocené 4 hvÄ›zdiÄkama +FILEBROWSER_SHOWRANK5HINT;Ukaž obrázky hodnocené 5 hvÄ›zdiÄkama +FILEBROWSER_SHOWTRASHHINT;Ukaž obsah koÅ¡e +FILEBROWSER_SHOWUNRANKHINT;Ukaž nehodnocené obrázky +FILEBROWSER_STARTPROCESSING;SpusÅ¥ zpracování +FILEBROWSER_STARTPROCESSINGHINT;Spustí zpracování nebo ukládání obrázků ve frontÄ› +FILEBROWSER_STOPPROCESSING;Zastav zpracovávaní +FILEBROWSER_STOPPROCESSINGHINT;Zastaví zpracovávaní obrázků +FILEBROWSER_THUMBSIZE;Velikost náhledů +FILEBROWSER_ZOOMINHINT;ZvÄ›tší velikost náhledů +FILEBROWSER_ZOOMOUTHINT;Zmenší velikost náhledů +GENERAL_ABOUT;O programu +GENERAL_CANCEL;Storno +GENERAL_DISABLE;Vypnout +GENERAL_DISABLED;Vypnuto +GENERAL_ENABLE;Zapnout +GENERAL_ENABLED;Zapnuto +GENERAL_LANDSCAPE;Na šířku +GENERAL_LOAD;NaÄíst +GENERAL_NA;n/a +GENERAL_NO;Ne +GENERAL_OK;OK +GENERAL_PORTRAIT;Na výšku +GENERAL_SAVE;Uschovat +GENERAL_YES;Ano +HISTOGRAM_LABEL;Histogram +HISTOGRAM_TOOLTIP_B;Schovej Äi zobraz histogram pro MODROU +HISTOGRAM_TOOLTIP_G;Schovej Äi zobraz histogram pro ZELENOU +HISTOGRAM_TOOLTIP_L;Schovej Äi zobraz histogram pro JAS v CIELAB +HISTOGRAM_TOOLTIP_R;Schovej Äi zobraz histogram pro ÄŒERVENOU +HISTORY_CHANGED;ZmÄ›nÄ›no +HISTORY_CUSTOMCURVE;Vlastní kÅ™ivka +HISTORY_DELSNAPSHOT;Odstranit snímek +HISTORY_FROMCLIPBOARD;Ze schránky +HISTORY_LABEL;Historie +HISTORY_MSG_10;Komprese stínů +HISTORY_MSG_11;Tónová kÅ™ivka +HISTORY_MSG_12;Automatická expozice +HISTORY_MSG_13;Oříznutí exozice +HISTORY_MSG_14;Jas (CIELAB) +HISTORY_MSG_15;Kontrast (CIELAB) +HISTORY_MSG_16;ÄŒerná (CIELAB) +HISTORY_MSG_17;Komprese svÄ›tel (CIELAB) +HISTORY_MSG_18;Komprese stínů (CIELAB) +HISTORY_MSG_19;Tónová kÅ™ivka (CIELAB) +HISTORY_MSG_1;Obrázek naÄten +HISTORY_MSG_20;DoostÅ™ení +HISTORY_MSG_21;PolomÄ›r doostÅ™ení +HISTORY_MSG_22;Míra doostÅ™ení +HISTORY_MSG_23;Práh doostÅ™ení +HISTORY_MSG_24;DoostÅ™ení pouze v okrajích +HISTORY_MSG_25;PolomÄ›r detekce okrajů pÅ™i doostÅ™ení +HISTORY_MSG_26;Tolerance okrajů pÅ™i doostÅ™ení +HISTORY_MSG_27;Omezení haló artefatů pÅ™i doostÅ™ení +HISTORY_MSG_28;Míra omezení haló artefatů +HISTORY_MSG_29;Metoda doostÅ™ení +HISTORY_MSG_2;Profil naÄten +HISTORY_MSG_30;PolomÄ›r dekonvoluce +HISTORY_MSG_31;Míra dekonvoluce +HISTORY_MSG_32;Útlum dekonvoluce +HISTORY_MSG_33;PoÄet opakování dekonvoluce +HISTORY_MSG_34;Zabránit oříznutí barev +HISTORY_MSG_35;Omezování sytosti +HISTORY_MSG_36;Omezení sytosti +HISTORY_MSG_37;Sytost barev +HISTORY_MSG_38;Metoda vyvážení bílé +HISTORY_MSG_39;Barevná teplota +HISTORY_MSG_3;Profil zmÄ›nÄ›n +HISTORY_MSG_40;Odstín vyvážení bílé +HISTORY_MSG_41;Posun barev "A" +HISTORY_MSG_42;Posun barev "B" +HISTORY_MSG_43;Redukce Å¡umu v jasech +HISTORY_MSG_44;PolomÄ›r redukce Å¡umu v jasech +HISTORY_MSG_45;Okrajová telorence v redukce Å¡umu v jasech +HISTORY_MSG_46;Redukce barevného Å¡umu +HISTORY_MSG_47;PolomÄ›r redukce barevného Å¡umu +HISTORY_MSG_48;Okrajová toleranve v redukci barevného Å¡umu +HISTORY_MSG_49;Redukce barevného Å¡umu s ohledem na okraje +HISTORY_MSG_4;Prohlížení historie +HISTORY_MSG_50;Nástroj Stíny/svÄ›tla +HISTORY_MSG_51;ZvýraznÄ›ní svÄ›tel +HISTORY_MSG_52;ZvýraznÄ›ní stínů +HISTORY_MSG_53;Tónová rozsah jasů +HISTORY_MSG_54;Tónový rozsah stínů +HISTORY_MSG_55;Místní kontrast +HISTORY_MSG_56;PolomÄ›r svÄ›tel a stínů +HISTORY_MSG_57;Hrubé otáÄení +HISTORY_MSG_58;Horizontální pÅ™eklopení +HISTORY_MSG_59;Vertikální pÅ™eklopení +HISTORY_MSG_5;Jas +HISTORY_MSG_60;OtáÄení +HISTORY_MSG_61;OtoÄení +HISTORY_MSG_62;Úprava zkreslení objektivu +HISTORY_MSG_63;Záložka zvolena +HISTORY_MSG_64;Oříznout obrázek +HISTORY_MSG_65;Úprava chromatické vady +HISTORY_MSG_66;Obnovení jasů +HISTORY_MSG_67;Míra obnovení jasů +HISTORY_MSG_68;Metoda obnovení jasů +HISTORY_MSG_69;Pracovní barevný prostor +HISTORY_MSG_6;Kontrast +HISTORY_MSG_70;Výstupní barevný prostor +HISTORY_MSG_71;Vstupní barevný prostor +HISTORY_MSG_72;Úprave vinÄ›tace +HISTORY_MSG_73;Míchání kanálů +HISTORY_MSG_74;Míra zmÄ›ny rozmÄ›rů +HISTORY_MSG_75;Metoda zmÄ›ny rozmÄ›ru +HISTORY_MSG_76;Exif Metadata +HISTORY_MSG_77;IPTC Metadata +HISTORY_MSG_7;ÄŒerná +HISTORY_MSG_8;ExpoziÄní korekce +HISTORY_MSG_9;Komprese svÄ›tel +HISTORY_NEWSNAPSHOT;Nový snímek +HISTORY_NEWSNAPSHOTAS;Jako... +HISTORY_NEWSSDIALOGLABEL;Titulek snímku: +HISTORY_NEWSSDIALOGTITLE;PÅ™idat nový snímek +HISTORY_SETTO;Nastavit na +HISTORY_SNAPSHOT;Snímek +HISTORY_SNAPSHOTS;Snímky +ICMPANEL_FILEDLGFILTERANY;Jakékoliv soubory +ICMPANEL_FILEDLGFILTERICM;Soubory ICC profilů +ICMPANEL_GAMMABEFOREINPUT;Profil provádí Gama korekci +ICMPANEL_INPUTCAMERA;Výchozí profil fotoaparátu +ICMPANEL_INPUTCUSTOM;Vlastní +ICMPANEL_INPUTDLGLABEL;Vyber vstupní ICC profil... +ICMPANEL_INPUTEMBEDDED;Použít vložený profil, pokud je k dispozici +ICMPANEL_INPUTPROFILE;Vstupní profil +ICMPANEL_NOICM;Bez správy barev: sRGB výstup +ICMPANEL_OUTPUTDLGLABEL;Vyber výstupní ICC profil... +ICMPANEL_OUTPUTPROFILE;Výstupní barevný prostor +ICMPANEL_SAVEREFERENCE;Uložit referenÄní obrázek pro profilování +ICMPANEL_WORKINGPROFILE;Pracovní barevný prostor +IMAGEAREA_DETAILVIEW;Detailní pohled +IPTCPANEL_AUTHOR;Autor +IPTCPANEL_AUTHORHINT;Jméno autora, například spisovatele, fotografa nebo grafika (By-line). +IPTCPANEL_AUTHORSPOSITION;Autorova pozice +IPTCPANEL_AUTHORSPOSITIONHINT;Titul/pozice autora nebo autorů obrázku (By-line Title). +IPTCPANEL_CAPTION;Popis +IPTCPANEL_CAPTIONHINT;Textový popis dat (Popis - Shrnutí) +IPTCPANEL_CAPTIONWRITER;PopisovaÄ +IPTCPANEL_CAPTIONWRITERHINT;Jméno osoby, která vložila, zmÄ›nila nebo opravila obrázek nebo popis/shrnutí (Autor - Editor) +IPTCPANEL_CATEGORY;Kategorie +IPTCPANEL_CATEGORYHINT;Obsah obrázku dle názoru dodavatele (Kategorie). +IPTCPANEL_CITY;MÄ›sto +IPTCPANEL_CITYHINT;Místo vzniku obrázku (MÄ›sto). +IPTCPANEL_COPYHINT;Zkopíruj IPTC nastavení do schránky +IPTCPANEL_COPYRIGHT;Copyright +IPTCPANEL_COPYRIGHTHINT;Autorská práva (Copyright Notice). +IPTCPANEL_COUNTRY;ZemÄ› +IPTCPANEL_COUNTRYHINT;Jméno zemÄ›/lokace kde byl obrázek vytvoÅ™en (ZemÄ› - Lokace). +IPTCPANEL_CREDIT;Zásluhy +IPTCPANEL_CREDITHINT;Dodavatel obrázku, ne nutnÄ› vlastník/autor (Credit). +IPTCPANEL_DATECREATED;Datum vytvoÅ™ení +IPTCPANEL_DATECREATEDHINT;Kdy byl obrázek vytvoÅ™en; Formát: RRRRMMDD (Datum vytvoÅ™ení). +IPTCPANEL_EMBEDDED;Uložené +IPTCPANEL_EMBEDDEDHINT;Obnov IPTC data z obrázku +IPTCPANEL_HEADLINE;Nadpis +IPTCPANEL_HEADLINEHINT;UveÅ™ejnitelný krátký popis obrázku (Nadpis). +IPTCPANEL_INSTRUCTIONS;Instrukce +IPTCPANEL_INSTRUCTIONSHINT;Další instrukce vztahující se k obrázku (Speciální instrukce). +IPTCPANEL_KEYWORDS;KlíÄová slova +IPTCPANEL_KEYWORDSHINT;Jednoslovná hesla popisující obrázek (KlíÄová slova). +IPTCPANEL_PASTEHINT;Vlož IPTC nastavení ze schránky +IPTCPANEL_PROVINCE;Kraj +IPTCPANEL_PROVINCEHINT;Kraj/stát kde byl obrázek vytvoÅ™en (Kraj-Stát). +IPTCPANEL_RESET;Obnov +IPTCPANEL_RESETHINT;Obnov výchozí profil +IPTCPANEL_SOURCE;Zdroj +IPTCPANEL_SOURCEHINT;Původní vlastník intelektuálního obsahu obrázku (Zdroj). +IPTCPANEL_SUPPCATEGORIES;Dodat. kategorie +IPTCPANEL_SUPPCATEGORIESHINT;UpÅ™esňující popis obsahu obrázku (DodateÄné kategorie). +IPTCPANEL_TITLE;Titulek +IPTCPANEL_TITLEHINT;Zkrácený popis obrázku (Jméno obrázku). +IPTCPANEL_TRANSREFERENCE;Trans. Reference +IPTCPANEL_TRANSREFERENCEHINT;Kód místa, odkud byl pÅ™evzat originální obrázek (Original Transmission Reference). +MAIN_BUTTON_PREFERENCES;Volby +MAIN_BUTTON_SAVE;Uložit +MAIN_BUTTON_SAVEAS;jako... +MAIN_BUTTON_SENDTOEDITOR;Odeslat do editoru +MAIN_MSG_ALREADYEXISTS;Soubor již existuje. +MAIN_MSG_CANNOTLOAD;NepodaÅ™ilo se naÄíst obrázek +MAIN_MSG_CANNOTSAVE;Chyba pÅ™i ukládání souboru. +MAIN_MSG_CANNOTSTARTEDITOR;Can not start editor. +MAIN_MSG_CANNOTSTARTEDITOR_SECONDARY;Please set the correct path in the "Preferences" dialog. +MAIN_MSG_EXITJOBSINQUEUEINFO;Nezpracované obrázky ve frontÄ› budou ztraceny! +MAIN_MSG_EXITJOBSINQUEUEQUEST;OPravdu chcete skonÄit? Ve frontÄ› jsou nezpracované obrázky. +MAIN_MSG_JOBSINQUEUE;Úlohy ve frontÄ› +MAIN_MSG_QOVERWRITE;Chcete jej pÅ™epsat? +MAIN_TAB_BASIC;Základní +MAIN_TAB_COLOR;Barvy +MAIN_TAB_DETAIL;Detaily +MAIN_TAB_EXIF;Exif +MAIN_TAB_EXPOSURE;Expozice +MAIN_TAB_ICM;ICM +MAIN_TAB_IPTC;IPTC +MAIN_TAB_METADATA;Metadata +MAIN_TAB_TRANSFORM;Transformace +MAIN_TOOLTIP_HIDEFP;Zobrazit Äi schovat dolní panel (složky a prohlížeÄ souborů, shortcut key: F)) +MAIN_TOOLTIP_HIDEHP;Zobrazit Äi schovat levý panel (obsahující historii, shortcut key: H) +MAIN_TOOLTIP_INDCLIPPEDH;Zvýraznit oříznuté jasy +MAIN_TOOLTIP_INDCLIPPEDS;Zvýraznit oříznuté stíny +MAIN_TOOLTIP_PREFERENCES;ZmÄ›nit volby +MAIN_TOOLTIP_QINFO;StruÄné informace o obrázku +MAIN_TOOLTIP_SAVE;Uložit obrázek do výchozí složky +MAIN_TOOLTIP_SAVEAS;Uložit obrázek do vybrané složky +PARTIALPASTE_BASICGROUP;Základní nastavení +PARTIALPASTE_CACORRECTION;Korekce C/A +PARTIALPASTE_COARSETRANS;Orientace / pÅ™evrácení +PARTIALPASTE_COLORBOOST;Posílení barev +PARTIALPASTE_COLORDENOISE;OdstranÄ›ní barevného Å¡umu +PARTIALPASTE_COLORGROUP;Nastavení barev +PARTIALPASTE_COLORMIXER;Mixér barev +PARTIALPASTE_COLORSHIFT;Posun barev +PARTIALPASTE_COMPOSITIONGROUP;Nastavení kompozice +PARTIALPASTE_CROP;OÅ™ez +PARTIALPASTE_DIALOGLABEL;Nastavení profilu ÄásteÄného vložení +PARTIALPASTE_DISTORTION;Korekce zkreslení +PARTIALPASTE_EXIFCHANGES;Upravené exif data +PARTIALPASTE_EXPOSURE;Expozice +PARTIALPASTE_HLRECOVERY;Obnovení svÄ›tel +PARTIALPASTE_ICMSETTINGS;Nastavení ICM +PARTIALPASTE_IPTCINFO;IPTC info +PARTIALPASTE_LENSGROUP;Nastavení objektivu +PARTIALPASTE_LUMACURVE;KÅ™ivka jasu +PARTIALPASTE_LUMADENOISE;Redukce Å¡umu v jasech +PARTIALPASTE_LUMINANCEGROUP;Nastavení svÄ›tel +PARTIALPASTE_METAICMGROUP;Nastavení metadat a ICM +PARTIALPASTE_RESIZE;ZmÄ›na velikosti +PARTIALPASTE_ROTATION;Rotace +PARTIALPASTE_SHADOWSHIGHLIGHTS;Stíny/SvÄ›tla +PARTIALPASTE_SHARPENING;DoostÅ™ení +PARTIALPASTE_VIGNETTING;Korekce vinÄ›tace +PARTIALPASTE_WHITEBALANCE;Nastavení bílé +PREFERENCES_APPLNEXTSTARTUP;Projeví se pÅ™i dalším spuÅ¡tÄ›ní +PREFERENCES_BLINKCLIPPED;Blikání v oříznutých oblastech +PREFERENCES_CACHECLEARALL;Vymaž vÅ¡e +PREFERENCES_CACHECLEARPROFILES;Vymaž profily +PREFERENCES_CACHECLEARTHUMBS;Vymaž náhledy +PREFERENCES_CACHEFORMAT1;Vlastní (rychlejší a kvalitnÄ›jší) +PREFERENCES_CACHEFORMAT2;JPEG (Menší velikost) +PREFERENCES_CACHEMAXENTRIES;Maximální poÄet záznamů v cache. +PREFERENCES_CACHEOPTS;Vlastnosti cache +PREFERENCES_CACHESTRAT1;UpÅ™ednostnit rychlost pÅ™ed spotÅ™ebou pamÄ›ti +PREFERENCES_CACHESTRAT2;UpÅ™ednostnit menší spotÅ™ebu pamÄ›ti pÅ™ed rychlostí +PREFERENCES_CACHESTRAT;Strategie cache +PREFERENCES_CACHETHUMBFORM;Formát náhledů v cache +PREFERENCES_CACHETHUMBHEIGHT;Maximální velikost náhledu +PREFERENCES_CLEARDLG_LINE1;ÄŒiÅ¡tÄ›ní cache +PREFERENCES_CLEARDLG_LINE2;může trvat nÄ›kolik sekund. +PREFERENCES_CLEARDLG_TITLE;Prosím poÄkejte. +PREFERENCES_CLIPPINGIND;ZvýraznÄ›ní oříznutých jasů Äi stínů +PREFERENCES_CMETRICINTENT;Kolorimetrická metoda +PREFERENCES_DATEFORMAT;Formát data +PREFERENCES_DATEFORMATHINT;Lze použít následující formátovací Å™etÄ›zce:\n%y : rok (year)\n%m : mÄ›síc (month)\n%d : den (day)\n\nNapříklad Äeský formát data:\n%d. %m. %y +PREFERENCES_DEFAULTLANG;Výchozí jazyk +PREFERENCES_DEFAULTTHEME;Výchozí vzhled +PREFERENCES_DEMOSAICINGALGO;Demozajkovací algoritmus +PREFERENCES_DIRHOME;Domovská složka +PREFERENCES_DIRLAST;Poslední navÅ¡tívená složka +PREFERENCES_DIROTHER;Jiná +PREFERENCES_DIRSELECTDLG;Zvolte složku s obrázky pro spuÅ¡tÄ›ní... +PREFERENCES_DIRSOFTWARE;InstalaÄní složka +PREFERENCES_DMETHOD;Metoda +PREFERENCES_EDITORCMDLINE;Jiný příkaz +PREFERENCES_EXTERNALEDITOR;Externí editor +PREFERENCES_FALSECOLOR;PoÄet kroků pÅ™i potlaÄování chybných barev +PREFERENCES_FBROWSEROPTS;Volby prohlížeÄe souborů +PREFERENCES_FILEFORMAT;Formát souboru +PREFERENCES_FORIMAGE;Pro obrázkové soubory +PREFERENCES_FORRAW;Pro RAW soubory +PREFERENCES_GIMPPATH;GIMP instalaÄní adresář +PREFERENCES_GTKTHEME;GTK výchozí +PREFERENCES_HINT;NápovÄ›da +PREFERENCES_HLTHRESHOLD;Práh pro oříznutá svÄ›tla +PREFERENCES_ICCDIR;Složka ICC profilů +PREFERENCES_IMPROCPARAMS;Výchozí profily pro zpracování obrázku +PREFERENCES_INTENT_ABSOLUTE;Absolutní kolorimetrie +PREFERENCES_INTENT_PERCEPTUAL;Vnímání +PREFERENCES_INTENT_RELATIVE;Relativní kolorimetrie +PREFERENCES_INTENT_SATURATION;Saturace +PREFERENCES_LIVETHUMBNAILS;Živé náhledy (pomalejší) +PREFERENCES_MONITORICC;Profil monitoru +PREFERENCES_OUTDIR;Výstupní složka +PREFERENCES_OUTDIRFOLDER;Ulož do souboru +PREFERENCES_OUTDIRFOLDERHINT;Uloží obrázky do vybraného adresáře +PREFERENCES_OUTDIRHINT;Lze použít následující formátovací Å™etÄ›zce:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nTyto formátovací Å™etÄ›zce reprezentují adresáře a Äásti cesty, kde je uložen raw soubor.\n\nNapříklad pokud je otevÅ™en soubor /home/tom/image/02-09-2006/dsc0012.nef, mají jednotlivé formátovací Å™etÄ›zce tento význam:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nPokud si pÅ™ejete uložit výstupní obrázek vedle originálu, napiÅ¡tÄ›:\n%p1/%f\n\nJestliže si jej ale pÅ™ejete uložit do adresáře 'converted' ve stejném adresáři jako originál, napiÅ¡tÄ›:\n%p1/converted/%f\n\nPro uložení výstupního obrázku do adresáře '/home/tom/converted' se zachováním adresáře s datem, použijte:\n%p2/converted/%d1/%f +PREFERENCES_OUTDIRTEMPLATE;Použij Å¡ablonu +PREFERENCES_OUTDIRTEMPLATEHINT;Lze použít následující formátovací Å™etÄ›zce:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nTyto formátovací Å™etÄ›zce reprezentují adresáře a Äásti cesty, kde je uložen raw soubor.\n\nNapříklad pokud je otevÅ™en soubor /home/tom/image/02-09-2006/dsc0012.nef, mají jednotlivé formátovací Å™etÄ›zce tento význam:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nPokud si pÅ™ejete uložit výstupní obrázek vedle originálu, napiÅ¡tÄ›:\n%p1/%f\n\nJestliže si jej ale pÅ™ejete uložit do adresáře 'converted' ve stejném adresáři jako originál, napiÅ¡tÄ›:\n%p1/converted/%f\n\nPro uložení výstupního obrázku do adresáře '/home/tom/converted' se zachováním adresáře s datem, použijte:\n%p2/converted/%d1/%f +PREFERENCES_PARSEDEXT;Zobrazované přípony +PREFERENCES_PARSEDEXTADD;PÅ™idej příponu +PREFERENCES_PARSEDEXTADDHINT;Vložte příponu a stisknÄ›te toto tlaÄítko pro pÅ™idání do seznamu +PREFERENCES_PARSEDEXTDELHINT;Vymaže oznaÄenou příponu ze seznamu +PREFERENCES_PROFILEHANDLING;Profily zpracování +PREFERENCES_PROFILELOADPR;Priorita nahrávání profilu +PREFERENCES_PROFILEPRCACHE;Profil v cache +PREFERENCES_PROFILEPRFILE;Profil uložený se zdrojovým souborem +PREFERENCES_PROFILESAVECACHE;Ukládat parametry zpracování do cache +PREFERENCES_PROFILESAVEINPUT;Ukládat parametry zpracování se zdrojovým souborem +PREFERENCES_PSPATH;Adobe Photoshop instalaÄní adresář +PREFERENCES_SELECTICCDIRDLG;Zvolte složky s ICC profily... +PREFERENCES_SELECTLANG;Volba jazyka +PREFERENCES_SELECTMONITORPROFDLG;Zvolte ICC profil obrazovky... +PREFERENCES_SELECTTHEME;Vybraný vzhled +PREFERENCES_SHOWBASICEXIF;Zobrazovat základní informace z EXIF +PREFERENCES_SHOWDATETIME;Zobrazovat datum a Äas +PREFERENCES_SHOWONLYRAW;Zobrazovat pouze soubory RAW +PREFERENCES_SHTHRESHOLD;Práh pro oříznuté stíny +PREFERENCES_STARTUPIMDIR;Složka s obrázky pÅ™i spuÅ¡tÄ›ní +PREFERENCES_TAB_BROWSER;ProhlížeÄ souborů +PREFERENCES_TAB_COLORMGR;Správa barev +PREFERENCES_TAB_GENERAL;Obecné +PREFERENCES_TAB_IMPROC;Zpracování obrázku +PREFERENCES_TAB_OUTPUT;Volby výstupu +PREFERENCES_THUMBSIZE;Velikost náhledu +PROFILEPANEL_FILEDLGFILTERANY;Jakékoliv souboru +PROFILEPANEL_FILEDLGFILTERPP;Profily zpracování +PROFILEPANEL_LABEL;Profily zpracování +PROFILEPANEL_LOADDLGLABEL;NaÄíst parametry zpracování... +PROFILEPANEL_PCUSTOM;Vlastní +PROFILEPANEL_PFILE;Ze souboru +PROFILEPANEL_PLASTPHOTO;Poslední obrázek +PROFILEPANEL_PLASTSAVED;Poslední uschovaný +PROFILEPANEL_PROFILE;Profil +PROFILEPANEL_SAVEDLGLABEL;Uschovat parametry zpracování... +PROFILEPANEL_TOOLTIPCOPY;Uložit aktuální profil do schránky +PROFILEPANEL_TOOLTIPLOAD;NaÄíst profil ze souboru +PROFILEPANEL_TOOLTIPPASTE;Vložit profil ze schránky +PROFILEPANEL_TOOLTIPSAVE;Uschovat souÄasný profil +PROGRESSBAR_DECODING;Dekódování RAW... +PROGRESSBAR_DEMOSAICING;Demozajkování... +PROGRESSBAR_LOADING;NaÄítám obrázek... +PROGRESSBAR_LOADJPEG;NaÄítám JPEG... +PROGRESSBAR_LOADPNG;NaÄítám PNG... +PROGRESSBAR_LOADTIFF;NaÄítám TIFF... +PROGRESSBAR_PROCESSING;Zpracovávám obrázek... +PROGRESSBAR_READY;PÅ™ipraven. +PROGRESSBAR_SAVEJPEG;Ukládám jako JPEG... +PROGRESSBAR_SAVEPNG;Ukládám jako PNG... +PROGRESSBAR_SAVETIFF;Ukládám jako TIFF... +PROGRESSDLG_LOADING;Loading file... +PROGRESSDLG_PROCESSING;Processing image... +PROGRESSDLG_SAVING;Saving file... +QINFO_FOCALLENGTH;Ohnisková vzdálenost +QINFO_ISO;ISO +QINFO_LENS;Lens +QINFO_NOEXIF;Exif údaje nejsou k dispozici. +SAVEDLG_FILEFORMAT;Formát souboru +SAVEDLG_JPEGQUAL;JPEG Kvalita +SAVEDLG_JPGFILTER;Soubory JPEG +SAVEDLG_PNGCOMPR;PNG Komprese +SAVEDLG_PNGFILTER;Soubory PNG +SAVEDLG_PUTTOQUEUE;Vložit soubor do fronty +SAVEDLG_PUTTOQUEUEHEAD;Put to the head of the processing queue +SAVEDLG_PUTTOQUEUETAIL;Put to the end of the processing queue +SAVEDLG_SAVEIMMEDIATELY;OkamžitÄ› uložit +SAVEDLG_SAVESPP;Uschovat s obrazem i parametry zpracování +SAVEDLG_TIFFFILTER;Soubory TIFF +TOOLBAR_TOOLTIP_CROP;OznaÄení výřezu (shortcut key: C) +TOOLBAR_TOOLTIP_HAND;Nástroj ruka (shortcut key: N) +TOOLBAR_TOOLTIP_STRAIGHTEN;VyznaÄení roviny (shortcut key: S) +TOOLBAR_TOOLTIP_WB;Bodové vyvážení bílé (shortcut key: W) +TP_CACORRECTION_BLUE;Modrá +TP_CACORRECTION_LABEL;Oprava chromatické vady +TP_CACORRECTION_RED;ÄŒervená +TP_CHMIXER_BLUE;Modrá +TP_CHMIXER_GREEN;Zelená +TP_CHMIXER_LABEL;Míchání kanálů +TP_CHMIXER_RED;ÄŒervená +TP_COARSETRAF_DEGREE;Stupeň: +TP_COARSETRAF_TOOLTIP_HFLIP;PÅ™eklopit horizontálnÄ› +TP_COARSETRAF_TOOLTIP_ROTLEFT;OtoÄit doleva +TP_COARSETRAF_TOOLTIP_ROTRIGHT;OtoÄit doprava +TP_COARSETRAF_TOOLTIP_VFLIP;PÅ™eklopit vertikálnÄ› +TP_COLORBOOST_ACHANNEL;kanál "a" +TP_COLORBOOST_AMOUNT;Míra +TP_COLORBOOST_AVOIDCOLORCLIP;Zabránit oříznutí barvy +TP_COLORBOOST_BCHANNEL;kanál "b" +TP_COLORBOOST_CHAB;a & b +TP_COLORBOOST_CHANNEL;Kanál +TP_COLORBOOST_CHSEPARATE;zvlášť +TP_COLORBOOST_ENABLESATLIMITER;Omezovat sytost +TP_COLORBOOST_LABEL;Sytost barev +TP_COLORBOOST_SATLIMIT;Limit sytosti +TP_COLORDENOISE_EDGESENSITIVE;Citlivost k okrajům +TP_COLORDENOISE_EDGETOLERANCE;Tolerance okrajům +TP_COLORDENOISE_LABEL;Redukce barevného Å¡umu +TP_COLORDENOISE_RADIUS;PolomÄ›r +TP_COLORSHIFT_BLUEYELLOW;Modrá-Žlutá +TP_COLORSHIFT_GREENMAGENTA;Modrá-Purpurová +TP_COLORSHIFT_LABEL;Barevný posun +TP_CROP_DPI;DPI= +TP_CROP_FIXRATIO;PomÄ›r stran: +TP_CROP_GTDIAGONALS;Pravidlo diagonál +TP_CROP_GTHARMMEANS1;Zlatý Å™ez 1 +TP_CROP_GTHARMMEANS2;Zlatý Å™ez 2 +TP_CROP_GTHARMMEANS3;Zlatý Å™ez 3 +TP_CROP_GTHARMMEANS4;Zlatý Å™ez 4 +TP_CROP_GTNONE;Žádné +TP_CROP_GTRULETHIRDS;Pravidlo tÅ™etin +TP_CROP_GUIDETYPE;Druh vodítek: +TP_CROP_H;V +TP_CROP_LABEL;Výřez +TP_CROP_SELECTCROP; OznaÄení výřezu +TP_CROP_W;Å  +TP_CROP_X;x +TP_CROP_Y;y +TP_DISTORTION_AMOUNT;Míra +TP_DISTORTION_LABEL;Oprava zkreslení objektivu +TP_EXPOSURE_AUTOLEVELS;ÚrovnÄ› automaticky +TP_EXPOSURE_BLACKLEVEL;ÄŒerná +TP_EXPOSURE_BRIGHTNESS;Jas +TP_EXPOSURE_CLIP;Oříznutí +TP_EXPOSURE_COMPRHIGHLIGHTS;Komprese svÄ›tel +TP_EXPOSURE_COMPRSHADOWS;Komprese stínů +TP_EXPOSURE_CONTRAST;Kontrast +TP_EXPOSURE_CURVEEDITOR;Tonální kÅ™ivka +TP_EXPOSURE_EXPCOMP;Korekce expozice +TP_EXPOSURE_LABEL;Expozice +TP_HLREC_CIELAB;Mísení CIELAB +TP_HLREC_COLOR;Propagace barev +TP_HLREC_LABEL;Obnovení jasů +TP_HLREC_LUMINANCE;Obnovení jasů +TP_HLREC_METHOD;Metoda: +TP_ICM_FILEDLGFILTERANY;Jakékoliv soubory +TP_ICM_FILEDLGFILTERICM;Soubory ICC profilů +TP_ICM_GAMMABEFOREINPUT;Profil provádí Gama korekci +TP_ICM_INPUTCAMERA;Výchozí profil fotoaparátu +TP_ICM_INPUTCUSTOM;Vlastní +TP_ICM_INPUTDLGLABEL;Vyber vstupní ICC profil... +TP_ICM_INPUTEMBEDDED;Použít vložený profil, pokud je k dispozici +TP_ICM_INPUTPROFILE;Vstupní profil +TP_ICM_LABEL;ICM +TP_ICM_NOICM;Bez správy barev: sRGB výstup +TP_ICM_OUTPUTDLGLABEL;Vyber výstupní ICC profil... +TP_ICM_OUTPUTPROFILE;Výstupní barevný prostor +TP_ICM_SAVEREFERENCE;Uložit referenÄní obrázek pro profilování +TP_ICM_WORKINGPROFILE;Pracovní barevný prostor +TP_LUMACURVE_BLACKLEVEL;ÄŒerná +TP_LUMACURVE_BRIGHTNESS;Jas +TP_LUMACURVE_COMPRHIGHLIGHTS;Komprese svÄ›tel +TP_LUMACURVE_COMPRSHADOWS;Komprese stínů +TP_LUMACURVE_CONTRAST;Kontrast +TP_LUMACURVE_CURVEEDITOR;KÅ™ivka +TP_LUMACURVE_LABEL;KÅ™ivka jasu v CIELAB +TP_LUMADENOISE_EDGETOLERANCE;Tolerance okrajů +TP_LUMADENOISE_LABEL;Redukce Å¡umu v jasech +TP_LUMADENOISE_RADIUS;PolomÄ›r +TP_RESIZE_BICUBIC;Bikubická +TP_RESIZE_BICUBICSF;Bikubická (MÄ›kÄí) +TP_RESIZE_BICUBICSH;Bikubická (OstÅ™ejší) +TP_RESIZE_BILINEAR;Bilineární +TP_RESIZE_FULLSIZE;Plná velikost obrázku: +TP_RESIZE_H;V: +TP_RESIZE_LABEL;ZmÄ›nit rozmÄ›ry +TP_RESIZE_METHOD;Metoda: +TP_RESIZE_NEAREST;Nejbližší +TP_RESIZE_SCALE;Měřítko +TP_RESIZE_W;Å : +TP_ROTATE_AUTOCROP;Automatický oÅ™ez +TP_ROTATE_DEGREE;StupnÄ› +TP_ROTATE_FILL;Vyplnit +TP_ROTATE_LABEL;OtáÄení +TP_ROTATE_SELECTLINE; VyznaÄ rovinu +TP_SHADOWSHLIGHTS_HIGHLIGHTS;SvÄ›tla +TP_SHADOWSHLIGHTS_HLTONALW;Tonální rozsah +TP_SHADOWSHLIGHTS_LABEL;Stíny/SvÄ›tla +TP_SHADOWSHLIGHTS_LOCALCONTR;Místní kontrast +TP_SHADOWSHLIGHTS_RADIUS;PolomÄ›r +TP_SHADOWSHLIGHTS_SHADOWS;Stíny +TP_SHADOWSHLIGHTS_SHTONALW;Tonální rozsah +TP_SHARPENING_AMOUNT;Míra +TP_SHARPENING_EDRADIUS;PolomÄ›r +TP_SHARPENING_EDTOLERANCE;Tolerance okrajů +TP_SHARPENING_HALOCONTROL;Omezení haló artefatů +TP_SHARPENING_HCAMOUNT;Míra +TP_SHARPENING_LABEL;DoostÅ™ení +TP_SHARPENING_METHOD;Metoda +TP_SHARPENING_ONLYEDGES;DoostÅ™it pouze okraje +TP_SHARPENING_RADIUS;PolomÄ›r +TP_SHARPENING_RLD;RL Dekonvoluce +TP_SHARPENING_RLD_AMOUNT;Míra +TP_SHARPENING_RLD_DAMPING;Útlum +TP_SHARPENING_RLD_ITERATIONS;PoÄet opakování +TP_SHARPENING_THRESHOLD;Práh +TP_SHARPENING_USM;Maskovat rozostÅ™ení +TP_VIGNETTING_AMOUNT;Míra +TP_VIGNETTING_LABEL;Oprava vinÄ›tace +TP_VIGNETTING_RADIUS;PolomÄ›r +TP_WBALANCE_AUTO;Automaticky +TP_WBALANCE_CAMERA;Fotoaparát +TP_WBALANCE_CUSTOM;Vlastní +TP_WBALANCE_GREEN;Odstín +TP_WBALANCE_LABEL;Vyvážení bílé +TP_WBALANCE_METHOD;Metoda +TP_WBALANCE_SIZE;RozmÄ›r: +TP_WBALANCE_SPOTWB;Bodové vyvážení +TP_WBALANCE_TEMPERATURE;Teplota +ZOOMBAR_DETAIL;Detail +ZOOMBAR_HUGE;Veliký +ZOOMBAR_LARGE;VÄ›tší +ZOOMBAR_NORMAL;Normální +ZOOMBAR_PREVIEW;Náhled +ZOOMBAR_SCALE;Měřítko +ZOOMBAR_SMALL;Malý diff --git a/release/languages/dansk b/release/languages/dansk new file mode 100755 index 000000000..6a018bf32 --- /dev/null +++ b/release/languages/dansk @@ -0,0 +1,577 @@ +# 2008-06-22 +# Translated by Torben Nielsen +# danish translation of RawTherapee +ADJUSTER_RESET_TO_DEFAULT;Tilbage til standard +CURVEEDITOR_FILEDLGFILTERANY;Hvilken som helst fil +CURVEEDITOR_FILEDLGFILTERCURVE;Kurvefiler +CURVEEDITOR_LINEAR;Liniær +CURVEEDITOR_LOADDLGLABEL;Ã…bn kurve... +CURVEEDITOR_SAVEDLGLABEL;Gem kurve... +CURVEEDITOR_TOOLTIPLINEAR;Nulstil kurve til liniær +CURVEEDITOR_TOOLTIPLOAD;Gem kurve fra fil +CURVEEDITOR_TOOLTIPSAVE;Gem nuværende kurve +EXIFFILTER_APERTURE;Aperture +EXIFFILTER_CAMERA;Camera +EXIFFILTER_DIALOGLABEL;Exif Filter +EXIFFILTER_FOCALLEN;Focal Length +EXIFFILTER_ISO;ISO +EXIFFILTER_LENS;Lens +EXIFFILTER_SHUTTER;Shutter +EXIFPANEL_ADDEDIT;Tilføj/Rediger +EXIFPANEL_ADDEDITHINT;Tilføj ny tag eller rediger tag +EXIFPANEL_ADDTAGDLG_ENTERVALUE;Skriv værdi +EXIFPANEL_ADDTAGDLG_SELECTTAG;Vælg tag +EXIFPANEL_ADDTAGDLG_TITLE;Tilføj/Rediger Tag +EXIFPANEL_KEEP;Behold +EXIFPANEL_KEEPHINT;Behold de udvalgte tags nÃ¥r der skrives output fil +EXIFPANEL_REMOVE;Fjern +EXIFPANEL_REMOVEHINT;Fjern de udvalgte tags nÃ¥r der skrives output fil +EXIFPANEL_RESET;Nulstil +EXIFPANEL_RESETALL;Nulstil alle +EXIFPANEL_RESETALLHINT;Nulstil alle tags til deres oprindelige værdier +EXIFPANEL_RESETHINT;Nulstil de udvalgte tags til deres oprindelige værdier +EXIFPANEL_SUBDIRECTORY;Undermappe +FILEBROWSER_APPLYPROFILE;Apply profile +FILEBROWSER_ARRANGEMENTHINT;Change between vertical/horizontal alignment of thumbnails +FILEBROWSER_CLEARPROFILE;Clear profile +FILEBROWSER_COPYPROFILE;Copy profile +FILEBROWSER_DELETEDLGLABEL;File delete confirmation +FILEBROWSER_DELETEDLGMSG;Are you sure you want to delete the selected %1 files? +FILEBROWSER_EMPTYTRASH;Empty Trash +FILEBROWSER_EMPTYTRASHHINT;Permanently delete the files of the trash +FILEBROWSER_EXIFFILTERAPPLY;Apply +FILEBROWSER_EXIFFILTERAPPLYHINT;Switch on/off exif filter of the file browser +FILEBROWSER_EXIFFILTERLABEL;Exif Filter +FILEBROWSER_EXIFFILTERSETTINGS;Setup +FILEBROWSER_EXIFFILTERSETTINGSHINT;Change settings of the exif filter +FILEBROWSER_PARTIALPASTEPROFILE;Partial paste +FILEBROWSER_PASTEPROFILE;Paste profile +FILEBROWSER_POPUPCANCELJOB;Cancel job +FILEBROWSER_POPUPMOVEEND;Move to end of queue +FILEBROWSER_POPUPMOVEHEAD;Move to head of queue +FILEBROWSER_POPUPOPEN;Open +FILEBROWSER_POPUPPROCESS;Put to processing queue +FILEBROWSER_POPUPRANK1;Rank 1 +FILEBROWSER_POPUPRANK2;Rank 2 +FILEBROWSER_POPUPRANK3;Rank 3 +FILEBROWSER_POPUPRANK4;Rank 4 +FILEBROWSER_POPUPRANK5;Rank 5 +FILEBROWSER_POPUPREMOVE;Remove from filesystem +FILEBROWSER_POPUPRENAME;Rename +FILEBROWSER_POPUPSELECTALL;Select all +FILEBROWSER_POPUPTRASH;Move to trash +FILEBROWSER_POPUPUNRANK;Unrank +FILEBROWSER_POPUPUNTRASH;Remove from trash +FILEBROWSER_PROCESSINGSETTINGS;Settings +FILEBROWSER_PROCESSINGSETTINGSHINT;Set the file format and output directory +FILEBROWSER_RENAMEDLGLABEL;Rename file +FILEBROWSER_RENAMEDLGMSG;Rename file "%1" to: +FILEBROWSER_SHOWDIRHINT;Show all images of the directory +FILEBROWSER_SHOWQUEUEHINT;Show content of the processing queue +FILEBROWSER_SHOWRANK1HINT;Show images ranked as 1 star +FILEBROWSER_SHOWRANK2HINT;Show images ranked as 2 star +FILEBROWSER_SHOWRANK3HINT;Show images ranked as 3 star +FILEBROWSER_SHOWRANK4HINT;Show images ranked as 4 star +FILEBROWSER_SHOWRANK5HINT;Show images ranked as 5 star +FILEBROWSER_SHOWTRASHHINT;Show content of the trash +FILEBROWSER_SHOWUNRANKHINT;Show unranked images +FILEBROWSER_STARTPROCESSING;Start Processing +FILEBROWSER_STARTPROCESSINGHINT;Start processing/saving of images in the queue +FILEBROWSER_STOPPROCESSING;Stop processing +FILEBROWSER_STOPPROCESSINGHINT;Stop processing of images +FILEBROWSER_THUMBSIZE;Thumb. size +FILEBROWSER_ZOOMINHINT;Increase thumbnail size +FILEBROWSER_ZOOMOUTHINT;Decrease thumbnail size +GENERAL_ABOUT;Om +GENERAL_CANCEL;Annuller +GENERAL_DISABLE;Deaktivere +GENERAL_DISABLED;Deaktiveret +GENERAL_ENABLE;Aktiveret +GENERAL_ENABLED;Aktiveret +GENERAL_LANDSCAPE;Landskab +GENERAL_LOAD;Ã…bn +GENERAL_NA;n/a +GENERAL_NO;Nej +GENERAL_OK;Ok +GENERAL_PORTRAIT;Portræt +GENERAL_SAVE;Gem +GENERAL_YES;Ja +HISTOGRAM_LABEL;Histogram +HISTOGRAM_TOOLTIP_B;Vis/skjul blÃ¥t histogram +HISTOGRAM_TOOLTIP_G;Vis/skjul grønt histogram +HISTOGRAM_TOOLTIP_L;Vis/skjul CIELAB Luminans histogram +HISTOGRAM_TOOLTIP_R;Vis/skjul rødt histogram +HISTORY_CHANGED;Forandret +HISTORY_CUSTOMCURVE;Egen kurve +HISTORY_DELSNAPSHOT;Fjern bogmærke +HISTORY_FROMCLIPBOARD;From clipboard +HISTORY_LABEL;Historik +HISTORY_MSG_10;Skyggekomprimering +HISTORY_MSG_11;Tonekurve +HISTORY_MSG_12;Autoeksponering +HISTORY_MSG_13;Eksponeringsmarkering +HISTORY_MSG_14;Luminanslysstyrke +HISTORY_MSG_15;Luminanskontrast +HISTORY_MSG_16;Sort luminans +HISTORY_MSG_17;Luminans højlys kompr. +HISTORY_MSG_18;Luminans skygge kompr. +HISTORY_MSG_19;Luminanskurve +HISTORY_MSG_1;Foto Ã¥bnet +HISTORY_MSG_20;Skarphed +HISTORY_MSG_21;Skarphedsradius +HISTORY_MSG_22;Skarphedsmængde +HISTORY_MSG_23;Skarphedstærskelværdi +HISTORY_MSG_24;Skarphed kun i kanter +HISTORY_MSG_25;Kanttegningsradie-skarphed +HISTORY_MSG_26;Kantskarphedstolerance +HISTORY_MSG_27;Halo-skarphedsskontrol +HISTORY_MSG_28;Halo-kontrolstørrelse +HISTORY_MSG_29;Skarphedsmetode +HISTORY_MSG_2;Profil Ã¥bnet +HISTORY_MSG_30;Deconvolution-radius +HISTORY_MSG_31;Deconvolution-størrelse +HISTORY_MSG_32;Deconvolution-dæmpning +HISTORY_MSG_33;Deconvolution-gentagelse +HISTORY_MSG_34;UndgÃ¥ farvemarkeringer +HISTORY_MSG_35;Mæhedsbegrænsning +HISTORY_MSG_36;Mæthedsgrænse +HISTORY_MSG_37;Farveforstærkning +HISTORY_MSG_38;Hvidbalancemetode +HISTORY_MSG_39;Farvetemperatur +HISTORY_MSG_3;Profil ændret +HISTORY_MSG_40;Hvidbalancenuance +HISTORY_MSG_41;Farveskift "A" +HISTORY_MSG_42;Farveskift "B" +HISTORY_MSG_43;Luminans støjreduktion +HISTORY_MSG_44;Lum. støjreduktion-radie +HISTORY_MSG_45;Lum. støjreduktion kanttolerance +HISTORY_MSG_46;Farvestøjreduktion +HISTORY_MSG_47;Farvestøjreduktion-radie +HISTORY_MSG_48;Farvestøjreduktion-kanttolerance +HISTORY_MSG_49;Kantfølsom farvestøjreduktion +HISTORY_MSG_4;Historik-gennemsyn +HISTORY_MSG_50;Skygge/højlys værktøj +HISTORY_MSG_51;Højlys-forstærkning +HISTORY_MSG_52;Skyggeforstærkning +HISTORY_MSG_53;Højlys-tonvidde +HISTORY_MSG_54;Skygge-tonevidde +HISTORY_MSG_55;Lokal kontrast +HISTORY_MSG_56;Skygge/højlys -radie +HISTORY_MSG_57;Enkel rotation +HISTORY_MSG_58;Vend horisontalt +HISTORY_MSG_59;Vend vertikalt +HISTORY_MSG_5;Lysstyrke +HISTORY_MSG_60;Rotation +HISTORY_MSG_61;Rotation +HISTORY_MSG_62;Objektivforvrængning-korrigering +HISTORY_MSG_63;Valgt bogmærke +HISTORY_MSG_64;Beskær foto +HISTORY_MSG_65;C/A korrigering +HISTORY_MSG_66;Højlys-forbedring +HISTORY_MSG_67;Højlys-forbedringsstyrke +HISTORY_MSG_68;Højlys-forbedringsmetode +HISTORY_MSG_69;Arbejdsfarverum +HISTORY_MSG_6;Kontrast +HISTORY_MSG_70;Udgangssfarverum +HISTORY_MSG_71;Indgangsfarverum +HISTORY_MSG_72;Vignettering-korrigering +HISTORY_MSG_73;Kanalmixer +HISTORY_MSG_74;Ændre størrelsesskala +HISTORY_MSG_75;Ændre størrelses metode +HISTORY_MSG_76;Exif Metadata +HISTORY_MSG_77;IPTC Metadata +HISTORY_MSG_7;Sort +HISTORY_MSG_8;Eksponerings-komprimering +HISTORY_MSG_9;Højlys-komprimering +HISTORY_NEWSNAPSHOT;Nyt bogmærke +HISTORY_NEWSNAPSHOTAS;Som... +HISTORY_NEWSSDIALOGLABEL;Navn pÃ¥ bogmærket: +HISTORY_NEWSSDIALOGTITLE;Opret nyt bogmærke +HISTORY_SETTO;Indtil +HISTORY_SNAPSHOT;Bogmærke +HISTORY_SNAPSHOTS;Bogmærker +ICMPANEL_FILEDLGFILTERANY;Alle filer +ICMPANEL_FILEDLGFILTERICM;ICC profilfiler +ICMPANEL_GAMMABEFOREINPUT;Profilen tilføjer Gamma +ICMPANEL_INPUTCAMERA;Kameravalg +ICMPANEL_INPUTCUSTOM;Egen +ICMPANEL_INPUTDLGLABEL;Vælg indgangs ICC-profil... +ICMPANEL_INPUTEMBEDDED;Anvend intern, hvis muligt +ICMPANEL_INPUTPROFILE;Indgangprofil +ICMPANEL_NOICM;Ingen ICM: sRGB-profil +ICMPANEL_OUTPUTDLGLABEL;Vælg udgangs ICC-profil... +ICMPANEL_OUTPUTPROFILE;Udgangsprofil +ICMPANEL_SAVEREFERENCE;Gem reference billede til profil +ICMPANEL_WORKINGPROFILE;Arbejdsprofil +IMAGEAREA_DETAILVIEW;Detaljeret +IPTCPANEL_AUTHOR;Opretter +IPTCPANEL_AUTHORHINT;Navnet pÃ¥ opretteren, f.eks. forfatter, fotograf eller grafiker (By-line). +IPTCPANEL_AUTHORSPOSITION;Opretterens titel +IPTCPANEL_AUTHORSPOSITIONHINT;Beskrivelse af opretterens titel (By-line Title). +IPTCPANEL_CAPTION;Billedtekst +IPTCPANEL_CAPTIONHINT;Tekstbeskrivelse af billedets indhold (Caption - Abstract). +IPTCPANEL_CAPTIONWRITER;Billedtekst forfatter +IPTCPANEL_CAPTIONWRITERHINT;Navnet pÃ¥ personen der har oprettet, redigeret eller korigeret billedeteksten (Writer - Editor). +IPTCPANEL_CATEGORY;Kategori +IPTCPANEL_CATEGORYHINT;Bruges til at beskrive indholdet i billedet ifølge kategorien (Category). +IPTCPANEL_CITY;By +IPTCPANEL_CITYHINT;Billedets oprindelsesby (City). +IPTCPANEL_COPYHINT;Kopier IPTC indstillinger til udklipsholderen +IPTCPANEL_COPYRIGHT;Copyright +IPTCPANEL_COPYRIGHTHINT;Eventuelle copyright tilføjelser (Copyright Notice). +IPTCPANEL_COUNTRY;Land +IPTCPANEL_COUNTRYHINT;Navnet pÃ¥ landet/primære omrÃ¥de hvor billedet er optaget (Country - Primary Location Name). +IPTCPANEL_CREDIT;Kredit +IPTCPANEL_CREDITHINT;Idetificere opretteren af billedet, ikke nødvendivis den samme som ejeren (Credit). +IPTCPANEL_DATECREATED;Optagelsesdato +IPTCPANEL_DATECREATEDHINT;Datoen hvor billedet blev optaget; Format: JJJJMMTT (Date Created). +IPTCPANEL_EMBEDDED;Intern IPTC data +IPTCPANEL_EMBEDDEDHINT;Nulstil til de IPTC data der findes internt i billedfilen +IPTCPANEL_HEADLINE;Overskrift +IPTCPANEL_HEADLINEHINT;En kort beskrivelse af indholdet af billedet (Headline). +IPTCPANEL_INSTRUCTIONS;Instruktioner +IPTCPANEL_INSTRUCTIONSHINT;Andre instuktioner der omhandler brugen af billedet (Special Instructions). +IPTCPANEL_KEYWORDS;Nøgleord +IPTCPANEL_KEYWORDSHINT;Bruges til at beskrive specifikke nøgleord (Keywords). +IPTCPANEL_PASTEHINT;Indsæt IPTC indstillinger fra udklipsholderen +IPTCPANEL_PROVINCE;Provins +IPTCPANEL_PROVINCEHINT;Billedets oprindelsesprovins/-stat (Province-State). +IPTCPANEL_RESET;Nulstil +IPTCPANEL_RESETHINT;Nulstil til standard profil +IPTCPANEL_SOURCE;Kilde +IPTCPANEL_SOURCEHINT;Den originale ejer af billedets indhold (Source). +IPTCPANEL_SUPPCATEGORIES;Suppl. kategorier +IPTCPANEL_SUPPCATEGORIESHINT;Yderlige beskrivelser af indholdet i billedet (Supplemental Categories). +IPTCPANEL_TITLE;Billedtitel +IPTCPANEL_TITLEHINT;En kort beskrivelse af billedet (Object Name). +IPTCPANEL_TRANSREFERENCE;Trans. Reference +IPTCPANEL_TRANSREFERENCEHINT;En kode der representere stedet for original transmission (Original Transmission Reference). +MAIN_BUTTON_PREFERENCES;Indstillinger +MAIN_BUTTON_SAVE;Gem billede +MAIN_BUTTON_SAVEAS;Som... +MAIN_BUTTON_SENDTOEDITOR;Send to editor +MAIN_MSG_ALREADYEXISTS;Filen eksistere allerede. +MAIN_MSG_CANNOTLOAD;Kan ikke Ã¥bne billedet +MAIN_MSG_CANNOTSAVE;Kan ikke gemme +MAIN_MSG_CANNOTSTARTEDITOR;Can not start editor. +MAIN_MSG_CANNOTSTARTEDITOR_SECONDARY;Please set the correct path in the "Preferences" dialog. +MAIN_MSG_EXITJOBSINQUEUEINFO;Unprocessed images in the queue will be lost on exit. +MAIN_MSG_EXITJOBSINQUEUEQUEST;Are you sure you want to exit? There are unprocessed images waiting in the queue. +MAIN_MSG_JOBSINQUEUE;Arbejdet sættes i kø +MAIN_MSG_QOVERWRITE;Vil du overskrive? +MAIN_TAB_BASIC;Grundlæggende +MAIN_TAB_COLOR;Color +MAIN_TAB_DETAIL;Detail +MAIN_TAB_EXIF;Exif +MAIN_TAB_EXPOSURE;Exposure +MAIN_TAB_ICM;ICM +MAIN_TAB_IPTC;IPTC +MAIN_TAB_METADATA;Metadata +MAIN_TAB_TRANSFORM;Ændre +MAIN_TOOLTIP_HIDEFP;Vis/skjul nederste panel (Mapper og Filgennemsyn, shortcut key: F) +MAIN_TOOLTIP_HIDEHP;Vis/skjul venstre panel (Indeholder historiken shortcut key: H) +MAIN_TOOLTIP_INDCLIPPEDH;Marker højlys-indikation +MAIN_TOOLTIP_INDCLIPPEDS;Marker skygge-indikation +MAIN_TOOLTIP_PREFERENCES;Ændre indstillinger +MAIN_TOOLTIP_QINFO;Hurtig information om billedet +MAIN_TOOLTIP_SAVE;Gem billedet i standardmappen +MAIN_TOOLTIP_SAVEAS;Gem billedet i en anden mappe +PARTIALPASTE_BASICGROUP;Basic settings +PARTIALPASTE_CACORRECTION;C/A correction +PARTIALPASTE_COARSETRANS;90 deg rotation / flipping +PARTIALPASTE_COLORBOOST;Color boost +PARTIALPASTE_COLORDENOISE;Color denoise +PARTIALPASTE_COLORGROUP;Color related settings +PARTIALPASTE_COLORMIXER;Color mixer +PARTIALPASTE_COLORSHIFT;Color shift +PARTIALPASTE_COMPOSITIONGROUP;Composition settings +PARTIALPASTE_CROP;Crop +PARTIALPASTE_DIALOGLABEL;Partial paste processing profile +PARTIALPASTE_DISTORTION;Distortion correction +PARTIALPASTE_EXIFCHANGES;Changes to exif data +PARTIALPASTE_EXPOSURE;Exposure +PARTIALPASTE_HLRECOVERY;Highlight recovery +PARTIALPASTE_ICMSETTINGS;ICM settings +PARTIALPASTE_IPTCINFO;IPTC info +PARTIALPASTE_LENSGROUP;Lens related settings +PARTIALPASTE_LUMACURVE;Luminance curve +PARTIALPASTE_LUMADENOISE;Luminance noise reduction +PARTIALPASTE_LUMINANCEGROUP;Luminance related settings +PARTIALPASTE_METAICMGROUP;Metadata/ICM settings +PARTIALPASTE_RESIZE;Resize +PARTIALPASTE_ROTATION;Rotation +PARTIALPASTE_SHADOWSHIGHLIGHTS;Shadows/Highlights +PARTIALPASTE_SHARPENING;Sharpening +PARTIALPASTE_VIGNETTING;Vignetting correction +PARTIALPASTE_WHITEBALANCE;White balance +PREFERENCES_APPLNEXTSTARTUP;ændres ved næste opstart +PREFERENCES_BLINKCLIPPED;Vis markerede omrÃ¥der +PREFERENCES_CACHECLEARALL;Clear All +PREFERENCES_CACHECLEARPROFILES;Clear Profiles +PREFERENCES_CACHECLEARTHUMBS;Clear Thumbnails +PREFERENCES_CACHEFORMAT1;Proprietary (faster and better quality) +PREFERENCES_CACHEFORMAT2;JPEG (smaller disk footprint) +PREFERENCES_CACHEMAXENTRIES;Maximal Number of Cache Entries +PREFERENCES_CACHEOPTS;Cache Options +PREFERENCES_CACHESTRAT1;Prefer Speed to Low Memory Consumption +PREFERENCES_CACHESTRAT2;Prefer Low Memory Consumption to Speed +PREFERENCES_CACHESTRAT;Cache Strategy +PREFERENCES_CACHETHUMBFORM;Cache Thumbnail Format +PREFERENCES_CACHETHUMBHEIGHT;Maximal Thumbnail Height +PREFERENCES_CLEARDLG_LINE1;Clearing cache +PREFERENCES_CLEARDLG_LINE2;This may take a few seconds. +PREFERENCES_CLEARDLG_TITLE;Please wait +PREFERENCES_CLIPPINGIND;Markerings-indikation +PREFERENCES_CMETRICINTENT;Colorimetric Intent +PREFERENCES_DATEFORMAT;Datoformat +PREFERENCES_DATEFORMATHINT;Du kan bruge følgende formattering:\n%y : year\n%m : month\n%d : day\n\nFor example, the hungarian date format is:\n%y/%m/%d +PREFERENCES_DEFAULTLANG;Programsprog +PREFERENCES_DEFAULTTHEME;Standard tema +PREFERENCES_DEMOSAICINGALGO;Demosaikering Algorithme +PREFERENCES_DIRHOME;Hjemmemappe +PREFERENCES_DIRLAST;Sidste besøgte mappe +PREFERENCES_DIROTHER;Anden +PREFERENCES_DIRSELECTDLG;Vælg billedemappe ved opstart... +PREFERENCES_DIRSOFTWARE;Installations-mappe +PREFERENCES_DMETHOD;Metode +PREFERENCES_EDITORCMDLINE;Other command line +PREFERENCES_EXTERNALEDITOR;External editor +PREFERENCES_FALSECOLOR;Falsk farvefortrængningsværdi +PREFERENCES_FBROWSEROPTS;Filfremviser-indstillinger +PREFERENCES_FILEFORMAT;Filformat +PREFERENCES_FORIMAGE;For billedfiler +PREFERENCES_FORRAW;For RAW-filer +PREFERENCES_GIMPPATH;GIMP installation directory +PREFERENCES_GTKTHEME;GTK standard +PREFERENCES_HINT;Tips +PREFERENCES_HLTHRESHOLD;Tærskelværdi for markerede højlys +PREFERENCES_ICCDIR;Mappe til ICC-profiler +PREFERENCES_IMPROCPARAMS;Standard-billedbehandlingsparametre +PREFERENCES_INTENT_ABSOLUTE;Total colorimetric +PREFERENCES_INTENT_PERCEPTUAL;Perceptual +PREFERENCES_INTENT_RELATIVE;Relativ colorimetric +PREFERENCES_INTENT_SATURATION;Mæthed +PREFERENCES_LIVETHUMBNAILS;Live Thumbnails (slower) +PREFERENCES_MONITORICC;Skærmprofil +PREFERENCES_OUTDIR;Outputmappe +PREFERENCES_OUTDIRFOLDER;Save to folder +PREFERENCES_OUTDIRFOLDERHINT;Put the saved images to the seledted folder +PREFERENCES_OUTDIRHINT;Du kan bruge følgende formattering:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nThese formatting strings refer to the directories and sub-paths of the path of the raw file.\n\nFor example, if /home/tom/image/02-09-2006/dsc0012.nefhas been opened, the meaning of the formatting strings are:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nIf you want to save the output image where the original is, write:\n%p1/%f\n\nIf you want to save the output image in a directory 'converted' located the directory of the original, write:\n%p1/converted/%f\n\nIf you want to save the output image in directory '/home/tom/converted' with keeping the same subdirectory of dates, write:\n%p2/converted/%d1/%f +PREFERENCES_OUTDIRTEMPLATE;Use Template +PREFERENCES_OUTDIRTEMPLATEHINT;You can use the following formatting strings:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nThese formatting strings refer to the directories and sub-paths of the path of the raw file.\n\nFor example, if /home/tom/image/02-09-2006/dsc0012.nefhas been opened, the meaning of the formatting strings are:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nIf you want to save the output image where the original is, write:\n%p1/%f\n\nIf you want to save the output image in a directory 'converted' located the directory of the original, write:\n%p1/converted/%f\n\nIf you want to save the output image in directory '/home/tom/converted' with keeping the same subdirectory of dates, write:\n%p2/converted/%d1/%f +PREFERENCES_PARSEDEXT;Parsed Extensions +PREFERENCES_PARSEDEXTADD;Add Extension +PREFERENCES_PARSEDEXTADDHINT;Type an extension and press this button to append list +PREFERENCES_PARSEDEXTDELHINT;Delete selected extension from the list +PREFERENCES_PROFILEHANDLING;Processing Profile Handling +PREFERENCES_PROFILELOADPR;Profile Loading Priority +PREFERENCES_PROFILEPRCACHE;Profile in Cache +PREFERENCES_PROFILEPRFILE;Profile Next to the Input File +PREFERENCES_PROFILESAVECACHE;Save Processing Parameters to the Cache +PREFERENCES_PROFILESAVEINPUT;Save Processing Parameters Next to the Input File +PREFERENCES_PSPATH;Adobe Photoshop installation directory +PREFERENCES_SELECTICCDIRDLG;Vælg ICC-profil mappe... +PREFERENCES_SELECTLANG;Vælg sprog +PREFERENCES_SELECTMONITORPROFDLG;Vælg ICC-profil til skærmen... +PREFERENCES_SELECTTHEME;Vælg tema +PREFERENCES_SHOWBASICEXIF;Vis udvidet Exif-information +PREFERENCES_SHOWDATETIME;Vis dato og tid +PREFERENCES_SHOWONLYRAW;Vis kun RAW-filer +PREFERENCES_SHTHRESHOLD;Tærskelværdi for markerede skygger +PREFERENCES_STARTUPIMDIR;Billedmappe som vises ved opstart +PREFERENCES_TAB_BROWSER;Filfremviser +PREFERENCES_TAB_COLORMGR;FarvehÃ¥ndtering +PREFERENCES_TAB_GENERAL;Generel +PREFERENCES_TAB_IMPROC;Billedbehandling +PREFERENCES_TAB_OUTPUT;Output-indtillinger +PREFERENCES_THUMBSIZE;Miniaturebilledstørrelse +PROFILEPANEL_FILEDLGFILTERANY;Alle filer +PROFILEPANEL_FILEDLGFILTERPP;Billedbehandlings profiler +PROFILEPANEL_LABEL;Billedbehandlings profiler +PROFILEPANEL_LOADDLGLABEL;Ã…bn billedbehandlingsparametre... +PROFILEPANEL_PCUSTOM;Egen +PROFILEPANEL_PFILE;Fra fil +PROFILEPANEL_PLASTPHOTO;Seneste foto +PROFILEPANEL_PLASTSAVED;Seneste gemt +PROFILEPANEL_PROFILE;Profil +PROFILEPANEL_SAVEDLGLABEL;Gem billedbehandlingsparametre... +PROFILEPANEL_TOOLTIPCOPY;Copy current profile to clipboard +PROFILEPANEL_TOOLTIPLOAD;Ã…bn profil fra fil +PROFILEPANEL_TOOLTIPPASTE; Paste profile from clipboard +PROFILEPANEL_TOOLTIPSAVE;Gem nuværende profil +PROGRESSBAR_DECODING;Afkoder Raw-fil... +PROGRESSBAR_DEMOSAICING;Demosaikere... +PROGRESSBAR_LOADING;Ã…bner billede... +PROGRESSBAR_LOADJPEG;Ã…bner JPEG-fil... +PROGRESSBAR_LOADPNG;Ã…bner PNG-fil... +PROGRESSBAR_LOADTIFF;Ã…bner TIFF-fil... +PROGRESSBAR_PROCESSING;Bearbejder Billede... +PROGRESSBAR_READY;Klar. +PROGRESSBAR_SAVEJPEG;Gem JPEG-fil... +PROGRESSBAR_SAVEPNG;Gem PNG-fil... +PROGRESSBAR_SAVETIFF;Gem TIFF-fil... +PROGRESSDLG_LOADING;Loading file... +PROGRESSDLG_PROCESSING;Processing image... +PROGRESSDLG_SAVING;Saving file... +QINFO_FOCALLENGTH;Brændevidde +QINFO_ISO;ISO +QINFO_LENS;Lens +QINFO_NOEXIF;Exifdata utilgængelig. +SAVEDLG_FILEFORMAT;Filformat +SAVEDLG_JPEGQUAL;JPEG-kvalitet +SAVEDLG_JPGFILTER;JPEG-filer +SAVEDLG_PNGCOMPR;PNG-komprimering +SAVEDLG_PNGFILTER;PNG-filer +SAVEDLG_PUTTOQUEUE;Put into processing queue +SAVEDLG_PUTTOQUEUEHEAD;Put to the head of the processing queue +SAVEDLG_PUTTOQUEUETAIL;Put to the end of the processing queue +SAVEDLG_SAVEIMMEDIATELY;Save immediately +SAVEDLG_SAVESPP;Gem billedbehandlingsparameterne med billederne +SAVEDLG_TIFFFILTER;TIFF-filer +TOOLBAR_TOOLTIP_CROP;Vælg beskæringsomrÃ¥de (shortcut key: C) +TOOLBAR_TOOLTIP_HAND;HÃ¥ndværktøj (shortcut key: N) +TOOLBAR_TOOLTIP_STRAIGHTEN;Ret op (shortcut key: S) +TOOLBAR_TOOLTIP_WB;Punkt-hvidbalanse (shortcut key: W) +TP_CACORRECTION_BLUE;BlÃ¥ +TP_CACORRECTION_LABEL;C/A justering +TP_CACORRECTION_RED;Rød +TP_CHMIXER_BLUE;BlÃ¥ +TP_CHMIXER_GREEN;Grøn +TP_CHMIXER_LABEL;Kanalmixer +TP_CHMIXER_RED;Rød +TP_COARSETRAF_DEGREE;grad: +TP_COARSETRAF_TOOLTIP_HFLIP;Vend horisontalt +TP_COARSETRAF_TOOLTIP_ROTLEFT;Rotere mod venster +TP_COARSETRAF_TOOLTIP_ROTRIGHT;Rotere mod højre +TP_COARSETRAF_TOOLTIP_VFLIP;Vend vertikalt +TP_COLORBOOST_ACHANNEL;kanal "a" +TP_COLORBOOST_AMOUNT;Mængde +TP_COLORBOOST_AVOIDCOLORCLIP;UndgÃ¥ farveclipping +TP_COLORBOOST_BCHANNEL;kanal "b" +TP_COLORBOOST_CHAB;a & b +TP_COLORBOOST_CHANNEL;Kanal +TP_COLORBOOST_CHSEPARATE;separat +TP_COLORBOOST_ENABLESATLIMITER;Mæthedsdsgrænse +TP_COLORBOOST_LABEL;Farveforstærkning +TP_COLORBOOST_SATLIMIT;Mæthedssgrænse +TP_COLORDENOISE_EDGESENSITIVE;Kantfølsomhed +TP_COLORDENOISE_EDGETOLERANCE;Kanttolerance +TP_COLORDENOISE_LABEL;Farvestøj-reducering +TP_COLORDENOISE_RADIUS;Radius +TP_COLORSHIFT_BLUEYELLOW;BlÃ¥-Gul +TP_COLORSHIFT_GREENMAGENTA;Grøn-Magenta +TP_COLORSHIFT_LABEL;Farveskifte +TP_CROP_DPI;DPI= +TP_CROP_FIXRATIO;Fast proportion +TP_CROP_GTDIAGONALS;Diagonalreglen +TP_CROP_GTHARMMEANS1;Harmonic means 1 +TP_CROP_GTHARMMEANS2;Harmonic means 2 +TP_CROP_GTHARMMEANS3;Harmonic means 3 +TP_CROP_GTHARMMEANS4;Harmonic means 4 +TP_CROP_GTNONE;Ingen +TP_CROP_GTRULETHIRDS;Tredjedelsreglen +TP_CROP_GUIDETYPE;Guidetype: +TP_CROP_H;H +TP_CROP_LABEL;Beskæring +TP_CROP_SELECTCROP; Vælg beskæringsomrÃ¥de +TP_CROP_W;B +TP_CROP_X;x +TP_CROP_Y;y +TP_DISTORTION_AMOUNT;Mængde +TP_DISTORTION_LABEL;Forvrængning +TP_EXPOSURE_AUTOLEVELS;Auto niveau +TP_EXPOSURE_BLACKLEVEL;Sort +TP_EXPOSURE_BRIGHTNESS;Lysstyrke +TP_EXPOSURE_CLIP;Clip +TP_EXPOSURE_COMPRHIGHLIGHTS;Højlyskomprimering +TP_EXPOSURE_COMPRSHADOWS;Skyggekomprimering +TP_EXPOSURE_CONTRAST;Kontrast +TP_EXPOSURE_CURVEEDITOR;Tonekurve +TP_EXPOSURE_EXPCOMP;Eks. Komp. +TP_EXPOSURE_LABEL;Eksponering +TP_HLREC_CIELAB;CIELab Blending +TP_HLREC_COLOR;Farvespedning +TP_HLREC_LABEL;Højlys-forbedring +TP_HLREC_LUMINANCE;Forbedring af luminans +TP_HLREC_METHOD;Metode: +TP_ICM_FILEDLGFILTERANY;Alle filer +TP_ICM_FILEDLGFILTERICM;ICC profilfiler +TP_ICM_GAMMABEFOREINPUT;Profilen tilføjer Gamma +TP_ICM_INPUTCAMERA;Kameravalg +TP_ICM_INPUTCUSTOM;Egen +TP_ICM_INPUTDLGLABEL;Vælg indgangs ICC-profil... +TP_ICM_INPUTEMBEDDED;Anvend intern, hvis muligt +TP_ICM_INPUTPROFILE;Indgangprofil +TP_ICM_LABEL;ICM +TP_ICM_NOICM;Ingen ICM: sRGB-profil +TP_ICM_OUTPUTDLGLABEL;Select Vælg udgangs ICC-profil... +TP_ICM_OUTPUTPROFILE;Udgangsprofil +TP_ICM_SAVEREFERENCE;Gem reference billede til profil +TP_ICM_WORKINGPROFILE;Arbejdsprofil +TP_LUMACURVE_BLACKLEVEL;Sort +TP_LUMACURVE_BRIGHTNESS;Lysstyrke +TP_LUMACURVE_COMPRHIGHLIGHTS;Højlyskomprimering +TP_LUMACURVE_COMPRSHADOWS;Skyggekomprimering +TP_LUMACURVE_CONTRAST;Kontrast +TP_LUMACURVE_CURVEEDITOR;Luminanskurve +TP_LUMACURVE_LABEL;Luminanskurve +TP_LUMADENOISE_EDGETOLERANCE;Kanttolerance +TP_LUMADENOISE_LABEL;Luminans-støjreducering +TP_LUMADENOISE_RADIUS;Radius +TP_RESIZE_BICUBIC;Bicubic +TP_RESIZE_BICUBICSF;Bicubic (Blødere) +TP_RESIZE_BICUBICSH;Bicubic (Skarpere) +TP_RESIZE_BILINEAR;Bilinjær +TP_RESIZE_FULLSIZE;Billedstørrelse: +TP_RESIZE_H;H: +TP_RESIZE_LABEL;Ændre størrelse +TP_RESIZE_METHOD;Metode: +TP_RESIZE_NEAREST;Nærmeste +TP_RESIZE_SCALE;Skala +TP_RESIZE_W;B: +TP_ROTATE_AUTOCROP;Autobeskæring +TP_ROTATE_DEGREE;Antal grader +TP_ROTATE_FILL;Fyld +TP_ROTATE_LABEL;Ret op +TP_ROTATE_SELECTLINE; Vælg lige linje +TP_SHADOWSHLIGHTS_HIGHLIGHTS;Højlys +TP_SHADOWSHLIGHTS_HLTONALW;Toneomfang +TP_SHADOWSHLIGHTS_LABEL;Skygger/højlys +TP_SHADOWSHLIGHTS_LOCALCONTR;Lokal kontrast +TP_SHADOWSHLIGHTS_RADIUS;Radius +TP_SHADOWSHLIGHTS_SHADOWS;Skygger +TP_SHADOWSHLIGHTS_SHTONALW;Toneomfang +TP_SHARPENING_AMOUNT;Mængde +TP_SHARPENING_EDRADIUS;Radius +TP_SHARPENING_EDTOLERANCE;Kanttolerance +TP_SHARPENING_HALOCONTROL;Halo-kontrol +TP_SHARPENING_HCAMOUNT;Mængde +TP_SHARPENING_LABEL;Skarphed +TP_SHARPENING_METHOD;Metode +TP_SHARPENING_ONLYEDGES;Skarphed kun i kanter +TP_SHARPENING_RADIUS;Radius +TP_SHARPENING_RLD;RL Dekonvolution +TP_SHARPENING_RLD_AMOUNT;Mængde +TP_SHARPENING_RLD_DAMPING;Dæmpning +TP_SHARPENING_RLD_ITERATIONS;Gentagelse +TP_SHARPENING_THRESHOLD;Tærskelværdi +TP_SHARPENING_USM;Uskarp maske +TP_VIGNETTING_AMOUNT;Mængde +TP_VIGNETTING_LABEL;Vignetterings-korrigering +TP_VIGNETTING_RADIUS;Radius +TP_WBALANCE_AUTO;Auto +TP_WBALANCE_CAMERA;Kamera +TP_WBALANCE_CUSTOM;Egen +TP_WBALANCE_GREEN;Nuance +TP_WBALANCE_LABEL;Hvidbalance +TP_WBALANCE_METHOD;Metode +TP_WBALANCE_SIZE;Størrelse: +TP_WBALANCE_SPOTWB;Punkt HB +TP_WBALANCE_TEMPERATURE;Temperatur +ZOOMBAR_DETAIL;Lup +ZOOMBAR_HUGE;Ekstra stor +ZOOMBAR_LARGE;Stor +ZOOMBAR_NORMAL;Normal +ZOOMBAR_PREVIEW;Filgennemsyn +ZOOMBAR_SCALE;Skala +ZOOMBAR_SMALL;Lille diff --git a/release/languages/deutsch b/release/languages/deutsch new file mode 100755 index 000000000..da909df39 --- /dev/null +++ b/release/languages/deutsch @@ -0,0 +1,584 @@ +# Deutsch: Deutschland +# 20.12.2007 +# (phberlin; basiert auf keenonkites' Erstübersetzung) +# 22.12.2007 +# (keenonkites; Aktualisierte Version für 2.3 beta2) +# 08.01.2008/15.01.2008/20.02.2008 +# Leichte Anpassungen (keenonkites/klonk) +# 4.4.2008: Anpassungen für 2.4 +# 20.9.2008: keenonkites, Anpassungen für 2.4m2 +# 19.12.2008: keenonkites, Anpassungen für 2.4beta4 +ADJUSTER_RESET_TO_DEFAULT;Zurück zum Standard +CURVEEDITOR_FILEDLGFILTERANY;Alle Dateien +CURVEEDITOR_FILEDLGFILTERCURVE;Kurvendateien +CURVEEDITOR_LINEAR;Linear +CURVEEDITOR_LOADDLGLABEL;Kurve Laden... +CURVEEDITOR_SAVEDLGLABEL;Kurve Speichern... +CURVEEDITOR_TOOLTIPLINEAR;Zurücksetzen der Kurve (linear) +CURVEEDITOR_TOOLTIPLOAD;Laden einer Kurve +CURVEEDITOR_TOOLTIPSAVE;Speichern der aktuellen Kurve +EXIFFILTER_APERTURE;Blende +EXIFFILTER_CAMERA;Kamera +EXIFFILTER_DIALOGLABEL;Exif Filter +EXIFFILTER_FOCALLEN;Brennweite +EXIFFILTER_ISO;ISO +EXIFFILTER_LENS;Objektiv +EXIFFILTER_SHUTTER;Verschlusszeit +EXIFPANEL_ADDEDIT;Neu/Ändern +EXIFPANEL_ADDEDITHINT;Hinzufügen eines neuen oder Ändern eines bestehenden Attributs +EXIFPANEL_ADDTAGDLG_ENTERVALUE;Wert eingeben +EXIFPANEL_ADDTAGDLG_SELECTTAG;Attribut wählen +EXIFPANEL_ADDTAGDLG_TITLE;Attribut hinzufügen/ändern +EXIFPANEL_KEEP;Behalten +EXIFPANEL_KEEPHINT;Behalten der gewählten Attribute beim Erzeugen des Bildes +EXIFPANEL_REMOVE;Entfernen +EXIFPANEL_REMOVEHINT;Entfernen der gewählten Attributen beim Erzeugen des Bildes +EXIFPANEL_RESET;Zurücksetzen +EXIFPANEL_RESETALL;Alle zurücksetzen +EXIFPANEL_RESETALLHINT;Alle Attribute zu den ursrpünglichen Werten zurücksetzen +EXIFPANEL_RESETHINT;Gewählte Attribute zu den ursprünglich Werten zurücksetzen +EXIFPANEL_SUBDIRECTORY;Unterverzeichnis +FILEBROWSER_APPLYPROFILE;Profil anwenden +FILEBROWSER_ARRANGEMENTHINT;Wechseln zwischen vertikaler und horizontaler Ausrichtung der Voransichten +FILEBROWSER_CLEARPROFILE;Profil löschen +FILEBROWSER_COPYPROFILE;Profil kopieren +FILEBROWSER_DELETEDLGLABEL;Bestätige Löschen von Dateien +FILEBROWSER_DELETEDLGMSG;Wollen sie wirklich %1 Dateien löschen? +FILEBROWSER_EMPTYTRASH;Papierkorb leeren +FILEBROWSER_EMPTYTRASHHINT;Endgültiges Löschen der Dateien im Papierkorb +FILEBROWSER_EXIFFILTERAPPLY;Anwenden +FILEBROWSER_EXIFFILTERAPPLYHINT;Ein-/Ausschalten des Exif Filters im Datei-Browser +FILEBROWSER_EXIFFILTERLABEL;Exif Filter +FILEBROWSER_EXIFFILTERSETTINGS;Einstellungen +FILEBROWSER_EXIFFILTERSETTINGSHINT;Ändern der Einstellungen des Exif Filters +FILEBROWSER_PARTIALPASTEPROFILE;Profil selektiv einfügen +FILEBROWSER_PASTEPROFILE;Profil einfügen +FILEBROWSER_POPUPCANCELJOB;Job abbrechen +FILEBROWSER_POPUPMOVEEND;Ans Ende der Warteschlange verschieben +FILEBROWSER_POPUPMOVEHEAD;An den Anfang der Warteschlange verschieben +FILEBROWSER_POPUPOPEN;Öffnen +FILEBROWSER_POPUPPROCESS;Bild zur Warteschlange hinzufügen +FILEBROWSER_POPUPRANK1;Mit 1 Stern bewerten +FILEBROWSER_POPUPRANK2;Mit 2 Sternen bewerten +FILEBROWSER_POPUPRANK3;Mit 3 Sternen bewerten +FILEBROWSER_POPUPRANK4;Mit 4 Sternen bewerten +FILEBROWSER_POPUPRANK5;Mit 5 Sternen bewerten +FILEBROWSER_POPUPREMOVE;Aus dem Verzeichnis Löschen +FILEBROWSER_POPUPRENAME;Umbenennen +FILEBROWSER_POPUPSELECTALL;Alle auswählen +FILEBROWSER_POPUPTRASH;In den Papierkorb verschieben +FILEBROWSER_POPUPUNRANK;Entfernen der Bewertung +FILEBROWSER_POPUPUNTRASH;Aus dem Papierkorb retten +FILEBROWSER_PROCESSINGSETTINGS;Einstellungen +FILEBROWSER_PROCESSINGSETTINGSHINT;Einstellen von Ausgabeformat und Ausgabeverzeichnis +FILEBROWSER_RENAMEDLGLABEL;Datei umbenennen +FILEBROWSER_RENAMEDLGMSG;Umbenennen der Datei "%1" nach: +FILEBROWSER_SHOWDIRHINT;Alle Bilder im Verzeichnis zeigen +FILEBROWSER_SHOWQUEUEHINT;Inhalt der Warteschlange zeigen +FILEBROWSER_SHOWRANK1HINT;Bilder 1 Stern zeigen +FILEBROWSER_SHOWRANK2HINT;Bilder 2 Stern zeigen +FILEBROWSER_SHOWRANK3HINT;Bilder 3 Stern zeigen +FILEBROWSER_SHOWRANK4HINT;Bilder 4 Stern zeigen +FILEBROWSER_SHOWRANK5HINT;Bilder 5 Stern zeigen +FILEBROWSER_SHOWTRASHHINT;Bilder im Papierkorb zeigen +FILEBROWSER_SHOWUNRANKHINT;Unbewertete Bilder zeigen +FILEBROWSER_STARTPROCESSING;Verarbeitung starten +FILEBROWSER_STARTPROCESSINGHINT;Verarbeitung/Speichern der Bilder in der Warteschlange starten +FILEBROWSER_STOPPROCESSING;Verarbeitung stoppen +FILEBROWSER_STOPPROCESSINGHINT;Verarbeitung der Bilder stoppen +FILEBROWSER_THUMBSIZE;Grösse d. Vorschau +FILEBROWSER_ZOOMINHINT;Vergrössern der Vorschau +FILEBROWSER_ZOOMOUTHINT;Verkleinern der Vorschau +GENERAL_ABOUT;Über +GENERAL_CANCEL;Abbruch +GENERAL_DISABLE;ausschalten +GENERAL_DISABLED;ausgeschaltet +GENERAL_ENABLE;einschalten +GENERAL_ENABLED;eingeschaltet +GENERAL_LANDSCAPE;Quer +GENERAL_LOAD;Laden +GENERAL_NA;n/a +GENERAL_NO;Nein +GENERAL_OK;OK +GENERAL_PORTRAIT;Hoch +GENERAL_SAVE;Speichern +GENERAL_YES;Ja +HISTOGRAM_LABEL;Histogram +HISTOGRAM_TOOLTIP_B;Zeigen/Verstecke BLAU-Histogramm +HISTOGRAM_TOOLTIP_G;Zeigen/Verstecke GRÜN-Histogramm +HISTOGRAM_TOOLTIP_L;Zeigen/Verstecke CIELAB-Luminanz-Histogramm +HISTOGRAM_TOOLTIP_R;Zeigen/Verstecke ROT-Histogramm +HISTORY_CHANGED;Verändert +HISTORY_CUSTOMCURVE;Benutzerdefinierte Kurve +HISTORY_DELSNAPSHOT;Variante löschen +HISTORY_FROMCLIPBOARD;Aus der Zwischenablage +HISTORY_LABEL;Abfolge der Änderungen +HISTORY_MSG_10;Schatten-Kompression +HISTORY_MSG_11;Tonwertkurve +HISTORY_MSG_12;Automatische Belichtung +HISTORY_MSG_13;Belichtungsbeschneidung +HISTORY_MSG_14;Luminanz Helligkeit +HISTORY_MSG_15;Luminanz Kontrast +HISTORY_MSG_16;Luminanz Schwarz +HISTORY_MSG_17;Luminanz Lichter-Kompression +HISTORY_MSG_18;Luminanz Schatten-Kompression +HISTORY_MSG_19;Luminanz Kurve +HISTORY_MSG_1;Bild geladen +HISTORY_MSG_20;Schärfen +HISTORY_MSG_21;Schärfen Radius +HISTORY_MSG_22;Schärfen Menge +HISTORY_MSG_23;Schärfen Schwellwert +HISTORY_MSG_24;Schärfen nur Kanten +HISTORY_MSG_25;Schärfen Kantensuche Radius +HISTORY_MSG_26;Schärfen Kanten-Toleranz +HISTORY_MSG_27;Schärfen Halo-Kontrolle +HISTORY_MSG_28;Schärfen Halo-Kontrolle Menge +HISTORY_MSG_29;Schärfen Methode +HISTORY_MSG_2;Profil geladen +HISTORY_MSG_30;Dekonvolution Radius +HISTORY_MSG_31;Dekonvolution Menge +HISTORY_MSG_32;Dekonvolution Dämpfung +HISTORY_MSG_33;Dekonvolution Iterationen +HISTORY_MSG_34;Verhindere Farbbeschneidungen +HISTORY_MSG_35;Begrenzung der Sättigung +HISTORY_MSG_36;Sättigungsgrenzwert +HISTORY_MSG_37;Farbverstärkung +HISTORY_MSG_38;Weißabgleich Methode +HISTORY_MSG_39;Farbtemperatur +HISTORY_MSG_3;Profil geändert +HISTORY_MSG_40;Weißabgleich Farbton +HISTORY_MSG_41;Farbkorrektur "A" +HISTORY_MSG_42;Farbkorrektur "B" +HISTORY_MSG_43;Luminanz-Rauschfilter +HISTORY_MSG_44;Luminanz-Rauschfilter Radius +HISTORY_MSG_45;Luminanz-Rauschfilter Kantentoleranz +HISTORY_MSG_46;Farb-Rauschfilter +HISTORY_MSG_47;Farb-Rauschfilter Radius +HISTORY_MSG_48;Farb-Rauschfilter Kantentoleranz +HISTORY_MSG_49;Farb-Rauschfilter Kantensuche +HISTORY_MSG_4;Abfolge der Änderungen durchsehen +HISTORY_MSG_50;Schatten/Lichter-Werkzeug +HISTORY_MSG_51;Abschwächen der Lichter +HISTORY_MSG_52;Verstärken der Schatten +HISTORY_MSG_53;Tonweite Lichter +HISTORY_MSG_54;Tonweite Schatten +HISTORY_MSG_55;Lokaler Kontrast +HISTORY_MSG_56;Schatten/Lichter-Radius +HISTORY_MSG_57;grobe Drehung +HISTORY_MSG_58;Horizontal spiegeln +HISTORY_MSG_59;Vertikal spiegeln +HISTORY_MSG_5;Helligkeit +HISTORY_MSG_60;Drehung +HISTORY_MSG_61;Drehung +HISTORY_MSG_62;Objektiv-Verzerrungskorrektur +HISTORY_MSG_63;Variante gewählt +HISTORY_MSG_64;Bild beschneiden +HISTORY_MSG_65;Farbsaum-Entfernung +HISTORY_MSG_66;Lichter wiederherstellen +HISTORY_MSG_67;Lichter wiederherstellen Menge +HISTORY_MSG_68;Lichter wiederherstellen Methode +HISTORY_MSG_69;Aktueller Farbraum +HISTORY_MSG_6;Kontrast +HISTORY_MSG_70;Farbraum für Ausgabe +HISTORY_MSG_71;Farbraum für Eingabe +HISTORY_MSG_72;Korrektur Randlichtabfall +HISTORY_MSG_73;Kanal-Mixer +HISTORY_MSG_74;Änderung Größe - Maßstab +HISTORY_MSG_75;Änderung Größe - Methode +HISTORY_MSG_76;Exif Metadaten +HISTORY_MSG_77;IPTC Metadaten +HISTORY_MSG_7;Schwarz +HISTORY_MSG_8;Belichtungskorrektur +HISTORY_MSG_9;Lichter-Kompression +HISTORY_NEWSNAPSHOT;Neue Variante +HISTORY_NEWSNAPSHOTAS;als... +HISTORY_NEWSSDIALOGLABEL;Name der Variante: +HISTORY_NEWSSDIALOGTITLE;Variante hinzufügen +HISTORY_SETTO;Setzen auf +HISTORY_SNAPSHOT;Variante +HISTORY_SNAPSHOTS;Varianten +ICMPANEL_FILEDLGFILTERANY;Alle Dateien +ICMPANEL_FILEDLGFILTERICM;ICC-Profildatei +ICMPANEL_GAMMABEFOREINPUT;Profil enthält Gammaanpassung +ICMPANEL_INPUTCAMERA;Kamera-Standard +ICMPANEL_INPUTCUSTOM;Benutzerdefiniert +ICMPANEL_INPUTDLGLABEL;Wähle Eingabe-ICC-Profil... +ICMPANEL_INPUTEMBEDDED;Verwende eingebettetes, wenn möglich +ICMPANEL_INPUTPROFILE;Eingabeprofil +ICMPANEL_NOICM;Kein ICM: sRGB-Ausgabe +ICMPANEL_OUTPUTDLGLABEL;Wähle Ausgabe-ICC-Profil... +ICMPANEL_OUTPUTPROFILE;Ausgabeprofil +ICMPANEL_SAVEREFERENCE;Speichere Referenzbild für die Profilierung +ICMPANEL_WORKINGPROFILE;Arbeitsfarbraum +IMAGEAREA_DETAILVIEW;Detailansicht +IPTCPANEL_AUTHOR;Autor +IPTCPANEL_AUTHORHINT;Name des Autors, z.B. Name des Fotografen oder des Künstlers (By-line). +IPTCPANEL_AUTHORSPOSITION;Position des Autors +IPTCPANEL_AUTHORSPOSITIONHINT;Titel des Autors oder der Autoren (By-line Title). +IPTCPANEL_CAPTION;Bildbeschreibung +IPTCPANEL_CAPTIONHINT;Beschreibung des Bildinhaltes (Caption - Abstract) +IPTCPANEL_CAPTIONWRITER;Autor der Bildbeschreibung +IPTCPANEL_CAPTIONWRITERHINT;Name der beim Schreiben, Editieren oder Korrigieren des Bildes oder der Bildbeschreibung beteiligten Person (Writer - Editor). +IPTCPANEL_CATEGORY;Kategorie +IPTCPANEL_CATEGORYHINT;3-stelliger Code, der die Kategorie des Bildes beschreibt (Category). +IPTCPANEL_CITY;Stadt +IPTCPANEL_CITYHINT;Aufnahmeort: Stadt (City). +IPTCPANEL_COPYHINT;IPTC Werte in die Zwischenablage kopieren +IPTCPANEL_COPYRIGHT;Copyright +IPTCPANEL_COPYRIGHTHINT;Alle nötigen Hinweise über Urheberrechte (Copyright Notice). +IPTCPANEL_COUNTRY;Land +IPTCPANEL_COUNTRYHINT;Aufnahmeort: Land (Country - Primary Location Name). +IPTCPANEL_CREDIT;Bildrechte +IPTCPANEL_CREDITHINT;Identifiziert den Anbieter des Bildes, es muss nicht der Eigentümer sein (Credit). +IPTCPANEL_DATECREATED;Erstellt am +IPTCPANEL_DATECREATEDHINT;Das Datum an dem der Inhalt des Bildes kreiert wurde; Format: JJJJMMTT (Date Created). +IPTCPANEL_EMBEDDED;Eingebettete +IPTCPANEL_EMBEDDEDHINT;Zu den im Bild eingebetteten Werten zurücksetzen. +IPTCPANEL_HEADLINE;Bildtitel +IPTCPANEL_HEADLINEHINT;Kurzform der Bildbeschreibung, könnte als Überschrift an das Bild geklebt werden (Headline). +IPTCPANEL_INSTRUCTIONS;Hinweise +IPTCPANEL_INSTRUCTIONSHINT;Besondere Hinweise bezüglich der Verwendung des Bildes (Special Instructions). +IPTCPANEL_KEYWORDS;Schlagwörter +IPTCPANEL_KEYWORDSHINT;Stichwörter für das spätere Wiederfinden der Bilder (Keywords). +IPTCPANEL_PASTEHINT;Einfügen der IPTC Werte aus der Zwischenablage +IPTCPANEL_PROVINCE;Provinz +IPTCPANEL_PROVINCEHINT;Aufnahmeort: Provinz (Province-State). +IPTCPANEL_RESET;Zurücksetzen +IPTCPANEL_RESETHINT;Zu den im Profil gesetzten Werten zurücksetzen. +IPTCPANEL_SOURCE;Quelle +IPTCPANEL_SOURCEHINT;Der ursprüngliche Eigentümer des Werkes auf dem Bild (Source). +IPTCPANEL_SUPPCATEGORIES;Zusätz. Kategorien +IPTCPANEL_SUPPCATEGORIESHINT;Frei wählbare zusätzliche Kategorien (Supplemental Categories). +IPTCPANEL_TITLE;Titel +IPTCPANEL_TITLEHINT;Kurztitel des Bildes (Object Name). +IPTCPANEL_TRANSREFERENCE;Übertragungs Referenz +IPTCPANEL_TRANSREFERENCEHINT;Ein Code, der den ursprünglichen Ort der Übertragung definiert (Original Transmission Reference). +MAIN_BUTTON_PREFERENCES;Einstellungen +MAIN_BUTTON_SAVE;Bild speichern +MAIN_BUTTON_SAVEAS;unter... +MAIN_BUTTON_SENDTOEDITOR;Im Editor laden +MAIN_MSG_ALREADYEXISTS;Diese Datei existiert schon. +MAIN_MSG_CANNOTLOAD;Bild kann nicht geladen werden +MAIN_MSG_CANNOTSAVE;Fehler beim Speichern +MAIN_MSG_CANNOTSTARTEDITOR;Der Editor kann nicht gestartet werden. +MAIN_MSG_CANNOTSTARTEDITOR_SECONDARY;Setzen Sie bitte den richtigen Pfad in den Einstellungen. +MAIN_MSG_EXITJOBSINQUEUEINFO;Unverarbeitete Bilder in der Warteschlange gehen beim Verlassen der Anwendung verloren. +MAIN_MSG_EXITJOBSINQUEUEQUEST;Wollen Sie die Anwendung wirklich schliessen ? Es hat noch unverarbeitete Bilder in der Warteschlange. +MAIN_MSG_JOBSINQUEUE;Job in Bearbeitung +MAIN_MSG_QOVERWRITE;Wollen sie die Datei überschreiben ? +MAIN_TAB_BASIC;Basis +MAIN_TAB_COLOR;Farbe +MAIN_TAB_DETAIL;Detail +MAIN_TAB_EXIF;Exif +MAIN_TAB_EXPOSURE;Belichtung +MAIN_TAB_ICM;ICM +MAIN_TAB_IPTC;IPTC +MAIN_TAB_METADATA;Metadata +MAIN_TAB_TRANSFORM;Verändern +MAIN_TOOLTIP_HIDEFP;Zeigen/Verstecken von Verzeichnis- und Datei-Browser (Taste F) +MAIN_TOOLTIP_HIDEHP;Zeigen/Verstecken linke Seite (Abfolge der Änderungen, Taste H) +MAIN_TOOLTIP_INDCLIPPEDH;zu helle Bereiche blinken +MAIN_TOOLTIP_INDCLIPPEDS;zu dunkle Bereiche blinken +MAIN_TOOLTIP_PREFERENCES;Einstellungen ändern +MAIN_TOOLTIP_QINFO;Kurze Info über das Bild +MAIN_TOOLTIP_SAVE;Speichere Bild im Standard-Verzeichnis +MAIN_TOOLTIP_SAVEAS;Speichere Bild in anderem Verzeichnis +PARTIALPASTE_BASICGROUP;Gruppe Basiseinstellungen +PARTIALPASTE_CACORRECTION;Farbsaum-Entfernung +PARTIALPASTE_COARSETRANS;90 Grad Rotieren / Spiegeln +PARTIALPASTE_COLORBOOST;Farbverstärkung +PARTIALPASTE_COLORDENOISE;Farb-Rauschfilter +PARTIALPASTE_COLORGROUP;Gruppe Farbeinstellungen +PARTIALPASTE_COLORMIXER;Kanal-Mixer +PARTIALPASTE_COLORSHIFT;Farbverschiebung +PARTIALPASTE_COMPOSITIONGROUP;Gruppe Gestaltungseinstellungen +PARTIALPASTE_CROP;Ausschnitt +PARTIALPASTE_DIALOGLABEL;Selektives Einfügen des Bearbeitungsprofiles +PARTIALPASTE_DISTORTION;Entzerrung +PARTIALPASTE_EXIFCHANGES;Exifdaten Änderungen +PARTIALPASTE_EXPOSURE;Belichtung +PARTIALPASTE_HLRECOVERY;Lichter wiederherstellen +PARTIALPASTE_ICMSETTINGS;Einstellungen ICM +PARTIALPASTE_IPTCINFO;IPTC Informationen +PARTIALPASTE_LENSGROUP;Gruppe Farbeinstellungen +PARTIALPASTE_LUMACURVE;Luminanzkurve +PARTIALPASTE_LUMADENOISE;Luminanz-Rauschfilter +PARTIALPASTE_LUMINANCEGROUP;Gruppe Luminanzeinstellungen +PARTIALPASTE_METAICMGROUP;Gruppe Einstellungen Metadaten/ICM +PARTIALPASTE_RESIZE;Grösse ändern +PARTIALPASTE_ROTATION;Drehen +PARTIALPASTE_SHADOWSHIGHLIGHTS;Schatten/Lichter +PARTIALPASTE_SHARPENING;Schärfen +PARTIALPASTE_VIGNETTING;Korrektur Randlichtabfall +PARTIALPASTE_WHITEBALANCE;Weissabgleich +PREFERENCES_APPLNEXTSTARTUP;beim nächsten Programmstart aktiv +PREFERENCES_BLINKCLIPPED;Zu helle/zu dunkle Bereiche blinken +PREFERENCES_CACHECLEARALL;Alles Löschen +PREFERENCES_CACHECLEARPROFILES;Löschen der Profile +PREFERENCES_CACHECLEARTHUMBS;Löschen der Voransichten +PREFERENCES_CACHEFORMAT1;Proprietär (schneller und höhere Qualität) +PREFERENCES_CACHEFORMAT2;JPEG (geringerer Diskplatz) +PREFERENCES_CACHEMAXENTRIES;Maximale Anzahl der Einträge im Zwischenspeicher +PREFERENCES_CACHEOPTS;Einstellungen des Zwischenspeichers für die Voransichten (Cache) +PREFERENCES_CACHESTRAT1;Priorität auf Geschwindigkeit (erhöhter Speicherverbrauch) +PREFERENCES_CACHESTRAT2;Priorität auf minimierten Speicherverbrauch (geringere Geschwindigkeit) +PREFERENCES_CACHESTRAT;Strategie des Zwischenspeichers +PREFERENCES_CACHETHUMBFORM;Format des Zwischenspeichers +PREFERENCES_CACHETHUMBHEIGHT;Maximale Höhe der Voransichten +PREFERENCES_CLEARDLG_LINE1;Löschen des Zwischenspeichers +PREFERENCES_CLEARDLG_LINE2;Das kann einige Sekunden dauern. +PREFERENCES_CLEARDLG_TITLE;Bitte warten +PREFERENCES_CLIPPINGIND;Anzeige zu helle/zu dunkle Bereiche +PREFERENCES_CMETRICINTENT;Farbraumtransformation +PREFERENCES_DATEFORMAT;Datumsformat +PREFERENCES_DATEFORMATHINT;Die folgenden Variablen können verwendet werden:\n%y : Jahr\n%m : Monat\n%d : Tag\n\nDas Deutsche Datumsformat zum Beispiel ist:\n%d/%m/%y +PREFERENCES_DEFAULTLANG;Sprache für die Menüs und Dialoge +PREFERENCES_DEFAULTTHEME;Standard Oberflächendesign +PREFERENCES_DEMOSAICINGALGO;Algorithmus zur Entrasterung +PREFERENCES_DIRHOME;Benutzer-Verzeichnis +PREFERENCES_DIRLAST;Zuletzt geöffnetes Verzeichnis +PREFERENCES_DIROTHER;Anderes +PREFERENCES_DIRSELECTDLG;Wähle das Bild-Verzeichnis beim Programmstart... +PREFERENCES_DIRSOFTWARE;Installationsverzeichnis +PREFERENCES_DMETHOD;Methode +PREFERENCES_EDITORCMDLINE;Andere Befehlszeile +PREFERENCES_EXTERNALEDITOR;Externer Editor +PREFERENCES_FALSECOLOR;Stufen zur Unterdrückung von Falschfarben +PREFERENCES_FBROWSEROPTS;Datei-Browser-Einstellungen +PREFERENCES_FILEFORMAT;Datei-Format +PREFERENCES_FORIMAGE;Für Bild-Dateien +PREFERENCES_FORRAW;Für RAW-Dateien +PREFERENCES_GIMPPATH;GIMP Installations Verzeichnis +PREFERENCES_GTKTHEME;Standard GTK +PREFERENCES_HINT;Erklärungen +PREFERENCES_HLTHRESHOLD;Schwellwert - zu hell +PREFERENCES_ICCDIR;ICC-Profile-Verzeichnis +PREFERENCES_IMPROCPARAMS;Standard-Bildbearbeitungsparameter +PREFERENCES_INTENT_ABSOLUTE;Absolut farbmetrisch +PREFERENCES_INTENT_PERCEPTUAL;Wahrnehmungsabhängig +PREFERENCES_INTENT_RELATIVE;Relative farbmetrisch +PREFERENCES_INTENT_SATURATION;Sättigung +PREFERENCES_LIVETHUMBNAILS;Live Voransichten (langsamer) +PREFERENCES_MONITORICC;Monitor-Profil +PREFERENCES_OUTDIR;Ausgabe-Verzeichnis +PREFERENCES_OUTDIRFOLDER;Speichern in Verzeichnis +PREFERENCES_OUTDIRFOLDERHINT;Ablegen der gespeicherten Bilder in ein ausgewähltes Verzeichnis +PREFERENCES_OUTDIRHINT;Die folgenden Variablen können verwendet werden:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nDiese Variablen referenzieren die Verzeichnisse und Unterverzeichnisse des Pfades in dem das RAW liegt.\n\nWenn zum Beispiele /home/tom/image/02-09-2006/dsc0012.nefgeöffnet wurde, dann haben die Variablen den folgenden Inhalt:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nWenn Sie die Ausgabedatei in das selbe Verzeichnis wie das RAW speichern wollen, dann wählen Sie:\n%p1/%f\n\nWenn sie die Ausgabedatei in ein Unterverzeichnis mit dem Namen 'konvertiert' schreiben wollen, wählen sie:\n%p1/konvertiert/%f\n\nWenn Sie die Ausgabedatei im Verzeichnis '/home/tom/converted' unter beibehaltung des letzen Verzeichnisses wo das RAW lag, dann wählen sie:\n%p2/converted/%d1/%f +PREFERENCES_OUTDIRTEMPLATE;Verwenden einer Vorlage +PREFERENCES_OUTDIRTEMPLATEHINT;Die folgenden Variablen können verwendet werden:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nDiese Variablen referenzieren die Verzeichnisse und Unterverzeichnisse des Pfades in dem das RAW liegt.\n\nWenn zum Beispiele /home/tom/image/02-09-2006/dsc0012.nefgeöffnet wurde, dann haben die Variablen den folgenden Inhalt:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nWenn Sie die Ausgabedatei in das selbe Verzeichnis wie das RAW speichern wollen, dann wählen Sie:\n%p1/%f\n\nWenn sie die Ausgabedatei in ein Unterverzeichnis mit dem Namen 'konvertiert' schreiben wollen, wählen sie:\n%p1/konvertiert/%f\n\nWenn Sie die Ausgabedatei im Verzeichnis '/home/tom/converted' unter beibehaltung des letzen Verzeichnisses wo das RAW lag, dann wählen sie:\n%p2/converted/%d1/%f +PREFERENCES_PARSEDEXT;Im Datei-Browser angezeigte Datei-Typen +PREFERENCES_PARSEDEXTADD;Datei-Typ hinzufügen +PREFERENCES_PARSEDEXTADDHINT;Gebe einen Datei-Typ (Extension) ein und drücke diesen Knopf um diesen Typ hinzuzufügen +PREFERENCES_PARSEDEXTDELHINT;Lösche den ausgewählten Datei-Typ von der Liste +PREFERENCES_PROFILEHANDLING;Behandlung der Bearbeitungsprofile +PREFERENCES_PROFILELOADPR;Priorität der Profile beim Laden +PREFERENCES_PROFILEPRCACHE;Bearbeitungsprofil im Zwischenspeicher (Cache) +PREFERENCES_PROFILEPRFILE;Bearbeitungsprofile bei der urpsrünglich geladenen Datei +PREFERENCES_PROFILESAVECACHE;Speichern der Verarbeitungsparameter im Zwischenspeicher (Cache) +PREFERENCES_PROFILESAVEINPUT;Speichern der Verarbeitungsparameter zusammen mit der ursprünglich geladenen Datei +PREFERENCES_PSPATH;Adobe Photoshop Installations Verzeichnis +PREFERENCES_SELECTICCDIRDLG;Wähle ICC-Profile-Verzeichnis... +PREFERENCES_SELECTLANG;Sprache +PREFERENCES_SELECTMONITORPROFDLG;Wähle ICC-Profil für den Monitor... +PREFERENCES_SELECTTHEME;Wähle Oberflächendesign +PREFERENCES_SHOWBASICEXIF;Zeige grundlegende Exif-Informationen +PREFERENCES_SHOWDATETIME;Zeige Datum und Zeit +PREFERENCES_SHOWONLYRAW;Zeige nur Rohdateien (RAW) +PREFERENCES_SHTHRESHOLD;Schwellwert - zu dunkel +PREFERENCES_STARTUPIMDIR;Bild-Verzeichnis beim Programmstart +PREFERENCES_TAB_BROWSER;Datei-Browser +PREFERENCES_TAB_COLORMGR;Farbmanagement +PREFERENCES_TAB_GENERAL;Allgemein +PREFERENCES_TAB_IMPROC;Bildbearbeitung +PREFERENCES_TAB_OUTPUT;Ausgabe +PREFERENCES_THUMBSIZE;Größe der Vorschau +PROFILEPANEL_FILEDLGFILTERANY;Alle Dateien +PROFILEPANEL_FILEDLGFILTERPP;Bearbeitungsprofile +PROFILEPANEL_LABEL;Bearbeitungsprofile +PROFILEPANEL_LOADDLGLABEL;Lade Bearbeitungsprofil... +PROFILEPANEL_PCUSTOM;Benutzerdefiniert +PROFILEPANEL_PFILE;Aus Datei +PROFILEPANEL_PLASTPHOTO;Letztes Bild +PROFILEPANEL_PLASTSAVED;Zuletzt gespeichert +PROFILEPANEL_PROFILE;Profil +PROFILEPANEL_SAVEDLGLABEL;Speichere Bearbeitungsprofil... +PROFILEPANEL_TOOLTIPCOPY;Kopiere aktuelles Profil in Zwischenablage +PROFILEPANEL_TOOLTIPLOAD;Lade Profil aus Datei +PROFILEPANEL_TOOLTIPPASTE; Einfügen von Profil aus Zwischenablage +PROFILEPANEL_TOOLTIPSAVE;Speichere aktuelles Profil +PROGRESSBAR_DECODING;Dekodierung der Rohdatei (RAW)... +PROGRESSBAR_DEMOSAICING;Entrasterung... +PROGRESSBAR_LOADING;Laden des Bildes... +PROGRESSBAR_LOADJPEG;Laden der JPEG Datei... +PROGRESSBAR_LOADPNG;Laden der PNG Datei... +PROGRESSBAR_LOADTIFF;Laden der TIFF Datei... +PROGRESSBAR_PROCESSING;Berechnen des Bildes... +PROGRESSBAR_READY;Bereit. +PROGRESSBAR_SAVEJPEG;Speichern der JPEG Datei... +PROGRESSBAR_SAVEPNG;Speichern der PNG Datei... +PROGRESSBAR_SAVETIFF;Speichern der TIFF Datei... +PROGRESSDLG_LOADING;Laden der Datei... +PROGRESSDLG_PROCESSING;Berechnen des Bildes... +PROGRESSDLG_SAVING;Speichern der Datei... +QINFO_FOCALLENGTH;Brennweite +QINFO_ISO;ISO +QINFO_LENS;Objektiv +QINFO_NOEXIF;Keine Exif-Daten vorhanden. +SAVEDLG_FILEFORMAT;Dateiformat +SAVEDLG_JPEGQUAL;JPEG-Qualität +SAVEDLG_JPGFILTER;JPEG-Datei +SAVEDLG_PNGCOMPR;PNG-Kompression +SAVEDLG_PNGFILTER;PNG-Datei +SAVEDLG_PUTTOQUEUE;In Warteschlange für Verarbeitung legen +SAVEDLG_PUTTOQUEUEHEAD;An Anfang der Warteschlange für Verarbeitung legen +SAVEDLG_PUTTOQUEUETAIL;Ans Ende der Warteschlange für Verarbeitung legen +SAVEDLG_SAVEIMMEDIATELY;Sofort Speichern +SAVEDLG_SAVESPP;Speichere die Prozessparameter mit dem Bild +SAVEDLG_TIFFFILTER;TIFF-Datei +TOOLBAR_TOOLTIP_CROP;Auswahl des Ausschnitts (Taste C) +TOOLBAR_TOOLTIP_HAND;Hand-Werkzeug (Taste N) +TOOLBAR_TOOLTIP_STRAIGHTEN;Auswahl einer Leitlinie (Taste S) +TOOLBAR_TOOLTIP_WB;Weißabgleich manuel setzen (Taste W) +TP_CACORRECTION_BLUE;Blau +TP_CACORRECTION_LABEL;Farbsaum-Entfernung +TP_CACORRECTION_RED;Rot +TP_CHMIXER_BLUE;Blau +TP_CHMIXER_GREEN;Grün +TP_CHMIXER_LABEL;Kanal-Mixer +TP_CHMIXER_RED;Rot +TP_COARSETRAF_DEGREE;Grad: +TP_COARSETRAF_TOOLTIP_HFLIP;horizontal spiegeln +TP_COARSETRAF_TOOLTIP_ROTLEFT;nach links drehen +TP_COARSETRAF_TOOLTIP_ROTRIGHT;nach rechts drehen +TP_COARSETRAF_TOOLTIP_VFLIP;vertikal spiegeln +TP_COLORBOOST_ACHANNEL;Kanal "a" +TP_COLORBOOST_AMOUNT;Menge +TP_COLORBOOST_AVOIDCOLORCLIP;Verhindere Übersättigung +TP_COLORBOOST_BCHANNEL;Kanal "b" +TP_COLORBOOST_CHAB;a & b +TP_COLORBOOST_CHANNEL;Kanal +TP_COLORBOOST_CHSEPARATE;separat +TP_COLORBOOST_ENABLESATLIMITER;Sättigungsbegrenzung aktivieren +TP_COLORBOOST_LABEL;Farbverstärkung +TP_COLORBOOST_SATLIMIT;Sättigungsgrenze +TP_COLORDENOISE_EDGESENSITIVE;Kanten-Empfindlichkeit +TP_COLORDENOISE_EDGETOLERANCE;Kanten-Toleranz +TP_COLORDENOISE_LABEL;Farb-Rauschfilter +TP_COLORDENOISE_RADIUS;Radius +TP_COLORSHIFT_BLUEYELLOW;Blau-Gelb +TP_COLORSHIFT_GREENMAGENTA;Grün-Magenta +TP_COLORSHIFT_LABEL;Farbverschiebung +TP_CROP_DPI;DPI= +TP_CROP_FIXRATIO;Festes Format: +TP_CROP_GTDIAGONALS;Diagonale +TP_CROP_GTHARMMEANS1;Harmonischer Schnitt 1 +TP_CROP_GTHARMMEANS2;Harmonischer Schnitt 2 +TP_CROP_GTHARMMEANS3;Harmonischer Schnitt 3 +TP_CROP_GTHARMMEANS4;Harmonischer Schnitt 4 +TP_CROP_GTNONE;Keine +TP_CROP_GTRULETHIRDS;Goldener Schnitt +TP_CROP_GUIDETYPE;Hilfslinien: +TP_CROP_H;H +TP_CROP_LABEL;Ausschnitt +TP_CROP_SELECTCROP; Wähle Ausschnitt +TP_CROP_W;W +TP_CROP_X;x +TP_CROP_Y;y +TP_DISTORTION_AMOUNT;Menge +TP_DISTORTION_LABEL;Entzerrung +TP_EXPOSURE_AUTOLEVELS;autom. +TP_EXPOSURE_BLACKLEVEL;schwarz +TP_EXPOSURE_BRIGHTNESS;Helligkeit +TP_EXPOSURE_CLIP;beschneiden +TP_EXPOSURE_COMPRHIGHLIGHTS;Lichter-Kompression +TP_EXPOSURE_COMPRSHADOWS;Schatten-Kompression +TP_EXPOSURE_CONTRAST;Kontrast +TP_EXPOSURE_CURVEEDITOR;Tonwertkurve +TP_EXPOSURE_EXPCOMP;Bel.Korrektur +TP_EXPOSURE_LABEL;Belichtung +TP_HLREC_CIELAB;CIELab Überlagerung +TP_HLREC_COLOR;Farbübertragung +TP_HLREC_LABEL;Lichter wiederherstellen +TP_HLREC_LUMINANCE;Luminanz herstellen +TP_HLREC_METHOD;Methode: +TP_ICM_FILEDLGFILTERANY;Alle Dateien +TP_ICM_FILEDLGFILTERICM;ICC-Profildateien +TP_ICM_GAMMABEFOREINPUT;Profil enthält Gammaanpassung +TP_ICM_INPUTCAMERA;Kamera-Standard +TP_ICM_INPUTCUSTOM;Benutzerdefiniert +TP_ICM_INPUTDLGLABEL;Wähle Eingabe-ICC-Profil... +TP_ICM_INPUTEMBEDDED;Verwende eingebettetes, wenn möglich +TP_ICM_INPUTPROFILE;Eingabeprofil +TP_ICM_LABEL;ICM +TP_ICM_NOICM;Kein ICM: sRGB-Ausgabe +TP_ICM_OUTPUTDLGLABEL;Wähle Ausgabe-ICC-Profil... +TP_ICM_OUTPUTPROFILE;Ausgabeprofil +TP_ICM_SAVEREFERENCE;Speichere Referenzbild für die Profilierung +TP_ICM_WORKINGPROFILE;Arbeitsfarbraum +TP_LUMACURVE_BLACKLEVEL;schwarz +TP_LUMACURVE_BRIGHTNESS;Helligkeit +TP_LUMACURVE_COMPRHIGHLIGHTS;Lichter-Kompression +TP_LUMACURVE_COMPRSHADOWS;Schatten-Kompression +TP_LUMACURVE_CONTRAST;Kontrast +TP_LUMACURVE_CURVEEDITOR;Luminanzkurve +TP_LUMACURVE_LABEL;Luminanzkurve +TP_LUMADENOISE_EDGETOLERANCE;Kanten-Toleranz +TP_LUMADENOISE_LABEL;Luminanz-Rauschfilter +TP_LUMADENOISE_RADIUS;Radius +TP_RESIZE_BICUBIC;Bikubisch +TP_RESIZE_BICUBICSF;Bikubisch (Weicher) +TP_RESIZE_BICUBICSH;Bikubisch (Schärfer) +TP_RESIZE_BILINEAR;Bilinear +TP_RESIZE_FULLSIZE;Volle Bildgröße: +TP_RESIZE_H;H: +TP_RESIZE_LABEL;Größe ändern +TP_RESIZE_METHOD;Methode: +TP_RESIZE_NEAREST;Nächste +TP_RESIZE_SCALE;Maßstab +TP_RESIZE_W;W: +TP_ROTATE_AUTOCROP;Auto Ausschnitt +TP_ROTATE_DEGREE;Grad +TP_ROTATE_FILL;Füllen +TP_ROTATE_LABEL;Drehen +TP_ROTATE_SELECTLINE;Wähle Leitlinie +TP_SHADOWSHLIGHTS_HIGHLIGHTS;Lichter +TP_SHADOWSHLIGHTS_HLTONALW;Farbtonbereich +TP_SHADOWSHLIGHTS_LABEL;Schatten/Lichter +TP_SHADOWSHLIGHTS_LOCALCONTR;Lokaler Kontrast +TP_SHADOWSHLIGHTS_RADIUS;Radius +TP_SHADOWSHLIGHTS_SHADOWS;Schatten +TP_SHADOWSHLIGHTS_SHTONALW;Farbtonbereich +TP_SHARPENING_AMOUNT;Menge +TP_SHARPENING_EDRADIUS;Radius +TP_SHARPENING_EDTOLERANCE;Kanten-Toleranz +TP_SHARPENING_HALOCONTROL;Halo-Kontrolle +TP_SHARPENING_HCAMOUNT;Menge +TP_SHARPENING_LABEL;Schärfen +TP_SHARPENING_METHOD;Methode +TP_SHARPENING_ONLYEDGES;nur Kanten schärfen +TP_SHARPENING_RADIUS;Radius +TP_SHARPENING_RLD;R-L Bildrestaurierung +TP_SHARPENING_RLD_AMOUNT;Menge +TP_SHARPENING_RLD_DAMPING;Dämpfung +TP_SHARPENING_RLD_ITERATIONS;Iterationen +TP_SHARPENING_THRESHOLD;Schwellwert +TP_SHARPENING_USM;Unscharf maskieren +TP_VIGNETTING_AMOUNT;Menge +TP_VIGNETTING_LABEL;Korrektur Randlichtabfall +TP_VIGNETTING_RADIUS;Radius +TP_WBALANCE_AUTO;Automatisch +TP_WBALANCE_CAMERA;Kamera +TP_WBALANCE_CUSTOM;Benutzerdefiniert +TP_WBALANCE_GREEN;Farbton +TP_WBALANCE_LABEL;Weißabgleich +TP_WBALANCE_METHOD;Methode +TP_WBALANCE_SIZE;Größe: +TP_WBALANCE_SPOTWB;manuel setzen +TP_WBALANCE_TEMPERATURE;Farbtemperatur +ZOOMBAR_DETAIL;Detail +ZOOMBAR_HUGE;riesig +ZOOMBAR_LARGE;groß +ZOOMBAR_NORMAL;normal +ZOOMBAR_PREVIEW;Voransicht +ZOOMBAR_SCALE;Vergrößerung +ZOOMBAR_SMALL;klein diff --git a/release/languages/english-uk b/release/languages/english-uk new file mode 100755 index 000000000..fcef57bb8 --- /dev/null +++ b/release/languages/english-uk @@ -0,0 +1,577 @@ +# British english +# 16.01.2009: Richard Regal +# +ADJUSTER_RESET_TO_DEFAULT;Reset to default +CURVEEDITOR_FILEDLGFILTERANY;Any files +CURVEEDITOR_FILEDLGFILTERCURVE;Curve files +CURVEEDITOR_LINEAR;Linear +CURVEEDITOR_LOADDLGLABEL;Load Curve... +CURVEEDITOR_SAVEDLGLABEL;Save Curve... +CURVEEDITOR_TOOLTIPLINEAR;Reset curve to linear +CURVEEDITOR_TOOLTIPLOAD;Load a curve from file +CURVEEDITOR_TOOLTIPSAVE;Save current curve +EXIFFILTER_APERTURE;Aperture +EXIFFILTER_CAMERA;Camera +EXIFFILTER_DIALOGLABEL;Exif Filter +EXIFFILTER_FOCALLEN;Focal Length +EXIFFILTER_ISO;ISO +EXIFFILTER_LENS;Lens +EXIFFILTER_SHUTTER;Shutter +EXIFPANEL_ADDEDIT;Add/Edit +EXIFPANEL_ADDEDITHINT;Add new tag or edit tag +EXIFPANEL_ADDTAGDLG_ENTERVALUE;Enter value +EXIFPANEL_ADDTAGDLG_SELECTTAG;Select tag +EXIFPANEL_ADDTAGDLG_TITLE;Add/Edit Tag +EXIFPANEL_KEEP;Keep +EXIFPANEL_KEEPHINT;Keep the selected tags when writing output file +EXIFPANEL_REMOVE;Remove +EXIFPANEL_REMOVEHINT;Remove the selected tags when writing output file +EXIFPANEL_RESET;Reset +EXIFPANEL_RESETALL;Reset All +EXIFPANEL_RESETALLHINT;Reset all tags to their original values +EXIFPANEL_RESETHINT;Reset the selected tags to their original values +EXIFPANEL_SUBDIRECTORY;Subdirectory +FILEBROWSER_APPLYPROFILE;Apply profile +FILEBROWSER_ARRANGEMENTHINT;Change between vertical/horizontal alignment of thumbnails +FILEBROWSER_CLEARPROFILE;Clear profile +FILEBROWSER_COPYPROFILE;Copy profile +FILEBROWSER_DELETEDLGLABEL;File delete confirmation +FILEBROWSER_DELETEDLGMSG;Are you sure you want to delete the selected %1 files? +FILEBROWSER_EMPTYTRASH;Empty Trash +FILEBROWSER_EMPTYTRASHHINT;Permanently delete the files of the trash +FILEBROWSER_EXIFFILTERAPPLY;Apply +FILEBROWSER_EXIFFILTERAPPLYHINT;Switch on/off exif filter of the file browser +FILEBROWSER_EXIFFILTERLABEL;Exif Filter +FILEBROWSER_EXIFFILTERSETTINGS;Setup +FILEBROWSER_EXIFFILTERSETTINGSHINT;Change settings of the exif filter +FILEBROWSER_PARTIALPASTEPROFILE;Partial paste +FILEBROWSER_PASTEPROFILE;Paste profile +FILEBROWSER_POPUPCANCELJOB;Cancel job +FILEBROWSER_POPUPMOVEEND;Move to end of queue +FILEBROWSER_POPUPMOVEHEAD;Move to head of queue +FILEBROWSER_POPUPOPEN;Open +FILEBROWSER_POPUPPROCESS;Put to processing queue +FILEBROWSER_POPUPRANK1;Rank 1 +FILEBROWSER_POPUPRANK2;Rank 2 +FILEBROWSER_POPUPRANK3;Rank 3 +FILEBROWSER_POPUPRANK4;Rank 4 +FILEBROWSER_POPUPRANK5;Rank 5 +FILEBROWSER_POPUPREMOVE;Remove from filesystem +FILEBROWSER_POPUPRENAME;Rename +FILEBROWSER_POPUPSELECTALL;Select all +FILEBROWSER_POPUPTRASH;Move to trash +FILEBROWSER_POPUPUNRANK;Unrank +FILEBROWSER_POPUPUNTRASH;Remove from trash +FILEBROWSER_PROCESSINGSETTINGS;Settings +FILEBROWSER_PROCESSINGSETTINGSHINT;Set the file format and output directory +FILEBROWSER_RENAMEDLGLABEL;Rename file +FILEBROWSER_RENAMEDLGMSG;Rename file "%1" to: +FILEBROWSER_SHOWDIRHINT;Show all images of the directory +FILEBROWSER_SHOWQUEUEHINT;Show content of the processing queue +FILEBROWSER_SHOWRANK1HINT;Show images ranked as 1 star +FILEBROWSER_SHOWRANK2HINT;Show images ranked as 2 star +FILEBROWSER_SHOWRANK3HINT;Show images ranked as 3 star +FILEBROWSER_SHOWRANK4HINT;Show images ranked as 4 star +FILEBROWSER_SHOWRANK5HINT;Show images ranked as 5 star +FILEBROWSER_SHOWTRASHHINT;Show content of the trash +FILEBROWSER_SHOWUNRANKHINT;Show unranked images +FILEBROWSER_STARTPROCESSING;Start Processing +FILEBROWSER_STARTPROCESSINGHINT;Start processing/saving of images in the queue +FILEBROWSER_STOPPROCESSING;Stop processing +FILEBROWSER_STOPPROCESSINGHINT;Stop processing of images +FILEBROWSER_THUMBSIZE;Thumb. size +FILEBROWSER_ZOOMINHINT;Increase thumbnail size +FILEBROWSER_ZOOMOUTHINT;Decrease thumbnail size +GENERAL_ABOUT;About +GENERAL_CANCEL;Cancel +GENERAL_DISABLE;Disable +GENERAL_DISABLED;Disabled +GENERAL_ENABLE;Enable +GENERAL_ENABLED;Enabled +GENERAL_LANDSCAPE;Landscape +GENERAL_LOAD;Load +GENERAL_NA;n/a +GENERAL_NO;No +GENERAL_OK;OK +GENERAL_PORTRAIT;Portrait +GENERAL_SAVE;Save +GENERAL_YES;Yes +HISTOGRAM_LABEL;Histogram +HISTOGRAM_TOOLTIP_B;Show/Hide BLUE histogram +HISTOGRAM_TOOLTIP_G;Show/Hide GREEN histogram +HISTOGRAM_TOOLTIP_L;Show/Hide CIELAB Luminance histogram +HISTOGRAM_TOOLTIP_R;Show/Hide RED histogram +HISTORY_CHANGED;Changed +HISTORY_CUSTOMCURVE;Custom Curve +HISTORY_DELSNAPSHOT;Del +HISTORY_FROMCLIPBOARD;From clipboard +HISTORY_LABEL;History +HISTORY_MSG_10;Shadow Compression +HISTORY_MSG_11;Tone Curve +HISTORY_MSG_12;Auto Exposure +HISTORY_MSG_13;Exposure Clipping +HISTORY_MSG_14;Luminance Brightness +HISTORY_MSG_15;Luminance Contrast +HISTORY_MSG_16;Luminance Black +HISTORY_MSG_17;Luminance Highlight Compr. +HISTORY_MSG_18;Luminance Shadow Compr. +HISTORY_MSG_19;Luminance Curve +HISTORY_MSG_1;Photo Loaded +HISTORY_MSG_20;Sharpening +HISTORY_MSG_21;Sharpening Radius +HISTORY_MSG_22;Sharpening Amount +HISTORY_MSG_23;Sharpening Threshold +HISTORY_MSG_24;Sharpen Only Edges +HISTORY_MSG_25;Sharpening Edge Detection Radius +HISTORY_MSG_26;Sharpening Edge Tolerance +HISTORY_MSG_27;Sharpening Halo Control +HISTORY_MSG_28;Halo Control Amount +HISTORY_MSG_29;Sharpening Method +HISTORY_MSG_2;Profile Loaded +HISTORY_MSG_30;Deconvolution Radius +HISTORY_MSG_31;Deconvolution Amount +HISTORY_MSG_32;Deconvolution Damping +HISTORY_MSG_33;Deconvolution Iterations +HISTORY_MSG_34;Avoid Colour Clipping +HISTORY_MSG_35;Saturation Limiter +HISTORY_MSG_36;Saturation Limit +HISTORY_MSG_37;Colour Boost +HISTORY_MSG_38;White Balance Method +HISTORY_MSG_39;Colour Temperature +HISTORY_MSG_3;Profile Changed +HISTORY_MSG_40;White Balance Tint +HISTORY_MSG_41;Colour Shift "A" +HISTORY_MSG_42;Colour Shift "B" +HISTORY_MSG_43;Luminance Denoising +HISTORY_MSG_44;Lum. Denoising Radius +HISTORY_MSG_45;Lum. Denoising Edge Tolerance +HISTORY_MSG_46;Colour Denoising +HISTORY_MSG_47;Colour Denoising Radius +HISTORY_MSG_48;Colour Denoising Edge Tolerance +HISTORY_MSG_49;Edge Sensitive Colour Denoising +HISTORY_MSG_4;History Browsing +HISTORY_MSG_50;Shadow/Highlight tool +HISTORY_MSG_51;Highlight boost +HISTORY_MSG_52;Shadow Boost +HISTORY_MSG_53;Highlight Tonal Width +HISTORY_MSG_54;Shadow Tonal Width +HISTORY_MSG_55;Local Contrast +HISTORY_MSG_56;Shadow/Highlight Radius +HISTORY_MSG_57;Coarse Rotation +HISTORY_MSG_58;Horizontal Flipping +HISTORY_MSG_59;Vertical Flipping +HISTORY_MSG_5;Brightness +HISTORY_MSG_60;Rotation +HISTORY_MSG_61;Rotation +HISTORY_MSG_62;Lens Distortion Correction +HISTORY_MSG_63;Snapshot Selected +HISTORY_MSG_64;Crop Photo +HISTORY_MSG_65;C/A Correction +HISTORY_MSG_66;Highlight Recovery +HISTORY_MSG_67;Highlight Recovery Amount +HISTORY_MSG_68;Highlight Recovery Method +HISTORY_MSG_69;Working Colour Space +HISTORY_MSG_6;Contrast +HISTORY_MSG_70;Output Colour Space +HISTORY_MSG_71;Input Colour Space +HISTORY_MSG_72;Vignetting Correction +HISTORY_MSG_73;Channel Mixer +HISTORY_MSG_74;Resize Scale +HISTORY_MSG_75;Resize Method +HISTORY_MSG_76;Exif Metadata +HISTORY_MSG_77;IPTC Metadata +HISTORY_MSG_7;Black +HISTORY_MSG_8;Exposure Compensation +HISTORY_MSG_9;Highlight Compression +HISTORY_NEWSNAPSHOT;Add +HISTORY_NEWSNAPSHOTAS;As... +HISTORY_NEWSSDIALOGLABEL;Label of the snapshot: +HISTORY_NEWSSDIALOGTITLE;Add new snapshot +HISTORY_SETTO;Set to +HISTORY_SNAPSHOT;Snapshot +HISTORY_SNAPSHOTS;Snapshots +ICMPANEL_FILEDLGFILTERANY;Any files +ICMPANEL_FILEDLGFILTERICM;ICC Profile Files +ICMPANEL_GAMMABEFOREINPUT;Profile applies Gamma +ICMPANEL_INPUTCAMERA;Camera default +ICMPANEL_INPUTCUSTOM;Custom +ICMPANEL_INPUTDLGLABEL;Select Input ICC Profile... +ICMPANEL_INPUTEMBEDDED;Use Embedded, if possible +ICMPANEL_INPUTPROFILE;Input Profile +ICMPANEL_NOICM;No ICM: sRGB output +ICMPANEL_OUTPUTDLGLABEL;Select Output ICC Profile... +ICMPANEL_OUTPUTPROFILE;Output Profile +ICMPANEL_SAVEREFERENCE;Save reference image for profiling +ICMPANEL_WORKINGPROFILE;Working Profile +IMAGEAREA_DETAILVIEW;Detail view +IPTCPANEL_AUTHOR;Author +IPTCPANEL_AUTHORHINT;Name of the creator of the object, e.g. writer, photographer or graphic artist (By-line). +IPTCPANEL_AUTHORSPOSITION;Author's position +IPTCPANEL_AUTHORSPOSITIONHINT;Title of the creator or creators of the object (By-line Title). +IPTCPANEL_CAPTION;Caption +IPTCPANEL_CAPTIONHINT;A textual description of the data (Caption - Abstract). +IPTCPANEL_CAPTIONWRITER;Caption Writer +IPTCPANEL_CAPTIONWRITERHINT;The name of the person involved in the writing, editing or correcting the image or caption/abstract (Writer - Editor). +IPTCPANEL_CATEGORY;Category +IPTCPANEL_CATEGORYHINT;Identifies the subject of the image in the opinion of the provider (Category). +IPTCPANEL_CITY;City +IPTCPANEL_CITYHINT;City of image origin (City). +IPTCPANEL_COPYHINT;Copy IPTC settings to clipboard +IPTCPANEL_COPYRIGHT;Copyright +IPTCPANEL_COPYRIGHTHINT;Any necessary copyright notice (Copyright Notice). +IPTCPANEL_COUNTRY;Country +IPTCPANEL_COUNTRYHINT;The name of the country/primary location where the image was created (Country - Primary Location Name). +IPTCPANEL_CREDIT;Credit +IPTCPANEL_CREDITHINT;Identifies the provider of the image, not necessarily the owner/creator (Credit). +IPTCPANEL_DATECREATED;Date Created +IPTCPANEL_DATECREATEDHINT;The date the intellectual content of the image was created; Format: JJJJMMTT (Date Created). +IPTCPANEL_EMBEDDED;Embedded +IPTCPANEL_EMBEDDEDHINT;Reset to IPTC data embedded in the image file +IPTCPANEL_HEADLINE;Headline +IPTCPANEL_HEADLINEHINT;A publishable entry providing a synopsis of the contents of the image (Headline). +IPTCPANEL_INSTRUCTIONS;Instructions +IPTCPANEL_INSTRUCTIONSHINT;Other editorial instructions concerning the use of the image (Special Instructions). +IPTCPANEL_KEYWORDS;Keywords +IPTCPANEL_KEYWORDSHINT;Used to indicate specific information retrieval words (Keywords). +IPTCPANEL_PASTEHINT;Paste IPTC settings from clipboard +IPTCPANEL_PROVINCE;Province +IPTCPANEL_PROVINCEHINT;The Province/State where the image originates (Province-State). +IPTCPANEL_RESET;Reset +IPTCPANEL_RESETHINT;Reset to profile default +IPTCPANEL_SOURCE;Source +IPTCPANEL_SOURCEHINT;The original owner of the intellectual content of the image (Source). +IPTCPANEL_SUPPCATEGORIES;Suppl. Categories +IPTCPANEL_SUPPCATEGORIESHINT;Further refines the subject of the image (Supplemental Categories). +IPTCPANEL_TITLE;Title +IPTCPANEL_TITLEHINT;A shorthand reference for the image (Object Name). +IPTCPANEL_TRANSREFERENCE;Trans. Reference +IPTCPANEL_TRANSREFERENCEHINT;A code representing the location of original transmission (Original Transmission Reference). +MAIN_BUTTON_PREFERENCES;Preferences +MAIN_BUTTON_SAVE;Save Image +MAIN_BUTTON_SAVEAS;As... +MAIN_BUTTON_SENDTOEDITOR;Send to editor +MAIN_MSG_ALREADYEXISTS;File already exists. +MAIN_MSG_CANNOTLOAD;Cannot load image +MAIN_MSG_CANNOTSAVE;File saving error +MAIN_MSG_CANNOTSTARTEDITOR;Can not start editor. +MAIN_MSG_CANNOTSTARTEDITOR_SECONDARY;Please set the correct path in the "Preferences" dialog. +MAIN_MSG_EXITJOBSINQUEUEINFO;Unprocessed images in the queue will be lost on exit. +MAIN_MSG_EXITJOBSINQUEUEQUEST;Are you sure you want to exit? There are unprocessed images waiting in the queue. +MAIN_MSG_JOBSINQUEUE;job(s) in the queue +MAIN_MSG_QOVERWRITE;Do you want to overwrite it? +MAIN_TAB_BASIC;Basic +MAIN_TAB_COLOR;Colour +MAIN_TAB_DETAIL;Detail +MAIN_TAB_EXIF;Exif +MAIN_TAB_EXPOSURE;Exposure +MAIN_TAB_ICM;ICM +MAIN_TAB_IPTC;IPTC +MAIN_TAB_METADATA;Metadata +MAIN_TAB_TRANSFORM;Transform +MAIN_TOOLTIP_HIDEFP;Show/hide the bottom panel (directory and file browser, shortcut key: F) +MAIN_TOOLTIP_HIDEHP;Show/hide the left panel (including the history, shortcut key: H) +MAIN_TOOLTIP_INDCLIPPEDH;Clipped highlight indication +MAIN_TOOLTIP_INDCLIPPEDS;Clipped shadow indication +MAIN_TOOLTIP_PREFERENCES;Set preferences +MAIN_TOOLTIP_QINFO;Quick info on the image +MAIN_TOOLTIP_SAVE;Save image to the default folder +MAIN_TOOLTIP_SAVEAS;Save image to a selected folder +PARTIALPASTE_BASICGROUP;Basic settings +PARTIALPASTE_CACORRECTION;C/A correction +PARTIALPASTE_COARSETRANS;90 deg rotation / flipping +PARTIALPASTE_COLORBOOST;Colour boost +PARTIALPASTE_COLORDENOISE;Colour denoise +PARTIALPASTE_COLORGROUP;Colour related settings +PARTIALPASTE_COLORMIXER;Colour mixer +PARTIALPASTE_COLORSHIFT;Colour shift +PARTIALPASTE_COMPOSITIONGROUP;Composition settings +PARTIALPASTE_CROP;Crop +PARTIALPASTE_DIALOGLABEL;Partial paste processing profile +PARTIALPASTE_DISTORTION;Distortion correction +PARTIALPASTE_EXIFCHANGES;Changes to exif data +PARTIALPASTE_EXPOSURE;Exposure +PARTIALPASTE_HLRECOVERY;Highlight recovery +PARTIALPASTE_ICMSETTINGS;ICM settings +PARTIALPASTE_IPTCINFO;IPTC info +PARTIALPASTE_LENSGROUP;Lens related settings +PARTIALPASTE_LUMACURVE;Luminance curve +PARTIALPASTE_LUMADENOISE;Luminance noise reduction +PARTIALPASTE_LUMINANCEGROUP;Luminance related settings +PARTIALPASTE_METAICMGROUP;Metadata/ICM settings +PARTIALPASTE_RESIZE;Resize +PARTIALPASTE_ROTATION;Rotation +PARTIALPASTE_SHADOWSHIGHLIGHTS;Shadows/Highlights +PARTIALPASTE_SHARPENING;Sharpening +PARTIALPASTE_VIGNETTING;Vignetting correction +PARTIALPASTE_WHITEBALANCE;White balance +PREFERENCES_APPLNEXTSTARTUP;applied at next startup +PREFERENCES_BLINKCLIPPED;Blink clipped areas +PREFERENCES_CACHECLEARALL;Clear All +PREFERENCES_CACHECLEARPROFILES;Clear Profiles +PREFERENCES_CACHECLEARTHUMBS;Clear Thumbnails +PREFERENCES_CACHEFORMAT1;Proprietary (faster and better quality) +PREFERENCES_CACHEFORMAT2;JPEG (smaller disk footprint) +PREFERENCES_CACHEMAXENTRIES;Maximal Number of Cache Entries +PREFERENCES_CACHEOPTS;Cache Options +PREFERENCES_CACHESTRAT1;Prefer Speed to Low Memory Consumption +PREFERENCES_CACHESTRAT2;Prefer Low Memory Consumption to Speed +PREFERENCES_CACHESTRAT;Cache Strategy +PREFERENCES_CACHETHUMBFORM;Cache Thumbnail Format +PREFERENCES_CACHETHUMBHEIGHT;Maximal Thumbnail Height +PREFERENCES_CLEARDLG_LINE1;Clearing cache +PREFERENCES_CLEARDLG_LINE2;This may take a few seconds. +PREFERENCES_CLEARDLG_TITLE;Please wait +PREFERENCES_CLIPPINGIND;Clipping indication +PREFERENCES_CMETRICINTENT;Colorimetric Intent +PREFERENCES_DATEFORMAT;Date Format +PREFERENCES_DATEFORMATHINT;You can use the following formatting strings:\n%y : year\n%m : month\n%d : day\n\nFor example, the hungarian date format is:\n%y/%m/%d +PREFERENCES_DEFAULTLANG;Default language +PREFERENCES_DEFAULTTHEME;Default theme +PREFERENCES_DEMOSAICINGALGO;Demosaicing Algorithm +PREFERENCES_DIRHOME;Home directory +PREFERENCES_DIRLAST;Last visited directory +PREFERENCES_DIROTHER;Other +PREFERENCES_DIRSELECTDLG;Select Image Directory at Startup... +PREFERENCES_DIRSOFTWARE;Installation directory +PREFERENCES_DMETHOD;Method +PREFERENCES_EDITORCMDLINE;Other command line +PREFERENCES_EXTERNALEDITOR;External editor +PREFERENCES_FALSECOLOR;False colour surpression steps +PREFERENCES_FBROWSEROPTS;File Browser Options +PREFERENCES_FILEFORMAT;File Format +PREFERENCES_FORIMAGE;For image files +PREFERENCES_FORRAW;For RAW files +PREFERENCES_GIMPPATH;GIMP installation directory +PREFERENCES_GTKTHEME;GTK default +PREFERENCES_HINT;Hint +PREFERENCES_HLTHRESHOLD;Threshold for clipped highlights +PREFERENCES_ICCDIR;Directory of ICC profiles +PREFERENCES_IMPROCPARAMS;Default image processing parameters +PREFERENCES_INTENT_ABSOLUTE;Absolute Colorimetric +PREFERENCES_INTENT_PERCEPTUAL;Perceptual +PREFERENCES_INTENT_RELATIVE;Relative Colorimetric +PREFERENCES_INTENT_SATURATION;Saturation +PREFERENCES_LIVETHUMBNAILS;Live Thumbnails (slower) +PREFERENCES_MONITORICC;Monitor Profile +PREFERENCES_OUTDIR;Output Directory +PREFERENCES_OUTDIRFOLDER;Save to folder +PREFERENCES_OUTDIRFOLDERHINT;Put the saved images to the seledted folder +PREFERENCES_OUTDIRHINT;You can use the following formatting strings:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nThese formatting strings refer to the directories and sub-paths of the path of the raw file.\n\nFor example, if /home/tom/image/02-09-2006/dsc0012.nefhas been opened, the meaning of the formatting strings are:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nIf you want to save the output image where the original is, write:\n%p1/%f\n\nIf you want to save the output image in a directory 'converted' located the directory of the original, write:\n%p1/converted/%f\n\nIf you want to save the output image in directory '/home/tom/converted' with keeping the same subdirectory of dates, write:\n%p2/converted/%d1/%f +PREFERENCES_OUTDIRTEMPLATE;Use Template +PREFERENCES_OUTDIRTEMPLATEHINT;You can use the following formatting strings:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nThese formatting strings refer to the directories and sub-paths of the path of the raw file.\n\nFor example, if /home/tom/image/02-09-2006/dsc0012.nefhas been opened, the meaning of the formatting strings are:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nIf you want to save the output image where the original is, write:\n%p1/%f\n\nIf you want to save the output image in a directory 'converted' located the directory of the original, write:\n%p1/converted/%f\n\nIf you want to save the output image in directory '/home/tom/converted' with keeping the same subdirectory of dates, write:\n%p2/converted/%d1/%f +PREFERENCES_PARSEDEXT;Parsed Extensions +PREFERENCES_PARSEDEXTADD;Add Extension +PREFERENCES_PARSEDEXTADDHINT;Type an extension and press this button to append list +PREFERENCES_PARSEDEXTDELHINT;Delete selected extension from the list +PREFERENCES_PROFILEHANDLING;Processing Profile Handling +PREFERENCES_PROFILELOADPR;Profile Loading Priority +PREFERENCES_PROFILEPRCACHE;Profile in Cache +PREFERENCES_PROFILEPRFILE;Profile Next to the Input File +PREFERENCES_PROFILESAVECACHE;Save Processing Parameters to the Cache +PREFERENCES_PROFILESAVEINPUT;Save Processing Parameters Next to the Input File +PREFERENCES_PSPATH;Adobe Photoshop installation directory +PREFERENCES_SELECTICCDIRDLG;Select ICC Profile Directory... +PREFERENCES_SELECTLANG;Select language +PREFERENCES_SELECTMONITORPROFDLG;Select ICC Profile of the Display... +PREFERENCES_SELECTTHEME;Select theme +PREFERENCES_SHOWBASICEXIF;Show basic Exif info +PREFERENCES_SHOWDATETIME;Show date and time +PREFERENCES_SHOWONLYRAW;Show only RAW files +PREFERENCES_SHTHRESHOLD;Threshold for clipped shadows +PREFERENCES_STARTUPIMDIR;Image directory at startup +PREFERENCES_TAB_BROWSER;File Browser +PREFERENCES_TAB_COLORMGR;Colour Management +PREFERENCES_TAB_GENERAL;General +PREFERENCES_TAB_IMPROC;Image Processing +PREFERENCES_TAB_OUTPUT;Output Options +PREFERENCES_THUMBSIZE;Thumbnail Size +PROFILEPANEL_FILEDLGFILTERANY;Any files +PROFILEPANEL_FILEDLGFILTERPP;Postprocessing profiles +PROFILEPANEL_LABEL;Postprocessing Profiles +PROFILEPANEL_LOADDLGLABEL;Load Postprocessing Parameters... +PROFILEPANEL_PCUSTOM;Custom +PROFILEPANEL_PFILE;From file +PROFILEPANEL_PLASTPHOTO;Last Photo +PROFILEPANEL_PLASTSAVED;Last Saved +PROFILEPANEL_PROFILE;Profile +PROFILEPANEL_SAVEDLGLABEL;Save Postprocessing Parameters... +PROFILEPANEL_TOOLTIPCOPY;Copy current profile to clipboard +PROFILEPANEL_TOOLTIPLOAD;Load a profile from file +PROFILEPANEL_TOOLTIPPASTE; Paste profile from clipboard +PROFILEPANEL_TOOLTIPSAVE;Save current profile +PROGRESSBAR_DECODING;Decoding raw file... +PROGRESSBAR_DEMOSAICING;Demosaicing... +PROGRESSBAR_LOADING;Loading Image... +PROGRESSBAR_LOADJPEG;Loading JPEG file... +PROGRESSBAR_LOADPNG;Loading PNG file... +PROGRESSBAR_LOADTIFF;Loading TIFF file... +PROGRESSBAR_PROCESSING;Processing Image... +PROGRESSBAR_READY;Ready. +PROGRESSBAR_SAVEJPEG;Saving JPEG file... +PROGRESSBAR_SAVEPNG;Saving PNG file... +PROGRESSBAR_SAVETIFF;Saving TIFF file... +PROGRESSDLG_LOADING;Loading file... +PROGRESSDLG_PROCESSING;Processing image... +PROGRESSDLG_SAVING;Saving file... +QINFO_FOCALLENGTH;Focal length +QINFO_ISO;ISO +QINFO_LENS;Lens +QINFO_NOEXIF;Exif data not available. +SAVEDLG_FILEFORMAT;File format +SAVEDLG_JPEGQUAL;JPEG Quality +SAVEDLG_JPGFILTER;JPEG files +SAVEDLG_PNGCOMPR;PNG Compression +SAVEDLG_PNGFILTER;PNG files +SAVEDLG_PUTTOQUEUE;Put into processing queue +SAVEDLG_PUTTOQUEUEHEAD;Put to the head of the processing queue +SAVEDLG_PUTTOQUEUETAIL;Put to the end of the processing queue +SAVEDLG_SAVEIMMEDIATELY;Save immediately +SAVEDLG_SAVESPP;Save processing parameters with image +SAVEDLG_TIFFFILTER;TIFF files +TOOLBAR_TOOLTIP_CROP;Crop selection (Shortcut key: C) +TOOLBAR_TOOLTIP_HAND;Hand tool (Shortcut key: N) +TOOLBAR_TOOLTIP_STRAIGHTEN;Straight line selection (Shortcut key: S) +TOOLBAR_TOOLTIP_WB;Spot white balance (Shortcut key: W) +TP_CACORRECTION_BLUE;Blue +TP_CACORRECTION_LABEL;C/A Correction +TP_CACORRECTION_RED;Red +TP_CHMIXER_BLUE;Blue +TP_CHMIXER_GREEN;Green +TP_CHMIXER_LABEL;Channel Mixer +TP_CHMIXER_RED;Red +TP_COARSETRAF_DEGREE;degree: +TP_COARSETRAF_TOOLTIP_HFLIP;Flip horizontally +TP_COARSETRAF_TOOLTIP_ROTLEFT;Rotate left +TP_COARSETRAF_TOOLTIP_ROTRIGHT;Rotate right +TP_COARSETRAF_TOOLTIP_VFLIP;Flip vertically +TP_COLORBOOST_ACHANNEL;Channel "a" +TP_COLORBOOST_AMOUNT;Amount +TP_COLORBOOST_AVOIDCOLORCLIP;Avoid colour clipping +TP_COLORBOOST_BCHANNEL;Channel "b" +TP_COLORBOOST_CHAB;a & b +TP_COLORBOOST_CHANNEL;Channel +TP_COLORBOOST_CHSEPARATE;separate +TP_COLORBOOST_ENABLESATLIMITER;Enable saturation limiter +TP_COLORBOOST_LABEL;Colour Boost +TP_COLORBOOST_SATLIMIT;Saturation limit +TP_COLORDENOISE_EDGESENSITIVE;Edge Sensitive +TP_COLORDENOISE_EDGETOLERANCE;Edge Tolerance +TP_COLORDENOISE_LABEL;Colour Noise Reduction +TP_COLORDENOISE_RADIUS;Radius +TP_COLORSHIFT_BLUEYELLOW;Blue-Yellow +TP_COLORSHIFT_GREENMAGENTA;Green-Magenta +TP_COLORSHIFT_LABEL;Colour Shift +TP_CROP_DPI;DPI= +TP_CROP_FIXRATIO;Fix Ratio: +TP_CROP_GTDIAGONALS;Rule of diagonals +TP_CROP_GTHARMMEANS1;Harmonic means 1 +TP_CROP_GTHARMMEANS2;Harmonic means 2 +TP_CROP_GTHARMMEANS3;Harmonic means 3 +TP_CROP_GTHARMMEANS4;Harmonic means 4 +TP_CROP_GTNONE;None +TP_CROP_GTRULETHIRDS;Rule of thirds +TP_CROP_GUIDETYPE;Guide Type: +TP_CROP_H;H +TP_CROP_LABEL;Crop +TP_CROP_SELECTCROP; Select Crop +TP_CROP_W;W +TP_CROP_X;x +TP_CROP_Y;y +TP_DISTORTION_AMOUNT;Amount +TP_DISTORTION_LABEL;Distortion +TP_EXPOSURE_AUTOLEVELS;Auto Levels +TP_EXPOSURE_BLACKLEVEL;Black +TP_EXPOSURE_BRIGHTNESS;Brightness +TP_EXPOSURE_CLIP;Clip +TP_EXPOSURE_COMPRHIGHLIGHTS;Highlight compression +TP_EXPOSURE_COMPRSHADOWS;Shadow compression +TP_EXPOSURE_CONTRAST;Contrast +TP_EXPOSURE_CURVEEDITOR;Tone Curve +TP_EXPOSURE_EXPCOMP;Exp. Comp. +TP_EXPOSURE_LABEL;Exposure +TP_HLREC_CIELAB;CIELab Blending +TP_HLREC_COLOR;Colour Propagation +TP_HLREC_LABEL;Highlight Recovery +TP_HLREC_LUMINANCE;Luminance Recovery +TP_HLREC_METHOD;Method: +TP_ICM_FILEDLGFILTERANY;Any files +TP_ICM_FILEDLGFILTERICM;ICC Profile Files +TP_ICM_GAMMABEFOREINPUT;Profile applies Gamma +TP_ICM_INPUTCAMERA;Camera default +TP_ICM_INPUTCUSTOM;Custom +TP_ICM_INPUTDLGLABEL;Select Input ICC Profile... +TP_ICM_INPUTEMBEDDED;Use Embedded, if possible +TP_ICM_INPUTPROFILE;Input Profile +TP_ICM_LABEL;ICM +TP_ICM_NOICM;No ICM: sRGB output +TP_ICM_OUTPUTDLGLABEL;Select Output ICC Profile... +TP_ICM_OUTPUTPROFILE;Output Profile +TP_ICM_SAVEREFERENCE;Save reference image for profiling +TP_ICM_WORKINGPROFILE;Working Profile +TP_LUMACURVE_BLACKLEVEL;Black +TP_LUMACURVE_BRIGHTNESS;Brightness +TP_LUMACURVE_COMPRHIGHLIGHTS;Highlight compression +TP_LUMACURVE_COMPRSHADOWS;Shadow compression +TP_LUMACURVE_CONTRAST;Contrast +TP_LUMACURVE_CURVEEDITOR;Luminance Curve +TP_LUMACURVE_LABEL;Luminance Curve +TP_LUMADENOISE_EDGETOLERANCE;Edge Tolerance +TP_LUMADENOISE_LABEL;Luminance Noise Reduction +TP_LUMADENOISE_RADIUS;Radius +TP_RESIZE_BICUBIC;Bicubic +TP_RESIZE_BICUBICSF;Bicubic (Softer) +TP_RESIZE_BICUBICSH;Bicubic (Sharper) +TP_RESIZE_BILINEAR;Bilinear +TP_RESIZE_FULLSIZE;Full Image Size: +TP_RESIZE_H;H: +TP_RESIZE_LABEL;Resize +TP_RESIZE_METHOD;Method: +TP_RESIZE_NEAREST;Nearest +TP_RESIZE_SCALE;Scale +TP_RESIZE_W;W: +TP_ROTATE_AUTOCROP;Auto Crop +TP_ROTATE_DEGREE;Degree +TP_ROTATE_FILL;Fill +TP_ROTATE_LABEL;Rotate +TP_ROTATE_SELECTLINE; Select Straight Line +TP_SHADOWSHLIGHTS_HIGHLIGHTS;Highlights +TP_SHADOWSHLIGHTS_HLTONALW;Tonal Width +TP_SHADOWSHLIGHTS_LABEL;Shadows/Highlights +TP_SHADOWSHLIGHTS_LOCALCONTR;Local Contrast +TP_SHADOWSHLIGHTS_RADIUS;Radius +TP_SHADOWSHLIGHTS_SHADOWS;Shadows +TP_SHADOWSHLIGHTS_SHTONALW;Tonal Width +TP_SHARPENING_AMOUNT;Amount +TP_SHARPENING_EDRADIUS;Radius +TP_SHARPENING_EDTOLERANCE;Edge tolerance +TP_SHARPENING_HALOCONTROL;Halo control +TP_SHARPENING_HCAMOUNT;Amount +TP_SHARPENING_LABEL;Sharpening +TP_SHARPENING_METHOD;Method +TP_SHARPENING_ONLYEDGES;Sharpen only edges +TP_SHARPENING_RADIUS;Radius +TP_SHARPENING_RLD;RL Deconvolution +TP_SHARPENING_RLD_AMOUNT;Amount +TP_SHARPENING_RLD_DAMPING;Damping +TP_SHARPENING_RLD_ITERATIONS;Iterations +TP_SHARPENING_THRESHOLD;Threshold +TP_SHARPENING_USM;Unsharp Mask +TP_VIGNETTING_AMOUNT;Amount +TP_VIGNETTING_LABEL;Vignetting Correction +TP_VIGNETTING_RADIUS;Radius +TP_WBALANCE_AUTO;Auto +TP_WBALANCE_CAMERA;Camera +TP_WBALANCE_CUSTOM;Custom +TP_WBALANCE_GREEN;Tint +TP_WBALANCE_LABEL;White Balance +TP_WBALANCE_METHOD;Method +TP_WBALANCE_SIZE;Size: +TP_WBALANCE_SPOTWB;Spot WB +TP_WBALANCE_TEMPERATURE;Temperature +ZOOMBAR_DETAIL;Detail +ZOOMBAR_HUGE;Huge +ZOOMBAR_LARGE;Large +ZOOMBAR_NORMAL;Normal +ZOOMBAR_PREVIEW;Preview +ZOOMBAR_SCALE;Scale +ZOOMBAR_SMALL;Small diff --git a/release/languages/english-us b/release/languages/english-us new file mode 100755 index 000000000..f07a04713 --- /dev/null +++ b/release/languages/english-us @@ -0,0 +1,581 @@ +# +# +# +ADJUSTER_RESET_TO_DEFAULT;Reset to default +CURVEEDITOR_FILEDLGFILTERANY;Any files +CURVEEDITOR_FILEDLGFILTERCURVE;Curve files +CURVEEDITOR_LINEAR;Linear +CURVEEDITOR_LOADDLGLABEL;Load Curve... +CURVEEDITOR_SAVEDLGLABEL;Save Curve... +CURVEEDITOR_TOOLTIPLINEAR;Reset curve to linear +CURVEEDITOR_TOOLTIPLOAD;Load a curve from file +CURVEEDITOR_TOOLTIPSAVE;Save current curve +EXIFFILTER_APERTURE;Aperture +EXIFFILTER_CAMERA;Camera +EXIFFILTER_DIALOGLABEL;Exif Filter +EXIFFILTER_FOCALLEN;Focal Length +EXIFFILTER_ISO;ISO +EXIFFILTER_LENS;Lens +EXIFFILTER_SHUTTER;Shutter +EXIFPANEL_ADDEDIT;Add/Edit +EXIFPANEL_ADDEDITHINT;Add new tag or edit tag +EXIFPANEL_ADDTAGDLG_ENTERVALUE;Enter value +EXIFPANEL_ADDTAGDLG_SELECTTAG;Select tag +EXIFPANEL_ADDTAGDLG_TITLE;Add/Edit Tag +EXIFPANEL_KEEP;Keep +EXIFPANEL_KEEPHINT;Keep the selected tags when writing output file +EXIFPANEL_REMOVE;Remove +EXIFPANEL_REMOVEHINT;Remove the selected tags when writing output file +EXIFPANEL_RESET;Reset +EXIFPANEL_RESETALL;Reset All +EXIFPANEL_RESETALLHINT;Reset all tags to their original values +EXIFPANEL_RESETHINT;Reset the selected tags to their original values +EXIFPANEL_SUBDIRECTORY;Subdirectory +FILEBROWSER_APPLYPROFILE;Apply profile +FILEBROWSER_ARRANGEMENTHINT;Change between vertical/horizontal alignment of thumbnails +FILEBROWSER_CLEARPROFILE;Clear profile +FILEBROWSER_COPYPROFILE;Copy profile +FILEBROWSER_DELETEDLGLABEL;File delete confirmation +FILEBROWSER_DELETEDLGMSG;Are you sure you want to delete the selected %1 files? +FILEBROWSER_EMPTYTRASH;Empty Trash +FILEBROWSER_EMPTYTRASHHINT;Permanently delete the files of the trash +FILEBROWSER_EXIFFILTERAPPLY;Apply +FILEBROWSER_EXIFFILTERAPPLYHINT;Switch on/off exif filter of the file browser +FILEBROWSER_EXIFFILTERLABEL;Exif Filter +FILEBROWSER_EXIFFILTERSETTINGS;Setup +FILEBROWSER_EXIFFILTERSETTINGSHINT;Change settings of the exif filter +FILEBROWSER_PARTIALPASTEPROFILE;Partial paste +FILEBROWSER_PASTEPROFILE;Paste profile +FILEBROWSER_POPUPCANCELJOB;Cancel job +FILEBROWSER_POPUPMOVEEND;Move to end of queue +FILEBROWSER_POPUPMOVEHEAD;Move to head of queue +FILEBROWSER_POPUPOPEN;Open +FILEBROWSER_POPUPPROCESS;Put to processing queue +FILEBROWSER_POPUPRANK1;Rank 1 +FILEBROWSER_POPUPRANK2;Rank 2 +FILEBROWSER_POPUPRANK3;Rank 3 +FILEBROWSER_POPUPRANK4;Rank 4 +FILEBROWSER_POPUPRANK5;Rank 5 +FILEBROWSER_POPUPREMOVE;Remove from filesystem +FILEBROWSER_POPUPRENAME;Rename +FILEBROWSER_POPUPSELECTALL;Select all +FILEBROWSER_POPUPTRASH;Move to trash +FILEBROWSER_POPUPUNRANK;Unrank +FILEBROWSER_POPUPUNTRASH;Remove from trash +FILEBROWSER_PROCESSINGSETTINGS;Settings +FILEBROWSER_PROCESSINGSETTINGSHINT;Set the file format and output directory +FILEBROWSER_RENAMEDLGLABEL;Rename file +FILEBROWSER_RENAMEDLGMSG;Rename file "%1" to: +FILEBROWSER_SHOWDIRHINT;Show all images of the directory +FILEBROWSER_SHOWQUEUEHINT;Show content of the processing queue +FILEBROWSER_SHOWRANK1HINT;Show images ranked as 1 star +FILEBROWSER_SHOWRANK2HINT;Show images ranked as 2 star +FILEBROWSER_SHOWRANK3HINT;Show images ranked as 3 star +FILEBROWSER_SHOWRANK4HINT;Show images ranked as 4 star +FILEBROWSER_SHOWRANK5HINT;Show images ranked as 5 star +FILEBROWSER_SHOWTRASHHINT;Show content of the trash +FILEBROWSER_SHOWUNRANKHINT;Show unranked images +FILEBROWSER_STARTPROCESSING;Start Processing +FILEBROWSER_STARTPROCESSINGHINT;Start processing/saving of images in the queue +FILEBROWSER_STOPPROCESSING;Stop processing +FILEBROWSER_STOPPROCESSINGHINT;Stop processing of images +FILEBROWSER_THUMBSIZE;Thumb. size +FILEBROWSER_ZOOMINHINT;Increase thumbnail size +FILEBROWSER_ZOOMOUTHINT;Decrease thumbnail size +GENERAL_ABOUT;About +GENERAL_CANCEL;Cancel +GENERAL_DISABLE;Disable +GENERAL_DISABLED;Disabled +GENERAL_ENABLE;Enable +GENERAL_ENABLED;Enabled +GENERAL_LANDSCAPE;Landscape +GENERAL_LOAD;Load +GENERAL_NA;n/a +GENERAL_NO;No +GENERAL_OK;OK +GENERAL_PORTRAIT;Portrait +GENERAL_SAVE;Save +GENERAL_YES;Yes +HISTOGRAM_LABEL;Histogram +HISTOGRAM_TOOLTIP_B;Show/Hide BLUE histogram +HISTOGRAM_TOOLTIP_G;Show/Hide GREEN histogram +HISTOGRAM_TOOLTIP_L;Show/Hide CIELAB Luminance histogram +HISTOGRAM_TOOLTIP_R;Show/Hide RED histogram +HISTORY_CHANGED;Changed +HISTORY_CUSTOMCURVE;Custom Curve +HISTORY_DELSNAPSHOT;Del +HISTORY_FROMCLIPBOARD;From clipboard +HISTORY_LABEL;History +HISTORY_MSG_10;Shadow Compression +HISTORY_MSG_11;Tone Curve +HISTORY_MSG_12;Auto Exposure +HISTORY_MSG_13;Exposure Clipping +HISTORY_MSG_14;Luminance Brightness +HISTORY_MSG_15;Luminance Contrast +HISTORY_MSG_16;Luminance Black +HISTORY_MSG_17;Luminance Highlight Compr. +HISTORY_MSG_18;Luminance Shadow Compr. +HISTORY_MSG_19;Luminance Curve +HISTORY_MSG_1;Photo Loaded +HISTORY_MSG_20;Sharpening +HISTORY_MSG_21;Sharpening Radius +HISTORY_MSG_22;Sharpening Amount +HISTORY_MSG_23;Sharpening Threshold +HISTORY_MSG_24;Sharpen Only Edges +HISTORY_MSG_25;Sharpening Edge Detection Radius +HISTORY_MSG_26;Sharpening Edge Tolerance +HISTORY_MSG_27;Sharpening Halo Control +HISTORY_MSG_28;Halo Control Amount +HISTORY_MSG_29;Sharpening Method +HISTORY_MSG_2;Profile Loaded +HISTORY_MSG_30;Deconvolution Radius +HISTORY_MSG_31;Deconvolution Amount +HISTORY_MSG_32;Deconvolution Damping +HISTORY_MSG_33;Deconvolution Iterations +HISTORY_MSG_34;Avoid Color Clipping +HISTORY_MSG_35;Saturation Limiter +HISTORY_MSG_36;Saturation Limit +HISTORY_MSG_37;Color Boost +HISTORY_MSG_38;White Balance Method +HISTORY_MSG_39;Color Temperature +HISTORY_MSG_3;Profile Changed +HISTORY_MSG_40;White Balance Tint +HISTORY_MSG_41;Color Shift "A" +HISTORY_MSG_42;Color Shift "B" +HISTORY_MSG_43;Luminance Denoising +HISTORY_MSG_44;Lum. Denoising Radius +HISTORY_MSG_45;Lum. Denoising Edge Tolerance +HISTORY_MSG_46;Color Denoising +HISTORY_MSG_47;Color Denoising Radius +HISTORY_MSG_48;Color Denoising Edge Tolerance +HISTORY_MSG_49;Edge Sensitive Color Denoising +HISTORY_MSG_4;History Browsing +HISTORY_MSG_50;Shadow/Highlight tool +HISTORY_MSG_51;Highlight boost +HISTORY_MSG_52;Shadow Boost +HISTORY_MSG_53;Highlight Tonal Width +HISTORY_MSG_54;Shadow Tonal Width +HISTORY_MSG_55;Local Contrast +HISTORY_MSG_56;Shadow/Highlight Radius +HISTORY_MSG_57;Coarse Rotation +HISTORY_MSG_58;Horizontal Flipping +HISTORY_MSG_59;Vertical Flipping +HISTORY_MSG_5;Brightness +HISTORY_MSG_60;Rotation +HISTORY_MSG_61;Rotation +HISTORY_MSG_62;Lens Distortion Correction +HISTORY_MSG_63;Snapshot Selected +HISTORY_MSG_64;Crop Photo +HISTORY_MSG_65;C/A Correction +HISTORY_MSG_66;Highlight Recovery +HISTORY_MSG_67;Highlight Recovery Amount +HISTORY_MSG_68;Highlight Recovery Method +HISTORY_MSG_69;Working Color Space +HISTORY_MSG_6;Contrast +HISTORY_MSG_70;Output Color Space +HISTORY_MSG_71;Input Color Space +HISTORY_MSG_72;Vignetting Correction +HISTORY_MSG_73;Channel Mixer +HISTORY_MSG_74;Resize Scale +HISTORY_MSG_75;Resize Method +HISTORY_MSG_76;Exif Metadata +HISTORY_MSG_77;IPTC Metadata +HISTORY_MSG_78;Data specified for resize +HISTORY_MSG_79;Resize width +HISTORY_MSG_80;Resize height +HISTORY_MSG_81;Resize enabled +HISTORY_MSG_7;Black +HISTORY_MSG_8;Exposure Compensation +HISTORY_MSG_9;Highlight Compression +HISTORY_NEWSNAPSHOT;Add +HISTORY_NEWSNAPSHOTAS;As... +HISTORY_NEWSSDIALOGLABEL;Label of the snapshot: +HISTORY_NEWSSDIALOGTITLE;Add new snapshot +HISTORY_SETTO;Set to +HISTORY_SNAPSHOT;Snapshot +HISTORY_SNAPSHOTS;Snapshots +ICMPANEL_FILEDLGFILTERANY;Any files +ICMPANEL_FILEDLGFILTERICM;ICC Profile Files +ICMPANEL_GAMMABEFOREINPUT;Profile applies Gamma +ICMPANEL_INPUTCAMERA;Camera default +ICMPANEL_INPUTCUSTOM;Custom +ICMPANEL_INPUTDLGLABEL;Select Input ICC Profile... +ICMPANEL_INPUTEMBEDDED;Use Embedded, if possible +ICMPANEL_INPUTPROFILE;Input Profile +ICMPANEL_NOICM;No ICM: sRGB output +ICMPANEL_OUTPUTDLGLABEL;Select Output ICC Profile... +ICMPANEL_OUTPUTPROFILE;Output Profile +ICMPANEL_SAVEREFERENCE;Save reference image for profiling +ICMPANEL_WORKINGPROFILE;Working Profile +IMAGEAREA_DETAILVIEW;Detail view +IPTCPANEL_AUTHOR;Author +IPTCPANEL_AUTHORHINT;Name of the creator of the object, e.g. writer, photographer or graphic artist (By-line). +IPTCPANEL_AUTHORSPOSITION;Author's position +IPTCPANEL_AUTHORSPOSITIONHINT;Title of the creator or creators of the object (By-line Title). +IPTCPANEL_CAPTION;Caption +IPTCPANEL_CAPTIONHINT;A textual description of the data (Caption - Abstract). +IPTCPANEL_CAPTIONWRITER;Caption Writer +IPTCPANEL_CAPTIONWRITERHINT;The name of the person involved in the writing, editing or correcting the image or caption/abstract (Writer - Editor). +IPTCPANEL_CATEGORY;Category +IPTCPANEL_CATEGORYHINT;Identifies the subject of the image in the opinion of the provider (Category). +IPTCPANEL_CITY;City +IPTCPANEL_CITYHINT;City of image origin (City). +IPTCPANEL_COPYHINT;Copy IPTC settings to clipboard +IPTCPANEL_COPYRIGHT;Copyright +IPTCPANEL_COPYRIGHTHINT;Any necessary copyright notice (Copyright Notice). +IPTCPANEL_COUNTRY;Country +IPTCPANEL_COUNTRYHINT;The name of the country/primary location where the image was created (Country - Primary Location Name). +IPTCPANEL_CREDIT;Credit +IPTCPANEL_CREDITHINT;Identifies the provider of the image, not necessarily the owner/creator (Credit). +IPTCPANEL_DATECREATED;Date Created +IPTCPANEL_DATECREATEDHINT;The date the intellectual content of the image was created; Format: JJJJMMTT (Date Created). +IPTCPANEL_EMBEDDED;Embedded +IPTCPANEL_EMBEDDEDHINT;Reset to IPTC data embedded in the image file +IPTCPANEL_HEADLINE;Headline +IPTCPANEL_HEADLINEHINT;A publishable entry providing a synopsis of the contents of the image (Headline). +IPTCPANEL_INSTRUCTIONS;Instructions +IPTCPANEL_INSTRUCTIONSHINT;Other editorial instructions concerning the use of the image (Special Instructions). +IPTCPANEL_KEYWORDS;Keywords +IPTCPANEL_KEYWORDSHINT;Used to indicate specific information retrieval words (Keywords). +IPTCPANEL_PASTEHINT;Paste IPTC settings from clipboard +IPTCPANEL_PROVINCE;Province +IPTCPANEL_PROVINCEHINT;The Province/State where the image originates (Province-State). +IPTCPANEL_RESET;Reset +IPTCPANEL_RESETHINT;Reset to profile default +IPTCPANEL_SOURCE;Source +IPTCPANEL_SOURCEHINT;The original owner of the intellectual content of the image (Source). +IPTCPANEL_SUPPCATEGORIES;Suppl. Categories +IPTCPANEL_SUPPCATEGORIESHINT;Further refines the subject of the image (Supplemental Categories). +IPTCPANEL_TITLE;Title +IPTCPANEL_TITLEHINT;A shorthand reference for the image (Object Name). +IPTCPANEL_TRANSREFERENCE;Trans. Reference +IPTCPANEL_TRANSREFERENCEHINT;A code representing the location of original transmission (Original Transmission Reference). +MAIN_BUTTON_PREFERENCES;Preferences +MAIN_BUTTON_SAVE;Save Image +MAIN_BUTTON_SAVEAS;As... +MAIN_BUTTON_SENDTOEDITOR;Send to editor +MAIN_MSG_ALREADYEXISTS;File already exists. +MAIN_MSG_CANNOTLOAD;Cannot load image +MAIN_MSG_CANNOTSAVE;File saving error +MAIN_MSG_CANNOTSTARTEDITOR;Can not start editor. +MAIN_MSG_CANNOTSTARTEDITOR_SECONDARY;Please set the correct path in the "Preferences" dialog. +MAIN_MSG_EXITJOBSINQUEUEINFO;Unprocessed images in the queue will be lost on exit. +MAIN_MSG_EXITJOBSINQUEUEQUEST;Are you sure you want to exit? There are unprocessed images waiting in the queue. +MAIN_MSG_JOBSINQUEUE;job(s) in the queue +MAIN_MSG_QOVERWRITE;Do you want to overwrite it? +MAIN_TAB_BASIC;Basic +MAIN_TAB_COLOR;Color +MAIN_TAB_DETAIL;Detail +MAIN_TAB_EXIF;Exif +MAIN_TAB_EXPOSURE;Exposure +MAIN_TAB_ICM;ICM +MAIN_TAB_IPTC;IPTC +MAIN_TAB_METADATA;Metadata +MAIN_TAB_TRANSFORM;Transform +MAIN_TOOLTIP_HIDEFP;Show/hide the bottom panel (directory and file browser, shortcut key: F) +MAIN_TOOLTIP_HIDEHP;Show/hide the left panel (including the history, shortcut key: H) +MAIN_TOOLTIP_INDCLIPPEDH;Clipped highlight indication +MAIN_TOOLTIP_INDCLIPPEDS;Clipped shadow indication +MAIN_TOOLTIP_PREFERENCES;Set preferences +MAIN_TOOLTIP_QINFO;Quick info on the image +MAIN_TOOLTIP_SAVE;Save image to the default folder +MAIN_TOOLTIP_SAVEAS;Save image to a selected folder +PARTIALPASTE_BASICGROUP;Basic settings +PARTIALPASTE_CACORRECTION;C/A correction +PARTIALPASTE_COARSETRANS;90 deg rotation / flipping +PARTIALPASTE_COLORBOOST;Color boost +PARTIALPASTE_COLORDENOISE;Color denoise +PARTIALPASTE_COLORGROUP;Color related settings +PARTIALPASTE_COLORMIXER;Color mixer +PARTIALPASTE_COLORSHIFT;Color shift +PARTIALPASTE_COMPOSITIONGROUP;Composition settings +PARTIALPASTE_CROP;Crop +PARTIALPASTE_DIALOGLABEL;Partial paste processing profile +PARTIALPASTE_DISTORTION;Distortion correction +PARTIALPASTE_EXIFCHANGES;Changes to exif data +PARTIALPASTE_EXPOSURE;Exposure +PARTIALPASTE_HLRECOVERY;Highlight recovery +PARTIALPASTE_ICMSETTINGS;ICM settings +PARTIALPASTE_IPTCINFO;IPTC info +PARTIALPASTE_LENSGROUP;Lens related settings +PARTIALPASTE_LUMACURVE;Luminance curve +PARTIALPASTE_LUMADENOISE;Luminance noise reduction +PARTIALPASTE_LUMINANCEGROUP;Luminance related settings +PARTIALPASTE_METAICMGROUP;Metadata/ICM settings +PARTIALPASTE_RESIZE;Resize +PARTIALPASTE_ROTATION;Rotation +PARTIALPASTE_SHADOWSHIGHLIGHTS;Shadows/Highlights +PARTIALPASTE_SHARPENING;Sharpening +PARTIALPASTE_VIGNETTING;Vignetting correction +PARTIALPASTE_WHITEBALANCE;White balance +PREFERENCES_APPLNEXTSTARTUP;applied at next startup +PREFERENCES_BLINKCLIPPED;Blink clipped areas +PREFERENCES_CACHECLEARALL;Clear All +PREFERENCES_CACHECLEARPROFILES;Clear Profiles +PREFERENCES_CACHECLEARTHUMBS;Clear Thumbnails +PREFERENCES_CACHEFORMAT1;Proprietary (faster and better quality) +PREFERENCES_CACHEFORMAT2;JPEG (smaller disk footprint) +PREFERENCES_CACHEMAXENTRIES;Maximal Number of Cache Entries +PREFERENCES_CACHEOPTS;Cache Options +PREFERENCES_CACHESTRAT1;Prefer Speed to Low Memory Consumption +PREFERENCES_CACHESTRAT2;Prefer Low Memory Consumption to Speed +PREFERENCES_CACHESTRAT;Cache Strategy +PREFERENCES_CACHETHUMBFORM;Cache Thumbnail Format +PREFERENCES_CACHETHUMBHEIGHT;Maximal Thumbnail Height +PREFERENCES_CLEARDLG_LINE1;Clearing cache +PREFERENCES_CLEARDLG_LINE2;This may take a few seconds. +PREFERENCES_CLEARDLG_TITLE;Please wait +PREFERENCES_CLIPPINGIND;Clipping indication +PREFERENCES_CMETRICINTENT;Colorimetric Intent +PREFERENCES_DATEFORMAT;Date Format +PREFERENCES_DATEFORMATHINT;You can use the following formatting strings:\n%y : year\n%m : month\n%d : day\n\nFor example, the hungarian date format is:\n%y/%m/%d +PREFERENCES_DEFAULTLANG;Default language +PREFERENCES_DEFAULTTHEME;Default theme +PREFERENCES_DEMOSAICINGALGO;Demosaicing Algorithm +PREFERENCES_DIRHOME;Home directory +PREFERENCES_DIRLAST;Last visited directory +PREFERENCES_DIROTHER;Other +PREFERENCES_DIRSELECTDLG;Select Image Directory at Startup... +PREFERENCES_DIRSOFTWARE;Installation directory +PREFERENCES_DMETHOD;Method +PREFERENCES_EDITORCMDLINE;Other command line +PREFERENCES_EXTERNALEDITOR;External editor +PREFERENCES_FALSECOLOR;False color surpression steps +PREFERENCES_FBROWSEROPTS;File Browser Options +PREFERENCES_FILEFORMAT;File Format +PREFERENCES_FORIMAGE;For image files +PREFERENCES_FORRAW;For RAW files +PREFERENCES_GIMPPATH;GIMP installation directory +PREFERENCES_GTKTHEME;GTK default +PREFERENCES_HINT;Hint +PREFERENCES_HLTHRESHOLD;Threshold for clipped highlights +PREFERENCES_ICCDIR;Directory of ICC profiles +PREFERENCES_IMPROCPARAMS;Default image processing parameters +PREFERENCES_INTENT_ABSOLUTE;Absolute Colorimetric +PREFERENCES_INTENT_PERCEPTUAL;Perceptual +PREFERENCES_INTENT_RELATIVE;Relative Colorimetric +PREFERENCES_INTENT_SATURATION;Saturation +PREFERENCES_LIVETHUMBNAILS;Live Thumbnails (slower) +PREFERENCES_MONITORICC;Monitor Profile +PREFERENCES_OUTDIR;Output Directory +PREFERENCES_OUTDIRFOLDER;Save to folder +PREFERENCES_OUTDIRFOLDERHINT;Put the saved images to the seledted folder +PREFERENCES_OUTDIRHINT;You can use the following formatting strings:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nThese formatting strings refer to the directories and sub-paths of the path of the raw file.\n\nFor example, if /home/tom/image/02-09-2006/dsc0012.nefhas been opened, the meaning of the formatting strings are:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nIf you want to save the output image where the original is, write:\n%p1/%f\n\nIf you want to save the output image in a directory 'converted' located the directory of the original, write:\n%p1/converted/%f\n\nIf you want to save the output image in directory '/home/tom/converted' with keeping the same subdirectory of dates, write:\n%p2/converted/%d1/%f +PREFERENCES_OUTDIRTEMPLATE;Use Template +PREFERENCES_OUTDIRTEMPLATEHINT;You can use the following formatting strings:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nThese formatting strings refer to the directories and sub-paths of the path of the raw file.\n\nFor example, if /home/tom/image/02-09-2006/dsc0012.nefhas been opened, the meaning of the formatting strings are:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nIf you want to save the output image where the original is, write:\n%p1/%f\n\nIf you want to save the output image in a directory 'converted' located the directory of the original, write:\n%p1/converted/%f\n\nIf you want to save the output image in directory '/home/tom/converted' with keeping the same subdirectory of dates, write:\n%p2/converted/%d1/%f +PREFERENCES_PARSEDEXT;Parsed Extensions +PREFERENCES_PARSEDEXTADD;Add Extension +PREFERENCES_PARSEDEXTADDHINT;Type an extension and press this button to append list +PREFERENCES_PARSEDEXTDELHINT;Delete selected extension from the list +PREFERENCES_PROFILEHANDLING;Processing Profile Handling +PREFERENCES_PROFILELOADPR;Profile Loading Priority +PREFERENCES_PROFILEPRCACHE;Profile in Cache +PREFERENCES_PROFILEPRFILE;Profile Next to the Input File +PREFERENCES_PROFILESAVECACHE;Save Processing Parameters to the Cache +PREFERENCES_PROFILESAVEINPUT;Save Processing Parameters Next to the Input File +PREFERENCES_PSPATH;Adobe Photoshop installation directory +PREFERENCES_SELECTICCDIRDLG;Select ICC Profile Directory... +PREFERENCES_SELECTLANG;Select language +PREFERENCES_SELECTMONITORPROFDLG;Select ICC Profile of the Display... +PREFERENCES_SELECTTHEME;Select theme +PREFERENCES_SHOWBASICEXIF;Show basic Exif info +PREFERENCES_SHOWDATETIME;Show date and time +PREFERENCES_SHOWONLYRAW;Show only RAW files +PREFERENCES_SHTHRESHOLD;Threshold for clipped shadows +PREFERENCES_STARTUPIMDIR;Image directory at startup +PREFERENCES_TAB_BROWSER;File Browser +PREFERENCES_TAB_COLORMGR;Color Management +PREFERENCES_TAB_GENERAL;General +PREFERENCES_TAB_IMPROC;Image Processing +PREFERENCES_TAB_OUTPUT;Output Options +PREFERENCES_THUMBSIZE;Thumbnail Size +PROFILEPANEL_FILEDLGFILTERANY;Any files +PROFILEPANEL_FILEDLGFILTERPP;Postprocessing profiles +PROFILEPANEL_LABEL;Postprocessing Profiles +PROFILEPANEL_LOADDLGLABEL;Load Postprocessing Parameters... +PROFILEPANEL_PCUSTOM;Custom +PROFILEPANEL_PFILE;From file +PROFILEPANEL_PLASTPHOTO;Last Photo +PROFILEPANEL_PLASTSAVED;Last Saved +PROFILEPANEL_PROFILE;Profile +PROFILEPANEL_SAVEDLGLABEL;Save Postprocessing Parameters... +PROFILEPANEL_TOOLTIPCOPY;Copy current profile to clipboard +PROFILEPANEL_TOOLTIPLOAD;Load a profile from file +PROFILEPANEL_TOOLTIPPASTE; Paste profile from clipboard +PROFILEPANEL_TOOLTIPSAVE;Save current profile +PROGRESSBAR_DECODING;Decoding raw file... +PROGRESSBAR_DEMOSAICING;Demosaicing... +PROGRESSBAR_LOADING;Loading Image... +PROGRESSBAR_LOADJPEG;Loading JPEG file... +PROGRESSBAR_LOADPNG;Loading PNG file... +PROGRESSBAR_LOADTIFF;Loading TIFF file... +PROGRESSBAR_PROCESSING;Processing Image... +PROGRESSBAR_READY;Ready. +PROGRESSBAR_SAVEJPEG;Saving JPEG file... +PROGRESSBAR_SAVEPNG;Saving PNG file... +PROGRESSBAR_SAVETIFF;Saving TIFF file... +PROGRESSDLG_LOADING;Loading file... +PROGRESSDLG_PROCESSING;Processing image... +PROGRESSDLG_SAVING;Saving file... +QINFO_FOCALLENGTH;Focal length +QINFO_ISO;ISO +QINFO_LENS;Lens +QINFO_NOEXIF;Exif data not available. +SAVEDLG_FILEFORMAT;File format +SAVEDLG_JPEGQUAL;JPEG Quality +SAVEDLG_JPGFILTER;JPEG files +SAVEDLG_PNGCOMPR;PNG Compression +SAVEDLG_PNGFILTER;PNG files +SAVEDLG_PUTTOQUEUE;Put into processing queue +SAVEDLG_PUTTOQUEUEHEAD;Put to the head of the processing queue +SAVEDLG_PUTTOQUEUETAIL;Put to the end of the processing queue +SAVEDLG_SAVEIMMEDIATELY;Save immediately +SAVEDLG_SAVESPP;Save processing parameters with image +SAVEDLG_TIFFFILTER;TIFF files +TOOLBAR_TOOLTIP_CROP;Crop selection (Shortcut key: C) +TOOLBAR_TOOLTIP_HAND;Hand tool (Shortcut key: N) +TOOLBAR_TOOLTIP_STRAIGHTEN;Straight line selection (Shortcut key: S) +TOOLBAR_TOOLTIP_WB;Spot white balance (Shortcut key: W) +TP_CACORRECTION_BLUE;Blue +TP_CACORRECTION_LABEL;C/A Correction +TP_CACORRECTION_RED;Red +TP_CHMIXER_BLUE;Blue +TP_CHMIXER_GREEN;Green +TP_CHMIXER_LABEL;Channel Mixer +TP_CHMIXER_RED;Red +TP_COARSETRAF_DEGREE;degree: +TP_COARSETRAF_TOOLTIP_HFLIP;Flip horizontally +TP_COARSETRAF_TOOLTIP_ROTLEFT;Rotate left +TP_COARSETRAF_TOOLTIP_ROTRIGHT;Rotate right +TP_COARSETRAF_TOOLTIP_VFLIP;Flip vertically +TP_COLORBOOST_ACHANNEL;Channel "a" +TP_COLORBOOST_AMOUNT;Amount +TP_COLORBOOST_AVOIDCOLORCLIP;Avoid color clipping +TP_COLORBOOST_BCHANNEL;Channel "b" +TP_COLORBOOST_CHAB;a & b +TP_COLORBOOST_CHANNEL;Channel +TP_COLORBOOST_CHSEPARATE;separate +TP_COLORBOOST_ENABLESATLIMITER;Enable saturation limiter +TP_COLORBOOST_LABEL;Color Boost +TP_COLORBOOST_SATLIMIT;Saturation limit +TP_COLORDENOISE_EDGESENSITIVE;Edge Sensitive +TP_COLORDENOISE_EDGETOLERANCE;Edge Tolerance +TP_COLORDENOISE_LABEL;Color Noise Reduction +TP_COLORDENOISE_RADIUS;Radius +TP_COLORSHIFT_BLUEYELLOW;Blue-Yellow +TP_COLORSHIFT_GREENMAGENTA;Green-Magenta +TP_COLORSHIFT_LABEL;Color Shift +TP_CROP_DPI;DPI= +TP_CROP_FIXRATIO;Fix Ratio: +TP_CROP_GTDIAGONALS;Rule of diagonals +TP_CROP_GTHARMMEANS1;Harmonic means 1 +TP_CROP_GTHARMMEANS2;Harmonic means 2 +TP_CROP_GTHARMMEANS3;Harmonic means 3 +TP_CROP_GTHARMMEANS4;Harmonic means 4 +TP_CROP_GTNONE;None +TP_CROP_GTRULETHIRDS;Rule of thirds +TP_CROP_GUIDETYPE;Guide Type: +TP_CROP_H;H +TP_CROP_LABEL;Crop +TP_CROP_SELECTCROP; Select Crop +TP_CROP_W;W +TP_CROP_X;x +TP_CROP_Y;y +TP_DISTORTION_AMOUNT;Amount +TP_DISTORTION_LABEL;Distortion +TP_EXPOSURE_AUTOLEVELS;Auto Levels +TP_EXPOSURE_BLACKLEVEL;Black +TP_EXPOSURE_BRIGHTNESS;Brightness +TP_EXPOSURE_CLIP;Clip +TP_EXPOSURE_COMPRHIGHLIGHTS;Highlight compression +TP_EXPOSURE_COMPRSHADOWS;Shadow compression +TP_EXPOSURE_CONTRAST;Contrast +TP_EXPOSURE_CURVEEDITOR;Tone Curve +TP_EXPOSURE_EXPCOMP;Exp. Comp. +TP_EXPOSURE_LABEL;Exposure +TP_HLREC_CIELAB;CIELab Blending +TP_HLREC_COLOR;Color Propagation +TP_HLREC_LABEL;Highlight Recovery +TP_HLREC_LUMINANCE;Luminance Recovery +TP_HLREC_METHOD;Method: +TP_ICM_FILEDLGFILTERANY;Any files +TP_ICM_FILEDLGFILTERICM;ICC Profile Files +TP_ICM_GAMMABEFOREINPUT;Profile applies Gamma +TP_ICM_INPUTCAMERA;Camera default +TP_ICM_INPUTCUSTOM;Custom +TP_ICM_INPUTDLGLABEL;Select Input ICC Profile... +TP_ICM_INPUTEMBEDDED;Use Embedded, if possible +TP_ICM_INPUTPROFILE;Input Profile +TP_ICM_LABEL;ICM +TP_ICM_NOICM;No ICM: sRGB output +TP_ICM_OUTPUTDLGLABEL;Select Output ICC Profile... +TP_ICM_OUTPUTPROFILE;Output Profile +TP_ICM_SAVEREFERENCE;Save reference image for profiling +TP_ICM_WORKINGPROFILE;Working Profile +TP_LUMACURVE_BLACKLEVEL;Black +TP_LUMACURVE_BRIGHTNESS;Brightness +TP_LUMACURVE_COMPRHIGHLIGHTS;Highlight compression +TP_LUMACURVE_COMPRSHADOWS;Shadow compression +TP_LUMACURVE_CONTRAST;Contrast +TP_LUMACURVE_CURVEEDITOR;Luminance Curve +TP_LUMACURVE_LABEL;Luminance Curve +TP_LUMADENOISE_EDGETOLERANCE;Edge Tolerance +TP_LUMADENOISE_LABEL;Luminance Noise Reduction +TP_LUMADENOISE_RADIUS;Radius +TP_RESIZE_BICUBIC;Bicubic +TP_RESIZE_BICUBICSF;Bicubic (Softer) +TP_RESIZE_BICUBICSH;Bicubic (Sharper) +TP_RESIZE_BILINEAR;Bilinear +TP_RESIZE_FULLSIZE;Full Image Size: +TP_RESIZE_H;H: +TP_RESIZE_LABEL;Resize +TP_RESIZE_METHOD;Method: +TP_RESIZE_NEAREST;Nearest +TP_RESIZE_SCALE;Scale +TP_RESIZE_W;W: +TP_ROTATE_AUTOCROP;Auto Crop +TP_ROTATE_DEGREE;Degree +TP_ROTATE_FILL;Fill +TP_ROTATE_LABEL;Rotate +TP_ROTATE_SELECTLINE; Select Straight Line +TP_SHADOWSHLIGHTS_HIGHLIGHTS;Highlights +TP_SHADOWSHLIGHTS_HLTONALW;Tonal Width +TP_SHADOWSHLIGHTS_LABEL;Shadows/Highlights +TP_SHADOWSHLIGHTS_LOCALCONTR;Local Contrast +TP_SHADOWSHLIGHTS_RADIUS;Radius +TP_SHADOWSHLIGHTS_SHADOWS;Shadows +TP_SHADOWSHLIGHTS_SHTONALW;Tonal Width +TP_SHARPENING_AMOUNT;Amount +TP_SHARPENING_EDRADIUS;Radius +TP_SHARPENING_EDTOLERANCE;Edge tolerance +TP_SHARPENING_HALOCONTROL;Halo control +TP_SHARPENING_HCAMOUNT;Amount +TP_SHARPENING_LABEL;Sharpening +TP_SHARPENING_METHOD;Method +TP_SHARPENING_ONLYEDGES;Sharpen only edges +TP_SHARPENING_RADIUS;Radius +TP_SHARPENING_RLD;RL Deconvolution +TP_SHARPENING_RLD_AMOUNT;Amount +TP_SHARPENING_RLD_DAMPING;Damping +TP_SHARPENING_RLD_ITERATIONS;Iterations +TP_SHARPENING_THRESHOLD;Threshold +TP_SHARPENING_USM;Unsharp Mask +TP_VIGNETTING_AMOUNT;Amount +TP_VIGNETTING_LABEL;Vignetting Correction +TP_VIGNETTING_RADIUS;Radius +TP_WBALANCE_AUTO;Auto +TP_WBALANCE_CAMERA;Camera +TP_WBALANCE_CUSTOM;Custom +TP_WBALANCE_GREEN;Tint +TP_WBALANCE_LABEL;White Balance +TP_WBALANCE_METHOD;Method +TP_WBALANCE_SIZE;Size: +TP_WBALANCE_SPOTWB;Spot WB +TP_WBALANCE_TEMPERATURE;Temperature +ZOOMBAR_DETAIL;Detail +ZOOMBAR_HUGE;Huge +ZOOMBAR_LARGE;Large +ZOOMBAR_NORMAL;Normal +ZOOMBAR_PREVIEW;Preview +ZOOMBAR_SCALE;Scale +ZOOMBAR_SMALL;Small diff --git a/release/languages/espanol b/release/languages/espanol new file mode 100755 index 000000000..a28881fe2 --- /dev/null +++ b/release/languages/espanol @@ -0,0 +1,583 @@ +# Espanol +# 15.1.2008: keenonkites, first translation +# 03.03.2008: Ioritz Ibarguren, corrections +# 05.04.2008: keenonkites, completed for 2.4m1 +# 09.04.2008: Ramon, partly corrected (part of 2.3) +# 29.04.2008: Ramon, small correction +# 09.06.2008: Ramon, Adaptions regarding 2.4m1 and others +# 20.09.2008: keenonkites, first version for 2.4m2 +# 19.12.2008: keenonkites, first version for 2.4beta4 +ADJUSTER_RESET_TO_DEFAULT;Restablece los valores predeterminados +CURVEEDITOR_FILEDLGFILTERANY;Cuaquier archivo +CURVEEDITOR_FILEDLGFILTERCURVE;Archivos de curvas +CURVEEDITOR_LINEAR;Lineal +CURVEEDITOR_LOADDLGLABEL;Cargar curva... +CURVEEDITOR_SAVEDLGLABEL;Guardar curva... +CURVEEDITOR_TOOLTIPLINEAR;Restablece la curva a lineal +CURVEEDITOR_TOOLTIPLOAD;Abre una curva desde un archivo +CURVEEDITOR_TOOLTIPSAVE;Guarda curva actual +EXIFFILTER_APERTURE;Diafragma +EXIFFILTER_CAMERA;Cámera +EXIFFILTER_DIALOGLABEL;Filtro Exif +EXIFFILTER_FOCALLEN;Distancia focal +EXIFFILTER_ISO;ISO +EXIFFILTER_LENS;Objectivo +EXIFFILTER_SHUTTER;tiempo de exposición +EXIFPANEL_ADDEDIT;Agregar/Cambiar +EXIFPANEL_ADDEDITHINT;Agregar atributo nuevo o cambiar atributo +EXIFPANEL_ADDTAGDLG_ENTERVALUE;Entroducir valor +EXIFPANEL_ADDTAGDLG_SELECTTAG;Seleccionar atributo +EXIFPANEL_ADDTAGDLG_TITLE;Agregar/Cambiar atributo +EXIFPANEL_KEEP;Conservar +EXIFPANEL_KEEPHINT;Conserva las etiquetas seleccionadas al escribir el archivo de salida +EXIFPANEL_REMOVE;Borrar +EXIFPANEL_REMOVEHINT;Quita las etiquetas seleccionadas al escribir el archivo de salida +EXIFPANEL_RESET;Reiniciar +EXIFPANEL_RESETALL;Reiniciar todo +EXIFPANEL_RESETALLHINT;Reiniciar todos los atributos a los valores originales +EXIFPANEL_RESETHINT;Reiniciar atributos seleccionados a los valores originales +EXIFPANEL_SUBDIRECTORY;Subcarpeta +FILEBROWSER_APPLYPROFILE;Aplicar perfil +FILEBROWSER_ARRANGEMENTHINT;Cambiar disposición de las miniaturas entre horizontal y vertical +FILEBROWSER_CLEARPROFILE;Borrar perfil +FILEBROWSER_COPYPROFILE;Copiar perfil +FILEBROWSER_DELETEDLGLABEL;Confirmacion de borrar archivos +FILEBROWSER_DELETEDLGMSG;¿Seguro que quieres borrar los %1 archivos seleccionados? +FILEBROWSER_EMPTYTRASH;Vaciar papelera +FILEBROWSER_EMPTYTRASHHINT;Borrar archivos de la papelera definitivamente +FILEBROWSER_EXIFFILTERAPPLY;Aplicar +FILEBROWSER_EXIFFILTERAPPLYHINT;Activar/desactivar filtro exif en el explorador de archivos +FILEBROWSER_EXIFFILTERLABEL;Filtro Exif +FILEBROWSER_EXIFFILTERSETTINGS;Ajuste +FILEBROWSER_EXIFFILTERSETTINGSHINT;Cambiar ajustes del filtro exif +FILEBROWSER_PARTIALPASTEPROFILE;Pegar perfil parcialmente +FILEBROWSER_PASTEPROFILE;Pegar perfil +FILEBROWSER_POPUPCANCELJOB;Cancelar trabajo +FILEBROWSER_POPUPMOVEEND;Desplazar al fin de la cola +FILEBROWSER_POPUPMOVEHEAD;Desplazar al comienzo de la cola +FILEBROWSER_POPUPOPEN;Abrir +FILEBROWSER_POPUPPROCESS;Poner en la cola +FILEBROWSER_POPUPRANK1;Valorar con 1 estrella +FILEBROWSER_POPUPRANK2;Valorar con 2 estrella +FILEBROWSER_POPUPRANK3;Valorar con 3 estrella +FILEBROWSER_POPUPRANK4;Valorar con 4 estrella +FILEBROWSER_POPUPRANK5;Valorar con 5 estrella +FILEBROWSER_POPUPREMOVE;Borrar del systema +FILEBROWSER_POPUPRENAME;Renombrar +FILEBROWSER_POPUPSELECTALL;Seleccionar todo +FILEBROWSER_POPUPTRASH;Desplazar a la papelera +FILEBROWSER_POPUPUNRANK;Quitar valoración +FILEBROWSER_POPUPUNTRASH;Salvar de la papelera +FILEBROWSER_PROCESSINGSETTINGS;Ajustes +FILEBROWSER_PROCESSINGSETTINGSHINT;Ajustar formato de archivo y carpeta de salida +FILEBROWSER_RENAMEDLGLABEL;Renombrar archivo +FILEBROWSER_RENAMEDLGMSG;Renombrar archive "%1"a: +FILEBROWSER_SHOWDIRHINT;Mostrar todas imagenes de la carpeta +FILEBROWSER_SHOWQUEUEHINT;Mostrar contenido de la cola de procesamiento +FILEBROWSER_SHOWRANK1HINT;Mostrar imagenes con 1 estrella +FILEBROWSER_SHOWRANK2HINT;Mostrar imagenes con 2 estrellas +FILEBROWSER_SHOWRANK3HINT;Mostrar imagenes con 3 estrellas +FILEBROWSER_SHOWRANK4HINT;Mostrar imagenes con 4 estrellas +FILEBROWSER_SHOWRANK5HINT;Mostrar imagenes con 5 estrellas +FILEBROWSER_SHOWTRASHHINT;Mostrar contenido de la papelera +FILEBROWSER_SHOWUNRANKHINT;Mostrar imagenes sin valoración +FILEBROWSER_STARTPROCESSING;Iniciar procesamiento +FILEBROWSER_STARTPROCESSINGHINT;Iniciar procesamiento de imagenes en la cola +FILEBROWSER_STOPPROCESSING;Parar procesamiento +FILEBROWSER_STOPPROCESSINGHINT;Parar procesamiento de imagenes en la cola +FILEBROWSER_THUMBSIZE;Tamaño miniatura +FILEBROWSER_ZOOMINHINT;Agrandar miniatura +FILEBROWSER_ZOOMOUTHINT;Reducir miniatura +GENERAL_ABOUT;Acerca de +GENERAL_CANCEL;Cancelar +GENERAL_DISABLE;Desactivar +GENERAL_DISABLED;Desactivado +GENERAL_ENABLE;Activar +GENERAL_ENABLED;Activado +GENERAL_LANDSCAPE;Paisaje +GENERAL_LOAD;Abrir +GENERAL_NA;n/a +GENERAL_NO;No +GENERAL_OK;Aceptar +GENERAL_PORTRAIT;Retrato +GENERAL_SAVE;Guardar +GENERAL_YES;Sí +HISTOGRAM_LABEL;Histograma +HISTOGRAM_TOOLTIP_B;Mostrar/Ocultar histograma AZUL +HISTOGRAM_TOOLTIP_G;Mostrar/Ocultar histograma VERDE +HISTOGRAM_TOOLTIP_L;Mostrar/Ocultar histograma de Luminancia CIELAB +HISTOGRAM_TOOLTIP_R;Mostrar/Ocultar histograma ROJO +HISTORY_CHANGED;Cambiado +HISTORY_CUSTOMCURVE;Curva a medida +HISTORY_DELSNAPSHOT;Quitar Instantánea +HISTORY_FROMCLIPBOARD;Desde el portapapeles +HISTORY_LABEL;Historial +HISTORY_MSG_10;Compresión de Sombras +HISTORY_MSG_11;Curva de Tono +HISTORY_MSG_12;Exposición Automática +HISTORY_MSG_13;Recorte de Exposición +HISTORY_MSG_14;Luminancia Brillo +HISTORY_MSG_15;Luminancia Contraste +HISTORY_MSG_16;Luminancia Negro +HISTORY_MSG_17;Luminancia Compr. de Luces Altas +HISTORY_MSG_18;Luminancia Compr. de Sombras +HISTORY_MSG_19;Luminancia Curva +HISTORY_MSG_1;Foto Abierta +HISTORY_MSG_20;Enfoque +HISTORY_MSG_21;Enfoque Radio +HISTORY_MSG_22;Enfoque Cantidad +HISTORY_MSG_23;Enfoque Umbral +HISTORY_MSG_24;Enfocar solo Bordes +HISTORY_MSG_25;Enfoque Detección de Bordes Radio +HISTORY_MSG_26;Enfoque Tolerancia de bordes +HISTORY_MSG_27;Enfoque Control de Halo +HISTORY_MSG_28;Control de Halo Cantidad +HISTORY_MSG_29;Enfoque Método +HISTORY_MSG_2;Perfil Abierto +HISTORY_MSG_30;Deconvolución Radio +HISTORY_MSG_31;Deconvolución Cantidad +HISTORY_MSG_32;Deconvolución Amortiguación +HISTORY_MSG_33;Deconvolución Reiteraciones +HISTORY_MSG_34;Evitar Recorte de Colores +HISTORY_MSG_35;Limitador de Saturación +HISTORY_MSG_36;Límite de Saturación +HISTORY_MSG_37;Aumento de Colores +HISTORY_MSG_38;Equilibrio del Blancos Método +HISTORY_MSG_39;Temperatura de Color +HISTORY_MSG_3;Perfil Cambiado +HISTORY_MSG_40;Equilibrio del Blancos Tinte +HISTORY_MSG_41;Cambio de Colores "A" +HISTORY_MSG_42;Cambio de Colores "B" +HISTORY_MSG_43;Reducción Ruido de Luminancia +HISTORY_MSG_44;Red. Ruido de Lum. Radio +HISTORY_MSG_45;Red. Ruido de Lum. Tolerancia de Bordes +HISTORY_MSG_46;Red. Ruido de Color +HISTORY_MSG_47;Red. Ruido de Color Radio +HISTORY_MSG_48;Red. Ruido de Color Tolerancia de bordes +HISTORY_MSG_49;Red. Ruido de Color Sensible a bordes +HISTORY_MSG_4;Búsqueda de Historial +HISTORY_MSG_50;Herramienta Sombras/Luces Altas +HISTORY_MSG_51;Aumento de Luces altas +HISTORY_MSG_52;Aumento de Sombras +HISTORY_MSG_53;Luces altas Ancho Tonal +HISTORY_MSG_54;Sombras Ancho Tonal +HISTORY_MSG_55;Constraste local +HISTORY_MSG_56;Sombras/Luces altas Radio +HISTORY_MSG_57;Rotación basta +HISTORY_MSG_58;Volteo horizontal +HISTORY_MSG_59;Volteo vertical +HISTORY_MSG_5;Brillo +HISTORY_MSG_60;Rotación +HISTORY_MSG_61;Rotación +HISTORY_MSG_62;Corrección de Distorsión del Objectivo +HISTORY_MSG_63;Marcador seleccionado +HISTORY_MSG_64;Recortar Foto +HISTORY_MSG_65;Corrección Ab. Cr. +HISTORY_MSG_66;Recuperación de Luces Altas +HISTORY_MSG_67;Recuperación de Luces Altas Cantidad +HISTORY_MSG_68;Recuperación de Luces Altas Método +HISTORY_MSG_69;Espacio de Color de trabajo +HISTORY_MSG_6;Contraste +HISTORY_MSG_70;Espacio de Color de Salida +HISTORY_MSG_71;Espacio de Color de Entrada +HISTORY_MSG_72;Corrección de viñeteo +HISTORY_MSG_73;Mezclador de Canal +HISTORY_MSG_74;Cambiar Tamaño Escala +HISTORY_MSG_75;Cambiar Tamaño Método +HISTORY_MSG_76;Metadato de Exif +HISTORY_MSG_77;Metadato de IPTC +HISTORY_MSG_7;Negro +HISTORY_MSG_8;Compensación de Exposición +HISTORY_MSG_9;Compresión de Luces Altas +HISTORY_NEWSNAPSHOT;Instantánea nueva +HISTORY_NEWSNAPSHOTAS;Como... +HISTORY_NEWSSDIALOGLABEL;Etiqueta de la Instantánea: +HISTORY_NEWSSDIALOGTITLE;Añadir Instantánea Nueva +HISTORY_SETTO;Ajustado a +HISTORY_SNAPSHOT;Instantánea +HISTORY_SNAPSHOTS;Instantáneas +ICMPANEL_FILEDLGFILTERANY;Cualquier Archivo +ICMPANEL_FILEDLGFILTERICM;Archivos de Perfiles ICC +ICMPANEL_GAMMABEFOREINPUT;El Perfil aplica Gamma +ICMPANEL_INPUTCAMERA;Valores predeterminados de la cámara +ICMPANEL_INPUTCUSTOM;A Medida +ICMPANEL_INPUTDLGLABEL;Seleccionar perfil ICC de entrada... +ICMPANEL_INPUTEMBEDDED;Usar Incrustado, si es posible +ICMPANEL_INPUTPROFILE;Perfil de Entrada +ICMPANEL_NOICM;Ningún MIC: Salida sRGB +ICMPANEL_OUTPUTDLGLABEL;Seleccionar perfil ICC de salida... +ICMPANEL_OUTPUTPROFILE;Perfil de Salida +ICMPANEL_SAVEREFERENCE;Guardar imagen de referencia para el perfilado +ICMPANEL_WORKINGPROFILE;Perfil de Trabajo +IMAGEAREA_DETAILVIEW;Vista de detalle +IPTCPANEL_AUTHOR;Autor +IPTCPANEL_AUTHORHINT;Nombre del creador del objeto, por ejemplo el escritor, el fotótografo o el artista gráfico (By-line). +IPTCPANEL_AUTHORSPOSITION;Tratamiento o título del autor +IPTCPANEL_AUTHORSPOSITIONHINT;Título del creador o de los creadores del objeto (By-line Title). +IPTCPANEL_CAPTION;Leyenda +IPTCPANEL_CAPTIONHINT;Descripción textual de la información (Caption - Abstract). +IPTCPANEL_CAPTIONWRITER;Autor de la Leyenda +IPTCPANEL_CAPTIONWRITERHINT;Nombre de la persona que escribió, modificó o corrigió la imagen o leyenda/resumen (Writer - Editor). +IPTCPANEL_CATEGORY;Categoría +IPTCPANEL_CATEGORYHINT;Código de tres letras que identifica el sujeto de la imagen en opinión del proveedor (Category). +IPTCPANEL_CITY;Ciudad +IPTCPANEL_CITYHINT;Origen de la imagen: Ciudad (City). +IPTCPANEL_COPYHINT;Copiar ajustes IPTC al portapapeles +IPTCPANEL_COPYRIGHT;Derechos de autor +IPTCPANEL_COPYRIGHTHINT;Cualquier llamada de atención necesaria sobre los derechos de autor (Copyright Notice). +IPTCPANEL_COUNTRY;País +IPTCPANEL_COUNTRYHINT;Origen de la imagen: Pais (Country - Primary Location Name). +IPTCPANEL_CREDIT;Créditos +IPTCPANEL_CREDITHINT;Identifica el proveedor de la imagen, no tiene que ser el creador o el propietario (Credit). +IPTCPANEL_DATECREATED;Fecha de creación +IPTCPANEL_DATECREATEDHINT;Fecha de creación del contenido intelectual de la imagen; Format: AAAAMMDD (Date Created). +IPTCPANEL_EMBEDDED;Incrustado +IPTCPANEL_EMBEDDEDHINT;Reiniciar a los datos IPTC incrustados en el archivo de la imagen +IPTCPANEL_HEADLINE;Titular +IPTCPANEL_HEADLINEHINT;Una anotación publicable que provee una sinopsis de los contenidos de la imagen (Headline). +IPTCPANEL_INSTRUCTIONS;Instrucciones +IPTCPANEL_INSTRUCTIONSHINT;Otras instrucciones editoriales sobre el uso de la imagen (Special Instructions). +IPTCPANEL_KEYWORDS;Palabras clave +IPTCPANEL_KEYWORDSHINT;Palabras clave que hacen la búsqueda de la imagen mas fácil (Keywords). +IPTCPANEL_PASTEHINT;Pegar ajustes IPTC desde el portapapeles +IPTCPANEL_PROVINCE;Estado/Provincia +IPTCPANEL_PROVINCEHINT;Origen de la imagen: Estado/Provincia (Province-State). +IPTCPANEL_RESET;Reiniciar +IPTCPANEL_RESETHINT;Reiniciar a los ajustes predeterminados del perfil. +IPTCPANEL_SOURCE;Fuente +IPTCPANEL_SOURCEHINT;Propietario original del contenido intelectual de la imagen (Source). +IPTCPANEL_SUPPCATEGORIES;Categorías suplementarias +IPTCPANEL_SUPPCATEGORIESHINT;Afinado del sujeto de la imagen (Supplemental Categories). +IPTCPANEL_TITLE;Título +IPTCPANEL_TITLEHINT;Referencia concisa de la imagen (Object Name). +IPTCPANEL_TRANSREFERENCE;Ref. trans. original +IPTCPANEL_TRANSREFERENCEHINT;Un código que representa el lugar de la transmisión original (Original Transmission Reference). +MAIN_BUTTON_PREFERENCES;Preferencias +MAIN_BUTTON_SAVE;Guardar Imagen +MAIN_BUTTON_SAVEAS;Como... +MAIN_BUTTON_SENDTOEDITOR;Abrir con editor +MAIN_MSG_ALREADYEXISTS;Este archivo ya existe. +MAIN_MSG_CANNOTLOAD;No se puede abrir imagen +MAIN_MSG_CANNOTSAVE;Error al guardar archivo +MAIN_MSG_CANNOTSTARTEDITOR;Problema abriendo con editor. +MAIN_MSG_CANNOTSTARTEDITOR_SECONDARY;Porfavor ajusten las preferencias. +MAIN_MSG_EXITJOBSINQUEUEINFO;Saliendo del programa imagenes no terminados en la cola son perdidos. +MAIN_MSG_EXITJOBSINQUEUEQUEST;Estas seguro de salis ? Hay imagenes no terminados en la cola. +MAIN_MSG_JOBSINQUEUE;trabajo(s) en cola +MAIN_MSG_QOVERWRITE;¿Quieres reemplazarlo? +MAIN_TAB_BASIC;Básicos +MAIN_TAB_COLOR;Color +MAIN_TAB_DETAIL;Detail +MAIN_TAB_EXIF;Exif +MAIN_TAB_EXPOSURE;Exposición +MAIN_TAB_ICM;GIC +MAIN_TAB_IPTC;IPTC +MAIN_TAB_METADATA;Metadata +MAIN_TAB_TRANSFORM;Transformar +MAIN_TOOLTIP_HIDEFP;Mostrar/Ocultar panel inferior (explorador carpetas y arch. tecla F) +MAIN_TOOLTIP_HIDEHP;Mostrar/Ocultar panel izquierdo (incluyendo historial, tecla H) +MAIN_TOOLTIP_INDCLIPPEDH;Indicación de luces altas recortadas +MAIN_TOOLTIP_INDCLIPPEDS;Indicación de sombras recortadas +MAIN_TOOLTIP_PREFERENCES;Ajustar preferencias +MAIN_TOOLTIP_QINFO; Información breve de la imagen +MAIN_TOOLTIP_SAVE;Guardar imagen a la carpeta predeterminada +MAIN_TOOLTIP_SAVEAS;Guardar imagen a una carpeta seleccionada +PARTIALPASTE_BASICGROUP;Ajustes Básicos +PARTIALPASTE_CACORRECTION;Corrección de Aberraciones Cromáticas +PARTIALPASTE_COARSETRANS;Rotar 90 grados / voltear +PARTIALPASTE_COLORBOOST;Aumenta de Colores +PARTIALPASTE_COLORDENOISE;Reducción de Ruido de Color +PARTIALPASTE_COLORGROUP;Ajustes de Color +PARTIALPASTE_COLORMIXER;Mezclador de Canal +PARTIALPASTE_COLORSHIFT;Cambio de Colores +PARTIALPASTE_COMPOSITIONGROUP;Ajustes al respecto de la figuración +PARTIALPASTE_CROP;Recortar +PARTIALPASTE_DIALOGLABEL;Pegar perfil de procesamiento parcialmente +PARTIALPASTE_DISTORTION;Distorsión +PARTIALPASTE_EXIFCHANGES;Cambio en datos exif +PARTIALPASTE_EXPOSURE;Exposición +PARTIALPASTE_HLRECOVERY;Recuperación de Luces Altas +PARTIALPASTE_ICMSETTINGS;Ajustes GIC +PARTIALPASTE_IPTCINFO;Informaciones IPTC +PARTIALPASTE_LENSGROUP;Ajustes al respecto del objetivo +PARTIALPASTE_LUMACURVE;Curva de Luminancia +PARTIALPASTE_LUMADENOISE;Reducción de Ruido de Luminancia +PARTIALPASTE_LUMINANCEGROUP;Ajustes de Luminancia +PARTIALPASTE_METAICMGROUP;Ajustes Metadatos/GIC +PARTIALPASTE_RESIZE;Cambiar Tamaño +PARTIALPASTE_ROTATION;Rotar +PARTIALPASTE_SHADOWSHIGHLIGHTS;Sombras/Luces Altas +PARTIALPASTE_SHARPENING;Enfoque +PARTIALPASTE_VIGNETTING;Corrección de viñeteo +PARTIALPASTE_WHITEBALANCE;Equilibrio de Blancos +PREFERENCES_APPLNEXTSTARTUP;aplicado al próximo arranque +PREFERENCES_BLINKCLIPPED;Parpadear áreas cortadas +PREFERENCES_CACHECLEARALL;Borrar todo +PREFERENCES_CACHECLEARPROFILES;Borrar perfiles +PREFERENCES_CACHECLEARTHUMBS;Borrar miniaturas +PREFERENCES_CACHEFORMAT1;Propio (mas rapido y mejor calidad) +PREFERENCES_CACHEFORMAT2;JPEG (menos consume de disco duro) +PREFERENCES_CACHEMAXENTRIES;Cantidad máxima de entradas en la memoria intermedia +PREFERENCES_CACHEOPTS;Ajustar memoria intermedia +PREFERENCES_CACHESTRAT1;Preferir velocidad sobre consume de memoria +PREFERENCES_CACHESTRAT2;Preferir consume de memoria bajo sobre velocidad +PREFERENCES_CACHESTRAT;Estrategia de la memoria intermedia +PREFERENCES_CACHETHUMBFORM;Formato de las miniaturas +PREFERENCES_CACHETHUMBHEIGHT;Altura máxima de las miniaturas +PREFERENCES_CLEARDLG_LINE1;Borrando memoria intermedia +PREFERENCES_CLEARDLG_LINE2;Puede durar unos segundos. +PREFERENCES_CLEARDLG_TITLE;Aguardar, por favor +PREFERENCES_CLIPPINGIND;Indicación de recortes +PREFERENCES_CMETRICINTENT;Intento Colorimétrico +PREFERENCES_DATEFORMAT;Formato de Fechas +PREFERENCES_DATEFORMATHINT;Se puede usar las variables siguientes:\n%y : año\n%m : mes\n%d : dia\n\nPor ejemplo, la fecha en Argentina es:\n%d/%m/%y +PREFERENCES_DEFAULTLANG;Idioma predeterminado +PREFERENCES_DEFAULTTHEME;Estilo predeterminado +PREFERENCES_DEMOSAICINGALGO;Algoritmo de desmosaicado +PREFERENCES_DIRHOME;Carpeta de Usuario +PREFERENCES_DIRLAST;Última carpeta visitada +PREFERENCES_DIROTHER;Otro +PREFERENCES_DIRSELECTDLG;Seleccionar Carpeta de Imagenes en el arranque... +PREFERENCES_DIRSOFTWARE;Carpeta de instalación +PREFERENCES_DMETHOD;Método +PREFERENCES_EDITORCMDLINE;Otro mandato +PREFERENCES_EXTERNALEDITOR;Editor externa +PREFERENCES_FALSECOLOR;Pasos de supresión de colores falsos +PREFERENCES_FBROWSEROPTS;Opciones del Explorador de archivos +PREFERENCES_FILEFORMAT;Formato de Archivos +PREFERENCES_FORIMAGE;Para Archivos de Imágenes +PREFERENCES_FORRAW;Para archivos RAW +PREFERENCES_GIMPPATH;Carpeta de instalación de GIMP +PREFERENCES_GTKTHEME;Estilo de GTK predeterminado +PREFERENCES_HINT;Consejo +PREFERENCES_HLTHRESHOLD;Umbral de luces altas cortados +PREFERENCES_ICCDIR;Carpeta de Perfiles ICC +PREFERENCES_IMPROCPARAMS;Parámetros predeterminados de procesamiento de imágenes +PREFERENCES_INTENT_ABSOLUTE;Colorimétrico Absoluto +PREFERENCES_INTENT_PERCEPTUAL;Perceptual +PREFERENCES_INTENT_RELATIVE;Colorimétrico Relativo +PREFERENCES_INTENT_SATURATION;Saturación +PREFERENCES_LIVETHUMBNAILS;Miniaturas 'en vivo' (mas lento) +PREFERENCES_MONITORICC;Perfil de Pantalla +PREFERENCES_OUTDIR;Carpeta de Salida +PREFERENCES_OUTDIRFOLDER;Guardar en carpeta +PREFERENCES_OUTDIRFOLDERHINT;Guardar las imagenes creadas en una carpeta elegida +PREFERENCES_OUTDIRHINT;Se puede usar las variables siguientes:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nEstas variables son referencias a las carpetas y subrutas de las rutas del lugar donde se encuentra la imagen RAW.\n\nPor ejemplo, si abres /home/tom/image/02-09-2006/dsc0012.nef, los valores de las variables son:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nSi quieres guardar la imagen de salida en el lugar original, usa:\n%p1/%f\n\nSi quieres guardar la imagen de salida en una carpeta 'convertida' dentro de la carpeta original, usa:\n%p1/convertida/%f\n\nSi quieres guardar la imagen de salida en la carpeta '/home/tom/convertida' conservando la misma subcarpeta de fechas, usa:\n%p2/convertida/%d1/%f +PREFERENCES_OUTDIRTEMPLATE;Usar plantilla +PREFERENCES_OUTDIRTEMPLATEHINT;Se puede usar las variables siguientes:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nEstas variables son referencias a las carpetas y subrutas de las rutas del lugar donde se encuentra la imagen RAW.\n\nPor ejemplo, si abres /home/tom/image/02-09-2006/dsc0012.nef, los valores de las variables son:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nSi quieres guardar la imagen de salida en el lugar original, usa:\n%p1/%f\n\nSi quieres guardar la imagen de salida en una carpeta 'convertida' dentro de la carpeta original, usa:\n%p1/convertida/%f\n\nSi quieres guardar la imagen de salida en la carpeta '/home/tom/convertida' conservando la misma subcarpeta de fechas, usa:\n%p2/convertida/%d1/%f +PREFERENCES_PARSEDEXT;Extensiones analizados +PREFERENCES_PARSEDEXTADD;Agregar Extensión +PREFERENCES_PARSEDEXTADDHINT;Entra una extensión y apreta este botón para agregar a la lista +PREFERENCES_PARSEDEXTDELHINT;Borrar extensión de la lista +PREFERENCES_PROFILEHANDLING;Tratamiento de perfiles de procesamiento +PREFERENCES_PROFILELOADPR;Prioridad de perfiles quando abriendo imagen +PREFERENCES_PROFILEPRCACHE;Perfil en memoria intermedia +PREFERENCES_PROFILEPRFILE;Perfil junto con imagen de entrada +PREFERENCES_PROFILESAVECACHE;Guardar perfiles de procesamiento en memoria intermedia +PREFERENCES_PROFILESAVEINPUT;Guardar perfiles de procesamiento junto con imagen de entrada +PREFERENCES_PSPATH;Carpeta de instalación de Adobe Photoshop +PREFERENCES_SELECTICCDIRDLG;Seleccionar Carpeta de Perfiles ICC... +PREFERENCES_SELECTLANG;Seleccionar idioma +PREFERENCES_SELECTMONITORPROFDLG;Seleccionar Perfil ICC de la Pantalla... +PREFERENCES_SELECTTHEME;Seleccionar estilo +PREFERENCES_SHOWBASICEXIF;Mostrar datos EXIF básicos +PREFERENCES_SHOWDATETIME;Mostrar fecha y hora +PREFERENCES_SHOWONLYRAW;Mostrar solo Archivos RAW +PREFERENCES_SHTHRESHOLD;Umbral de sombras cortados +PREFERENCES_STARTUPIMDIR;Carpeta de imágenes en el arranque +PREFERENCES_TAB_BROWSER;Explorador de Archivos +PREFERENCES_TAB_COLORMGR;Gestión del Color +PREFERENCES_TAB_GENERAL;General +PREFERENCES_TAB_IMPROC;Procesamiento de Imagenes +PREFERENCES_TAB_OUTPUT;Opciones de Salida +PREFERENCES_THUMBSIZE;Tamaño de Miniaturas +PROFILEPANEL_FILEDLGFILTERANY;Cualquier archivo +PROFILEPANEL_FILEDLGFILTERPP;Perfiles de procesamiento +PROFILEPANEL_LABEL;Perfiles de Procesamiento +PROFILEPANEL_LOADDLGLABEL;Cargar parámetros de procesamiento... +PROFILEPANEL_PCUSTOM;A medida +PROFILEPANEL_PFILE;Desde archivo +PROFILEPANEL_PLASTPHOTO;Última Foto +PROFILEPANEL_PLASTSAVED;Último Guardado +PROFILEPANEL_PROFILE;Perfil +PROFILEPANEL_SAVEDLGLABEL;Guardar parámetros de procesamiento... +PROFILEPANEL_TOOLTIPCOPY;Copiar parámetros de procesamiento al portapapeles +PROFILEPANEL_TOOLTIPLOAD;Cargar perfil de un archivo +PROFILEPANEL_TOOLTIPPASTE; Pegar perfil del portapapeles +PROFILEPANEL_TOOLTIPSAVE;Guardar perfil actual +PROGRESSBAR_DECODING;Descodificando archivo RAW... +PROGRESSBAR_DEMOSAICING;Interpolando mosaico... +PROGRESSBAR_LOADING;Abriendo imagen... +PROGRESSBAR_LOADJPEG;Abriendo archivo JPEG... +PROGRESSBAR_LOADPNG;Abriendo archivo PNG... +PROGRESSBAR_LOADTIFF;Abriendo archivo TIFF... +PROGRESSBAR_PROCESSING;Procesando imagen... +PROGRESSBAR_READY;Listo. +PROGRESSBAR_SAVEJPEG;Guardando archivo JPEG... +PROGRESSBAR_SAVEPNG;Guardando archivo PNG... +PROGRESSBAR_SAVETIFF;Guardando archivo TIFF... +PROGRESSDLG_LOADING;Abriendo archivo... +PROGRESSDLG_PROCESSING;Procesando imagen... +PROGRESSDLG_SAVING;Guardando archivo... +QINFO_FOCALLENGTH;Longitud Focal +QINFO_ISO;ISO +QINFO_LENS;Objetivo +QINFO_NOEXIF;No hay datos EXIF. +SAVEDLG_FILEFORMAT;Formato de archivo +SAVEDLG_JPEGQUAL;Calidad JPEG +SAVEDLG_JPGFILTER;Archivos JPEG +SAVEDLG_PNGCOMPR;Compresión PNG +SAVEDLG_PNGFILTER;Archivos PNG +SAVEDLG_PUTTOQUEUE;Poner en la cola +SAVEDLG_PUTTOQUEUEHEAD;Poner al principio de la cola +SAVEDLG_PUTTOQUEUETAIL;Poner al fin de la cola +SAVEDLG_SAVEIMMEDIATELY;Guardar inmediatamente +SAVEDLG_SAVESPP;Guardar parámetros de procesamiento con la imagen +SAVEDLG_TIFFFILTER;Archivos TIFF +TOOLBAR_TOOLTIP_CROP;Elección de recorte (tecla C) +TOOLBAR_TOOLTIP_HAND;Herramienta mano (tecla N) +TOOLBAR_TOOLTIP_STRAIGHTEN;Elección de línea recta (tecla S) +TOOLBAR_TOOLTIP_WB;Muestrea equilibrio de blancos (tecla W) +TP_CACORRECTION_BLUE;Azul +TP_CACORRECTION_LABEL;Corrección de Aberraciones Cromáticas +TP_CACORRECTION_RED;Rojo +TP_CHMIXER_BLUE;Azul +TP_CHMIXER_GREEN;Verde +TP_CHMIXER_LABEL;Mezclador de Canal +TP_CHMIXER_RED;Rojo +TP_COARSETRAF_DEGREE;Grados: +TP_COARSETRAF_TOOLTIP_HFLIP;Voltear horizontalmente +TP_COARSETRAF_TOOLTIP_ROTLEFT;Rotar a la izquierda +TP_COARSETRAF_TOOLTIP_ROTRIGHT;Rotar a la derecha +TP_COARSETRAF_TOOLTIP_VFLIP;Voltear verticalmente +TP_COLORBOOST_ACHANNEL;canal "a" +TP_COLORBOOST_AMOUNT;Cantidad +TP_COLORBOOST_AVOIDCOLORCLIP;Evitar Recorte de Colores +TP_COLORBOOST_BCHANNEL;canal "b" +TP_COLORBOOST_CHAB;a & b +TP_COLORBOOST_CHANNEL;Canal +TP_COLORBOOST_CHSEPARATE;independiente +TP_COLORBOOST_ENABLESATLIMITER;Activar Limitador de Saturación +TP_COLORBOOST_LABEL;Aumento de Color +TP_COLORBOOST_SATLIMIT;Límite de Saturación +TP_COLORDENOISE_EDGESENSITIVE;Sensible a bordes +TP_COLORDENOISE_EDGETOLERANCE;Tolerancia de bordes +TP_COLORDENOISE_LABEL;Reducción de Ruido de Color +TP_COLORDENOISE_RADIUS;Radio +TP_COLORSHIFT_BLUEYELLOW;Azul-Amarillo +TP_COLORSHIFT_GREENMAGENTA;Verde-Magenta +TP_COLORSHIFT_LABEL;Cambio de Colores +TP_CROP_DPI;DPI= +TP_CROP_FIXRATIO;Fijar Proporciones: +TP_CROP_GTDIAGONALS;Regla de las diagonales +TP_CROP_GTHARMMEANS1;Forma armónica 1 +TP_CROP_GTHARMMEANS2;Forma armónica 2 +TP_CROP_GTHARMMEANS3;Forma armónica 3 +TP_CROP_GTHARMMEANS4;Forma armónica 4 +TP_CROP_GTNONE;Ninguna +TP_CROP_GTRULETHIRDS;Regla de los tercios +TP_CROP_GUIDETYPE;Clase de Guía: +TP_CROP_H;Al +TP_CROP_LABEL;Recortar +TP_CROP_SELECTCROP; Seleccionar Recorte +TP_CROP_W;An +TP_CROP_X;x +TP_CROP_Y;y +TP_DISTORTION_AMOUNT;Cantidad +TP_DISTORTION_LABEL;Distorsión +TP_EXPOSURE_AUTOLEVELS;Niveles Automáticos +TP_EXPOSURE_BLACKLEVEL;Negro +TP_EXPOSURE_BRIGHTNESS;Brillo +TP_EXPOSURE_CLIP;Recorte +TP_EXPOSURE_COMPRHIGHLIGHTS;Compresión de Luces Altas +TP_EXPOSURE_COMPRSHADOWS;Compresión de Sombras +TP_EXPOSURE_CONTRAST;Contraste +TP_EXPOSURE_CURVEEDITOR;Curva de Tono +TP_EXPOSURE_EXPCOMP;Comp. de Expos. +TP_EXPOSURE_LABEL;Exposición +TP_HLREC_CIELAB;Superposición de CIELab +TP_HLREC_COLOR;Propagación de Color +TP_HLREC_LABEL;Recuperación de Luces Altas +TP_HLREC_LUMINANCE;Recuperación de Luminancia +TP_HLREC_METHOD;Método: +TP_ICM_FILEDLGFILTERANY;Cualquier Archivo +TP_ICM_FILEDLGFILTERICM;Archivos de Perfiles ICC +TP_ICM_GAMMABEFOREINPUT;El Perfil aplica Gamma +TP_ICM_INPUTCAMERA;Valores predeterminados de la cámara +TP_ICM_INPUTCUSTOM;A Medida +TP_ICM_INPUTDLGLABEL;Seleccionar perfil ICC de entrada... +TP_ICM_INPUTEMBEDDED;Usar Incrustado, si es posible +TP_ICM_INPUTPROFILE;Perfil de Entrada +TP_ICM_LABEL;GIC +TP_ICM_NOICM;Ningún MIC: Salida sRGB +TP_ICM_OUTPUTDLGLABEL;Seleccionar perfil ICC de salida... +TP_ICM_OUTPUTPROFILE;Perfil de Salida +TP_ICM_SAVEREFERENCE;Guardar imagen de referencia para el perfilado +TP_ICM_WORKINGPROFILE;Perfil de Trabajo +TP_LUMACURVE_BLACKLEVEL;Negro +TP_LUMACURVE_BRIGHTNESS;Brillo +TP_LUMACURVE_COMPRHIGHLIGHTS;Compresión de Luces Altas +TP_LUMACURVE_COMPRSHADOWS;Compresión de Sombras +TP_LUMACURVE_CONTRAST;Contraste +TP_LUMACURVE_CURVEEDITOR;Curva de Luminancia +TP_LUMACURVE_LABEL;Curva de Luminancia +TP_LUMADENOISE_EDGETOLERANCE;Tolerancia de bordes +TP_LUMADENOISE_LABEL;Reducción de Ruido de Luminancia +TP_LUMADENOISE_RADIUS;Radio +TP_RESIZE_BICUBIC;Bicúbica +TP_RESIZE_BICUBICSF;Bicúbica (Más suave) +TP_RESIZE_BICUBICSH;Bicúbica (Más enfocado) +TP_RESIZE_BILINEAR;Bilineal +TP_RESIZE_FULLSIZE;Tamaño de imagen completo: +TP_RESIZE_H;Al: +TP_RESIZE_LABEL;Cambiar Tamaño +TP_RESIZE_METHOD;Método: +TP_RESIZE_NEAREST;Más cercano +TP_RESIZE_SCALE;Escala +TP_RESIZE_W;An: +TP_ROTATE_AUTOCROP;Recorte Automático +TP_ROTATE_DEGREE;Grados +TP_ROTATE_FILL;Llenar +TP_ROTATE_LABEL;Rotar +TP_ROTATE_SELECTLINE; Seleccionar Línea Recta +TP_SHADOWSHLIGHTS_HIGHLIGHTS;Luces Altas +TP_SHADOWSHLIGHTS_HLTONALW;Ancho Tonal +TP_SHADOWSHLIGHTS_LABEL;Sombras/Luces Altas +TP_SHADOWSHLIGHTS_LOCALCONTR;Constraste Local +TP_SHADOWSHLIGHTS_RADIUS;Radio +TP_SHADOWSHLIGHTS_SHADOWS;Sombras +TP_SHADOWSHLIGHTS_SHTONALW;Ancho Tonal +TP_SHARPENING_AMOUNT;Cantidad +TP_SHARPENING_EDRADIUS;Radio +TP_SHARPENING_EDTOLERANCE;Tolerancia de Bordes +TP_SHARPENING_HALOCONTROL;Control de Halo +TP_SHARPENING_HCAMOUNT;Cantidad +TP_SHARPENING_LABEL;Enfoque +TP_SHARPENING_METHOD;Método +TP_SHARPENING_ONLYEDGES;Enfocar solo Bordes +TP_SHARPENING_RADIUS;Radio +TP_SHARPENING_RLD;Deconvolución RL +TP_SHARPENING_RLD_AMOUNT;Cantidad +TP_SHARPENING_RLD_DAMPING;Amortiguación +TP_SHARPENING_RLD_ITERATIONS;Reiteraciones +TP_SHARPENING_THRESHOLD;Umbral +TP_SHARPENING_USM;Máscara de enfoque +TP_VIGNETTING_AMOUNT;Cantidad +TP_VIGNETTING_LABEL;Corrección de viñeteo +TP_VIGNETTING_RADIUS;Radio +TP_WBALANCE_AUTO;Auto +TP_WBALANCE_CAMERA;Cámara +TP_WBALANCE_CUSTOM;A Medida +TP_WBALANCE_GREEN;Tinte +TP_WBALANCE_LABEL;Equilibrio de Blancos +TP_WBALANCE_METHOD;Método +TP_WBALANCE_SIZE;Tamaño: +TP_WBALANCE_SPOTWB;Muestra Eq.Bl. +TP_WBALANCE_TEMPERATURE;Temperatura +ZOOMBAR_DETAIL;Detalle +ZOOMBAR_HUGE;Enorme +ZOOMBAR_LARGE;Grande +ZOOMBAR_NORMAL;Normal +ZOOMBAR_PREVIEW;Previsualización +ZOOMBAR_SCALE;Escala +ZOOMBAR_SMALL;Pequeño diff --git a/release/languages/euskara b/release/languages/euskara new file mode 100755 index 000000000..1ccef5b57 --- /dev/null +++ b/release/languages/euskara @@ -0,0 +1,577 @@ +# Euskara (Basque) +# 03.03.2008 +# Ioritz Ibarguren +ADJUSTER_RESET_TO_DEFAULT;Hasierako balioetara itzuli +CURVEEDITOR_FILEDLGFILTERANY;Artxibo guztiak +CURVEEDITOR_FILEDLGFILTERCURVE;Kurba artxiboak +CURVEEDITOR_LINEAR;Lineala +CURVEEDITOR_LOADDLGLABEL;Kurba ireki... +CURVEEDITOR_SAVEDLGLABEL;Kurba gorde... +CURVEEDITOR_TOOLTIPLINEAR;Kurba lineala berrabiarazi +CURVEEDITOR_TOOLTIPLOAD;Artxibo batetik kurba ireki +CURVEEDITOR_TOOLTIPSAVE;Uneko kurba gorde +EXIFFILTER_APERTURE;Aperture +EXIFFILTER_CAMERA;Camera +EXIFFILTER_DIALOGLABEL;Exif Filter +EXIFFILTER_FOCALLEN;Focal Length +EXIFFILTER_ISO;ISO +EXIFFILTER_LENS;Lens +EXIFFILTER_SHUTTER;Shutter +EXIFPANEL_ADDEDIT;Add/Edit +EXIFPANEL_ADDEDITHINT;Add new tag or edit tag +EXIFPANEL_ADDTAGDLG_ENTERVALUE;Enter value +EXIFPANEL_ADDTAGDLG_SELECTTAG;Select tag +EXIFPANEL_ADDTAGDLG_TITLE;Add/Edit Tag +EXIFPANEL_KEEP;Keep +EXIFPANEL_KEEPHINT;Keep the selected tags when writing output file +EXIFPANEL_REMOVE;Remove +EXIFPANEL_REMOVEHINT;Remove the selected tags when writing output file +EXIFPANEL_RESET;Reset +EXIFPANEL_RESETALL;Reset All +EXIFPANEL_RESETALLHINT;Reset all tags to their original values +EXIFPANEL_RESETHINT;Reset the selected tags to their original values +EXIFPANEL_SUBDIRECTORY;Subdirectory +FILEBROWSER_APPLYPROFILE;Apply profile +FILEBROWSER_ARRANGEMENTHINT;Change between vertical/horizontal alignment of thumbnails +FILEBROWSER_CLEARPROFILE;Clear profile +FILEBROWSER_COPYPROFILE;Copy profile +FILEBROWSER_DELETEDLGLABEL;File delete confirmation +FILEBROWSER_DELETEDLGMSG;Are you sure you want to delete the selected %1 files? +FILEBROWSER_EMPTYTRASH;Empty Trash +FILEBROWSER_EMPTYTRASHHINT;Permanently delete the files of the trash +FILEBROWSER_EXIFFILTERAPPLY;Apply +FILEBROWSER_EXIFFILTERAPPLYHINT;Switch on/off exif filter of the file browser +FILEBROWSER_EXIFFILTERLABEL;Exif Filter +FILEBROWSER_EXIFFILTERSETTINGS;Setup +FILEBROWSER_EXIFFILTERSETTINGSHINT;Change settings of the exif filter +FILEBROWSER_PARTIALPASTEPROFILE;Partial paste +FILEBROWSER_PASTEPROFILE;Paste profile +FILEBROWSER_POPUPCANCELJOB;Cancel job +FILEBROWSER_POPUPMOVEEND;Move to end of queue +FILEBROWSER_POPUPMOVEHEAD;Move to head of queue +FILEBROWSER_POPUPOPEN;Open +FILEBROWSER_POPUPPROCESS;Put to processing queue +FILEBROWSER_POPUPRANK1;Rank 1 +FILEBROWSER_POPUPRANK2;Rank 2 +FILEBROWSER_POPUPRANK3;Rank 3 +FILEBROWSER_POPUPRANK4;Rank 4 +FILEBROWSER_POPUPRANK5;Rank 5 +FILEBROWSER_POPUPREMOVE;Remove from filesystem +FILEBROWSER_POPUPRENAME;Rename +FILEBROWSER_POPUPSELECTALL;Select all +FILEBROWSER_POPUPTRASH;Move to trash +FILEBROWSER_POPUPUNRANK;Unrank +FILEBROWSER_POPUPUNTRASH;Remove from trash +FILEBROWSER_PROCESSINGSETTINGS;Settings +FILEBROWSER_PROCESSINGSETTINGSHINT;Set the file format and output directory +FILEBROWSER_RENAMEDLGLABEL;Rename file +FILEBROWSER_RENAMEDLGMSG;Rename file "%1" to: +FILEBROWSER_SHOWDIRHINT;Show all images of the directory +FILEBROWSER_SHOWQUEUEHINT;Show content of the processing queue +FILEBROWSER_SHOWRANK1HINT;Show images ranked as 1 star +FILEBROWSER_SHOWRANK2HINT;Show images ranked as 2 star +FILEBROWSER_SHOWRANK3HINT;Show images ranked as 3 star +FILEBROWSER_SHOWRANK4HINT;Show images ranked as 4 star +FILEBROWSER_SHOWRANK5HINT;Show images ranked as 5 star +FILEBROWSER_SHOWTRASHHINT;Show content of the trash +FILEBROWSER_SHOWUNRANKHINT;Show unranked images +FILEBROWSER_STARTPROCESSING;Start Processing +FILEBROWSER_STARTPROCESSINGHINT;Start processing/saving of images in the queue +FILEBROWSER_STOPPROCESSING;Stop processing +FILEBROWSER_STOPPROCESSINGHINT;Stop processing of images +FILEBROWSER_THUMBSIZE;Thumb. size +FILEBROWSER_ZOOMINHINT;Increase thumbnail size +FILEBROWSER_ZOOMOUTHINT;Decrease thumbnail size +GENERAL_ABOUT;Honi buruz +GENERAL_CANCEL;Baztertu +GENERAL_DISABLE;Ezestatu +GENERAL_DISABLED;Ezeztatua +GENERAL_ENABLE;Gaitu +GENERAL_ENABLED;Gaitua +GENERAL_LANDSCAPE;Paisaia +GENERAL_LOAD;Ireki +GENERAL_NA;n/a +GENERAL_NO;Ez +GENERAL_OK;Onartu +GENERAL_PORTRAIT;Erretratua +GENERAL_SAVE;Gorde +GENERAL_YES;Bai +HISTOGRAM_LABEL;Histogram +HISTOGRAM_TOOLTIP_B;Erakutsi/Ezkutatu urdin histograma +HISTOGRAM_TOOLTIP_G;Erakutsi/Ezkutatu berde histograma +HISTOGRAM_TOOLTIP_L;Erakutsi/Ezkutatu CIELAB argitasun histograma +HISTOGRAM_TOOLTIP_R;Erakutsi/Ezkutatu gorri histograma +HISTORY_CHANGED;Changed +HISTORY_CUSTOMCURVE;Neurriko kurba +HISTORY_DELSNAPSHOT;Argazkia kendu +HISTORY_FROMCLIPBOARD;From clipboard +HISTORY_LABEL;Historia +HISTORY_MSG_10;Itzal konpresioa +HISTORY_MSG_11;Tonu kurba +HISTORY_MSG_12;Auto-esposizioa +HISTORY_MSG_13;Esposizio mozketa +HISTORY_MSG_14;Liminantzia argitasuna +HISTORY_MSG_15;Luminantzia kontrastea +HISTORY_MSG_16;Luminantzia beltza +HISTORY_MSG_17;Liminantzia argi konpresioa +HISTORY_MSG_18;Luminantzia itzal konpresioa +HISTORY_MSG_19;Luminantzia kurba +HISTORY_MSG_1;Argazki irekia +HISTORY_MSG_20;Fokatzea +HISTORY_MSG_21;Fokatze erradioa +HISTORY_MSG_22;Fokatze kopurua +HISTORY_MSG_23;Fokatze muga +HISTORY_MSG_24;Ertzak bakarrik fokatu +HISTORY_MSG_25;Ertz detekzio erradio fokatzea +HISTORY_MSG_26;Ertz tolerantzia fokatzea +HISTORY_MSG_27;Halo kontrol fokatzea +HISTORY_MSG_28;Halo kopuru kontrola +HISTORY_MSG_29;Fokatze metodoa +HISTORY_MSG_2;Profila irekia +HISTORY_MSG_30;Dekonboluzio erradioa +HISTORY_MSG_31;Dekonboluzio kopurua +HISTORY_MSG_32;Dekonboluzio indargetzea +HISTORY_MSG_33;Dekonboluzio iterazioak +HISTORY_MSG_34;Kolore mozketa ekidin +HISTORY_MSG_35;Saturazio mugatzailea +HISTORY_MSG_36;Saturazio muga +HISTORY_MSG_37;Koloreak jaso +HISTORY_MSG_38;Zuri balantze metodoa +HISTORY_MSG_39;Kolore tenperatura +HISTORY_MSG_3;Profila aldatua +HISTORY_MSG_40;Zuri balantze tonua +HISTORY_MSG_41;"A" kolore aldaketa +HISTORY_MSG_42;"B" kolore aldaketa +HISTORY_MSG_43;Luminantzia zarata murrizketa +HISTORY_MSG_44;Lum. zar. murr. erradioa +HISTORY_MSG_45;Lum. zar. murr. ertz tolerantzia +HISTORY_MSG_46;Kolore zarata murrizketa +HISTORY_MSG_47;Kol. zar. murr. erradioa +HISTORY_MSG_48;Kol. zar. murr. ertz tolerantzia +HISTORY_MSG_49;Kol. zar. murr. ertzekiko sentikorra +HISTORY_MSG_4;Historia arakatu +HISTORY_MSG_50;Itzal/Argi tresna +HISTORY_MSG_51;Argiak jaso +HISTORY_MSG_52;Itzalak jaso +HISTORY_MSG_53;Argi tonu zabalera +HISTORY_MSG_54;Itzal tonu zabalera +HISTORY_MSG_55;Tokiko kontrastea +HISTORY_MSG_56;Itzal/Argi erradioa +HISTORY_MSG_57;Biraketa arrunta +HISTORY_MSG_58;Horizontalki irauli +HISTORY_MSG_59;Bertikalki irauli +HISTORY_MSG_5;Argitasuna +HISTORY_MSG_60;Biraketa +HISTORY_MSG_61;Biraketa +HISTORY_MSG_62;Objetibo deformazio zuzenketa +HISTORY_MSG_63;Lastermarka hautatua +HISTORY_MSG_64;Argazkia moztu +HISTORY_MSG_65;C/A zuzenketa +HISTORY_MSG_66;Distira berreskurapena +HISTORY_MSG_67;Distira berreskurapen kopurua +HISTORY_MSG_68;Distira berreskurapen metodoa +HISTORY_MSG_69;Lan kolore esparrua +HISTORY_MSG_6;Kontrastea +HISTORY_MSG_70;Irteera kolore esparrua +HISTORY_MSG_71;Sarrera kolore esparrua +HISTORY_MSG_72;Iluntze zuzenketa +HISTORY_MSG_73;Kanal nahastainlea +HISTORY_MSG_74;Eskala tamaina aldaketa +HISTORY_MSG_75;Tamaina aldaketa metodoa +HISTORY_MSG_76;Exif Metadata +HISTORY_MSG_77;IPTC Metadata +HISTORY_MSG_7;Beltza +HISTORY_MSG_8;Esposizio konpentsazioa +HISTORY_MSG_9;Argi konpresioa +HISTORY_NEWSNAPSHOT;Argazki berria +HISTORY_NEWSNAPSHOTAS;Honela... +HISTORY_NEWSSDIALOGLABEL;Argazkiaren etiketa: +HISTORY_NEWSSDIALOGTITLE;Argazki berria gehitu +HISTORY_SETTO;Honetara doitua +HISTORY_SNAPSHOT;Argazkia +HISTORY_SNAPSHOTS;Argazkiak +ICMPANEL_FILEDLGFILTERANY;Artxibo guztiak +ICMPANEL_FILEDLGFILTERICM;ICC profilen artxiboak +ICMPANEL_GAMMABEFOREINPUT;Profile applies Gamma +ICMPANEL_INPUTCAMERA;Kameraren jatorrizko balioak +ICMPANEL_INPUTCUSTOM;Neurrira +ICMPANEL_INPUTDLGLABEL;Sarrerako ICC profila hautatu... +ICMPANEL_INPUTEMBEDDED;Txertatutakoa erabili, egonez gero +ICMPANEL_INPUTPROFILE;Sarrerako profila +ICMPANEL_NOICM;ICM-rik ez: sRGB irteera +ICMPANEL_OUTPUTDLGLABEL;Irteerako ICC profila hautatu... +ICMPANEL_OUTPUTPROFILE;Irteera profila +ICMPANEL_SAVEREFERENCE;Save reference image for profiling +ICMPANEL_WORKINGPROFILE;Lan profila +IMAGEAREA_DETAILVIEW;Zehaztasun bista +IPTCPANEL_AUTHOR;Author +IPTCPANEL_AUTHORHINT;Name of the creator of the object, e.g. writer, photographer or graphic artist (By-line). +IPTCPANEL_AUTHORSPOSITION;Author's position +IPTCPANEL_AUTHORSPOSITIONHINT;Title of the creator or creators of the object (By-line Title). +IPTCPANEL_CAPTION;Caption +IPTCPANEL_CAPTIONHINT;A textual description of the data (Caption - Abstract) +IPTCPANEL_CAPTIONWRITER;Caption Writer +IPTCPANEL_CAPTIONWRITERHINT;The name of the person involved in the writing, editing or correcting the image or caption/abstract (Writer - Editor) +IPTCPANEL_CATEGORY;Category +IPTCPANEL_CATEGORYHINT;Identifies the subject of the image in the opinion of the provider (Category). +IPTCPANEL_CITY;City +IPTCPANEL_CITYHINT;City of image origin (City). +IPTCPANEL_COPYHINT;Copy IPTC settings to clipboard +IPTCPANEL_COPYRIGHT;Copyright +IPTCPANEL_COPYRIGHTHINT;Any necessary copyright notice (Copyright Notice). +IPTCPANEL_COUNTRY;Country +IPTCPANEL_COUNTRYHINT;The name of the country/primary location where the image was created (Country - Primary Location Name). +IPTCPANEL_CREDIT;Credit +IPTCPANEL_CREDITHINT;Identifies the provider of the image, not necessarily the owner/creator (Credit). +IPTCPANEL_DATECREATED;Date Created +IPTCPANEL_DATECREATEDHINT;The date the intellectual content of the image was created; Format: JJJJMMTT (Date Created). +IPTCPANEL_EMBEDDED;Embedded +IPTCPANEL_EMBEDDEDHINT;Reset to IPTC data embedded in the image file +IPTCPANEL_HEADLINE;Headline +IPTCPANEL_HEADLINEHINT;A publishable entry providing a synopsis of the contents of the image (Headline). +IPTCPANEL_INSTRUCTIONS;Instructions +IPTCPANEL_INSTRUCTIONSHINT;Other editorial instructions concerning the use of the image (Special Instructions). +IPTCPANEL_KEYWORDS;Keywords +IPTCPANEL_KEYWORDSHINT;Used to indicate specific information retrieval words (Keywords). +IPTCPANEL_PASTEHINT;Paste IPTC settings from clipboard +IPTCPANEL_PROVINCE;Province +IPTCPANEL_PROVINCEHINT;The Province/State where the image originates (Province-State). +IPTCPANEL_RESET;Reset +IPTCPANEL_RESETHINT;Reset to profile default +IPTCPANEL_SOURCE;Source +IPTCPANEL_SOURCEHINT;The original owner of the intellectual content of the image (Source). +IPTCPANEL_SUPPCATEGORIES;Suppl. Categories +IPTCPANEL_SUPPCATEGORIESHINT;Further refines the subject of the image (Supplemental Categories). +IPTCPANEL_TITLE;Title +IPTCPANEL_TITLEHINT;A shorthand reference for the image (Object Name). +IPTCPANEL_TRANSREFERENCE;Trans. Reference +IPTCPANEL_TRANSREFERENCEHINT;A code representing the location of original transmission (Original Transmission Reference). +MAIN_BUTTON_PREFERENCES;Ezarpenak +MAIN_BUTTON_SAVE;Irudia gorde +MAIN_BUTTON_SAVEAS;Honela... +MAIN_BUTTON_SENDTOEDITOR;Send to editor +MAIN_MSG_ALREADYEXISTS;Artxiboa jadanik badago. +MAIN_MSG_CANNOTLOAD;Ezin dut irudia ireki +MAIN_MSG_CANNOTSAVE;Errorea irudia gordetzen +MAIN_MSG_CANNOTSTARTEDITOR;Can not start editor. +MAIN_MSG_CANNOTSTARTEDITOR_SECONDARY;Please set the correct path in the "Preferences" dialog. +MAIN_MSG_EXITJOBSINQUEUEINFO;Unprocessed images in the queue will be lost on exit. +MAIN_MSG_EXITJOBSINQUEUEQUEST;Are you sure you want to exit? There are unprocessed images waiting in the queue. +MAIN_MSG_JOBSINQUEUE;lana(k) ilaran +MAIN_MSG_QOVERWRITE;Gainidatzi? +MAIN_TAB_BASIC;Oinarrizkoak +MAIN_TAB_COLOR;Color +MAIN_TAB_DETAIL;Detail +MAIN_TAB_EXIF;Exif +MAIN_TAB_EXPOSURE;Exposure +MAIN_TAB_ICM;ICM +MAIN_TAB_IPTC;IPTC +MAIN_TAB_METADATA;Metadata +MAIN_TAB_TRANSFORM;Bihurtu +MAIN_TOOLTIP_HIDEFP;Erakutsi/Ezkutatu behe panela (arakatzailea, shortcut key: F) +MAIN_TOOLTIP_HIDEHP;Erakutsi/Ezkutatu ezker panela (historia, shortcut key: H) +MAIN_TOOLTIP_INDCLIPPEDH;Mozturiko argi adierazlea +MAIN_TOOLTIP_INDCLIPPEDS;Mozturiko itzal adierazlea +MAIN_TOOLTIP_PREFERENCES;Ezarpenak doitu +MAIN_TOOLTIP_QINFO; Irudiaren informazio laburra +MAIN_TOOLTIP_SAVE;Irudia lehenetsiriko karpetara gorde +MAIN_TOOLTIP_SAVEAS;Irudia hautatutako karpeta batera gorde +PARTIALPASTE_BASICGROUP;Basic settings +PARTIALPASTE_CACORRECTION;C/A correction +PARTIALPASTE_COARSETRANS;90 deg rotation / flipping +PARTIALPASTE_COLORBOOST;Color boost +PARTIALPASTE_COLORDENOISE;Color denoise +PARTIALPASTE_COLORGROUP;Color related settings +PARTIALPASTE_COLORMIXER;Color mixer +PARTIALPASTE_COLORSHIFT;Color shift +PARTIALPASTE_COMPOSITIONGROUP;Composition settings +PARTIALPASTE_CROP;Crop +PARTIALPASTE_DIALOGLABEL;Partial paste processing profile +PARTIALPASTE_DISTORTION;Distortion correction +PARTIALPASTE_EXIFCHANGES;Changes to exif data +PARTIALPASTE_EXPOSURE;Exposure +PARTIALPASTE_HLRECOVERY;Highlight recovery +PARTIALPASTE_ICMSETTINGS;ICM settings +PARTIALPASTE_IPTCINFO;IPTC info +PARTIALPASTE_LENSGROUP;Lens related settings +PARTIALPASTE_LUMACURVE;Luminance curve +PARTIALPASTE_LUMADENOISE;Luminance noise reduction +PARTIALPASTE_LUMINANCEGROUP;Luminance related settings +PARTIALPASTE_METAICMGROUP;Metadata/ICM settings +PARTIALPASTE_RESIZE;Resize +PARTIALPASTE_ROTATION;Rotation +PARTIALPASTE_SHADOWSHIGHLIGHTS;Shadows/Highlights +PARTIALPASTE_SHARPENING;Sharpening +PARTIALPASTE_VIGNETTING;Vignetting correction +PARTIALPASTE_WHITEBALANCE;White balance +PREFERENCES_APPLNEXTSTARTUP;hurrengo abioan aplikatua +PREFERENCES_BLINKCLIPPED;Moztutako guneak keinuka +PREFERENCES_CACHECLEARALL;Clear All +PREFERENCES_CACHECLEARPROFILES;Clear Profiles +PREFERENCES_CACHECLEARTHUMBS;Clear Thumbnails +PREFERENCES_CACHEFORMAT1;Proprietary (faster and better quality) +PREFERENCES_CACHEFORMAT2;JPEG (smaller disk footprint) +PREFERENCES_CACHEMAXENTRIES;Maximal Number of Cache Entries +PREFERENCES_CACHEOPTS;Cache Options +PREFERENCES_CACHESTRAT1;Prefer Speed to Low Memory Consumption +PREFERENCES_CACHESTRAT2;Prefer Low Memory Consumption to Speed +PREFERENCES_CACHESTRAT;Cache Strategy +PREFERENCES_CACHETHUMBFORM;Cache Thumbnail Format +PREFERENCES_CACHETHUMBHEIGHT;Maximal Thumbnail Height +PREFERENCES_CLEARDLG_LINE1;Clearing cache +PREFERENCES_CLEARDLG_LINE2;This may take a few seconds. +PREFERENCES_CLEARDLG_TITLE;Please wait +PREFERENCES_CLIPPINGIND;Itzal/argi moztuen adierazlea +PREFERENCES_CMETRICINTENT;Saiakera kolorimetrikoa +PREFERENCES_DATEFORMAT;Data formatua +PREFERENCES_DATEFORMATHINT;You can use the following formatting strings:\n%y : year\n%m : month\n%d : day\n\nFor example, the hungarian date format is:\n%y/%m/%d +PREFERENCES_DEFAULTLANG;Hizkuntza +PREFERENCES_DEFAULTTHEME;Default theme +PREFERENCES_DEMOSAICINGALGO;Demosaikatze algoritmoa +PREFERENCES_DIRHOME;Etxe karpeta +PREFERENCES_DIRLAST;Azkena ikusitako karpeta +PREFERENCES_DIROTHER;Besterik +PREFERENCES_DIRSELECTDLG;Abioko irudien karpeta hautatu... +PREFERENCES_DIRSOFTWARE;Inatalazio karpeta +PREFERENCES_DMETHOD;Metodoa +PREFERENCES_EDITORCMDLINE;Other command line +PREFERENCES_EXTERNALEDITOR;External editor +PREFERENCES_FALSECOLOR;Okerreko kolore ezabaketa atalak +PREFERENCES_FBROWSEROPTS;Arakatzailearen aukerak +PREFERENCES_FILEFORMAT;Artxiboen formatua +PREFERENCES_FORIMAGE;Irudi artxiboetarako +PREFERENCES_FORRAW;RAW artxiboetarako +PREFERENCES_GIMPPATH;GIMP installation directory +PREFERENCES_GTKTHEME;GTK default +PREFERENCES_HINT;Gomendioa +PREFERENCES_HLTHRESHOLD;Moztutako argien muga +PREFERENCES_ICCDIR;ICC profilen karpeta +PREFERENCES_IMPROCPARAMS;Irudi prozesurako aukera lehenetsiak +PREFERENCES_INTENT_ABSOLUTE;Kolorimetriko absolutua +PREFERENCES_INTENT_PERCEPTUAL;Petzeptuala +PREFERENCES_INTENT_RELATIVE;Kolorimetriko erlatiboa +PREFERENCES_INTENT_SATURATION;Saturazioa +PREFERENCES_LIVETHUMBNAILS;Live Thumbnails (slower) +PREFERENCES_MONITORICC;Pantaila profilak +PREFERENCES_OUTDIR;Irteera karpeta +PREFERENCES_OUTDIRFOLDER;Save to folder +PREFERENCES_OUTDIRFOLDERHINT;Put the saved images to the seledted folder +PREFERENCES_OUTDIRHINT;You can use the following formatting strings:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nThese formatting strings refer to the directories and sub-paths of the path of the raw file.\n\nFor example, if /home/tom/image/02-09-2006/dsc0012.nefhas been opened, the meaning of the formatting strings are:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nIf you want to save the output image where the original is, write:\n%p1/%f\n\nIf you want to save the output image in a directory 'converted' located the directory of the original, write:\n%p1/converted/%f\n\nIf you want to save the output image in directory '/home/tom/converted' with keeping the same subdirectory of dates, write:\n%p2/converted/%d1/%f +PREFERENCES_OUTDIRTEMPLATE;Use Template +PREFERENCES_OUTDIRTEMPLATEHINT;You can use the following formatting strings:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nThese formatting strings refer to the directories and sub-paths of the path of the raw file.\n\nFor example, if /home/tom/image/02-09-2006/dsc0012.nefhas been opened, the meaning of the formatting strings are:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nIf you want to save the output image where the original is, write:\n%p1/%f\n\nIf you want to save the output image in a directory 'converted' located the directory of the original, write:\n%p1/converted/%f\n\nIf you want to save the output image in directory '/home/tom/converted' with keeping the same subdirectory of dates, write:\n%p2/converted/%d1/%f +PREFERENCES_PARSEDEXT;Parsed Extensions +PREFERENCES_PARSEDEXTADD;Add Extension +PREFERENCES_PARSEDEXTADDHINT;Type an extension and press this button to append list +PREFERENCES_PARSEDEXTDELHINT;Delete selected extension from the list +PREFERENCES_PROFILEHANDLING;Processing Profile Handling +PREFERENCES_PROFILELOADPR;Profile Loading Priority +PREFERENCES_PROFILEPRCACHE;Profile in Cache +PREFERENCES_PROFILEPRFILE;Profile Next to the Input File +PREFERENCES_PROFILESAVECACHE;Save Processing Parameters to the Cache +PREFERENCES_PROFILESAVEINPUT;Save Processing Parameters Next to the Input File +PREFERENCES_PSPATH;Adobe Photoshop installation directory +PREFERENCES_SELECTICCDIRDLG;ICC profilen carpeta hautatu... +PREFERENCES_SELECTLANG;Hizkuntza hautatu +PREFERENCES_SELECTMONITORPROFDLG;Pantaila profilen karpeta hautatu... +PREFERENCES_SELECTTHEME;Select theme +PREFERENCES_SHOWBASICEXIF;Oinarrizko EXIF datuak bistaratu +PREFERENCES_SHOWDATETIME;Data eta ordua bistratu +PREFERENCES_SHOWONLYRAW;RAW artxiboak bakarrik erakutsi +PREFERENCES_SHTHRESHOLD;Moztutako itzalen muga +PREFERENCES_STARTUPIMDIR;Abioako irudien karpeta +PREFERENCES_TAB_BROWSER;Artxibo arakatzailea +PREFERENCES_TAB_COLORMGR;Kolore kudeaketa +PREFERENCES_TAB_GENERAL;Orokorra +PREFERENCES_TAB_IMPROC;Irudien prozesua +PREFERENCES_TAB_OUTPUT;Irteera aukerak +PREFERENCES_THUMBSIZE;Miniaturen tamaina +PROFILEPANEL_FILEDLGFILTERANY;Artxibo guztiak +PROFILEPANEL_FILEDLGFILTERPP;Prozesu profilak +PROFILEPANEL_LABEL;Prozesu profilak +PROFILEPANEL_LOADDLGLABEL;Profilaren aldagaiak ireki... +PROFILEPANEL_PCUSTOM;Neurrira +PROFILEPANEL_PFILE;Artxibotik +PROFILEPANEL_PLASTPHOTO;Azken argazkia +PROFILEPANEL_PLASTSAVED;Gordtako azkena +PROFILEPANEL_PROFILE;Profilak +PROFILEPANEL_SAVEDLGLABEL;Profilaren aldagaiak gorde... +PROFILEPANEL_TOOLTIPCOPY;Copy current profile to clipboard +PROFILEPANEL_TOOLTIPLOAD;Profila artxibotik ireki +PROFILEPANEL_TOOLTIPPASTE; Paste profile from clipboard +PROFILEPANEL_TOOLTIPSAVE;Uneko profila gorde +PROGRESSBAR_DECODING;RAW artxiboa dekodetzen... +PROGRESSBAR_DEMOSAICING;Demosaikatzen... +PROGRESSBAR_LOADING;Irudia ireki... +PROGRESSBAR_LOADJPEG;JPG artxiboa irekitzen... +PROGRESSBAR_LOADPNG;PNG artxiboa irekitzen... +PROGRESSBAR_LOADTIFF;TIFF artxiboa irekitzen... +PROGRESSBAR_PROCESSING;Irudiaren prozesua... +PROGRESSBAR_READY;Prest. +PROGRESSBAR_SAVEJPEG;JPG artxiboa gordetzen... +PROGRESSBAR_SAVEPNG;PNG artxiboa gordetzen... +PROGRESSBAR_SAVETIFF;TIFF artxiboa gordetzen... +PROGRESSDLG_LOADING;Loading file... +PROGRESSDLG_PROCESSING;Processing image... +PROGRESSDLG_SAVING;Saving file... +QINFO_FOCALLENGTH;Fokal luzera +QINFO_ISO;ISO +QINFO_LENS;Lens +QINFO_NOEXIF;Ez dago EXIF daturik. +SAVEDLG_FILEFORMAT;Artxiboaren formatua +SAVEDLG_JPEGQUAL;JPEG kalitatea +SAVEDLG_JPGFILTER;JPEG artxiboak +SAVEDLG_PNGCOMPR;PNG konpresioa +SAVEDLG_PNGFILTER;PNG artxiboak +SAVEDLG_PUTTOQUEUE;Put into processing queue +SAVEDLG_PUTTOQUEUEHEAD;Put to the head of the processing queue +SAVEDLG_PUTTOQUEUETAIL;Put to the end of the processing queue +SAVEDLG_SAVEIMMEDIATELY;Save immediately +SAVEDLG_SAVESPP;Prozesu aldagaiak irudiarekin batera gorde +SAVEDLG_TIFFFILTER;TIFF artxiboak +TOOLBAR_TOOLTIP_CROP;Hautapena moztu (shortcut key: C) +TOOLBAR_TOOLTIP_HAND;Esku tresna (shortcut key: N) +TOOLBAR_TOOLTIP_STRAIGHTEN;Lerro zuzena hautatu (shortcut key: S) +TOOLBAR_TOOLTIP_WB;Zuri balantze puntuala (shortcut key: W) +TP_CACORRECTION_BLUE;Urdina +TP_CACORRECTION_LABEL;C/A zuzenketa +TP_CACORRECTION_RED;Gorria +TP_CHMIXER_BLUE;Urdina +TP_CHMIXER_GREEN;Berdea +TP_CHMIXER_LABEL;Kanal nahastailea +TP_CHMIXER_RED;Gorria +TP_COARSETRAF_DEGREE;Graduak: +TP_COARSETRAF_TOOLTIP_HFLIP;Horizontalki irauli +TP_COARSETRAF_TOOLTIP_ROTLEFT;Errotazioa ezkerraldera +TP_COARSETRAF_TOOLTIP_ROTRIGHT;Errotazioa eskunialdera +TP_COARSETRAF_TOOLTIP_VFLIP;Bertikalki irauli +TP_COLORBOOST_ACHANNEL;"a" kanala +TP_COLORBOOST_AMOUNT;Kopurua +TP_COLORBOOST_AVOIDCOLORCLIP;Kolore mozketa ekidin +TP_COLORBOOST_BCHANNEL;"b" kanala +TP_COLORBOOST_CHAB;a & b +TP_COLORBOOST_CHANNEL;Kanala +TP_COLORBOOST_CHSEPARATE;bananduak +TP_COLORBOOST_ENABLESATLIMITER;Saturazio muga gaitu +TP_COLORBOOST_LABEL;Koloreak jaso +TP_COLORBOOST_SATLIMIT;Saturazio muga +TP_COLORDENOISE_EDGESENSITIVE;Ertzetara sentikorra +TP_COLORDENOISE_EDGETOLERANCE;Ertz tolerantzia +TP_COLORDENOISE_LABEL;Kolore zarata murrizketa +TP_COLORDENOISE_RADIUS;Erradioa +TP_COLORSHIFT_BLUEYELLOW;Urdin-Horia +TP_COLORSHIFT_GREENMAGENTA;Berde-Magenta +TP_COLORSHIFT_LABEL;Kolore aldaketa +TP_CROP_DPI;DPI= +TP_CROP_FIXRATIO;Erlazio finkoa: +TP_CROP_GTDIAGONALS;Diagonalen erregela +TP_CROP_GTHARMMEANS1;Bataz besteko armonikoa 1 +TP_CROP_GTHARMMEANS2;Bataz besteko armonikoa 2 +TP_CROP_GTHARMMEANS3;Bataz besteko armonikoa 3 +TP_CROP_GTHARMMEANS4;Bataz besteko armonikoa 4 +TP_CROP_GTNONE;Bat ere ez +TP_CROP_GTRULETHIRDS;Herenen erregela +TP_CROP_GUIDETYPE;Gida mota: +TP_CROP_H;H +TP_CROP_LABEL;Moztu +TP_CROP_SELECTCROP; Mozketa hautatu +TP_CROP_W;W +TP_CROP_X;x +TP_CROP_Y;y +TP_DISTORTION_AMOUNT;Kopurua +TP_DISTORTION_LABEL;Distortsioa +TP_EXPOSURE_AUTOLEVELS;Maila auto. +TP_EXPOSURE_BLACKLEVEL;Beltza +TP_EXPOSURE_BRIGHTNESS;Distira +TP_EXPOSURE_CLIP;Moztu +TP_EXPOSURE_COMPRHIGHLIGHTS;Argi konpresioa +TP_EXPOSURE_COMPRSHADOWS;Itzal konpresioa +TP_EXPOSURE_CONTRAST;Kontrastea +TP_EXPOSURE_CURVEEDITOR;Tonu kurba +TP_EXPOSURE_EXPCOMP;Esp. Konp. +TP_EXPOSURE_LABEL;Esposizioa +TP_HLREC_CIELAB;CIELab Blending +TP_HLREC_COLOR;Kolorearen hedapena +TP_HLREC_LABEL;Distiren berreskurapena +TP_HLREC_LUMINANCE;Argitasun berreskurapena +TP_HLREC_METHOD;Metodoa: +TP_ICM_FILEDLGFILTERANY;Artxibo guztiak +TP_ICM_FILEDLGFILTERICM;ICC profilen artxiboak +TP_ICM_GAMMABEFOREINPUT;Profile applies Gamma +TP_ICM_INPUTCAMERA;Kameraren jatorrizko balioak +TP_ICM_INPUTCUSTOM;Neurrira +TP_ICM_INPUTDLGLABEL;Sarrerako ICC profila hautatu... +TP_ICM_INPUTEMBEDDED;Txertatutakoa erabili, egonez gero +TP_ICM_INPUTPROFILE;Sarrerako profila +TP_ICM_LABEL;ICM +TP_ICM_NOICM;ICM-rik ez: sRGB irteera +TP_ICM_OUTPUTDLGLABEL;Irteerako ICC profila hautatu... +TP_ICM_OUTPUTPROFILE;Irteera profila +TP_ICM_SAVEREFERENCE;Save reference image for profiling +TP_ICM_WORKINGPROFILE;Lan profila +TP_LUMACURVE_BLACKLEVEL;Beltza +TP_LUMACURVE_BRIGHTNESS;Distira +TP_LUMACURVE_COMPRHIGHLIGHTS;Argi konpresioa +TP_LUMACURVE_COMPRSHADOWS;Itzal konpresioa +TP_LUMACURVE_CONTRAST;Kontrastea +TP_LUMACURVE_CURVEEDITOR;Argitasun kurba +TP_LUMACURVE_LABEL;Argitasun kurba +TP_LUMADENOISE_EDGETOLERANCE;Ertz tolerantzia +TP_LUMADENOISE_LABEL;Argitasun zarata murrizketa +TP_LUMADENOISE_RADIUS;Erradioa +TP_RESIZE_BICUBIC;Bikubikoa +TP_RESIZE_BICUBICSF;Bikubikoa (Biguna) +TP_RESIZE_BICUBICSH;Bikubikoa (Fokatua) +TP_RESIZE_BILINEAR;Bilineala +TP_RESIZE_FULLSIZE;Irudi tamaina osoa: +TP_RESIZE_H;H: +TP_RESIZE_LABEL;Tamaina aldatu +TP_RESIZE_METHOD;Metodoa: +TP_RESIZE_NEAREST;Gertuena +TP_RESIZE_SCALE;Eskala +TP_RESIZE_W;W: +TP_ROTATE_AUTOCROP;Auto mozketa +TP_ROTATE_DEGREE;Angelua +TP_ROTATE_FILL;Bete +TP_ROTATE_LABEL;Errotazioa +TP_ROTATE_SELECTLINE; Lerro zuzena hautatu +TP_SHADOWSHLIGHTS_HIGHLIGHTS;Argiak +TP_SHADOWSHLIGHTS_HLTONALW;Tonu zabalera +TP_SHADOWSHLIGHTS_LABEL;Itzalak/Argiak +TP_SHADOWSHLIGHTS_LOCALCONTR;Tokiko kontrastea +TP_SHADOWSHLIGHTS_RADIUS;Erradioa +TP_SHADOWSHLIGHTS_SHADOWS;Itzalak +TP_SHADOWSHLIGHTS_SHTONALW;Tonu zabalera +TP_SHARPENING_AMOUNT;Kopurua +TP_SHARPENING_EDRADIUS;Erradioa +TP_SHARPENING_EDTOLERANCE;Ertz tolerantzia +TP_SHARPENING_HALOCONTROL;Halo kontrola +TP_SHARPENING_HCAMOUNT;Kopurua +TP_SHARPENING_LABEL;Fokatu +TP_SHARPENING_METHOD;Metodoa +TP_SHARPENING_ONLYEDGES;Ertzak bakarrik fokatu +TP_SHARPENING_RADIUS;Erradioa +TP_SHARPENING_RLD;RL Dekonboluzioa +TP_SHARPENING_RLD_AMOUNT;Kopurua +TP_SHARPENING_RLD_DAMPING;Indargetzea +TP_SHARPENING_RLD_ITERATIONS;Iterazioak +TP_SHARPENING_THRESHOLD;Muga +TP_SHARPENING_USM;Defokatze maskara +TP_VIGNETTING_AMOUNT;Kopurua +TP_VIGNETTING_LABEL;Iluntze zuzenketa +TP_VIGNETTING_RADIUS;Erradioa +TP_WBALANCE_AUTO;Auto +TP_WBALANCE_CAMERA;Camera +TP_WBALANCE_CUSTOM;Pertsonalizatua +TP_WBALANCE_GREEN;Tindua +TP_WBALANCE_LABEL;Zuri balantzea +TP_WBALANCE_METHOD;Metodoa +TP_WBALANCE_SIZE;Tamaina: +TP_WBALANCE_SPOTWB;Z/B Puntuala +TP_WBALANCE_TEMPERATURE;Tenperatura +ZOOMBAR_DETAIL;Xehetasuna +ZOOMBAR_HUGE;Ikaragarria +ZOOMBAR_LARGE;Handia +ZOOMBAR_NORMAL;Arrunta +ZOOMBAR_PREVIEW;Aurrebista +ZOOMBAR_SCALE;Eskala +ZOOMBAR_SMALL;Txikia diff --git a/release/languages/francais b/release/languages/francais new file mode 100755 index 000000000..854ed703f --- /dev/null +++ b/release/languages/francais @@ -0,0 +1,579 @@ +# Français +# 1.3.2008: Hombre +# 1.5.2008: Hombre: updates for 2.4m1 +# 27.10.2008: Hombre: updates for 2.4b1 +# 18.11.2008: Hombre: updates for 2.4b2 +ADJUSTER_RESET_TO_DEFAULT;Réglages par défaut +CURVEEDITOR_FILEDLGFILTERANY;Tous les fichiers +CURVEEDITOR_FILEDLGFILTERCURVE;Fichiers de courbe +CURVEEDITOR_LINEAR;Linéaire +CURVEEDITOR_LOADDLGLABEL;Charger la Courbe... +CURVEEDITOR_SAVEDLGLABEL;Enregistrer la Courbe... +CURVEEDITOR_TOOLTIPLINEAR;Réinitialise la courbe en linéaire +CURVEEDITOR_TOOLTIPLOAD;Charger une courbe depuis un fichier +CURVEEDITOR_TOOLTIPSAVE;Enregistrer la courbe actuelle +EXIFFILTER_APERTURE;Ouverture +EXIFFILTER_CAMERA;Appareil photo +EXIFFILTER_DIALOGLABEL;Filtre EXIF +EXIFFILTER_FOCALLEN;Longueur focale +EXIFFILTER_ISO;ISO +EXIFFILTER_LENS;Optique +EXIFFILTER_SHUTTER;Obturateur +EXIFPANEL_ADDEDIT;Ajouter/Editer +EXIFPANEL_ADDEDITHINT;Ajoute ou édite un tag +EXIFPANEL_ADDTAGDLG_ENTERVALUE;Saisissez une valeur +EXIFPANEL_ADDTAGDLG_SELECTTAG;Choisissez un tag +EXIFPANEL_ADDTAGDLG_TITLE;Ajouter/Editer un tag +EXIFPANEL_KEEP;Conserver +EXIFPANEL_KEEPHINT;Conserve les tags sélectionnés lors de l'écriture du fichier de sortie +EXIFPANEL_REMOVE;Retirer +EXIFPANEL_REMOVEHINT;Retire les tags sélectionnés lors de l'écriture du fichier de sortie +EXIFPANEL_RESET;Réinitialiser +EXIFPANEL_RESETALL;Réinitialiser tout +EXIFPANEL_RESETALLHINT;Réinitialise tout les tags à leur valeurs initiales +EXIFPANEL_RESETHINT;Réinitialise les tags séléctionnés à la valeurs initials +EXIFPANEL_SUBDIRECTORY;Sous-répertoire +FILEBROWSER_APPLYPROFILE;Appliquer le profile +FILEBROWSER_ARRANGEMENTHINT;Permuter entre l'alignement vertical/horizontal des vignettes +FILEBROWSER_CLEARPROFILE;Remise à zéro du profie +FILEBROWSER_COPYPROFILE;Copie du profile +FILEBROWSER_DELETEDLGLABEL;Confirmation de la suppression de fichier +FILEBROWSER_DELETEDLGMSG;Êtes-vous sûr de vouloir supprimer les %1 fichiers selectionnés? +FILEBROWSER_EMPTYTRASH;Vider la corbeille +FILEBROWSER_EMPTYTRASHHINT;Supprime définitivement les fichiers de la corbeille +FILEBROWSER_EXIFFILTERAPPLY;Appliquer +FILEBROWSER_EXIFFILTERAPPLYHINT;Activer/désactiver les filtres EXIF du navigateur de fichier +FILEBROWSER_EXIFFILTERLABEL;Filtre EXIF +FILEBROWSER_EXIFFILTERSETTINGS;Réglages +FILEBROWSER_EXIFFILTERSETTINGSHINT;Change les réglages du filtre EXIF +FILEBROWSER_PARTIALPASTEPROFILE;Coller partiellement +FILEBROWSER_PASTEPROFILE;Coller le profil +FILEBROWSER_POPUPCANCELJOB;Abandonner la queue de traitement +FILEBROWSER_POPUPMOVEEND;Déplacer à la fin de la queue +FILEBROWSER_POPUPMOVEHEAD;Déplacer en tête de queue +FILEBROWSER_POPUPOPEN;Ouvrir +FILEBROWSER_POPUPPROCESS;Mettre dans la queue de traitement +FILEBROWSER_POPUPRANK1;1 étoile +FILEBROWSER_POPUPRANK2;2 étoiles +FILEBROWSER_POPUPRANK3;3 étoiles +FILEBROWSER_POPUPRANK4;4 étoiles +FILEBROWSER_POPUPRANK5;5 étoiles +FILEBROWSER_POPUPREMOVE;Retirer du système de fichier +FILEBROWSER_POPUPRENAME;Renommer +FILEBROWSER_POPUPSELECTALL;Selectionner tout +FILEBROWSER_POPUPTRASH;Déplace dans la corbeille +FILEBROWSER_POPUPUNRANK;Effacer le rang +FILEBROWSER_POPUPUNTRASH;Retirer de la corbeille +FILEBROWSER_PROCESSINGSETTINGS;Reglages +FILEBROWSER_PROCESSINGSETTINGSHINT;Règle le format de fichier et le dossier de sortie +FILEBROWSER_RENAMEDLGLABEL;Rennommage du fichier +FILEBROWSER_RENAMEDLGMSG;Renommer le fichier "%1" en: +FILEBROWSER_SHOWDIRHINT;Voir toutes les images du dossier +FILEBROWSER_SHOWQUEUEHINT;Voir le contenu de la queue de traitement +FILEBROWSER_SHOWRANK1HINT;Voir les images 1 étoile +FILEBROWSER_SHOWRANK2HINT;Voir les images 2 étoiles +FILEBROWSER_SHOWRANK3HINT;Voir les images 3 étoiles +FILEBROWSER_SHOWRANK4HINT;Voir les images 4 étoiles +FILEBROWSER_SHOWRANK5HINT;Voir les images 5 étoiles +FILEBROWSER_SHOWTRASHHINT;Voir le contenu de la corbeille +FILEBROWSER_SHOWUNRANKHINT;Voir les images sans étoile +FILEBROWSER_STARTPROCESSING;Démarrer le traitement +FILEBROWSER_STARTPROCESSINGHINT;Démarre le traitement/sauvegarde des images dans le queue +FILEBROWSER_STOPPROCESSING;Arrêter le traitement +FILEBROWSER_STOPPROCESSINGHINT;Arrête le traitement des images +FILEBROWSER_THUMBSIZE;Taille vign. +FILEBROWSER_ZOOMINHINT;Augmenter la taille des vignettes +FILEBROWSER_ZOOMOUTHINT;Diminuer la taille des vignettes +GENERAL_ABOUT;À propos +GENERAL_CANCEL;Annuler +GENERAL_DISABLE;Désactiver +GENERAL_DISABLED;Désactivé +GENERAL_ENABLE;Activer +GENERAL_ENABLED;Activé +GENERAL_LANDSCAPE;Paysage +GENERAL_LOAD;Charger +GENERAL_NA;indisponible +GENERAL_NO;Non +GENERAL_OK;OK +GENERAL_PORTRAIT;Portrait +GENERAL_SAVE;Enregistrer +GENERAL_YES;Oui +HISTOGRAM_LABEL;Histogramme +HISTOGRAM_TOOLTIP_B;Montrer/cacher l'histogramme BLEU +HISTOGRAM_TOOLTIP_G;Montrer/cacher l'histogramme VERT +HISTOGRAM_TOOLTIP_L;Montrer/cacher l'histogramme Luminance CIELAB +HISTOGRAM_TOOLTIP_R;Montrer/cacher l'histogramme ROUGE +HISTORY_CHANGED;Changé +HISTORY_CUSTOMCURVE;Courbe personnelle +HISTORY_DELSNAPSHOT;Supprimer +HISTORY_FROMCLIPBOARD;Du presse-papier +HISTORY_LABEL;Historique +HISTORY_MSG_10;Compression des ombres +HISTORY_MSG_11;Courbe tonale +HISTORY_MSG_12;Exposition auto +HISTORY_MSG_13;Rognage de l'exposition +HISTORY_MSG_14;Luminance - Luminosité +HISTORY_MSG_15;Luminance - Contraste +HISTORY_MSG_16;Luminance - Noir +HISTORY_MSG_17;Luminance - Compression Hautes lumières +HISTORY_MSG_18;Luminance - Compression des Ombres +HISTORY_MSG_19;Luminance - Courbe +HISTORY_MSG_1;Photo chargée +HISTORY_MSG_20;Netteté +HISTORY_MSG_21;Netteté - Rayon +HISTORY_MSG_22;Netteté - Quantité +HISTORY_MSG_23;Netteté - Seuil +HISTORY_MSG_24;Netteté - Améliorer seulement les bords +HISTORY_MSG_25;Netteté - Amélio. bords - Rayon +HISTORY_MSG_26;Netteté - Amélio. bords - Tolérance +HISTORY_MSG_27;Netteté - Contrôle du halo +HISTORY_MSG_28;Netteté - Contrôle du halo - Quantité +HISTORY_MSG_29;Méthode d'amélioration de la netteté +HISTORY_MSG_2;Profil chargé +HISTORY_MSG_30;Déconvolution - Rayon +HISTORY_MSG_31;Déconvolution - Quantité +HISTORY_MSG_32;Déconvolution - Amortissement +HISTORY_MSG_33;Déconvolution - Itérations +HISTORY_MSG_34;Éviter l'écrêtage couleur +HISTORY_MSG_35;Limiteur de saturation +HISTORY_MSG_36;Limite de saturation +HISTORY_MSG_37;Rehaussement couleur +HISTORY_MSG_38;Méthode de balance des blancs +HISTORY_MSG_39;Température de couleur +HISTORY_MSG_3;Profil changé +HISTORY_MSG_40;Teinte de balance des blancs +HISTORY_MSG_41;Décalage couleur "A" +HISTORY_MSG_42;Décalage couleur "B" +HISTORY_MSG_43;Débruitage de la Luminance +HISTORY_MSG_44;Débruitage Lum. - Rayon +HISTORY_MSG_45;Débruitage Lum. - Tolérance des bords +HISTORY_MSG_46;Débruitage Chromatique +HISTORY_MSG_47;Débruitage Chrom. - Rayon +HISTORY_MSG_48;Débruitage Chrom. - Tolérance des bords +HISTORY_MSG_49;Débruitage Chrom. - Sensible aux bords +HISTORY_MSG_4;Navigation dans l'historique +HISTORY_MSG_50;Outil Ombres/Hautes lumières +HISTORY_MSG_51;Accentuation des Hautes lumières +HISTORY_MSG_52;Accentuation des Ombres +HISTORY_MSG_53;Amplitude tonale des Hautes lumières +HISTORY_MSG_54;Amplitude tonale des Ombres +HISTORY_MSG_55;Contraste Local +HISTORY_MSG_56;Ombres/Hautes lumières - Rayon +HISTORY_MSG_57;Rotation grossière +HISTORY_MSG_58;Symétrisation / axe vertical +HISTORY_MSG_59;Symétrisation / axe horizontal +HISTORY_MSG_5;Luminosité +HISTORY_MSG_60;Rotation +HISTORY_MSG_61;Rotation +HISTORY_MSG_62;Correction de la Distorsion +HISTORY_MSG_63;Signet sélectionné +HISTORY_MSG_64;Rognage de la Photo +HISTORY_MSG_65;Correction de l'aberration chromatique +HISTORY_MSG_66;Récup. Hautes lumières +HISTORY_MSG_67;Récup. Hautes lumières - Quantité +HISTORY_MSG_68;Récup. Hautes lumières - Méthode +HISTORY_MSG_69;Espace de Couleur de Travail +HISTORY_MSG_6;Contraste +HISTORY_MSG_70;Espace de Couleur de Sortie +HISTORY_MSG_71;Espace de Couleur d'Entrée +HISTORY_MSG_72;Correction du Vignetage +HISTORY_MSG_73;Mixage des Canaux +HISTORY_MSG_74;Echelle de Redimensionnement +HISTORY_MSG_75;Méthode de Redimensionnement +HISTORY_MSG_76;Métadonnées EXIF +HISTORY_MSG_77;Métadonnées IPTC +HISTORY_MSG_7;Noir +HISTORY_MSG_8;Compensation d'exposition +HISTORY_MSG_9;Compression des hautes lumières +HISTORY_NEWSNAPSHOT;Ajouter +HISTORY_NEWSNAPSHOTAS;Sous... +HISTORY_NEWSSDIALOGLABEL;Label de la capture: +HISTORY_NEWSSDIALOGTITLE;Ajouter une nouvelle capture +HISTORY_SETTO;Réglé à +HISTORY_SNAPSHOT;Capture +HISTORY_SNAPSHOTS;Captures +ICMPANEL_FILEDLGFILTERANY;Tous les fichiers +ICMPANEL_FILEDLGFILTERICM;Fichiers de profil ICC +ICMPANEL_GAMMABEFOREINPUT;Appliquer le Gamma du profil +ICMPANEL_INPUTCAMERA;Celui de l'appareil photo +ICMPANEL_INPUTCUSTOM;Personnel +ICMPANEL_INPUTDLGLABEL;Choix du profil ICC d'entrée... +ICMPANEL_INPUTEMBEDDED;Utiliser celui inclus, si possible +ICMPANEL_INPUTPROFILE;Profil d'entrée +ICMPANEL_NOICM;Pas d'ICM: sortie sRGB +ICMPANEL_OUTPUTDLGLABEL;Choix du profil ICC de sortie... +ICMPANEL_OUTPUTPROFILE;Profil de Sortie +ICMPANEL_SAVEREFERENCE;Utiliser l'image comme profil de référence +ICMPANEL_WORKINGPROFILE;Profil de Travail +IMAGEAREA_DETAILVIEW;Vue de détail +IPTCPANEL_AUTHOR;Auteur +IPTCPANEL_AUTHORHINT;Nom du créateur de l'objet, p.ex. le rédacteur, le photographe ou le graphiste (By-line). +IPTCPANEL_AUTHORSPOSITION;Status de l'auteur +IPTCPANEL_AUTHORSPOSITIONHINT;Status du ou des créateurs de l'objet (By-line Title). +IPTCPANEL_CAPTION;Légende +IPTCPANEL_CAPTIONHINT;Une description explicite de la donnée (Légende - Résumé) +IPTCPANEL_CAPTIONWRITER;Auteur de la légende +IPTCPANEL_CAPTIONWRITERHINT;Le nom de la personne ayant rédigé, édité ou corrigé l'image ou la légende/résumé (Auteur - Editeur). +IPTCPANEL_CATEGORY;Catégorie +IPTCPANEL_CATEGORYHINT;Identifie le sujet de l'image selon l'avis du fournisseur (Catégorie). +IPTCPANEL_CITY;Ville +IPTCPANEL_CITYHINT;Ville d'origine de l'image (Ville). +IPTCPANEL_COPYHINT;Copie les réglages IPTC dans le presse-papier +IPTCPANEL_COPYRIGHT;Droit de copie +IPTCPANEL_COPYRIGHTHINT;Toute remarque nécessaire de droit de copie (Remarque Droit de copie). +IPTCPANEL_COUNTRY;Pays +IPTCPANEL_COUNTRYHINT;Le nom du pays de la ville principale où l'image a été créé (Pays - Nom de la ville principale). +IPTCPANEL_CREDIT;Crédit +IPTCPANEL_CREDITHINT;Identifie le fournisseur de l'image, pas nécessairement le propriétaire/créateur (Crédit). +IPTCPANEL_DATECREATED;Date de création +IPTCPANEL_DATECREATEDHINT;La date de création du contenu intellectuel de l'image; Format: AAAAMMJJ (Date de création). +IPTCPANEL_EMBEDDED;Incorporés +IPTCPANEL_EMBEDDEDHINT;Réinitialise selon les données IPTC incorporés dans le fichier image +IPTCPANEL_HEADLINE;Titre +IPTCPANEL_HEADLINEHINT;Une entrée publiable fournissant un synopsis du contenu de l'image (Titre). +IPTCPANEL_INSTRUCTIONS;Instructions +IPTCPANEL_INSTRUCTIONSHINT;Autres instructions éditoriales concernant l'utilisation de l'image (Instructions spéciales). +IPTCPANEL_KEYWORDS;Mots clés +IPTCPANEL_KEYWORDSHINT;Utilisé pour spécifier des mots clés de recherches (Mots clés). +IPTCPANEL_PASTEHINT;Colle les réglages IPTC du presse-papier +IPTCPANEL_PROVINCE;Province +IPTCPANEL_PROVINCEHINT;La province/état d'où est issue l'image (Province-Etat). +IPTCPANEL_RESET;Réinitialisation +IPTCPANEL_RESETHINT;Réinitialise selon le profil par défaut +IPTCPANEL_SOURCE;Source +IPTCPANEL_SOURCEHINT;Le propriétaire intellectuel du contenu de l'image (Source). +IPTCPANEL_SUPPCATEGORIES;Cétgories suppl. +IPTCPANEL_SUPPCATEGORIESHINT;Précise un peu plus le sujet de l'image (Catégories supplémentaires). +IPTCPANEL_TITLE;Titre +IPTCPANEL_TITLEHINT;Raccourcis de référence de l'image (Nom de l'objet). +IPTCPANEL_TRANSREFERENCE;Réf. transmission +IPTCPANEL_TRANSREFERENCEHINT;Un code représentant le lieux de la transmission initiale (Référence de transmission initiale). +MAIN_BUTTON_PREFERENCES;Préférences +MAIN_BUTTON_SAVE;Enregistrer l'image +MAIN_BUTTON_SAVEAS;Sous... +MAIN_BUTTON_SENDTOEDITOR;Envoyer vers l'éditeur +MAIN_MSG_ALREADYEXISTS;Le fichier existe déjà. +MAIN_MSG_CANNOTLOAD;Impossible de charger l'image +MAIN_MSG_CANNOTSAVE;Erreur d'enregistrement du fichier +MAIN_MSG_CANNOTSTARTEDITOR;Impossible de lancer l'éditeur. +MAIN_MSG_CANNOTSTARTEDITOR_SECONDARY;Veuillez saisir son chemin d'accès dans les "Préférences". +MAIN_MSG_EXITJOBSINQUEUEINFO;Les images non traités seront perdus en quittant l'application +MAIN_MSG_EXITJOBSINQUEUEQUEST;Êtes-vous sûr de vouloir quitter? Il reste dans la queue des images en attente de traitement. +MAIN_MSG_JOBSINQUEUE;travail(aux) en fil d'attente +MAIN_MSG_QOVERWRITE;Voulez-vous l'écraser? +MAIN_TAB_BASIC;Basique +MAIN_TAB_COLOR;Couleur +MAIN_TAB_DETAIL;Détail +MAIN_TAB_EXIF;EXIF +MAIN_TAB_EXPOSURE;Exposition +MAIN_TAB_ICM;ICM +MAIN_TAB_IPTC;IPTC +MAIN_TAB_METADATA;Métadonnées +MAIN_TAB_TRANSFORM;Transformation +MAIN_TOOLTIP_HIDEFP;Montrer/cacher le panneau inférieur (navigateur de dossiers et de fichiers, touche F) +MAIN_TOOLTIP_HIDEHP;Montrer/cacher le panneau gauche (incluant l'historique, touche H) +MAIN_TOOLTIP_INDCLIPPEDH;Indication Hautes lumières hors domaine +MAIN_TOOLTIP_INDCLIPPEDS;Indication Ombres hors domaine +MAIN_TOOLTIP_PREFERENCES;Régler les préférences +MAIN_TOOLTIP_QINFO;Infos rapides sur l'image +MAIN_TOOLTIP_SAVE;Enregistrer l'image dans le dossier par défaut +MAIN_TOOLTIP_SAVEAS;Enregistrer l'image dans un dossier de son choix +PARTIALPASTE_BASICGROUP;Réglages de base +PARTIALPASTE_CACORRECTION;Correction Aberr./Chrom. +PARTIALPASTE_COARSETRANS;Rotation de 90° / symétrisation +PARTIALPASTE_COLORBOOST;Réhaussement couleur +PARTIALPASTE_COLORDENOISE;Réduction du bruit chromatique +PARTIALPASTE_COLORGROUP;Réglages couleurs +PARTIALPASTE_COLORMIXER;Mixage couleur +PARTIALPASTE_COLORSHIFT;Décalage couleur +PARTIALPASTE_COMPOSITIONGROUP;Réglages de la composition +PARTIALPASTE_CROP;Rognage +PARTIALPASTE_DIALOGLABEL;Collage partiel de profile de traitement +PARTIALPASTE_DISTORTION;Correction de distortion +PARTIALPASTE_EXIFCHANGES;Modification des données EXIF +PARTIALPASTE_EXPOSURE;Exposition +PARTIALPASTE_HLRECOVERY;Récupération des hautes lumières +PARTIALPASTE_ICMSETTINGS;Réglages ICM +PARTIALPASTE_IPTCINFO;Infos IPTC +PARTIALPASTE_LENSGROUP;Réglages de l'objectif +PARTIALPASTE_LUMACURVE;Courbe de luminance +PARTIALPASTE_LUMADENOISE;Réduction du bruit de luminance +PARTIALPASTE_LUMINANCEGROUP;Réglages de la luminance +PARTIALPASTE_METAICMGROUP;Réglages des Métadonnées/ICM +PARTIALPASTE_RESIZE;Redimentionnement +PARTIALPASTE_ROTATION;Rotation +PARTIALPASTE_SHADOWSHIGHLIGHTS;Ombres/Hautes lumières +PARTIALPASTE_SHARPENING;Netteté +PARTIALPASTE_VIGNETTING;Correction du vignetage +PARTIALPASTE_WHITEBALANCE;Balance des blancs +PREFERENCES_APPLNEXTSTARTUP;appliqué au prochain lancement +PREFERENCES_BLINKCLIPPED;Faire clignoter les zones hors domaine +PREFERENCES_CACHECLEARALL;Tout nettoyer +PREFERENCES_CACHECLEARPROFILES;Nettoyer les Profiles +PREFERENCES_CACHECLEARTHUMBS;Nettoyer les Vignettes +PREFERENCES_CACHEFORMAT1;Propriétaire (plus rapide et de meilleur qualité) +PREFERENCES_CACHEFORMAT2;JPEG (moins volumineux sur le disque) +PREFERENCES_CACHEMAXENTRIES;Nombre maximal d'éléments dans le Cache +PREFERENCES_CACHEOPTS;Options du Cache +PREFERENCES_CACHESTRAT1;Optimiser la vitesse au détriment de la Consommation mémoire +PREFERENCES_CACHESTRAT2;Optimiser la Consommation mémoire au détriment de la Vitesse +PREFERENCES_CACHESTRAT;Stratégie de gestion du Cache +PREFERENCES_CACHETHUMBFORM;Format des vignettes du Cache +PREFERENCES_CACHETHUMBHEIGHT;Hauteur maximale des vignettes +PREFERENCES_CLEARDLG_LINE1;Nettoyage du Cache +PREFERENCES_CLEARDLG_LINE2;Ceci peut prendre plusieurs secondes. +PREFERENCES_CLEARDLG_TITLE;Veuillez patienter +PREFERENCES_CLIPPINGIND;Indication du dépassement de plage dynamique +PREFERENCES_CMETRICINTENT;Intention Colorimétrique +PREFERENCES_DATEFORMAT;Format de la date +PREFERENCES_DATEFORMATHINT;Vous pouvez utiliser les paramètres de chaînes formatés suivants:\n%y : année\n%m : mois\n%d : jour\n\nPar exemple, le format de date hongroise est:\n%y/%m/%d +PREFERENCES_DEFAULTLANG;Langue par défaut +PREFERENCES_DEFAULTTHEME;Thème par défaut +PREFERENCES_DEMOSAICINGALGO;Algorithme de dématriçage +PREFERENCES_DIRHOME;Racine de mes documents personnels +PREFERENCES_DIRLAST;Dernier dossier visité +PREFERENCES_DIROTHER;Autre +PREFERENCES_DIRSELECTDLG;Choix du dossier Image au lancement... +PREFERENCES_DIRSOFTWARE;Dossier d'installation +PREFERENCES_DMETHOD;Méthode +PREFERENCES_EDITORCMDLINE;Autre ligne de commande +PREFERENCES_EXTERNALEDITOR;Editeur externe +PREFERENCES_FALSECOLOR;Itérations pour la suppression des fausses couleurs +PREFERENCES_FBROWSEROPTS;Options du Navigateur de fichiers +PREFERENCES_FILEFORMAT;Format du fichier +PREFERENCES_FORIMAGE;Pour les fichiers images +PREFERENCES_FORRAW;Pour les fichiers RAW +PREFERENCES_GIMPPATH;Dossier d'intallation de GIMP +PREFERENCES_GTKTHEME;GTK par défaut +PREFERENCES_HINT;Conseil +PREFERENCES_HLTHRESHOLD;Seuil pour le dépassement de domaine supérieur +PREFERENCES_ICCDIR;Dossier des profils ICC +PREFERENCES_IMPROCPARAMS;Paramètres de traitement d'image par défaut +PREFERENCES_INTENT_ABSOLUTE;Colorimétrie Absolue +PREFERENCES_INTENT_PERCEPTUAL;Perceptuel +PREFERENCES_INTENT_RELATIVE;Colorimétrie Relative +PREFERENCES_INTENT_SATURATION;Saturation +PREFERENCES_LIVETHUMBNAILS;Vignettes "Live" (plus lent) +PREFERENCES_MONITORICC;Profil du Moniteur +PREFERENCES_OUTDIR;Dossier de sortie +PREFERENCES_OUTDIRFOLDER;Dossier de sauvegarde +PREFERENCES_OUTDIRFOLDERHINT;Place les images traités dans le dossier selectionné +PREFERENCES_OUTDIRHINT;Vous pouvez utiliser les paramètres de chaîne formatés suivants:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nCes paramètres de chaînes formatés se réfèrent au dossiers et sous-chemins du chemin du fichier RAW.\n\nPar exemple, si /home/tom/image/02-09-2006/dsc0012.nefa été ouvert, la signification des paramètres est:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nSi vous voulez enregistrer l'image de sortie là où se trouve l'original, écrivez:\n%p1/%f\n\nSi vous voulez enregistrer l'image de sortie dans un dossier 'convertis' situé dans le dossier de l'original, écrivez:\n%p1/convertis/%f\n\nSi vous voulez enregistrer l'image de sortie dans le dossier '/home/tom/convertis' en conservant le même sous-dossier de dates, écrivez:\n%p2/convertis/%d1/%f +PREFERENCES_OUTDIRTEMPLATE;Utiliser le modèle +PREFERENCES_OUTDIRTEMPLATEHINT;Vous pouvez utiliser les paramètres de chaîne formatés suivants:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nCes paramètres de chaînes formatés se réfèrent au dossiers et sous-chemins du chemin du fichier RAW.\n\nPar exemple, si /home/tom/image/02-09-2006/dsc0012.nefa été ouvert, la signification des paramètres est:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nSi vous voulez enregistrer l'image de sortie là où se trouve l'original, écrivez:\n%p1/%f\n\nSi vous voulez enregistrer l'image de sortie dans un dossier 'convertis' situé dans le dossier de l'original, écrivez:\n%p1/convertis/%f\n\nSi vous voulez enregistrer l'image de sortie dans le dossier '/home/tom/convertis' en conservant le même sous-dossier de dates, écrivez:\n%p2/convertis/%d1/%f +PREFERENCES_PARSEDEXT;Extensions considérés +PREFERENCES_PARSEDEXTADD;Ajout de l'extension +PREFERENCES_PARSEDEXTADDHINT;Tapez une extension et cliquez ce bouton pour l'ajouter à la liste +PREFERENCES_PARSEDEXTDELHINT;Supprime de la liste les extensions sélectionnés +PREFERENCES_PROFILEHANDLING;Gestionnaire des profils de traitement +PREFERENCES_PROFILELOADPR;Priorité de chargement des profiles +PREFERENCES_PROFILEPRCACHE;Profile dans le Cache +PREFERENCES_PROFILEPRFILE;Profile accolé au fichier d'entrée +PREFERENCES_PROFILESAVECACHE;Enregistrer la paramètres de traitement dans le Cache +PREFERENCES_PROFILESAVEINPUT;Enregistrer la paramètres de traitement accolé au fichier d'entrée +PREFERENCES_PSPATH;Dossier d'installation d'Adobe Photoshop +PREFERENCES_SELECTICCDIRDLG;Choix du dossier des profils ICC... +PREFERENCES_SELECTLANG;Choix de la langue +PREFERENCES_SELECTMONITORPROFDLG;Choix du profil ICC de l'affichage... +PREFERENCES_SELECTTHEME;Choisissez un thème +PREFERENCES_SHOWBASICEXIF;Voir les infos Exif basiques +PREFERENCES_SHOWDATETIME;Voir la date et l'heure +PREFERENCES_SHOWONLYRAW;Voir seulement les fichiers RAW +PREFERENCES_SHTHRESHOLD;Seuil pour le dépassement de domaine inférieur +PREFERENCES_STARTUPIMDIR;Répertoire Image au démarrage +PREFERENCES_TAB_BROWSER;Navigateur de fichiers +PREFERENCES_TAB_COLORMGR;Gestion des couleurs +PREFERENCES_TAB_GENERAL;Général +PREFERENCES_TAB_IMPROC;Traitement de l'Image +PREFERENCES_TAB_OUTPUT;Options de Sortie +PREFERENCES_THUMBSIZE;Tailles des vignettes +PROFILEPANEL_FILEDLGFILTERANY;Tous les fichiers +PROFILEPANEL_FILEDLGFILTERPP;Profils de Post-Traitement +PROFILEPANEL_LABEL;Profils de Post-traitement +PROFILEPANEL_LOADDLGLABEL;Charger les Paramètres de Post-traitement... +PROFILEPANEL_PCUSTOM;Personnel +PROFILEPANEL_PFILE;Depuis le fichier +PROFILEPANEL_PLASTPHOTO;Photo précédente +PROFILEPANEL_PLASTSAVED;Dernière sauvegarde +PROFILEPANEL_PROFILE;Profile +PROFILEPANEL_SAVEDLGLABEL;Enregistrer les Paramètres de Post-traitement... +PROFILEPANEL_TOOLTIPCOPY;Copie le profile courant dans le presse-papier +PROFILEPANEL_TOOLTIPLOAD;Charger un profil depuis un fichier +PROFILEPANEL_TOOLTIPPASTE; Colle le profile depuis le presse-papier +PROFILEPANEL_TOOLTIPSAVE;Enregistrer le profil actuel +PROGRESSBAR_DECODING;Décodage du fichier RAW... +PROGRESSBAR_DEMOSAICING;Dématriçage... +PROGRESSBAR_LOADING;Chargement de l'Image... +PROGRESSBAR_LOADJPEG;Chargement du fichier JPEG... +PROGRESSBAR_LOADPNG;Chargement du fichier PNG... +PROGRESSBAR_LOADTIFF;Chargement du fichier TIFF... +PROGRESSBAR_PROCESSING;Traitement de l'Image... +PROGRESSBAR_READY;Prêt. +PROGRESSBAR_SAVEJPEG;Enregistrement du fichier JPEG... +PROGRESSBAR_SAVEPNG;Enregistrement du fichier PNG... +PROGRESSBAR_SAVETIFF;Enregistrement du fichier TIFF... +PROGRESSDLG_LOADING;Chargement du fichier... +PROGRESSDLG_PROCESSING;Traitement de l'image... +PROGRESSDLG_SAVING;Enregistrement du fichier... +QINFO_FOCALLENGTH;Longueur focale +QINFO_ISO;ISO +QINFO_LENS;Objectif +QINFO_NOEXIF;Données Exif non disponible. +SAVEDLG_FILEFORMAT;Format de fichier +SAVEDLG_JPEGQUAL;Qualité JPEG +SAVEDLG_JPGFILTER;Fichiers JPEG +SAVEDLG_PNGCOMPR;Compression PNG +SAVEDLG_PNGFILTER;Fichiers PNG +SAVEDLG_PUTTOQUEUE;Placer dans la queue de traitement +SAVEDLG_PUTTOQUEUEHEAD;Placer au début de la queue de traitement +SAVEDLG_PUTTOQUEUETAIL;Placer au fin de la queue de traitement +SAVEDLG_SAVEIMMEDIATELY;Enregistrer immédiatement +SAVEDLG_SAVESPP;Enregistrer les paramètres de développement avec l'image +SAVEDLG_TIFFFILTER;Fichiers TIFF +TOOLBAR_TOOLTIP_CROP;Sélection du rognage (touche C) +TOOLBAR_TOOLTIP_HAND;Outil de navigation (touche N) +TOOLBAR_TOOLTIP_STRAIGHTEN;Sélection de la ligne d'horizon (touche S) +TOOLBAR_TOOLTIP_WB;Choix du point déterminant la balance des blancs (touche W) +TP_CACORRECTION_BLUE;Bleu +TP_CACORRECTION_LABEL;Correction Aberration Chromatique +TP_CACORRECTION_RED;Rouge +TP_CHMIXER_BLUE;Bleu +TP_CHMIXER_GREEN;Vert +TP_CHMIXER_LABEL;Mixage des Canaux +TP_CHMIXER_RED;Rouge +TP_COARSETRAF_DEGREE;degré: +TP_COARSETRAF_TOOLTIP_HFLIP;Symétriser / axe vertical +TP_COARSETRAF_TOOLTIP_ROTLEFT;Rotation vers la gauche +TP_COARSETRAF_TOOLTIP_ROTRIGHT;Rotation vers la droite +TP_COARSETRAF_TOOLTIP_VFLIP;Symétriser / axe horizontal +TP_COLORBOOST_ACHANNEL;canal "a" +TP_COLORBOOST_AMOUNT;Quantité +TP_COLORBOOST_AVOIDCOLORCLIP;Éviter l'écrêtage couleur +TP_COLORBOOST_BCHANNEL;canal "b" +TP_COLORBOOST_CHAB;a & b +TP_COLORBOOST_CHANNEL;Canal +TP_COLORBOOST_CHSEPARATE;séparé +TP_COLORBOOST_ENABLESATLIMITER;Activer le limiteur de saturation +TP_COLORBOOST_LABEL;Rehaussement couleur +TP_COLORBOOST_SATLIMIT;Limite de saturation +TP_COLORDENOISE_EDGESENSITIVE;Sensible aux bords +TP_COLORDENOISE_EDGETOLERANCE;Tolérance des bords +TP_COLORDENOISE_LABEL;Réduction du bruit chromatique +TP_COLORDENOISE_RADIUS;Rayon +TP_COLORSHIFT_BLUEYELLOW;Bleu-Jaune +TP_COLORSHIFT_GREENMAGENTA;Vert-Magenta +TP_COLORSHIFT_LABEL;Décalage couleur +TP_CROP_DPI;PPP= +TP_CROP_FIXRATIO;Ratio fixe: +TP_CROP_GTDIAGONALS;Règle des diagonales +TP_CROP_GTHARMMEANS1;Manière harmonique 1 +TP_CROP_GTHARMMEANS2;Manière harmonique 2 +TP_CROP_GTHARMMEANS3;Manière harmonique 3 +TP_CROP_GTHARMMEANS4;Manière harmonique 4 +TP_CROP_GTNONE;Aucun +TP_CROP_GTRULETHIRDS;Règle des tiers +TP_CROP_GUIDETYPE;Type de guide: +TP_CROP_H;H +TP_CROP_LABEL;Rognage +TP_CROP_SELECTCROP; Sélection du rognage +TP_CROP_W;L +TP_CROP_X;x +TP_CROP_Y;y +TP_DISTORTION_AMOUNT;Quantité +TP_DISTORTION_LABEL;Distorsion +TP_EXPOSURE_AUTOLEVELS;Niveaux Auto +TP_EXPOSURE_BLACKLEVEL;Noir +TP_EXPOSURE_BRIGHTNESS;Luminosité +TP_EXPOSURE_CLIP;Rognage +TP_EXPOSURE_COMPRHIGHLIGHTS;Compression hautes lumières +TP_EXPOSURE_COMPRSHADOWS;Compression des ombres +TP_EXPOSURE_CONTRAST;Contraste +TP_EXPOSURE_CURVEEDITOR;Courbe tonale +TP_EXPOSURE_EXPCOMP;Compensation d'exposition +TP_EXPOSURE_LABEL;Exposition +TP_HLREC_CIELAB;Mélange CIELab +TP_HLREC_COLOR;Propagation de la couleur +TP_HLREC_LABEL;Récupération des hautes lumières +TP_HLREC_LUMINANCE;Récupération de la luminance +TP_HLREC_METHOD;Méthode: +TP_ICM_FILEDLGFILTERANY;Tous les fichiers +TP_ICM_FILEDLGFILTERICM;Fichiers de profil ICC +TP_ICM_GAMMABEFOREINPUT;Appliquer le Gamma du profil +TP_ICM_INPUTCAMERA;Celui de l'appareil photo +TP_ICM_INPUTCUSTOM;Personnel +TP_ICM_INPUTDLGLABEL;Choix du profil ICC d'entrée... +TP_ICM_INPUTEMBEDDED;Utiliser celui inclus, si possible +TP_ICM_INPUTPROFILE;Profil d'entrée +TP_ICM_LABEL;ICM +TP_ICM_NOICM;Pas d'ICM: sortie sRGB +TP_ICM_OUTPUTDLGLABEL;Choix du profil ICC de sortie... +TP_ICM_OUTPUTPROFILE;Profil de Sortie +TP_ICM_SAVEREFERENCE;Utiliser l'image comme profil de référence +TP_ICM_WORKINGPROFILE;Profil de Travail +TP_LUMACURVE_BLACKLEVEL;Noir +TP_LUMACURVE_BRIGHTNESS;Luminosité +TP_LUMACURVE_COMPRHIGHLIGHTS;Compression hautes lumières +TP_LUMACURVE_COMPRSHADOWS;Compression des ombres +TP_LUMACURVE_CONTRAST;Contraste +TP_LUMACURVE_CURVEEDITOR;Courbe de luminance +TP_LUMACURVE_LABEL;Courbe de Luminance +TP_LUMADENOISE_EDGETOLERANCE;Tolérance des bords +TP_LUMADENOISE_LABEL;Réduction du bruit de luminance +TP_LUMADENOISE_RADIUS;Rayon +TP_RESIZE_BICUBIC;Bicubique +TP_RESIZE_BICUBICSF;Bicubique (Plus doux) +TP_RESIZE_BICUBICSH;Bicubique (Plus net) +TP_RESIZE_BILINEAR;Bilinéaire +TP_RESIZE_FULLSIZE;Dimensions finales de l'image: +TP_RESIZE_H;H: +TP_RESIZE_LABEL;Redimensionnement +TP_RESIZE_METHOD;Méthode: +TP_RESIZE_NEAREST;Au plus proche +TP_RESIZE_SCALE;Echelle +TP_RESIZE_W;L: +TP_ROTATE_AUTOCROP;Rognage auto +TP_ROTATE_DEGREE;Degré +TP_ROTATE_FILL;Remplir +TP_ROTATE_LABEL;Rotation +TP_ROTATE_SELECTLINE; Choisir la ligne d'horizon +TP_SHADOWSHLIGHTS_HIGHLIGHTS;Hautes lumières +TP_SHADOWSHLIGHTS_HLTONALW;Amplitude tonale +TP_SHADOWSHLIGHTS_LABEL;Ombres/Hautes lumières +TP_SHADOWSHLIGHTS_LOCALCONTR;Contraste local +TP_SHADOWSHLIGHTS_RADIUS;Rayon +TP_SHADOWSHLIGHTS_SHADOWS;Ombres +TP_SHADOWSHLIGHTS_SHTONALW;Amplitude tonale +TP_SHARPENING_AMOUNT;Quantité +TP_SHARPENING_EDRADIUS;Rayon +TP_SHARPENING_EDTOLERANCE;Tolérance des bords +TP_SHARPENING_HALOCONTROL;Contrôle du halo +TP_SHARPENING_HCAMOUNT;Quantité +TP_SHARPENING_LABEL;Netteté +TP_SHARPENING_METHOD;Méthode +TP_SHARPENING_ONLYEDGES;Améliorer seulement les bords +TP_SHARPENING_RADIUS;Rayon +TP_SHARPENING_RLD;Déconvolution de Richardson–Lucy +TP_SHARPENING_RLD_AMOUNT;Quantité +TP_SHARPENING_RLD_DAMPING;Amortissement +TP_SHARPENING_RLD_ITERATIONS;Itérations +TP_SHARPENING_THRESHOLD;Seuil +TP_SHARPENING_USM;Masque flou +TP_VIGNETTING_AMOUNT;Quantité +TP_VIGNETTING_LABEL;Correction Vignetage +TP_VIGNETTING_RADIUS;Rayon +TP_WBALANCE_AUTO;Auto +TP_WBALANCE_CAMERA;Appareil photo +TP_WBALANCE_CUSTOM;Personnalisé +TP_WBALANCE_GREEN;Teinte +TP_WBALANCE_LABEL;Balance des blancs +TP_WBALANCE_METHOD;Méthode +TP_WBALANCE_SIZE;Taille: +TP_WBALANCE_SPOTWB;Point de mesure +TP_WBALANCE_TEMPERATURE;Température +ZOOMBAR_DETAIL;Détail +ZOOMBAR_HUGE;Énorme +ZOOMBAR_LARGE;Large +ZOOMBAR_NORMAL;Normal +ZOOMBAR_PREVIEW;Prévisualiation +ZOOMBAR_SCALE;Echelle +ZOOMBAR_SMALL;Petit diff --git a/release/languages/greek b/release/languages/greek new file mode 100755 index 000000000..ae8d9ba92 --- /dev/null +++ b/release/languages/greek @@ -0,0 +1,575 @@ +# 14.05.2008: zeusalmighty +ADJUSTER_RESET_TO_DEFAULT;ΕπαναφοÏά Ï€Ïοεπιλογών +CURVEEDITOR_FILEDLGFILTERANY;Οποιοδήποτε αÏχείο +CURVEEDITOR_FILEDLGFILTERCURVE;ΑÏχεία καμπυλών +CURVEEDITOR_LINEAR;ΓÏαμμικό +CURVEEDITOR_LOADDLGLABEL;ΦόÏτωση καμπÏλης... +CURVEEDITOR_SAVEDLGLABEL;Αποθήκευση καμπλης... +CURVEEDITOR_TOOLTIPLINEAR;ΕπαναφοÏά καμπÏλης σε γÏαμμική +CURVEEDITOR_TOOLTIPLOAD;ΦόÏτωση καμπÏλης απο αÏχείο +CURVEEDITOR_TOOLTIPSAVE;Αποθήκευση παÏοÏσας καμπÏλης +EXIFFILTER_APERTURE;Aperture +EXIFFILTER_CAMERA;Camera +EXIFFILTER_DIALOGLABEL;Exif Filter +EXIFFILTER_FOCALLEN;Focal Length +EXIFFILTER_ISO;ISO +EXIFFILTER_LENS;Lens +EXIFFILTER_SHUTTER;Shutter +EXIFPANEL_ADDEDIT;ΠÏοσθήκη/ΕπεξεÏγασία +EXIFPANEL_ADDEDITHINT;ΠÏοσθήκη καινοÏÏιας ετικέττας ή επεξεÏγασία +EXIFPANEL_ADDTAGDLG_ENTERVALUE;Εισαγωγή τιμής +EXIFPANEL_ADDTAGDLG_SELECTTAG;Επιλογή ετικέττας +EXIFPANEL_ADDTAGDLG_TITLE;ΠÏοσθήκη/ΕπεξεÏγασία ετικέττας +EXIFPANEL_KEEP;ΣυγκÏάτηση +EXIFPANEL_KEEPHINT;ΣυγκÏάτηση των επιλεγμένων ετικεττών κατά την εγγÏαφή του παÏαγώμενου αÏχείου +EXIFPANEL_REMOVE;ΑφαίÏεση +EXIFPANEL_REMOVEHINT;ΑφαίÏεση των επιλεγμένων ετικεττών κατά την εγγÏαφή του παÏαγώμενου αÏχείου +EXIFPANEL_RESET;ΕπαναφοÏά +EXIFPANEL_RESETALL;ΕπαναφοÏά όλων +EXIFPANEL_RESETALLHINT;ΕπαναφοÏά όλων των ετικεττών στην αÏχική τους τιμή +EXIFPANEL_RESETHINT;ΕπαναφοÏά των επιλεγμένων ετικεττών στις Ï€Ïωτότυπες τους τιμές +EXIFPANEL_SUBDIRECTORY;Subdirectory +FILEBROWSER_APPLYPROFILE;Apply profile +FILEBROWSER_ARRANGEMENTHINT;Change between vertical/horizontal alignment of thumbnails +FILEBROWSER_CLEARPROFILE;Clear profile +FILEBROWSER_COPYPROFILE;Copy profile +FILEBROWSER_DELETEDLGLABEL;File delete confirmation +FILEBROWSER_DELETEDLGMSG;Are you sure you want to delete the selected %1 files? +FILEBROWSER_EMPTYTRASH;Empty Trash +FILEBROWSER_EMPTYTRASHHINT;Permanently delete the files of the trash +FILEBROWSER_EXIFFILTERAPPLY;Apply +FILEBROWSER_EXIFFILTERAPPLYHINT;Switch on/off exif filter of the file browser +FILEBROWSER_EXIFFILTERLABEL;Exif Filter +FILEBROWSER_EXIFFILTERSETTINGS;Setup +FILEBROWSER_EXIFFILTERSETTINGSHINT;Change settings of the exif filter +FILEBROWSER_PARTIALPASTEPROFILE;Partial paste +FILEBROWSER_PASTEPROFILE;Paste profile +FILEBROWSER_POPUPCANCELJOB;Cancel job +FILEBROWSER_POPUPMOVEEND;Move to end of queue +FILEBROWSER_POPUPMOVEHEAD;Move to head of queue +FILEBROWSER_POPUPOPEN;Open +FILEBROWSER_POPUPPROCESS;Put to processing queue +FILEBROWSER_POPUPRANK1;Rank 1 +FILEBROWSER_POPUPRANK2;Rank 2 +FILEBROWSER_POPUPRANK3;Rank 3 +FILEBROWSER_POPUPRANK4;Rank 4 +FILEBROWSER_POPUPRANK5;Rank 5 +FILEBROWSER_POPUPREMOVE;Remove from filesystem +FILEBROWSER_POPUPRENAME;Rename +FILEBROWSER_POPUPSELECTALL;Select all +FILEBROWSER_POPUPTRASH;Move to trash +FILEBROWSER_POPUPUNRANK;Unrank +FILEBROWSER_POPUPUNTRASH;Remove from trash +FILEBROWSER_PROCESSINGSETTINGS;Settings +FILEBROWSER_PROCESSINGSETTINGSHINT;Set the file format and output directory +FILEBROWSER_RENAMEDLGLABEL;Rename file +FILEBROWSER_RENAMEDLGMSG;Rename file "%1" to: +FILEBROWSER_SHOWDIRHINT;Show all images of the directory +FILEBROWSER_SHOWQUEUEHINT;Show content of the processing queue +FILEBROWSER_SHOWRANK1HINT;Show images ranked as 1 star +FILEBROWSER_SHOWRANK2HINT;Show images ranked as 2 star +FILEBROWSER_SHOWRANK3HINT;Show images ranked as 3 star +FILEBROWSER_SHOWRANK4HINT;Show images ranked as 4 star +FILEBROWSER_SHOWRANK5HINT;Show images ranked as 5 star +FILEBROWSER_SHOWTRASHHINT;Show content of the trash +FILEBROWSER_SHOWUNRANKHINT;Show unranked images +FILEBROWSER_STARTPROCESSING;Start Processing +FILEBROWSER_STARTPROCESSINGHINT;Start processing/saving of images in the queue +FILEBROWSER_STOPPROCESSING;Stop processing +FILEBROWSER_STOPPROCESSINGHINT;Stop processing of images +FILEBROWSER_THUMBSIZE;Thumb. size +FILEBROWSER_ZOOMINHINT;Increase thumbnail size +FILEBROWSER_ZOOMOUTHINT;Decrease thumbnail size +GENERAL_ABOUT;About +GENERAL_CANCEL;ΑκÏÏωση +GENERAL_DISABLE;ΑπενεÏγοποίηση +GENERAL_DISABLED;ΑπενεÏγοποιημένο +GENERAL_ENABLE;ΕνεÏγοποίηση +GENERAL_ENABLED;ΕνεÏγοποιημένο +GENERAL_LANDSCAPE;Τοπίο +GENERAL_LOAD;ΦόÏτωση +GENERAL_NA;μη διαθέσιμο +GENERAL_NO;Όχι +GENERAL_OK;Εντάξει +GENERAL_PORTRAIT;ΠοÏÏ„Ïαίτο +GENERAL_SAVE;Αποθήκευση +GENERAL_YES;Îαί +HISTOGRAM_LABEL;Histogram +HISTOGRAM_TOOLTIP_B;ΠÏοβολή/απόκÏυψη ΜΠΛΕ ιστογÏάμματος +HISTOGRAM_TOOLTIP_G;ΠÏοβολή/απόκÏυψη ΠΡΑΣΙÎΟΥ ιστογÏάμματος +HISTOGRAM_TOOLTIP_L;ΠÏοβολή/απόκÏυψη CIELAB ιστογÏάμματος φωτεινότητας +HISTOGRAM_TOOLTIP_R;ΠÏοβολή/απόκÏυψη KOKKINOY ιστογÏάμματος +HISTORY_CHANGED;Αλλαγή +HISTORY_CUSTOMCURVE;ΠÏοσαÏμοσμένη καμπÏλη +HISTORY_DELSNAPSHOT;ΑφαίÏεση στιγμιοτÏπου +HISTORY_FROMCLIPBOARD;From clipboard +HISTORY_LABEL;ΙστοÏικό +HISTORY_MSG_10;Συμπίεση σκιών +HISTORY_MSG_11;ΚαμπÏλη τονικότητας +HISTORY_MSG_12;Αυτόματη έκθεση +HISTORY_MSG_13;Ψαλιδισμός έκθεσης +HISTORY_MSG_14;Φωτεινότητα Φωτεινότητας +HISTORY_MSG_15;Φωτεινότητα αντίθεσης +HISTORY_MSG_16;Φωτεινότητα μαÏÏων +HISTORY_MSG_17;Φωτεινότητα συμπίεσησ φωτεινών σημείων. +HISTORY_MSG_18;Φωτεινότητα συμπίεσης σκιών. +HISTORY_MSG_19;ΚαμπÏλη φωτεινότητας +HISTORY_MSG_1;ΦοÏτώθηκε εικόνα +HISTORY_MSG_20;Όξυνση +HISTORY_MSG_21;Ακτίνα όξυνσης +HISTORY_MSG_22;Ένταση όξυνσης +HISTORY_MSG_23;Κατώφλι όξυνσης +HISTORY_MSG_24;Όξυνση μόνο οÏίων +HISTORY_MSG_25;Ακτίνα ανίχνευσης οÏίων όξυνσης +HISTORY_MSG_26;Όξυνση, Ανοχή οÏίων +HISTORY_MSG_27;Όξυνση, Έλεγχος άλως +HISTORY_MSG_28;Ένταση ελέγχου άλως +HISTORY_MSG_29;Μέθοδοςν όξυνσης +HISTORY_MSG_2;ΦοÏτώθηκε Ï€Ïοφίλ +HISTORY_MSG_30;Ακτίνα Deconvolution +HISTORY_MSG_31;Ένταση Deconvolution +HISTORY_MSG_32;Καταστολή Deconvolution +HISTORY_MSG_33;Επαναλήψεις Deconvolution +HISTORY_MSG_34;Αποφυγή ψαλιδίσματος χÏώματος +HISTORY_MSG_35;ΠεÏιοσμός κοÏÎµÏƒÎ¼Î¿Ï +HISTORY_MSG_36;Ένταση πεÏÎ¹Î¿ÏƒÎ¼Î¿Ï ÎºÎ¿ÏÎµÏƒÎ¼Î¿Ï +HISTORY_MSG_37;Ενίσχυση χÏώματος +HISTORY_MSG_38;Μέθοδος εξισοÏÏόπησης Î»ÎµÏ…ÎºÎ¿Ï +HISTORY_MSG_39;ΘεÏμοκÏασία χÏώματος +HISTORY_MSG_3;Αλλαγή Ï€Ïοφίλ +HISTORY_MSG_40;ΑπόχÏωση εξισοÏÏόπησης Î»ÎµÏ…ÎºÎ¿Ï +HISTORY_MSG_41;ΧÏωματική μετατόπιση "A" +HISTORY_MSG_42;ΧÏωματική μετατόπιση "B" +HISTORY_MSG_43;ΑποθοÏÏβηση φωτεινότητας +HISTORY_MSG_44;Ακτίνα αποθοÏÏβησης φωτεινότητας +HISTORY_MSG_45;Ανοχή οÏίων αποθοÏÏβησης φωτεινότητας +HISTORY_MSG_46;ΑποθοÏÏβηση χÏώματος +HISTORY_MSG_47;Ακτίνα αποθοÏÏβησης χÏώματος +HISTORY_MSG_48;Ανοχή οÏίων αποθοÏÏβησης χÏώματος +HISTORY_MSG_49;ΑποθοÏÏβηση χÏώματος (ευαισθησία οÏίων) +HISTORY_MSG_4;Αναζήτηση ιστοÏÎ¹ÎºÎ¿Ï +HISTORY_MSG_50;ΕÏγαλείο σκιών/φωτεινών σημείων +HISTORY_MSG_51;Μείωση φωτεινών σημείων +HISTORY_MSG_52;Ενίσχυση σκιών +HISTORY_MSG_53;Τονικό εÏÏος φωτεινών σημείων +HISTORY_MSG_54;Τονικό εÏÏος σκιών +HISTORY_MSG_55;Τοπική αντίθεση +HISTORY_MSG_56;Ακτίνα σκιών/φωτεινών σημείων +HISTORY_MSG_57;Coarse Rotation +HISTORY_MSG_58;ΟÏιζόντια ανατÏοπή +HISTORY_MSG_59;ΚατακόÏυφη ανατÏοπή +HISTORY_MSG_5;Φωτεινότητα +HISTORY_MSG_60;ΠεÏιστÏοφή +HISTORY_MSG_61;ΠεÏιστÏοφή +HISTORY_MSG_62;ΔιόÏθωση παÏαμόÏφωσης Ï†Î±ÎºÎ¿Ï +HISTORY_MSG_63;Επιλέχθηκε στιγμιότυπο +HISTORY_MSG_64;Αποκοπή εικόνας +HISTORY_MSG_65;C/A ΔιόÏθωση +HISTORY_MSG_66;Ανάκτηση Φωτεινών σημείων +HISTORY_MSG_67;Ένταση ανάκτησης φωτεινών σημείων +HISTORY_MSG_68;Μέθοδος ανάκτηση φωτεινών σημείων +HISTORY_MSG_69;ΠαÏόν χÏωματικό Ï€Ïοφίλ +HISTORY_MSG_6;Αντίθεση +HISTORY_MSG_70;ΧÏωματικό Ï€Ïοφίλ εξόδου +HISTORY_MSG_71;ΧÏωματικό Ï€Ïοφίλ εισόδου +HISTORY_MSG_72;ΔιόÏθωση Vignetting +HISTORY_MSG_73;Μίξη καναλιών +HISTORY_MSG_74;Αλλαγή μεγέθους/κλίμακας +HISTORY_MSG_75;Μέθοδος αλλαγής μεγέθους +HISTORY_MSG_76;Αλλαγή στοιχείων Exif +HISTORY_MSG_77;Αλλαγή στοιχίεων IPTC +HISTORY_MSG_7;ΜαÏÏα +HISTORY_MSG_8;ΕπανόÏθωση Έκθεσης +HISTORY_MSG_9;Συμπίεση φωτεινών σημείων +HISTORY_NEWSNAPSHOT;Îέο στιγμιότυπο +HISTORY_NEWSNAPSHOTAS;Ως... +HISTORY_NEWSSDIALOGLABEL;Όνομα στιγμιοτÏπου: +HISTORY_NEWSSDIALOGTITLE;ΠÏοσθήκη νέου στιγμιοτÏπου +HISTORY_SETTO;ΟÏισμός σε +HISTORY_SNAPSHOT;Στιγμιότυπο +HISTORY_SNAPSHOTS;Στιγμιότυπα +ICMPANEL_FILEDLGFILTERANY;Οποιοδήποτε αÏχείο +ICMPANEL_FILEDLGFILTERICM;ΑÏχεία Ï€Ïοφίλ ICC +ICMPANEL_GAMMABEFOREINPUT;Το Ï€Ïοφίλ αλλάζει την gamma +ICMPANEL_INPUTCAMERA;ΠÏοεπιλογή φωτογÏαφικής μηχανής +ICMPANEL_INPUTCUSTOM;ΠÏοσαÏμοσμένο +ICMPANEL_INPUTDLGLABEL;Επιλέξτε Ï€Ïοφιλ ICC εισόδου... +ICMPANEL_INPUTEMBEDDED;ΧÏήση ενσωματωμένου, αν αυτό είναι δυνατό +ICMPANEL_INPUTPROFILE;ΠÏοφίλ εισαγωγής +ICMPANEL_NOICM;No ICM: sRGB output +ICMPANEL_OUTPUTDLGLABEL;Επιλέξτε Ï€Ïοφιλ ICC εξόδου... +ICMPANEL_OUTPUTPROFILE;ΠÏοφίλ εξόδου +ICMPANEL_SAVEREFERENCE;Αποθήκευση εικόνας ως αναφοÏά για δημιουÏγία Ï€Ïοφίλ. +ICMPANEL_WORKINGPROFILE;ΠαÏόν Ï€Ïοφίλ +IMAGEAREA_DETAILVIEW;ΛεπτομεÏής Ï€Ïοβολή +IPTCPANEL_AUTHOR;ΣυγγÏαφέας +IPTCPANEL_AUTHORHINT;Όνομα του δημιουÏÎ³Î¿Ï Ï„Î¿Ï… αντικειμένου, Ï€.χ. συγγÏαφέας, φωτογÏάφος ή γÏαφίστας (Ανα γÏαμμή). +IPTCPANEL_AUTHORSPOSITION;Θέση δημιουÏÎ³Î¿Ï +IPTCPANEL_AUTHORSPOSITIONHINT;Τίτλος που αποδίδεται από τον/τους δημιουÏγό/γους (Ανα γÏαμμή τίτλος). +IPTCPANEL_CAPTION;Λεζάντα +IPTCPANEL_CAPTIONHINT;Μια λεκτική πεÏιγÏαφή των στοιχείων (Λεζάντα - ΠεÏίληψη). +IPTCPANEL_CAPTIONWRITER;ΣυγγÏαφέας λεζάντας +IPTCPANEL_CAPTIONWRITERHINT;Το όνομα του Ï€Ïοσώπου που ασχολήθηκε με την συγγÏαφή, επεξεÏγασία ή διόÏθωση της εικόνας ή λεζάντας/πεÏίληψης (ΣυγγÏαφέας - Επιμελητής). +IPTCPANEL_CATEGORY;ΚατηγοÏία +IPTCPANEL_CATEGORYHINT;Ταυτοποιεί το θέμα της εικόνας βάση της άποψης του παÏοχέα (ΚατηγοÏία). +IPTCPANEL_CITY;Πόλη +IPTCPANEL_CITYHINT;Πόλη Ï€Ïοέλευσης εικόνας (Πόλη). +IPTCPANEL_COPYHINT;ΑντιγÏαφή Ïυθμίσεων IPTC στην πεÏιοχή αποκομμάτων +IPTCPANEL_COPYRIGHT;Πνευματική ιδιοκτησία +IPTCPANEL_COPYRIGHTHINT;Όποιο απαÏαίτητο σχόλιο πεÏι πνευματικής ιδιοκτησίας (Σχόλια πεÏι πνευματική ιδιοκτησία). +IPTCPANEL_COUNTRY;ΧώÏα +IPTCPANEL_COUNTRYHINT;ΧώÏα/αÏχική τοποθεσία δημιουÏγίας εικόνας (ΧώÏα/αÏχική τοποθεσία). +IPTCPANEL_CREDIT;ΕÏσημα +IPTCPANEL_CREDITHINT;Ταυτοποιεί τον παÏοχέα της εικόνας, όχι απÏαίτητα δημιουÏγό/ιδιοκτήτη (ΕÏσημα). +IPTCPANEL_DATECREATED;ΗμεÏομηνία δημιουÏγίας +IPTCPANEL_DATECREATEDHINT;Η ημεÏομηνία δημιουÏγίας του Ï€Î½ÎµÏ…Î¼Î±Ï„Î¹ÎºÎ¿Ï Ï€ÎµÏιεχομένου; ΤÏπος: JJJJMMTT (ΗμεÏομηνία δημιουÏγίας). +IPTCPANEL_EMBEDDED;Ενσωματωμένο +IPTCPANEL_EMBEDDEDHINT;ΕπαναφοÏά στοιχείων IPTC αÏχείου εικόνας +IPTCPANEL_HEADLINE;Επικεφαλίδα +IPTCPANEL_HEADLINEHINT;Ένας δημοσιεÏσιμος τίτλος που παÏέχει μια σÏνοψη των πεÏιεχομένων της εικόνας (Επικεφαλίδα). +IPTCPANEL_INSTRUCTIONS;Οδηγίες +IPTCPANEL_INSTRUCTIONSHINT;Άλλες οδηγίες επιμέλειας που αφοÏοÏν την χÏήση της εικόνας (Ειδικίες οδηγίες). +IPTCPANEL_KEYWORDS;Λέξεις-κλειδιά +IPTCPANEL_KEYWORDSHINT;ΧÏησιμοποιοÏνται ενδεικτικά ως λέξεις ανάκτησης(Λέξεις-κλειδιά). +IPTCPANEL_PASTEHINT;Επικόλληση Ïυθμίσεων IPTC από την πεÏιοχή αποκομμάτων +IPTCPANEL_PROVINCE;ΕπαÏχία +IPTCPANEL_PROVINCEHINT;ΕπαÏχία/Πολιτεία/Îομός Ï€Ïοέλευσης της εικόνας (ΕπαÏχία/Πολιτεία/Îομός). +IPTCPANEL_RESET;ΕπαναφοÏά +IPTCPANEL_RESETHINT;ΕπαναφοÏά Ï€Ïοεπιλεγμένου Ï€Ïοφίλ +IPTCPANEL_SOURCE;Πηγή +IPTCPANEL_SOURCEHINT;Αυθεντικός ιδιοκτήτης Ï€Î½ÎµÏ…Î¼Î±Ï„Î¹ÎºÎ¿Ï Ï€ÎµÏιεχομένου της εικόνας (Πηγή). +IPTCPANEL_SUPPCATEGORIES;ΣυμπληÏ. ΚατηγοÏίες +IPTCPANEL_SUPPCATEGORIESHINT;ΠÏοσδιοÏίζουν επιπλέον το θέμα της εικόνας (ΣυμπληÏωματικές κατηγοÏίες). +IPTCPANEL_TITLE;Τίτλος +IPTCPANEL_TITLEHINT;Μια σÏντομη αναφοÏά για την εικόνα (Όνομα αντικειμένου). +IPTCPANEL_TRANSREFERENCE;Κωδικός αυθεντικής μετάδοσης +IPTCPANEL_TRANSREFERENCEHINT;Ένας κωδικός που αντιπÏοσωπέυει την τοποθεσία αυθεντικής μετάδοσης (Κωδικός Αυθεντικής Μετάδοσης). +MAIN_BUTTON_PREFERENCES;Ρυθμίσεις +MAIN_BUTTON_SAVE;Αποθήκευση εικόνας +MAIN_BUTTON_SAVEAS;Ως... +MAIN_BUTTON_SENDTOEDITOR;Send to editor +MAIN_MSG_ALREADYEXISTS;Το αÏχείο ήδη υπάÏχει. +MAIN_MSG_CANNOTLOAD;ΑδÏνατη η φόÏτωση εικόνας +MAIN_MSG_CANNOTSAVE;ΑδÏνατη η αποθήκευση αÏχείου +MAIN_MSG_CANNOTSTARTEDITOR;Can not start editor. +MAIN_MSG_CANNOTSTARTEDITOR_SECONDARY;Please set the correct path in the "Preferences" dialog. +MAIN_MSG_EXITJOBSINQUEUEINFO;Unprocessed images in the queue will be lost on exit. +MAIN_MSG_EXITJOBSINQUEUEQUEST;Are you sure you want to exit? There are unprocessed images waiting in the queue. +MAIN_MSG_JOBSINQUEUE;εÏγασία(ες) μέσα στην λίστα αναμονής +MAIN_MSG_QOVERWRITE;Θέλετε να το αντικαταστήσετε; +MAIN_TAB_BASIC;Βασικό +MAIN_TAB_COLOR;Color +MAIN_TAB_DETAIL;Detail +MAIN_TAB_EXIF;Exif +MAIN_TAB_EXPOSURE;Exposure +MAIN_TAB_ICM;ICM +MAIN_TAB_IPTC;IPTC +MAIN_TAB_METADATA;Metadata +MAIN_TAB_TRANSFORM;ΜετατÏοπή +MAIN_TOOLTIP_HIDEFP;ΠÏοβολή/απόκÏυψη του κάτω πλαισίου (τοποθεσίες και πεÏιηγητής αÏχείων, shortcut key: F) +MAIN_TOOLTIP_HIDEHP;ΠÏοβολή/απόκÏυψη αÏιστεÏÎ¿Ï Ï€Î»Î±Î¹ÏƒÎ¯Î¿Ï… (πεÏιλαμβανομένου του ιστοÏικοÏ, shortcut key: H) +MAIN_TOOLTIP_INDCLIPPEDH;Ένδειξη ÏˆÎ±Î»Î¹ÏƒÎ¼Î¿Ï Ï†Ï‰Ï„ÎµÎ¹Î½ÏŽÎ½ σημείων +MAIN_TOOLTIP_INDCLIPPEDS;Ένδειξη ÏˆÎ±Î»Î¹ÏƒÎ¼Î¿Ï ÏƒÎºÎ¹ÏŽÎ½ +MAIN_TOOLTIP_PREFERENCES;ΟÏισμός Ïυθμίσεων +MAIN_TOOLTIP_QINFO;ΓÏήγοÏες πληÏοφοÏίες στην εικόνα +MAIN_TOOLTIP_SAVE;Αποθήκευση εικόνας στον Ï€ÏοκαθοÏισμένο φάκελο +MAIN_TOOLTIP_SAVEAS;Αποθήκευση εικόνας σε ένα επιλεγμένο φάκελο +PARTIALPASTE_BASICGROUP;Basic settings +PARTIALPASTE_CACORRECTION;C/A correction +PARTIALPASTE_COARSETRANS;90 deg rotation / flipping +PARTIALPASTE_COLORBOOST;Color boost +PARTIALPASTE_COLORDENOISE;Color denoise +PARTIALPASTE_COLORGROUP;Color related settings +PARTIALPASTE_COLORMIXER;Color mixer +PARTIALPASTE_COLORSHIFT;Color shift +PARTIALPASTE_COMPOSITIONGROUP;Composition settings +PARTIALPASTE_CROP;Crop +PARTIALPASTE_DIALOGLABEL;Partial paste processing profile +PARTIALPASTE_DISTORTION;Distortion correction +PARTIALPASTE_EXIFCHANGES;Changes to exif data +PARTIALPASTE_EXPOSURE;Exposure +PARTIALPASTE_HLRECOVERY;Highlight recovery +PARTIALPASTE_ICMSETTINGS;ICM settings +PARTIALPASTE_IPTCINFO;IPTC info +PARTIALPASTE_LENSGROUP;Lens related settings +PARTIALPASTE_LUMACURVE;Luminance curve +PARTIALPASTE_LUMADENOISE;Luminance noise reduction +PARTIALPASTE_LUMINANCEGROUP;Luminance related settings +PARTIALPASTE_METAICMGROUP;Metadata/ICM settings +PARTIALPASTE_RESIZE;Resize +PARTIALPASTE_ROTATION;Rotation +PARTIALPASTE_SHADOWSHIGHLIGHTS;Shadows/Highlights +PARTIALPASTE_SHARPENING;Sharpening +PARTIALPASTE_VIGNETTING;Vignetting correction +PARTIALPASTE_WHITEBALANCE;White balance +PREFERENCES_APPLNEXTSTARTUP;εφαÏμόζεται στην επόμενη εκκίνηση +PREFERENCES_BLINKCLIPPED;Οι πεÏιοχές ψαλιδίσματος να αναβοσβήνουν +PREFERENCES_CACHECLEARALL;Clear All +PREFERENCES_CACHECLEARPROFILES;Clear Profiles +PREFERENCES_CACHECLEARTHUMBS;Clear Thumbnails +PREFERENCES_CACHEFORMAT1;Proprietary (faster and better quality) +PREFERENCES_CACHEFORMAT2;JPEG (smaller disk footprint) +PREFERENCES_CACHEMAXENTRIES;Maximal Number of Cache Entries +PREFERENCES_CACHEOPTS;Cache Options +PREFERENCES_CACHESTRAT1;Prefer Speed to Low Memory Consumption +PREFERENCES_CACHESTRAT2;Prefer Low Memory Consumption to Speed +PREFERENCES_CACHESTRAT;Cache Strategy +PREFERENCES_CACHETHUMBFORM;Cache Thumbnail Format +PREFERENCES_CACHETHUMBHEIGHT;Maximal Thumbnail Height +PREFERENCES_CLEARDLG_LINE1;Clearing cache +PREFERENCES_CLEARDLG_LINE2;This may take a few seconds. +PREFERENCES_CLEARDLG_TITLE;Please wait +PREFERENCES_CLIPPINGIND;Ένδειξη ψαλιδίσματος +PREFERENCES_CMETRICINTENT;Colorimetric Intent +PREFERENCES_DATEFORMAT;Διάταξη ημεÏομηνίας +PREFERENCES_DATEFORMATHINT;YΜποÏείτε να χÏησιμοποιήσετε τις εξής εντολές μοÏφοποίησης:\n%y : χÏονολογία\n%m : μήνας\n%d : ημέÏα\n\nΓια παÏάδειγμα, η μοÏφοποίηση ημεÏομηνίας στην Ελλάδα είναι:\n%y/%m/%d +PREFERENCES_DEFAULTLANG;ΠÏοεπιλεγμένη γλώσσα +PREFERENCES_DEFAULTTHEME;ΠÏοεπιλεγμένο θέμα +PREFERENCES_DEMOSAICINGALGO;ΑλγόÏιθμος απομωσαϊκοποίησης +PREFERENCES_DIRHOME;Τοποθεσία "Home" +PREFERENCES_DIRLAST;Τελευταία τοποθεσία που χÏησιμοποιήθηκε +PREFERENCES_DIROTHER;Άλλο +PREFERENCES_DIRSELECTDLG;Επιλέξτε τοποθεσία εικόνων κατά την έναÏξη... +PREFERENCES_DIRSOFTWARE;Τοποθεσία εγκατάστασης +PREFERENCES_DMETHOD;Μέθοδος +PREFERENCES_EDITORCMDLINE;Other command line +PREFERENCES_EXTERNALEDITOR;External editor +PREFERENCES_FALSECOLOR;Βήματα καταστολής σφαλμένων χÏωμάτων +PREFERENCES_FBROWSEROPTS;Επιλογές πεÏιήγησης αÏχείων +PREFERENCES_FILEFORMAT;Είδος αÏχείου +PREFERENCES_FORIMAGE;Για αÏχεία εικόνων +PREFERENCES_FORRAW;Για αÏχεία RAW +PREFERENCES_GIMPPATH;GIMP installation directory +PREFERENCES_GTKTHEME;ΠÏοεπιλεγμένη GTK +PREFERENCES_HINT;ÎÏξη +PREFERENCES_HLTHRESHOLD;Κατώφλι ψαλιδίσματος φωτεινών σημείων +PREFERENCES_ICCDIR;Τοποθεσία των Ï€Ïοφίλ ICC +PREFERENCES_IMPROCPARAMS;ΠÏοεπιλεγμένες παÏαμέτÏοι επεξεÏγασίας εικόνας +PREFERENCES_INTENT_ABSOLUTE;Absolute Colorimetric +PREFERENCES_INTENT_PERCEPTUAL;Perceptual +PREFERENCES_INTENT_RELATIVE;Relative Colorimetric +PREFERENCES_INTENT_SATURATION;Saturation +PREFERENCES_LIVETHUMBNAILS;Live Thumbnails (slower) +PREFERENCES_MONITORICC;ΠÏοφίλ οθόνης +PREFERENCES_OUTDIR;Τοποθεσία εξόδου +PREFERENCES_OUTDIRFOLDER;Save to folder +PREFERENCES_OUTDIRFOLDERHINT;Put the saved images to the seledted folder +PREFERENCES_OUTDIRHINT;ΜποÏείτε να χÏησιμοποιήσετε τις ακόλουθες σειÏές μοÏφοποίησης:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nΑυτές οι σειÏές μοÏφοποίησης αναφέÏονται στις τοποθεσίες και τις υπο-διαδÏομές της τοποθεσίας του αÏχείου raw.\n\nΓια παÏάδειγμα, αν το /home/tom/image/02-09-2006/dsc0012.nef ανοιχθεί, η σημασία των ακόλουθων σειÏών μοÏφοποίησης είναι:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nΑν θέλεθτε να αποδηκεÏσετε την εικόνα εξόδου μαζί με το Ï€Ïωτότυπο, γÏάψτε:\n%p1/%f\n\nΑν θέλετε να αποθηκεÏσετε την εικόνα εξόδου σε ένα φάκελο 'converted', μέσα στην τοποθεσία που βÏίσκεται το Ï€Ïωτότυπο, γÏάψτε:\n%p1/converted/%f\n\nΑν θέλετε να αποθηκεÏσετε την εικόνα εξόδου σε στην τοποθεσία '/home/tom/converted' κÏατώντας όμως την ίδια δομή υπο-τοποθεσιών ημεÏομηνίων, γÏάψτε:\n%p2/converted/%d1/%f +PREFERENCES_OUTDIRTEMPLATE;Use Template +PREFERENCES_OUTDIRTEMPLATEHINT;You can use the following formatting strings:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nThese formatting strings refer to the directories and sub-paths of the path of the raw file.\n\nFor example, if /home/tom/image/02-09-2006/dsc0012.nefhas been opened, the meaning of the formatting strings are:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nIf you want to save the output image where the original is, write:\n%p1/%f\n\nIf you want to save the output image in a directory 'converted' located the directory of the original, write:\n%p1/converted/%f\n\nIf you want to save the output image in directory '/home/tom/converted' with keeping the same subdirectory of dates, write:\n%p2/converted/%d1/%f +PREFERENCES_PARSEDEXT;Parsed Extensions +PREFERENCES_PARSEDEXTADD;Add Extension +PREFERENCES_PARSEDEXTADDHINT;Type an extension and press this button to append list +PREFERENCES_PARSEDEXTDELHINT;Delete selected extension from the list +PREFERENCES_PROFILEHANDLING;Processing Profile Handling +PREFERENCES_PROFILELOADPR;Profile Loading Priority +PREFERENCES_PROFILEPRCACHE;Profile in Cache +PREFERENCES_PROFILEPRFILE;Profile Next to the Input File +PREFERENCES_PROFILESAVECACHE;Save Processing Parameters to the Cache +PREFERENCES_PROFILESAVEINPUT;Save Processing Parameters Next to the Input File +PREFERENCES_PSPATH;Adobe Photoshop installation directory +PREFERENCES_SELECTICCDIRDLG;Επιλογή τοποθεσίας Ï€Ïοφίλ ICC... +PREFERENCES_SELECTLANG;Επιλογή γλώσσας +PREFERENCES_SELECTMONITORPROFDLG;Επιλογή Ï€Ïοφίλ ICC της οθόνης... +PREFERENCES_SELECTTHEME;Επιλογή θέματος +PREFERENCES_SHOWBASICEXIF;ΠÏοβολή βασικών στοιχείων Exif +PREFERENCES_SHOWDATETIME;ΠÏοβολή ημεÏομηνίας και ÏŽÏας +PREFERENCES_SHOWONLYRAW;ΠÏοβολή μόνο αÏχείων RAW +PREFERENCES_SHTHRESHOLD;Κατώφλι ψαλιδίσματος σκιών +PREFERENCES_STARTUPIMDIR;Τοποθεσία εικόνων κατά την έναÏξη +PREFERENCES_TAB_BROWSER;ΠεÏιήγηση αÏχείου +PREFERENCES_TAB_COLORMGR;ΔιαχείÏιση χÏώματος +PREFERENCES_TAB_GENERAL;Γενικά +PREFERENCES_TAB_IMPROC;ΕπεξεÏγασίας εικόνας +PREFERENCES_TAB_OUTPUT;Επιλογές παÏαγωγής +PREFERENCES_THUMBSIZE;Μέγεθος εικονιδίου +PROFILEPANEL_FILEDLGFILTERANY;Οποιοφήποτε αÏχείο +PROFILEPANEL_FILEDLGFILTERPP;ΠÏοφίλ επεξεÏγασίας +PROFILEPANEL_LABEL;ΠÏοφίλ επεξεÏγασίας +PROFILEPANEL_LOADDLGLABEL;ΦόÏτωση παÏαμέτÏων επεξεÏγασίας... +PROFILEPANEL_PCUSTOM;ΠÏοσαÏμοσμένο +PROFILEPANEL_PFILE;Απο αÏχείο +PROFILEPANEL_PLASTPHOTO;Τελευταία φωτογÏαφία +PROFILEPANEL_PLASTSAVED;Τελευταία αποθηκευμένη +PROFILEPANEL_PROFILE;ΠÏοφίλ +PROFILEPANEL_SAVEDLGLABEL;Αποθήκευση παÏαμέτÏων επεξεÏγασίας... +PROFILEPANEL_TOOLTIPCOPY;Copy current profile to clipboard +PROFILEPANEL_TOOLTIPLOAD;ΦόÏτωση Ï€Ïοφίλ απο αÏχείο +PROFILEPANEL_TOOLTIPPASTE; Paste profile from clipboard +PROFILEPANEL_TOOLTIPSAVE;Αποθήκευση παÏόντος Ï€Ïοφίλ +PROGRESSBAR_DECODING;Αποκωδικοποίηση εικόνας... +PROGRESSBAR_DEMOSAICING;Demosaicing... +PROGRESSBAR_LOADING;ΦόÏτωση εικόνας... +PROGRESSBAR_LOADJPEG;ΦόÏτωση αÏχείου JPEG... +PROGRESSBAR_LOADPNG;ΦόÏτωση αÏχείου PNG... +PROGRESSBAR_LOADTIFF;ΦόÏτωση αÏχείου TIFF... +PROGRESSBAR_PROCESSING;ΕπεξεÏγάζεται εικόνα... +PROGRESSBAR_READY;Έτοιμο. +PROGRESSBAR_SAVEJPEG;Αποθήκευση αÏχείου JPEG... +PROGRESSBAR_SAVEPNG;Αποθήκευση αÏχείου PNG... +PROGRESSBAR_SAVETIFF;Αποθήκευση αÏχείου TIFF... +PROGRESSDLG_LOADING;Loading file... +PROGRESSDLG_PROCESSING;Processing image... +PROGRESSDLG_SAVING;Saving file... +QINFO_FOCALLENGTH;Εστιακή απόσταση +QINFO_ISO;ISO +QINFO_LENS;Lens +QINFO_NOEXIF;Στοιχεία Exif μη διαθέσιμα. +SAVEDLG_FILEFORMAT;Είδος αÏχείου +SAVEDLG_JPEGQUAL;Ποιότητα JPEG +SAVEDLG_JPGFILTER;ΑÏχεία JPEG +SAVEDLG_PNGCOMPR;Συμπίεση PNG +SAVEDLG_PNGFILTER;ΑÏχεία PNG +SAVEDLG_PUTTOQUEUE;Put into processing queue +SAVEDLG_PUTTOQUEUEHEAD;Put to the head of the processing queue +SAVEDLG_PUTTOQUEUETAIL;Put to the end of the processing queue +SAVEDLG_SAVEIMMEDIATELY;Save immediately +SAVEDLG_SAVESPP;Αποθήκευση παÏαμέτÏων επεξεÏγασίας μαζί με την εικόνα +SAVEDLG_TIFFFILTER;ΑÏχεία TIFF +TOOLBAR_TOOLTIP_CROP;Αποκοπή επιλογής (shortcut key: C) +TOOLBAR_TOOLTIP_HAND;ΕÏγαλείο μετακίνησης (shortcut key: N) +TOOLBAR_TOOLTIP_STRAIGHTEN;Επιλογή ευθείας γÏαμμής (shortcut key: S) +TOOLBAR_TOOLTIP_WB;ΕξισοÏÏοπία Î»ÎµÏ…ÎºÎ¿Ï Î±Ï€ÏŒ σημείο (shortcut key: W) +TP_CACORRECTION_BLUE;Μπλέ +TP_CACORRECTION_LABEL;C/A ΔιόÏθωση +TP_CACORRECTION_RED;Κόκκινο +TP_CHMIXER_BLUE;Μπλέ +TP_CHMIXER_GREEN;ΠÏάσινο +TP_CHMIXER_LABEL;Μίξη καναλιών +TP_CHMIXER_RED;Κόκκινο +TP_COARSETRAF_DEGREE;γωνία: +TP_COARSETRAF_TOOLTIP_HFLIP;ΑναστÏοφή οÏιζόντια +TP_COARSETRAF_TOOLTIP_ROTLEFT;ΠεÏιστÏοφή αÏιστεÏά +TP_COARSETRAF_TOOLTIP_ROTRIGHT;ΠεÏιστÏοφή δεξιά +TP_COARSETRAF_TOOLTIP_VFLIP;ΑναστÏοφή κατακόÏυφα +TP_COLORBOOST_ACHANNEL;κανάλι "a" +TP_COLORBOOST_AMOUNT;Ένταση +TP_COLORBOOST_AVOIDCOLORCLIP;Αποφυγή ψαλιδίσματος χÏώματος +TP_COLORBOOST_BCHANNEL;κανάλι "b" +TP_COLORBOOST_CHAB;a & b +TP_COLORBOOST_CHANNEL;Κανάλι +TP_COLORBOOST_CHSEPARATE;ξεχωÏιστά +TP_COLORBOOST_ENABLESATLIMITER;ΕνεÏγοποίηση πεÏιοÏÎ¹ÏƒÎ¼Î¿Ï ÎºÎ¿ÏÎµÏƒÎ¼Î¿Ï +TP_COLORBOOST_LABEL;Ενίσχυση χÏώματος +TP_COLORBOOST_SATLIMIT;ΠεÏιοÏισμός κοÏÎµÏƒÎ¼Î¿Ï +TP_COLORDENOISE_EDGESENSITIVE;Ευαισθησία οÏίων +TP_COLORDENOISE_EDGETOLERANCE;Ανοχή οÏίων +TP_COLORDENOISE_LABEL;Μείωση χÏÏ‰Î¼Î±Ï„Î¹ÎºÎ¿Ï Î¸Î¿ÏÏβου +TP_COLORDENOISE_RADIUS;Ακτίνα +TP_COLORSHIFT_BLUEYELLOW;Μπλέ-ΚίτÏινο +TP_COLORSHIFT_GREENMAGENTA;ΠÏάσινο-Magenta +TP_COLORSHIFT_LABEL;Μετατόπιση χÏώματος +TP_CROP_DPI;DPI= +TP_CROP_FIXRATIO;Κλείδωμα αναλογίας: +TP_CROP_GTDIAGONALS;Κανόνας διαγωνίων +TP_CROP_GTHARMMEANS1;Harmonic means 1 +TP_CROP_GTHARMMEANS2;Harmonic means 2 +TP_CROP_GTHARMMEANS3;Harmonic means 3 +TP_CROP_GTHARMMEANS4;Harmonic means 4 +TP_CROP_GTNONE;Κανένα +TP_CROP_GTRULETHIRDS;Κανόνας Ï„Ïίτων +TP_CROP_GUIDETYPE;Είδος βοηθών: +TP_CROP_H;H +TP_CROP_LABEL;Αποκοπή +TP_CROP_SELECTCROP; Επιλογή αποκοπής +TP_CROP_W;W +TP_CROP_X;x +TP_CROP_Y;y +TP_DISTORTION_AMOUNT;Ένταση +TP_DISTORTION_LABEL;ΠαÏαμόÏφωση +TP_EXPOSURE_AUTOLEVELS;Αυτόματα επίπεδα +TP_EXPOSURE_BLACKLEVEL;ΜαÏÏα +TP_EXPOSURE_BRIGHTNESS;Φωτεινότητα +TP_EXPOSURE_CLIP;Αποκοπή +TP_EXPOSURE_COMPRHIGHLIGHTS;Συμπίεση φωτεινών σημείων +TP_EXPOSURE_COMPRSHADOWS;Συμπίεση σκιών +TP_EXPOSURE_CONTRAST;Αντίθεση +TP_EXPOSURE_CURVEEDITOR;ΚαμπÏλη τονικότητας +TP_EXPOSURE_EXPCOMP;ΕπανόÏθωση Έκθεσης +TP_EXPOSURE_LABEL;Έκθεση +TP_HLREC_CIELAB;Ανάμιξη CIELab +TP_HLREC_COLOR;Διάδοση χÏώματος +TP_HLREC_LABEL;Ανάκτηση φωτεινών σημείων +TP_HLREC_LUMINANCE;Ανάκτηση Φωτεινότητας +TP_HLREC_METHOD;Μέθοδος: +TP_ICM_FILEDLGFILTERANY;Οποιοδήποτε αÏχείο +TP_ICM_FILEDLGFILTERICM;ΑÏχεία Ï€Ïοφίλ ICC +TP_ICM_GAMMABEFOREINPUT;Το Ï€Ïοφίλ αλλάζει την gamma +TP_ICM_INPUTCAMERA;ΠÏοεπιλογή φωτογÏαφικής μηχανής +TP_ICM_INPUTCUSTOM;ΠÏοσαÏμοσμένο +TP_ICM_INPUTDLGLABEL;Επιλέξτε Ï€Ïοφιλ ICC εισόδου... +TP_ICM_INPUTEMBEDDED;ΧÏήση ενσωματωμένου, αν αυτό είναι δυνατό +TP_ICM_INPUTPROFILE;ΠÏοφίλ εισαγωγής +TP_ICM_LABEL;ICM +TP_ICM_NOICM;No ICM: sRGB output +TP_ICM_OUTPUTDLGLABEL;Επιλέξτε Ï€Ïοφιλ ICC εξόδου... +TP_ICM_OUTPUTPROFILE;ΠÏοφίλ εξόδου +TP_ICM_SAVEREFERENCE;Αποθήκευση εικόνας ως αναφοÏά για δημιουÏγία Ï€Ïοφίλ. +TP_ICM_WORKINGPROFILE;ΠαÏόν Ï€Ïοφίλ +TP_LUMACURVE_BLACKLEVEL;ΜαÏÏα +TP_LUMACURVE_BRIGHTNESS;Φωτεινότητα +TP_LUMACURVE_COMPRHIGHLIGHTS;Συμπίεση φωτεινών σημείων +TP_LUMACURVE_COMPRSHADOWS;Συμπίεση σκιών +TP_LUMACURVE_CONTRAST;Αντίθεση +TP_LUMACURVE_CURVEEDITOR;ΚαμπÏλη φωτεινότητας +TP_LUMACURVE_LABEL;ΚαμπÏλη φωτεινότητας +TP_LUMADENOISE_EDGETOLERANCE;Ανοχή οÏίων +TP_LUMADENOISE_LABEL;Μείωση θοÏÏβου φωτεινότητας +TP_LUMADENOISE_RADIUS;Ακτίνα +TP_RESIZE_BICUBIC;Bicubic +TP_RESIZE_BICUBICSF;Bicubic (Softer) +TP_RESIZE_BICUBICSH;Bicubic (Sharper) +TP_RESIZE_BILINEAR;Bilinear +TP_RESIZE_FULLSIZE;ΠλήÏες μέγεθος εικόνας: +TP_RESIZE_H;H: +TP_RESIZE_LABEL;Αλλαγή μεγέθους +TP_RESIZE_METHOD;Μέθοδος: +TP_RESIZE_NEAREST;Nearest +TP_RESIZE_SCALE;Κλίμακα +TP_RESIZE_W;W: +TP_ROTATE_AUTOCROP;Αυτόματη αποκοπή +TP_ROTATE_DEGREE;Γωνία +TP_ROTATE_FILL;Γέμισμα εικόνας +TP_ROTATE_LABEL;ΠεÏιστÏοφή +TP_ROTATE_SELECTLINE; Επιλογή ευθείας +TP_SHADOWSHLIGHTS_HIGHLIGHTS;Φωτεινά σημεία +TP_SHADOWSHLIGHTS_HLTONALW;Τονικό εÏÏος +TP_SHADOWSHLIGHTS_LABEL;Σκιές/Φωτεινά σημεία +TP_SHADOWSHLIGHTS_LOCALCONTR;Τοπική αντίθεση +TP_SHADOWSHLIGHTS_RADIUS;Ακτίνα +TP_SHADOWSHLIGHTS_SHADOWS;Σκιές +TP_SHADOWSHLIGHTS_SHTONALW;Τονικό εÏÏος +TP_SHARPENING_AMOUNT;Ένταση +TP_SHARPENING_EDRADIUS;Ακτίνα +TP_SHARPENING_EDTOLERANCE;Ανοχή οÏίων +TP_SHARPENING_HALOCONTROL;Έλεγχος άλως +TP_SHARPENING_HCAMOUNT;Ένταση +TP_SHARPENING_LABEL;Όξυνση +TP_SHARPENING_METHOD;Μέθοδος +TP_SHARPENING_ONLYEDGES;Όξυνση μόνο οÏίων +TP_SHARPENING_RADIUS;Ακτίνα +TP_SHARPENING_RLD;RL Deconvolution +TP_SHARPENING_RLD_AMOUNT;Ένταση +TP_SHARPENING_RLD_DAMPING;Απόσβεση +TP_SHARPENING_RLD_ITERATIONS;Επαναλήψεις +TP_SHARPENING_THRESHOLD;Κατώφλι +TP_SHARPENING_USM;Unsharp Mask +TP_VIGNETTING_AMOUNT;Ένταση +TP_VIGNETTING_LABEL;ΔιόÏθωση vignetting +TP_VIGNETTING_RADIUS;Ακτίνα +TP_WBALANCE_AUTO;Αυτόματο +TP_WBALANCE_CAMERA;ΦωτογÏαφικής μηχανής +TP_WBALANCE_CUSTOM;ΠÏοσαÏμοσμένο +TP_WBALANCE_GREEN;ΑπόχÏωση +TP_WBALANCE_LABEL;ΕξισοÏÏόπηση Î»ÎµÏ…ÎºÎ¿Ï +TP_WBALANCE_METHOD;Μέθοδος +TP_WBALANCE_SIZE;Μέγεθος: +TP_WBALANCE_SPOTWB;Εξ.Λ. σημείου +TP_WBALANCE_TEMPERATURE;ΘεÏμοκÏασία +ZOOMBAR_DETAIL;ΛεπτομέÏεια +ZOOMBAR_HUGE;ΤεÏάστιο +ZOOMBAR_LARGE;Μεγάλο +ZOOMBAR_NORMAL;Κανονικό +ZOOMBAR_PREVIEW;ΠÏοεπισκόπηση +ZOOMBAR_SCALE;Κλίμακα +ZOOMBAR_SMALL;ΜικÏÏŒ diff --git a/release/languages/hebrew b/release/languages/hebrew new file mode 100755 index 000000000..2c667213a --- /dev/null +++ b/release/languages/hebrew @@ -0,0 +1,577 @@ +# Hebrew +# 21.02.2008: initially translated by ??? +# ---------------------------------------------- +ADJUSTER_RESET_TO_DEFAULT;ברירת מחדל +CURVEEDITOR_FILEDLGFILTERANY;×§×‘×¦×™× ×›×œ×©×”× +CURVEEDITOR_FILEDLGFILTERCURVE;קבצי עקמות +CURVEEDITOR_LINEAR;ישיר +CURVEEDITOR_LOADDLGLABEL;הטען עקמה +CURVEEDITOR_SAVEDLGLABEL;שמור עקמה +CURVEEDITOR_TOOLTIPLINEAR;החזר עקמה לישירה +CURVEEDITOR_TOOLTIPLOAD;הטען עקמה +CURVEEDITOR_TOOLTIPSAVE;שמור עקמה נוכחית +EXIFFILTER_APERTURE;Aperture +EXIFFILTER_CAMERA;Camera +EXIFFILTER_DIALOGLABEL;Exif Filter +EXIFFILTER_FOCALLEN;Focal Length +EXIFFILTER_ISO;ISO +EXIFFILTER_LENS;Lens +EXIFFILTER_SHUTTER;Shutter +EXIFPANEL_ADDEDIT;Add/Edit +EXIFPANEL_ADDEDITHINT;Add new tag or edit tag +EXIFPANEL_ADDTAGDLG_ENTERVALUE;Enter value +EXIFPANEL_ADDTAGDLG_SELECTTAG;Select tag +EXIFPANEL_ADDTAGDLG_TITLE;Add/Edit Tag +EXIFPANEL_KEEP;Keep +EXIFPANEL_KEEPHINT;Keep the selected tags when writing output file +EXIFPANEL_REMOVE;Remove +EXIFPANEL_REMOVEHINT;Remove the selected tags when writing output file +EXIFPANEL_RESET;Reset +EXIFPANEL_RESETALL;Reset All +EXIFPANEL_RESETALLHINT;Reset all tags to their original values +EXIFPANEL_RESETHINT;Reset the selected tags to their original values +EXIFPANEL_SUBDIRECTORY;Subdirectory +FILEBROWSER_APPLYPROFILE;Apply profile +FILEBROWSER_ARRANGEMENTHINT;Change between vertical/horizontal alignment of thumbnails +FILEBROWSER_CLEARPROFILE;Clear profile +FILEBROWSER_COPYPROFILE;Copy profile +FILEBROWSER_DELETEDLGLABEL;File delete confirmation +FILEBROWSER_DELETEDLGMSG;Are you sure you want to delete the selected %1 files? +FILEBROWSER_EMPTYTRASH;Empty Trash +FILEBROWSER_EMPTYTRASHHINT;Permanently delete the files of the trash +FILEBROWSER_EXIFFILTERAPPLY;Apply +FILEBROWSER_EXIFFILTERAPPLYHINT;Switch on/off exif filter of the file browser +FILEBROWSER_EXIFFILTERLABEL;Exif Filter +FILEBROWSER_EXIFFILTERSETTINGS;Setup +FILEBROWSER_EXIFFILTERSETTINGSHINT;Change settings of the exif filter +FILEBROWSER_PARTIALPASTEPROFILE;Partial paste +FILEBROWSER_PASTEPROFILE;Paste profile +FILEBROWSER_POPUPCANCELJOB;Cancel job +FILEBROWSER_POPUPMOVEEND;Move to end of queue +FILEBROWSER_POPUPMOVEHEAD;Move to head of queue +FILEBROWSER_POPUPOPEN;Open +FILEBROWSER_POPUPPROCESS;Put to processing queue +FILEBROWSER_POPUPRANK1;Rank 1 +FILEBROWSER_POPUPRANK2;Rank 2 +FILEBROWSER_POPUPRANK3;Rank 3 +FILEBROWSER_POPUPRANK4;Rank 4 +FILEBROWSER_POPUPRANK5;Rank 5 +FILEBROWSER_POPUPREMOVE;Remove from filesystem +FILEBROWSER_POPUPRENAME;Rename +FILEBROWSER_POPUPSELECTALL;Select all +FILEBROWSER_POPUPTRASH;Move to trash +FILEBROWSER_POPUPUNRANK;Unrank +FILEBROWSER_POPUPUNTRASH;Remove from trash +FILEBROWSER_PROCESSINGSETTINGS;Settings +FILEBROWSER_PROCESSINGSETTINGSHINT;Set the file format and output directory +FILEBROWSER_RENAMEDLGLABEL;Rename file +FILEBROWSER_RENAMEDLGMSG;Rename file "%1" to: +FILEBROWSER_SHOWDIRHINT;Show all images of the directory +FILEBROWSER_SHOWQUEUEHINT;Show content of the processing queue +FILEBROWSER_SHOWRANK1HINT;Show images ranked as 1 star +FILEBROWSER_SHOWRANK2HINT;Show images ranked as 2 star +FILEBROWSER_SHOWRANK3HINT;Show images ranked as 3 star +FILEBROWSER_SHOWRANK4HINT;Show images ranked as 4 star +FILEBROWSER_SHOWRANK5HINT;Show images ranked as 5 star +FILEBROWSER_SHOWTRASHHINT;Show content of the trash +FILEBROWSER_SHOWUNRANKHINT;Show unranked images +FILEBROWSER_STARTPROCESSING;Start Processing +FILEBROWSER_STARTPROCESSINGHINT;Start processing/saving of images in the queue +FILEBROWSER_STOPPROCESSING;Stop processing +FILEBROWSER_STOPPROCESSINGHINT;Stop processing of images +FILEBROWSER_THUMBSIZE;Thumb. size +FILEBROWSER_ZOOMINHINT;Increase thumbnail size +FILEBROWSER_ZOOMOUTHINT;Decrease thumbnail size +GENERAL_ABOUT;×ודות +GENERAL_CANCEL;בטל +GENERAL_DISABLE;בטל +GENERAL_DISABLED;מבוטל +GENERAL_ENABLE;הפעל +GENERAL_ENABLED;מופעל +GENERAL_LANDSCAPE;נוף +GENERAL_LOAD;הטען +GENERAL_NA;×ין +GENERAL_NO;×œ× +GENERAL_OK;שמור +GENERAL_PORTRAIT;דיוקן +GENERAL_SAVE;שמור +GENERAL_YES;כן +HISTOGRAM_LABEL;Histogram +HISTOGRAM_TOOLTIP_B;Show/הסתר ×”×™×¡×˜×•×’×¨× ×›×—×•×œ +HISTOGRAM_TOOLTIP_G;Show/הסתר ×”×™×¡×˜×•×’×¨× ×™×¨×•×§ +HISTOGRAM_TOOLTIP_L;Show/CIELAB הסתר ×”×™×¡×˜×•×’×¨× +HISTOGRAM_TOOLTIP_R;Show/הסתר ×”×™×¡×˜×•×’×¨× ××“×•× +HISTORY_CHANGED;Changed +HISTORY_CUSTOMCURVE;עקמה מות×מת +HISTORY_DELSNAPSHOT;הסר ×ª×¦×œ×•× +HISTORY_FROMCLIPBOARD;From clipboard +HISTORY_LABEL;היסטוריה +HISTORY_MSG_10;דחיסת ×’×•×•× ×™× ×›×”×™× +HISTORY_MSG_11;עקמת ×’×•×•× ×™× +HISTORY_MSG_12;חשיפה ×וטומטית +HISTORY_MSG_13;קיצוץ החסיפה +HISTORY_MSG_14;×”×רה - בהירות +HISTORY_MSG_15;×”×רה - ניגודיות +HISTORY_MSG_16;×”×רה - שחור +HISTORY_MSG_17;×”×רה - דחיסת ×’×•×•× ×™× ×‘×”×™×¨×™× +HISTORY_MSG_18;×”×רה - דחיסת ×’×•×•× ×™× ×›×”×™× +HISTORY_MSG_19;×”×רה - עקמה +HISTORY_MSG_1;×¦×™×œ×•× ×˜×¢×•×Ÿ +HISTORY_MSG_20;חידוד +HISTORY_MSG_21;חידוד - רדיוס +HISTORY_MSG_22;חידוד - כמות +HISTORY_MSG_23;חידוד - סף +HISTORY_MSG_24;חידוד - רק קצוות +HISTORY_MSG_25;חידוד - רדיוס גילוי קצוות +HISTORY_MSG_26;חידוד - סבילות קצוות +HISTORY_MSG_27;חידוד - בקרת הילה +HISTORY_MSG_28;בקרת הילה, כמות +HISTORY_MSG_29;שיטת החידוד +HISTORY_MSG_2;פרופיל טעון +HISTORY_MSG_30;דיקונבולוציה - רדיוס +HISTORY_MSG_31;גיקונבולוציה - כמות +HISTORY_MSG_32;גיקונבולוציה - ריסון +HISTORY_MSG_33;גיקונבולוציה - חזרות +HISTORY_MSG_34;המנע מקיצוץ צבע +HISTORY_MSG_35;הגבלת רויה +HISTORY_MSG_36;גבול רויה +HISTORY_MSG_37;הגברת צבע +HISTORY_MSG_38;שיטת ×יזון לבן +HISTORY_MSG_39;מידת ×—×•× +HISTORY_MSG_3;פרופיל הוחלף +HISTORY_MSG_40;גיוון ×יזון צבע +HISTORY_MSG_41;העברת צבע × +HISTORY_MSG_42;העברת צבע ב +HISTORY_MSG_43;הסרת רעש בהירות +HISTORY_MSG_44;הסרת רעש בהירות רדיוס +HISTORY_MSG_45;הסרת רעש בהירות סבילות קצוות +HISTORY_MSG_46;הסרת רעש צבעוני +HISTORY_MSG_47;הסרת רעש צבעוני רדיוס +HISTORY_MSG_48;הסרת רעש צבעוני סבילות קצוות +HISTORY_MSG_49;הסרת רעש צבעוני רגישות לקצוות +HISTORY_MSG_4;דיפדוף בהיסטוריה +HISTORY_MSG_50;כלי בהירי×\×›×”×™× +HISTORY_MSG_51;הגברת ×’×•×•× ×™× ×‘×”×™×¨×™× +HISTORY_MSG_52;ההגברת ×’×•×•× ×™× ×›×”×™× +HISTORY_MSG_53;בהירי×, רוחב ×’×•×•× ×™× +HISTORY_MSG_54;×›×”×™×, רוחב ×’×•×•× ×™× +HISTORY_MSG_55;ניגודיות מקומית +HISTORY_MSG_56;בהירי×\×›×”×™× ×¨×“×™×•×¡ +HISTORY_MSG_57;סיבוב גס +HISTORY_MSG_58;היפוך ×ופקי +HISTORY_MSG_59;היפוך ×× ×›×™ +HISTORY_MSG_5;בהירות +HISTORY_MSG_60;סיבוב +HISTORY_MSG_61;סיבוב +HISTORY_MSG_62;תיקון עיוות בעדשה +HISTORY_MSG_63;סימניה נבחרה +HISTORY_MSG_64;גזירת ×ª×¦×œ×•× +HISTORY_MSG_65;C/A תיקון עיוות +HISTORY_MSG_66;שחזור ×’×•×•× ×™× ×‘×”×™×¨×™× +HISTORY_MSG_67;שחזור ×’×•×•× ×™× ×‘×”×™×¨×™×, כמות +HISTORY_MSG_68;שחזור ×’×•×•× ×™× ×‘×”×™×¨×™×, שיטה +HISTORY_MSG_69;מרחב צבע עבודה +HISTORY_MSG_6;ניגודיות +HISTORY_MSG_70;מרחב צבע ×™×™×¦×•× +HISTORY_MSG_71;מרחב צבע ×™×™×‘×•× +HISTORY_MSG_72;תיקון פינות כהות +HISTORY_MSG_73;מערבב ×¢×¨×•×¦×™× +HISTORY_MSG_74;מידת שינוי גודל +HISTORY_MSG_75;שיטת שינוי גודל +HISTORY_MSG_76;Exif Metadata +HISTORY_MSG_77;IPTC Metadata +HISTORY_MSG_7;שחור +HISTORY_MSG_8;פיצוי חשיפה +HISTORY_MSG_9;דחיסת ×’×•×•× ×™× ×‘×”×™×¨×™× +HISTORY_NEWSNAPSHOT;×ª×¦×œ×•× ×—×“×© +HISTORY_NEWSNAPSHOTAS;×‘×©× +HISTORY_NEWSSDIALOGLABEL;×©× ×”×ª×¦×œ×•× +HISTORY_NEWSSDIALOGTITLE;הוסף ×ª×¦×œ×•× ×—×“×© +HISTORY_SETTO;העבר ×ל +HISTORY_SNAPSHOT;×ª×¦×œ×•× +HISTORY_SNAPSHOTS;×ª×¦×œ×•×ž×™× +ICMPANEL_FILEDLGFILTERANY;×§×‘×¦×™× ×›×œ×©×”× +ICMPANEL_FILEDLGFILTERICM;ICC קבצי צבע +ICMPANEL_GAMMABEFOREINPUT;Profile applies Gamma +ICMPANEL_INPUTCAMERA;ברירת מחדל המצלמה +ICMPANEL_INPUTCUSTOM;מות×× +ICMPANEL_INPUTDLGLABEL;בחר בפרופיל צבע ×™×™×‘×•× +ICMPANEL_INPUTEMBEDDED;השתמש בפרופיל משובץ,×× ×פשר +ICMPANEL_INPUTPROFILE;פרופיל ×™×™×‘×•× +ICMPANEL_NOICM;sRGB×œ×œ× × ×™×”×•×œ צבע - ×™×™×¦×•× ×‘ +ICMPANEL_OUTPUTDLGLABEL;בחר בפרופיל צבע ×™×™×¦×•× +ICMPANEL_OUTPUTPROFILE;פרופיל ×™×™×¦×•× +ICMPANEL_SAVEREFERENCE;Save reference image for profiling +ICMPANEL_WORKINGPROFILE;פרופיל עבודה +IMAGEAREA_DETAILVIEW;תצוגת ×¤×¨×˜×™× +IPTCPANEL_AUTHOR;Author +IPTCPANEL_AUTHORHINT;Name of the creator of the object, e.g. writer, photographer or graphic artist (By-line). +IPTCPANEL_AUTHORSPOSITION;Author's position +IPTCPANEL_AUTHORSPOSITIONHINT;Title of the creator or creators of the object (By-line Title). +IPTCPANEL_CAPTION;Caption +IPTCPANEL_CAPTIONHINT;A textual description of the data (Caption - Abstract) +IPTCPANEL_CAPTIONWRITER;Caption Writer +IPTCPANEL_CAPTIONWRITERHINT;The name of the person involved in the writing, editing or correcting the image or caption/abstract (Writer - Editor). +IPTCPANEL_CATEGORY;Category +IPTCPANEL_CATEGORYHINT;Identifies the subject of the image in the opinion of the provider (Category). +IPTCPANEL_CITY;City +IPTCPANEL_CITYHINT;City of image origin (City). +IPTCPANEL_COPYHINT;Copy IPTC settings to clipboard +IPTCPANEL_COPYRIGHT;Copyright +IPTCPANEL_COPYRIGHTHINT;Any necessary copyright notice (Copyright Notice). +IPTCPANEL_COUNTRY;Country +IPTCPANEL_COUNTRYHINT;The name of the country/primary location where the image was created (Country - Primary Location Name). +IPTCPANEL_CREDIT;Credit +IPTCPANEL_CREDITHINT;Identifies the provider of the image, not necessarily the owner/creator (Credit). +IPTCPANEL_DATECREATED;Date Created +IPTCPANEL_DATECREATEDHINT;The date the intellectual content of the image was created; Format: JJJJMMTT (Date Created). +IPTCPANEL_EMBEDDED;Embedded +IPTCPANEL_EMBEDDEDHINT;Reset to IPTC data embedded in the image file +IPTCPANEL_HEADLINE;Headline +IPTCPANEL_HEADLINEHINT;A publishable entry providing a synopsis of the contents of the image (Headline). +IPTCPANEL_INSTRUCTIONS;Instructions +IPTCPANEL_INSTRUCTIONSHINT;Other editorial instructions concerning the use of the image (Special Instructions). +IPTCPANEL_KEYWORDS;Keywords +IPTCPANEL_KEYWORDSHINT;Used to indicate specific information retrieval words (Keywords). +IPTCPANEL_PASTEHINT;Paste IPTC settings from clipboard +IPTCPANEL_PROVINCE;Province +IPTCPANEL_PROVINCEHINT;The Province/State where the image originates (Province-State). +IPTCPANEL_RESET;Reset +IPTCPANEL_RESETHINT;Reset to profile default +IPTCPANEL_SOURCE;Source +IPTCPANEL_SOURCEHINT;The original owner of the intellectual content of the image (Source). +IPTCPANEL_SUPPCATEGORIES;Suppl. Categories +IPTCPANEL_SUPPCATEGORIESHINT;Further refines the subject of the image (Supplemental Categories). +IPTCPANEL_TITLE;Title +IPTCPANEL_TITLEHINT;A shorthand reference for the image (Object Name). +IPTCPANEL_TRANSREFERENCE;Trans. Reference +IPTCPANEL_TRANSREFERENCEHINT;A code representing the location of original transmission (Original Transmission Reference). +MAIN_BUTTON_PREFERENCES;העדפויות +MAIN_BUTTON_SAVE;שמור ×¦×™×œ×•× +MAIN_BUTTON_SAVEAS;שמור ×‘×©× +MAIN_BUTTON_SENDTOEDITOR;Send to editor +MAIN_MSG_ALREADYEXISTS;הקובץ כבר ×§×™×™× +MAIN_MSG_CANNOTLOAD;×œ× ×™×›×•×œ להעלות ×ת הקובץ +MAIN_MSG_CANNOTSAVE;טעות בשמירת הקובץ +MAIN_MSG_CANNOTSTARTEDITOR;Can not start editor. +MAIN_MSG_CANNOTSTARTEDITOR_SECONDARY;Please set the correct path in the "Preferences" dialog. +MAIN_MSG_EXITJOBSINQUEUEINFO;Unprocessed images in the queue will be lost on exit. +MAIN_MSG_EXITJOBSINQUEUEQUEST;Are you sure you want to exit? There are unprocessed images waiting in the queue. +MAIN_MSG_JOBSINQUEUE;עבודות בתור +MAIN_MSG_QOVERWRITE;?רצונך לכתוב ×ותו מחדש? +MAIN_TAB_BASIC;יסודות +MAIN_TAB_COLOR;Color +MAIN_TAB_DETAIL;Detail +MAIN_TAB_EXIF;Exif +MAIN_TAB_EXPOSURE;Exposure +MAIN_TAB_ICM;ניהול צבע +MAIN_TAB_IPTC;IPTC +MAIN_TAB_METADATA;Metadata +MAIN_TAB_TRANSFORM;התמרות +MAIN_TOOLTIP_HIDEFP;גלה\הסתר לוח תחתון - דפדפן (shortcut key: F) +MAIN_TOOLTIP_HIDEHP;גלה\הסתר לוח שמ×לי - היסטוריה (shortcut key: F) +MAIN_TOOLTIP_INDCLIPPEDH;סימן ×œ×’×•×•× ×™× ×‘×”×™×¨×™× ×ž×§×•×¦×¦×™× +MAIN_TOOLTIP_INDCLIPPEDS;סימן ×œ×’×•×•× ×™× ×›×”×™× ×ž×§×•×¦×¦×™× +MAIN_TOOLTIP_PREFERENCES;קבע העדפויות +MAIN_TOOLTIP_QINFO;מידע מהיר ×ודות ×”×¦×™×œ×•× +MAIN_TOOLTIP_SAVE;שמור לתיק ברירת המחדל +MAIN_TOOLTIP_SAVEAS;שמור לתיק נבחר +PARTIALPASTE_BASICGROUP;Basic settings +PARTIALPASTE_CACORRECTION;C/A correction +PARTIALPASTE_COARSETRANS;90 deg rotation / flipping +PARTIALPASTE_COLORBOOST;Color boost +PARTIALPASTE_COLORDENOISE;Color denoise +PARTIALPASTE_COLORGROUP;Color related settings +PARTIALPASTE_COLORMIXER;Color mixer +PARTIALPASTE_COLORSHIFT;Color shift +PARTIALPASTE_COMPOSITIONGROUP;Composition settings +PARTIALPASTE_CROP;Crop +PARTIALPASTE_DIALOGLABEL;Partial paste processing profile +PARTIALPASTE_DISTORTION;Distortion correction +PARTIALPASTE_EXIFCHANGES;Changes to exif data +PARTIALPASTE_EXPOSURE;Exposure +PARTIALPASTE_HLRECOVERY;Highlight recovery +PARTIALPASTE_ICMSETTINGS;ICM settings +PARTIALPASTE_IPTCINFO;IPTC info +PARTIALPASTE_LENSGROUP;Lens related settings +PARTIALPASTE_LUMACURVE;Luminance curve +PARTIALPASTE_LUMADENOISE;Luminance noise reduction +PARTIALPASTE_LUMINANCEGROUP;Luminance related settings +PARTIALPASTE_METAICMGROUP;Metadata/ICM settings +PARTIALPASTE_RESIZE;Resize +PARTIALPASTE_ROTATION;Rotation +PARTIALPASTE_SHADOWSHIGHLIGHTS;Shadows/Highlights +PARTIALPASTE_SHARPENING;Sharpening +PARTIALPASTE_VIGNETTING;Vignetting correction +PARTIALPASTE_WHITEBALANCE;White balance +PREFERENCES_APPLNEXTSTARTUP;×™×™×•×©× ×‘×תחול ×”×‘× +PREFERENCES_BLINKCLIPPED;הבהוב ב×זור המקוצץ +PREFERENCES_CACHECLEARALL;Clear All +PREFERENCES_CACHECLEARPROFILES;Clear Profiles +PREFERENCES_CACHECLEARTHUMBS;Clear Thumbnails +PREFERENCES_CACHEFORMAT1;Proprietary (faster and better quality) +PREFERENCES_CACHEFORMAT2;JPEG (smaller disk footprint) +PREFERENCES_CACHEMAXENTRIES;Maximal Number of Cache Entries +PREFERENCES_CACHEOPTS;Cache Options +PREFERENCES_CACHESTRAT1;Prefer Speed to Low Memory Consumption +PREFERENCES_CACHESTRAT2;Prefer Low Memory Consumption to Speed +PREFERENCES_CACHESTRAT;Cache Strategy +PREFERENCES_CACHETHUMBFORM;Cache Thumbnail Format +PREFERENCES_CACHETHUMBHEIGHT;Maximal Thumbnail Height +PREFERENCES_CLEARDLG_LINE1;Clearing cache +PREFERENCES_CLEARDLG_LINE2;This may take a few seconds. +PREFERENCES_CLEARDLG_TITLE;Please wait +PREFERENCES_CLIPPINGIND;סימון קיצוץ +PREFERENCES_CMETRICINTENT;כוונה קולורמטרית +PREFERENCES_DATEFORMAT;צורת ת×ריך +PREFERENCES_DATEFORMATHINT;You can use the following formatting strings:\n%y : year\n%m : month\n%d : day\n\nFor example, the hungarian date format is:\n%y/%m/%d +PREFERENCES_DEFAULTLANG;שפה ברירת המחדל +PREFERENCES_DEFAULTTHEME;Default theme +PREFERENCES_DEMOSAICINGALGO;××œ×’×•×¨×™×ª× ×“×™×ž×•×–××™×§ +PREFERENCES_DIRHOME;תיקיית הבית +PREFERENCES_DIRLAST;תיקיה ×”×חרונה שביקרתי בה +PREFERENCES_DIROTHER;×חר +PREFERENCES_DIRSELECTDLG;בחר תיקיית ×¦×™×œ×•×ž×™× ×œ×תחול +PREFERENCES_DIRSOFTWARE;תיקיית התקנה +PREFERENCES_DMETHOD;שיטה +PREFERENCES_EDITORCMDLINE;Other command line +PREFERENCES_EXTERNALEDITOR;External editor +PREFERENCES_FALSECOLOR;דחיית צבע מסולף +PREFERENCES_FBROWSEROPTS;ברירות דפדפן +PREFERENCES_FILEFORMAT;תצורת קובץ +PREFERENCES_FORIMAGE;עבור קבצי ×¦×™×œ×•× +PREFERENCES_FORRAW;RAW עבור קבצי +PREFERENCES_GIMPPATH;GIMP installation directory +PREFERENCES_GTKTHEME;GTK default +PREFERENCES_HINT;רמז +PREFERENCES_HLTHRESHOLD;סף קיצוץ עליון +PREFERENCES_ICCDIR;ICC תיקיית פרופילי צבע +PREFERENCES_IMPROCPARAMS;נתוני עיבוד ברירת המחדל +PREFERENCES_INTENT_ABSOLUTE;קולורמטרית מוחלטת +PREFERENCES_INTENT_PERCEPTUAL;תפיסתית +PREFERENCES_INTENT_RELATIVE;קולורמטרית יחסית +PREFERENCES_INTENT_SATURATION;רויה +PREFERENCES_LIVETHUMBNAILS;Live Thumbnails (slower) +PREFERENCES_MONITORICC;פרופיל מסך +PREFERENCES_OUTDIR;תיקיית ×™×™×¦×•× +PREFERENCES_OUTDIRFOLDER;Save to folder +PREFERENCES_OUTDIRFOLDERHINT;Put the saved images to the seledted folder +PREFERENCES_OUTDIRHINT;You can use the following formatting strings:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nThese formatting strings refer to the directories and sub-paths of the path of the raw file.\n\nFor example, if /home/tom/image/02-09-2006/dsc0012.nefhas been opened, the meaning of the formatting strings are:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nIf you want to save the output image where the original is, write:\n%p1/%f\n\nIf you want to save the output image in a directory 'converted' located the directory of the original, write:\n%p1/converted/%f\n\nIf you want to save the output image in directory '/home/tom/converted' with keeping the same subdirectory of dates, write:\n%p2/converted/%d1/%f +PREFERENCES_OUTDIRTEMPLATE;Use Template +PREFERENCES_OUTDIRTEMPLATEHINT;You can use the following formatting strings:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nThese formatting strings refer to the directories and sub-paths of the path of the raw file.\n\nFor example, if /home/tom/image/02-09-2006/dsc0012.nefhas been opened, the meaning of the formatting strings are:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nIf you want to save the output image where the original is, write:\n%p1/%f\n\nIf you want to save the output image in a directory 'converted' located the directory of the original, write:\n%p1/converted/%f\n\nIf you want to save the output image in directory '/home/tom/converted' with keeping the same subdirectory of dates, write:\n%p2/converted/%d1/%f +PREFERENCES_PARSEDEXT;Parsed Extensions +PREFERENCES_PARSEDEXTADD;Add Extension +PREFERENCES_PARSEDEXTADDHINT;Type an extension and press this button to append list +PREFERENCES_PARSEDEXTDELHINT;Delete selected extension from the list +PREFERENCES_PROFILEHANDLING;Processing Profile Handling +PREFERENCES_PROFILELOADPR;Profile Loading Priority +PREFERENCES_PROFILEPRCACHE;Profile in Cache +PREFERENCES_PROFILEPRFILE;Profile Next to the Input File +PREFERENCES_PROFILESAVECACHE;Save Processing Parameters to the Cache +PREFERENCES_PROFILESAVEINPUT;Save Processing Parameters Next to the Input File +PREFERENCES_PSPATH;Adobe Photoshop installation directory +PREFERENCES_SELECTICCDIRDLG;ICC בחר תיקיית פרופילי צבע +PREFERENCES_SELECTLANG;בחר שפה +PREFERENCES_SELECTMONITORPROFDLG;של התצוגה ICC בחר פרופיל +PREFERENCES_SELECTTHEME;Select theme +PREFERENCES_SHOWBASICEXIF;Exif הר××” מידע +PREFERENCES_SHOWDATETIME;הר××” ת×ריך ושעה +PREFERENCES_SHOWONLYRAW;RAW הר××” רק קבצי +PREFERENCES_SHTHRESHOLD;סף קיצוץ תחתון +PREFERENCES_STARTUPIMDIR;תיקיית ×¦×™×œ×•×ž×™× ×‘×תחול +PREFERENCES_TAB_BROWSER;דפדפן ×§×‘×¦×™× +PREFERENCES_TAB_COLORMGR;ניהול ×¦×‘×¢×™× +PREFERENCES_TAB_GENERAL;כללי +PREFERENCES_TAB_IMPROC;עיבוד ×¦×™×œ×•× +PREFERENCES_TAB_OUTPUT;×פשרויות ×™×™×¦×•× +PREFERENCES_THUMBSIZE;גודל תמונות ממוזערות +PROFILEPANEL_FILEDLGFILTERANY;×§×‘×¦×™× ×›×œ×©×”× +PROFILEPANEL_FILEDLGFILTERPP;פרופילי עיבוד +PROFILEPANEL_LABEL;פרופילי עיבוד +PROFILEPANEL_LOADDLGLABEL;הטען נתוני עיבוד +PROFILEPANEL_PCUSTOM;מות×× +PROFILEPANEL_PFILE;מקובץ +PROFILEPANEL_PLASTPHOTO;×¦×™×œ×•× ×חרון +PROFILEPANEL_PLASTSAVED;נשמר ×חרון +PROFILEPANEL_PROFILE;פרופיל +PROFILEPANEL_SAVEDLGLABEL;שמור נתוני עיבוד +PROFILEPANEL_TOOLTIPCOPY;Copy current profile to clipboard +PROFILEPANEL_TOOLTIPLOAD;הטען פרופיל מקובץ +PROFILEPANEL_TOOLTIPPASTE; Paste profile from clipboard +PROFILEPANEL_TOOLTIPSAVE;שמור פרופיל נוכחי +PROGRESSBAR_DECODING;מפענח קובץ +PROGRESSBAR_DEMOSAICING;מעבד ×¦×™×œ×•× +PROGRESSBAR_LOADING;מטעין ×¦×™×œ×•× +PROGRESSBAR_LOADJPEG;JPG מטעין קובץ +PROGRESSBAR_LOADPNG;PNG מטעין קובץ +PROGRESSBAR_LOADTIFF;TIFF מטעין קובץ +PROGRESSBAR_PROCESSING;מעבד ×¦×™×œ×•× +PROGRESSBAR_READY;מוכן +PROGRESSBAR_SAVEJPEG;JPG שומר קובץ +PROGRESSBAR_SAVEPNG;PNG שומר קובץ +PROGRESSBAR_SAVETIFF;TIFF שומר קובץ +PROGRESSDLG_LOADING;Loading file... +PROGRESSDLG_PROCESSING;Processing image... +PROGRESSDLG_SAVING;Saving file... +QINFO_FOCALLENGTH;×ורך מוקד +QINFO_ISO;ISO +QINFO_LENS;Lens +QINFO_NOEXIF;המידע ×œ× ×–×ž×™×Ÿ +SAVEDLG_FILEFORMAT;תצורת קובץ +SAVEDLG_JPEGQUAL;JPEG ×יכות +SAVEDLG_JPGFILTER;JPEG קבצי +SAVEDLG_PNGCOMPR;PNG דחיסת +SAVEDLG_PNGFILTER;PNG קבצי +SAVEDLG_PUTTOQUEUE;Put into processing queue +SAVEDLG_PUTTOQUEUEHEAD;Put to the head of the processing queue +SAVEDLG_PUTTOQUEUETAIL;Put to the end of the processing queue +SAVEDLG_SAVEIMMEDIATELY;Save immediately +SAVEDLG_SAVESPP;שמור נתוני עיבוד ×¢× ×”×¦×™×œ×•× +SAVEDLG_TIFFFILTER;TIFF קבצי +TOOLBAR_TOOLTIP_CROP;בחירת גזירה (shortcut key: C) +TOOLBAR_TOOLTIP_HAND;כלי יד (shortcut key: N) +TOOLBAR_TOOLTIP_STRAIGHTEN;בחירת קו ישר (shortcut key: S) +TOOLBAR_TOOLTIP_WB;×יזון לבן נקודתי (shortcut key: W) +TP_CACORRECTION_BLUE;כחול +TP_CACORRECTION_LABEL;C/A תיקון +TP_CACORRECTION_RED;××“×•× +TP_CHMIXER_BLUE;כחול +TP_CHMIXER_GREEN;ירוק +TP_CHMIXER_LABEL;מערבב ×¢×¨×•×¦×™× +TP_CHMIXER_RED;××“×•× +TP_COARSETRAF_DEGREE;מעלות +TP_COARSETRAF_TOOLTIP_HFLIP;הפוך ×ופקי +TP_COARSETRAF_TOOLTIP_ROTLEFT;סובב שמ×לה +TP_COARSETRAF_TOOLTIP_ROTRIGHT;סובב ימינה +TP_COARSETRAF_TOOLTIP_VFLIP;הפוך ×× ×›×™ +TP_COLORBOOST_ACHANNEL;ערוץ × +TP_COLORBOOST_AMOUNT;כמות +TP_COLORBOOST_AVOIDCOLORCLIP;הימנע מקיצוץ צבע +TP_COLORBOOST_BCHANNEL;ערוץ ב +TP_COLORBOOST_CHAB;'×'/ב +TP_COLORBOOST_CHANNEL;ערוץ +TP_COLORBOOST_CHSEPARATE;ליחוד +TP_COLORBOOST_ENABLESATLIMITER;הגבל רויה +TP_COLORBOOST_LABEL;הגברת צבע +TP_COLORBOOST_SATLIMIT;גבול רויה +TP_COLORDENOISE_EDGESENSITIVE;רגישות לקצוות +TP_COLORDENOISE_EDGETOLERANCE;סבילות לקצוות +TP_COLORDENOISE_LABEL;הסרת רעש צבעוני +TP_COLORDENOISE_RADIUS;רדיוס +TP_COLORSHIFT_BLUEYELLOW;צהוב-כחול +TP_COLORSHIFT_GREENMAGENTA;מג'נטה-ירוק +TP_COLORSHIFT_LABEL;העברת צבע +TP_CROP_DPI;DPI= +TP_CROP_FIXRATIO;קבע יחס +TP_CROP_GTDIAGONALS;כלל ×”×לכסון +TP_CROP_GTHARMMEANS1;×ž×ž×•×¦× ×”×¨×ž×•× ×™ 1 +TP_CROP_GTHARMMEANS2;×ž×ž×•×¦× ×”×¨×ž×•× ×™ 2 +TP_CROP_GTHARMMEANS3;×ž×ž×•×¦× ×”×¨×ž×•× ×™ 3 +TP_CROP_GTHARMMEANS4;×ž×ž×•×¦× ×”×¨×ž×•× ×™ 4 +TP_CROP_GTNONE;×œ×œ× +TP_CROP_GTRULETHIRDS;כלל השליש +TP_CROP_GUIDETYPE;סוג מדריך +TP_CROP_H;גובה +TP_CROP_LABEL;גזור +TP_CROP_SELECTCROP;בחור גזירה +TP_CROP_W;רוחב +TP_CROP_X;x +TP_CROP_Y;y +TP_DISTORTION_AMOUNT;כמות +TP_DISTORTION_LABEL;עיוות +TP_EXPOSURE_AUTOLEVELS;×ž×¤×œ×¡×™× ××•×˜×•×ž×˜×™× +TP_EXPOSURE_BLACKLEVEL;שחור +TP_EXPOSURE_BRIGHTNESS;בהירות +TP_EXPOSURE_CLIP;קצץ +TP_EXPOSURE_COMPRHIGHLIGHTS;דחיסת ×’×•×•× ×™× ×‘×”×™×¨×™× +TP_EXPOSURE_COMPRSHADOWS;דחיסת ×’×•×•× ×™× ×›×”×™× +TP_EXPOSURE_CONTRAST;ניגודיות +TP_EXPOSURE_CURVEEDITOR;עקמת ×’×•×•× ×™× +TP_EXPOSURE_EXPCOMP;פיצוי חשיפה +TP_EXPOSURE_LABEL;חשיפה +TP_HLREC_CIELAB;CIELab Blending +TP_HLREC_COLOR;הפצת צבע +TP_HLREC_LABEL;שחזור ×’×•×•× ×™× ×‘×”×™×¨×™× +TP_HLREC_LUMINANCE;שחזור בהירות +TP_HLREC_METHOD;שיטה +TP_ICM_FILEDLGFILTERANY;×§×‘×¦×™× ×›×œ×©×”× +TP_ICM_FILEDLGFILTERICM;ICC קבצי צבע +TP_ICM_GAMMABEFOREINPUT;Profile applies Gamma +TP_ICM_INPUTCAMERA;ברירת מחדל המצלמה +TP_ICM_INPUTCUSTOM;מות×× +TP_ICM_INPUTDLGLABEL;בחר בפרופיל צבע ×™×™×‘×•× +TP_ICM_INPUTEMBEDDED;השתמש בפרופיל משובץ,×× ×פשר +TP_ICM_INPUTPROFILE;פרופיל ×™×™×‘×•× +TP_ICM_LABEL;ניהול צבע +TP_ICM_NOICM;sRGB×œ×œ× × ×™×”×•×œ צבע - ×™×™×¦×•× ×‘ +TP_ICM_OUTPUTDLGLABEL;בחר בפרופיל צבע ×™×™×¦×•× +TP_ICM_OUTPUTPROFILE;פרופיל ×™×™×¦×•× +TP_ICM_SAVEREFERENCE;Save reference image for profiling +TP_ICM_WORKINGPROFILE;פרופיל עבודה +TP_LUMACURVE_BLACKLEVEL;שחור +TP_LUMACURVE_BRIGHTNESS;בהירות +TP_LUMACURVE_COMPRHIGHLIGHTS;דחיסת ×’×•×•× ×™× ×‘×”×™×¨×™× +TP_LUMACURVE_COMPRSHADOWS;דחיסת ×’×•×•× ×™× ×›×”×™× +TP_LUMACURVE_CONTRAST;ניגודיות +TP_LUMACURVE_CURVEEDITOR;עקמת בהירות +TP_LUMACURVE_LABEL;עקמת בהירות +TP_LUMADENOISE_EDGETOLERANCE;סבילות לקצוות +TP_LUMADENOISE_LABEL;הסרת רעש בהירות +TP_LUMADENOISE_RADIUS;רדיוס +TP_RESIZE_BICUBIC;ביקובי +TP_RESIZE_BICUBICSF;ביקובי חלק +TP_RESIZE_BICUBICSH;ביקובי חד +TP_RESIZE_BILINEAR;בילינ×רי +TP_RESIZE_FULLSIZE;גודל ×ž×œ× +TP_RESIZE_H;גובה +TP_RESIZE_LABEL;החלף גודל +TP_RESIZE_METHOD;שיטה +TP_RESIZE_NEAREST;הקרוב +TP_RESIZE_SCALE;מידה +TP_RESIZE_W;רוחב +TP_ROTATE_AUTOCROP;גזירה ×וטומטי +TP_ROTATE_DEGREE;מעלות +TP_ROTATE_FILL;×ž×œ× +TP_ROTATE_LABEL;סובב +TP_ROTATE_SELECTLINE;בחור קו ישר +TP_SHADOWSHLIGHTS_HIGHLIGHTS;×’×•×•× ×™× ×‘×”×™×¨×™× +TP_SHADOWSHLIGHTS_HLTONALW;רוחב ×’×•×•× ×™× +TP_SHADOWSHLIGHTS_LABEL;בהירי×\×›×”×™× +TP_SHADOWSHLIGHTS_LOCALCONTR;ניגודיות מקומית +TP_SHADOWSHLIGHTS_RADIUS;רדיוס +TP_SHADOWSHLIGHTS_SHADOWS;×’×•×•× ×™× ×›×”×™× +TP_SHADOWSHLIGHTS_SHTONALW;רוחב ×’×•×•× ×™× +TP_SHARPENING_AMOUNT;כמות +TP_SHARPENING_EDRADIUS;רדיוס +TP_SHARPENING_EDTOLERANCE;סבילות לקצוות +TP_SHARPENING_HALOCONTROL;בקרת הילה +TP_SHARPENING_HCAMOUNT;כמות +TP_SHARPENING_LABEL;חידוד +TP_SHARPENING_METHOD;שיטה +TP_SHARPENING_ONLYEDGES;חידוד רק בקצוות +TP_SHARPENING_RADIUS;רדיוס +TP_SHARPENING_RLD;RL דיקונבולוציה +TP_SHARPENING_RLD_AMOUNT;כמות +TP_SHARPENING_RLD_DAMPING;ריסון +TP_SHARPENING_RLD_ITERATIONS;חזרות +TP_SHARPENING_THRESHOLD;××£ +TP_SHARPENING_USM;מיסוך ××™-חדות +TP_VIGNETTING_AMOUNT;כמות +TP_VIGNETTING_LABEL;תיקון פינות כהות +TP_VIGNETTING_RADIUS;רדיוס +TP_WBALANCE_AUTO;×וטומטי +TP_WBALANCE_CAMERA;מצלמה +TP_WBALANCE_CUSTOM;מות×× +TP_WBALANCE_GREEN;גיוון +TP_WBALANCE_LABEL;×יזון לבן +TP_WBALANCE_METHOD;שיטה +TP_WBALANCE_SIZE;גודל +TP_WBALANCE_SPOTWB;לפי נקודה +TP_WBALANCE_TEMPERATURE;מידת ×—×•× +ZOOMBAR_DETAIL;×¤×¨×˜×™× +ZOOMBAR_HUGE;×¢× ×§ +ZOOMBAR_LARGE;גדול +ZOOMBAR_NORMAL;רגיל +ZOOMBAR_PREVIEW;תצוגה מקדימה +ZOOMBAR_SCALE;מידה +ZOOMBAR_SMALL;קטן diff --git a/release/languages/italian b/release/languages/italian new file mode 100755 index 000000000..7b2e81bf5 --- /dev/null +++ b/release/languages/italian @@ -0,0 +1,580 @@ +# italian language file for rawtherapee +# UTF-8(unix mode) +# translated by breek, pantaraf, chelidon, roberto +# IMPORTANTE: facci sapere sul forum di rawtherapee nella sezione del locale italiano se ci sono errori, qui http://www.rawtherapee.com/forum/viewtopic.php?p=3354#3354 +# IMPORTANT: post on the italian locale in the rawtherapee if are any errors, here http://www.rawtherapee.com/forum/viewtopic.php?p=3354#3354 +# 01-11-2008 +ADJUSTER_RESET_TO_DEFAULT;Valori originali +CURVEEDITOR_FILEDLGFILTERANY;Qualsiasi file +CURVEEDITOR_FILEDLGFILTERCURVE;File curve +CURVEEDITOR_LINEAR;Lineare +CURVEEDITOR_LOADDLGLABEL;Carica curva... +CURVEEDITOR_SAVEDLGLABEL;Salva curva... +CURVEEDITOR_TOOLTIPLINEAR;Ripristina curva lineare +CURVEEDITOR_TOOLTIPLOAD;Carica curva da file +CURVEEDITOR_TOOLTIPSAVE;Salva curva corrente +EXIFFILTER_APERTURE;Diaframma +EXIFFILTER_CAMERA;Fotocamera +EXIFFILTER_DIALOGLABEL;Filtro Exif +EXIFFILTER_FOCALLEN;Lunghezza focale +EXIFFILTER_ISO;ISO +EXIFFILTER_LENS;Obiettivo +EXIFFILTER_SHUTTER;Tempo d'esposizione +EXIFPANEL_ADDEDIT;Aggiungi/Modifica +EXIFPANEL_ADDEDITHINT;Aggiungi un nuovo campo o modificane uno esistente +EXIFPANEL_ADDTAGDLG_ENTERVALUE;Inserisci valore +EXIFPANEL_ADDTAGDLG_SELECTTAG;Seleziona campo +EXIFPANEL_ADDTAGDLG_TITLE;Aggiungi/Modifica campo +EXIFPANEL_KEEP;Mantieni +EXIFPANEL_KEEPHINT;Mantieni il campo selezionato nel risultato finale +EXIFPANEL_REMOVE;Rimuovi +EXIFPANEL_REMOVEHINT;Rimuovi il campo selezionato dal risultato finale +EXIFPANEL_RESET;Ripristina +EXIFPANEL_RESETALL;Ripristina tutto +EXIFPANEL_RESETALLHINT;Ripristina tutti i campi al loro valore originario +EXIFPANEL_RESETHINT;Ripristina i campi selezionati ai loro valori originari +EXIFPANEL_SUBDIRECTORY;Sottocartella +FILEBROWSER_APPLYPROFILE;Applica un profilo +FILEBROWSER_ARRANGEMENTHINT;Commuta fra la disposizione verticale o orizzontale delle miniature +FILEBROWSER_CLEARPROFILE;Azzera il profilo +FILEBROWSER_COPYPROFILE;Copia il profilo +FILEBROWSER_DELETEDLGLABEL;Conferma eliminazione file +FILEBROWSER_DELETEDLGMSG;Sei certo di voler eliminare i %1 file selezionati? +FILEBROWSER_EMPTYTRASH;Svuota cestino +FILEBROWSER_EMPTYTRASHHINT;Elimina permanentemente i file dal cestino +FILEBROWSER_EXIFFILTERAPPLY;Applica +FILEBROWSER_EXIFFILTERAPPLYHINT;Accendi/Spegni il filtro exif nel navigatore +FILEBROWSER_EXIFFILTERLABEL;Filtro Exif +FILEBROWSER_EXIFFILTERSETTINGS;Imposta +FILEBROWSER_EXIFFILTERSETTINGSHINT;Modifica le impostazioni del filtro exif +FILEBROWSER_PARTIALPASTEPROFILE;Incolla parzialmente +FILEBROWSER_PASTEPROFILE;Incolla il profilo +FILEBROWSER_POPUPCANCELJOB;Cancella compito +FILEBROWSER_POPUPMOVEEND;Sposta in fondo alla coda +FILEBROWSER_POPUPMOVEHEAD;Sposta in cima alla coda +FILEBROWSER_POPUPOPEN;Apri +FILEBROWSER_POPUPPROCESS;Invia alla coda di sviluppo +FILEBROWSER_POPUPRANK1;Classificazione 1 +FILEBROWSER_POPUPRANK2;Classificazione 2 +FILEBROWSER_POPUPRANK3;Classificazione 3 +FILEBROWSER_POPUPRANK4;Classificazione 4 +FILEBROWSER_POPUPRANK5;Classificazione 5 +FILEBROWSER_POPUPREMOVE;Rimuovi definitivamente +FILEBROWSER_POPUPRENAME;Rinomina +FILEBROWSER_POPUPSELECTALL;Seleziona tutto +FILEBROWSER_POPUPTRASH;Butta nel cestino +FILEBROWSER_POPUPUNRANK;Declassifica +FILEBROWSER_POPUPUNTRASH;Togli dal cestino +FILEBROWSER_PROCESSINGSETTINGS;Impostazioni +FILEBROWSER_PROCESSINGSETTINGSHINT;Scegli il formato del file e la cartella di destinazione +FILEBROWSER_RENAMEDLGLABEL;Rinomina il file +FILEBROWSER_RENAMEDLGMSG;Rinomina il file "%1" in: +FILEBROWSER_SHOWDIRHINT;Mostra tutte le immagini della cartella +FILEBROWSER_SHOWQUEUEHINT;Mostra il contenuto della coda di sviluppo +FILEBROWSER_SHOWRANK1HINT;Mostra le immagini classificate con 1 stella +FILEBROWSER_SHOWRANK2HINT;Mostra le immagini classificate con 2 stelle +FILEBROWSER_SHOWRANK3HINT;Mostra le immagini classificate con 3 stelle +FILEBROWSER_SHOWRANK4HINT;Mostra le immagini classificate con 4 stelle +FILEBROWSER_SHOWRANK5HINT;Mostra le immagini classificate con 5 stelle +FILEBROWSER_SHOWTRASHHINT;Mostra il contenuto del cestino +FILEBROWSER_SHOWUNRANKHINT;Mostra le immagini non classificate +FILEBROWSER_STARTPROCESSING;Comincia a sviluppare +FILEBROWSER_STARTPROCESSINGHINT;Inizia lo sviluppo o il salvataggio delle immagini in coda +FILEBROWSER_STOPPROCESSING;Smetti di sviluppare +FILEBROWSER_STOPPROCESSINGHINT;Ferma lo sviluppo delle immagini +FILEBROWSER_THUMBSIZE;Dimensione miniature +FILEBROWSER_ZOOMINHINT;Aumenta la dimensione delle miniature +FILEBROWSER_ZOOMOUTHINT;Diminuisci la dimensione delle miniature +GENERAL_ABOUT;Informazioni +GENERAL_CANCEL;Annulla +GENERAL_DISABLE;Disabilita +GENERAL_DISABLED;Disabilitato +GENERAL_ENABLE;Abilita +GENERAL_ENABLED;Abilitato +GENERAL_LANDSCAPE;Panorama +GENERAL_LOAD;Carica +GENERAL_NA;n/d +GENERAL_NO;No +GENERAL_OK;OK +GENERAL_PORTRAIT;Ritratto +GENERAL_SAVE;Salva +GENERAL_YES;Sì +HISTOGRAM_LABEL;Istogramma +HISTOGRAM_TOOLTIP_B;Mostra/Nascondi istogramma del BLU +HISTOGRAM_TOOLTIP_G;Mostra/Nascondi istogramma del VERDE +HISTOGRAM_TOOLTIP_L;Mostra/Nascondi istogramma di luminanza CIELAB +HISTOGRAM_TOOLTIP_R;Mostra/Nascondi istogramma del ROSSO +HISTORY_CHANGED;Modificato +HISTORY_CUSTOMCURVE;Curva personalizzata +HISTORY_DELSNAPSHOT;Rimuovi +HISTORY_FROMCLIPBOARD;Dagli appunti +HISTORY_LABEL;Cronologia +HISTORY_MSG_10;Compressione ombre +HISTORY_MSG_11;Curva di tono +HISTORY_MSG_12;Esposizione automatica +HISTORY_MSG_13;Sovraesposizione +HISTORY_MSG_14;Luminosità luminanza +HISTORY_MSG_15;Contrasto luminanza +HISTORY_MSG_16;Punto del nero luminanza +HISTORY_MSG_17;Compressione alteluci luminanza +HISTORY_MSG_18;Compressione ombre luminanza +HISTORY_MSG_19;Curva di luminanza +HISTORY_MSG_1;Foto caricata +HISTORY_MSG_20;Nitidezza +HISTORY_MSG_21;Raggio nitidezza +HISTORY_MSG_22;Quantità nitidezza +HISTORY_MSG_23;Soglia nitidezza +HISTORY_MSG_24;Definisci solo i bordi +HISTORY_MSG_25;Raggio di rilevamento bordi nitidezza +HISTORY_MSG_26;Tolleranza bordi nitidezza +HISTORY_MSG_27;Controllo alone nitidezza +HISTORY_MSG_28;Quantità controllo alone +HISTORY_MSG_29;Metodo controllo nitidezza +HISTORY_MSG_2;Profilo caricato +HISTORY_MSG_30;Raggio deconvoluzione +HISTORY_MSG_31;Quantità deconvoluzione +HISTORY_MSG_32;Smorzamento deconvoluzione +HISTORY_MSG_33;Iterazioni deconvoluzione +HISTORY_MSG_34;Previeni tosaggio dei colori +HISTORY_MSG_35;Limitatore saturazione +HISTORY_MSG_36;Limite saturazione +HISTORY_MSG_37;Potenziamento colore +HISTORY_MSG_38;Metodo di bilanciamento del bianco +HISTORY_MSG_39;Temperatura colore +HISTORY_MSG_3;Profilo cambiato +HISTORY_MSG_40;Tinta bilanciamento del bianco +HISTORY_MSG_41;Spostamento colore "A" +HISTORY_MSG_42;Spostamento colore "B" +HISTORY_MSG_43;Riduzione rumore luminanza +HISTORY_MSG_44;Raggio rumore luminanza +HISTORY_MSG_45;Tolleranza bordi rumore luminanza +HISTORY_MSG_46;Riduzione rumore crominanza +HISTORY_MSG_47;Raggio rumore crominanza +HISTORY_MSG_48;Tolleranza bordi rumore crominanza +HISTORY_MSG_49;Sensibilità bordi rumore crominanza +HISTORY_MSG_4;Visualizzazione cronologia +HISTORY_MSG_50;Strumento ombre/alteluci +HISTORY_MSG_51;Miglioramento alteluci +HISTORY_MSG_52;Miglioramento ombre +HISTORY_MSG_53;Ampiezza tonale alteluci +HISTORY_MSG_54;Ampiezza tonale ombre +HISTORY_MSG_55;Contrasto locale +HISTORY_MSG_56;Raggio per ombre/alteluci +HISTORY_MSG_57;Rotazione arbitraria +HISTORY_MSG_58;Ribaltamento orizzontale +HISTORY_MSG_59;Ribaltamento verticale +HISTORY_MSG_5;Luminosità +HISTORY_MSG_60;Rotazione +HISTORY_MSG_61;Rotazione +HISTORY_MSG_62;Correzione distorsione dell'obiettivo +HISTORY_MSG_63;Istantanea selezionata +HISTORY_MSG_64;Ritaglio foto +HISTORY_MSG_65;Correzione aberrazioni cromatiche +HISTORY_MSG_66;Recupero alteluci +HISTORY_MSG_67;Quantità recupero alteluci +HISTORY_MSG_68;Metodo di recupero alteluci +HISTORY_MSG_69;Spazio colore di lavoro +HISTORY_MSG_6;Contrasto +HISTORY_MSG_70;Spazio colore di uscita +HISTORY_MSG_71;Spazio colore di ingresso +HISTORY_MSG_72;Correzione vignettatura +HISTORY_MSG_73;Miscelatore dei canali +HISTORY_MSG_74;Ridimensiona +HISTORY_MSG_75;Metodo di ridimensionamento +HISTORY_MSG_76;Metadati Exif +HISTORY_MSG_77;Metadati IPTC +HISTORY_MSG_7;Livello del nero +HISTORY_MSG_8;Compensazione dell'esposizione +HISTORY_MSG_9;Compressione alteluci +HISTORY_NEWSNAPSHOT;Aggiungi +HISTORY_NEWSNAPSHOTAS;Come... +HISTORY_NEWSSDIALOGLABEL;Etichetta dell'istantanea: +HISTORY_NEWSSDIALOGTITLE;Aggiungi nuova istantanea +HISTORY_SETTO;Impostato a +HISTORY_SNAPSHOT;Istantanea +HISTORY_SNAPSHOTS;Istantanee +ICMPANEL_FILEDLGFILTERANY;Qualsiasi file +ICMPANEL_FILEDLGFILTERICM;Profili ICC +ICMPANEL_GAMMABEFOREINPUT;Il profilo applica il gamma +ICMPANEL_INPUTCAMERA;Predefinito della fotocamera +ICMPANEL_INPUTCUSTOM;Personalizzato +ICMPANEL_INPUTDLGLABEL;Seleziona il profilo ICC di ingresso... +ICMPANEL_INPUTEMBEDDED;Incorporato, se possibile +ICMPANEL_INPUTPROFILE;Profilo di ingresso +ICMPANEL_NOICM;Nessun ICM: uscita in sRGB +ICMPANEL_OUTPUTDLGLABEL;Seleziona il profilo ICC di uscita... +ICMPANEL_OUTPUTPROFILE;Profilo di uscita +ICMPANEL_SAVEREFERENCE;Salva immagine di riferimento per la profilazione +ICMPANEL_WORKINGPROFILE;Profilo di lavoro +IMAGEAREA_DETAILVIEW;Visualizza dettaglio +IPTCPANEL_AUTHOR;Autore +IPTCPANEL_AUTHORHINT;Nome del creatore dell'opera, es. scrittore, fotografo o artista grafico (By-line). +IPTCPANEL_AUTHORSPOSITION;Qualifica dell'Autore +IPTCPANEL_AUTHORSPOSITIONHINT;Titolo lavorativo del creatore o creatori dell'opera (By-line Title). +IPTCPANEL_CAPTION;Didascalia +IPTCPANEL_CAPTIONHINT;Una descrizione testuale dei dati (Caption - Abstract). +IPTCPANEL_CAPTIONWRITER;Autore della didascalia +IPTCPANEL_CAPTIONWRITERHINT;Il nome della persona impegnata nella scrittura, modifica o correzione dell'immagine o della descrizione riassuntiva (Writer - Editor). +IPTCPANEL_CATEGORY;Categoria +IPTCPANEL_CATEGORYHINT;Identifica il soggetto dell'immagine secondo l'opinione del curatore (Category). +IPTCPANEL_CITY;Città +IPTCPANEL_CITYHINT;Città o luogo di origine dell'immagine (City). +IPTCPANEL_COPYHINT;Copia le impostazioni IPTC negli appunti +IPTCPANEL_COPYRIGHT;Diritto d'autore +IPTCPANEL_COPYRIGHTHINT;Qualsiasi annotazione necessaria riguardante il diritto d'autore (Copyright Notice). +IPTCPANEL_COUNTRY;Stato +IPTCPANEL_COUNTRYHINT;Il nome dello stato/confederazione in cui l'immagine è stata creata (Country - Primary Location Name). +IPTCPANEL_CREDIT;Riconoscimento +IPTCPANEL_CREDITHINT;Identifica il fornitore dell'immagine, non necessariamente il possessore/creatore (Credit). +IPTCPANEL_DATECREATED;Data di creazione +IPTCPANEL_DATECREATEDHINT;La data in cui è stato creato il contenuto intellettuale dell'immagine; Formato: AAAAMMTT (Date Created). +IPTCPANEL_EMBEDDED;Incorporato +IPTCPANEL_EMBEDDEDHINT;Ripristina i dati IPTC incorporati nel file d'immagine +IPTCPANEL_HEADLINE;Intestazione +IPTCPANEL_HEADLINEHINT;Una didascalia pubblicabile che esprime una sinossi del contenuto dell'immagine (Headline). +IPTCPANEL_INSTRUCTIONS;Istruzioni +IPTCPANEL_INSTRUCTIONSHINT;Altre istruzioni editoriali riguardanti l'uso dell'immagine (Special Instructions). +IPTCPANEL_KEYWORDS;Parole Chiave +IPTCPANEL_KEYWORDSHINT;Usate per indicare parole emblematiche per il recupero di informazioni specifiche (Keywords). +IPTCPANEL_PASTEHINT;Incolla le impostazioni IPTC dagli appunti +IPTCPANEL_PROVINCE;Provincia +IPTCPANEL_PROVINCEHINT;La provincia/regione da cui l'immagine proviene (Province-State). +IPTCPANEL_RESET;Ripristina +IPTCPANEL_RESETHINT;Ripristina il profilo predefinito +IPTCPANEL_SOURCE;Origine +IPTCPANEL_SOURCEHINT;Il possessore originario del contenuto intellettuale rappresentato nell'immagine (Source). +IPTCPANEL_SUPPCATEGORIES;Categorie agg. +IPTCPANEL_SUPPCATEGORIESHINT;Ulteriore raffinamento del soggetto dell'immagine (Supplemental Categories). +IPTCPANEL_TITLE;Titolo +IPTCPANEL_TITLEHINT;Un breve riferimento per l'immagine (Object Name). +IPTCPANEL_TRANSREFERENCE;Riferimento Trasm. +IPTCPANEL_TRANSREFERENCEHINT;Un codice che rappresenta la locazione da cui è avvenuta la trasmissione originaria (Original Transmission Reference). +MAIN_BUTTON_PREFERENCES;Preferenze +MAIN_BUTTON_SAVE;Salva immagine +MAIN_BUTTON_SAVEAS;Salva come... +MAIN_BUTTON_SENDTOEDITOR;Passa al ritocco +MAIN_MSG_ALREADYEXISTS;Il file esiste già! +MAIN_MSG_CANNOTLOAD;Impossibile caricare l'immagine +MAIN_MSG_CANNOTSAVE;Errore nel salvare il file! +MAIN_MSG_CANNOTSTARTEDITOR;Non riesco ad avviare il programma di ritocco. +MAIN_MSG_CANNOTSTARTEDITOR_SECONDARY;Prego inserire il percorso corretto mediante l'impostazione delle "Preferenze". +MAIN_MSG_EXITJOBSINQUEUEINFO;Le immagini non ancora sviluppate dalla coda andranno perse all'uscita. +MAIN_MSG_EXITJOBSINQUEUEQUEST;Sei certo di voler uscire? Ci sono immagini non ancora sviluppate rimaste nella coda. +MAIN_MSG_JOBSINQUEUE;operazione/i in coda +MAIN_MSG_QOVERWRITE;Vuoi sovrascriverlo? +MAIN_TAB_BASIC;Base +MAIN_TAB_COLOR;Colore +MAIN_TAB_DETAIL;Dettaglio +MAIN_TAB_EXIF;Exif +MAIN_TAB_EXPOSURE;Esposizione +MAIN_TAB_ICM;ICM +MAIN_TAB_IPTC;IPTC +MAIN_TAB_METADATA;Metadati +MAIN_TAB_TRANSFORM;Trasformazione +MAIN_TOOLTIP_HIDEFP;Mostra/Nascondi il pannello dei pulsanti (cartelle e navigatore di file, shortcut key: F) +MAIN_TOOLTIP_HIDEHP;Mostra/Nascondi il pannello sinistro (inclusa la cronologia, shortcut key: H) +MAIN_TOOLTIP_INDCLIPPEDH;Indicazione delle alteluci tosate +MAIN_TOOLTIP_INDCLIPPEDS;Indicazione delle ombre tosate +MAIN_TOOLTIP_PREFERENCES;Imposta preferenze +MAIN_TOOLTIP_QINFO;Informazioni generali sullo scatto +MAIN_TOOLTIP_SAVE;Salva immagine nella cartella predefinita +MAIN_TOOLTIP_SAVEAS;Salva immagine nella cartella selezionata +PARTIALPASTE_BASICGROUP;Parametri di base +PARTIALPASTE_CACORRECTION;Correzione A/C +PARTIALPASTE_COARSETRANS;Rotazione di 90° / riflessione +PARTIALPASTE_COLORBOOST;Potenziamento colore +PARTIALPASTE_COLORDENOISE;Riduzione rumore di crominanza +PARTIALPASTE_COLORGROUP;Parametri relativi al colore +PARTIALPASTE_COLORMIXER;Miscelatore colore +PARTIALPASTE_COLORSHIFT;Spostamento colore +PARTIALPASTE_COMPOSITIONGROUP;Parametri di composizione +PARTIALPASTE_CROP;Ritaglio +PARTIALPASTE_DIALOGLABEL;Incolla una porzione del profilo +PARTIALPASTE_DISTORTION;Correzione distorsione +PARTIALPASTE_EXIFCHANGES;Cambiamenti nei dati exif +PARTIALPASTE_EXPOSURE;Esposizione +PARTIALPASTE_HLRECOVERY;Recupero alteluci +PARTIALPASTE_ICMSETTINGS;Parametri ICM +PARTIALPASTE_IPTCINFO;Informazioni IPTC +PARTIALPASTE_LENSGROUP;Parametri correlati all'ottica +PARTIALPASTE_LUMACURVE;Curva di luminanza +PARTIALPASTE_LUMADENOISE;Riduzione rumore di luminanza +PARTIALPASTE_LUMINANCEGROUP;Parametri riguardanti la luminanza +PARTIALPASTE_METAICMGROUP;Parametri di Metadati/ICM +PARTIALPASTE_RESIZE;Ridimensionamento +PARTIALPASTE_ROTATION;Rotazione +PARTIALPASTE_SHADOWSHIGHLIGHTS;Ombre/Alteluci +PARTIALPASTE_SHARPENING;Nitidezza +PARTIALPASTE_VIGNETTING;Correzione vignettatura +PARTIALPASTE_WHITEBALANCE;Bilanciamento del bianco +PREFERENCES_APPLNEXTSTARTUP;applicato al prossimo avvio +PREFERENCES_BLINKCLIPPED;Lampeggia le aree tosate +PREFERENCES_CACHECLEARALL;Ripulisci tutto +PREFERENCES_CACHECLEARPROFILES;Ripulisci i profili +PREFERENCES_CACHECLEARTHUMBS;Ripulisci le miniature +PREFERENCES_CACHEFORMAT1;Proprietario (più rapido e di migliore qualità) +PREFERENCES_CACHEFORMAT2;JPEG (minore impatto sul disco) +PREFERENCES_CACHEMAXENTRIES;Numero massimo di oggetti conservati in memoria +PREFERENCES_CACHEOPTS;Opzioni per il precaricamento +PREFERENCES_CACHESTRAT1;Privilegia la rapidità al minore consumo di memoria +PREFERENCES_CACHESTRAT2;Privilegia il minore consumo di memoria alla rapidità +PREFERENCES_CACHESTRAT;Strategia di precaricamento +PREFERENCES_CACHETHUMBFORM;Formato delle miniature precaricate +PREFERENCES_CACHETHUMBHEIGHT;Massima quantità di miniature +PREFERENCES_CLEARDLG_LINE1;Ripulitura dati in memoria +PREFERENCES_CLEARDLG_LINE2;Questa operazione potrebbe impiegare alcuni secondi. +PREFERENCES_CLEARDLG_TITLE;Prego attendere +PREFERENCES_CLIPPINGIND;Indicazione di tosaggio +PREFERENCES_CMETRICINTENT;Intento colorimetrico +PREFERENCES_DATEFORMAT;Formato data +PREFERENCES_DATEFORMATHINT;Puoi usare le seguenti stringhe di formattazione:\n%y : anno\n%m : mese\n%d : giorno\n\nPer esempio, il formato italiano per la data è:\n%d/%m/%y +PREFERENCES_DEFAULTLANG;Lingua predefinita +PREFERENCES_DEFAULTTHEME;Aspetto ordinario +PREFERENCES_DEMOSAICINGALGO;Algoritmo di demosaicizzazione +PREFERENCES_DIRHOME;Cartella personale dell'utente (home directory) +PREFERENCES_DIRLAST;Ultima cartella visitata +PREFERENCES_DIROTHER;Altra +PREFERENCES_DIRSELECTDLG;Seleziona la cartella delle immagini all'avvio... +PREFERENCES_DIRSOFTWARE;Cartella d'installazione +PREFERENCES_DMETHOD;Metodo +PREFERENCES_EDITORCMDLINE;Esegui altro da linea di comando +PREFERENCES_EXTERNALEDITOR;Programmi di ritocco esterni +PREFERENCES_FALSECOLOR;Iterazioni per la soppressione dei falsi colori +PREFERENCES_FBROWSEROPTS;Opzioni del navigatore di file +PREFERENCES_FILEFORMAT;Formato file +PREFERENCES_FORIMAGE;Per file immagine +PREFERENCES_FORRAW;Per file RAW +PREFERENCES_GIMPPATH;Cartella d'installazione di GIMP +PREFERENCES_GTKTHEME;Predefinito GTK +PREFERENCES_HINT;Suggerimento +PREFERENCES_HLTHRESHOLD;Soglia per le alteluci tosate +PREFERENCES_ICCDIR;Cartella profili ICC +PREFERENCES_IMPROCPARAMS;Parametri predefiniti di elaborazione dell'immagine +PREFERENCES_INTENT_ABSOLUTE;Colorimetrico Assoluto +PREFERENCES_INTENT_PERCEPTUAL;Percettivo +PREFERENCES_INTENT_RELATIVE;Colorimetrico Relativo +PREFERENCES_INTENT_SATURATION;Saturazione +PREFERENCES_LIVETHUMBNAILS;Miniature sincronizzate (maggiore lentezza) +PREFERENCES_MONITORICC;Profilo dello schermo +PREFERENCES_OUTDIR;Cartella di destinazione +PREFERENCES_OUTDIRFOLDER;Salva nella cartella +PREFERENCES_OUTDIRFOLDERHINT;Mette le immagini salvate nella cartella scelta +PREFERENCES_OUTDIRHINT;Puoi usare le seguenti stringhe di formattazione:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nQueste stringhe di formattazione si riferiscono alle cartelle e ai percorsi sottostanti la posizione del file raw.\n\nPer esempio, se si è aperto /home/tom/immagini/02-09-2006/dsc0012.nef, il senso delle stringhe di formattazione è:\n%f=dsc0012, %d1=02-09-2006, %d2=immagini, ...\n%p1=/home/tom/immagini/02-09-2006, %p2=/home/tom/immagini, p3=/home/tom, ...\n\nSe vuoi salvare l'immagine finale nella stessa posizione dove si trova l'originale, scrivi:\n%p1/%f\n\nSe vuoi salvare l'immagine finale in una cartella 'sviluppate' situata nella cartella degli originali, scrivi:\n%p1/sviluppate/%f\n\nSe intendi salvare l'immagine finale in una cartella '/home/tom/sviluppate' mantenendo la stessa sottocartella della data, scrivi:\n%p2/sviluppate/%d1/%f +PREFERENCES_OUTDIRTEMPLATE;Usa modello +PREFERENCES_OUTDIRTEMPLATEHINT;Puoi usare le seguenti stringhe di formattazione:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nQueste stringhe di formattazione si riferiscono alle cartelle e ai percorsi sottostanti la posizione del file raw.\n\nPer esempio, se si è aperto /home/tom/immagini/02-09-2006/dsc0012.nef, il senso delle stringhe di formattazione è:\n%f=dsc0012, %d1=02-09-2006, %d2=immagini, ...\n%p1=/home/tom/immagini/02-09-2006, %p2=/home/tom/immagini, p3=/home/tom, ...\n\nSe vuoi salvare l'immagine finale nella stessa posizione dove si trova l'originale, scrivi:\n%p1/%f\n\nSe vuoi salvare l'immagine finale in una cartella 'sviluppate' situata nella cartella degli originali, scrivi:\n%p1/sviluppate/%f\n\nSe intendi salvare l'immagine finale in una cartella '/home/tom/sviluppate' mantenendo la stessa sottocartella della data, scrivi:\n%p2/sviluppate/%d1/%f +PREFERENCES_PARSEDEXT;Estensioni riconosciute +PREFERENCES_PARSEDEXTADD;Aggiungi estensione +PREFERENCES_PARSEDEXTADDHINT;Immetti l'estensione e premi questo tasto per aggiungerla alla lista +PREFERENCES_PARSEDEXTDELHINT;Rimuovi l'estensione selezionata dalla lista +PREFERENCES_PROFILEHANDLING;Gestione dei profili di elaborazione +PREFERENCES_PROFILELOADPR;Priorità nel caricamento del profilo +PREFERENCES_PROFILEPRCACHE;Profilo situato nella memoria del programma +PREFERENCES_PROFILEPRFILE;Profilo presente a fianco del file originario +PREFERENCES_PROFILESAVECACHE;Salva i parametri di elaborazione nella memoria del programma +PREFERENCES_PROFILESAVEINPUT;Salva i parametri di elaborazione a fianco del file originario +PREFERENCES_PSPATH;Cartella d'installazione di Adobe Photoshop +PREFERENCES_SELECTICCDIRDLG;Seleziona la cartella dei profili ICC... +PREFERENCES_SELECTLANG;Seleziona lingua +PREFERENCES_SELECTMONITORPROFDLG;Seleziona il profilo ICC dello schermo... +PREFERENCES_SELECTTHEME;Seleziona un tema +PREFERENCES_SHOWBASICEXIF;Mostra informazioni Exif di base +PREFERENCES_SHOWDATETIME;Mostra data e ora +PREFERENCES_SHOWONLYRAW;Mostra solo file RAW +PREFERENCES_SHTHRESHOLD;Soglia per le ombre tosate +PREFERENCES_STARTUPIMDIR;Cartella delle immagini all'avvio +PREFERENCES_TAB_BROWSER;Navigatore di file +PREFERENCES_TAB_COLORMGR;Gestione colore +PREFERENCES_TAB_GENERAL;Generale +PREFERENCES_TAB_IMPROC;Elaborazione immagine +PREFERENCES_TAB_OUTPUT;Opzioni di salvataggio +PREFERENCES_THUMBSIZE;Dimensione miniature +PROFILEPANEL_FILEDLGFILTERANY;Qualsiasi file +PROFILEPANEL_FILEDLGFILTERPP;Profili di postelaborazione +PROFILEPANEL_LABEL;Profili di postelaborazione +PROFILEPANEL_LOADDLGLABEL;Carico i parametri di postelaborazione... +PROFILEPANEL_PCUSTOM;Personalizzato +PROFILEPANEL_PFILE;Da file +PROFILEPANEL_PLASTPHOTO;Ultima foto +PROFILEPANEL_PLASTSAVED;Ultimo salvato +PROFILEPANEL_PROFILE;Profilo +PROFILEPANEL_SAVEDLGLABEL;Salvo i parametri di postelaborazione... +PROFILEPANEL_TOOLTIPCOPY;Copia il profilo corrente negli appunti +PROFILEPANEL_TOOLTIPLOAD;Carica profilo da file +PROFILEPANEL_TOOLTIPPASTE;Incolla il profilo dagli appunti +PROFILEPANEL_TOOLTIPSAVE;Salva il profilo corrente +PROGRESSBAR_DECODING;Decodifica file raw... +PROGRESSBAR_DEMOSAICING;Demosaicizzazione... +PROGRESSBAR_LOADING;Caricamento immagine... +PROGRESSBAR_LOADJPEG;Caricamento file JPEG... +PROGRESSBAR_LOADPNG;Caricamento file PNG... +PROGRESSBAR_LOADTIFF;Caricamento file TIFF... +PROGRESSBAR_PROCESSING;Elaborazione immagine... +PROGRESSBAR_READY;Pronto. +PROGRESSBAR_SAVEJPEG;Salvataggio file JPEG... +PROGRESSBAR_SAVEPNG;Salvataggio file PNG... +PROGRESSBAR_SAVETIFF;Salvataggio file TIFF... +PROGRESSDLG_LOADING;Caricamento del file... +PROGRESSDLG_PROCESSING;Elaborazione dell'immagine... +PROGRESSDLG_SAVING;Salvataggio del file... +QINFO_FOCALLENGTH;Lunghezza focale +QINFO_ISO;ISO +QINFO_LENS;Obiettivo +QINFO_NOEXIF;Dati Exif non disponibili. +SAVEDLG_FILEFORMAT;Formato file +SAVEDLG_JPEGQUAL;Qualità JPEG +SAVEDLG_JPGFILTER;file JPEG +SAVEDLG_PNGCOMPR;Compressione PNG +SAVEDLG_PNGFILTER;file PNG +SAVEDLG_PUTTOQUEUE;Inserisci nella coda di sviluppo +SAVEDLG_PUTTOQUEUEHEAD;Put to the head of the processing queue +SAVEDLG_PUTTOQUEUETAIL;Put to the end of the processing queue +SAVEDLG_SAVEIMMEDIATELY;Salva subito +SAVEDLG_SAVESPP;Salva i parametri di elaborazione assieme all'immagine +SAVEDLG_TIFFFILTER;file TIFF +TOOLBAR_TOOLTIP_CROP;Ritaglia selezione (shortcut key: C) +TOOLBAR_TOOLTIP_HAND;Strumento mano (shortcut key: N) +TOOLBAR_TOOLTIP_STRAIGHTEN;Seleziona linea dritta (shortcut key: S) +TOOLBAR_TOOLTIP_WB;Bilanciamento del bianco puntuale (shortcut key: W) +TP_CACORRECTION_BLUE;Blu +TP_CACORRECTION_LABEL;Correzione A/C +TP_CACORRECTION_RED;Rosso +TP_CHMIXER_BLUE;Blu +TP_CHMIXER_GREEN;Verde +TP_CHMIXER_LABEL;Miscelatore canali +TP_CHMIXER_RED;Rosso +TP_COARSETRAF_DEGREE;Angolo: +TP_COARSETRAF_TOOLTIP_HFLIP;Rifletti orizzontalmente +TP_COARSETRAF_TOOLTIP_ROTLEFT;Ruota a sinistra +TP_COARSETRAF_TOOLTIP_ROTRIGHT;Ruota a destra +TP_COARSETRAF_TOOLTIP_VFLIP;Rifletti verticalmente +TP_COLORBOOST_ACHANNEL;canale "a" +TP_COLORBOOST_AMOUNT;Quantità +TP_COLORBOOST_AVOIDCOLORCLIP;Previeni tosaggio dei colori +TP_COLORBOOST_BCHANNEL;canale "b" +TP_COLORBOOST_CHAB;a & b +TP_COLORBOOST_CHANNEL;Canale +TP_COLORBOOST_CHSEPARATE;separati +TP_COLORBOOST_ENABLESATLIMITER;Abilita limite di saturazione +TP_COLORBOOST_LABEL;Potenziamento colore +TP_COLORBOOST_SATLIMIT;Limite di saturazione +TP_COLORDENOISE_EDGESENSITIVE;Sensibile ai bordi +TP_COLORDENOISE_EDGETOLERANCE;Tolleranza bordi +TP_COLORDENOISE_LABEL;Riduzione rumore crominanza +TP_COLORDENOISE_RADIUS;Raggio +TP_COLORSHIFT_BLUEYELLOW;Blu-Giallo +TP_COLORSHIFT_GREENMAGENTA;Verde-Magenta +TP_COLORSHIFT_LABEL;Spostamento colore +TP_CROP_DPI;DPI= +TP_CROP_FIXRATIO;Rapporto fisso: +TP_CROP_GTDIAGONALS;Regola delle diagonali +TP_CROP_GTHARMMEANS1;Media armonica 1 +TP_CROP_GTHARMMEANS2;Media armonica 2 +TP_CROP_GTHARMMEANS3;Media armonica 3 +TP_CROP_GTHARMMEANS4;Media armonica 4 +TP_CROP_GTNONE;Nessuna +TP_CROP_GTRULETHIRDS;Regola dei terzi +TP_CROP_GUIDETYPE;Tipo di guida: +TP_CROP_H;A +TP_CROP_LABEL;Ritaglia +TP_CROP_SELECTCROP; Seleziona Area +TP_CROP_W;L +TP_CROP_X;x +TP_CROP_Y;y +TP_DISTORTION_AMOUNT;Quantità +TP_DISTORTION_LABEL;Distorsione +TP_EXPOSURE_AUTOLEVELS;Livelli automatici +TP_EXPOSURE_BLACKLEVEL;Nero +TP_EXPOSURE_BRIGHTNESS;Luminosità +TP_EXPOSURE_CLIP;Tosaggio +TP_EXPOSURE_COMPRHIGHLIGHTS;Compressione alteluci +TP_EXPOSURE_COMPRSHADOWS;Compressione ombre +TP_EXPOSURE_CONTRAST;Contrasto +TP_EXPOSURE_CURVEEDITOR;Curva di tono +TP_EXPOSURE_EXPCOMP;Compensazione esposizione +TP_EXPOSURE_LABEL;Esposizione +TP_HLREC_CIELAB;Miscelazione in CIELab +TP_HLREC_COLOR;Propagazione di crominanza +TP_HLREC_LABEL;Recupero alteluci +TP_HLREC_LUMINANCE;Recupero di luminanza +TP_HLREC_METHOD;Metodo: +TP_ICM_FILEDLGFILTERANY;Qualsiasi file +TP_ICM_FILEDLGFILTERICM;Profili ICC +TP_ICM_GAMMABEFOREINPUT;Il profilo applica il gamma +TP_ICM_INPUTCAMERA;Predefinito della fotocamera +TP_ICM_INPUTCUSTOM;Personalizzato +TP_ICM_INPUTDLGLABEL;Seleziona il profilo ICC di ingresso... +TP_ICM_INPUTEMBEDDED;Incorporato, se possibile +TP_ICM_INPUTPROFILE;Profilo di ingresso +TP_ICM_LABEL;ICM +TP_ICM_NOICM;Nessun ICM: uscita in sRGB +TP_ICM_OUTPUTDLGLABEL;Seleziona il profilo ICC di uscita... +TP_ICM_OUTPUTPROFILE;Profilo di uscita +TP_ICM_SAVEREFERENCE;Salva immagine di riferimento per la profilazione +TP_ICM_WORKINGPROFILE;Profilo di lavoro +TP_LUMACURVE_BLACKLEVEL;Nero +TP_LUMACURVE_BRIGHTNESS;Luminosità +TP_LUMACURVE_COMPRHIGHLIGHTS;Compressione alteluci +TP_LUMACURVE_COMPRSHADOWS;Compressione ombre +TP_LUMACURVE_CONTRAST;Contrasto +TP_LUMACURVE_CURVEEDITOR;Curva di luminanza +TP_LUMACURVE_LABEL;Curva di luminanza +TP_LUMADENOISE_EDGETOLERANCE;Tolleranza bordi +TP_LUMADENOISE_LABEL;Riduzione rumore luminanza +TP_LUMADENOISE_RADIUS;Raggio +TP_RESIZE_BICUBIC;Bicubico +TP_RESIZE_BICUBICSF;Bicubico (più sfumato) +TP_RESIZE_BICUBICSH;Bicubico (più definito) +TP_RESIZE_BILINEAR;Bilineare +TP_RESIZE_FULLSIZE;Dimensione dell'intera immagine: +TP_RESIZE_H;A: +TP_RESIZE_LABEL;Ridimensiona +TP_RESIZE_METHOD;Metodo: +TP_RESIZE_NEAREST;Più fedele +TP_RESIZE_SCALE;Scala +TP_RESIZE_W;L: +TP_ROTATE_AUTOCROP;Ritaglio automatico +TP_ROTATE_DEGREE;Angolo +TP_ROTATE_FILL;Adatta +TP_ROTATE_LABEL;Ruota +TP_ROTATE_SELECTLINE; Seleziona linea dritta +TP_SHADOWSHLIGHTS_HIGHLIGHTS;Alteluci +TP_SHADOWSHLIGHTS_HLTONALW;Ampiezza tonale +TP_SHADOWSHLIGHTS_LABEL;Ombre/Alteluci +TP_SHADOWSHLIGHTS_LOCALCONTR;Contrasto locale +TP_SHADOWSHLIGHTS_RADIUS;Raggio +TP_SHADOWSHLIGHTS_SHADOWS;Ombre +TP_SHADOWSHLIGHTS_SHTONALW;Ampiezza tonale +TP_SHARPENING_AMOUNT;Quantità +TP_SHARPENING_EDRADIUS;Raggio +TP_SHARPENING_EDTOLERANCE;Tolleranza bordi +TP_SHARPENING_HALOCONTROL;Controllo alone +TP_SHARPENING_HCAMOUNT;Quantità +TP_SHARPENING_LABEL;Nitidezza +TP_SHARPENING_METHOD;Metodo +TP_SHARPENING_ONLYEDGES;Definisci solo i bordi +TP_SHARPENING_RADIUS;Raggio +TP_SHARPENING_RLD;Deconvoluzione RL +TP_SHARPENING_RLD_AMOUNT;Quantità +TP_SHARPENING_RLD_DAMPING;Smorzamento +TP_SHARPENING_RLD_ITERATIONS;Iterazioni +TP_SHARPENING_THRESHOLD;Soglia +TP_SHARPENING_USM;Maschera di Contrasto +TP_VIGNETTING_AMOUNT;Quantità +TP_VIGNETTING_LABEL;Correzione vignettatura +TP_VIGNETTING_RADIUS;Raggio +TP_WBALANCE_AUTO;Automatico +TP_WBALANCE_CAMERA;Fotocamera +TP_WBALANCE_CUSTOM;Personalizzato +TP_WBALANCE_GREEN;Tinta +TP_WBALANCE_LABEL;Bilanciamento del bianco +TP_WBALANCE_METHOD;Metodo +TP_WBALANCE_SIZE;Dimensione: +TP_WBALANCE_SPOTWB;Punto BB manuale +TP_WBALANCE_TEMPERATURE;Temperatura +ZOOMBAR_DETAIL;Dettaglio +ZOOMBAR_HUGE;Enorme +ZOOMBAR_LARGE;Grande +ZOOMBAR_NORMAL;Normale +ZOOMBAR_PREVIEW;Anteprima +ZOOMBAR_SCALE;Scala +ZOOMBAR_SMALL;Piccola diff --git a/release/languages/japanese b/release/languages/japanese new file mode 100755 index 000000000..f36ed69e1 --- /dev/null +++ b/release/languages/japanese @@ -0,0 +1,576 @@ +# Japanese translation of RawTherapee 2.4m1 +# 2008-04-24 by A3novy +ADJUSTER_RESET_TO_DEFAULT;ãƒªã‚»ãƒƒãƒˆåˆæœŸåŒ– +CURVEEDITOR_FILEDLGFILTERANY;ã™ã¹ã¦ã®ãƒ•ァイル +CURVEEDITOR_FILEDLGFILTERCURVE;カーブ・ファイル +CURVEEDITOR_LINEAR;リニア +CURVEEDITOR_LOADDLGLABEL;カーブ読ã¿è¾¼ã¿... +CURVEEDITOR_SAVEDLGLABEL;カーブä¿å­˜... +CURVEEDITOR_TOOLTIPLINEAR;リニアã«ãƒªã‚»ãƒƒãƒˆ +CURVEEDITOR_TOOLTIPLOAD;ファイルã‹ã‚‰èª­ã¿è¾¼ã¿ +CURVEEDITOR_TOOLTIPSAVE;カーブä¿å­˜ +EXIFFILTER_APERTURE;Aperture +EXIFFILTER_CAMERA;Camera +EXIFFILTER_DIALOGLABEL;Exif Filter +EXIFFILTER_FOCALLEN;Focal Length +EXIFFILTER_ISO;ISO +EXIFFILTER_LENS;Lens +EXIFFILTER_SHUTTER;Shutter +EXIFPANEL_ADDEDIT;追加/編集 +EXIFPANEL_ADDEDITHINT;æ–°ã—ã„タグを追加ã€ã¾ãŸã¯ã‚¿ã‚°ã®ç·¨é›† +EXIFPANEL_ADDTAGDLG_ENTERVALUE;値 入力 +EXIFPANEL_ADDTAGDLG_SELECTTAG;ã‚¿ã‚°é¸æŠž +EXIFPANEL_ADDTAGDLG_TITLE;追加/タグ編集 +EXIFPANEL_KEEP;キープ +EXIFPANEL_KEEPHINT;é¸æŠžã‚¿ã‚°ã‚’å‡ºåŠ›ãƒ•ã‚¡ã‚¤ãƒ«ã«æ›¸ã込む場åˆã‚­ãƒ¼ãƒ—ã™ã‚‹ +EXIFPANEL_REMOVE;リムーブ +EXIFPANEL_REMOVEHINT;é¸æŠžã‚¿ã‚°ã‚’å‡ºåŠ›ãƒ•ã‚¡ã‚¤ãƒ«ã«æ›¸ã込む場åˆå–り除ã +EXIFPANEL_RESET;リセット +EXIFPANEL_RESETALL;ã™ã¹ã¦ãƒªã‚»ãƒƒãƒˆ +EXIFPANEL_RESETALLHINT;ã™ã¹ã¦å…ƒã®å€¤ã«ãƒªã‚»ãƒƒãƒˆ +EXIFPANEL_RESETHINT;é¸æŠžã‚¿ã‚°ã‚’å…ƒã®å€¤ã«ãƒªã‚»ãƒƒãƒˆ +EXIFPANEL_SUBDIRECTORY;サブディレクトリ +FILEBROWSER_APPLYPROFILE;Apply profile +FILEBROWSER_ARRANGEMENTHINT;Change between vertical/horizontal alignment of thumbnails +FILEBROWSER_CLEARPROFILE;Clear profile +FILEBROWSER_COPYPROFILE;Copy profile +FILEBROWSER_DELETEDLGLABEL;File delete confirmation +FILEBROWSER_DELETEDLGMSG;Are you sure you want to delete the selected %1 files? +FILEBROWSER_EMPTYTRASH;Empty Trash +FILEBROWSER_EMPTYTRASHHINT;Permanently delete the files of the trash +FILEBROWSER_EXIFFILTERAPPLY;Apply +FILEBROWSER_EXIFFILTERAPPLYHINT;Switch on/off exif filter of the file browser +FILEBROWSER_EXIFFILTERLABEL;Exif Filter +FILEBROWSER_EXIFFILTERSETTINGS;Setup +FILEBROWSER_EXIFFILTERSETTINGSHINT;Change settings of the exif filter +FILEBROWSER_PARTIALPASTEPROFILE;Partial paste +FILEBROWSER_PASTEPROFILE;Paste profile +FILEBROWSER_POPUPCANCELJOB;Cancel job +FILEBROWSER_POPUPMOVEEND;Move to end of queue +FILEBROWSER_POPUPMOVEHEAD;Move to head of queue +FILEBROWSER_POPUPOPEN;Open +FILEBROWSER_POPUPPROCESS;Put to processing queue +FILEBROWSER_POPUPRANK1;Rank 1 +FILEBROWSER_POPUPRANK2;Rank 2 +FILEBROWSER_POPUPRANK3;Rank 3 +FILEBROWSER_POPUPRANK4;Rank 4 +FILEBROWSER_POPUPRANK5;Rank 5 +FILEBROWSER_POPUPREMOVE;Remove from filesystem +FILEBROWSER_POPUPRENAME;Rename +FILEBROWSER_POPUPSELECTALL;Select all +FILEBROWSER_POPUPTRASH;Move to trash +FILEBROWSER_POPUPUNRANK;Unrank +FILEBROWSER_POPUPUNTRASH;Remove from trash +FILEBROWSER_PROCESSINGSETTINGS;Settings +FILEBROWSER_PROCESSINGSETTINGSHINT;Set the file format and output directory +FILEBROWSER_RENAMEDLGLABEL;Rename file +FILEBROWSER_RENAMEDLGMSG;Rename file "%1" to: +FILEBROWSER_SHOWDIRHINT;Show all images of the directory +FILEBROWSER_SHOWQUEUEHINT;Show content of the processing queue +FILEBROWSER_SHOWRANK1HINT;Show images ranked as 1 star +FILEBROWSER_SHOWRANK2HINT;Show images ranked as 2 star +FILEBROWSER_SHOWRANK3HINT;Show images ranked as 3 star +FILEBROWSER_SHOWRANK4HINT;Show images ranked as 4 star +FILEBROWSER_SHOWRANK5HINT;Show images ranked as 5 star +FILEBROWSER_SHOWTRASHHINT;Show content of the trash +FILEBROWSER_SHOWUNRANKHINT;Show unranked images +FILEBROWSER_STARTPROCESSING;Start Processing +FILEBROWSER_STARTPROCESSINGHINT;Start processing/saving of images in the queue +FILEBROWSER_STOPPROCESSING;Stop processing +FILEBROWSER_STOPPROCESSINGHINT;Stop processing of images +FILEBROWSER_THUMBSIZE;Thumb. size +FILEBROWSER_ZOOMINHINT;Increase thumbnail size +FILEBROWSER_ZOOMOUTHINT;Decrease thumbnail size +GENERAL_ABOUT;ã«ã¤ã„㦠+GENERAL_CANCEL;キャンセル +GENERAL_DISABLE;無効 +GENERAL_DISABLED;無効 +GENERAL_ENABLE;有効 +GENERAL_ENABLED;有効 +GENERAL_LANDSCAPE;横 +GENERAL_LOAD;読ã¿è¾¼ã¿ +GENERAL_NA;n/a +GENERAL_NO;No +GENERAL_OK;OK +GENERAL_PORTRAIT;縦 +GENERAL_SAVE;ä¿å­˜ +GENERAL_YES;Yes +HISTOGRAM_LABEL;Histogram +HISTOGRAM_TOOLTIP_B;ブルー・ヒストグラム 表示/éžè¡¨ç¤º +HISTOGRAM_TOOLTIP_G;グリーン・ヒストグラム 表示/éžè¡¨ç¤º +HISTOGRAM_TOOLTIP_L;CIELABè¼åº¦ãƒ»ãƒ’ストグラム 表示/éžè¡¨ç¤º +HISTOGRAM_TOOLTIP_R;レッド・ヒストグラム 表示/éžè¡¨ç¤º +HISTORY_CHANGED;変更ã•れã¾ã—㟠+HISTORY_CUSTOMCURVE;カスタムカーブ +HISTORY_DELSNAPSHOT;消去スナップショット +HISTORY_FROMCLIPBOARD;From clipboard +HISTORY_LABEL;ヒストリー +HISTORY_MSG_10;シャドウ補正 +HISTORY_MSG_11;トーンカーブ +HISTORY_MSG_12;露出 オート +HISTORY_MSG_13;露出 クリッピング +HISTORY_MSG_14;è¼åº¦ 明る㕠+HISTORY_MSG_15;è¼åº¦ コントラスト +HISTORY_MSG_16;è¼åº¦ 黒レベル +HISTORY_MSG_17;è¼åº¦ ãƒã‚¤ãƒ©ã‚¤ãƒˆåœ§ç¸® +HISTORY_MSG_18;è¼åº¦ シャドウ圧縮 +HISTORY_MSG_19;è¼åº¦ カーブ +HISTORY_MSG_1;写真を読ã¿è¾¼ã¿ã¾ã—㟠+HISTORY_MSG_20;シャープ +HISTORY_MSG_21;シャープ åŠå¾„ +HISTORY_MSG_22;シャープ é‡ +HISTORY_MSG_23;シャープ ã—ãã„値 +HISTORY_MSG_24;シャープ エッジã®ã¿ +HISTORY_MSG_25;シャープ エッジ検出 åŠå¾„ +HISTORY_MSG_26;シャープ エッジ許容 +HISTORY_MSG_27;シャープ フレア抑制 +HISTORY_MSG_28;フレア抑制 é‡ +HISTORY_MSG_29;シャープ æ–¹å¼ +HISTORY_MSG_2;プロファイルを読ã¿ã“ã¿ã¾ã—㟠+HISTORY_MSG_30;RL デコンボリューション åŠå¾„ +HISTORY_MSG_31;RL デコンボリューション é‡ +HISTORY_MSG_32;RL デコンボリューション 減衰 +HISTORY_MSG_33;RL デコンボリューション 繰返㗠+HISTORY_MSG_34;カラークリッピングãªã— +HISTORY_MSG_35;彩度増化制é™ãƒ»æœ‰åй +HISTORY_MSG_36;å½©åº¦å¢—åŒ–åˆ¶é™ +HISTORY_MSG_37;カラー 増化 +HISTORY_MSG_38;ホワイトãƒãƒ©ãƒ³ã‚¹ æ–¹å¼ +HISTORY_MSG_39;色温度 +HISTORY_MSG_3;プロファイル変更 +HISTORY_MSG_40;ホワイトãƒãƒ©ãƒ³ã‚¹ 色åˆã„ +HISTORY_MSG_41;カラー シフト "A" +HISTORY_MSG_42;カラー シフト "B" +HISTORY_MSG_43;è¼åº¦ãƒŽã‚¤ã‚ºé™¤åŽ» +HISTORY_MSG_44;è¼åº¦ãƒŽã‚¤ã‚ºé™¤åŽ» åŠå¾„ +HISTORY_MSG_45;è¼åº¦ãƒŽã‚¤ã‚ºé™¤åŽ» エッジã®è¨±å®¹åº¦ +HISTORY_MSG_46;カラー ノイズ除去 +HISTORY_MSG_47;カラー ノイズ除去 åŠå¾„ +HISTORY_MSG_48;カラー ノイズ除去 エッジã®è¨±å®¹åº¦ +HISTORY_MSG_49;カラー ノイズ除去 ã‚¨ãƒƒã‚¸ã®æ„Ÿåº¦ +HISTORY_MSG_4;ヒストリー・ブラウジング +HISTORY_MSG_50;シャドウï¼ãƒã‚¤ãƒ©ã‚¤ãƒˆãƒ»ãƒ„ール +HISTORY_MSG_51;ãƒã‚¤ãƒ©ã‚¤ãƒˆå¢—化 +HISTORY_MSG_52;シャドウ増化 +HISTORY_MSG_53;ãƒã‚¤ãƒ©ã‚¤ãƒˆ 色調ã®å¹… +HISTORY_MSG_54;シャドウ 色調ã®å¹… +HISTORY_MSG_55;局部的コントラスト +HISTORY_MSG_56;シャドウï¼ãƒã‚¤ãƒ©ã‚¤ãƒˆ åŠå¾„ +HISTORY_MSG_57;90度 回転 +HISTORY_MSG_58;æ°´å¹³ã«å転 +HISTORY_MSG_59;垂直ã«å転 +HISTORY_MSG_5;明る㕠+HISTORY_MSG_60;回転 +HISTORY_MSG_61;回転 +HISTORY_MSG_62;歪曲åŽå·®è£œæ­£ +HISTORY_MSG_63;ã‚¹ãƒŠãƒƒãƒ—ã‚·ãƒ§ãƒƒãƒˆé¸æŠž +HISTORY_MSG_64;写真切り抜ã +HISTORY_MSG_65;色åŽå·®è£œæ­£ +HISTORY_MSG_66;ãƒã‚¤ãƒ©ã‚¤ãƒˆä¿®å¾© +HISTORY_MSG_67;ãƒã‚¤ãƒ©ã‚¤ãƒˆä¿®å¾© é‡ +HISTORY_MSG_68;ãƒã‚¤ãƒ©ã‚¤ãƒˆä¿®å¾© æ–¹å¼ +HISTORY_MSG_69;作業カラースペース +HISTORY_MSG_6;コントラスト +HISTORY_MSG_70;出力カラースペース +HISTORY_MSG_71;入力カラースペース +HISTORY_MSG_72;周辺光é‡è£œæ­£ +HISTORY_MSG_73;ãƒãƒ£ãƒ³ãƒãƒ«ãƒŸã‚­ã‚µãƒ¼ +HISTORY_MSG_74;リサイズ スケール +HISTORY_MSG_75;リサイズ æ–¹å¼ +HISTORY_MSG_76;Exif メタデータ +HISTORY_MSG_77;IPTC メタデータ +HISTORY_MSG_7;黒レベル +HISTORY_MSG_8;露出補正 +HISTORY_MSG_9;ãƒã‚¤ãƒ©ã‚¤ãƒˆè£œæ­£ +HISTORY_NEWSNAPSHOT;æ–°è¦ã‚¹ãƒŠãƒƒãƒ—ショット +HISTORY_NEWSNAPSHOTAS;ラベル +HISTORY_NEWSSDIALOGLABEL;スナップショットã®ãƒ©ãƒ™ãƒ«: +HISTORY_NEWSSDIALOGTITLE;æ–°è¦ã‚¹ãƒŠãƒƒãƒ—ショット追加 +HISTORY_SETTO;セット: +HISTORY_SNAPSHOT;スナップショット +HISTORY_SNAPSHOTS;スナップショット +ICMPANEL_FILEDLGFILTERANY;ã™ã¹ã¦ã®ãƒ•ァイル +ICMPANEL_FILEDLGFILTERICM;ICCプロファイル ファイル +ICMPANEL_GAMMABEFOREINPUT;プロファイルã«ã‚¬ãƒ³ãƒžé©å¿œ +ICMPANEL_INPUTCAMERA;カメラã®è¨­å®šå€¤ +ICMPANEL_INPUTCUSTOM;カスタム +ICMPANEL_INPUTDLGLABEL;入力 ICC ãƒ—ãƒ­ãƒ•ã‚¡ã‚¤ãƒ«ã‚’é¸æŠž... +ICMPANEL_INPUTEMBEDDED;埋ã‚è¾¼ã¿ä½¿ç”¨, å¯èƒ½ãªã‚‰ +ICMPANEL_INPUTPROFILE;入力プロファイル +ICMPANEL_NOICM;No ICM: sRGB 出力 +ICMPANEL_OUTPUTDLGLABEL;出力 ICC ãƒ—ãƒ­ãƒ•ã‚¡ã‚¤ãƒ«ã‚’é¸æŠž... +ICMPANEL_OUTPUTPROFILE;出力プロファイル +ICMPANEL_SAVEREFERENCE;プロファイリングã®å‚ç…§ã™ã‚‹ç”»åƒã‚’ä¿å­˜ +ICMPANEL_WORKINGPROFILE;作業プロファイル +IMAGEAREA_DETAILVIEW;詳細 +IPTCPANEL_AUTHOR;作æˆè€… +IPTCPANEL_AUTHORHINT;作æˆè€…ã®åå‰ã€ãŸã¨ãˆã°ç­†è€…ã€ã‚«ãƒ¡ãƒ©ãƒžãƒ³ã€ã‚°ãƒ©ãƒ•ィックス作æˆè€… (作æˆè€…). +IPTCPANEL_AUTHORSPOSITION;作æˆè€…ã®è‚©æ›¸ +IPTCPANEL_AUTHORSPOSITIONHINT;作æˆè€…ã®è‚©æ›¸ã‹ä½œå“ã®ä½œæˆè€…é”(作æˆè€… 肩書). +IPTCPANEL_CAPTION;説明 +IPTCPANEL_CAPTIONHINT;ãƒ‡ãƒ¼ã‚¿ã®æœ¬æ–‡ã®è¨˜è¿°(説明--è¦ç´„) +IPTCPANEL_CAPTIONWRITER;説明記入者 +IPTCPANEL_CAPTIONWRITERHINT;ç”»åƒã‚’編集修正ã™ã‚‹ã€ã¾ãŸã¯èª¬æ˜Ž/è¦ç´„ã®åŸ·ç­†ã«ã‹ã‹ã‚る人ã®åå‰ (記入者--編集者). +IPTCPANEL_CATEGORY;カテゴリ +IPTCPANEL_CATEGORYHINT;ç”»åƒã®ä¸»é¡Œã‚’識別ã™ã‚‹3文字コード (カテゴリ). +IPTCPANEL_CITY;å¸‚ç”ºæ‘ +IPTCPANEL_CITYHINT;撮影ã•れãŸå¸‚ç”ºæ‘ (市町æ‘). +IPTCPANEL_COPYHINT;IPTC設定をクリップボードã«ã‚³ãƒ”ー +IPTCPANEL_COPYRIGHT;著作権 +IPTCPANEL_COPYRIGHTHINT;著作権情報ã«å¿…è¦ãªäº‹æŸ„ (著作権情報). +IPTCPANEL_COUNTRY;国 +IPTCPANEL_COUNTRYHINT;国åã€/ç”»åƒãŒæ’®å½±ãƒ»ä½œæˆã•れãŸå›½ (国--撮影国). +IPTCPANEL_CREDIT;クレジット +IPTCPANEL_CREDITHINT;ç”»åƒã®æä¾›å…ƒã®è­˜åˆ¥, å¿…ãšã—も所有者/作æˆè€…ã§ã¯ãªã„ (クレジット). +IPTCPANEL_DATECREATED;ä½œæˆæ—¥ +IPTCPANEL_DATECREATEDHINT;ç”»åƒã®çŸ¥çš„内容ãŒä½œæˆã•ã‚ŒãŸæ—¥ä»˜; フォーマット: JJJJMMTT (ä½œæˆæ—¥). +IPTCPANEL_EMBEDDED;埋ã‚込㿠+IPTCPANEL_EMBEDDEDHINT;ç”»åƒã«åŸ‹ã‚è¾¼ã¾ã‚ŒãŸIPTCデータã«ãƒªã‚»ãƒƒãƒˆ +IPTCPANEL_HEADLINE;見出㗠+IPTCPANEL_HEADLINEHINT;ç”»åƒã®å†…å®¹ã®æ¦‚è¦ã‚’示ã™è¨˜å…¥é …ç›® (見出ã—). +IPTCPANEL_INSTRUCTIONS;編集注記 +IPTCPANEL_INSTRUCTIONSHINT;ç”»åƒã®ä½¿ç”¨ã«é–¢ã™ã‚‹ãã®ä»–ã®ç‰¹è¨˜äº‹é … (編集注記). +IPTCPANEL_KEYWORDS;キーワード +IPTCPANEL_KEYWORDSHINT;情報検索ã«ä½¿ç”¨ã™ã‚‹å˜èªž (キーワード). +IPTCPANEL_PASTEHINT;IPTC設定をクリップボードã‹ã‚‰è²¼ã‚Šä»˜ã‘ +IPTCPANEL_PROVINCE;州・県 +IPTCPANEL_PROVINCEHINT;撮影ã•れãŸåœ°åŸŸ/州・県(地域--州・県). +IPTCPANEL_RESET;リセット +IPTCPANEL_RESETHINT;デフォルトã®ãƒ—ロファイルã«ãƒªã‚»ãƒƒãƒˆ +IPTCPANEL_SOURCE;ソース +IPTCPANEL_SOURCEHINT;ç”»åƒã®è‘—ä½œæ¨©ä¿æœ‰è€… (ソース). +IPTCPANEL_SUPPCATEGORIES;カテゴリ補助 +IPTCPANEL_SUPPCATEGORIESHINT;ã•らã«ç´°ã‹ãç”»åƒã®ä¸»é¡Œ (カテゴリ補助). +IPTCPANEL_TITLE;タイトル +IPTCPANEL_TITLEHINT;ç”»åƒã®è¡¨é¡Œã‚’簡略㫠(タイトル). +IPTCPANEL_TRANSREFERENCE;é€ä¿¡è¨¼æ˜Ž +IPTCPANEL_TRANSREFERENCEHINT;オリジナルã®é€ä¿¡è¨¼æ˜Žã®ä½ç½®ã‚’表ã™ã‚³ãƒ¼ãƒ‰ (オリジナル é€ä¿¡è¨¼æ˜Ž). +MAIN_BUTTON_PREFERENCES;環境設定 +MAIN_BUTTON_SAVE;イメージã®ä¿å­˜ +MAIN_BUTTON_SAVEAS;別åä¿å­˜ +MAIN_BUTTON_SENDTOEDITOR;Send to editor +MAIN_MSG_ALREADYEXISTS;ファイルã¯ã™ã§ã«å­˜åœ¨ã—ã¾ã™ +MAIN_MSG_CANNOTLOAD;イメージを読ã¿è¾¼ã¿ã§ãã¾ã›ã‚“ +MAIN_MSG_CANNOTSAVE;ファイルä¿å­˜ã‚¨ãƒ©ãƒ¼ +MAIN_MSG_CANNOTSTARTEDITOR;Can not start editor. +MAIN_MSG_CANNOTSTARTEDITOR_SECONDARY;Please set the correct path in the "Preferences" dialog. +MAIN_MSG_EXITJOBSINQUEUEINFO;Unprocessed images in the queue will be lost on exit. +MAIN_MSG_EXITJOBSINQUEUEQUEST;Are you sure you want to exit? There are unprocessed images waiting in the queue. +MAIN_MSG_JOBSINQUEUE; 作業中・・・ +MAIN_MSG_QOVERWRITE;上書ãã—ã¾ã™ã‹? +MAIN_TAB_BASIC;ベーシック +MAIN_TAB_COLOR;Color +MAIN_TAB_DETAIL;Detail +MAIN_TAB_EXIF;Exif +MAIN_TAB_EXPOSURE;Exposure +MAIN_TAB_ICM;ICM +MAIN_TAB_IPTC;IPTC +MAIN_TAB_METADATA;Metadata +MAIN_TAB_TRANSFORM;変形 (shortcut key: F) +MAIN_TOOLTIP_HIDEFP;ボタンパãƒãƒ« 表示/éžè¡¨ç¤º(ディレクトリã¨ãƒ•ァイルブラウザ, shortcut key: H) +MAIN_TOOLTIP_HIDEHP;左パãƒãƒ« 表示/éžè¡¨ç¤º (ヒストリーå«ã‚€) +MAIN_TOOLTIP_INDCLIPPEDH;ãƒã‚¤ãƒ©ã‚¤ãƒˆãƒ»ã‚¯ãƒªãƒƒãƒ”ング領域ã®è¡¨ç¤º +MAIN_TOOLTIP_INDCLIPPEDS;シャドウ・クリッピング領域ã®è¡¨ç¤º +MAIN_TOOLTIP_PREFERENCES;設定ã™ã‚‹ +MAIN_TOOLTIP_QINFO;ã‚¤ãƒ¡ãƒ¼ã‚¸ã®æƒ…å ± +MAIN_TOOLTIP_SAVE;デフォルトã®ãƒ•ォルダーã«ä¿å­˜ +MAIN_TOOLTIP_SAVEAS;ãƒ•ã‚©ãƒ«ãƒ€ãƒ¼ã‚’é¸æŠžã—ã¦ä¿å­˜ +PARTIALPASTE_BASICGROUP;Basic settings +PARTIALPASTE_CACORRECTION;C/A correction +PARTIALPASTE_COARSETRANS;90 deg rotation / flipping +PARTIALPASTE_COLORBOOST;Color boost +PARTIALPASTE_COLORDENOISE;Color denoise +PARTIALPASTE_COLORGROUP;Color related settings +PARTIALPASTE_COLORMIXER;Color mixer +PARTIALPASTE_COLORSHIFT;Color shift +PARTIALPASTE_COMPOSITIONGROUP;Composition settings +PARTIALPASTE_CROP;Crop +PARTIALPASTE_DIALOGLABEL;Partial paste processing profile +PARTIALPASTE_DISTORTION;Distortion correction +PARTIALPASTE_EXIFCHANGES;Changes to exif data +PARTIALPASTE_EXPOSURE;Exposure +PARTIALPASTE_HLRECOVERY;Highlight recovery +PARTIALPASTE_ICMSETTINGS;ICM settings +PARTIALPASTE_IPTCINFO;IPTC info +PARTIALPASTE_LENSGROUP;Lens related settings +PARTIALPASTE_LUMACURVE;Luminance curve +PARTIALPASTE_LUMADENOISE;Luminance noise reduction +PARTIALPASTE_LUMINANCEGROUP;Luminance related settings +PARTIALPASTE_METAICMGROUP;Metadata/ICM settings +PARTIALPASTE_RESIZE;Resize +PARTIALPASTE_ROTATION;Rotation +PARTIALPASTE_SHADOWSHIGHLIGHTS;Shadows/Highlights +PARTIALPASTE_SHARPENING;Sharpening +PARTIALPASTE_VIGNETTING;Vignetting correction +PARTIALPASTE_WHITEBALANCE;White balance +PREFERENCES_APPLNEXTSTARTUP;次ã®èµ·å‹•時ã«é©å¿œ +PREFERENCES_BLINKCLIPPED;クリッピング領域ã®ç‚¹æ»… +PREFERENCES_CACHECLEARALL;Clear All +PREFERENCES_CACHECLEARPROFILES;Clear Profiles +PREFERENCES_CACHECLEARTHUMBS;Clear Thumbnails +PREFERENCES_CACHEFORMAT1;Proprietary (faster and better quality) +PREFERENCES_CACHEFORMAT2;JPEG (smaller disk footprint) +PREFERENCES_CACHEMAXENTRIES;Maximal Number of Cache Entries +PREFERENCES_CACHEOPTS;Cache Options +PREFERENCES_CACHESTRAT1;Prefer Speed to Low Memory Consumption +PREFERENCES_CACHESTRAT2;Prefer Low Memory Consumption to Speed +PREFERENCES_CACHESTRAT;Cache Strategy +PREFERENCES_CACHETHUMBFORM;Cache Thumbnail Format +PREFERENCES_CACHETHUMBHEIGHT;Maximal Thumbnail Height +PREFERENCES_CLEARDLG_LINE1;Clearing cache +PREFERENCES_CLEARDLG_LINE2;This may take a few seconds. +PREFERENCES_CLEARDLG_TITLE;Please wait +PREFERENCES_CLIPPINGIND;クリッピング領域ã®è¡¨ç¤º +PREFERENCES_CMETRICINTENT;レンダリングインテント +PREFERENCES_DATEFORMAT;データフォーマット +PREFERENCES_DATEFORMATHINT;æ¬¡ã®æ›¸å¼æŒ‡å®šæ–‡å­—を使用ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™:\n%y : å¹´\n%m : 月\n%d : æ—¥\n\n例ã¨ã—ã¦, ãƒãƒ³ã‚¬ãƒªã‚¢ãƒ³è¨˜æ³•:\n%y/%m/%d +PREFERENCES_DEFAULTLANG;デフォルトã®è¨€èªž +PREFERENCES_DEFAULTTHEME;デフォルト テーマ +PREFERENCES_DEMOSAICINGALGO;ãƒ‡ãƒ¢ã‚¶ã‚¤ã‚¯å‡¦ç† +PREFERENCES_DIRHOME;ホーム・ディレクトリ +PREFERENCES_DIRLAST;最近å‚ç…§ã—ãŸãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª +PREFERENCES_DIROTHER;ä»– +PREFERENCES_DIRSELECTDLG;起動時ã®ã‚¤ãƒ¡ãƒ¼ã‚¸ãƒ»ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªé¸æŠž... +PREFERENCES_DIRSOFTWARE;インストール・ディレクトリ +PREFERENCES_DMETHOD;方法 +PREFERENCES_EDITORCMDLINE;Other command line +PREFERENCES_EXTERNALEDITOR;External editor +PREFERENCES_FALSECOLOR;å½è‰² 補間ステップ +PREFERENCES_FBROWSEROPTS;ファイルブラウザã®ã‚ªãƒ—ション +PREFERENCES_FILEFORMAT;ãƒ•ã‚¡ã‚¤ãƒ«å½¢å¼ +PREFERENCES_FORIMAGE;イメージファイル +PREFERENCES_FORRAW;RAW ファイル +PREFERENCES_GIMPPATH;GIMP installation directory +PREFERENCES_GTKTHEME;GTK デフォルト +PREFERENCES_HINT;ヒント +PREFERENCES_HLTHRESHOLD;ãƒã‚¤ãƒ©ã‚¤ãƒˆãƒ»ã‚¯ãƒªãƒƒãƒ”ング領域ã®ã—ãã„値 +PREFERENCES_ICCDIR;ICCプロファイルã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª +PREFERENCES_IMPROCPARAMS;イメージ処ç†ã®è¦å®šå€¤ +PREFERENCES_INTENT_ABSOLUTE;絶対的ãªè‰²åŸŸã‚’ç¶­æŒ +PREFERENCES_INTENT_PERCEPTUAL;知覚的 +PREFERENCES_INTENT_RELATIVE;相対的ãªè‰²åŸŸã‚’ç¶­æŒ +PREFERENCES_INTENT_SATURATION;彩度 +PREFERENCES_LIVETHUMBNAILS;Live Thumbnails (slower) +PREFERENCES_MONITORICC;モニタープロファイル +PREFERENCES_OUTDIR;出力ディレクトリ +PREFERENCES_OUTDIRFOLDER;Save to folder +PREFERENCES_OUTDIRFOLDERHINT;Put the saved images to the seledted folder +PREFERENCES_OUTDIRHINT;æ¬¡ã®æ›¸å¼æŒ‡å®šæ–‡å­—を使用ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nã“ã‚Œã‚‰ã®æ›¸å¼æŒ‡å®šæ–‡å­—ã¯ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã¨rawファイルã®ã‚µãƒ–パスを示ã—ã¾ã™.\n\n例ãˆã°, ã‚‚ã— /home/tom/image/02-09-2006/dsc0012.nefã‚’é–‹ã„ã¦ã„ãŸãªã‚‰, æ›¸å¼æŒ‡å®šæ–‡å­—ã®æ„味ã¯:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nã‚‚ã— å…ƒã®ã¨ã“ã‚ã«å‡ºåŠ›ç”»åƒã‚’ä¿å­˜ã—ãŸã„ãªã‚‰, ã“ã®ã‚ˆã†ã«æ›¸ãã¾ã™:\n%p1/%f\n\nã‚‚ã— å…ƒã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã®ã¨ã“ã‚ã®'converted'ディレクトリã®ä¸­ã«å‡ºåŠ›ç”»åƒã‚’ä¿å­˜ã—ãŸã„ãªã‚‰, ã“ã®ã‚ˆã†ã«æ›¸ãã¾ã™:\n%p1/converted/%f\n\nã‚‚ã— åŒã˜æ—¥ä»˜ã®ã‚µãƒ–ディレクトリをä¿ã£ãŸã¾ã¾'/home/tom/converted'ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã®ä¸­ã«å‡ºåŠ›ç”»åƒã‚’ä¿å­˜ã—ãŸã„ã®ãªã‚‰, ã“ã®ã‚ˆã†ã«æ›¸ãã¾ã™:\n%p2/converted/%d1/%f +PREFERENCES_OUTDIRTEMPLATE;Use Template +PREFERENCES_OUTDIRTEMPLATEHINT;You can use the following formatting strings:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nThese formatting strings refer to the directories and sub-paths of the path of the raw file.\n\nFor example, if /home/tom/image/02-09-2006/dsc0012.nefhas been opened, the meaning of the formatting strings are:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nIf you want to save the output image where the original is, write:\n%p1/%f\n\nIf you want to save the output image in a directory 'converted' located the directory of the original, write:\n%p1/converted/%f\n\nIf you want to save the output image in directory '/home/tom/converted' with keeping the same subdirectory of dates, write:\n%p2/converted/%d1/%f +PREFERENCES_PARSEDEXT;Parsed Extensions +PREFERENCES_PARSEDEXTADD;Add Extension +PREFERENCES_PARSEDEXTADDHINT;Type an extension and press this button to append list +PREFERENCES_PARSEDEXTDELHINT;Delete selected extension from the list +PREFERENCES_PROFILEHANDLING;Processing Profile Handling +PREFERENCES_PROFILELOADPR;Profile Loading Priority +PREFERENCES_PROFILEPRCACHE;Profile in Cache +PREFERENCES_PROFILEPRFILE;Profile Next to the Input File +PREFERENCES_PROFILESAVECACHE;Save Processing Parameters to the Cache +PREFERENCES_PROFILESAVEINPUT;Save Processing Parameters Next to the Input File +PREFERENCES_PSPATH;Adobe Photoshop installation directory +PREFERENCES_SELECTICCDIRDLG;ICCãƒ—ãƒ­ãƒ•ã‚¡ã‚¤ãƒ«ãƒ»ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªé¸æŠž... +PREFERENCES_SELECTLANG;è¨€èªžé¸æŠž +PREFERENCES_SELECTMONITORPROFDLG;ディスプレイã®ICCãƒ—ãƒ­ãƒ•ã‚¡ã‚¤ãƒ«ã‚’é¸æŠž... +PREFERENCES_SELECTTHEME;é¸æŠž テーマ +PREFERENCES_SHOWBASICEXIF;基本Exif情報 表示 +PREFERENCES_SHOWDATETIME;日付表示 +PREFERENCES_SHOWONLYRAW;RAWファイルã®ã¿è¡¨ç¤º +PREFERENCES_SHTHRESHOLD;シャドウ・クリッピング領域ã®ã—ãã„値 +PREFERENCES_STARTUPIMDIR;起動時ã®ã‚¤ãƒ¡ãƒ¼ã‚¸ãƒ»ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª +PREFERENCES_TAB_BROWSER;ファイルブラウザ +PREFERENCES_TAB_COLORMGR;カラーマãƒã‚¸ãƒ¡ãƒ³ãƒˆ +PREFERENCES_TAB_GENERAL;一般 +PREFERENCES_TAB_IMPROC;ã‚¤ãƒ¡ãƒ¼ã‚¸å‡¦ç† +PREFERENCES_TAB_OUTPUT;出力オプション +PREFERENCES_THUMBSIZE;サムãƒã‚¤ãƒ«ãƒ»ã‚µã‚¤ã‚º +PROFILEPANEL_FILEDLGFILTERANY;ã™ã¹ã¦ã®ãƒ•ァイル +PROFILEPANEL_FILEDLGFILTERPP;å‡¦ç†æ¸ˆã¿ãƒ—ロファイル +PROFILEPANEL_LABEL;å‡¦ç†æ¸ˆã¿ãƒ—ロファイル +PROFILEPANEL_LOADDLGLABEL;å‡¦ç†æ¸ˆã¿ãƒ—ロファイルを読ã¿è¾¼ã‚€... +PROFILEPANEL_PCUSTOM;カスタム +PROFILEPANEL_PFILE;ファイルã‹ã‚‰ +PROFILEPANEL_PLASTPHOTO;更新済ã®å†™çœŸ +PROFILEPANEL_PLASTSAVED;更新済 +PROFILEPANEL_PROFILE;プロファイル +PROFILEPANEL_SAVEDLGLABEL;å‡¦ç†æ¸ˆã¿ãƒ—ロファイルをä¿å­˜... +PROFILEPANEL_TOOLTIPCOPY;Copy current profile to clipboard +PROFILEPANEL_TOOLTIPLOAD;ファイルã‹ã‚‰ãƒ—ロファイルを読ã¿è¾¼ã‚€ +PROFILEPANEL_TOOLTIPPASTE; Paste profile from clipboard +PROFILEPANEL_TOOLTIPSAVE;ç¾åœ¨ã®ãƒ—ロファイルをä¿å­˜ +PROGRESSBAR_DECODING;rawファイルデコード中... +PROGRESSBAR_DEMOSAICING;デモザイク処ç†ä¸­... +PROGRESSBAR_LOADING;イメージ読ã¿è¾¼ã¿ä¸­... +PROGRESSBAR_LOADJPEG;JPEGファイル読ã¿è¾¼ã¿ä¸­... +PROGRESSBAR_LOADPNG;;PNGファイル読ã¿è¾¼ã¿ä¸­... +PROGRESSBAR_LOADTIFF;TIFFファイル読ã¿è¾¼ã¿ä¸­... +PROGRESSBAR_PROCESSING;イメージ処ç†ä¸­... +PROGRESSBAR_READY;準備ãŒã§ãã¾ã—㟠+PROGRESSBAR_SAVEJPEG;JPEGファイルä¿å­˜ä¸­... +PROGRESSBAR_SAVEPNG;PNGファイルä¿å­˜ä¸­... +PROGRESSBAR_SAVETIFF;TIFFファイルä¿å­˜ä¸­... +PROGRESSDLG_LOADING;Loading file... +PROGRESSDLG_PROCESSING;Processing image... +PROGRESSDLG_SAVING;Saving file... +QINFO_FOCALLENGTH;焦点è·é›¢ +QINFO_ISO;ISO +QINFO_LENS;Lens +QINFO_NOEXIF;ExifデータãŒã‚りã¾ã›ã‚“ +SAVEDLG_FILEFORMAT;ãƒ•ã‚¡ã‚¤ãƒ«å½¢å¼ +SAVEDLG_JPEGQUAL;JPEG å“質 +SAVEDLG_JPGFILTER;JPEG files +SAVEDLG_PNGCOMPR;PNG 圧縮 +SAVEDLG_PNGFILTER;PNG files +SAVEDLG_PUTTOQUEUE;Put into processing queue +SAVEDLG_PUTTOQUEUEHEAD;Put to the head of the processing queue +SAVEDLG_PUTTOQUEUETAIL;Put to the end of the processing queue +SAVEDLG_SAVEIMMEDIATELY;Save immediately +SAVEDLG_SAVESPP;設定値もä¿å­˜ã™ã‚‹ +SAVEDLG_TIFFFILTER;TIFF files +TOOLBAR_TOOLTIP_CROP;切り抜ãç¯„å›²é¸æŠž (shortcut key: C) +TOOLBAR_TOOLTIP_HAND;手ã®å¹³ãƒ„ール (shortcut key: N) +TOOLBAR_TOOLTIP_STRAIGHTEN;ç›´ç·šé¸æŠž (shortcut key: S) +TOOLBAR_TOOLTIP_WB;スãƒãƒƒãƒˆãƒ»ãƒ›ãƒ¯ã‚¤ãƒˆãƒãƒ©ãƒ³ã‚¹ (shortcut key: W) +TP_CACORRECTION_BLUE;ブルー +TP_CACORRECTION_LABEL;色åŽå·®è£œæ­£ +TP_CACORRECTION_RED;レッド +TP_CHMIXER_BLUE;ブルー +TP_CHMIXER_GREEN;グリーン +TP_CHMIXER_LABEL;ãƒãƒ£ãƒ³ãƒãƒ«ãƒŸã‚­ã‚µãƒ¼ +TP_CHMIXER_RED;レッド +TP_COARSETRAF_DEGREE;度: +TP_COARSETRAF_TOOLTIP_HFLIP;æ°´å¹³ã«å転 +TP_COARSETRAF_TOOLTIP_ROTLEFT;90度左回転 +TP_COARSETRAF_TOOLTIP_ROTRIGHT;90度å³å›žè»¢ +TP_COARSETRAF_TOOLTIP_VFLIP;垂直ã«å転 +TP_COLORBOOST_ACHANNEL;a ãƒãƒ£ãƒ³ãƒãƒ« +TP_COLORBOOST_AMOUNT;é‡ +TP_COLORBOOST_AVOIDCOLORCLIP;カラークリッピングãªã— +TP_COLORBOOST_BCHANNEL;b ãƒãƒ£ãƒ³ãƒãƒ« +TP_COLORBOOST_CHAB;a & b +TP_COLORBOOST_CHANNEL;ãƒãƒ£ãƒ³ãƒãƒ« +TP_COLORBOOST_CHSEPARATE;a/b分離 +TP_COLORBOOST_ENABLESATLIMITER;彩度増化制é™ãƒ»æœ‰åй +TP_COLORBOOST_LABEL;カラー 増化 +TP_COLORBOOST_SATLIMIT;å½©åº¦å¢—åŒ–åˆ¶é™ +TP_COLORDENOISE_EDGESENSITIVE;ã‚¨ãƒƒã‚¸ã®æ„Ÿåº¦ +TP_COLORDENOISE_EDGETOLERANCE;エッジã®è¨±å®¹åº¦ +TP_COLORDENOISE_LABEL;カラー ノイズ除去 +TP_COLORDENOISE_RADIUS;åŠå¾„ +TP_COLORSHIFT_BLUEYELLOW;ブルー-イエロー +TP_COLORSHIFT_GREENMAGENTA;グリーン-マゼンタ +TP_COLORSHIFT_LABEL;カラー シフト +TP_CROP_DPI;DPI= +TP_CROP_FIXRATIO;縦横比 固定: +TP_CROP_GTDIAGONALS;対角線 +TP_CROP_GTHARMMEANS1;èª¿å’Œå¹³å‡ 1 +TP_CROP_GTHARMMEANS2;èª¿å’Œå¹³å‡ 2 +TP_CROP_GTHARMMEANS3;èª¿å’Œå¹³å‡ 3 +TP_CROP_GTHARMMEANS4;èª¿å’Œå¹³å‡ 4 +TP_CROP_GTNONE;ãªã— +TP_CROP_GTRULETHIRDS;三分割 +TP_CROP_GUIDETYPE;ガイドタイプ: +TP_CROP_H;H +TP_CROP_LABEL;切り抜ã +TP_CROP_SELECTCROP; é¸æŠžç¯„å›²åˆ‡ã‚ŠæŠœã +TP_CROP_W;W +TP_CROP_X;x +TP_CROP_Y;y +TP_DISTORTION_AMOUNT;é‡ +TP_DISTORTION_LABEL;歪曲åŽå·®è£œæ­£ +TP_EXPOSURE_AUTOLEVELS;オートレベル +TP_EXPOSURE_BLACKLEVEL;黒レベル +TP_EXPOSURE_BRIGHTNESS;明る㕠+TP_EXPOSURE_CLIP;クリップ +TP_EXPOSURE_COMPRHIGHLIGHTS;ãƒã‚¤ãƒ©ã‚¤ãƒˆåœ§ç¸® +TP_EXPOSURE_COMPRSHADOWS;シャドウ圧縮 +TP_EXPOSURE_CONTRAST;コントラスト +TP_EXPOSURE_CURVEEDITOR;トーンカーブ +TP_EXPOSURE_EXPCOMP;露出 補正 +TP_EXPOSURE_LABEL;露出 +TP_HLREC_CIELAB;CIELab ブレンディング +TP_HLREC_COLOR;è‰²ã®æ³¢åŠ +TP_HLREC_LABEL;ãƒã‚¤ãƒ©ã‚¤ãƒˆä¿®å¾© +TP_HLREC_LUMINANCE;è¼åº¦ä¿®å¾© +TP_HLREC_METHOD;æ–¹å¼: +TP_ICM_FILEDLGFILTERANY;ã™ã¹ã¦ã®ãƒ•ァイル +TP_ICM_FILEDLGFILTERICM;ICCプロファイル ファイル +TP_ICM_GAMMABEFOREINPUT;プロファイルã«ã‚¬ãƒ³ãƒžé©å¿œ +TP_ICM_INPUTCAMERA;カメラã®è¨­å®šå€¤ +TP_ICM_INPUTCUSTOM;カスタム +TP_ICM_INPUTDLGLABEL;入力 ICC ãƒ—ãƒ­ãƒ•ã‚¡ã‚¤ãƒ«ã‚’é¸æŠž... +TP_ICM_INPUTEMBEDDED;埋ã‚è¾¼ã¿ä½¿ç”¨, å¯èƒ½ãªã‚‰ +TP_ICM_INPUTPROFILE;入力プロファイル +TP_ICM_LABEL;ICM +TP_ICM_NOICM;No ICM: sRGB 出力 +TP_ICM_OUTPUTDLGLABEL;出力 ICC ãƒ—ãƒ­ãƒ•ã‚¡ã‚¤ãƒ«ã‚’é¸æŠž... +TP_ICM_OUTPUTPROFILE;出力プロファイル +TP_ICM_SAVEREFERENCE;プロファイリングã®å‚ç…§ã™ã‚‹ç”»åƒã‚’ä¿å­˜ +TP_ICM_WORKINGPROFILE;作業プロファイル +TP_LUMACURVE_BLACKLEVEL;黒レベル +TP_LUMACURVE_BRIGHTNESS;明る㕠+TP_LUMACURVE_COMPRHIGHLIGHTS;ãƒã‚¤ãƒ©ã‚¤ãƒˆåœ§ç¸® +TP_LUMACURVE_COMPRSHADOWS;シャドウ圧縮 +TP_LUMACURVE_CONTRAST;コントラスト +TP_LUMACURVE_CURVEEDITOR;è¼åº¦ã‚«ãƒ¼ãƒ–エディター +TP_LUMACURVE_LABEL;è¼åº¦ã‚«ãƒ¼ãƒ– +TP_LUMADENOISE_EDGETOLERANCE;エッジã®è¨±å®¹åº¦ +TP_LUMADENOISE_LABEL;è¼åº¦ ノイズ除去 +TP_LUMADENOISE_RADIUS;åŠå¾„ +TP_RESIZE_BICUBIC;ãƒã‚¤ã‚­ãƒ¥ãƒ¼ãƒ“ック +TP_RESIZE_BICUBICSF;ãƒã‚¤ã‚­ãƒ¥ãƒ¼ãƒ“ック (ソフトã«) +TP_RESIZE_BICUBICSH;ãƒã‚¤ã‚­ãƒ¥ãƒ¼ãƒ“ック (シャープã«) +TP_RESIZE_BILINEAR;ãƒã‚¤ãƒªãƒ‹ã‚¢ +TP_RESIZE_FULLSIZE;フル イメージ サイズ: +TP_RESIZE_H;H: +TP_RESIZE_LABEL;リサイズ +TP_RESIZE_METHOD;æ–¹å¼: +TP_RESIZE_NEAREST;ニアリスト +TP_RESIZE_SCALE;スケール +TP_RESIZE_W;W: +TP_ROTATE_AUTOCROP;自動的ã«åˆ‡ã‚ŠæŠœãé¸æŠž +TP_ROTATE_DEGREE;度 +TP_ROTATE_FILL;塗り +TP_ROTATE_LABEL;回転 +TP_ROTATE_SELECTLINE; ç›´ç·šé¸æŠž +TP_SHADOWSHLIGHTS_HIGHLIGHTS;ãƒã‚¤ãƒ©ã‚¤ãƒˆ +TP_SHADOWSHLIGHTS_HLTONALW;色調ã®å¹… +TP_SHADOWSHLIGHTS_LABEL;シャドウï¼ãƒã‚¤ãƒ©ã‚¤ãƒˆ +TP_SHADOWSHLIGHTS_LOCALCONTR;局所コントラスト +TP_SHADOWSHLIGHTS_RADIUS;åŠå¾„ +TP_SHADOWSHLIGHTS_SHADOWS;シャドウ +TP_SHADOWSHLIGHTS_SHTONALW;色調ã®å¹… +TP_SHARPENING_AMOUNT;é‡ +TP_SHARPENING_EDRADIUS;åŠå¾„ +TP_SHARPENING_EDTOLERANCE;エッジ許容 +TP_SHARPENING_HALOCONTROL;フレア抑制 +TP_SHARPENING_HCAMOUNT;é‡ +TP_SHARPENING_LABEL;シャープ化 +TP_SHARPENING_METHOD;æ–¹å¼ +TP_SHARPENING_ONLYEDGES;エッジã®ã¿ +TP_SHARPENING_RADIUS;åŠå¾„ +TP_SHARPENING_RLD;RL デコンボリューション +TP_SHARPENING_RLD_AMOUNT;é‡ +TP_SHARPENING_RLD_DAMPING;減衰 +TP_SHARPENING_RLD_ITERATIONS;繰返㗠+TP_SHARPENING_THRESHOLD;ã—ãã„値 +TP_SHARPENING_USM;アンシャープマスク +TP_VIGNETTING_AMOUNT;é‡ +TP_VIGNETTING_LABEL;周辺光é‡è£œæ­£ +TP_VIGNETTING_RADIUS;åŠå¾„ +TP_WBALANCE_AUTO;オート +TP_WBALANCE_CAMERA;カメラ +TP_WBALANCE_CUSTOM;カスタム +TP_WBALANCE_GREEN;色åˆã„ +TP_WBALANCE_LABEL;ホワイトãƒãƒ©ãƒ³ã‚¹ +TP_WBALANCE_METHOD;æ–¹å¼ +TP_WBALANCE_SIZE;サイズ: +TP_WBALANCE_SPOTWB;スãƒãƒƒãƒˆWB +TP_WBALANCE_TEMPERATURE;色温度 +ZOOMBAR_DETAIL;詳細 +ZOOMBAR_HUGE;特大 +ZOOMBAR_LARGE;大 +ZOOMBAR_NORMAL;標準 +ZOOMBAR_PREVIEW;プレビュー +ZOOMBAR_SCALE;スケール +ZOOMBAR_SMALL;å° diff --git a/release/languages/latvian b/release/languages/latvian new file mode 100755 index 000000000..4699eba65 --- /dev/null +++ b/release/languages/latvian @@ -0,0 +1,574 @@ +ADJUSTER_RESET_TO_DEFAULT;AtiestatÄ«t uz noklusÄ“to +CURVEEDITOR_FILEDLGFILTERANY;Visi faili +CURVEEDITOR_FILEDLGFILTERCURVE;LÄ«kņu faili +CURVEEDITOR_LINEAR;LineÄri +CURVEEDITOR_LOADDLGLABEL;IelÄdÄ“t lÄ«kni... +CURVEEDITOR_SAVEDLGLABEL;SaglabÄt lÄ«kni... +CURVEEDITOR_TOOLTIPLINEAR;Iztaisnot lÄ«kni +CURVEEDITOR_TOOLTIPLOAD;IelÄdÄ“t lÄ«kni no faila +CURVEEDITOR_TOOLTIPSAVE;SaglabÄt esoÅ¡o lÄ«kni +EXIFFILTER_APERTURE;Aperture +EXIFFILTER_CAMERA;Camera +EXIFFILTER_DIALOGLABEL;Exif Filter +EXIFFILTER_FOCALLEN;Focal Length +EXIFFILTER_ISO;ISO +EXIFFILTER_LENS;Lens +EXIFFILTER_SHUTTER;Shutter +EXIFPANEL_ADDEDIT;Pielikt/Labot +EXIFPANEL_ADDEDITHINT;Pielikt jaunu birku vai labot birku +EXIFPANEL_ADDTAGDLG_ENTERVALUE;Ievadiet vÄ“rtÄ«bu +EXIFPANEL_ADDTAGDLG_SELECTTAG;IzvÄ“lÄ“t birku +EXIFPANEL_ADDTAGDLG_TITLE;Pielikt/Labot birku +EXIFPANEL_KEEP;AtstÄt +EXIFPANEL_KEEPHINT;AtstÄt izvÄ“lÄ“tÄs birkas kad raksta izejas failu +EXIFPANEL_REMOVE;Noņemt +EXIFPANEL_REMOVEHINT;Noņemt izvÄ“lÄ“tÄs birkas kad raksta izejas failu +EXIFPANEL_RESET;Atiestate +EXIFPANEL_RESETALL;AtiestatÄ«t visu +EXIFPANEL_RESETALLHINT;AtiestatÄ«t visas birkas uz to noklusÄ“tajÄm vÄ“rtÄ«bÄm +EXIFPANEL_RESETHINT;AtiestatÄ«t izvÄ“lÄ“tÄs birkas uz to noklusÄ“tajÄm vÄ“rtÄ«bÄm +EXIFPANEL_SUBDIRECTORY;Subdirectory +FILEBROWSER_APPLYPROFILE;Apply profile +FILEBROWSER_ARRANGEMENTHINT;Change between vertical/horizontal alignment of thumbnails +FILEBROWSER_CLEARPROFILE;Clear profile +FILEBROWSER_COPYPROFILE;Copy profile +FILEBROWSER_DELETEDLGLABEL;File delete confirmation +FILEBROWSER_DELETEDLGMSG;Are you sure you want to delete the selected %1 files? +FILEBROWSER_EMPTYTRASH;Empty Trash +FILEBROWSER_EMPTYTRASHHINT;Permanently delete the files of the trash +FILEBROWSER_EXIFFILTERAPPLY;Apply +FILEBROWSER_EXIFFILTERAPPLYHINT;Switch on/off exif filter of the file browser +FILEBROWSER_EXIFFILTERLABEL;Exif Filter +FILEBROWSER_EXIFFILTERSETTINGS;Setup +FILEBROWSER_EXIFFILTERSETTINGSHINT;Change settings of the exif filter +FILEBROWSER_PARTIALPASTEPROFILE;Partial paste +FILEBROWSER_PASTEPROFILE;Paste profile +FILEBROWSER_POPUPCANCELJOB;Cancel job +FILEBROWSER_POPUPMOVEEND;Move to end of queue +FILEBROWSER_POPUPMOVEHEAD;Move to head of queue +FILEBROWSER_POPUPOPEN;Open +FILEBROWSER_POPUPPROCESS;Put to processing queue +FILEBROWSER_POPUPRANK1;Rank 1 +FILEBROWSER_POPUPRANK2;Rank 2 +FILEBROWSER_POPUPRANK3;Rank 3 +FILEBROWSER_POPUPRANK4;Rank 4 +FILEBROWSER_POPUPRANK5;Rank 5 +FILEBROWSER_POPUPREMOVE;Remove from filesystem +FILEBROWSER_POPUPRENAME;Rename +FILEBROWSER_POPUPSELECTALL;Select all +FILEBROWSER_POPUPTRASH;Move to trash +FILEBROWSER_POPUPUNRANK;Unrank +FILEBROWSER_POPUPUNTRASH;Remove from trash +FILEBROWSER_PROCESSINGSETTINGS;Settings +FILEBROWSER_PROCESSINGSETTINGSHINT;Set the file format and output directory +FILEBROWSER_RENAMEDLGLABEL;Rename file +FILEBROWSER_RENAMEDLGMSG;Rename file "%1" to: +FILEBROWSER_SHOWDIRHINT;Show all images of the directory +FILEBROWSER_SHOWQUEUEHINT;Show content of the processing queue +FILEBROWSER_SHOWRANK1HINT;Show images ranked as 1 star +FILEBROWSER_SHOWRANK2HINT;Show images ranked as 2 star +FILEBROWSER_SHOWRANK3HINT;Show images ranked as 3 star +FILEBROWSER_SHOWRANK4HINT;Show images ranked as 4 star +FILEBROWSER_SHOWRANK5HINT;Show images ranked as 5 star +FILEBROWSER_SHOWTRASHHINT;Show content of the trash +FILEBROWSER_SHOWUNRANKHINT;Show unranked images +FILEBROWSER_STARTPROCESSING;Start Processing +FILEBROWSER_STARTPROCESSINGHINT;Start processing/saving of images in the queue +FILEBROWSER_STOPPROCESSING;Stop processing +FILEBROWSER_STOPPROCESSINGHINT;Stop processing of images +FILEBROWSER_THUMBSIZE;Thumb. size +FILEBROWSER_ZOOMINHINT;Increase thumbnail size +FILEBROWSER_ZOOMOUTHINT;Decrease thumbnail size +GENERAL_ABOUT;Par +GENERAL_CANCEL;Atcelt +GENERAL_DISABLE;AtslÄ“gt +GENERAL_DISABLED;AtslÄ“gts +GENERAL_ENABLE;IeslÄ“gt +GENERAL_ENABLED;IeslÄ“gts +GENERAL_LANDSCAPE;Ainava +GENERAL_LOAD;IelÄdÄ“t +GENERAL_NA;n/a +GENERAL_NO;NÄ“ +GENERAL_OK;Labi +GENERAL_PORTRAIT;Portrets +GENERAL_SAVE;SaglabÄt +GENERAL_YES;JÄ +HISTOGRAM_LABEL;Histogram +HISTOGRAM_TOOLTIP_B;RÄdÄ«t/SlÄ“pt ZilÄ histogrammu +HISTOGRAM_TOOLTIP_G;RÄdÄ«t/SlÄ“pt ZaÄ¼Ä histogrammu +HISTOGRAM_TOOLTIP_L;RÄdÄ«t/SlÄ“pt CIELAB SpÄ«duma histogrammu +HISTOGRAM_TOOLTIP_R;RÄdÄ«t/SlÄ“pt SarkanÄ histogrammu +HISTORY_CHANGED;MainÄ«ts +HISTORY_CUSTOMCURVE;PielÄgota lÄ«kne +HISTORY_DELSNAPSHOT;Noņemt grÄmtzÄ«mi +HISTORY_FROMCLIPBOARD;From clipboard +HISTORY_LABEL;VÄ“sture +HISTORY_MSG_10;Ä’nu spieÅ¡ana +HISTORY_MSG_11;Toņa lÄ«kne +HISTORY_MSG_12;Auto EkspozÄ«cija +HISTORY_MSG_13;EkspozÄ«cijas cirpÅ¡ana +HISTORY_MSG_14;SpÄ«duma GaiÅ¡ums +HISTORY_MSG_15;SpÄ«duma Kontrasts +HISTORY_MSG_16;SpÄ«duma Melnais +HISTORY_MSG_17;SpÄ«duma Izgaismojumu spieÅ¡ana +HISTORY_MSG_18;SpÄ«duma Ä’nu spieÅ¡ana +HISTORY_MSG_19;SpÄ«duma LÄ«kne +HISTORY_MSG_1;AttÄ“ls ielÄdÄ“ts +HISTORY_MSG_20;AsinÄÅ¡ana +HISTORY_MSG_21;AsinÄÅ¡anas radiuss +HISTORY_MSG_22;AsinÄÅ¡anas apjoms +HISTORY_MSG_23;AsinÄÅ¡anas slieksnis +HISTORY_MSG_24;AsinÄt tikai malas +HISTORY_MSG_25;AsinÄÅ¡anas malu noteikÅ¡anas radiuss +HISTORY_MSG_26;AsinÄÅ¡anas malu iecietÄ«ba +HISTORY_MSG_27;AsinÄÅ¡anas caurumu kontrole +HISTORY_MSG_28;Caurumu kontroles apjoms +HISTORY_MSG_29;AsinÄÅ¡anas paņēmiens +HISTORY_MSG_2;Profils ielÄdÄ“ts +HISTORY_MSG_30;AtritinÄÅ¡anas radiuss +HISTORY_MSG_31;AtritinÄÅ¡anas apjoms +HISTORY_MSG_32;AtritinÄÅ¡anas slÄpēšana +HISTORY_MSG_33;AtritinÄÅ¡anas soļi +HISTORY_MSG_34;IzvairÄ«ties no krÄsu cirpÅ¡anas +HISTORY_MSG_35;PiesÄtinÄjuma ierobežotÄjs +HISTORY_MSG_36;PiesÄtinÄjuma robeža +HISTORY_MSG_37;KrÄsu pastiprinÄÅ¡ana +HISTORY_MSG_38;BaltÄ lÄ«dzsvara paņēmiens +HISTORY_MSG_39;KrÄsu temperatÅ«ra +HISTORY_MSG_3;Profils izmainÄ«ts +HISTORY_MSG_40;BaltÄ lÄ«dzsvara nokrÄsa +HISTORY_MSG_41;KrÄsu nobÄ«de "A" +HISTORY_MSG_42;KrÄsu nobÄ«de "B" +HISTORY_MSG_43;SpÄ«duma trokšņu slÄpēšana +HISTORY_MSG_44;Spož. trokšņu slÄpēšanas radiuss +HISTORY_MSG_45;Spož. trokšņu slÄpēšanas malu iecietÄ«ba +HISTORY_MSG_46;KrÄsu trokšņu slÄpēšana +HISTORY_MSG_47;KrÄsu trokšņu slÄpēšanas radiuss +HISTORY_MSG_48;KrÄsu trokšņu slÄpēšanas malu iecietÄ«ba +HISTORY_MSG_49;KrÄsu trokšņu slÄpēšanas malu jutÄ«gums +HISTORY_MSG_4;VÄ“stures pÄrlÅ«koÅ¡ana +HISTORY_MSG_50;Ä’nu/Izgaismojumu rÄ«ks +HISTORY_MSG_51;Izgaismojumu pastiprinÄÅ¡ana +HISTORY_MSG_52;Ä’nu pastiprinÄÅ¡ana +HISTORY_MSG_53;Izgaismojumu toņa platums +HISTORY_MSG_54;Ä’nu toņa platums +HISTORY_MSG_55;VietÄ“jais kontrasts +HISTORY_MSG_56;Ä’nu/Izgaismojumu radiuss +HISTORY_MSG_57;Raupja pagrieÅ¡ana +HISTORY_MSG_58;HorizontÄla apmeÅ¡ana +HISTORY_MSG_59;VertikÄla apmeÅ¡ana +HISTORY_MSG_5;GaiÅ¡ums +HISTORY_MSG_60;PagrieÅ¡ana +HISTORY_MSG_61;PagrieÅ¡ana +HISTORY_MSG_62;LÄ“cu kropļojumu laboÅ¡ana +HISTORY_MSG_63;GrÄmatzÄ«me izvÄ“lÄ“ta +HISTORY_MSG_64;KadrÄ“jums +HISTORY_MSG_65;KrÄsu nobÄ«des laboÅ¡ana +HISTORY_MSG_66;Izgaismojumu atgūšana +HISTORY_MSG_67;Izgaismojumu atgūšanas apjoms +HISTORY_MSG_68;Izgaismojumu atgūšanas paņēmiens +HISTORY_MSG_69;KrÄsu telpa darbam +HISTORY_MSG_6;Kontrasts +HISTORY_MSG_70;KrÄsu telpa izvadei +HISTORY_MSG_71;Ievades krÄsu telpa +HISTORY_MSG_72;Vinjetes laboÅ¡ana +HISTORY_MSG_73;KanÄlu jaucÄ“js +HISTORY_MSG_74;IzmÄ“ra mÄ“rogs +HISTORY_MSG_75;IzmÄ“ra maiņas paņēmiens +HISTORY_MSG_76;Exif meta dati +HISTORY_MSG_77;IPTC meta dati +HISTORY_MSG_7;Melnais +HISTORY_MSG_8;EkspozÄ«cijas laboÅ¡ana +HISTORY_MSG_9;Izgaismojumu spieÅ¡ana +HISTORY_NEWSNAPSHOT;Jauna grÄmtzÄ«me +HISTORY_NEWSNAPSHOTAS;KÄ... +HISTORY_NEWSSDIALOGLABEL;GrÄmtzÄ«mes nosaukums: +HISTORY_NEWSSDIALOGTITLE;Pielikt grÄmtzÄ«mi +HISTORY_SETTO;IestatÄ«ts uz +HISTORY_SNAPSHOT;GrÄmtzÄ«me +HISTORY_SNAPSHOTS;GrÄmtzÄ«mes +ICMPANEL_FILEDLGFILTERANY;Visi faili +ICMPANEL_FILEDLGFILTERICM;ICC Profilu faili +ICMPANEL_GAMMABEFOREINPUT;Uzlikta Gammu pirms Ievades profila +ICMPANEL_INPUTCAMERA;Kameras noklusÄ“tais +ICMPANEL_INPUTCUSTOM;PielÄgots +ICMPANEL_INPUTDLGLABEL;IzvÄ“lies Ievades ICC Profilu... +ICMPANEL_INPUTEMBEDDED;Lietot iegulto, ja var +ICMPANEL_INPUTPROFILE;Ievades profils +ICMPANEL_NOICM;Bez ICM: sRGB izvade +ICMPANEL_OUTPUTDLGLABEL;IzvÄ“lies Izvades ICC Profilu... +ICMPANEL_OUTPUTPROFILE;Izvades profils +ICMPANEL_SAVEREFERENCE;SaglabÄt atsauces attÄ“lu profila izveidei +ICMPANEL_WORKINGPROFILE;Darba profils +IMAGEAREA_DETAILVIEW;Tuvskats +IPTCPANEL_AUTHOR;Autors +IPTCPANEL_AUTHORHINT;Objekta radÄ«tÄjs vÄrds, t.i. rakstnieks, fotogrÄfs vai mÄkslinieks (By-line). +IPTCPANEL_AUTHORSPOSITION;Autora amats +IPTCPANEL_AUTHORSPOSITIONHINT;Objekta radÄ«tÄja amapts (By-line Title). +IPTCPANEL_CAPTION;Virsraksts +IPTCPANEL_CAPTIONHINT;Datu tekstveida apraksts (Caption - Abstract) +IPTCPANEL_CAPTIONWRITER;Virsraksta autors +IPTCPANEL_CAPTIONWRITERHINT;Personas vÄrfds, kura ir iesaistÄ«ta attÄ“la, virsraksta vai kopsavilkuma rakstīšanÄ, rediģēšanÄ vai laboÅ¡ÄnÄ (Writer - Editor) +IPTCPANEL_CATEGORY;Kategorija +IPTCPANEL_CATEGORYHINT;AttÄ“la radÄ«tÄjs identificÄ“ attÄ“la subjektu (Category). +IPTCPANEL_CITY;PilsÄ“ta +IPTCPANEL_CITYHINT;AttÄ“la izcelsmes pilsÄ“ta (City). +IPTCPANEL_COPYHINT;KopÄ“t IPTC iestatÄ«jumus uz starpliku +IPTCPANEL_COPYRIGHT;AutortiesÄ«bas +IPTCPANEL_COPYRIGHTHINT;JebkÄds nepiecieÅ¡amais brÄ«dinÄjums par autortiesÄ«bÄm (Copyright Notice). +IPTCPANEL_COUNTRY;Valsts +IPTCPANEL_COUNTRYHINT;AttÄ“la sÄkotnÄ“jÄs izveidoÅ¡anas valsts (Country - Primary Location Name). +IPTCPANEL_CREDIT;PateicÄ«ba +IPTCPANEL_CREDITHINT;IdentificÄ“ attÄ“la sniedzÄ“ju, nav obligÄti radÄ«tÄjs vai Ä«paÅ¡nieks (Credit). +IPTCPANEL_DATECREATED;IzveidoÅ¡anas datums +IPTCPANEL_DATECREATEDHINT;AttÄ“la intelektuÄlÄ satura radīšanas datums; FormÄts: ggggmmdd (Date Created). +IPTCPANEL_EMBEDDED;Iegultais +IPTCPANEL_EMBEDDEDHINT;AttiestatÄ«t uz attÄ“la iegultajiem IPTC datiem +IPTCPANEL_HEADLINE;Konspekts +IPTCPANEL_HEADLINEHINT;PublicÄ“jams raksts, kas satur attÄ“la konspektu (Headline). +IPTCPANEL_INSTRUCTIONS;NorÄdÄ«jumi +IPTCPANEL_INSTRUCTIONSHINT;Citi redaktora norÄdÄ«jumi par attÄ“la lietoÅ¡anu (Special Instructions). +IPTCPANEL_KEYWORDS;AtslÄ“gvÄrdi +IPTCPANEL_KEYWORDSHINT;NorÄda vÄrdus specifiskas informÄcijas iegūšanai (Keywords). +IPTCPANEL_PASTEHINT;IelÄ«mÄ“t IPTC iestatÄ«jumus no starplikas +IPTCPANEL_PROVINCE;Province +IPTCPANEL_PROVINCEHINT;AttÄ“la izcelsmes valsts vai province (Province-State). +IPTCPANEL_RESET;Atiestate +IPTCPANEL_RESETHINT;AtiestatÄ«t uz profila noklusÄ“jumu +IPTCPANEL_SOURCE;Avots +IPTCPANEL_SOURCEHINT;AttÄ“la intelektuÄlÄ Ä«paÅ¡uma Ä«paÅ¡nieks (Source). +IPTCPANEL_SUPPCATEGORIES;ApakÅ¡kategorija +IPTCPANEL_SUPPCATEGORIESHINT;PrecizÄ“ attÄ“la subjektu (Supplemental Categories). +IPTCPANEL_TITLE;Nosaukums +IPTCPANEL_TITLEHINT;AttÄ“la saÄ«sinÄts nosaukums (Object Name). +IPTCPANEL_TRANSREFERENCE;PÄrneses atsauce +IPTCPANEL_TRANSREFERENCEHINT;Kods, kas norÄda uz attÄ“la sÄkotnÄ“jas pÄrneses vietu (Original Transmission Reference). +MAIN_BUTTON_PREFERENCES;IestatÄ«jumi +MAIN_BUTTON_SAVE;SaglabÄt attÄ“lu +MAIN_BUTTON_SAVEAS;KÄ... +MAIN_BUTTON_SENDTOEDITOR;Send to editor +MAIN_MSG_ALREADYEXISTS;Fails jau ir. +MAIN_MSG_CANNOTLOAD;Nevaru ielÄdÄ“t attÄ“lu +MAIN_MSG_CANNOTSAVE;Faila saglabÄÅ¡anas kļūda +MAIN_MSG_CANNOTSTARTEDITOR;Can not start editor. +MAIN_MSG_CANNOTSTARTEDITOR_SECONDARY;Please set the correct path in the "Preferences" dialog. +MAIN_MSG_EXITJOBSINQUEUEINFO;Unprocessed images in the queue will be lost on exit. +MAIN_MSG_EXITJOBSINQUEUEQUEST;Are you sure you want to exit? There are unprocessed images waiting in the queue. +MAIN_MSG_JOBSINQUEUE;darbs(i) rindÄ +MAIN_MSG_QOVERWRITE;Vai pÄrrakstÄ«t to? +MAIN_TAB_BASIC;Pamats +MAIN_TAB_COLOR;Color +MAIN_TAB_DETAIL;Detail +MAIN_TAB_EXIF;Exif +MAIN_TAB_EXPOSURE;Exposure +MAIN_TAB_ICM;ICM +MAIN_TAB_IPTC;IPTC +MAIN_TAB_METADATA;Metadata +MAIN_TAB_TRANSFORM;PÄrveidot +MAIN_TOOLTIP_HIDEFP;RÄdÄ«t/slÄ“pt apakšējo ielaidumu (mapju un failu pÄrlÅ«ks, shortcut key: F)) +MAIN_TOOLTIP_HIDEHP;RÄdÄ«t/slÄ“pt kreiso ielaidumu (ieskaitot vÄ“sturi, shortcut key: H) +MAIN_TOOLTIP_INDCLIPPEDH;Izgaismojumu cirpÅ¡anas pazÄ«me +MAIN_TOOLTIP_INDCLIPPEDS;Ä’nu cirpÅ¡anas pazÄ«me +MAIN_TOOLTIP_PREFERENCES;MainÄ«t iestatÄ«jumus +MAIN_TOOLTIP_QINFO;Ä€trÄ info uz attÄ“la +MAIN_TOOLTIP_SAVE;SaglabÄt attÄ“lu noklusÄ“tÄ mapÄ“ +MAIN_TOOLTIP_SAVEAS;SaglabÄt attÄ“lu izvÄ“lÄ“tÄ mapÄ“ +PARTIALPASTE_BASICGROUP;Basic settings +PARTIALPASTE_CACORRECTION;C/A correction +PARTIALPASTE_COARSETRANS;90 deg rotation / flipping +PARTIALPASTE_COLORBOOST;Color boost +PARTIALPASTE_COLORDENOISE;Color denoise +PARTIALPASTE_COLORGROUP;Color related settings +PARTIALPASTE_COLORMIXER;Color mixer +PARTIALPASTE_COLORSHIFT;Color shift +PARTIALPASTE_COMPOSITIONGROUP;Composition settings +PARTIALPASTE_CROP;Crop +PARTIALPASTE_DIALOGLABEL;Partial paste processing profile +PARTIALPASTE_DISTORTION;Distortion correction +PARTIALPASTE_EXIFCHANGES;Changes to exif data +PARTIALPASTE_EXPOSURE;Exposure +PARTIALPASTE_HLRECOVERY;Highlight recovery +PARTIALPASTE_ICMSETTINGS;ICM settings +PARTIALPASTE_IPTCINFO;IPTC info +PARTIALPASTE_LENSGROUP;Lens related settings +PARTIALPASTE_LUMACURVE;Luminance curve +PARTIALPASTE_LUMADENOISE;Luminance noise reduction +PARTIALPASTE_LUMINANCEGROUP;Luminance related settings +PARTIALPASTE_METAICMGROUP;Metadata/ICM settings +PARTIALPASTE_RESIZE;Resize +PARTIALPASTE_ROTATION;Rotation +PARTIALPASTE_SHADOWSHIGHLIGHTS;Shadows/Highlights +PARTIALPASTE_SHARPENING;Sharpening +PARTIALPASTE_VIGNETTING;Vignetting correction +PARTIALPASTE_WHITEBALANCE;White balance +PREFERENCES_APPLNEXTSTARTUP;lietos nÄkamÄ reizÄ“ +PREFERENCES_BLINKCLIPPED;Mirgot cirptos laukumus +PREFERENCES_CACHECLEARALL;Clear All +PREFERENCES_CACHECLEARPROFILES;Clear Profiles +PREFERENCES_CACHECLEARTHUMBS;Clear Thumbnails +PREFERENCES_CACHEFORMAT1;Proprietary (faster and better quality) +PREFERENCES_CACHEFORMAT2;JPEG (smaller disk footprint) +PREFERENCES_CACHEMAXENTRIES;Maximal Number of Cache Entries +PREFERENCES_CACHEOPTS;Cache Options +PREFERENCES_CACHESTRAT1;Prefer Speed to Low Memory Consumption +PREFERENCES_CACHESTRAT2;Prefer Low Memory Consumption to Speed +PREFERENCES_CACHESTRAT;Cache Strategy +PREFERENCES_CACHETHUMBFORM;Cache Thumbnail Format +PREFERENCES_CACHETHUMBHEIGHT;Maximal Thumbnail Height +PREFERENCES_CLEARDLG_LINE1;Clearing cache +PREFERENCES_CLEARDLG_LINE2;This may take a few seconds. +PREFERENCES_CLEARDLG_TITLE;Please wait +PREFERENCES_CLIPPINGIND;CirpÅ¡anas pazÄ«me +PREFERENCES_CMETRICINTENT;Kolorimetriskais nolÅ«ks +PREFERENCES_DATEFORMAT;Datuma formÄts +PREFERENCES_DATEFORMATHINT;JÅ«s varat lietot Å¡Äduas formatēšanas parametrus:\n%y : gads\n%m : mÄ“nesis\n%d : diena\n\nPiemÄ“ram, ungÄru datuma formÄts ir:\n%y/%m/%d +PREFERENCES_DEFAULTLANG;NoklusÄ“tÄ valoda +PREFERENCES_DEFAULTTHEME;NoklusÄ“tÄ tÄ“ma +PREFERENCES_DEMOSAICINGALGO;MozaÄ«kas interpolÄcijas algoritms +PREFERENCES_DIRHOME;MÄjas mape +PREFERENCES_DIRLAST;PÄ“dÄ“jÄ lietotÄ mape +PREFERENCES_DIROTHER;Cita +PREFERENCES_DIRSELECTDLG;IzvÄ“lies attÄ“lu mapi sÄkumam... +PREFERENCES_DIRSOFTWARE;UzstÄdīšanas mape +PREFERENCES_DMETHOD;Metode +PREFERENCES_EDITORCMDLINE;Other command line +PREFERENCES_EXTERNALEDITOR;External editor +PREFERENCES_FALSECOLOR;NeÄ«sto krÄsu slÄpēšanas soļi +PREFERENCES_FBROWSEROPTS;Failu pÄrlÅ«ka iespÄ“jas +PREFERENCES_FILEFORMAT;Faila formÄts +PREFERENCES_FORIMAGE;AttÄ“lu failiem +PREFERENCES_FORRAW;RAW failiem +PREFERENCES_GIMPPATH;GIMP installation directory +PREFERENCES_GTKTHEME;GTK noklusÄ“tÄ +PREFERENCES_HINT;MÄjiens +PREFERENCES_HLTHRESHOLD;Cirpto izgaismojumu slieksnis +PREFERENCES_ICCDIR;ICC profilu mape +PREFERENCES_IMPROCPARAMS;NoklusÄ“tie attÄ“la apstrÄdes parametri +PREFERENCES_INTENT_ABSOLUTE;AbsolÅ«tÄ kolorimetrija +PREFERENCES_INTENT_PERCEPTUAL;Uztverams +PREFERENCES_INTENT_RELATIVE;RelatÄ«vÄ kolorimetrija +PREFERENCES_INTENT_SATURATION;PiesÄtinÄjums +PREFERENCES_LIVETHUMBNAILS;Live Thumbnails (slower) +PREFERENCES_MONITORICC;Monitora Profils +PREFERENCES_OUTDIR;Izvades mape +PREFERENCES_OUTDIRFOLDER;Save to folder +PREFERENCES_OUTDIRFOLDERHINT;Put the saved images to the seledted folder +PREFERENCES_OUTDIRHINT;JÅ«s varat lietot Å¡Äduas formatēšanas parametrus:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nÅ ie formatēšanas parametri attiecas uz raw faila direktoriju un apakÅ¡ceļiem.\n\nPiemÄ“ram, ja /home/tom/image/02-09-2006/dsc0012.nef ir atvÄ“rts, formatēšanas parametri nozÄ«mÄ“:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nJa JÅ«s vÄ“laties saglabÄt rezultÄtu tur pat kur ir oriÄ£inÄls, rakstiet:\n%p1/%f\n\nJa JÅ«s vÄ“laties saglabÄt rezultÄtu direktorijÄ 'converted', kas novietota oriÄ£inÄla direktorijÄ, rakstiet:\n%p1/converted/%f\n\nJa JÅ«s vÄ“laties saglabÄt rezultÄtu '/home/tom/converted' paturot tÄdu paÅ¡u apakÅ¡direktoriju datumu struktÅ«ru, rakstiet:\n%p2/converted/%d1/%f +PREFERENCES_OUTDIRTEMPLATE;Use Template +PREFERENCES_OUTDIRTEMPLATEHINT;You can use the following formatting strings:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nThese formatting strings refer to the directories and sub-paths of the path of the raw file.\n\nFor example, if /home/tom/image/02-09-2006/dsc0012.nefhas been opened, the meaning of the formatting strings are:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nIf you want to save the output image where the original is, write:\n%p1/%f\n\nIf you want to save the output image in a directory 'converted' located the directory of the original, write:\n%p1/converted/%f\n\nIf you want to save the output image in directory '/home/tom/converted' with keeping the same subdirectory of dates, write:\n%p2/converted/%d1/%f +PREFERENCES_PARSEDEXT;Parsed Extensions +PREFERENCES_PARSEDEXTADD;Add Extension +PREFERENCES_PARSEDEXTADDHINT;Type an extension and press this button to append list +PREFERENCES_PARSEDEXTDELHINT;Delete selected extension from the list +PREFERENCES_PROFILEHANDLING;Processing Profile Handling +PREFERENCES_PROFILELOADPR;Profile Loading Priority +PREFERENCES_PROFILEPRCACHE;Profile in Cache +PREFERENCES_PROFILEPRFILE;Profile Next to the Input File +PREFERENCES_PROFILESAVECACHE;Save Processing Parameters to the Cache +PREFERENCES_PROFILESAVEINPUT;Save Processing Parameters Next to the Input File +PREFERENCES_PSPATH;Adobe Photoshop installation directory +PREFERENCES_SELECTICCDIRDLG;IzvÄ“lies ICC Profilu mapi... +PREFERENCES_SELECTLANG;IzvÄ“lies valodu +PREFERENCES_SELECTMONITORPROFDLG;IzvÄ“lies displeja ICC profilu... +PREFERENCES_SELECTTHEME;IzvÄ“lieties tÄ“mu +PREFERENCES_SHOWBASICEXIF;RÄdÄ«t Exif pamatdatus +PREFERENCES_SHOWDATETIME;RÄdÄ«t datumu un laiku +PREFERENCES_SHOWONLYRAW;RÄdÄ«t tikai RAW failus +PREFERENCES_SHTHRESHOLD;Cirpto Ä“nu slieksnis +PREFERENCES_STARTUPIMDIR;AttÄ“lu mape sÄkumÄ +PREFERENCES_TAB_BROWSER;Failu pÄrlÅ«ks +PREFERENCES_TAB_COLORMGR;KrÄsu pÄrvaldÄ«ba +PREFERENCES_TAB_GENERAL;VispÄrÄ«gi +PREFERENCES_TAB_IMPROC;AttÄ“lu apstrÄde +PREFERENCES_TAB_OUTPUT;Izvades iespÄ“jas +PREFERENCES_THUMBSIZE;SÄ«ktÄ“la izmÄ“rs +PROFILEPANEL_FILEDLGFILTERANY;Visus failus +PROFILEPANEL_FILEDLGFILTERPP;ApstrÄdes profili +PROFILEPANEL_LABEL;PÄ“capstrÄdes profili +PROFILEPANEL_LOADDLGLABEL;IelÄdÄ“t apstrÄdes parametrus... +PROFILEPANEL_PCUSTOM;PielÄgots +PROFILEPANEL_PFILE;No faila +PROFILEPANEL_PLASTPHOTO;Iepriekšējais attÄ“ls +PROFILEPANEL_PLASTSAVED;PÄ“dÄ“jais saglabÄtais +PROFILEPANEL_PROFILE;Profils +PROFILEPANEL_SAVEDLGLABEL;SaglabÄt apstrÄdes parametrus... +PROFILEPANEL_TOOLTIPCOPY;Copy current profile to clipboard +PROFILEPANEL_TOOLTIPLOAD;IelÄdÄ“t profilu no faila +PROFILEPANEL_TOOLTIPPASTE; Paste profile from clipboard +PROFILEPANEL_TOOLTIPSAVE;SaglabÄt šībrīža profilu +PROGRESSBAR_DECODING;DekodÄ“ju raw failu... +PROGRESSBAR_DEMOSAICING;MozaÄ«kas interpolÄcija... +PROGRESSBAR_LOADING;AttÄ“la ielÄde... +PROGRESSBAR_LOADJPEG;IelÄdÄ“ju JPEG failu... +PROGRESSBAR_LOADPNG;IelÄdÄ“ju PNG failu... +PROGRESSBAR_LOADTIFF;IelÄdÄ“ju TIFF failu... +PROGRESSBAR_PROCESSING;AttÄ“la apstrÄde... +PROGRESSBAR_READY;Gatavs. +PROGRESSBAR_SAVEJPEG;SaglabÄju JPEG failu... +PROGRESSBAR_SAVEPNG;SaglabÄju PNG failu... +PROGRESSBAR_SAVETIFF;SaglabÄju TIFF failu... +PROGRESSDLG_LOADING;Loading file... +PROGRESSDLG_PROCESSING;Processing image... +PROGRESSDLG_SAVING;Saving file... +QINFO_FOCALLENGTH;Fokusa garums +QINFO_ISO;ISO +QINFO_LENS;Lens +QINFO_NOEXIF;Exif dati nav pieejami. +SAVEDLG_FILEFORMAT;Faila formÄts +SAVEDLG_JPEGQUAL;JPEG KvalitÄte +SAVEDLG_JPGFILTER;JPEG faili +SAVEDLG_PNGCOMPR;PNG SpieÅ¡ana +SAVEDLG_PNGFILTER;PNG faili +SAVEDLG_PUTTOQUEUE;Put into processing queue +SAVEDLG_PUTTOQUEUEHEAD;Put to the head of the processing queue +SAVEDLG_PUTTOQUEUETAIL;Put to the end of the processing queue +SAVEDLG_SAVEIMMEDIATELY;Save immediately +SAVEDLG_SAVESPP;SaglabÄt apstrÄdes parametrus ar attÄ“lu +SAVEDLG_TIFFFILTER;TIFF faili +TOOLBAR_TOOLTIP_CROP;Kadrēšanas rÄ«ks (shortcut key: C) +TOOLBAR_TOOLTIP_HAND;Plaukstas rÄ«ks (shortcut key: N) +TOOLBAR_TOOLTIP_STRAIGHTEN;TaisnoÅ¡anas rÄ«ks (shortcut key: S) +TOOLBAR_TOOLTIP_WB;Punkta baltÄ lÄ«dzsvara rÄ«ks (shortcut key: W) +TP_CACORRECTION_BLUE;Zils +TP_CACORRECTION_LABEL;LÄ“cas krÄsu nobÄ«des +TP_CACORRECTION_RED;Sarkans +TP_CHMIXER_BLUE;Zils +TP_CHMIXER_GREEN;Zaļš +TP_CHMIXER_LABEL;KanÄlu jaucÄ“js +TP_CHMIXER_RED;Sarkans +TP_COARSETRAF_DEGREE;grÄdi: +TP_COARSETRAF_TOOLTIP_HFLIP;Apmest horizontÄli +TP_COARSETRAF_TOOLTIP_ROTLEFT;Pagriezt pa kreisi +TP_COARSETRAF_TOOLTIP_ROTRIGHT;Pagriezt pa labi +TP_COARSETRAF_TOOLTIP_VFLIP;Apmest vertikÄli +TP_COLORBOOST_ACHANNEL;kanÄls "a" +TP_COLORBOOST_AMOUNT;Apjoms +TP_COLORBOOST_AVOIDCOLORCLIP;IzvairÄ«ties no krÄsu cirpÅ¡anas +TP_COLORBOOST_BCHANNEL;kanÄls "b" +TP_COLORBOOST_CHAB;a un b +TP_COLORBOOST_CHANNEL;KanÄls +TP_COLORBOOST_CHSEPARATE;atsevišķi +TP_COLORBOOST_ENABLESATLIMITER;Ierobežot piesÄtinÄjumu +TP_COLORBOOST_LABEL;KrÄsu pastiprinÄÅ¡ana +TP_COLORBOOST_SATLIMIT;PiesÄtinÄjuma robeža +TP_COLORDENOISE_EDGESENSITIVE;JutÄ«gs uz malÄm +TP_COLORDENOISE_EDGETOLERANCE;IecietÄ«ba pret malÄm +TP_COLORDENOISE_LABEL;KrÄsu trokšņu slÄpēšana +TP_COLORDENOISE_RADIUS;Radius +TP_COLORSHIFT_BLUEYELLOW;Zils-Dzeltens +TP_COLORSHIFT_GREENMAGENTA;Zaļš-FuksÄ«ns +TP_COLORSHIFT_LABEL;KrÄsu nobÄ«de +TP_CROP_DPI;DPI= +TP_CROP_FIXRATIO;AttiecÄ«ba: +TP_CROP_GTDIAGONALS;DiagonÄles +TP_CROP_GTHARMMEANS1;Harmon. vidÄ“jais 1 +TP_CROP_GTHARMMEANS2;Harmon. vidÄ“jais 2 +TP_CROP_GTHARMMEANS3;Harmon. vidÄ“jais 3 +TP_CROP_GTHARMMEANS4;Harmon. vidÄ“jais 4 +TP_CROP_GTNONE;NekÄdas +TP_CROP_GTRULETHIRDS;TreÅ¡daļas +TP_CROP_GUIDETYPE;VadlÄ«nijas: +TP_CROP_H;A +TP_CROP_LABEL;KadrÄ“jums +TP_CROP_SELECTCROP; IzvÄ“lies kadrÄ“jumu +TP_CROP_W;P +TP_CROP_X;x +TP_CROP_Y;y +TP_DISTORTION_AMOUNT;Apjoms +TP_DISTORTION_LABEL;LÄ“cas kropļojums +TP_EXPOSURE_AUTOLEVELS;Auto LÄ«meņi +TP_EXPOSURE_BLACKLEVEL;Melnais +TP_EXPOSURE_BRIGHTNESS;GaiÅ¡ums +TP_EXPOSURE_CLIP;Cirpt +TP_EXPOSURE_COMPRHIGHLIGHTS;Izgaismojumu spieÅ¡ana +TP_EXPOSURE_COMPRSHADOWS;Ä’nu spieÅ¡ana +TP_EXPOSURE_CONTRAST;Kontrasts +TP_EXPOSURE_CURVEEDITOR;Toņa lÄ«kne +TP_EXPOSURE_EXPCOMP;Eksp. nobÄ«de +TP_EXPOSURE_LABEL;EkspozÄ«cija +TP_HLREC_CIELAB;CIELab maisÄ«jums +TP_HLREC_COLOR;KrÄsu pavairoÅ¡ana +TP_HLREC_LABEL;Izgaismojumu atgūšana +TP_HLREC_LUMINANCE;SpÄ«duma atgūšana +TP_HLREC_METHOD;Paņēmiens: +TP_ICM_FILEDLGFILTERANY;Visi faili +TP_ICM_FILEDLGFILTERICM;ICC Profilu faili +TP_ICM_GAMMABEFOREINPUT;Uzlikta Gammu pirms Ievades profila +TP_ICM_INPUTCAMERA;Kameras noklusÄ“tais +TP_ICM_INPUTCUSTOM;PielÄgots +TP_ICM_INPUTDLGLABEL;IzvÄ“lies Ievades ICC Profilu... +TP_ICM_INPUTEMBEDDED;Lietot iegulto, ja var +TP_ICM_INPUTPROFILE;Ievades profils +TP_ICM_LABEL;ICM +TP_ICM_NOICM;Bez ICM: sRGB izvade +TP_ICM_OUTPUTDLGLABEL;IzvÄ“lies Izvades ICC Profilu... +TP_ICM_OUTPUTPROFILE;Izvades profils +TP_ICM_SAVEREFERENCE;SaglabÄt atsauces attÄ“lu profila izveidei +TP_ICM_WORKINGPROFILE;Darba profils +TP_LUMACURVE_BLACKLEVEL;Melnais +TP_LUMACURVE_BRIGHTNESS;GaiÅ¡ums +TP_LUMACURVE_COMPRHIGHLIGHTS;Izgaismojumu spieÅ¡ana +TP_LUMACURVE_COMPRSHADOWS;Ä’nu spieÅ¡ana +TP_LUMACURVE_CONTRAST;Kontrasts +TP_LUMACURVE_CURVEEDITOR;SpÄ«duma lÄ«kne +TP_LUMACURVE_LABEL;SpÄ«duma lÄ«kne +TP_LUMADENOISE_EDGETOLERANCE;IecietÄ«ba pret malÄm +TP_LUMADENOISE_LABEL;SpÄ«duma trokšņu slÄpēšana +TP_LUMADENOISE_RADIUS;Radiuss +TP_RESIZE_BICUBIC;Bikubiski +TP_RESIZE_BICUBICSF;Bikubiski (MÄ«kstÄk) +TP_RESIZE_BICUBICSH;Bikubiski (AsÄk) +TP_RESIZE_BILINEAR;BilineÄri +TP_RESIZE_FULLSIZE;Pilns attÄ“la izmÄ“rs: +TP_RESIZE_H;A: +TP_RESIZE_LABEL;MainÄ«t izmÄ“ru +TP_RESIZE_METHOD;Metode: +TP_RESIZE_NEAREST;TuvÄkais +TP_RESIZE_SCALE;MÄ“rogs +TP_RESIZE_W;P: +TP_ROTATE_AUTOCROP;Auto Kardēšana +TP_ROTATE_DEGREE;GrÄdi +TP_ROTATE_FILL;AizpildÄ«t +TP_ROTATE_LABEL;Pagriezt +TP_ROTATE_SELECTLINE; NorÄdÄ«t taisnu lÄ«niju +TP_SHADOWSHLIGHTS_HIGHLIGHTS;Izgaismojumi +TP_SHADOWSHLIGHTS_HLTONALW;Toņa platums +TP_SHADOWSHLIGHTS_LABEL;Ä’nas/Izgaismojumi +TP_SHADOWSHLIGHTS_LOCALCONTR;VietÄ“jais kontrasts +TP_SHADOWSHLIGHTS_RADIUS;Radiuss +TP_SHADOWSHLIGHTS_SHADOWS;Ä’nas +TP_SHADOWSHLIGHTS_SHTONALW;Toņa platums +TP_SHARPENING_AMOUNT;Apjoms +TP_SHARPENING_EDRADIUS;Radiuss +TP_SHARPENING_EDTOLERANCE;IecietÄ«ba pret malÄm +TP_SHARPENING_HALOCONTROL;Caurumu kontole +TP_SHARPENING_HCAMOUNT;Apjoms +TP_SHARPENING_LABEL;AsinÄÅ¡ana +TP_SHARPENING_METHOD;Paņēmiens +TP_SHARPENING_ONLYEDGES;AsinÄt tikai malas +TP_SHARPENING_RADIUS;Radiuss +TP_SHARPENING_RLD;RL atritinÄÅ¡ana +TP_SHARPENING_RLD_AMOUNT;Apjoms +TP_SHARPENING_RLD_DAMPING;SlÄpēšana +TP_SHARPENING_RLD_ITERATIONS;Soļi +TP_SHARPENING_THRESHOLD;Slieksnis +TP_SHARPENING_USM;NeasÄ maska +TP_VIGNETTING_AMOUNT;Apjoms +TP_VIGNETTING_LABEL;Vinjetes LaboÅ¡ana +TP_VIGNETTING_RADIUS;Radiuss +TP_WBALANCE_AUTO;Auto +TP_WBALANCE_CAMERA;Kamera +TP_WBALANCE_CUSTOM;PielÄgots +TP_WBALANCE_GREEN;NokrÄsa +TP_WBALANCE_LABEL;BaltÄ lÄ«dzsvars +TP_WBALANCE_METHOD;Metode +TP_WBALANCE_SIZE;izmÄ“rs: +TP_WBALANCE_SPOTWB;Punkta WB +TP_WBALANCE_TEMPERATURE;TemperatÅ«ra +ZOOMBAR_DETAIL;Tuvskats +ZOOMBAR_HUGE;MilzÄ«gs +ZOOMBAR_LARGE;Liels +ZOOMBAR_NORMAL;NormÄls +ZOOMBAR_PREVIEW;Pirmsskats +ZOOMBAR_SCALE;MÄ“rogs +ZOOMBAR_SMALL;Mazs diff --git a/release/languages/magyar b/release/languages/magyar new file mode 100755 index 000000000..1134a2667 --- /dev/null +++ b/release/languages/magyar @@ -0,0 +1,577 @@ +# +# +# +ADJUSTER_RESET_TO_DEFAULT;Alaphelyzetbe állítás +CURVEEDITOR_FILEDLGFILTERANY;Minden fájl +CURVEEDITOR_FILEDLGFILTERCURVE;Görbe fájlok +CURVEEDITOR_LINEAR;Lineáris +CURVEEDITOR_LOADDLGLABEL;Görbe betöltése... +CURVEEDITOR_SAVEDLGLABEL;Görbe mentése... +CURVEEDITOR_TOOLTIPLINEAR;Lineáris görbe visszaállítása +CURVEEDITOR_TOOLTIPLOAD;Görbe betöltése +CURVEEDITOR_TOOLTIPSAVE;Görbe mentése +EXIFFILTER_APERTURE;Blende +EXIFFILTER_CAMERA;FényképezÅ‘gép +EXIFFILTER_DIALOGLABEL;Exif SzűrÅ‘ +EXIFFILTER_FOCALLEN;Fókusztávolság +EXIFFILTER_ISO;ISO +EXIFFILTER_LENS;Objektív +EXIFFILTER_SHUTTER;ZáridÅ‘ +EXIFPANEL_ADDEDIT;Hozzáad/Szerkeszt +EXIFPANEL_ADDEDITHINT;Új tagok hozzáadása, szerkesztése +EXIFPANEL_ADDTAGDLG_ENTERVALUE;Érték megadása +EXIFPANEL_ADDTAGDLG_SELECTTAG;Tag kijelölése +EXIFPANEL_ADDTAGDLG_TITLE;Új tagok hozzáadása / Tagok szerkesztése +EXIFPANEL_KEEP;Megtart +EXIFPANEL_KEEPHINT;A kijelölt adatok megtartása a végsÅ‘ fájl mentésekor +EXIFPANEL_REMOVE;Eltávolít +EXIFPANEL_REMOVEHINT;A kijelölt adatok eldobása a végsÅ‘ fájl mentésekor +EXIFPANEL_RESET;Visszaállít +EXIFPANEL_RESETALL;Mindent visszaállít +EXIFPANEL_RESETALLHINT;Az összes meta-adat visszaáttítása az eredeti állapotba +EXIFPANEL_RESETHINT;A kijelölt adatok visszaáttítása az eredeti állapotba +EXIFPANEL_SUBDIRECTORY;Alkönyvtár +FILEBROWSER_APPLYPROFILE;Feldolgozási paraméter hozzárendelés +FILEBROWSER_ARRANGEMENTHINT;Váltás az elÅ‘nézeti képek függÅ‘leges/vízszintes elrendezése között +FILEBROWSER_CLEARPROFILE;Feldolgozási paraméter törlése +FILEBROWSER_COPYPROFILE;Feldolgozási paraméterek másolása +FILEBROWSER_DELETEDLGLABEL;Fájl törlés megerÅ‘sítése +FILEBROWSER_DELETEDLGMSG;Biztosan törölni kívánja a kijelölt %1 képet? +FILEBROWSER_EMPTYTRASH;Kuka ürítése +FILEBROWSER_EMPTYTRASHHINT;Véglegesen letörli a kukában lévÅ‘ képeket +FILEBROWSER_EXIFFILTERAPPLY;Aktív +FILEBROWSER_EXIFFILTERAPPLYHINT;Az exif szűrÅ‘ ki/bekapcsolása +FILEBROWSER_EXIFFILTERLABEL;Exif SzűrÅ‘ +FILEBROWSER_EXIFFILTERSETTINGS;Beállítások +FILEBROWSER_EXIFFILTERSETTINGSHINT;Az exif szűrÅ‘ beállítása +FILEBROWSER_PARTIALPASTEPROFILE;Részleges beillesztés +FILEBROWSER_PASTEPROFILE;Feldolgozási paraméterek beillesztése +FILEBROWSER_POPUPCANCELJOB;Eltávolítás a sorból +FILEBROWSER_POPUPMOVEEND;Végére mozgatás +FILEBROWSER_POPUPMOVEHEAD;Elejére mozgatás +FILEBROWSER_POPUPOPEN;Megnyitás szerkesztésre +FILEBROWSER_POPUPPROCESS;Feldolgozási sorba helyezés +FILEBROWSER_POPUPRANK1;Jelölés 1 csillaggal +FILEBROWSER_POPUPRANK2;Jelölés 2 csillaggal +FILEBROWSER_POPUPRANK3;Jelölés 3 csillaggal +FILEBROWSER_POPUPRANK4;Jelölés 4 csillaggal +FILEBROWSER_POPUPRANK5;Jelölés 5 csillaggal +FILEBROWSER_POPUPREMOVE;Törlés (végleges) +FILEBROWSER_POPUPRENAME;Ãtnevezés +FILEBROWSER_POPUPSELECTALL;Mindent kijelöl +FILEBROWSER_POPUPTRASH;Kukába dobás +FILEBROWSER_POPUPUNRANK;Jelölés megszüntetése +FILEBROWSER_POPUPUNTRASH;Visszaállítás a kukából +FILEBROWSER_PROCESSINGSETTINGS;Beállítások +FILEBROWSER_PROCESSINGSETTINGSHINT;A fájl formátum és a célkönyvtár beállítása +FILEBROWSER_RENAMEDLGLABEL;Fájl átnevezése +FILEBROWSER_RENAMEDLGMSG;%1 új neve: +FILEBROWSER_SHOWDIRHINT;A könyvtárban lévÅ‘ összes kép mutatása +FILEBROWSER_SHOWQUEUEHINT;A feldolgozási sor tartalmának mutatása +FILEBROWSER_SHOWRANK1HINT;1 csillaggal jelölt képek mutatása +FILEBROWSER_SHOWRANK2HINT;2 csillaggal jelölt képek mutatása +FILEBROWSER_SHOWRANK3HINT;3 csillaggal jelölt képek mutatása +FILEBROWSER_SHOWRANK4HINT;4 csillaggal jelölt képek mutatása +FILEBROWSER_SHOWRANK5HINT;5 csillaggal jelölt képek mutatása +FILEBROWSER_SHOWTRASHHINT;A kuka tartalmának mutatása +FILEBROWSER_SHOWUNRANKHINT;Meg nem jelölt képek mutatása +FILEBROWSER_STARTPROCESSING;Feldolgozás indítása +FILEBROWSER_STARTPROCESSINGHINT;A sorban álló képek feldolgozásának elindítása +FILEBROWSER_STOPPROCESSING;Feldolgozás leállítása +FILEBROWSER_STOPPROCESSINGHINT;A sorban álló képek feldolgozásának leállítása +FILEBROWSER_THUMBSIZE;Bélyegméret +FILEBROWSER_ZOOMINHINT;Növelés +FILEBROWSER_ZOOMOUTHINT;Csökkentés +GENERAL_ABOUT;Névjegy +GENERAL_CANCEL;Mégsem +GENERAL_DISABLE;Kikapcsol +GENERAL_DISABLED;Kikapcsolva +GENERAL_ENABLE;Engedélyez +GENERAL_ENABLED;Engedélyezve +GENERAL_LANDSCAPE;FekvÅ‘ +GENERAL_LOAD;Betöltés +GENERAL_NA;n/a +GENERAL_NO;Nem +GENERAL_OK;OK +GENERAL_PORTRAIT;Ãlló +GENERAL_SAVE;Mentés +GENERAL_YES;Igen +HISTOGRAM_LABEL;Hisztogram +HISTOGRAM_TOOLTIP_B;Kék csatorna hisztogrammja (mutat/elrejt) +HISTOGRAM_TOOLTIP_G;Zöld csatorna hisztogrammja (mutat/elrejt) +HISTOGRAM_TOOLTIP_L;CIELAB Luminancia hisztogramm (mutat/elrejt) +HISTOGRAM_TOOLTIP_R;Piros csatorna hisztogrammja (mutat/elrejt) +HISTORY_CHANGED;Megváltozott +HISTORY_CUSTOMCURVE;Saját görbe +HISTORY_DELSNAPSHOT;Töröl +HISTORY_FROMCLIPBOARD;Vágólapról +HISTORY_LABEL;ElÅ‘zmények +HISTORY_MSG_10;Sötét tónus tömörítés +HISTORY_MSG_11;Tónusgörbe +HISTORY_MSG_12;Auto szint +HISTORY_MSG_13;Vágás +HISTORY_MSG_14;Luminancia fényerÅ‘ +HISTORY_MSG_15;Luminancia kontraszt +HISTORY_MSG_16;Luminancia fekete szint +HISTORY_MSG_17;Luminancia világos tónus tömörítés +HISTORY_MSG_18;Luminancia sötét tónus tömörítés +HISTORY_MSG_19;Luminancia görbe +HISTORY_MSG_1;Kép betöltve +HISTORY_MSG_20;Élesítés +HISTORY_MSG_21;Élesítés sugara +HISTORY_MSG_22;Élesítés mértéke +HISTORY_MSG_23;Élesítés küszöb +HISTORY_MSG_24;Csak az élek élesítése +HISTORY_MSG_25;Élesítés élferismerési sugár +HISTORY_MSG_26;Élesítés élferismerési tolerancia +HISTORY_MSG_27;Élesítés mellékhatás csökkentés +HISTORY_MSG_28;Élesítés mellékhatás csökkentés mértéke +HISTORY_MSG_29;Élesítés algoritmusa +HISTORY_MSG_2;Beállítások betöltése +HISTORY_MSG_30;Dekonvolúciós sugár +HISTORY_MSG_31;Deconvolúció mértéke +HISTORY_MSG_32;Deconvolúció zajelnyomás +HISTORY_MSG_33;Deconvolúció iterációszám +HISTORY_MSG_34;SzíntelítÅ‘dés megelÅ‘zés +HISTORY_MSG_35;Telítettség korlátozó +HISTORY_MSG_36;Telítettség korlát +HISTORY_MSG_37;Színtelítettség +HISTORY_MSG_38;Fehéregyensúly beállítás +HISTORY_MSG_39;SzínhÅ‘mérséklet +HISTORY_MSG_3;Beállítások változtatása +HISTORY_MSG_40;Fehér árnyalat +HISTORY_MSG_41;Színeltolás "A" +HISTORY_MSG_42;Színeltolás "B" +HISTORY_MSG_43;Luminanciazaj-csökkentés +HISTORY_MSG_44;Lum. zajcsökkentés sugár +HISTORY_MSG_45;Lum. zajcsökkentés éltolerancia +HISTORY_MSG_46;Színzaj-csökkentés +HISTORY_MSG_47;Színzaj-csökkentés sugár +HISTORY_MSG_48;Színzaj-csökkentés éltolerancia +HISTORY_MSG_49;Élérzékeny színzaj-csökkentés +HISTORY_MSG_4;ElÅ‘zmény böngészés +HISTORY_MSG_50;Ãrnyékok/Fények korrekció +HISTORY_MSG_51;Fényes részek +HISTORY_MSG_52;Sötét részek +HISTORY_MSG_53;Világos tonális szélesség +HISTORY_MSG_54;Sötét tonális szélesség +HISTORY_MSG_55;Lokális kontraszt +HISTORY_MSG_56;Ãrnyékok/Fények sugár +HISTORY_MSG_57;Durva forgatás +HISTORY_MSG_58;Vízszintes tükrözés +HISTORY_MSG_59;FüggÅ‘leges tükrözés +HISTORY_MSG_5;FényerÅ‘ +HISTORY_MSG_60;Forgatás +HISTORY_MSG_61;Forgatás +HISTORY_MSG_62;Torzítás korrekció +HISTORY_MSG_63;Pillanatkép kiválasztás +HISTORY_MSG_64;Képkivágás +HISTORY_MSG_65;Kromatikus aberráció korrigálás +HISTORY_MSG_66;Beégett részek megmentése +HISTORY_MSG_67;Beégett részek visszaállítása +HISTORY_MSG_68;Beégett részek algoritmus +HISTORY_MSG_69;Munka színprofil +HISTORY_MSG_6;Kontraszt +HISTORY_MSG_70;Kimeneti színprofil +HISTORY_MSG_71;Bemeneti színprofil +HISTORY_MSG_72;Saroksötétedés +HISTORY_MSG_73;Szín keverÅ‘ +HISTORY_MSG_74;Ãtméretezés szorzó +HISTORY_MSG_75;Ãtméretezés algoritmus +HISTORY_MSG_76;Exif Meta-adatok +HISTORY_MSG_77;IPTC Meta-adatok +HISTORY_MSG_7;Fekete szint +HISTORY_MSG_8;Expozíció kompenzáció +HISTORY_MSG_9;Világos tónus tömörítés +HISTORY_NEWSNAPSHOT;Új +HISTORY_NEWSNAPSHOTAS;cimkével... +HISTORY_NEWSSDIALOGLABEL;Pillanatkép cimkéje: +HISTORY_NEWSSDIALOGTITLE;Új pillanatkép +HISTORY_SETTO;új érték: +HISTORY_SNAPSHOT;Pillanatkép +HISTORY_SNAPSHOTS;Pillanatképek +ICMPANEL_FILEDLGFILTERANY;inden fájl +ICMPANEL_FILEDLGFILTERICM;ICC színprofil fájl +ICMPANEL_GAMMABEFOREINPUT;Gamma korrekció a bemeneti profil elÅ‘tt +ICMPANEL_INPUTCAMERA;FényképezÅ‘gép alapértelmezése +ICMPANEL_INPUTCUSTOM;Saját +ICMPANEL_INPUTDLGLABEL;Bemeneti színprofil kiválasztása... +ICMPANEL_INPUTEMBEDDED;Beágyazott profil, ha van +ICMPANEL_INPUTPROFILE;Bemeneti színprofil +ICMPANEL_NOICM;Nincs színmenedzsment: sRGB kimenet +ICMPANEL_OUTPUTDLGLABEL;Kimeneti színprofil kiválasztása... +ICMPANEL_OUTPUTPROFILE;Kimeneti színprofil +ICMPANEL_SAVEREFERENCE;Referencia kép mentése profil kalibráláshoz +ICMPANEL_WORKINGPROFILE;Munka színprofil +IMAGEAREA_DETAILVIEW;Részlet nézet +IPTCPANEL_AUTHOR;SzerzÅ‘ +IPTCPANEL_AUTHORHINT;A kép létrehozójának neve, pl. író, fényképész, grafikus művész (By-line) +IPTCPANEL_AUTHORSPOSITION;SzerzÅ‘ titulusa +IPTCPANEL_AUTHORSPOSITIONHINT;A kép létrehozójának munkaköre illetve titulusa (By-line Title) +IPTCPANEL_CAPTION;Leírás +IPTCPANEL_CAPTIONHINT;A kép szöveges leírása (Caption - Abstract) +IPTCPANEL_CAPTIONWRITER;Ãró +IPTCPANEL_CAPTIONWRITERHINT;A leírást és az adatok rögzítését/szerkesztését/javítását végzÅ‘ személy neve (Writer - Editor) +IPTCPANEL_CATEGORY;Kategória +IPTCPANEL_CATEGORYHINT;A kép témáját azonosítja (Category) +IPTCPANEL_CITY;Város +IPTCPANEL_CITYHINT;A város, ahonnan a kép származik (City) +IPTCPANEL_COPYHINT;IPTC beállítások másolása a vágólapra +IPTCPANEL_COPYRIGHT;SzerzÅ‘i jog +IPTCPANEL_COPYRIGHTHINT;SzerzÅ‘i joggal kapcsolatos megjegyzések (Copyright Notice) +IPTCPANEL_COUNTRY;Ország +IPTCPANEL_COUNTRYHINT;Az ország, ahonnan a kép származik (Country - Primary Location Name) +IPTCPANEL_CREDIT;RendelkezÅ‘ +IPTCPANEL_CREDITHINT;A kép kibocsájtójának neve (nem feltétlenül a szerzÅ‘) (Credit) +IPTCPANEL_DATECREATED;Dátum +IPTCPANEL_DATECREATEDHINT;A kép rögzítésének dátuma; formátum: ééééhhnn (Date Created) +IPTCPANEL_EMBEDDED;Beágyazott +IPTCPANEL_EMBEDDEDHINT;A betöltött képbe ágyazott információk kiolvasása +IPTCPANEL_HEADLINE;FÅ‘cím +IPTCPANEL_HEADLINEHINT;A kép témájának összegzése (Headline) +IPTCPANEL_INSTRUCTIONS;Útmutatás +IPTCPANEL_INSTRUCTIONSHINT;Egyéb, a képre vonatkozó szerkesztési útmutatás (Special Instructions) +IPTCPANEL_KEYWORDS;Kulcsszavak +IPTCPANEL_KEYWORDSHINT;Kategorizáláshoz/szűréshez használatos, a képre vonatkozó kulcsszavak (Keywords) +IPTCPANEL_PASTEHINT;IPTC beállítások beillesztése a vágólapról +IPTCPANEL_PROVINCE;Régió +IPTCPANEL_PROVINCEHINT;A megye/állam/régió, ahonnan a kép származik (Province-State) +IPTCPANEL_RESET;Visszaállítás +IPTCPANEL_RESETHINT;Visszatérés az aktuális profil alapértékéhez +IPTCPANEL_SOURCE;Forrás +IPTCPANEL_SOURCEHINT;A kép szellemi tartalmának eredeti tulajdonosa (Source) +IPTCPANEL_SUPPCATEGORIES;További kategóriák +IPTCPANEL_SUPPCATEGORIESHINT;A kép finomabb, részletesebb kategorizálását teszi lehetÅ‘vé (Supplemental Categories) +IPTCPANEL_TITLE;Címke +IPTCPANEL_TITLEHINT;A kép rövid azonosítója (Object Name) +IPTCPANEL_TRANSREFERENCE;Továbbítás helye +IPTCPANEL_TRANSREFERENCEHINT;A továbbítás helyének megjelölése (Original Transmission Reference) +MAIN_BUTTON_PREFERENCES;Beállítások +MAIN_BUTTON_SAVE;Kép mentése +MAIN_BUTTON_SAVEAS;másként... +MAIN_BUTTON_SENDTOEDITOR;Megnyitás külsÅ‘ programmal +MAIN_MSG_ALREADYEXISTS;Ilyen nevü fájl már létezik. +MAIN_MSG_CANNOTLOAD;A képet nem sikerült betölteni. +MAIN_MSG_CANNOTSAVE;Hiba történt a fájl mentése közben. +MAIN_MSG_CANNOTSTARTEDITOR;A meadott külsÅ‘ program nem indítható. +MAIN_MSG_CANNOTSTARTEDITOR_SECONDARY;Ãllítsa be a helyes elérési útat a "Beállítások" ablakban. +MAIN_MSG_EXITJOBSINQUEUEINFO;A sorban álló feldolgozatlan képek kilépéskor el fognak veszni. +MAIN_MSG_EXITJOBSINQUEUEQUEST;Biztos, hogy ki akar lépni? Feldolgozatlan képek vannak a feldolgozási sorban. +MAIN_MSG_JOBSINQUEUE;tennivaló vár a sorban +MAIN_MSG_QOVERWRITE;Felülírjam? +MAIN_TAB_BASIC;Alap +MAIN_TAB_COLOR;Színek +MAIN_TAB_DETAIL;Részletek +MAIN_TAB_EXIF;Exif +MAIN_TAB_EXPOSURE;Expozíció +MAIN_TAB_ICM;ICM +MAIN_TAB_IPTC;IPTC +MAIN_TAB_METADATA;Meta-adatok +MAIN_TAB_TRANSFORM;Transzformáció +MAIN_TOOLTIP_HIDEFP;A fájlkezelÅ‘ alsó panel elrejtése/megjelenítése (Gyorsbillentyű: F) +MAIN_TOOLTIP_HIDEHP;Az elÅ‘zményeket is tartalmazó bal panel elrejtése/megjelenítése (Gyorsbillentyű: H) +MAIN_TOOLTIP_INDCLIPPEDH;Túlexponált területek jelzése +MAIN_TOOLTIP_INDCLIPPEDS;Alulexponált területek jelzése +MAIN_TOOLTIP_PREFERENCES;Beállítások megváltoztatása +MAIN_TOOLTIP_QINFO;Néhány fontos információ megjelenítése a képrÅ‘l +MAIN_TOOLTIP_SAVE;A kép mentése az alapértelmezett könyvtárba az alapértelmezett néven +MAIN_TOOLTIP_SAVEAS;A kép mentése a kiválasztott könyvtárba +PARTIALPASTE_BASICGROUP;Alapbeállítások +PARTIALPASTE_CACORRECTION;Kromatikus aberráció +PARTIALPASTE_COARSETRANS;90 fokonkénti forgatás/tükrözés +PARTIALPASTE_COLORBOOST;Színtelítettség +PARTIALPASTE_COLORDENOISE;Színzaj-csökkentés +PARTIALPASTE_COLORGROUP;Színeket érintÅ‘ beállítások +PARTIALPASTE_COLORMIXER;SzínkeverÅ‘ +PARTIALPASTE_COLORSHIFT;Színeltolás +PARTIALPASTE_COMPOSITIONGROUP;Kompozíciós beállítások +PARTIALPASTE_CROP;Crop +PARTIALPASTE_DIALOGLABEL;Feldolgozási beállítások részleges alkalmazása +PARTIALPASTE_DISTORTION;Torzítás +PARTIALPASTE_EXIFCHANGES;Exif változtatások +PARTIALPASTE_EXPOSURE;Expozíció +PARTIALPASTE_HLRECOVERY;Beégett részletek megmentése +PARTIALPASTE_ICMSETTINGS;ICM beállítások +PARTIALPASTE_IPTCINFO;IPTC információk +PARTIALPASTE_LENSGROUP;Objektív optikai hibáinak javítása +PARTIALPASTE_LUMACURVE;Luminancia görbe +PARTIALPASTE_LUMADENOISE;Luminanciazaj-csökkentés +PARTIALPASTE_LUMINANCEGROUP;Luminanciát érintÅ‘ beállítások +PARTIALPASTE_METAICMGROUP;Meta-adat/Színprofil beállítások +PARTIALPASTE_RESIZE;Ãtméretezés +PARTIALPASTE_ROTATION;Forgatás +PARTIALPASTE_SHADOWSHIGHLIGHTS;Ãrnyékos/Fényes részek +PARTIALPASTE_SHARPENING;Élesítés +PARTIALPASTE_VIGNETTING;Saroksötétedés +PARTIALPASTE_WHITEBALANCE;Fehéregyensúly +PREFERENCES_APPLNEXTSTARTUP;újraindítás után érvényes +PREFERENCES_BLINKCLIPPED;Beégett részek villogtatása +PREFERENCES_CACHECLEARALL;Teljes gyorsítótár törlése +PREFERENCES_CACHECLEARPROFILES;Feldolgozási paraméterek törlése +PREFERENCES_CACHECLEARTHUMBS;ElÅ‘nézeti képek törlése +PREFERENCES_CACHEFORMAT1;Egyebi (gyorsabb és szebb) +PREFERENCES_CACHEFORMAT2;JPEG (kisebb a háttértáron) +PREFERENCES_CACHEMAXENTRIES;Gyorsítótárban tárolt képek max. száma +PREFERENCES_CACHEOPTS;Gyorsítótár beállítások +PREFERENCES_CACHESTRAT1;Inkább gyors mint memóriatakarékos +PREFERENCES_CACHESTRAT2;Inkább memóriatakarékos mint gyors +PREFERENCES_CACHESTRAT;Gyorsítótár stratégia +PREFERENCES_CACHETHUMBFORM;ElÅ‘nézeti kép formátuma +PREFERENCES_CACHETHUMBHEIGHT;ElÅ‘nézeti kép maximális magassága +PREFERENCES_CLEARDLG_LINE1;Gyorsítótár ürítése +PREFERENCES_CLEARDLG_LINE2;Ez eltarthat pár másodpercig. +PREFERENCES_CLEARDLG_TITLE;Kérem várjon +PREFERENCES_CLIPPINGIND;Beégett részek jelzése +PREFERENCES_CMETRICINTENT;Intent +PREFERENCES_DATEFORMAT;Dátumformátum +PREFERENCES_DATEFORMATHINT;A következÅ‘ jeleket lehet használni:\n%y : év\n%m : hónap\n%d : nap\n\nPéldául a magyar dátumformátum:\n%y/%m/%d +PREFERENCES_DEFAULTLANG;Alapértelmezett nyelv +PREFERENCES_DEFAULTTHEME;Alapértelmezett kinézet +PREFERENCES_DEMOSAICINGALGO;Bayer interpoláció +PREFERENCES_DIRHOME;Saját könyvtár +PREFERENCES_DIRLAST;Utoljára látogatott könyvtár +PREFERENCES_DIROTHER;Más +PREFERENCES_DIRSELECTDLG;Képek könyvtára induláskor... +PREFERENCES_DIRSOFTWARE;Telepítés helye +PREFERENCES_DMETHOD;Algoritmus +PREFERENCES_EDITORCMDLINE;Egyéb parancssor +PREFERENCES_EXTERNALEDITOR;KülsÅ‘ képszerkesztÅ‘ program +PREFERENCES_FALSECOLOR;Színhiba-elnyomási lépések +PREFERENCES_FBROWSEROPTS;Fájl böngészÅ‘ beállítások +PREFERENCES_FILEFORMAT;Fájl formátum +PREFERENCES_FORIMAGE;Egyéb képekre +PREFERENCES_FORRAW;RAW fájlokra +PREFERENCES_GIMPPATH;GIMP telepítési könyvtára +PREFERENCES_GTKTHEME;Alap GTK kinézet +PREFERENCES_HINT;Tipp +PREFERENCES_HLTHRESHOLD;Küszöbérték kiégett fényekhez +PREFERENCES_ICCDIR;ICC profilok könyvtára +PREFERENCES_IMPROCPARAMS;Alapértelmezett feldolgozási paraméterek +PREFERENCES_INTENT_ABSOLUTE;Absolute Colorimetric +PREFERENCES_INTENT_PERCEPTUAL;Perceptual +PREFERENCES_INTENT_RELATIVE;Relative Colorimetric +PREFERENCES_INTENT_SATURATION;Saturation +PREFERENCES_LIVETHUMBNAILS;ÉlÅ‘ elÅ‘nézeti képek (lassabb) +PREFERENCES_MONITORICC;Monitor ICC profilja +PREFERENCES_OUTDIR;Kimeneti alapértelmezett könyvtár +PREFERENCES_OUTDIRFOLDER;Mentés ebbe a könyvtárba: +PREFERENCES_OUTDIRFOLDERHINT;Ha ezt a lehetÅ‘séget választja, az összes feldolgozott képek ebbe a könyvtárba kerül +PREFERENCES_OUTDIRHINT;A következÅ‘ jeleket lehet használni:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nEzek a jelek a megnyitott kép elérési útvonalának részeire vonatkoznak.\n\nPéldául, ha a /home/tom/image/02-09-2006/dsc0012.nef képet nyitjuk meg, ezek a jelek a következÅ‘ket jelentik:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nHa oda kívánja menteni a kész képet, ahol az eredeti volt, az alábbiakat kell beírni:\n%p1/%f\n\nHa a kész képet az eredeti könyvtárán belül egy "converted" alkönyvtárba kívánja menteni, az alábbiakat kell beírni:\n%p1/converted/%f\n\nHa a kész képeket a '/home/tom/converted' könyvtárba kívánja menteni az eredeti, dátumot tartalmazó alkönyvtár megtartásával, írja ezt:\n%p2/converted/%d1/%f +PREFERENCES_OUTDIRTEMPLATE;Sablon használata +PREFERENCES_OUTDIRTEMPLATEHINT;A következÅ‘ jeleket lehet használni:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nEzek a jelek a megnyitott kép elérési útvonalának részeire vonatkoznak.\n\nPéldául, ha a /home/tom/image/02-09-2006/dsc0012.nef képet nyitjuk meg, ezek a jelek a következÅ‘ket jelentik:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nHa oda kívánja menteni a kész képet, ahol az eredeti volt, az alábbiakat kell beírni:\n%p1/%f\n\nHa a kész képet az eredeti könyvtárán belül egy "converted" alkönyvtárba kívánja menteni, az alábbiakat kell beírni:\n%p1/converted/%f\n\nHa a kész képeket a '/home/tom/converted' könyvtárba kívánja menteni az eredeti, dátumot tartalmazó alkönyvtár megtartásával, írja ezt:\n%p2/converted/%d1/%f +PREFERENCES_PARSEDEXT;Felismert kiterjesztések +PREFERENCES_PARSEDEXTADD;Kiterjesztés hozzáadása +PREFERENCES_PARSEDEXTADDHINT;A kiterjesztés beírása után ez a gomb felveszi a listára +PREFERENCES_PARSEDEXTDELHINT;A kiválasztott sor törlése a listából +PREFERENCES_PROFILEHANDLING;Feldolgozási paraméterek kezelése +PREFERENCES_PROFILELOADPR;Ha mindkét helyen van feldolgozási paraméter +PREFERENCES_PROFILEPRCACHE;A gyorsítótárban lévÅ‘t használja +PREFERENCES_PROFILEPRFILE;A kép mellettit használja +PREFERENCES_PROFILESAVECACHE;Feldolgozási paraméterek mentése a gyorsítótárba +PREFERENCES_PROFILESAVEINPUT;Feldolgozási paraméterek mentése a kép mellé +PREFERENCES_PSPATH;Adobe Photoshop telepítési könyvtára +PREFERENCES_SELECTICCDIRDLG;ICC profilok könyvtárának kiválasztása... +PREFERENCES_SELECTLANG;Nyelv kiválasztása +PREFERENCES_SELECTMONITORPROFDLG;Monitor ICC profiljának kiválasztása... +PREFERENCES_SELECTTHEME;Kinézet kiválasztása +PREFERENCES_SHOWBASICEXIF;Fontosabb Exif információk megjelenítése +PREFERENCES_SHOWDATETIME;Felvétel dátumának és idejének megjelenítése +PREFERENCES_SHOWONLYRAW;Csak a RAW fájok megjelenítése +PREFERENCES_SHTHRESHOLD;Küszöbérték elveszett árnyékokhoz +PREFERENCES_STARTUPIMDIR;Képek könyvtára induláskor +PREFERENCES_TAB_BROWSER;Fájl böngészÅ‘ +PREFERENCES_TAB_COLORMGR;Szín menedzsment +PREFERENCES_TAB_GENERAL;Ãltalános +PREFERENCES_TAB_IMPROC;Képfeldolgozás +PREFERENCES_TAB_OUTPUT;Fájl mentési beállítások +PREFERENCES_THUMBSIZE;Képek mérete a böngészÅ‘ben +PROFILEPANEL_FILEDLGFILTERANY;Minden fájl +PROFILEPANEL_FILEDLGFILTERPP;Feldolgozási beállítások +PROFILEPANEL_LABEL;Feldolgozási beállítások +PROFILEPANEL_LOADDLGLABEL;Feldolgozási beállítások betöltése... +PROFILEPANEL_PCUSTOM;Egyedi +PROFILEPANEL_PFILE;Fáljból +PROFILEPANEL_PLASTPHOTO;ElÅ‘zÅ‘ fotó +PROFILEPANEL_PLASTSAVED;Legutóbb használt +PROFILEPANEL_PROFILE;Beállítások +PROFILEPANEL_SAVEDLGLABEL;Feldolgozási beállítások mentése... +PROFILEPANEL_TOOLTIPCOPY;Feldolgozási beállítások vágólapra mentése +PROFILEPANEL_TOOLTIPLOAD;Feldolgozási beállítások betöltése +PROFILEPANEL_TOOLTIPPASTE;Feldolgozási beállítások beillesztése a vágólapról +PROFILEPANEL_TOOLTIPSAVE;Feldolgozási beállítások mentése +PROGRESSBAR_DECODING;Raw fájl dekódolása... +PROGRESSBAR_DEMOSAICING;Bayer interpoláció... +PROGRESSBAR_LOADING;Kép betöltése... +PROGRESSBAR_LOADJPEG;JPEG fájl betöltése... +PROGRESSBAR_LOADPNG;PNG fájl betöltése... +PROGRESSBAR_LOADTIFF;TIFF fájl betöltése... +PROGRESSBAR_PROCESSING;Kép feldolgozása... +PROGRESSBAR_READY;Kész. +PROGRESSBAR_SAVEJPEG;JPEG fájl mentése... +PROGRESSBAR_SAVEPNG;PNG fájl mentése... +PROGRESSBAR_SAVETIFF;TIFF fájl mentése... +PROGRESSDLG_LOADING;Fájl betöltése... +PROGRESSDLG_PROCESSING;Kép feldolgozása... +PROGRESSDLG_SAVING;Fájl mentése... +QINFO_FOCALLENGTH;Fokális távolság +QINFO_ISO;ISO +QINFO_LENS;Objektív +QINFO_NOEXIF;Exif adat nem áll rendelkezésre. +SAVEDLG_FILEFORMAT;Fájl formátum +SAVEDLG_JPEGQUAL;JPEG MinÅ‘ség +SAVEDLG_JPGFILTER;JPEG fájlok +SAVEDLG_PNGCOMPR;PNG Tömörítés +SAVEDLG_PNGFILTER;PNG fájlok +SAVEDLG_PUTTOQUEUE;Feldolgozási sorba helyezés +SAVEDLG_PUTTOQUEUEHEAD;Feldolgozási sorba helyezés az elsÅ‘ helyre +SAVEDLG_PUTTOQUEUETAIL;Feldolgozási sorba helyezés az utolsó helyre +SAVEDLG_SAVEIMMEDIATELY;Mentés azonnal +SAVEDLG_SAVESPP;Feldolgozási paraméterek mentése a kép mellé +SAVEDLG_TIFFFILTER;TIFF fájlok +TOOLBAR_TOOLTIP_CROP;Képkivágás (Gyorsbillentyű: C) +TOOLBAR_TOOLTIP_HAND;"Kéz" eszköz (Gyorsbillentyű: N) +TOOLBAR_TOOLTIP_STRAIGHTEN;Vizszintes/függÅ‘leges vonal kijelölése (Gyorsbillentyű: S) +TOOLBAR_TOOLTIP_WB;Fehéregyensúly kijelölés (Gyorsbillentyű: W) +TP_CACORRECTION_BLUE;Kék +TP_CACORRECTION_LABEL;Kromatikus aberráció +TP_CACORRECTION_RED;Piros +TP_CHMIXER_BLUE;Kék +TP_CHMIXER_GREEN;Zöld +TP_CHMIXER_LABEL;SzínkeverÅ‘ +TP_CHMIXER_RED;Piros +TP_COARSETRAF_DEGREE;fok: +TP_COARSETRAF_TOOLTIP_HFLIP;Vizszintes tükrözés +TP_COARSETRAF_TOOLTIP_ROTLEFT;Forgatás balra +TP_COARSETRAF_TOOLTIP_ROTRIGHT;Forgatás jobbra +TP_COARSETRAF_TOOLTIP_VFLIP;FüggÅ‘leges tükrözés +TP_COLORBOOST_ACHANNEL;"a" csatorna +TP_COLORBOOST_AMOUNT;Mennyiség +TP_COLORBOOST_AVOIDCOLORCLIP;Szín telítÅ‘dés elkerülése +TP_COLORBOOST_BCHANNEL;"b" csatorna +TP_COLORBOOST_CHAB;a & b együtt +TP_COLORBOOST_CHANNEL;Csatorna +TP_COLORBOOST_CHSEPARATE;külön +TP_COLORBOOST_ENABLESATLIMITER;Telítettség korlátozás +TP_COLORBOOST_LABEL;Színtelítettség +TP_COLORBOOST_SATLIMIT;Telítettség korlát +TP_COLORDENOISE_EDGESENSITIVE;Élérzékeny +TP_COLORDENOISE_EDGETOLERANCE;Él tolerancia +TP_COLORDENOISE_LABEL;Színzaj-csökkentés +TP_COLORDENOISE_RADIUS;Sugár +TP_COLORSHIFT_BLUEYELLOW;Kék-Sárga +TP_COLORSHIFT_GREENMAGENTA;Zöld-Lila +TP_COLORSHIFT_LABEL;Színeltolás +TP_CROP_DPI;DPI= +TP_CROP_FIXRATIO;Rögzített oldalarány +TP_CROP_GTDIAGONALS;Diagonál módszer +TP_CROP_GTHARMMEANS1;Aranymetszés 1 +TP_CROP_GTHARMMEANS2;Aranymetszés 2 +TP_CROP_GTHARMMEANS3;Aranymetszés 3 +TP_CROP_GTHARMMEANS4;Aranymetszés 4 +TP_CROP_GTNONE;Nincs +TP_CROP_GTRULETHIRDS;Harmadolás +TP_CROP_GUIDETYPE;Segédvonal típusa: +TP_CROP_H;M +TP_CROP_LABEL;Kivágás +TP_CROP_SELECTCROP; Kijelölés egérrel +TP_CROP_W;Sz +TP_CROP_X;x +TP_CROP_Y;y +TP_DISTORTION_AMOUNT;ErÅ‘sség +TP_DISTORTION_LABEL;Torzítás +TP_EXPOSURE_AUTOLEVELS;Auto szint +TP_EXPOSURE_BLACKLEVEL;Fekete szint +TP_EXPOSURE_BRIGHTNESS;FényerÅ‘ +TP_EXPOSURE_CLIP;Vágás +TP_EXPOSURE_COMPRHIGHLIGHTS;Világos tónus tömörítés +TP_EXPOSURE_COMPRSHADOWS;Sötét tónus tömörítés +TP_EXPOSURE_CONTRAST;Kontraszt +TP_EXPOSURE_CURVEEDITOR;Tónusgörbe +TP_EXPOSURE_EXPCOMP;Exp. Kompenzáció +TP_EXPOSURE_LABEL;Expozíció +TP_HLREC_CIELAB;CIELab visszaállítás +TP_HLREC_COLOR;Szín terjesztés +TP_HLREC_LABEL;Beégett részletek megmentése +TP_HLREC_LUMINANCE;Luminancia +TP_HLREC_METHOD;Preferencia: +TP_ICM_FILEDLGFILTERANY;inden fájl +TP_ICM_FILEDLGFILTERICM;ICC színprofil fájl +TP_ICM_GAMMABEFOREINPUT;Gamma korrekció a bemeneti profil elÅ‘tt +TP_ICM_INPUTCAMERA;FényképezÅ‘gép alapértelmezése +TP_ICM_INPUTCUSTOM;Saját +TP_ICM_INPUTDLGLABEL;Bemeneti színprofil kiválasztása... +TP_ICM_INPUTEMBEDDED;Beágyazott profil, ha van +TP_ICM_INPUTPROFILE;Bemeneti színprofil +TP_ICM_LABEL;ICM +TP_ICM_NOICM;Nincs színmenedzsment: sRGB kimenet +TP_ICM_OUTPUTDLGLABEL;Kimeneti színprofil kiválasztása... +TP_ICM_OUTPUTPROFILE;Kimeneti színprofil +TP_ICM_SAVEREFERENCE;Referencia kép mentése profil kalibráláshoz +TP_ICM_WORKINGPROFILE;Munka színprofil +TP_LUMACURVE_BLACKLEVEL;Fekete szint +TP_LUMACURVE_BRIGHTNESS;FényerÅ‘ +TP_LUMACURVE_COMPRHIGHLIGHTS;Világos tónus tömörítés +TP_LUMACURVE_COMPRSHADOWS;Sötét tónus tömörítés +TP_LUMACURVE_CONTRAST;Kontraszt +TP_LUMACURVE_CURVEEDITOR;Fényesség görbe +TP_LUMACURVE_LABEL;Luminancia +TP_LUMADENOISE_EDGETOLERANCE;Él tolerancia +TP_LUMADENOISE_LABEL;Luminanciazaj-csökkentés +TP_LUMADENOISE_RADIUS;Sugár +TP_RESIZE_BICUBIC;Bicubic +TP_RESIZE_BICUBICSF;Bicubic (lágyabb) +TP_RESIZE_BICUBICSH;Bicubic (keményebb) +TP_RESIZE_BILINEAR;Bilineáris +TP_RESIZE_FULLSIZE;Képméret: +TP_RESIZE_H;M: +TP_RESIZE_LABEL;Ãtméretezés +TP_RESIZE_METHOD;Algoritmus: +TP_RESIZE_NEAREST;Legközelebbi szomszéd +TP_RESIZE_SCALE;Szorzó +TP_RESIZE_W;Sz: +TP_ROTATE_AUTOCROP;Autómatikus kivágás +TP_ROTATE_DEGREE;Fok +TP_ROTATE_FILL;Kitöltés +TP_ROTATE_LABEL;Forgatás +TP_ROTATE_SELECTLINE; Vizszintes vonal kijelölése +TP_SHADOWSHLIGHTS_HIGHLIGHTS;Fényes részek +TP_SHADOWSHLIGHTS_HLTONALW;Tonális szélesség +TP_SHADOWSHLIGHTS_LABEL;Ãrnyékos/Fényes részek +TP_SHADOWSHLIGHTS_LOCALCONTR;Lokális kontraszt +TP_SHADOWSHLIGHTS_RADIUS;Sugár +TP_SHADOWSHLIGHTS_SHADOWS;Sötét részek +TP_SHADOWSHLIGHTS_SHTONALW;Tonális szélesség +TP_SHARPENING_AMOUNT;ErÅ‘sség +TP_SHARPENING_EDRADIUS;Sugár +TP_SHARPENING_EDTOLERANCE;Él tolerancia +TP_SHARPENING_HALOCONTROL;Mellékhatás csökkentés +TP_SHARPENING_HCAMOUNT;Mértéke +TP_SHARPENING_LABEL;Élesítés +TP_SHARPENING_METHOD;Algoritmus +TP_SHARPENING_ONLYEDGES;Csak az élek élesítése +TP_SHARPENING_RADIUS;Sugár +TP_SHARPENING_RLD;RL Dekonvolúció +TP_SHARPENING_RLD_AMOUNT;ErÅ‘sség +TP_SHARPENING_RLD_DAMPING;Zajelnyomás +TP_SHARPENING_RLD_ITERATIONS;Iterációszám +TP_SHARPENING_THRESHOLD;Küszöb +TP_SHARPENING_USM;Unsharp Mask +TP_VIGNETTING_AMOUNT;ErÅ‘sség +TP_VIGNETTING_LABEL;Saroksötétedés +TP_VIGNETTING_RADIUS;Sugár +TP_WBALANCE_AUTO;Automatikus +TP_WBALANCE_CAMERA;Tárolt +TP_WBALANCE_CUSTOM;Egyedi +TP_WBALANCE_GREEN;Ãrnyalat +TP_WBALANCE_LABEL;Fehéregyensúly +TP_WBALANCE_METHOD;Beállítás +TP_WBALANCE_SIZE;Méret: +TP_WBALANCE_SPOTWB;Mintavétel +TP_WBALANCE_TEMPERATURE;SzínhÅ‘mérséklet +ZOOMBAR_DETAIL;Részlet nézet +ZOOMBAR_HUGE;Nagyobb +ZOOMBAR_LARGE;Nagy +ZOOMBAR_NORMAL;Normál +ZOOMBAR_PREVIEW;ElÅ‘nézet +ZOOMBAR_SCALE;Kicsinyítés +ZOOMBAR_SMALL;Kicsi diff --git a/release/languages/nederlands b/release/languages/nederlands new file mode 100755 index 000000000..e16b182ce --- /dev/null +++ b/release/languages/nederlands @@ -0,0 +1,578 @@ +# RT 2.3 Nederlands +# 26.12.2007: door Rens Duijsens en Brent Huisman +# 14.03.2008: updated by reggybe +# 26.12.2008: updated to RT2.4b4 by paul.matthijsse +ADJUSTER_RESET_TO_DEFAULT;Terug naar beginwaarde +CURVEEDITOR_FILEDLGFILTERANY;Alle bestanden +CURVEEDITOR_FILEDLGFILTERCURVE;Curvebestanden +CURVEEDITOR_LINEAR;Lineair +CURVEEDITOR_LOADDLGLABEL;Laad curve... +CURVEEDITOR_SAVEDLGLABEL;Bewaar curve... +CURVEEDITOR_TOOLTIPLINEAR;Maak curve lineair +CURVEEDITOR_TOOLTIPLOAD;Laad curve uit bestand +CURVEEDITOR_TOOLTIPSAVE;Bewaar huidige curve +EXIFFILTER_APERTURE;Diafragma +EXIFFILTER_CAMERA;Camera +EXIFFILTER_DIALOGLABEL;Exif-filter +EXIFFILTER_FOCALLEN;Brandpuntsafstand +EXIFFILTER_ISO;ISO-waarde +EXIFFILTER_LENS;Objectief +EXIFFILTER_SHUTTER;Sluitertijd +EXIFPANEL_ADDEDIT;Voeg toe/bewerk +EXIFPANEL_ADDEDITHINT;Voeg nieuwe tag toe of bewerk tag +EXIFPANEL_ADDTAGDLG_ENTERVALUE;Geef waarde +EXIFPANEL_ADDTAGDLG_SELECTTAG;Selecteer tag +EXIFPANEL_ADDTAGDLG_TITLE;Voeg tag toe of bewerk +EXIFPANEL_KEEP;Bewaar +EXIFPANEL_KEEPHINT;Bewaar geselecteerde tags in doelbestand +EXIFPANEL_REMOVE;Verwijder +EXIFPANEL_REMOVEHINT;Verwijder geselecteerde tags in doelbestand +EXIFPANEL_RESET;Herstel +EXIFPANEL_RESETALL;Herstel alles +EXIFPANEL_RESETALLHINT;Zet alle tags terug naar oorspronkelijke waarden +EXIFPANEL_RESETHINT;Zet geselecteerde tags terug naar oorspronkelijke waarden +EXIFPANEL_SUBDIRECTORY;Submap +FILEBROWSER_APPLYPROFILE;Pas profiel toe +FILEBROWSER_ARRANGEMENTHINT;Verticale/horizontale uitlijning miniaturen +FILEBROWSER_CLEARPROFILE;Verwijder profiel +FILEBROWSER_COPYPROFILE;Kopieer profiel +FILEBROWSER_DELETEDLGLABEL;Bevestiging bestand verwijderen +FILEBROWSER_DELETEDLGMSG;Weet u zeker dat u de geselecteerde %1 bestanden wilt verwijderen? +FILEBROWSER_EMPTYTRASH;Leeg prullenbak +FILEBROWSER_EMPTYTRASHHINT;Verwijder bestanden in prullenbak voorgoed +FILEBROWSER_EXIFFILTERAPPLY;Activeer +FILEBROWSER_EXIFFILTERAPPLYHINT;Pas Exif-filter toe op bestandsnavigator +FILEBROWSER_EXIFFILTERLABEL;Exif-filter +FILEBROWSER_EXIFFILTERSETTINGS;Stel in +FILEBROWSER_EXIFFILTERSETTINGSHINT;Stel Exif-filter in +FILEBROWSER_PARTIALPASTEPROFILE;Gedeeltelijk plakken +FILEBROWSER_PASTEPROFILE;Plak profiel +FILEBROWSER_POPUPCANCELJOB;Verwijder uit verwerkingsrij +FILEBROWSER_POPUPMOVEEND;Naar eind van verwerkingsrij +FILEBROWSER_POPUPMOVEHEAD;Naar begin verwerkingsrij +FILEBROWSER_POPUPOPEN;Open +FILEBROWSER_POPUPPROCESS;Plaats in verwerkingsrij +FILEBROWSER_POPUPRANK1;Waardeer met 1 ster +FILEBROWSER_POPUPRANK2;Waardeer met 2 sterren +FILEBROWSER_POPUPRANK3;Waardeer met 3 sterren +FILEBROWSER_POPUPRANK4;Waardeer met 4 sterren +FILEBROWSER_POPUPRANK5;Waardeer met 5 sterren +FILEBROWSER_POPUPREMOVE;Verwijder van bestandssysteem +FILEBROWSER_POPUPRENAME;Hernoem +FILEBROWSER_POPUPSELECTALL;Alles selecteren +FILEBROWSER_POPUPTRASH;Verplaats naar prullenbak +FILEBROWSER_POPUPUNRANK;Verwijder sterwaardering +FILEBROWSER_POPUPUNTRASH;Haal terug uit prullenbak +FILEBROWSER_PROCESSINGSETTINGS;Instellingen +FILEBROWSER_PROCESSINGSETTINGSHINT;Kies bestandsformaat en doelmap +FILEBROWSER_RENAMEDLGLABEL;Hernoem bestand +FILEBROWSER_RENAMEDLGMSG;Hernoem bestand "%1" naar: +FILEBROWSER_SHOWDIRHINT;Toon alle foto's in map +FILEBROWSER_SHOWQUEUEHINT;Toon inhoud verwerkingsrij +FILEBROWSER_SHOWRANK1HINT;Toon foto's met 1 ster waardering +FILEBROWSER_SHOWRANK2HINT;Toon foto's met 2 sterren waardering +FILEBROWSER_SHOWRANK3HINT;Toon foto's met 3 sterren waardering +FILEBROWSER_SHOWRANK4HINT;Toon foto's met 4 sterren waardering +FILEBROWSER_SHOWRANK5HINT;Toon foto's met 5 sterren waardering +FILEBROWSER_SHOWTRASHHINT;Toon inhoud prullenbak +FILEBROWSER_SHOWUNRANKHINT;Toon foto's zonder sterwaardering +FILEBROWSER_STARTPROCESSING;Start verwerking +FILEBROWSER_STARTPROCESSINGHINT;Start verwerking/bewaren van bestanden in verwerkingsrij +FILEBROWSER_STOPPROCESSING;Stop verwerking +FILEBROWSER_STOPPROCESSINGHINT;Stop verwerking van foto's in verwerkingsrij +FILEBROWSER_THUMBSIZE;Miniaturen +FILEBROWSER_ZOOMINHINT;Groter +FILEBROWSER_ZOOMOUTHINT;Kleiner +GENERAL_ABOUT;Over +GENERAL_CANCEL;Annuleren +GENERAL_DISABLE;Deactiveren +GENERAL_DISABLED;Gedeactiveerd +GENERAL_ENABLE;Activeer +GENERAL_ENABLED;Geactiveerd +GENERAL_LANDSCAPE;Landschap +GENERAL_LOAD;Laden +GENERAL_NA;nvt. +GENERAL_NO;Nee +GENERAL_OK;OK +GENERAL_PORTRAIT;Portret +GENERAL_SAVE;Opslaan +GENERAL_YES;Ja +HISTOGRAM_LABEL;Histogram +HISTOGRAM_TOOLTIP_B;Toon/verberg blauw histogram +HISTOGRAM_TOOLTIP_G;Toon/verberg groen histogram +HISTOGRAM_TOOLTIP_L;Toon/verberg CIELAB luminantie histogram +HISTOGRAM_TOOLTIP_R;Toon/verberg rood histogram +HISTORY_CHANGED;Veranderd +HISTORY_CUSTOMCURVE;Handmatig +HISTORY_DELSNAPSHOT;Wis +HISTORY_FROMCLIPBOARD;Van klembord +HISTORY_LABEL;Geschiedenis +HISTORY_MSG_10;Schaduwcompressie +HISTORY_MSG_11;Tooncurve +HISTORY_MSG_12;Automatische belichting +HISTORY_MSG_13;Drempel +HISTORY_MSG_14;Lum: helderheid +HISTORY_MSG_15;Lum: contrast +HISTORY_MSG_16;Lum: schaduwen +HISTORY_MSG_17;Lum: compr. hoge lichten +HISTORY_MSG_18;Lum: schaduwcompressie +HISTORY_MSG_19;Luminantiecurve +HISTORY_MSG_1;Foto geladen +HISTORY_MSG_20;Verscherping +HISTORY_MSG_21;Straal verscherping +HISTORY_MSG_22;Hoeveelheid verscherping +HISTORY_MSG_23;Drempel verscherping +HISTORY_MSG_24;Alleen randen verscherpen +HISTORY_MSG_25;Straal randverscherping +HISTORY_MSG_26;Tolerantie randverscherping +HISTORY_MSG_27;Verscherpen halocontrole +HISTORY_MSG_28;Halocontrole hoeveelheid +HISTORY_MSG_29;Verscherpingsmethode +HISTORY_MSG_2;Profiel geladen +HISTORY_MSG_30;Straal RL-verscherping +HISTORY_MSG_31;Hoeveelheid RL-verscherping +HISTORY_MSG_32;Demping RL-verscherping +HISTORY_MSG_33;Herhaling RL-verscherping +HISTORY_MSG_34;Vermijd kleuroversturing +HISTORY_MSG_35;Verzadigingsbegrenzer +HISTORY_MSG_36;Verzadigingslimiet +HISTORY_MSG_37;Kleurversterking +HISTORY_MSG_38;Witbalansmethode +HISTORY_MSG_39;Kleurtemperatuur +HISTORY_MSG_3;Profiel aangepast +HISTORY_MSG_40;Groentint WB +HISTORY_MSG_41;Kleurverschuiving A +HISTORY_MSG_42;Kleurverschuiving B +HISTORY_MSG_43;Ruisreductie luminantie +HISTORY_MSG_44;Straal lum. ruisreductie +HISTORY_MSG_45;Randtolerantie lum. ruisreductie +HISTORY_MSG_46;Ruisreductie kleur +HISTORY_MSG_47;Straal kleurruisreductie +HISTORY_MSG_48;Randtolerantie kleurruisreductie +HISTORY_MSG_49;Randgevoeligheid kleurruisreductie +HISTORY_MSG_4;Door geschiedenis bladeren +HISTORY_MSG_50;Schaduwen/hoge lichten +HISTORY_MSG_51;Compressie hoge lichten +HISTORY_MSG_52;Schaduwen ophelderen +HISTORY_MSG_53;Toonomvang hoge lichten +HISTORY_MSG_54;Toonomvang schaduwen +HISTORY_MSG_55;Lokaal contrast +HISTORY_MSG_56;Straal schaduwen/hoge lichten +HISTORY_MSG_57;Grof roteren +HISTORY_MSG_58;Horizontaal spiegelen +HISTORY_MSG_59;Vertikaal spiegelen +HISTORY_MSG_5;Helderheid +HISTORY_MSG_60;Roteren +HISTORY_MSG_61;Rotatie +HISTORY_MSG_62;Corrigeer lensvervorming +HISTORY_MSG_63;Snapshot +HISTORY_MSG_64;Afbeelding bijsnijden +HISTORY_MSG_65;C/A-correctie +HISTORY_MSG_66;Repareer hoge lichten +HISTORY_MSG_67;Repareer hoge lichten, hoeveelheid +HISTORY_MSG_68;Repareer hoge lichten, methode +HISTORY_MSG_69;Kleurwerkruimte +HISTORY_MSG_6;Contrast +HISTORY_MSG_70;Uitvoerkleurruimte +HISTORY_MSG_71;Invoerkleurruimte +HISTORY_MSG_72;Vignetteringscorrectie +HISTORY_MSG_73;Kanaalmixer +HISTORY_MSG_74;Schalingsinstelling +HISTORY_MSG_75;Schalingsmethode +HISTORY_MSG_76;Exif-metadata +HISTORY_MSG_77;IPTC-metadata +HISTORY_MSG_7;Schaduwen versterken +HISTORY_MSG_8;Belichtingscompensatie +HISTORY_MSG_9;Compressie hoge lichten +HISTORY_NEWSNAPSHOT;Nieuw +HISTORY_NEWSNAPSHOTAS;Als... +HISTORY_NEWSSDIALOGLABEL;Naam snapshot: +HISTORY_NEWSSDIALOGTITLE;Voeg nieuw snapshot toe +HISTORY_SETTO;Instellen +HISTORY_SNAPSHOT;Nieuw +HISTORY_SNAPSHOTS;Snapshots +ICMPANEL_FILEDLGFILTERANY;Alle bestanden +ICMPANEL_FILEDLGFILTERICM;ICC-profielbestanden +ICMPANEL_GAMMABEFOREINPUT;Profiel past gamma toe +ICMPANEL_INPUTCAMERA;Camera +ICMPANEL_INPUTCUSTOM;Handmatig +ICMPANEL_INPUTDLGLABEL;Selecteer invoer-ICC-profiel... +ICMPANEL_INPUTEMBEDDED;Gebruik ingebed profiel indien mogelijk +ICMPANEL_INPUTPROFILE;Invoerprofiel +ICMPANEL_NOICM;Geen ICM: sRGB-uitvoer +ICMPANEL_OUTPUTDLGLABEL;Selecteer uitvoer-ICC-profiel... +ICMPANEL_OUTPUTPROFILE;Uitvoerprofiel +ICMPANEL_SAVEREFERENCE;Bewaar referentiefoto tbv. profiling +ICMPANEL_WORKINGPROFILE;Werkprofiel +IMAGEAREA_DETAILVIEW;Detailvenster +IPTCPANEL_AUTHOR;Auteur +IPTCPANEL_AUTHORHINT;Naam van de maker van het object, bijv. schrijver, fotograaf of ontwerper (By-line) +IPTCPANEL_AUTHORSPOSITION;Positie van de maker +IPTCPANEL_AUTHORSPOSITIONHINT;Titel van de maker(s) van het object (By-line Title) +IPTCPANEL_CAPTION;Omschrijving +IPTCPANEL_CAPTIONHINT;Tekstuele omschrijving van de data (Omschrijving - abstract) +IPTCPANEL_CAPTIONWRITER;Maker van de omschrijving +IPTCPANEL_CAPTIONWRITERHINT;De naam van de persoon betrokken bij het schrijven, bewerken of corrigeren van de foto of omschrijving (Schrijver - Editor) +IPTCPANEL_CATEGORY;Categorie +IPTCPANEL_CATEGORYHINT;Beschrijft het onderwerp van de foto volgens de mening van de maker (Categorie) +IPTCPANEL_CITY;Plaats +IPTCPANEL_CITYHINT;Plaats van de opname (Plaats) +IPTCPANEL_COPYHINT;Kopieer IPTC-instellingen naar klembord +IPTCPANEL_COPYRIGHT;Copyright +IPTCPANEL_COPYRIGHTHINT;Eventuele vereiste copyright-meldingen (Copyright-melding) +IPTCPANEL_COUNTRY;Land +IPTCPANEL_COUNTRYHINT;De naam van het land/primaire locatie waar de foto werd genomen (Land - Primaire locatienaam) +IPTCPANEL_CREDIT;Credit +IPTCPANEL_CREDITHINT;Naam van de leverancier van de foto, niet noodzakelijkerwijs de eigenaar/maker (Credit) +IPTCPANEL_DATECREATED;Opnamedatum +IPTCPANEL_DATECREATEDHINT;Datum waarop de foto werd genomen; formaat: JJJJMMDD (Opnamedatum) +IPTCPANEL_EMBEDDED;Ingebed +IPTCPANEL_EMBEDDEDHINT;Keer terug naar IPTC-data die in de foto zijn opgeslagen +IPTCPANEL_HEADLINE;Titel +IPTCPANEL_HEADLINEHINT;Samenvatting van de inhoud van de foto (Titel) +IPTCPANEL_INSTRUCTIONS;Instructies +IPTCPANEL_INSTRUCTIONSHINT;Andere instructies mbt. beeldgebruik (Speciale Instructies) +IPTCPANEL_KEYWORDS;Sleutelwoorden +IPTCPANEL_KEYWORDSHINT;Gebruikt om sleutelwoorden mee te geven tbv. zoekdoeleinden (Sleutelwoorden) +IPTCPANEL_PASTEHINT;Plak IPTC-instellingen van klembord +IPTCPANEL_PROVINCE;Provincie +IPTCPANEL_PROVINCEHINT;De provincie/staat/departement waar de foto werd genomen (Provincie-Staat) +IPTCPANEL_RESET;Standaardwaarden +IPTCPANEL_RESETHINT;Terug naar standaardwaarden +IPTCPANEL_SOURCE;Bron +IPTCPANEL_SOURCEHINT;De oorspronkelijke eigenaar van de foto (Bron) +IPTCPANEL_SUPPCATEGORIES;Extra categorieën +IPTCPANEL_SUPPCATEGORIESHINT;Verdere verfijning van het onderwerp van de foto (Extra categorieën) +IPTCPANEL_TITLE;Titel +IPTCPANEL_TITLEHINT;Een korte referentienaam voor de foto (Objectnaam) +IPTCPANEL_TRANSREFERENCE;Trans. Reference +IPTCPANEL_TRANSREFERENCEHINT;Een code die de locatie van de oorspronkelijke transmissie representeert (Original Transmission Reference) +MAIN_BUTTON_PREFERENCES;Voorkeuren +MAIN_BUTTON_SAVE;Bewaar foto +MAIN_BUTTON_SAVEAS;Als... +MAIN_BUTTON_SENDTOEDITOR;Stuur naar fotoprogramma +MAIN_MSG_ALREADYEXISTS;Bestand bestaat reeds. +MAIN_MSG_CANNOTLOAD;Fout bij laden +MAIN_MSG_CANNOTSAVE;Fout bij opslaan van de afbeelding +MAIN_MSG_CANNOTSTARTEDITOR;Kan fotoprogramma niet starten. +MAIN_MSG_CANNOTSTARTEDITOR_SECONDARY;Geef juiste pad op in 'Voorkeuren'. +MAIN_MSG_EXITJOBSINQUEUEINFO;Foto's in de verwerkingsrij zullen niet verwerkt worden bij afsluiten. +MAIN_MSG_EXITJOBSINQUEUEQUEST;Weet u zeker dat u wilt stoppen? De verwerkingsrij bevat onverwerkte foto's. +MAIN_MSG_JOBSINQUEUE;Bewerking(en) in de wachtrij +MAIN_MSG_QOVERWRITE;Wilt u het bestand overschrijven? +MAIN_TAB_BASIC;Grondwaarde +MAIN_TAB_COLOR;Kleur +MAIN_TAB_DETAIL;Detail +MAIN_TAB_EXIF;Exif +MAIN_TAB_EXPOSURE;Belichting +MAIN_TAB_ICM;ICM +MAIN_TAB_IPTC;IPTC +MAIN_TAB_METADATA;Metadata +MAIN_TAB_TRANSFORM;Transformeer +MAIN_TOOLTIP_HIDEFP;Toon/verberg onderpaneel (bestandsnavigator, shortcut key: F) +MAIN_TOOLTIP_HIDEHP;Toon/verberg linkerpaneel (geschiedenis, shortcut key: H) +MAIN_TOOLTIP_INDCLIPPEDH;Overbelichtingsindicatie +MAIN_TOOLTIP_INDCLIPPEDS;Onderbelichtingsindicatie +MAIN_TOOLTIP_PREFERENCES;Voorkeuren en instellingen +MAIN_TOOLTIP_QINFO;Beknopte fotogegevens +MAIN_TOOLTIP_SAVE;Bewaar foto in standaardmap +MAIN_TOOLTIP_SAVEAS;Bewaar foto in andere map/ander formaat +PARTIALPASTE_BASICGROUP;Basisinstellingen +PARTIALPASTE_CACORRECTION;C/A-correctie +PARTIALPASTE_COARSETRANS;90 graden roteren/spiegelen +PARTIALPASTE_COLORBOOST;Kleurversterking +PARTIALPASTE_COLORDENOISE;Ruisreductie kleur +PARTIALPASTE_COLORGROUP;Kleurgerelateerde instellingen +PARTIALPASTE_COLORMIXER;Kleurenmixer +PARTIALPASTE_COLORSHIFT;Kleurverschuiving +PARTIALPASTE_COMPOSITIONGROUP;Compositie-instellingen +PARTIALPASTE_CROP;Bijsnijden +PARTIALPASTE_DIALOGLABEL;Profiel gedeeltelijk plakken... +PARTIALPASTE_DISTORTION;Corrigeer lensvervorming +PARTIALPASTE_EXIFCHANGES;Wijzig Exif-gegevens +PARTIALPASTE_EXPOSURE;Belichting +PARTIALPASTE_HLRECOVERY;Repareer hoge lichten +PARTIALPASTE_ICMSETTINGS;ICM-instellingen +PARTIALPASTE_IPTCINFO;IPTC-informatie +PARTIALPASTE_LENSGROUP;Lensgerelateerde instellingen +PARTIALPASTE_LUMACURVE;Luminantiecurve +PARTIALPASTE_LUMADENOISE;Ruisreductie luminantie +PARTIALPASTE_LUMINANCEGROUP;Instellingen luminantie +PARTIALPASTE_METAICMGROUP;Metadata/ICM-instellingen +PARTIALPASTE_RESIZE;Wijzig grootte +PARTIALPASTE_ROTATION;Roteren +PARTIALPASTE_SHADOWSHIGHLIGHTS;Schaduwen/hoge lichten +PARTIALPASTE_SHARPENING;Verscherping +PARTIALPASTE_VIGNETTING;Vignetteringscorrectie +PARTIALPASTE_WHITEBALANCE;Witbalans +PREFERENCES_APPLNEXTSTARTUP;Opnieuw opstarten vereist +PREFERENCES_BLINKCLIPPED;Knipper bij over/onderbelichting +PREFERENCES_CACHECLEARALL;Wis alles +PREFERENCES_CACHECLEARPROFILES;Wis profielen +PREFERENCES_CACHECLEARTHUMBS;Wis miniaturen +PREFERENCES_CACHEFORMAT1;RawTherapee (sneller en hogere kwalteit) +PREFERENCES_CACHEFORMAT2;JPEG (minder harde schijfruimte vereist) +PREFERENCES_CACHEMAXENTRIES;Maximaal aantal elementen in cache +PREFERENCES_CACHEOPTS;Cache-opties +PREFERENCES_CACHESTRAT1;Prefereer snelheid boven weinig geheugenbeslag +PREFERENCES_CACHESTRAT2;Prefereer weinig geheugenbeslag boven snelheid +PREFERENCES_CACHESTRAT;Cache-strategie +PREFERENCES_CACHETHUMBFORM;Miniatuurformaat cache +PREFERENCES_CACHETHUMBHEIGHT;Maximale hoogte miniaturen +PREFERENCES_CLEARDLG_LINE1;Cache legen... +PREFERENCES_CLEARDLG_LINE2;Dit kan even duren. +PREFERENCES_CLEARDLG_TITLE;Momentje svp. +PREFERENCES_CLIPPINGIND;Indicatie over/onderbelichting +PREFERENCES_CMETRICINTENT;Bedoelde colorimetrie +PREFERENCES_DATEFORMAT;Datumformaat +PREFERENCES_DATEFORMATHINT;U kunt de volgende formaten gebruiken:\n%y : jaar\n%m : maand\n%d : dag\n\nHet Nederlandse datumformaat is bijvoorbeeld:\n%d/%m/%y +PREFERENCES_DEFAULTLANG;Standaardtaal +PREFERENCES_DEFAULTTHEME;Standaardthema +PREFERENCES_DEMOSAICINGALGO;Demozaïek-algoritme +PREFERENCES_DIRHOME;Standaardmap +PREFERENCES_DIRLAST;Laatst bezochte map +PREFERENCES_DIROTHER;Anders +PREFERENCES_DIRSELECTDLG;Selecteer standaardmap bij opstarten... +PREFERENCES_DIRSOFTWARE;Installatiemap +PREFERENCES_DMETHOD;Methode +PREFERENCES_EDITORCMDLINE;Andere editor, geef pad +PREFERENCES_EXTERNALEDITOR;Externe editor +PREFERENCES_FALSECOLOR;Stapgrootte kleurfoutonderdrukking +PREFERENCES_FBROWSEROPTS;Opties bestandsnavigator +PREFERENCES_FILEFORMAT;Bestandstype +PREFERENCES_FORIMAGE;Voor niet-RAW-bestanden +PREFERENCES_FORRAW;Voor RAW-bestanden +PREFERENCES_GIMPPATH;Installatiemap GIMP +PREFERENCES_GTKTHEME;GTK standaard +PREFERENCES_HINT;Voorbeeld +PREFERENCES_HLTHRESHOLD;Grenswaarde overbelichting +PREFERENCES_ICCDIR;Map met ICC-profielen +PREFERENCES_IMPROCPARAMS;Standaardprofiel +PREFERENCES_INTENT_ABSOLUTE;Absolute colorimetrie +PREFERENCES_INTENT_PERCEPTUAL;Waargenomen colorimetrie +PREFERENCES_INTENT_RELATIVE;Relatieve colorimetrie +PREFERENCES_INTENT_SATURATION;Verzadiging +PREFERENCES_LIVETHUMBNAILS;Live-miniaturen (langzamer) +PREFERENCES_MONITORICC;Monitorprofiel +PREFERENCES_OUTDIR;Uitvoermap +PREFERENCES_OUTDIRFOLDER;Sla op in map +PREFERENCES_OUTDIRFOLDERHINT;Sla foto's op in andere map +PREFERENCES_OUTDIRHINT;U kunt de volgende formaten gebruiken:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nDeze formaten hebben betrekking op de mappen en submappen van het RAW-bestand.\n\nAls bijvoorbeeld /home/tom/image/02-09-2006/dsc0012.nef is geopend, hebben deze formaten de volgende betekenis:\n%f=dsc0012, %d1=02-09-2006, %d2=foto, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nWanneer de geconverteerde RAW-foto in dezelfde map moet komen als het origineel, schrijf dan:\n%p1/%f\n\nIndien u de geconverteerde RAW-foto in een map genaamd 'geconverteerd' wilt plaatsen die een submap is van de oorspronkelijke locatie, schrijft u:\n%p1/geconverteerd/%f\n\nWilt u het geconverteerde RAW-bestand bewaren in map '/home/tom/geconverteerd' met behoud van dezelfde submap met datums, schrijf dan:\n%p2/geconverteerd/%d1/%f +PREFERENCES_OUTDIRTEMPLATE;Gebruik sjabloon +PREFERENCES_OUTDIRTEMPLATEHINT;U kunt de volgende formaten gebruiken:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nDeze formaten hebben betrekking op de mappen en submappen van het RAW-bestand.\n\nAls bijvoorbeeld /home/tom/image/02-09-2006/dsc0012.nef is geopend, hebben deze formaten de volgende betekenis:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nWanneer de geconverteerde RAW-foto in dezelfde map moet komen als het origineel, schrijf dan:\n%p1/%f\n\nIndien u de geconverteerde RAW-foto in een map genaamd 'geconverteerd' wilt plaatsen die een submap is van de oorspronkelijke locatie, schrijft u:\n%p1/geconverteerd/%f\n\nWilt u het geconverteerde RAW-bestand bewaren in map '/home/tom/geconverteerd' met behoud van dezelfde submap met datums, schrijf dan:\n%p2/geconverteerd/%d1/%f +PREFERENCES_PARSEDEXT;Toon extensies +PREFERENCES_PARSEDEXTADD;Voeg extensie toe +PREFERENCES_PARSEDEXTADDHINT;Typ nieuwe extensie en druk op knop om aan lijst toe te voegen +PREFERENCES_PARSEDEXTDELHINT;Verwijder geselecteerde extensie(s) uit lijst +PREFERENCES_PROFILEHANDLING;Verwerking profielen +PREFERENCES_PROFILELOADPR;Laadprioriteit profielen +PREFERENCES_PROFILEPRCACHE;Profiel in cache +PREFERENCES_PROFILEPRFILE;Profiel bij RAW-bestand +PREFERENCES_PROFILESAVECACHE;Bewaar profiel in cache +PREFERENCES_PROFILESAVEINPUT;Bewaar profiel bij RAW-bestand +PREFERENCES_PSPATH;Installatiemap Adobe Photoshop +PREFERENCES_SELECTICCDIRDLG;Selecteer ICC-profielmap... +PREFERENCES_SELECTLANG;Selecteer taal +PREFERENCES_SELECTMONITORPROFDLG;Selecteer ICC-profielmap van de monitor... +PREFERENCES_SELECTTHEME;Kies thema +PREFERENCES_SHOWBASICEXIF;Toon standaard Exif-info +PREFERENCES_SHOWDATETIME;Toon datum en tijd +PREFERENCES_SHOWONLYRAW;Toon alleen RAW-bestanden +PREFERENCES_SHTHRESHOLD;Grenswaarde onderbelichting +PREFERENCES_STARTUPIMDIR;Standaardmap bij opstarten +PREFERENCES_TAB_BROWSER;Bestandsnavigator +PREFERENCES_TAB_COLORMGR;Kleurbeheer +PREFERENCES_TAB_GENERAL;Algemeen +PREFERENCES_TAB_IMPROC;Beeldverwerking +PREFERENCES_TAB_OUTPUT;Uitvoeropties +PREFERENCES_THUMBSIZE;Miniatuurgrootte +PROFILEPANEL_FILEDLGFILTERANY;Alle bestanden +PROFILEPANEL_FILEDLGFILTERPP;Profielen +PROFILEPANEL_LABEL;Profielen +PROFILEPANEL_LOADDLGLABEL;Kies profiel... +PROFILEPANEL_PCUSTOM;Handmatig +PROFILEPANEL_PFILE;Uit bestand +PROFILEPANEL_PLASTPHOTO;Laatste afbeelding +PROFILEPANEL_PLASTSAVED;Laatst opgeslagen +PROFILEPANEL_PROFILE;Profiel +PROFILEPANEL_SAVEDLGLABEL;Bewaar profiel... +PROFILEPANEL_TOOLTIPCOPY;Kopieer huidig profiel naar klembord +PROFILEPANEL_TOOLTIPLOAD;Laad profiel uit bestand +PROFILEPANEL_TOOLTIPPASTE; Plak profiel van klembord +PROFILEPANEL_TOOLTIPSAVE;Bewaar huidig profiel +PROGRESSBAR_DECODING;Laden RAW-bestand... +PROGRESSBAR_DEMOSAICING;Demozaïek-algoritme... +PROGRESSBAR_LOADING;Afbeelding laden... +PROGRESSBAR_LOADJPEG;Laden JPEG-bestand... +PROGRESSBAR_LOADPNG;Laden PNG-bestand... +PROGRESSBAR_LOADTIFF;Laden TIFF-bestand... +PROGRESSBAR_PROCESSING;Foto verwerken... +PROGRESSBAR_READY;Gereed. +PROGRESSBAR_SAVEJPEG;Opslaan JPEG-bestand... +PROGRESSBAR_SAVEPNG;Opslaan PNG-bestand... +PROGRESSBAR_SAVETIFF;Opslaan TIFF-bestand... +PROGRESSDLG_LOADING;Foto laden... +PROGRESSDLG_PROCESSING;Foto verwerken... +PROGRESSDLG_SAVING;Foto opslaan... +QINFO_FOCALLENGTH;Brandpuntsafstand +QINFO_ISO;ISO +QINFO_LENS;Objectief +QINFO_NOEXIF;Exif-gegevens niet beschikbaar. +SAVEDLG_FILEFORMAT;Bestandstype +SAVEDLG_JPEGQUAL;JPEG-kwaliteit +SAVEDLG_JPGFILTER;JPEG-bestanden +SAVEDLG_PNGCOMPR;PNG-compressie +SAVEDLG_PNGFILTER;PNG-bestanden +SAVEDLG_PUTTOQUEUE;Plaats in verwerkingsrij +SAVEDLG_PUTTOQUEUEHEAD;Put to the head of the processing queue +SAVEDLG_PUTTOQUEUETAIL;Put to the end of the processing queue +SAVEDLG_SAVEIMMEDIATELY;Bewaar meteen +SAVEDLG_SAVESPP;Bewaar afbeelding met profiel +SAVEDLG_TIFFFILTER;TIFF-bestanden +TOOLBAR_TOOLTIP_CROP;Bijsnijden (shortcut key: C) +TOOLBAR_TOOLTIP_HAND;Sleepgereedschap (shortcut key: N) +TOOLBAR_TOOLTIP_STRAIGHTEN;Rechte lijn bepalen (shortcut key: S) +TOOLBAR_TOOLTIP_WB;Witbalans (shortcut key: W) +TP_CACORRECTION_BLUE;Blauw +TP_CACORRECTION_LABEL;Corrigeer chrom. aberratie +TP_CACORRECTION_RED;Rood +TP_CHMIXER_BLUE;Blauw +TP_CHMIXER_GREEN;Groen +TP_CHMIXER_LABEL;Kanaalmixer +TP_CHMIXER_RED;Rood +TP_COARSETRAF_DEGREE;graden: +TP_COARSETRAF_TOOLTIP_HFLIP;Horizontaal spiegelen +TP_COARSETRAF_TOOLTIP_ROTLEFT;Linksom roteren +TP_COARSETRAF_TOOLTIP_ROTRIGHT;Rechtsom roteren +TP_COARSETRAF_TOOLTIP_VFLIP;Verticaal spiegelen +TP_COLORBOOST_ACHANNEL;Kanaal A +TP_COLORBOOST_AMOUNT;Hoeveelheid +TP_COLORBOOST_AVOIDCOLORCLIP;Vermijd kleuroversturing +TP_COLORBOOST_BCHANNEL;Kanaal B +TP_COLORBOOST_CHAB;a & b +TP_COLORBOOST_CHANNEL;Kanaal +TP_COLORBOOST_CHSEPARATE;Scheiden +TP_COLORBOOST_ENABLESATLIMITER;Activeer verzadigingsbegrenzer +TP_COLORBOOST_LABEL;Kleurversterking +TP_COLORBOOST_SATLIMIT;Verzadigingslimiet +TP_COLORDENOISE_EDGESENSITIVE;Randgevoeligheid +TP_COLORDENOISE_EDGETOLERANCE;Randtolerantie +TP_COLORDENOISE_LABEL;Ruisonderdrukking op kleur +TP_COLORDENOISE_RADIUS;Straal +TP_COLORSHIFT_BLUEYELLOW;Blauw-Geel +TP_COLORSHIFT_GREENMAGENTA;Groen-Magenta +TP_COLORSHIFT_LABEL;Kleurverschuiving +TP_CROP_DPI;DPI= +TP_CROP_FIXRATIO;Verhouding: +TP_CROP_GTDIAGONALS;Diagonaalmethode +TP_CROP_GTHARMMEANS1;Harmonische snede 1 +TP_CROP_GTHARMMEANS2;Harmonische snede 2 +TP_CROP_GTHARMMEANS3;Harmonische snede 3 +TP_CROP_GTHARMMEANS4;Harmonische snede 4 +TP_CROP_GTNONE;Geen +TP_CROP_GTRULETHIRDS;Regel van derden +TP_CROP_GUIDETYPE;Hulplijnen: +TP_CROP_H;H +TP_CROP_LABEL;Bijsnijden +TP_CROP_SELECTCROP;Selecteer gebied +TP_CROP_W;B +TP_CROP_X;X +TP_CROP_Y;Y +TP_DISTORTION_AMOUNT;Hoeveelheid +TP_DISTORTION_LABEL;Corrigeer lensvervorming +TP_EXPOSURE_AUTOLEVELS;Autom. niveaus +TP_EXPOSURE_BLACKLEVEL;Schaduwen +TP_EXPOSURE_BRIGHTNESS;Helderheid +TP_EXPOSURE_CLIP;Drempel +TP_EXPOSURE_COMPRHIGHLIGHTS;Hoge lichten comprimeren +TP_EXPOSURE_COMPRSHADOWS;Schaduwcompressie +TP_EXPOSURE_CONTRAST;Contrast +TP_EXPOSURE_CURVEEDITOR;Tooncurve +TP_EXPOSURE_EXPCOMP;Belichtingscompensatie +TP_EXPOSURE_LABEL;Belichting +TP_HLREC_CIELAB;CIELab-blending +TP_HLREC_COLOR;Kleurherstel +TP_HLREC_LABEL;Repareer hoge lichten +TP_HLREC_LUMINANCE;Lichtherstel +TP_HLREC_METHOD;Methode: +TP_ICM_FILEDLGFILTERANY;Alle bestanden +TP_ICM_FILEDLGFILTERICM;ICC-profielbestanden +TP_ICM_GAMMABEFOREINPUT;Profiel past gamma toe +TP_ICM_INPUTCAMERA;Camera +TP_ICM_INPUTCUSTOM;Handmatig +TP_ICM_INPUTDLGLABEL;Selecteer invoer-ICC-profiel... +TP_ICM_INPUTEMBEDDED;Gebruik ingebed profiel, indien mogelijk +TP_ICM_INPUTPROFILE;Invoerprofiel +TP_ICM_LABEL;ICM +TP_ICM_NOICM;Geen ICM: sRGB-uitvoer +TP_ICM_OUTPUTDLGLABEL;Selecteer uitvoer-ICC-profiel... +TP_ICM_OUTPUTPROFILE;Uitvoerprofiel +TP_ICM_SAVEREFERENCE;Bewaar referentiefoto tbv. profiling +TP_ICM_WORKINGPROFILE;Werkprofiel +TP_LUMACURVE_BLACKLEVEL;Schaduwen +TP_LUMACURVE_BRIGHTNESS;Helderheid +TP_LUMACURVE_COMPRHIGHLIGHTS;Hoge lichten comprimeren +TP_LUMACURVE_COMPRSHADOWS;Schaduwen comprimeren +TP_LUMACURVE_CONTRAST;Contrast +TP_LUMACURVE_CURVEEDITOR;Luminantiecurve +TP_LUMACURVE_LABEL;Luminantiecurve +TP_LUMADENOISE_EDGETOLERANCE;Randtolerantie +TP_LUMADENOISE_LABEL;Ruisonderdrukking op luminantie +TP_LUMADENOISE_RADIUS;Straal +TP_RESIZE_BICUBIC;Bikubisch +TP_RESIZE_BICUBICSF;Bikubisch (zachter) +TP_RESIZE_BICUBICSH;Bikubisch (scherper) +TP_RESIZE_BILINEAR;Bilineair +TP_RESIZE_FULLSIZE;Volledige beeldgrootte: +TP_RESIZE_H;H: +TP_RESIZE_LABEL;Grootte aanpassen +TP_RESIZE_METHOD;Methode: +TP_RESIZE_NEAREST;Dichtstbij +TP_RESIZE_SCALE;Verhouding +TP_RESIZE_W;B: +TP_ROTATE_AUTOCROP;Automatisch bijsnijden +TP_ROTATE_DEGREE;Graden +TP_ROTATE_FILL;Uitvullen +TP_ROTATE_LABEL;Roteren +TP_ROTATE_SELECTLINE;Bepaal rechte lijn +TP_SHADOWSHLIGHTS_HIGHLIGHTS;Hoge lichten +TP_SHADOWSHLIGHTS_HLTONALW;Toonomvang +TP_SHADOWSHLIGHTS_LABEL;Schaduwen/hoge lichten +TP_SHADOWSHLIGHTS_LOCALCONTR;Lokaal contrast +TP_SHADOWSHLIGHTS_RADIUS;Straal +TP_SHADOWSHLIGHTS_SHADOWS;Schaduwen +TP_SHADOWSHLIGHTS_SHTONALW;Toonomvang +TP_SHARPENING_AMOUNT;Hoeveelheid +TP_SHARPENING_EDRADIUS;Straal +TP_SHARPENING_EDTOLERANCE;Randtolerantie +TP_SHARPENING_HALOCONTROL;Halocontrole +TP_SHARPENING_HCAMOUNT;Hoeveelheid +TP_SHARPENING_LABEL;Verscherpen +TP_SHARPENING_METHOD;Methode +TP_SHARPENING_ONLYEDGES;Alleen randen verscherpen +TP_SHARPENING_RADIUS;Straal +TP_SHARPENING_RLD;RL-verscherping +TP_SHARPENING_RLD_AMOUNT;Hoeveelheid +TP_SHARPENING_RLD_DAMPING;Demping +TP_SHARPENING_RLD_ITERATIONS;Herhaling +TP_SHARPENING_THRESHOLD;Drempel +TP_SHARPENING_USM;Onscherpmasker +TP_VIGNETTING_AMOUNT;Hoeveelheid +TP_VIGNETTING_LABEL;Corrigeer vignettering +TP_VIGNETTING_RADIUS;Straal +TP_WBALANCE_AUTO;Automatisch +TP_WBALANCE_CAMERA;Camera +TP_WBALANCE_CUSTOM;Handmatig +TP_WBALANCE_GREEN;Groentint +TP_WBALANCE_LABEL;Witbalans +TP_WBALANCE_METHOD;Methode +TP_WBALANCE_SIZE;Grootte: +TP_WBALANCE_SPOTWB;Wijs WB aan +TP_WBALANCE_TEMPERATURE;Kleurtemperatuur +ZOOMBAR_DETAIL;Detailvenster +ZOOMBAR_HUGE;Groter +ZOOMBAR_LARGE;Groot +ZOOMBAR_NORMAL;Normaal +ZOOMBAR_PREVIEW;Afbeelding +ZOOMBAR_SCALE;Schaal +ZOOMBAR_SMALL;Klein diff --git a/release/languages/polish b/release/languages/polish new file mode 100755 index 000000000..7e6265539 --- /dev/null +++ b/release/languages/polish @@ -0,0 +1,583 @@ +# polish version +# 24.12.2007 +# Mateusz Ludwin +# ----------------------------- +# 17.03.2007 +# Some minor bugfixes +# Multiple capitalized letters removed +# Mateusz Ludwin +# +ADJUSTER_RESET_TO_DEFAULT;Przywróć domyÅ›lne +CURVEEDITOR_FILEDLGFILTERANY;Wszystkie pliki +CURVEEDITOR_FILEDLGFILTERCURVE;Pliki z krzywymi +CURVEEDITOR_LINEAR;Liniowa +CURVEEDITOR_LOADDLGLABEL;Wczytaj krzywÄ…... +CURVEEDITOR_SAVEDLGLABEL;Zapisz krzywÄ…... +CURVEEDITOR_TOOLTIPLINEAR;Zresetuj krzywÄ… do liniowej +CURVEEDITOR_TOOLTIPLOAD;Wczytaj krzywÄ… z pliku +CURVEEDITOR_TOOLTIPSAVE;Zapisz aktualnÄ… krzywÄ… +EXIFFILTER_APERTURE;Aperture +EXIFFILTER_CAMERA;Camera +EXIFFILTER_DIALOGLABEL;Exif Filter +EXIFFILTER_FOCALLEN;Focal Length +EXIFFILTER_ISO;ISO +EXIFFILTER_LENS;Lens +EXIFFILTER_SHUTTER;Shutter +EXIFPANEL_ADDEDIT;Add/Edit +EXIFPANEL_ADDEDITHINT;Add new tag or edit tag +EXIFPANEL_ADDTAGDLG_ENTERVALUE;Enter value +EXIFPANEL_ADDTAGDLG_SELECTTAG;Select tag +EXIFPANEL_ADDTAGDLG_TITLE;Add/Edit Tag +EXIFPANEL_KEEP;Keep +EXIFPANEL_KEEPHINT;Keep the selected tags when writing output file +EXIFPANEL_REMOVE;Remove +EXIFPANEL_REMOVEHINT;Remove the selected tags when writing output file +EXIFPANEL_RESET;Reset +EXIFPANEL_RESETALL;Reset All +EXIFPANEL_RESETALLHINT;Reset all tags to their original values +EXIFPANEL_RESETHINT;Reset the selected tags to their original values +EXIFPANEL_SUBDIRECTORY;Subdirectory +FILEBROWSER_APPLYPROFILE;Apply profile +FILEBROWSER_ARRANGEMENTHINT;Change between vertical/horizontal alignment of thumbnails +FILEBROWSER_CLEARPROFILE;Clear profile +FILEBROWSER_COPYPROFILE;Copy profile +FILEBROWSER_DELETEDLGLABEL;File delete confirmation +FILEBROWSER_DELETEDLGMSG;Are you sure you want to delete the selected %1 files? +FILEBROWSER_EMPTYTRASH;Empty Trash +FILEBROWSER_EMPTYTRASHHINT;Permanently delete the files of the trash +FILEBROWSER_EXIFFILTERAPPLY;Apply +FILEBROWSER_EXIFFILTERAPPLYHINT;Switch on/off exif filter of the file browser +FILEBROWSER_EXIFFILTERLABEL;Exif Filter +FILEBROWSER_EXIFFILTERSETTINGS;Setup +FILEBROWSER_EXIFFILTERSETTINGSHINT;Change settings of the exif filter +FILEBROWSER_PARTIALPASTEPROFILE;Partial paste +FILEBROWSER_PASTEPROFILE;Paste profile +FILEBROWSER_POPUPCANCELJOB;Cancel job +FILEBROWSER_POPUPMOVEEND;Move to end of queue +FILEBROWSER_POPUPMOVEHEAD;Move to head of queue +FILEBROWSER_POPUPOPEN;Open +FILEBROWSER_POPUPPROCESS;Put to processing queue +FILEBROWSER_POPUPRANK1;Rank 1 +FILEBROWSER_POPUPRANK2;Rank 2 +FILEBROWSER_POPUPRANK3;Rank 3 +FILEBROWSER_POPUPRANK4;Rank 4 +FILEBROWSER_POPUPRANK5;Rank 5 +FILEBROWSER_POPUPREMOVE;Remove from filesystem +FILEBROWSER_POPUPRENAME;Rename +FILEBROWSER_POPUPSELECTALL;Select all +FILEBROWSER_POPUPTRASH;Move to trash +FILEBROWSER_POPUPUNRANK;Unrank +FILEBROWSER_POPUPUNTRASH;Remove from trash +FILEBROWSER_PROCESSINGSETTINGS;Settings +FILEBROWSER_PROCESSINGSETTINGSHINT;Set the file format and output directory +FILEBROWSER_RENAMEDLGLABEL;Rename file +FILEBROWSER_RENAMEDLGMSG;Rename file "%1" to: +FILEBROWSER_SHOWDIRHINT;Show all images of the directory +FILEBROWSER_SHOWQUEUEHINT;Show content of the processing queue +FILEBROWSER_SHOWRANK1HINT;Show images ranked as 1 star +FILEBROWSER_SHOWRANK2HINT;Show images ranked as 2 star +FILEBROWSER_SHOWRANK3HINT;Show images ranked as 3 star +FILEBROWSER_SHOWRANK4HINT;Show images ranked as 4 star +FILEBROWSER_SHOWRANK5HINT;Show images ranked as 5 star +FILEBROWSER_SHOWTRASHHINT;Show content of the trash +FILEBROWSER_SHOWUNRANKHINT;Show unranked images +FILEBROWSER_STARTPROCESSING;Start Processing +FILEBROWSER_STARTPROCESSINGHINT;Start processing/saving of images in the queue +FILEBROWSER_STOPPROCESSING;Stop processing +FILEBROWSER_STOPPROCESSINGHINT;Stop processing of images +FILEBROWSER_THUMBSIZE;Thumb. size +FILEBROWSER_ZOOMINHINT;Increase thumbnail size +FILEBROWSER_ZOOMOUTHINT;Decrease thumbnail size +GENERAL_ABOUT;About +GENERAL_CANCEL;Anuluj +GENERAL_DISABLE;Wyłącz +GENERAL_DISABLED;Wyłączone +GENERAL_ENABLE;Włącz +GENERAL_ENABLED;Włączone +GENERAL_LANDSCAPE;Poziomo +GENERAL_LOAD;Åaduj +GENERAL_NA;nd. +GENERAL_NO;Nie +GENERAL_OK;OK +GENERAL_PORTRAIT;Pionowo +GENERAL_SAVE;Zapisz +GENERAL_YES;Tak +HISTOGRAM_LABEL;Histogram +HISTOGRAM_TOOLTIP_B;Pokaż/Ukryj histogram NIEBIESKIEGO +HISTOGRAM_TOOLTIP_G;Pokaż/Ukryj histogram ZIELENI +HISTOGRAM_TOOLTIP_L;Pokaż/Ukryj histogram luminancji CIELAB +HISTOGRAM_TOOLTIP_R;Pokaż/Ukryj histogram CZERWIENI +HISTORY_CHANGED;Changed +HISTORY_CUSTOMCURVE;Dowolna krzywa +HISTORY_DELSNAPSHOT;UsuÅ„ migawkÄ™ +HISTORY_FROMCLIPBOARD;From clipboard +HISTORY_LABEL;Historia +HISTORY_MSG_10;Kompresja cieni +HISTORY_MSG_11;Krzywa tonalna +HISTORY_MSG_12;Automatyczna ekspozycja +HISTORY_MSG_13;Przycinanie ekspozycji +HISTORY_MSG_14;Jasność luminancji +HISTORY_MSG_15;Kontrast luminancji +HISTORY_MSG_16;CzerÅ„ luminancji +HISTORY_MSG_17;Kompr. Å›wiateÅ‚ luminancji +HISTORY_MSG_18;Kompr. cieni luminancji +HISTORY_MSG_19;Krzywa luminancji +HISTORY_MSG_1;ZdjÄ™cie zaÅ‚adowane +HISTORY_MSG_20;Wyostrzanie +HISTORY_MSG_21;PromieÅ„ wyostrzania +HISTORY_MSG_22;SiÅ‚a wyostrzania +HISTORY_MSG_23;Próg wyostrzania +HISTORY_MSG_24;Wyostrz tylko krawÄ™dzie +HISTORY_MSG_25;PromieÅ„ detekcji krawÄ™dzi wyostrzania +HISTORY_MSG_26;Tolerancja wyostrzania krawÄ™dzi +HISTORY_MSG_27;Kontrola poÅ›wiaty wyostrzania +HISTORY_MSG_28;StopieÅ„ kontroli poÅ›wiaty +HISTORY_MSG_29;Metoda wyostrzania +HISTORY_MSG_2;Profil zaÅ‚adowany +HISTORY_MSG_30;PromieÅ„ dekonwolucji +HISTORY_MSG_31;SiÅ‚a dekonwolucji +HISTORY_MSG_32;TÅ‚umienie dekonwolucji +HISTORY_MSG_33;Iteracje dekonwolucji +HISTORY_MSG_34;Zapobiegaj przycinaniu kolorów +HISTORY_MSG_35;Limit saturacji +HISTORY_MSG_36;Limit saturacji +HISTORY_MSG_37;Wzmocnienie koloru +HISTORY_MSG_38;Metoda balansu bieli +HISTORY_MSG_39;Temperatura koloru +HISTORY_MSG_3;Profil zmieniony +HISTORY_MSG_40;OdcieÅ„ balansu bieli +HISTORY_MSG_41;PrzesuniÄ™cie koloru "A" +HISTORY_MSG_42;PrzesuniÄ™cie koloru "B" +HISTORY_MSG_43;Odszumianie luminancji +HISTORY_MSG_44;PromieÅ„ odszumiania lum. +HISTORY_MSG_45;Tol. krawÄ™dzi odszumiania lum. +HISTORY_MSG_46;Odszumianie koloru +HISTORY_MSG_47;PromieÅ„ odszumiania kolorowego +HISTORY_MSG_48;Tol. krawÄ™dzi odszumiania kol. +HISTORY_MSG_49;Odszumianie koloru z czuÅ‚. kraw. +HISTORY_MSG_4;PrzeglÄ…danie historii +HISTORY_MSG_50;NarzÄ™dzie Å›wiatÅ‚a/cienie +HISTORY_MSG_51;Wzmocnienie Å›wiateÅ‚ +HISTORY_MSG_52;Wzmocnienie cieni +HISTORY_MSG_53;Szerokość tonalna Å›wiateÅ‚ +HISTORY_MSG_54;Szerokość tonalna cieni +HISTORY_MSG_55;Kontrast lokalny +HISTORY_MSG_56;PromieÅ„ Å›wiateÅ‚/cieni +HISTORY_MSG_57;Surowy obrót +HISTORY_MSG_58;Odbicie w poziomie +HISTORY_MSG_59;Odbicie w pionie +HISTORY_MSG_5;Jasność +HISTORY_MSG_60;Obrót +HISTORY_MSG_61;Obrót +HISTORY_MSG_62;Korekcja dystorsji obiektywu +HISTORY_MSG_63;ZapamiÄ™taj wybrany +HISTORY_MSG_64;Kadrowanie zdjÄ™cia +HISTORY_MSG_65;Korekcja AC +HISTORY_MSG_66;Odzyskiwanie przeÅ›wietleÅ„ +HISTORY_MSG_67;SiÅ‚a odzyskiwania przeÅ›wietleÅ„ +HISTORY_MSG_68;Metoda odzyskiwania PrzeÅ›wietleÅ„ +HISTORY_MSG_69;Robocza przestrzeÅ„ kolorów +HISTORY_MSG_6;Kontrast +HISTORY_MSG_70;WyjÅ›ciowa przestrzeÅ„ kolorów +HISTORY_MSG_71;WejÅ›ciowa przestrzeÅ„ kolorów +HISTORY_MSG_72;Korekcja winietowania +HISTORY_MSG_73;Mikser kanałów +HISTORY_MSG_74;Skala zmiany rozmiaru +HISTORY_MSG_75;Metoda zmiany rozmiaru +HISTORY_MSG_76;Exif Metadata +HISTORY_MSG_77;IPTC Metadata +HISTORY_MSG_7;CzerÅ„ +HISTORY_MSG_8;Kompensacja ekspozycji +HISTORY_MSG_9;Kompresja Å›wiateÅ‚ +HISTORY_NEWSNAPSHOT;Nowa migawka +HISTORY_NEWSNAPSHOTAS;Jako... +HISTORY_NEWSSDIALOGLABEL;Nazwa migawki: +HISTORY_NEWSSDIALOGTITLE;Dodaj nowÄ… migawkÄ™ +HISTORY_SETTO;Wybrano +HISTORY_SNAPSHOT;Migawka +HISTORY_SNAPSHOTS;Migawki +ICMPANEL_FILEDLGFILTERANY;Wszystkie pliki +ICMPANEL_FILEDLGFILTERICM;Pliki z profilami ICC +ICMPANEL_GAMMABEFOREINPUT;Profile applies Gamma +ICMPANEL_INPUTCAMERA;DomyÅ›lny aparatu +ICMPANEL_INPUTCUSTOM;RÄ™czny +ICMPANEL_INPUTDLGLABEL;Wybierz wejÅ›ciowy profil ICC... +ICMPANEL_INPUTEMBEDDED;JeÅ›li to możliwe, użyj osadzonego +ICMPANEL_INPUTPROFILE;Profil wejÅ›ciowy +ICMPANEL_NOICM;No ICM: WyjÅ›cie sRGB +ICMPANEL_OUTPUTDLGLABEL;Wybierz wyjÅ›ciowy profil ICC... +ICMPANEL_OUTPUTPROFILE;Profil wyjÅ›ciowy +ICMPANEL_SAVEREFERENCE;Save reference image for profiling +ICMPANEL_WORKINGPROFILE;Profil roboczy +IMAGEAREA_DETAILVIEW;Lupa +IPTCPANEL_AUTHOR;Author +IPTCPANEL_AUTHORHINT;Name of the creator of the object, e.g. writer, photographer or graphic artist (By-line). +IPTCPANEL_AUTHORSPOSITION;Author's position +IPTCPANEL_AUTHORSPOSITIONHINT;Title of the creator or creators of the object (By-line Title). +IPTCPANEL_CAPTION;Caption +IPTCPANEL_CAPTIONHINT;A textual description of the data (Caption - Abstract). +IPTCPANEL_CAPTIONWRITER;Caption Writer +IPTCPANEL_CAPTIONWRITERHINT;The name of the person involved in the writing, editing or correcting the image or caption/abstract (Writer - Editor). +IPTCPANEL_CATEGORY;Category +IPTCPANEL_CATEGORYHINT;Identifies the subject of the image in the opinion of the provider (Category). +IPTCPANEL_CITY;City +IPTCPANEL_CITYHINT;City of image origin (City). +IPTCPANEL_COPYHINT;Copy IPTC settings to clipboard +IPTCPANEL_COPYRIGHT;Copyright +IPTCPANEL_COPYRIGHTHINT;Any necessary copyright notice (Copyright Notice). +IPTCPANEL_COUNTRY;Country +IPTCPANEL_COUNTRYHINT;The name of the country/primary location where the image was created (Country - Primary Location Name). +IPTCPANEL_CREDIT;Credit +IPTCPANEL_CREDITHINT;Identifies the provider of the image, not necessarily the owner/creator (Credit). +IPTCPANEL_DATECREATED;Date Created +IPTCPANEL_DATECREATEDHINT;The date the intellectual content of the image was created; Format: JJJJMMTT (Date Created). +IPTCPANEL_EMBEDDED;Embedded +IPTCPANEL_EMBEDDEDHINT;Reset to IPTC data embedded in the image file +IPTCPANEL_HEADLINE;Headline +IPTCPANEL_HEADLINEHINT;A publishable entry providing a synopsis of the contents of the image (Headline). +IPTCPANEL_INSTRUCTIONS;Instructions +IPTCPANEL_INSTRUCTIONSHINT;Other editorial instructions concerning the use of the image (Special Instructions). +IPTCPANEL_KEYWORDS;Keywords +IPTCPANEL_KEYWORDSHINT;Used to indicate specific information retrieval words (Keywords). +IPTCPANEL_PASTEHINT;Paste IPTC settings from clipboard +IPTCPANEL_PROVINCE;Province +IPTCPANEL_PROVINCEHINT;The Province/State where the image originates (Province-State). +IPTCPANEL_RESET;Reset +IPTCPANEL_RESETHINT;Reset to profile default +IPTCPANEL_SOURCE;Source +IPTCPANEL_SOURCEHINT;The original owner of the intellectual content of the image (Source). +IPTCPANEL_SUPPCATEGORIES;Suppl. Categories +IPTCPANEL_SUPPCATEGORIESHINT;Further refines the subject of the image (Supplemental Categories). +IPTCPANEL_TITLE;Title +IPTCPANEL_TITLEHINT;A shorthand reference for the image (Object Name). +IPTCPANEL_TRANSREFERENCE;Trans. Reference +IPTCPANEL_TRANSREFERENCEHINT;A code representing the location of original transmission (Original Transmission Reference). +MAIN_BUTTON_PREFERENCES;Preferencje +MAIN_BUTTON_SAVE;Zapisz obraz +MAIN_BUTTON_SAVEAS;Jako... +MAIN_BUTTON_SENDTOEDITOR;Send to editor +MAIN_MSG_ALREADYEXISTS;Plik już istnieje. +MAIN_MSG_CANNOTLOAD;Nie można wczytać obrazu +MAIN_MSG_CANNOTSAVE;Błąd zapisu pliku +MAIN_MSG_CANNOTSTARTEDITOR;Can not start editor. +MAIN_MSG_CANNOTSTARTEDITOR_SECONDARY;Please set the correct path in the "Preferences" dialog. +MAIN_MSG_EXITJOBSINQUEUEINFO;Unprocessed images in the queue will be lost on exit. +MAIN_MSG_EXITJOBSINQUEUEQUEST;Are you sure you want to exit? There are unprocessed images waiting in the queue. +MAIN_MSG_JOBSINQUEUE;zadaÅ„ w kolejce +MAIN_MSG_QOVERWRITE;Czy chcesz go zastÄ…pić? +MAIN_TAB_BASIC;Podstawowe +MAIN_TAB_COLOR;Color +MAIN_TAB_DETAIL;Detail +MAIN_TAB_EXIF;Exif +MAIN_TAB_EXPOSURE;Exposure +MAIN_TAB_ICM;ICM +MAIN_TAB_IPTC;IPTC +MAIN_TAB_METADATA;Metadata +MAIN_TAB_TRANSFORM;Transformacje +MAIN_TOOLTIP_HIDEFP;Pokaż/ukryj dolny panel (przeglÄ…darka plików i katalogów, shortcut key: F) +MAIN_TOOLTIP_HIDEHP;Pokaż/ukryj lewy panel (razem z historiÄ…, shortcut key: H) +MAIN_TOOLTIP_INDCLIPPEDH;Pokaż przeÅ›wietlenia +MAIN_TOOLTIP_INDCLIPPEDS;Pokaż niedoÅ›wietlenia +MAIN_TOOLTIP_PREFERENCES;Ustaw preferencje +MAIN_TOOLTIP_QINFO;Informacje o pliku +MAIN_TOOLTIP_SAVE;Zapisz obraz w katalogu domyÅ›lnym +MAIN_TOOLTIP_SAVEAS;Zapisz obraz we wskazanym katalogu +PARTIALPASTE_BASICGROUP;Basic settings +PARTIALPASTE_CACORRECTION;C/A correction +PARTIALPASTE_COARSETRANS;90 deg rotation / flipping +PARTIALPASTE_COLORBOOST;Color boost +PARTIALPASTE_COLORDENOISE;Color denoise +PARTIALPASTE_COLORGROUP;Color related settings +PARTIALPASTE_COLORMIXER;Color mixer +PARTIALPASTE_COLORSHIFT;Color shift +PARTIALPASTE_COMPOSITIONGROUP;Composition settings +PARTIALPASTE_CROP;Crop +PARTIALPASTE_DIALOGLABEL;Partial paste processing profile +PARTIALPASTE_DISTORTION;Distortion correction +PARTIALPASTE_EXIFCHANGES;Changes to exif data +PARTIALPASTE_EXPOSURE;Exposure +PARTIALPASTE_HLRECOVERY;Highlight recovery +PARTIALPASTE_ICMSETTINGS;ICM settings +PARTIALPASTE_IPTCINFO;IPTC info +PARTIALPASTE_LENSGROUP;Lens related settings +PARTIALPASTE_LUMACURVE;Luminance curve +PARTIALPASTE_LUMADENOISE;Luminance noise reduction +PARTIALPASTE_LUMINANCEGROUP;Luminance related settings +PARTIALPASTE_METAICMGROUP;Metadata/ICM settings +PARTIALPASTE_RESIZE;Resize +PARTIALPASTE_ROTATION;Rotation +PARTIALPASTE_SHADOWSHIGHLIGHTS;Shadows/Highlights +PARTIALPASTE_SHARPENING;Sharpening +PARTIALPASTE_VIGNETTING;Vignetting correction +PARTIALPASTE_WHITEBALANCE;White balance +PREFERENCES_APPLNEXTSTARTUP;wymaga ponownego uruchomienia +PREFERENCES_BLINKCLIPPED;MrugajÄ…ce przeÅ›wietlenia +PREFERENCES_CACHECLEARALL;Clear All +PREFERENCES_CACHECLEARPROFILES;Clear Profiles +PREFERENCES_CACHECLEARTHUMBS;Clear Thumbnails +PREFERENCES_CACHEFORMAT1;Proprietary (faster and better quality) +PREFERENCES_CACHEFORMAT2;JPEG (smaller disk footprint) +PREFERENCES_CACHEMAXENTRIES;Maximal Number of Cache Entries +PREFERENCES_CACHEOPTS;Cache Options +PREFERENCES_CACHESTRAT1;Prefer Speed to Low Memory Consumption +PREFERENCES_CACHESTRAT2;Prefer Low Memory Consumption to Speed +PREFERENCES_CACHESTRAT;Cache Strategy +PREFERENCES_CACHETHUMBFORM;Cache Thumbnail Format +PREFERENCES_CACHETHUMBHEIGHT;Maximal Thumbnail Height +PREFERENCES_CLEARDLG_LINE1;Clearing cache +PREFERENCES_CLEARDLG_LINE2;This may take a few seconds. +PREFERENCES_CLEARDLG_TITLE;Please wait +PREFERENCES_CLIPPINGIND;Pokazywanie przeÅ›wietleÅ„ +PREFERENCES_CMETRICINTENT;Sposób odwzorowania barw +PREFERENCES_DATEFORMAT;Format daty +PREFERENCES_DATEFORMATHINT;You can use the following formatting strings:\n%y : year\n%m : month\n%d : day\n\nFor example, the hungarian date format is:\n%y/%m/%d +PREFERENCES_DEFAULTLANG;JÄ™zyk domyÅ›lny +PREFERENCES_DEFAULTTHEME;Default theme +PREFERENCES_DEMOSAICINGALGO;Algorytm demozaikowania +PREFERENCES_DIRHOME;Katalog domowy +PREFERENCES_DIRLAST;Ostatnio odwiedzony katalog +PREFERENCES_DIROTHER;Inny +PREFERENCES_DIRSELECTDLG;Wybierz katalog z obrazami po uruchomieniu... +PREFERENCES_DIRSOFTWARE;Katalog instalacyjny +PREFERENCES_DMETHOD;Metoda +PREFERENCES_EDITORCMDLINE;Other command line +PREFERENCES_EXTERNALEDITOR;External editor +PREFERENCES_FALSECOLOR;Kroki zapobiegania zafaÅ‚szowaniom kolorów +PREFERENCES_FBROWSEROPTS;Opcje przeglÄ…darki plików +PREFERENCES_FILEFORMAT;Format pliku +PREFERENCES_FORIMAGE;Dla plików z obrazami +PREFERENCES_FORRAW;Dla plików RAW +PREFERENCES_GIMPPATH;GIMP installation directory +PREFERENCES_GTKTHEME;GTK default +PREFERENCES_HINT;Porada +PREFERENCES_HLTHRESHOLD;Próg dla przeÅ›wietleñ +PREFERENCES_ICCDIR;Katalog z profilami ICC +PREFERENCES_IMPROCPARAMS;DomyÅ›lne parametry przetwarzania obrazu +PREFERENCES_INTENT_ABSOLUTE;Absolutnie kolorymetryczny +PREFERENCES_INTENT_PERCEPTUAL;Percepcyjny +PREFERENCES_INTENT_RELATIVE;WzglÄ™dnie kolorymetryczny +PREFERENCES_INTENT_SATURATION;Nasyceniowy +PREFERENCES_LIVETHUMBNAILS;Live Thumbnails (slower) +PREFERENCES_MONITORICC;Profil monitora +PREFERENCES_OUTDIR;Katalog wyjÅ›ciowy +PREFERENCES_OUTDIRFOLDER;Save to folder +PREFERENCES_OUTDIRFOLDERHINT;Put the saved images to the seledted folder +PREFERENCES_OUTDIRHINT;You can use the following formatting strings:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nThese formatting strings refer to the directories and sub-paths of the path of the raw file.\n\nFor example, if /home/tom/image/02-09-2006/dsc0012.nefhas been opened, the meaning of the formatting strings are:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nIf you want to save the output image where the original is, write:\n%p1/%f\n\nIf you want to save the output image in a directory 'converted' located the directory of the original, write:\n%p1/converted/%f\n\nIf you want to save the output image in directory '/home/tom/converted' with keeping the same subdirectory of dates, write:\n%p2/converted/%d1/%f +PREFERENCES_OUTDIRTEMPLATE;Use Template +PREFERENCES_OUTDIRTEMPLATEHINT;You can use the following formatting strings:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nThese formatting strings refer to the directories and sub-paths of the path of the raw file.\n\nFor example, if /home/tom/image/02-09-2006/dsc0012.nefhas been opened, the meaning of the formatting strings are:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nIf you want to save the output image where the original is, write:\n%p1/%f\n\nIf you want to save the output image in a directory 'converted' located the directory of the original, write:\n%p1/converted/%f\n\nIf you want to save the output image in directory '/home/tom/converted' with keeping the same subdirectory of dates, write:\n%p2/converted/%d1/%f +PREFERENCES_PARSEDEXT;Parsed Extensions +PREFERENCES_PARSEDEXTADD;Add Extension +PREFERENCES_PARSEDEXTADDHINT;Type an extension and press this button to append list +PREFERENCES_PARSEDEXTDELHINT;Delete selected extension from the list +PREFERENCES_PROFILEHANDLING;Processing Profile Handling +PREFERENCES_PROFILELOADPR;Profile Loading Priority +PREFERENCES_PROFILEPRCACHE;Profile in Cache +PREFERENCES_PROFILEPRFILE;Profile Next to the Input File +PREFERENCES_PROFILESAVECACHE;Save Processing Parameters to the Cache +PREFERENCES_PROFILESAVEINPUT;Save Processing Parameters Next to the Input File +PREFERENCES_PSPATH;Adobe Photoshop installation directory +PREFERENCES_SELECTICCDIRDLG;Wybierz katalog z profilami ICC... +PREFERENCES_SELECTLANG;Wybierz jÄ™zyk +PREFERENCES_SELECTMONITORPROFDLG;Wybierz profil ICC do wyÅ›wietlenia... +PREFERENCES_SELECTTHEME;Select theme +PREFERENCES_SHOWBASICEXIF;Pokaż podstawowe dane Exif +PREFERENCES_SHOWDATETIME;Pokaż datÄ™ i czas +PREFERENCES_SHOWONLYRAW;Pokaż tylko pliki RAW +PREFERENCES_SHTHRESHOLD;Próg dla niedoÅ›wietleñ +PREFERENCES_STARTUPIMDIR;Katalog startowy +PREFERENCES_TAB_BROWSER;PrzeglÄ…darka plików +PREFERENCES_TAB_COLORMGR;ZarzÄ…dzanie kolorami +PREFERENCES_TAB_GENERAL;Ogólne +PREFERENCES_TAB_IMPROC;Przetwarzanie obrazu +PREFERENCES_TAB_OUTPUT;Opcje wyjÅ›ciowe +PREFERENCES_THUMBSIZE;Wielkość miniaturki +PROFILEPANEL_FILEDLGFILTERANY;Wszystkie pliki +PROFILEPANEL_FILEDLGFILTERPP;Profile postprocessingu +PROFILEPANEL_LABEL;Profil postprocessingu +PROFILEPANEL_LOADDLGLABEL;Åaduj parametry postprocessingu... +PROFILEPANEL_PCUSTOM;RÄ™czny +PROFILEPANEL_PFILE;Z pliku +PROFILEPANEL_PLASTPHOTO;Ostatnie ZdjÄ™cie +PROFILEPANEL_PLASTSAVED;Ostatnio zapisany +PROFILEPANEL_PROFILE;Profil +PROFILEPANEL_SAVEDLGLABEL;Zapisz parametry postprocessingu... +PROFILEPANEL_TOOLTIPCOPY;Copy current profile to clipboard +PROFILEPANEL_TOOLTIPLOAD;Åaduj profil z pliku +PROFILEPANEL_TOOLTIPPASTE; Paste profile from clipboard +PROFILEPANEL_TOOLTIPSAVE;Zapisz aktualny profil +PROGRESSBAR_DECODING;Dekodowanie pliku raw... +PROGRESSBAR_DEMOSAICING;Demozaikowanie... +PROGRESSBAR_LOADING;Wczytywanie obrazu... +PROGRESSBAR_LOADJPEG;Åadowanie pliku JPEG... +PROGRESSBAR_LOADPNG;Åadowanie pliku PNG... +PROGRESSBAR_LOADTIFF;Åadowanie pliku TIFF... +PROGRESSBAR_PROCESSING;Przetwarzanie obrazu... +PROGRESSBAR_READY;Gotowe. +PROGRESSBAR_SAVEJPEG;Zapisywanie pliku JPEG... +PROGRESSBAR_SAVEPNG;Zapisywanie pliku PNG... +PROGRESSBAR_SAVETIFF;Zapisywanie pliku TIFF... +PROGRESSDLG_LOADING;Loading file... +PROGRESSDLG_PROCESSING;Processing image... +PROGRESSDLG_SAVING;Saving file... +QINFO_FOCALLENGTH;Ogniskowa +QINFO_ISO;ISO +QINFO_LENS;Lens +QINFO_NOEXIF;Dane exif niedostÄ™pne. +SAVEDLG_FILEFORMAT;Format pliku +SAVEDLG_JPEGQUAL;Jakość JPEG +SAVEDLG_JPGFILTER;Pliki JPEG +SAVEDLG_PNGCOMPR;Kompresja PNG +SAVEDLG_PNGFILTER;Pliki PNG +SAVEDLG_PUTTOQUEUE;Put into processing queue +SAVEDLG_PUTTOQUEUEHEAD;Put to the head of the processing queue +SAVEDLG_PUTTOQUEUETAIL;Put to the end of the processing queue +SAVEDLG_SAVEIMMEDIATELY;Save immediately +SAVEDLG_SAVESPP;Zapisz parametry przetwarzania wraz z obrazem +SAVEDLG_TIFFFILTER;Pliki TIFF +TOOLBAR_TOOLTIP_CROP;Kadruj (shortcut key: C) +TOOLBAR_TOOLTIP_HAND;PrzesuÅ„ (shortcut key: N) +TOOLBAR_TOOLTIP_STRAIGHTEN;Wyprostuj obraz (shortcut key: S) +TOOLBAR_TOOLTIP_WB;Wskaż balans bieli (shortcut key: W) +TP_CACORRECTION_BLUE;Niebieski +TP_CACORRECTION_LABEL;Korekcja AC +TP_CACORRECTION_RED;Czerwony +TP_CHMIXER_BLUE;Blue +TP_CHMIXER_GREEN;Green +TP_CHMIXER_LABEL;Mikser kanałów +TP_CHMIXER_RED;Red +TP_COARSETRAF_DEGREE;stopnie: +TP_COARSETRAF_TOOLTIP_HFLIP;Odbij w poziomie +TP_COARSETRAF_TOOLTIP_ROTLEFT;Obróć w lewo +TP_COARSETRAF_TOOLTIP_ROTRIGHT;Obróć w prawo +TP_COARSETRAF_TOOLTIP_VFLIP;Odbij w pionie +TP_COLORBOOST_ACHANNEL;kanaÅ‚ "a" +TP_COLORBOOST_AMOUNT;StopieÅ„ +TP_COLORBOOST_AVOIDCOLORCLIP;Unikaj przycinania kolorów +TP_COLORBOOST_BCHANNEL;kanaÅ‚ "b" +TP_COLORBOOST_CHAB;a i b +TP_COLORBOOST_CHANNEL;KanaÅ‚ +TP_COLORBOOST_CHSEPARATE;oddzielnie +TP_COLORBOOST_ENABLESATLIMITER;Włącz limit saturacji +TP_COLORBOOST_LABEL;Wzmocnienie koloru +TP_COLORBOOST_SATLIMIT;Limit saturacji +TP_COLORDENOISE_EDGESENSITIVE;CzuÅ‚ość krawÄ™dzi +TP_COLORDENOISE_EDGETOLERANCE;Tolerancja krawÄ™dzi +TP_COLORDENOISE_LABEL;Odszumianie koloru +TP_COLORDENOISE_RADIUS;PromieÅ„ +TP_COLORSHIFT_BLUEYELLOW;Błękit-żółty +TP_COLORSHIFT_GREENMAGENTA;ZieleÅ„-magenta +TP_COLORSHIFT_LABEL;PrzesuniÄ™cie koloru +TP_CROP_DPI;DPI= +TP_CROP_FIXRATIO;Zablokuj proporcje: +TP_CROP_GTDIAGONALS;PrzekÄ…tna +TP_CROP_GTHARMMEANS1;ZÅ‚oty podziaÅ‚ 1 +TP_CROP_GTHARMMEANS2;ZÅ‚oty podziaÅ‚ 2 +TP_CROP_GTHARMMEANS3;ZÅ‚oty podziaÅ‚ 3 +TP_CROP_GTHARMMEANS4;ZÅ‚oty podziaÅ‚ 4 +TP_CROP_GTNONE;Nic +TP_CROP_GTRULETHIRDS;TrójpodziaÅ‚ +TP_CROP_GUIDETYPE;Typ pomocy: +TP_CROP_H;W +TP_CROP_LABEL;Kadrowanie +TP_CROP_SELECTCROP; Wybierz kadr +TP_CROP_W;S +TP_CROP_X;x +TP_CROP_Y;y +TP_DISTORTION_AMOUNT;SiÅ‚a +TP_DISTORTION_LABEL;Dystorsja +TP_EXPOSURE_AUTOLEVELS;Wyrównaj poziomy +TP_EXPOSURE_BLACKLEVEL;CzerÅ„ +TP_EXPOSURE_BRIGHTNESS;Jasność +TP_EXPOSURE_CLIP;Przytnij +TP_EXPOSURE_COMPRHIGHLIGHTS;Kompresja Å›wiateÅ‚ +TP_EXPOSURE_COMPRSHADOWS;Kompresja cieni +TP_EXPOSURE_CONTRAST;Kontrast +TP_EXPOSURE_CURVEEDITOR;Krzywa tonalna +TP_EXPOSURE_EXPCOMP;EV +TP_EXPOSURE_LABEL;Ekspozycja +TP_HLREC_CIELAB;CIELab Blending +TP_HLREC_COLOR;Propagacja koloru +TP_HLREC_LABEL;Odzyskiwanie przeÅ›wietleÅ„ +TP_HLREC_LUMINANCE;Odzyskiwanie luminancji +TP_HLREC_METHOD;Metoda: +TP_ICM_FILEDLGFILTERANY;Wszystkie pliki +TP_ICM_FILEDLGFILTERICM;Pliki z profilami ICC +TP_ICM_GAMMABEFOREINPUT;Profile applies Gamma +TP_ICM_INPUTCAMERA;DomyÅ›lny aparatu +TP_ICM_INPUTCUSTOM;RÄ™czny +TP_ICM_INPUTDLGLABEL;Wybierz wejÅ›ciowy profil ICC... +TP_ICM_INPUTEMBEDDED;JeÅ›li to możliwe, użyj osadzonego +TP_ICM_INPUTPROFILE;Profil wejÅ›ciowy +TP_ICM_LABEL;ICM +TP_ICM_NOICM;No ICM: WyjÅ›cie sRGB +TP_ICM_OUTPUTDLGLABEL;Wybierz wyjÅ›ciowy profil ICC... +TP_ICM_OUTPUTPROFILE;Profil wyjÅ›ciowy +TP_ICM_SAVEREFERENCE;Save reference image for profiling +TP_ICM_WORKINGPROFILE;Profil roboczy +TP_LUMACURVE_BLACKLEVEL;CzerÅ„ +TP_LUMACURVE_BRIGHTNESS;Jasność +TP_LUMACURVE_COMPRHIGHLIGHTS;Kompresja Å›wiateÅ‚ +TP_LUMACURVE_COMPRSHADOWS;Kompresja cieni +TP_LUMACURVE_CONTRAST;Kontrast +TP_LUMACURVE_CURVEEDITOR;Krzywa luminancji +TP_LUMACURVE_LABEL;Krzywa luminancji +TP_LUMADENOISE_EDGETOLERANCE;Tolerancja krawÄ™dzi +TP_LUMADENOISE_LABEL;Odszumianie luminancji +TP_LUMADENOISE_RADIUS;PromieÅ„ +TP_RESIZE_BICUBIC;Bicubic +TP_RESIZE_BICUBICSF;Bicubic (MiÄ™kko) +TP_RESIZE_BICUBICSH;Bicubic (Ostro) +TP_RESIZE_BILINEAR;Bilinear +TP_RESIZE_FULLSIZE;PeÅ‚ny rozmiar obrazu: +TP_RESIZE_H;W: +TP_RESIZE_LABEL;Skalowanie +TP_RESIZE_METHOD;Metoda: +TP_RESIZE_NEAREST;Nearest +TP_RESIZE_SCALE;Skala +TP_RESIZE_W;S: +TP_ROTATE_AUTOCROP;Auto crop +TP_ROTATE_DEGREE;Stopnie +TP_ROTATE_FILL;WypeÅ‚nij +TP_ROTATE_LABEL;Obrót +TP_ROTATE_SELECTLINE; Wyprostuj obraz +TP_SHADOWSHLIGHTS_HIGHLIGHTS;ÅšwiatÅ‚a +TP_SHADOWSHLIGHTS_HLTONALW;Szerokość tonalna +TP_SHADOWSHLIGHTS_LABEL;Cienie/ÅšwiatÅ‚a +TP_SHADOWSHLIGHTS_LOCALCONTR;Kontrast lokalny +TP_SHADOWSHLIGHTS_RADIUS;PromieÅ„ +TP_SHADOWSHLIGHTS_SHADOWS;Cienie +TP_SHADOWSHLIGHTS_SHTONALW;Szerokość tonalna +TP_SHARPENING_AMOUNT;SiÅ‚a +TP_SHARPENING_EDRADIUS;PromieÅ„ +TP_SHARPENING_EDTOLERANCE;Tolerancja +TP_SHARPENING_HALOCONTROL;Kontrola poÅ›wiaty +TP_SHARPENING_HCAMOUNT;SiÅ‚a +TP_SHARPENING_LABEL;Wyostrzanie +TP_SHARPENING_METHOD;Metoda +TP_SHARPENING_ONLYEDGES;Wyostrz tylko krawÄ™dzie +TP_SHARPENING_RADIUS;PromieÅ„ +TP_SHARPENING_RLD;Dekonwolucja RL +TP_SHARPENING_RLD_AMOUNT;SiÅ‚a +TP_SHARPENING_RLD_DAMPING;TÅ‚umienie +TP_SHARPENING_RLD_ITERATIONS;Iteracje +TP_SHARPENING_THRESHOLD;Próg +TP_SHARPENING_USM;Maska wyostrzajÄ…ca +TP_VIGNETTING_AMOUNT;SiÅ‚a +TP_VIGNETTING_LABEL;Korekcja winietowania +TP_VIGNETTING_RADIUS;PromieÅ„ +TP_WBALANCE_AUTO;Auto +TP_WBALANCE_CAMERA;Z aparatu +TP_WBALANCE_CUSTOM;RÄ™czny +TP_WBALANCE_GREEN;OdcieÅ„ +TP_WBALANCE_LABEL;Balans bieli +TP_WBALANCE_METHOD;Metoda +TP_WBALANCE_SIZE;Wielkość: +TP_WBALANCE_SPOTWB;Punktowy +TP_WBALANCE_TEMPERATURE;Temperatura +ZOOMBAR_DETAIL;Lupa +ZOOMBAR_HUGE;Olbrzymia +ZOOMBAR_LARGE;Duża +ZOOMBAR_NORMAL;Normalna +ZOOMBAR_PREVIEW;Widok +ZOOMBAR_SCALE;Skala +ZOOMBAR_SMALL;MaÅ‚a diff --git a/release/languages/russian b/release/languages/russian new file mode 100755 index 000000000..4710e0c87 --- /dev/null +++ b/release/languages/russian @@ -0,0 +1,579 @@ +# Russian +# 23.12.2007 +# ArtDen +# 20.07.2008: Denis Artemov +# 29.12.2008: Kvark +ADJUSTER_RESET_TO_DEFAULT;По умолчанию +CURVEEDITOR_FILEDLGFILTERANY;Любые файлы +CURVEEDITOR_FILEDLGFILTERCURVE;Файлы тоновых кривых +CURVEEDITOR_LINEAR;Ð›Ð¸Ð½ÐµÐ¹Ð½Ð°Ñ +CURVEEDITOR_LOADDLGLABEL;Считать кривую... +CURVEEDITOR_SAVEDLGLABEL;Сохранить кривую... +CURVEEDITOR_TOOLTIPLINEAR;Ð’Ñ‹Ñтавить линейную тоновую кривую +CURVEEDITOR_TOOLTIPLOAD;Загрузить тоновую кривую +CURVEEDITOR_TOOLTIPSAVE;Сохранить тоновую кривую +EXIFFILTER_APERTURE;Диафрагма +EXIFFILTER_CAMERA;Камера +EXIFFILTER_DIALOGLABEL;Фильтр Exif +EXIFFILTER_FOCALLEN;ФокуÑное раÑÑтоÑние +EXIFFILTER_ISO;ISO +EXIFFILTER_LENS;Объектив +EXIFFILTER_SHUTTER;Выдержка +EXIFPANEL_ADDEDIT;Добавить/редактировать +EXIFPANEL_ADDEDITHINT;Добавить новый Ñ‚Ñг или редактировать тег +EXIFPANEL_ADDTAGDLG_ENTERVALUE;ВвеÑти значение +EXIFPANEL_ADDTAGDLG_SELECTTAG;Выбрать тег +EXIFPANEL_ADDTAGDLG_TITLE;Добавить/редактировать тег +EXIFPANEL_KEEP;Сохранить +EXIFPANEL_KEEPHINT;СохранÑть выбранные теги при запиÑи файла +EXIFPANEL_REMOVE;Удалить +EXIFPANEL_REMOVEHINT;УдалÑть выбранные теги при запиÑи файла +EXIFPANEL_RESET;СброÑить +EXIFPANEL_RESETALL;СброÑить вÑе +EXIFPANEL_RESETALLHINT;СброÑить вÑе теги в первоначальные Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ +EXIFPANEL_RESETHINT;СброÑить выбранные теги в первоначальные Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ +EXIFPANEL_SUBDIRECTORY;Подкаталог +FILEBROWSER_APPLYPROFILE;Применить профиль +FILEBROWSER_ARRANGEMENTHINT;Вертикальное/горизонтальное раÑположение ÑÑкизов +FILEBROWSER_CLEARPROFILE;Удалить профиль +FILEBROWSER_COPYPROFILE;Скопировать профиль +FILEBROWSER_DELETEDLGLABEL;Подтверждение ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð° +FILEBROWSER_DELETEDLGMSG;Ð’Ñ‹ уверены, что хотите удалить %1 выбранный(ых) файл(ов)? +FILEBROWSER_EMPTYTRASH;ОчиÑтить корзину +FILEBROWSER_EMPTYTRASHHINT;Удалить файлы из корзины без возможноÑти воÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ +FILEBROWSER_EXIFFILTERAPPLY;Применить +FILEBROWSER_EXIFFILTERAPPLYHINT;Включение/Ð²Ñ‹ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ñ„Ð¸Ð»ÑŒÑ‚Ñ€Ð° Exif в браузере +FILEBROWSER_EXIFFILTERLABEL;Фильтр Exif +FILEBROWSER_EXIFFILTERSETTINGS;ÐаÑтройка +FILEBROWSER_EXIFFILTERSETTINGSHINT;ÐаÑтройка параметров фильтра Exif +FILEBROWSER_PARTIALPASTEPROFILE;ЧаÑÑ‚Ð¸Ñ‡Ð½Ð°Ñ Ð²Ñтавка +FILEBROWSER_PASTEPROFILE;Ð’Ñтавка Ð¿Ñ€Ð¾Ñ„Ð¸Ð»Ñ +FILEBROWSER_POPUPCANCELJOB;Отменить задание +FILEBROWSER_POPUPMOVEEND;ПеремеÑтить в конец очереди +FILEBROWSER_POPUPMOVEHEAD;ПеремеÑтить в начало очереди +FILEBROWSER_POPUPOPEN;Открыть +FILEBROWSER_POPUPPROCESS;ПомеÑтить в очередь на обработку +FILEBROWSER_POPUPRANK1;Рейтинг 1 +FILEBROWSER_POPUPRANK2;Рейтинг 2 +FILEBROWSER_POPUPRANK3;Рейтинг 3 +FILEBROWSER_POPUPRANK4;Рейтинг 4 +FILEBROWSER_POPUPRANK5;Рейтинг 5 +FILEBROWSER_POPUPREMOVE;Удалить Ñ Ð´Ð¸Ñка +FILEBROWSER_POPUPRENAME;Переименовать +FILEBROWSER_POPUPSELECTALL;Выбрать вÑе +FILEBROWSER_POPUPTRASH;Удалить в корзину +FILEBROWSER_POPUPUNRANK;СнÑть рейтинг +FILEBROWSER_POPUPUNTRASH;Удалить из корзины +FILEBROWSER_PROCESSINGSETTINGS;Параметры +FILEBROWSER_PROCESSINGSETTINGSHINT;Задать формат файла и выходной каталог +FILEBROWSER_RENAMEDLGLABEL;Переименовать файл +FILEBROWSER_RENAMEDLGMSG;Переименовать файл "%1" в: +FILEBROWSER_SHOWDIRHINT;Показать вÑе Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð² каталоге +FILEBROWSER_SHOWQUEUEHINT;Показать Ñодержимое очереди на обработку +FILEBROWSER_SHOWRANK1HINT;Показать Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ñ Ñ€ÐµÐ¹Ñ‚Ð¸Ð½Ð³Ð¾Ð¼ 1 +FILEBROWSER_SHOWRANK2HINT;Показать Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ñ Ñ€ÐµÐ¹Ñ‚Ð¸Ð½Ð³Ð¾Ð¼ 2 +FILEBROWSER_SHOWRANK3HINT;Показать Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ñ Ñ€ÐµÐ¹Ñ‚Ð¸Ð½Ð³Ð¾Ð¼ 3 +FILEBROWSER_SHOWRANK4HINT;Показать Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ñ Ñ€ÐµÐ¹Ñ‚Ð¸Ð½Ð³Ð¾Ð¼ 4 +FILEBROWSER_SHOWRANK5HINT;Показать Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ñ Ñ€ÐµÐ¹Ñ‚Ð¸Ð½Ð³Ð¾Ð¼ 5 +FILEBROWSER_SHOWTRASHHINT;Показать Ñодержимое корзины +FILEBROWSER_SHOWUNRANKHINT;Показать Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð±ÐµÐ· рейтинга +FILEBROWSER_STARTPROCESSING;Ðачать обработку +FILEBROWSER_STARTPROCESSINGHINT;ЗапуÑк обработки/ÑÐ¾Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ð¿Ð¾Ð¼ÐµÑ‰ÐµÐ½Ð½Ñ‹Ñ… в очередь изображений +FILEBROWSER_STOPPROCESSING;ОÑтановить обработку +FILEBROWSER_STOPPROCESSINGHINT;Отмена обработки изображений +FILEBROWSER_THUMBSIZE;Размер ÑÑкиза +FILEBROWSER_ZOOMINHINT;Увеличить размер ÑÑкиза +FILEBROWSER_ZOOMOUTHINT;Уменьшить размер ÑÑкиза +GENERAL_ABOUT;О программе +GENERAL_CANCEL;Отмена +GENERAL_DISABLE;Выключить +GENERAL_DISABLED;Выключено +GENERAL_ENABLE;Включить +GENERAL_ENABLED;Включено +GENERAL_LANDSCAPE;Ðльбомный +GENERAL_LOAD;Загрузить +GENERAL_NA;Ð/Д +GENERAL_NO;Ðет +GENERAL_OK;OK +GENERAL_PORTRAIT;Портретный +GENERAL_SAVE;Сохранить +GENERAL_YES;Да +HISTOGRAM_LABEL;Histogram +HISTOGRAM_TOOLTIP_B;Показать/Ñкрыть СИÐИЙ канал гиÑтограммы +HISTOGRAM_TOOLTIP_G;Показать/Ñкрыть ЗЕЛÐÐЫЙ канал гиÑтограммы +HISTOGRAM_TOOLTIP_L;Показать/Ñкрыть CIELAB канал гиÑтограммы +HISTOGRAM_TOOLTIP_R;Показать/Ñкрыть КРÐСÐЫЙ канал гиÑтограммы +HISTORY_CHANGED;Изменено +HISTORY_CUSTOMCURVE;ПользовательÑÐºÐ°Ñ ÐºÑ€Ð¸Ð²Ð°Ñ +HISTORY_DELSNAPSHOT;Удалить Ñнимок +HISTORY_FROMCLIPBOARD;Из буфера обмена +HISTORY_LABEL;ИÑÑ‚Ð¾Ñ€Ð¸Ñ +HISTORY_MSG_10;Сжатие теней +HISTORY_MSG_11;Ð¢Ð¾Ð½Ð¾Ð²Ð°Ñ ÐºÑ€Ð¸Ð²Ð°Ñ +HISTORY_MSG_12;ÐвтоматичеÑÐºÐ°Ñ Ð½Ð°Ñтройка +HISTORY_MSG_13;Ограничение ÑкÑпозиции +HISTORY_MSG_14;Luminance ЯркоÑть +HISTORY_MSG_15;Luminance КонтраÑÑ‚ +HISTORY_MSG_16;Luminance Уровень чёрного +HISTORY_MSG_17;Luminance Сжатие Ñветов +HISTORY_MSG_18;Luminance Сжатие теней +HISTORY_MSG_19;Luminance Ð¢Ð¾Ð½Ð¾Ð²Ð°Ñ ÐºÑ€Ð¸Ð²Ð°Ñ +HISTORY_MSG_1;Фото загружено +HISTORY_MSG_20;РезкоÑть +HISTORY_MSG_21;Ð Ð°Ð´Ð¸ÑƒÑ Ñ€ÐµÐ·ÐºÐ¾Ñти +HISTORY_MSG_22;Величина резкоÑти +HISTORY_MSG_23;Порог резкоÑти +HISTORY_MSG_24;РезкоÑть: Только границы +HISTORY_MSG_25;РезкоÑть: Ð Ð°Ð´Ð¸ÑƒÑ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ð³Ñ€Ð°Ð½Ð¸Ñ† +HISTORY_MSG_26;РезкоÑть: ДопуÑк Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ð³Ñ€Ð°Ð½Ð¸Ñ† +HISTORY_MSG_27;РезкоÑть: Управление ореолом +HISTORY_MSG_28;РезкоÑть: Величина Halo +HISTORY_MSG_29;РезкоÑть: Метод +HISTORY_MSG_2;Профиль загружен +HISTORY_MSG_30;Deconvolution: Ð Ð°Ð´Ð¸ÑƒÑ +HISTORY_MSG_31;Deconvolution: Значение +HISTORY_MSG_32;Deconvolution: ОÑлабление +HISTORY_MSG_33;Deconvolution: Повторов +HISTORY_MSG_34;Предотвращать Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸Ñ Ñ†Ð²ÐµÑ‚Ð¾Ð² +HISTORY_MSG_35;Ограничитель наÑыщенноÑти +HISTORY_MSG_36;Ограничение наÑыщенноÑти +HISTORY_MSG_37;УÑиление цвета +HISTORY_MSG_38;Метод Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ð±Ð°Ð»Ð°Ð½Ñа белого +HISTORY_MSG_39;Ð¦Ð²ÐµÑ‚Ð¾Ð²Ð°Ñ Ñ‚ÐµÐ¼Ð¿ÐµÑ€Ð°Ñ‚ÑƒÑ€Ð° +HISTORY_MSG_3;Профиль изменён +HISTORY_MSG_40;Ð‘Ð°Ð»Ð°Ð½Ñ Ð±ÐµÐ»Ð¾Ð³Ð¾: оттенок +HISTORY_MSG_41;Сдвиг цвета "A" +HISTORY_MSG_42;Сдвиг цвета "B" +HISTORY_MSG_43;Удаление шума +HISTORY_MSG_44;Удаление шума: Ñ€Ð°Ð´Ð¸ÑƒÑ +HISTORY_MSG_45;Удаление шума: чувÑтвительноÑть к границам +HISTORY_MSG_46;Удаление цветового шума +HISTORY_MSG_47;Удаление цветового шума: Ñ€Ð°Ð´Ð¸ÑƒÑ +HISTORY_MSG_48;Удаление цветового шума: чувÑтвительноÑть к границам +HISTORY_MSG_49;Удаление цветового шума Ñ ÑƒÑ‡ÐµÑ‚Ð¾Ð¼ границ +HISTORY_MSG_4;ПроÑмотр иÑтории +HISTORY_MSG_50;ИнÑтрумент "Тени/Света" +HISTORY_MSG_51;Подъём Ñветов +HISTORY_MSG_52;Подъём теней +HISTORY_MSG_53;Уровень Ñветов +HISTORY_MSG_54;Уровень теней +HISTORY_MSG_55;Локальный контраÑÑ‚ +HISTORY_MSG_56;Ð Ð°Ð´Ð¸ÑƒÑ Ñветов/теней +HISTORY_MSG_57;Грубый поворот +HISTORY_MSG_58;Зеркальное отражение по горизонтали +HISTORY_MSG_59;Зеркальное отражение по вертикали +HISTORY_MSG_5;ЯркоÑть +HISTORY_MSG_60;Поворот +HISTORY_MSG_61;Поворот +HISTORY_MSG_62;ÐšÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ Ð¸Ñкажений оптики +HISTORY_MSG_63;Закладка выбрана +HISTORY_MSG_64;Кадрирование +HISTORY_MSG_65;ÐšÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ Ð¥Ð +HISTORY_MSG_66;ВоÑÑтановление Ñветов +HISTORY_MSG_67;Величина воÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ñветов +HISTORY_MSG_68;СпоÑоб воÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ñветов +HISTORY_MSG_69;Рабочее цветовое проÑтранÑтво +HISTORY_MSG_6;КонтраÑÑ‚ +HISTORY_MSG_70;Выходное цветовое проÑтранÑтво +HISTORY_MSG_71;Входное цветовое проÑтранÑтво +HISTORY_MSG_72;Виньетирование +HISTORY_MSG_73;Цветовые каналы +HISTORY_MSG_74;МаÑштаб Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ñ€Ð°Ð·Ð¼ÐµÑ€Ð¾Ð² +HISTORY_MSG_75;СпоÑоб Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ñ€Ð°Ð·Ð¼ÐµÑ€Ð¾Ð² +HISTORY_MSG_76;Метаданные Exif +HISTORY_MSG_77;Метаданные IPTC +HISTORY_MSG_7;Уровень чёрного +HISTORY_MSG_8;КомпенÑÐ°Ñ†Ð¸Ñ ÑкÑпозиции +HISTORY_MSG_9;Сжатие Ñветов +HISTORY_NEWSNAPSHOT;Ðовый Ñнимок +HISTORY_NEWSNAPSHOTAS;Как... +HISTORY_NEWSSDIALOGLABEL;Ðазвание Ñнимка: +HISTORY_NEWSSDIALOGTITLE;Добавить Ñнимок +HISTORY_SETTO;УÑтановить в +HISTORY_SNAPSHOT;Снимок +HISTORY_SNAPSHOTS;Снимки +ICMPANEL_FILEDLGFILTERANY;Любые файлы +ICMPANEL_FILEDLGFILTERICM;Файлы ICC профилей +ICMPANEL_GAMMABEFOREINPUT;ПрименÑть гамму Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñ„Ð¸Ð»Ñ +ICMPANEL_INPUTCAMERA;По умолчанию Ð´Ð»Ñ ÐºÐ°Ð¼ÐµÑ€Ñ‹ +ICMPANEL_INPUTCUSTOM;ПользовательÑкий +ICMPANEL_INPUTDLGLABEL;Выберите входной ICC профиль... +ICMPANEL_INPUTEMBEDDED;ИÑпользовать вÑтроенный, еÑли Ñто возможно +ICMPANEL_INPUTPROFILE;Входной профиль +ICMPANEL_NOICM;Без ICM: sRGB на выходе +ICMPANEL_OUTPUTDLGLABEL;Выберите выходной ICC профиль... +ICMPANEL_OUTPUTPROFILE;Выходной профиль +ICMPANEL_SAVEREFERENCE;Сохранить иÑходное изображение Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñ„Ð¸Ð»Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ +ICMPANEL_WORKINGPROFILE;Рабочий профиль +IMAGEAREA_DETAILVIEW;Детальный проÑмотр +IPTCPANEL_AUTHOR;Ðвтор +IPTCPANEL_AUTHORHINT;Ð˜Ð¼Ñ ÑÐ¾Ð·Ð´Ð°Ñ‚ÐµÐ»Ñ Ð¾Ð±ÑŠÐµÐºÑ‚Ð° (пиÑателÑ, фотографа или художника) (By-line) +IPTCPANEL_AUTHORSPOSITION;ÐŸÐ¾Ð·Ð¸Ñ†Ð¸Ñ Ð°Ð²Ñ‚Ð¾Ñ€Ð° +IPTCPANEL_AUTHORSPOSITIONHINT;Ðазвание автора или авторов объекта (By-line Title). +IPTCPANEL_CAPTION;ПодпиÑÑŒ +IPTCPANEL_CAPTIONHINT;ТекÑтовое опиÑание данных (Caption - Abstract) +IPTCPANEL_CAPTIONWRITER;Ðвтор подпиÑи +IPTCPANEL_CAPTIONWRITERHINT;Ð˜Ð¼Ñ Ñ‡ÐµÐ»Ð¾Ð²ÐµÐºÐ°, учаÑтвовавшего в Ñоздании, изменении или редактировании Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð»Ð¸Ð±Ð¾ подпиÑи (Writer - Editor). +IPTCPANEL_CATEGORY;ÐšÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ð¸Ñ +IPTCPANEL_CATEGORYHINT;УÑтанавливает тему Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ (Category) +IPTCPANEL_CITY;Город +IPTCPANEL_CITYHINT;Город (City). +IPTCPANEL_COPYHINT;Копировать данные IPTC в буфер обмена +IPTCPANEL_COPYRIGHT;ÐвторÑкие права +IPTCPANEL_COPYRIGHTHINT;Любые Ð¿Ñ€ÐµÐ´ÑƒÐ¿Ñ€ÐµÐ¶Ð´ÐµÐ½Ð¸Ñ Ð¾Ð± авторÑких правах (Copyright Notice). +IPTCPANEL_COUNTRY;Страна +IPTCPANEL_COUNTRYHINT;Ðазвание Ñтраны/начального меÑÑ‚Ð¾Ð¿Ð¾Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ (Country - Primary Location Name). +IPTCPANEL_CREDIT;Credit +IPTCPANEL_CREDITHINT;Идентифицирует продавца Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ (Credit). +IPTCPANEL_DATECREATED;Дата ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ +IPTCPANEL_DATECREATEDHINT;Дата ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¸Ð½Ñ‚ÐµÐ»Ð»ÐµÐºÑ‚ÑƒÐ°Ð»ÑŒÐ½Ð¾Ð³Ð¾ ÑÐ¾Ð´ÐµÑ€Ð¶Ð°Ð½Ð¸Ñ Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ; Формат: ГГГГММДД (Date Created). +IPTCPANEL_EMBEDDED;Ð’Ñтроенный +IPTCPANEL_EMBEDDEDHINT;СброÑить данные IPTC, вÑтроенные в файл Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ +IPTCPANEL_HEADLINE;Заголовок +IPTCPANEL_HEADLINEHINT;ПодходÑщий Ð´Ð»Ñ Ð¿ÑƒÐ±Ð»Ð¸ÐºÐ°Ñ†Ð¸Ð¸ краткий обзор Ñодержимого Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ (Headline). +IPTCPANEL_INSTRUCTIONS;ИнÑтрукции +IPTCPANEL_INSTRUCTIONSHINT;Прочие редакторÑкие инÑтрукции об иÑпользовании Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ (Special Instructions). +IPTCPANEL_KEYWORDS;Ключевые Ñлова +IPTCPANEL_KEYWORDSHINT;Ключевые Ñлова, иÑпользуемые Ð´Ð»Ñ Ð¿Ð¾Ð¸Ñка (Keywords). +IPTCPANEL_PASTEHINT;Ð’Ñтавить данные IPTC из буфера обмена +IPTCPANEL_PROVINCE;ÐŸÑ€Ð¾Ð²Ð¸Ð½Ñ†Ð¸Ñ +IPTCPANEL_PROVINCEHINT;ПровинциÑ/штат (Province-State). +IPTCPANEL_RESET;СброÑить +IPTCPANEL_RESETHINT;СброÑить профиль на Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¿Ð¾ умолчанию +IPTCPANEL_SOURCE;ИÑточник +IPTCPANEL_SOURCEHINT;Первоначальный владелец интеллектуального ÑÐ¾Ð´ÐµÑ€Ð¶Ð°Ð½Ð¸Ñ Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ (Source). +IPTCPANEL_SUPPCATEGORIES;Доп. категории +IPTCPANEL_SUPPCATEGORIESHINT;Дополнительные ÑƒÑ‚Ð¾Ñ‡Ð½ÐµÐ½Ð¸Ñ Ñ‚ÐµÐ¼Ñ‹ Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ (Supplemental Categories). +IPTCPANEL_TITLE;Ðазвание +IPTCPANEL_TITLEHINT;ПроÑтое опиÑание Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ (Object Name). +IPTCPANEL_TRANSREFERENCE;Trans. Reference +IPTCPANEL_TRANSREFERENCEHINT;Код, предÑтавлÑющий проиÑхождение Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ (Original Transmission Reference). +MAIN_BUTTON_PREFERENCES;ÐаÑтройки +MAIN_BUTTON_SAVE;Сохранить изображение +MAIN_BUTTON_SAVEAS;Как... +MAIN_BUTTON_SENDTOEDITOR;Открыть в редакторе +MAIN_MSG_ALREADYEXISTS;Файл уже ÑущеÑтвует. +MAIN_MSG_CANNOTLOAD;Ðевозможно загрузить изображение +MAIN_MSG_CANNOTSAVE;Ошибка при Ñохранении файла +MAIN_MSG_CANNOTSTARTEDITOR;не удалоÑÑŒ запуÑтить редактор. +MAIN_MSG_CANNOTSTARTEDITOR_SECONDARY;ПожалуйÑта, уÑтановите правильный путь в диалоге "ÐаÑтройки". +MAIN_MSG_EXITJOBSINQUEUEINFO;Ðеобработанные изображениÑ, находÑщиеÑÑ Ð² очереди,будут утерÑны при выходу. +MAIN_MSG_EXITJOBSINQUEUEQUEST;Ð’Ñ‹ уверены, что хотите выйти из программы? Ð’ очереди оÑталиÑÑŒ необработанные изображениÑ. +MAIN_MSG_JOBSINQUEUE;Идёт обработка +MAIN_MSG_QOVERWRITE;Ð’Ñ‹ хотите перезапиÑать его? +MAIN_TAB_BASIC;ОÑновные +MAIN_TAB_COLOR;Цвет +MAIN_TAB_DETAIL;Ð”ÐµÑ‚Ð°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ +MAIN_TAB_EXIF;Exif +MAIN_TAB_EXPOSURE;ЭкÑÐ¿Ð¾Ð·Ð¸Ñ†Ð¸Ñ +MAIN_TAB_ICM;ICM +MAIN_TAB_IPTC;IPTC +MAIN_TAB_METADATA;Метаданные +MAIN_TAB_TRANSFORM;ÐŸÑ€ÐµÐ¾Ð±Ñ€Ð°Ð·Ð¾Ð²Ð°Ð½Ð¸Ñ +MAIN_TOOLTIP_HIDEFP;Показать/Ñкрыть нижнюю панель (папки и ÑпиÑок файлов, shortcut key: F) +MAIN_TOOLTIP_HIDEHP;Показать/Ñкрыть левую панель (Ð²ÐºÐ»ÑŽÑ‡Ð°Ñ Ð¸Ñторию, shortcut key: H) +MAIN_TOOLTIP_INDCLIPPEDH;Индикатор переÑветов +MAIN_TOOLTIP_INDCLIPPEDS;Индикатор затемнений +MAIN_TOOLTIP_PREFERENCES;задать наÑтройки +MAIN_TOOLTIP_QINFO;Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾Ð± изображении +MAIN_TOOLTIP_SAVE;Сохранить изображение в каталог по умолчанию +MAIN_TOOLTIP_SAVEAS;Сохранить изображение в... +PARTIALPASTE_BASICGROUP;Базовые наÑтройки +PARTIALPASTE_CACORRECTION;ÐšÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ C/A +PARTIALPASTE_COARSETRANS;поворот на 90 гр. / отражение +PARTIALPASTE_COLORBOOST;УÑиление цвета +PARTIALPASTE_COLORDENOISE;Удаление цветового шума +PARTIALPASTE_COLORGROUP;ÐаÑтройка цвета +PARTIALPASTE_COLORMIXER;Цветовой микшер +PARTIALPASTE_COLORSHIFT;ИÑкажение цвета +PARTIALPASTE_COMPOSITIONGROUP;Параметры компоновки +PARTIALPASTE_CROP;Кадрирование +PARTIALPASTE_DIALOGLABEL;ЧаÑÑ‚Ð¸Ñ‡Ð½Ð°Ñ Ð²Ñтавка параметров обработки +PARTIALPASTE_DISTORTION;ДиÑторÑÐ¸Ñ +PARTIALPASTE_EXIFCHANGES;Ð˜Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ… Exif +PARTIALPASTE_EXPOSURE;ЭкÑÐ¿Ð¾Ð·Ð¸Ñ†Ð¸Ñ +PARTIALPASTE_HLRECOVERY;ВоÑÑтановление Ñветов +PARTIALPASTE_ICMSETTINGS;Параметры ICM +PARTIALPASTE_IPTCINFO;Данные IPTC +PARTIALPASTE_LENSGROUP;Параметры Ñъемки +PARTIALPASTE_LUMACURVE;ÐšÑ€Ð¸Ð²Ð°Ñ ÑркоÑти +PARTIALPASTE_LUMADENOISE;Удаление ÑркоÑтного шума +PARTIALPASTE_LUMINANCEGROUP;ÐаÑтройка параметров ÑркоÑти +PARTIALPASTE_METAICMGROUP;ÐаÑтройка метаданных/параметров ICM +PARTIALPASTE_RESIZE;Изменение размера +PARTIALPASTE_ROTATION;Поворот +PARTIALPASTE_SHADOWSHIGHLIGHTS;Тени/Ñвета +PARTIALPASTE_SHARPENING;Повышение резкоÑти +PARTIALPASTE_VIGNETTING;ÐšÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ Ð²Ð¸Ð½ÑŒÐµÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ +PARTIALPASTE_WHITEBALANCE;Ð‘Ð°Ð»Ð°Ð½Ñ Ð±ÐµÐ»Ð¾Ð³Ð¾ +PREFERENCES_APPLNEXTSTARTUP;Ðужен перезапуÑк программы +PREFERENCES_BLINKCLIPPED;Мигать проблемными зонами +PREFERENCES_CACHECLEARALL;Удалить вÑе +PREFERENCES_CACHECLEARPROFILES;Удалить параметры обработки +PREFERENCES_CACHECLEARTHUMBS;Удалить ÑÑкизы +PREFERENCES_CACHEFORMAT1;СобÑтвенный (быÑтрее, выше качеÑтво) +PREFERENCES_CACHEFORMAT2;JPEG (меньший объем диÑкового проÑтранÑтва) +PREFERENCES_CACHEMAXENTRIES;МакÑимальное чиÑло Ñлементов в кÑше +PREFERENCES_CACHEOPTS;Параметры кÑÑˆÐ¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ +PREFERENCES_CACHESTRAT1;Более выÑÐ¾ÐºÐ°Ñ ÑкороÑть работы - больший раÑход памÑти +PREFERENCES_CACHESTRAT2;Меньший раÑход памÑти - более Ð½Ð¸Ð·ÐºÐ°Ñ ÑкороÑть работы +PREFERENCES_CACHESTRAT;Ð¡Ñ‚Ñ€Ð°Ñ‚ÐµÐ³Ð¸Ñ ÐºÑÑˆÐ¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ +PREFERENCES_CACHETHUMBFORM;Формат кÑÑˆÐ¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ ÑÑкизов +PREFERENCES_CACHETHUMBHEIGHT;МакÑÐ¸Ð¼Ð°Ð»ÑŒÐ½Ð°Ñ Ð²Ñ‹Ñота ÑÑкиза +PREFERENCES_CLEARDLG_LINE1;ОчиÑтка кÑша +PREFERENCES_CLEARDLG_LINE2;Это может занÑть неÑколько Ñекунд. +PREFERENCES_CLEARDLG_TITLE;ПожалуйÑта, подождите +PREFERENCES_CLIPPINGIND;Ð˜Ð½Ð´Ð¸ÐºÐ°Ñ†Ð¸Ñ Ð¿ÐµÑ€ÐµÑветов/затемнений +PREFERENCES_CMETRICINTENT;КолориметричеÑкое преобразование +PREFERENCES_DATEFORMAT;Формат даты +PREFERENCES_DATEFORMATHINT;You can use the following formatting strings:\n%y : year\n%m : month\n%d : day\n\nFor example, the hungarian date format is:\n%y/%m/%d +PREFERENCES_DEFAULTLANG;Язык по умолчанию +PREFERENCES_DEFAULTTHEME;Тема по умолчанию +PREFERENCES_DEMOSAICINGALGO;Ðлгоритм Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ +PREFERENCES_DIRHOME;Домашний каталог +PREFERENCES_DIRLAST;ПоÑледний каталог +PREFERENCES_DIROTHER;Другой +PREFERENCES_DIRSELECTDLG;Выберите каталог Ð´Ð»Ñ Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ð¹ +PREFERENCES_DIRSOFTWARE;Каталог уÑтановки +PREFERENCES_DMETHOD;Метод +PREFERENCES_EDITORCMDLINE;Другой (путь к иÑполнÑемому файлу) +PREFERENCES_EXTERNALEDITOR;Внешний редактор +PREFERENCES_FALSECOLOR;ЧиÑло шагов Ð´Ð»Ñ Ð¿Ð¾Ð´Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð½ÐµÐºÐ¾Ñ€Ñ€ÐµÐºÑ‚Ð½Ñ‹Ñ… цветов +PREFERENCES_FBROWSEROPTS;ÐаÑтройки +PREFERENCES_FILEFORMAT;Формат файлов +PREFERENCES_FORIMAGE;Ð”Ð»Ñ Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ð¹ +PREFERENCES_FORRAW;Ð”Ð»Ñ RAW файлов +PREFERENCES_GIMPPATH;Путь уÑтановки GIMP +PREFERENCES_GTKTHEME;GTK по умолчанию +PREFERENCES_HINT;ПодÑказка +PREFERENCES_HLTHRESHOLD;Порог ÑÑ€Ð°Ð±Ð°Ñ‚Ñ‹Ð²Ð°Ð½Ð¸Ñ Ð¿ÐµÑ€ÐµÑветов +PREFERENCES_ICCDIR;Каталог Ð´Ð»Ñ ICC профилей +PREFERENCES_IMPROCPARAMS;Параметры обработки по умолчанию +PREFERENCES_INTENT_ABSOLUTE;ÐбÑолютное +PREFERENCES_INTENT_PERCEPTUAL;Перцепционное +PREFERENCES_INTENT_RELATIVE;ОтноÑительное +PREFERENCES_INTENT_SATURATION;По наÑыщенноÑти +PREFERENCES_LIVETHUMBNAILS;ЭÑкизы в реальном времени (медленно) +PREFERENCES_MONITORICC;Профиль монитора +PREFERENCES_OUTDIR;Каталог +PREFERENCES_OUTDIRFOLDER;Сохранить в папку +PREFERENCES_OUTDIRFOLDERHINT;Сохранение изображений в выбранную папку +PREFERENCES_OUTDIRHINT;Ð’Ñ‹ можете иÑпользовать Ñледующие Ñлементы Ð´Ð»Ñ Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nЭти Ñлементы ÑоответÑтвуют директориÑм и поддиректориÑм в пути к RAW файлу.\n\nÐ”Ð»Ñ Ð¿Ñ€Ð¸Ð¼ÐµÑ€Ð°, еÑли путь к файлу - /home/tom/image/02-09-2006/dsc0012.nef, то Ñлементы Ð´Ð»Ñ Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð±ÑƒÐ´ÑƒÑ‚ Ñледующими:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nЕÑли вы хотите ÑохранÑть Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð² один каталог Ñ Ð¾Ñ€Ð¸Ð³Ð¸Ð½Ð°Ð»Ð¾Ð¼, наÑтройка должна быть Ñледующей:\n%p1/%f\n\nЕÑли вы хотите ÑохранÑть Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð² подкаталог 'converted' в директории оригинального файла, укажите наÑтройку:\n%p1/converted/%f\n\nЕÑли вы хотите ÑохранÑть Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð² каталог '/home/tom/converted' Ñ Ñохранением поддиректорий Ñ Ð´Ð°Ñ‚Ð°Ð¼Ð¸, укажите наÑтройку:\n%p2/converted/%d1/%f +PREFERENCES_OUTDIRTEMPLATE;ИÑпользовать шаблон +PREFERENCES_OUTDIRTEMPLATEHINT;You can use the following formatting strings:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nThese formatting strings refer to the directories and sub-paths of the path of the raw file.\n\nFor example, if /home/tom/image/02-09-2006/dsc0012.nefhas been opened, the meaning of the formatting strings are:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nIf you want to save the output image where the original is, write:\n%p1/%f\n\nIf you want to save the output image in a directory 'converted' located the directory of the original, write:\n%p1/converted/%f\n\nIf you want to save the output image in directory '/home/tom/converted' with keeping the same subdirectory of dates, write:\n%p2/converted/%d1/%f +PREFERENCES_PARSEDEXT;РаÑÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð¾Ð² Ð´Ð»Ñ Ð¿Ñ€ÐµÐ´Ð²Ð°Ñ€Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ð³Ð¾ проÑмотра +PREFERENCES_PARSEDEXTADD;Добавить раÑширение +PREFERENCES_PARSEDEXTADDHINT;Введите раÑширение и нажмите на Ñту кнопку, чтобы добавить его в ÑпиÑок +PREFERENCES_PARSEDEXTDELHINT;Удаление выбранных раÑширений из ÑпиÑка +PREFERENCES_PROFILEHANDLING;Профиль поÑтобработки +PREFERENCES_PROFILELOADPR;Приоритет загрузки Ð¿Ñ€Ð¾Ñ„Ð¸Ð»Ñ Ð¿Ð¾Ñтобработки +PREFERENCES_PROFILEPRCACHE;загружать из кÑша +PREFERENCES_PROFILEPRFILE;загружать из каталога Ñ Ñ„Ð°Ð¹Ð»Ð¾Ð¼ +PREFERENCES_PROFILESAVECACHE;Сохранить профиль поÑтобработки в кÑше +PREFERENCES_PROFILESAVEINPUT;Сохранить профиль поÑтобработки в одном каталоге Ñ Ð¸Ñходным файлом +PREFERENCES_PSPATH;Путь уÑтановки Adobe Photoshop +PREFERENCES_SELECTICCDIRDLG;Выберите каталог Ð´Ð»Ñ ICC профилÑ... +PREFERENCES_SELECTLANG;Выберите Ñзык +PREFERENCES_SELECTMONITORPROFDLG;Выберите каталог Ð´Ð»Ñ ICC Ð¿Ñ€Ð¾Ñ„Ð¸Ð»Ñ Ð¼Ð¾Ð½Ð¸Ñ‚Ð¾Ñ€Ð°... +PREFERENCES_SELECTTHEME;Выбрать тему +PREFERENCES_SHOWBASICEXIF;Показывать оÑновные Exif данные +PREFERENCES_SHOWDATETIME;Показывать дату и Ð²Ñ€ÐµÐ¼Ñ +PREFERENCES_SHOWONLYRAW;Показывать только RAW-файлы +PREFERENCES_SHTHRESHOLD;Порог ÑÑ€Ð°Ð±Ð°Ñ‚Ñ‹Ð²Ð°Ð½Ð¸Ñ Ð·Ð°Ñ‚ÐµÐ¼Ð½ÐµÐ½Ð¸Ð¹ +PREFERENCES_STARTUPIMDIR;Каталог изображений при запуÑке +PREFERENCES_TAB_BROWSER;Браузер файлов +PREFERENCES_TAB_COLORMGR;Ð£Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ñ†Ð²ÐµÑ‚Ð¾Ð¼ +PREFERENCES_TAB_GENERAL;ОÑновные +PREFERENCES_TAB_IMPROC;Обработка Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ +PREFERENCES_TAB_OUTPUT;Сохранение +PREFERENCES_THUMBSIZE;Размер миниатюры +PROFILEPANEL_FILEDLGFILTERANY;Любые файлы +PROFILEPANEL_FILEDLGFILTERPP;Профили поÑтобработки +PROFILEPANEL_LABEL;Профиль поÑтобработки +PROFILEPANEL_LOADDLGLABEL;Загрузить профиль поÑтобработки... +PROFILEPANEL_PCUSTOM;ПользовательÑкий +PROFILEPANEL_PFILE;Из файла +PROFILEPANEL_PLASTPHOTO;Из прошлого Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ +PROFILEPANEL_PLASTSAVED;ПоÑледний запиÑанный +PROFILEPANEL_PROFILE;Профиль +PROFILEPANEL_SAVEDLGLABEL;Сохранить профиль поÑтобработки... +PROFILEPANEL_TOOLTIPCOPY;Скопировать текущий профиль в буфер обмена +PROFILEPANEL_TOOLTIPLOAD;Загрузить профиль из файла +PROFILEPANEL_TOOLTIPPASTE;Ð’Ñтавить профиль из буфера обмена +PROFILEPANEL_TOOLTIPSAVE;Сохранить текущий профиль +PROGRESSBAR_DECODING;Декодирование RAW файла... +PROGRESSBAR_DEMOSAICING;ПоÑтроение изображениÑ... +PROGRESSBAR_LOADING;Загрузка изображениÑ... +PROGRESSBAR_LOADJPEG;Чтение JPEG файла... +PROGRESSBAR_LOADPNG;Чтение PNG файла... +PROGRESSBAR_LOADTIFF;Чтение TIFF файла... +PROGRESSBAR_PROCESSING;Обработка изображениÑ... +PROGRESSBAR_READY;Готово. +PROGRESSBAR_SAVEJPEG;Сохранение JPEG файла... +PROGRESSBAR_SAVEPNG;Сохранение PNG файла... +PROGRESSBAR_SAVETIFF;Сохранение TIFF файла... +PROGRESSDLG_LOADING;Загрузка файла... +PROGRESSDLG_PROCESSING;Обработка изображениÑ... +PROGRESSDLG_SAVING;Сохранение файла... +QINFO_FOCALLENGTH;Focal Lenth +QINFO_ISO;ISO +QINFO_LENS;Объектив +QINFO_NOEXIF;Данные Exif недоÑтупны +SAVEDLG_FILEFORMAT;Формат файла +SAVEDLG_JPEGQUAL;КачеÑтво JPEG +SAVEDLG_JPGFILTER;Файлы JPEG +SAVEDLG_PNGCOMPR;Сжатие PNG +SAVEDLG_PNGFILTER;Файлы PNG +SAVEDLG_PUTTOQUEUE;ПомеÑтить в очередь на обработку +SAVEDLG_PUTTOQUEUEHEAD;Put to the head of the processing queue +SAVEDLG_PUTTOQUEUETAIL;Put to the end of the processing queue +SAVEDLG_SAVEIMMEDIATELY;Сохранить ÑÐµÐ¹Ñ‡Ð°Ñ +SAVEDLG_SAVESPP;СохранÑть параметры обработки вмеÑте Ñ Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸ÐµÐ¼ +SAVEDLG_TIFFFILTER;Файлы TIFF +TOOLBAR_TOOLTIP_CROP;Кадрирование (shortcut key: C) +TOOLBAR_TOOLTIP_HAND;ИнÑтрумент "Рука" (shortcut key: N) +TOOLBAR_TOOLTIP_STRAIGHTEN;УÑтановка прÑмой линии (shortcut key: S) +TOOLBAR_TOOLTIP_WB;Указать белую точку (shortcut key: W) +TP_CACORRECTION_BLUE;Синий +TP_CACORRECTION_LABEL;ХроматичеÑкие аберрации +TP_CACORRECTION_RED;КраÑный +TP_CHMIXER_BLUE;Синий +TP_CHMIXER_GREEN;Зелёный +TP_CHMIXER_LABEL;Цветовые каналы +TP_CHMIXER_RED;КраÑный +TP_COARSETRAF_DEGREE;угол: +TP_COARSETRAF_TOOLTIP_HFLIP;Гориз. зеркальное отражение +TP_COARSETRAF_TOOLTIP_ROTLEFT;Повернуть влево +TP_COARSETRAF_TOOLTIP_ROTRIGHT;Повернуть вправо +TP_COARSETRAF_TOOLTIP_VFLIP;Верт. зеркальное отражение +TP_COLORBOOST_ACHANNEL;Канал "a" +TP_COLORBOOST_AMOUNT;Величина +TP_COLORBOOST_AVOIDCOLORCLIP;Избегать Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸Ñ Ñ†Ð²ÐµÑ‚Ð¾Ð² +TP_COLORBOOST_BCHANNEL;Канал "b" +TP_COLORBOOST_CHAB;a & b +TP_COLORBOOST_CHANNEL;Канал +TP_COLORBOOST_CHSEPARATE;По отдельноÑти +TP_COLORBOOST_ENABLESATLIMITER;Ограничение наÑыщенноÑти +TP_COLORBOOST_LABEL;УÑиление цвета +TP_COLORBOOST_SATLIMIT;Ограничение наÑыщенноÑти +TP_COLORDENOISE_EDGESENSITIVE;ЧувÑтвительноÑть к границам +TP_COLORDENOISE_EDGETOLERANCE;УÑтойчивоÑть к границам +TP_COLORDENOISE_LABEL;Удаление цветового шума +TP_COLORDENOISE_RADIUS;Ð Ð°Ð´Ð¸ÑƒÑ +TP_COLORSHIFT_BLUEYELLOW;Синий-Жёлтый +TP_COLORSHIFT_GREENMAGENTA;Зелёный-Пурпурный +TP_COLORSHIFT_LABEL;Сдвиг цвета +TP_CROP_DPI;DPI= +TP_CROP_FIXRATIO;ПропорциÑ: +TP_CROP_GTDIAGONALS;Правило диагоналей +TP_CROP_GTHARMMEANS1;Среднее гармоничеÑкое 1 +TP_CROP_GTHARMMEANS2;Среднее гармоничеÑкое 2 +TP_CROP_GTHARMMEANS3;Среднее гармоничеÑкое 3 +TP_CROP_GTHARMMEANS4;Среднее гармоничеÑкое 4 +TP_CROP_GTNONE;Ðет +TP_CROP_GTRULETHIRDS;Правило третей +TP_CROP_GUIDETYPE;Тип направлÑющей: +TP_CROP_H;Ð’ +TP_CROP_LABEL;Кадрирование +TP_CROP_SELECTCROP; Вкл. режим обрезки +TP_CROP_W;Ш +TP_CROP_X;x +TP_CROP_Y;y +TP_DISTORTION_AMOUNT;Величина +TP_DISTORTION_LABEL;ДиÑторÑÐ¸Ñ +TP_EXPOSURE_AUTOLEVELS;ÐвтоматичеÑкие уровни +TP_EXPOSURE_BLACKLEVEL;Уровень чёрного +TP_EXPOSURE_BRIGHTNESS;ЯркоÑть +TP_EXPOSURE_CLIP;Ограничить +TP_EXPOSURE_COMPRHIGHLIGHTS;Сжатие бликов +TP_EXPOSURE_COMPRSHADOWS;Сжатие теней +TP_EXPOSURE_CONTRAST;КонтраÑÑ‚ +TP_EXPOSURE_CURVEEDITOR;Ð¢Ð¾Ð½Ð¾Ð²Ð°Ñ ÐºÑ€Ð¸Ð²Ð°Ñ +TP_EXPOSURE_EXPCOMP;Комп. ÑкÑп. +TP_EXPOSURE_LABEL;ЭкÑÐ¿Ð¾Ð·Ð¸Ñ†Ð¸Ñ +TP_HLREC_CIELAB;CIELab Blending +TP_HLREC_COLOR;РеконÑÑ‚Ñ€ÑƒÐºÑ†Ð¸Ñ Ñ†Ð²ÐµÑ‚Ð° +TP_HLREC_LABEL;ВоÑÑтановление Ñрких учаÑтков +TP_HLREC_LUMINANCE;ВоÑÑтановление ÑркоÑти +TP_HLREC_METHOD;Метод: +TP_ICM_FILEDLGFILTERANY;Любые файлы +TP_ICM_FILEDLGFILTERICM;Файлы ICC профилей +TP_ICM_GAMMABEFOREINPUT;ПрименÑть гамму Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñ„Ð¸Ð»Ñ +TP_ICM_INPUTCAMERA;По умолчанию Ð´Ð»Ñ ÐºÐ°Ð¼ÐµÑ€Ñ‹ +TP_ICM_INPUTCUSTOM;ПользовательÑкий +TP_ICM_INPUTDLGLABEL;Выберите входной ICC профиль... +TP_ICM_INPUTEMBEDDED;ИÑпользовать вÑтроенный, еÑли Ñто возможно +TP_ICM_INPUTPROFILE;Входной профиль +TP_ICM_LABEL;ICM +TP_ICM_NOICM;Без ICM: sRGB на выходе +TP_ICM_OUTPUTDLGLABEL;Выберите выходной ICC профиль... +TP_ICM_OUTPUTPROFILE;Выходной профиль +TP_ICM_SAVEREFERENCE;Сохранить иÑходное изображение Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñ„Ð¸Ð»Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ +TP_ICM_WORKINGPROFILE;Рабочий профиль +TP_LUMACURVE_BLACKLEVEL;Уровень чёрного +TP_LUMACURVE_BRIGHTNESS;ЯркоÑть +TP_LUMACURVE_COMPRHIGHLIGHTS;Сжатие бликов +TP_LUMACURVE_COMPRSHADOWS;Сжатие теней +TP_LUMACURVE_CONTRAST;КонтраÑÑ‚ +TP_LUMACURVE_CURVEEDITOR;Ð¢Ð¾Ð½Ð¾Ð²Ð°Ñ ÐºÑ€Ð¸Ð²Ð°Ñ +TP_LUMACURVE_LABEL;ÐšÑ€Ð¸Ð²Ð°Ñ ÑркоÑти +TP_LUMADENOISE_EDGETOLERANCE;УÑтойчивоÑть к границам +TP_LUMADENOISE_LABEL;Удаление шума +TP_LUMADENOISE_RADIUS;Ñ€Ð°Ð´Ð¸ÑƒÑ +TP_RESIZE_BICUBIC;БикубичеÑкий +TP_RESIZE_BICUBICSF;МÑгкий бикубичеÑкий +TP_RESIZE_BICUBICSH;Резкий бикубичеÑкий +TP_RESIZE_BILINEAR;Билинейный +TP_RESIZE_FULLSIZE;Размер изображениÑ: +TP_RESIZE_H;Ð’: +TP_RESIZE_LABEL;Изменение размера +TP_RESIZE_METHOD;Метод: +TP_RESIZE_NEAREST;Ближайшие точки +TP_RESIZE_SCALE;МаÑштаб +TP_RESIZE_W;Ш: +TP_ROTATE_AUTOCROP;Ðвто-кадрирование +TP_ROTATE_DEGREE;Угол +TP_ROTATE_FILL;Ðвтообрезка +TP_ROTATE_LABEL;Поворот +TP_ROTATE_SELECTLINE; Выбрать прÑмую линию +TP_SHADOWSHLIGHTS_HIGHLIGHTS;Яркие учаÑтки +TP_SHADOWSHLIGHTS_HLTONALW;Уровень +TP_SHADOWSHLIGHTS_LABEL;Тени/Ñвета +TP_SHADOWSHLIGHTS_LOCALCONTR;Локальный контраÑÑ‚ +TP_SHADOWSHLIGHTS_RADIUS;Ð Ð°Ð´Ð¸ÑƒÑ +TP_SHADOWSHLIGHTS_SHADOWS;Тени +TP_SHADOWSHLIGHTS_SHTONALW;Уровень +TP_SHARPENING_AMOUNT;Величина +TP_SHARPENING_EDRADIUS;Ð Ð°Ð´Ð¸ÑƒÑ +TP_SHARPENING_EDTOLERANCE;Границы краёв +TP_SHARPENING_HALOCONTROL;Регулировка хром. аберраций +TP_SHARPENING_HCAMOUNT;Величина +TP_SHARPENING_LABEL;РезкоÑть +TP_SHARPENING_METHOD;Метод +TP_SHARPENING_ONLYEDGES;Только границы +TP_SHARPENING_RADIUS;Ð Ð°Ð´Ð¸ÑƒÑ +TP_SHARPENING_RLD;ÐžÐ±Ñ€Ð°Ñ‰Ñ‘Ð½Ð½Ð°Ñ Ñвёртка RL +TP_SHARPENING_RLD_AMOUNT;Величина +TP_SHARPENING_RLD_DAMPING;ОÑлабление +TP_SHARPENING_RLD_ITERATIONS;Повторений +TP_SHARPENING_THRESHOLD;Порог +TP_SHARPENING_USM;МаÑка Ñ€Ð°Ð·Ð¼Ñ‹Ñ‚Ð¸Ñ +TP_VIGNETTING_AMOUNT;Величина +TP_VIGNETTING_LABEL;Виньетирование +TP_VIGNETTING_RADIUS;Ð Ð°Ð´Ð¸ÑƒÑ +TP_WBALANCE_AUTO;ÐвтоматичеÑкий +TP_WBALANCE_CAMERA;Камера +TP_WBALANCE_CUSTOM;ПользовательÑкий +TP_WBALANCE_GREEN;Оттенок +TP_WBALANCE_LABEL;Ð‘Ð°Ð»Ð°Ð½Ñ Ð±ÐµÐ»Ð¾Ð³Ð¾ +TP_WBALANCE_METHOD;Метод +TP_WBALANCE_SIZE;Размер пипетки: +TP_WBALANCE_SPOTWB;Указать точку белого +TP_WBALANCE_TEMPERATURE;Температура +ZOOMBAR_DETAIL;Увеличение +ZOOMBAR_HUGE;МакÑимальное +ZOOMBAR_LARGE;Большое +ZOOMBAR_NORMAL;Среднее +ZOOMBAR_PREVIEW;ПредпроÑмотр +ZOOMBAR_SCALE;МаÑштаб +ZOOMBAR_SMALL;Минимальное diff --git a/release/languages/slovak b/release/languages/slovak new file mode 100755 index 000000000..6d44f02df --- /dev/null +++ b/release/languages/slovak @@ -0,0 +1,577 @@ +# SlovenÄina +# 08.05.2008 +# (Slapo) +ADJUSTER_RESET_TO_DEFAULT;ResetovaÅ¥ na predvolené nastavenia +CURVEEDITOR_FILEDLGFILTERANY;VÅ¡etky súbory +CURVEEDITOR_FILEDLGFILTERCURVE;Súbory kriviek +CURVEEDITOR_LINEAR;Lineárna +CURVEEDITOR_LOADDLGLABEL;NaÄítaÅ¥ krivku... +CURVEEDITOR_SAVEDLGLABEL;UložiÅ¥ krivku... +CURVEEDITOR_TOOLTIPLINEAR;ResetovaÅ¥ krivku na lineárnu +CURVEEDITOR_TOOLTIPLOAD;NaÄítaÅ¥ krivku zo súboru +CURVEEDITOR_TOOLTIPSAVE;UložiÅ¥ súÄasnú krivku +EXIFFILTER_APERTURE;Clona +EXIFFILTER_CAMERA;Fotoaparát +EXIFFILTER_DIALOGLABEL;Exif filter +EXIFFILTER_FOCALLEN;Ohnisková vzdialenosÅ¥ +EXIFFILTER_ISO;ISO +EXIFFILTER_LENS;Objektív +EXIFFILTER_SHUTTER;Uzávierka +EXIFPANEL_ADDEDIT;PridaÅ¥/UpraviÅ¥ +EXIFPANEL_ADDEDITHINT;PridaÅ¥ novú znaÄku alebo upraviÅ¥ znaÄku +EXIFPANEL_ADDTAGDLG_ENTERVALUE;VložiÅ¥ hodnotu +EXIFPANEL_ADDTAGDLG_SELECTTAG;VybraÅ¥ znaÄku +EXIFPANEL_ADDTAGDLG_TITLE;PridaÅ¥/UpraviÅ¥ znaÄku +EXIFPANEL_KEEP;PonechaÅ¥ +EXIFPANEL_KEEPHINT;PonechaÅ¥ vybrané znaÄky pri písaní výstupného súboru +EXIFPANEL_REMOVE;OdstrániÅ¥ +EXIFPANEL_REMOVEHINT;OdstrániÅ¥ vybrané znaÄky pri písaní výstupného súboru +EXIFPANEL_RESET;ResetovaÅ¥ +EXIFPANEL_RESETALL;ResetovaÅ¥ vÅ¡etky +EXIFPANEL_RESETALLHINT;ResetovaÅ¥ vÅ¡etky znaÄky na ich pôvodné hodnoty +EXIFPANEL_RESETHINT;ResetovaÅ¥ vybrané znaÄky na ich pôvodné hodnoty +EXIFPANEL_SUBDIRECTORY;Podadresár +FILEBROWSER_APPLYPROFILE;PoužiÅ¥ profil +FILEBROWSER_ARRANGEMENTHINT;ZmeniÅ¥ medzi vertikálnym/horizontálnym zarovnaním zmenÅ¡enín +FILEBROWSER_CLEARPROFILE;VyÄistiÅ¥ profil +FILEBROWSER_COPYPROFILE;KopírovaÅ¥ profil +FILEBROWSER_DELETEDLGLABEL;Potvrdenie odstránenia súboru +FILEBROWSER_DELETEDLGMSG;Ste si istí, že chcete odstrániÅ¥ vybrané %1 súbory? +FILEBROWSER_EMPTYTRASH;VyprázdniÅ¥ kôš +FILEBROWSER_EMPTYTRASHHINT;Permanentne odstrániÅ¥ súbory z koÅ¡a +FILEBROWSER_EXIFFILTERAPPLY;PoužiÅ¥ +FILEBROWSER_EXIFFILTERAPPLYHINT;Zapnúť/vypnúť EXIF filter prehliadaÄa súborov +FILEBROWSER_EXIFFILTERLABEL;Exif Filter +FILEBROWSER_EXIFFILTERSETTINGS;Nastavenia +FILEBROWSER_EXIFFILTERSETTINGSHINT;Zmeňte nastavenia EXIF filtra +FILEBROWSER_PARTIALPASTEPROFILE;ÄŒiastoÄné vloženie +FILEBROWSER_PASTEPROFILE;VložiÅ¥ profil +FILEBROWSER_POPUPCANCELJOB;ZruÅ¡iÅ¥ úlohu +FILEBROWSER_POPUPMOVEEND;Presunúť na koniec radu +FILEBROWSER_POPUPMOVEHEAD;Presunúť na zaÄiatok radu +FILEBROWSER_POPUPOPEN;OtvoriÅ¥ +FILEBROWSER_POPUPPROCESS;VložiÅ¥ do radu na spracovanie +FILEBROWSER_POPUPRANK1;Trieda 1 +FILEBROWSER_POPUPRANK2;Trieda 2 +FILEBROWSER_POPUPRANK3;Trieda 3 +FILEBROWSER_POPUPRANK4;Trieda 4 +FILEBROWSER_POPUPRANK5;Trieda 5 +FILEBROWSER_POPUPREMOVE;OdstrániÅ¥ zo systému súborov +FILEBROWSER_POPUPRENAME;PremenovaÅ¥ +FILEBROWSER_POPUPSELECTALL;VybraÅ¥ vÅ¡etko +FILEBROWSER_POPUPTRASH;Presunúť do koÅ¡a +FILEBROWSER_POPUPUNRANK;ZruÅ¡iÅ¥ triedu +FILEBROWSER_POPUPUNTRASH;OdstrániÅ¥ z koÅ¡a +FILEBROWSER_PROCESSINGSETTINGS;Nastavenia +FILEBROWSER_PROCESSINGSETTINGSHINT;NastaviÅ¥ formát súborov a výstupný adresár +FILEBROWSER_RENAMEDLGLABEL;PremenovaÅ¥ súbor +FILEBROWSER_RENAMEDLGMSG;PremenovaÅ¥ súbor "%1" na: +FILEBROWSER_SHOWDIRHINT;UkázaÅ¥ vÅ¡etky obrázky v adresári +FILEBROWSER_SHOWQUEUEHINT;ZobraziÅ¥ obsah radu na spracovanie +FILEBROWSER_SHOWRANK1HINT;UkázaÅ¥ obrázky triedy 1 hviezda +FILEBROWSER_SHOWRANK2HINT;UkázaÅ¥ obrázky triedy 2 hviezda +FILEBROWSER_SHOWRANK3HINT;UkázaÅ¥ obrázky triedy 3 hviezda +FILEBROWSER_SHOWRANK4HINT;UkázaÅ¥ obrázky triedy 4 hviezda +FILEBROWSER_SHOWRANK5HINT;UkázaÅ¥ obrázky triedy 5 hviezda +FILEBROWSER_SHOWTRASHHINT;ZobraziÅ¥ obsah koÅ¡a +FILEBROWSER_SHOWUNRANKHINT;ZobraziÅ¥ obrázky bez triedy +FILEBROWSER_STARTPROCESSING;ZaÄaÅ¥ spracovanie +FILEBROWSER_STARTPROCESSINGHINT;ZaÄaÅ¥ spracovanie/ukladanie obrázkov v rade +FILEBROWSER_STOPPROCESSING;ZastaviÅ¥ spracovanie +FILEBROWSER_STOPPROCESSINGHINT;ZastaviÅ¥ spracovanie obrázkov +FILEBROWSER_THUMBSIZE;VeľkosÅ¥ zmenÅ¡enín +FILEBROWSER_ZOOMINHINT;ZväÄÅ¡iÅ¥ veľkosÅ¥ zmenÅ¡enín +FILEBROWSER_ZOOMOUTHINT;ZmenÅ¡iÅ¥ veľkosÅ¥ zmenÅ¡enín +GENERAL_ABOUT;O programe +GENERAL_CANCEL;ZruÅ¡iÅ¥ +GENERAL_DISABLE;ZakázaÅ¥ +GENERAL_DISABLED;Zakázané +GENERAL_ENABLE;PovoliÅ¥ +GENERAL_ENABLED;Povolené +GENERAL_LANDSCAPE;Krajina +GENERAL_LOAD;NaÄítaÅ¥ +GENERAL_NA;n/a +GENERAL_NO;Nie +GENERAL_OK;OK +GENERAL_PORTRAIT;Portrét +GENERAL_SAVE;UložiÅ¥ +GENERAL_YES;Ãno +HISTOGRAM_LABEL;Histogram +HISTOGRAM_TOOLTIP_B;ZobraziÅ¥/SchovaÅ¥ MODRà histogram +HISTOGRAM_TOOLTIP_G;ZobraziÅ¥/SchovaÅ¥ ZELENà histogram +HISTOGRAM_TOOLTIP_L;ZobraziÅ¥/SchovaÅ¥ histogram CIELAB svietivosti +HISTOGRAM_TOOLTIP_R;ZobraziÅ¥/SchovaÅ¥ ÄŒERVENà histogram +HISTORY_CHANGED;Zmenené +HISTORY_CUSTOMCURVE;Vlastná krivka +HISTORY_DELSNAPSHOT;OdstrániÅ¥ Snímok +HISTORY_FROMCLIPBOARD;Zo schránky +HISTORY_LABEL;História +HISTORY_MSG_10;Kompresia tieňov +HISTORY_MSG_11;Krivka tónov +HISTORY_MSG_12;Auto expozícia +HISTORY_MSG_13;Orezávanie expozície +HISTORY_MSG_14;Jas svietivosti +HISTORY_MSG_15;Kontrast svietivosti +HISTORY_MSG_16;ÄŒierna svietivosti +HISTORY_MSG_17;Kompresia najvyšších svetiel v oblasti svietivosti +HISTORY_MSG_18;Kompresia tieňov v oblasti svietivosti +HISTORY_MSG_19;Krivka svietivosti +HISTORY_MSG_1;Fotka naÄítaná +HISTORY_MSG_20;Doostrenie +HISTORY_MSG_21;Polomer doostrenia +HISTORY_MSG_22;Množstvo doostrenia +HISTORY_MSG_23;Prah doostrenia +HISTORY_MSG_24;DoostriÅ¥ len okraje +HISTORY_MSG_25;Polomer detekcie okrajov pri doostrení +HISTORY_MSG_26;Tolerancia okrajov pri doostrení +HISTORY_MSG_27;Kontrola svätožiary pri doostrení +HISTORY_MSG_28;Množstvo kontroly svätožiary +HISTORY_MSG_29;Doostrovacia metóda +HISTORY_MSG_2;Profil naÄítaný +HISTORY_MSG_30;Polomer dekonvolúcie +HISTORY_MSG_31;Množstvo dekonvolúcie +HISTORY_MSG_32;Tlmenie dekonvolúcie +HISTORY_MSG_33;Iterácie dekonvolúcie +HISTORY_MSG_34;Vyhnúť sa orezaniu farieb +HISTORY_MSG_35;ObmedzovaÄ sýtosti +HISTORY_MSG_36;Hranica sýtosti +HISTORY_MSG_37;Zosilnenie farieb +HISTORY_MSG_38;Metóda vyváženia bielej +HISTORY_MSG_39;Farebná teplota +HISTORY_MSG_3;Profil zmenený +HISTORY_MSG_40;Nádych vyváženia bielej +HISTORY_MSG_41;Farebný posun "A" +HISTORY_MSG_42;Farebný posun "B" +HISTORY_MSG_43;OdÅ¡umenie svietivosti +HISTORY_MSG_44;Polomer odÅ¡umenia svietivosti +HISTORY_MSG_45;Tolerancia okrajov odÅ¡umenia svietivosti +HISTORY_MSG_46;Farebné odÅ¡umenie +HISTORY_MSG_47;Polomer farebného odÅ¡umenia +HISTORY_MSG_48;Tolerancia okrajov farebného odÅ¡umenia +HISTORY_MSG_49;CitlivosÅ¥ na okraje pri farebnom odÅ¡umení +HISTORY_MSG_4;História prehliadania +HISTORY_MSG_50;Nástroj Tiene/Najvyššie svetlá +HISTORY_MSG_51;Zosilnenie najvyšších svetiel +HISTORY_MSG_52;Zosilnenie tieňov +HISTORY_MSG_53;Tonálna šírka najvyšších svetiel +HISTORY_MSG_54;Tonálna šírka tieňov +HISTORY_MSG_55;Miestny kontrast +HISTORY_MSG_56;Polomer Tiene/Najvyššie svetlá +HISTORY_MSG_57;Hrubé otoÄenie +HISTORY_MSG_58;Horizontálne preklápanie +HISTORY_MSG_59;Vertikálne preklápanie +HISTORY_MSG_5;Jas +HISTORY_MSG_60;OtoÄenie +HISTORY_MSG_61;OtoÄenie +HISTORY_MSG_62;Korekcia zakrivenia objektívu +HISTORY_MSG_63;Záložka vybraná +HISTORY_MSG_64;Orezanie fotky +HISTORY_MSG_65;Korekcia chromatickej aberácie +HISTORY_MSG_66;Obnova najvyšších svetiel +HISTORY_MSG_67;Množstvo obnovy najvyšších svetiel +HISTORY_MSG_68;Metóda obnovy najvyšších svetiel +HISTORY_MSG_69;Pracovný farebný priestor +HISTORY_MSG_6;Kontrast +HISTORY_MSG_70;Výstupný farebný priestor +HISTORY_MSG_71;Vstupný farebný priestor +HISTORY_MSG_72;Korekcia vignetácie +HISTORY_MSG_73;Mixér kanálov +HISTORY_MSG_74;ZmeniÅ¥ veľkosÅ¥ - Rozmer +HISTORY_MSG_75;ZmeniÅ¥ veľkosÅ¥ - Metóda +HISTORY_MSG_76;Exif Metadáta +HISTORY_MSG_77;IPTC Metadáta +HISTORY_MSG_7;ÄŒierna +HISTORY_MSG_8;Kompenzácia expozície +HISTORY_MSG_9;Kompresia najvyšších svetiel +HISTORY_NEWSNAPSHOT;Nový Snímok +HISTORY_NEWSNAPSHOTAS;Ako... +HISTORY_NEWSSDIALOGLABEL;Menovka snímku: +HISTORY_NEWSSDIALOGTITLE;PridaÅ¥ nový snímok +HISTORY_SETTO;NastaviÅ¥ na +HISTORY_SNAPSHOT;Snímok +HISTORY_SNAPSHOTS;Snímky +ICMPANEL_FILEDLGFILTERANY;VÅ¡etky súbory +ICMPANEL_FILEDLGFILTERICM;Súbory ICC profilu +ICMPANEL_GAMMABEFOREINPUT;Profil aplikuje Gamu +ICMPANEL_INPUTCAMERA;Predvolený aparátu +ICMPANEL_INPUTCUSTOM;Vlastný +ICMPANEL_INPUTDLGLABEL;VybraÅ¥ vstupný ICC profil... +ICMPANEL_INPUTEMBEDDED;PoužiÅ¥ vstavaný, ak je to možné +ICMPANEL_INPUTPROFILE;Vstupný profil +ICMPANEL_NOICM;Bez správy farieb: sRGB výstup +ICMPANEL_OUTPUTDLGLABEL;VybraÅ¥ výstupný ICC profil... +ICMPANEL_OUTPUTPROFILE;Výstupný profil +ICMPANEL_SAVEREFERENCE;UložiÅ¥ referenÄný obrázok pre tvorbu profilu +ICMPANEL_WORKINGPROFILE;Pracovný profil +IMAGEAREA_DETAILVIEW;Zobrazenie detailov +IPTCPANEL_AUTHOR;Autor +IPTCPANEL_AUTHORHINT;Meno tvorcu objektu, napr. pisateľa, fotografa alebo grafika (Meno autora). +IPTCPANEL_AUTHORSPOSITION;Autorov titul +IPTCPANEL_AUTHORSPOSITIONHINT;Titul tvorcu alebo tvorcov objektu (Titul pri mene autora). +IPTCPANEL_CAPTION;Titul +IPTCPANEL_CAPTIONHINT;Textový opis údajov (Titul - Abstrakt). +IPTCPANEL_CAPTIONWRITER;Pisateľ titulu +IPTCPANEL_CAPTIONWRITERHINT;Meno osoby, ktorá titul/abstrakt obrazu napísala, upravila alebo opravila (Pisateľ - Editor). +IPTCPANEL_CATEGORY;Kategória +IPTCPANEL_CATEGORYHINT;Identifikuje subjekt obrázka podľa názoru poskytovateľa (Kategória). +IPTCPANEL_CITY;Mesto +IPTCPANEL_CITYHINT;Mesto pôvodu (Mesto). +IPTCPANEL_COPYHINT;KopírovaÅ¥ IPTC nastavenia do schránky +IPTCPANEL_COPYRIGHT;Copyright +IPTCPANEL_COPYRIGHTHINT;Akýkoľvek potrebný oznam o copyrighte (Oznam o copyrighte). +IPTCPANEL_COUNTRY;Krajina +IPTCPANEL_COUNTRYHINT;Názov krajiny/miesta pôvodu (Krajina - miesto pôvodu). +IPTCPANEL_CREDIT;Kredit +IPTCPANEL_CREDITHINT;Identifikuje poskytovateľa obrázka, nemusí byÅ¥ nevyhnutne vlastníkom/tvorcom (Kredit). +IPTCPANEL_DATECREATED;Dátum vytvorenia +IPTCPANEL_DATECREATEDHINT;Dátum, kedy bol vytvorený intelektuálny obsah obrázka; Formát: RRRRMMDD (Deň vytvorenia). +IPTCPANEL_EMBEDDED;Vložené +IPTCPANEL_EMBEDDEDHINT;ResetovaÅ¥ na IPTV údaje vložené do obrázka +IPTCPANEL_HEADLINE;Nadpis +IPTCPANEL_HEADLINEHINT;Publikovateľný vstup poskytujúci zhrnutie obsahu obrázka (Nadpis). +IPTCPANEL_INSTRUCTIONS;Pokyny +IPTCPANEL_INSTRUCTIONSHINT;Iné pokyny ohľadne použitia obrázka (Å peciálne pokyny). +IPTCPANEL_KEYWORDS;KľúÄové slová +IPTCPANEL_KEYWORDSHINT;Používa sa na indikáciu kľúÄových slov. +IPTCPANEL_PASTEHINT;PrilepiÅ¥ IPTC nastavenia zo schránky +IPTCPANEL_PROVINCE;Provincia/Å¡tát +IPTCPANEL_PROVINCEHINT;Provincia/Å¡tát pôvodu obrázka (Provincia-Å¡tát). +IPTCPANEL_RESET;ResetovaÅ¥ +IPTCPANEL_RESETHINT;ResetovaÅ¥ na predvolené profilom +IPTCPANEL_SOURCE;Zdroj +IPTCPANEL_SOURCEHINT;Pôvodný vlastník intektuálneho obsahu obrázka (Zdroj). +IPTCPANEL_SUPPCATEGORIES;DodatoÄné kategórie +IPTCPANEL_SUPPCATEGORIESHINT;ÄŽalej upresňuje subjekt obrázka (DodatoÄné kategórie). +IPTCPANEL_TITLE;Názov +IPTCPANEL_TITLEHINT;Krátka referencia pre obrázok (Meno objektu). +IPTCPANEL_TRANSREFERENCE;Referencia prenosu +IPTCPANEL_TRANSREFERENCEHINT;Kód reprezentujúci miesto pôvodného prenosu (Pôvodná referencia prenosu). +MAIN_BUTTON_PREFERENCES;Predvoľby +MAIN_BUTTON_SAVE;UložiÅ¥ obrázok +MAIN_BUTTON_SAVEAS;Ako... +MAIN_BUTTON_SENDTOEDITOR;OdoslaÅ¥ do editora +MAIN_MSG_ALREADYEXISTS;Súbor už existuje. +MAIN_MSG_CANNOTLOAD;Nemôžem naÄítaÅ¥ obrázok +MAIN_MSG_CANNOTSAVE;Chyba pri ukladaní súboru +MAIN_MSG_CANNOTSTARTEDITOR;Nebolo možné spustiÅ¥ editor. +MAIN_MSG_CANNOTSTARTEDITOR_SECONDARY;Prosím, nastavte správnu cestu v dialógu "Predvoľby". +MAIN_MSG_EXITJOBSINQUEUEINFO;Nespracované obrázky v rade budú pri ukonÄení programu stratené. +MAIN_MSG_EXITJOBSINQUEUEQUEST;Ste si istí, že chcete ukonÄiÅ¥ program? V rade sú nespracované obrázky. +MAIN_MSG_JOBSINQUEUE;Úlohy v rade +MAIN_MSG_QOVERWRITE;Chcete ho prepísaÅ¥? +MAIN_TAB_BASIC;Základné +MAIN_TAB_COLOR;Farba +MAIN_TAB_DETAIL;Detail +MAIN_TAB_EXIF;Exif +MAIN_TAB_EXPOSURE;Expozícia +MAIN_TAB_ICM;ICM +MAIN_TAB_IPTC;IPTC +MAIN_TAB_METADATA;Metadáta +MAIN_TAB_TRANSFORM;Transformácie +MAIN_TOOLTIP_HIDEFP;ZobraziÅ¥/ukázaÅ¥ panel tlaÄidiel (prehliadaÄ adresárov a súborov, shortcut key: F) +MAIN_TOOLTIP_HIDEHP;ZobraziÅ¥/ukázaÅ¥ ľavý panel (vrátane histórie, shortcut key: H) +MAIN_TOOLTIP_INDCLIPPEDH;Indikácia orezania najvyšších svetiel +MAIN_TOOLTIP_INDCLIPPEDS;Indikácia orezania tieňov +MAIN_TOOLTIP_PREFERENCES;NastaviÅ¥ predvoľby +MAIN_TOOLTIP_QINFO;Rýchle informácie o obrázku +MAIN_TOOLTIP_SAVE;UložiÅ¥ obrázok do predvoleného adresára +MAIN_TOOLTIP_SAVEAS;UložiÅ¥ obrázok do vybraného adresára +PARTIALPASTE_BASICGROUP;Základné nastavenia +PARTIALPASTE_CACORRECTION;Korekcia C/A +PARTIALPASTE_COARSETRANS;90° otoÄenie/preklopenie +PARTIALPASTE_COLORBOOST;Zosilnenie farieb +PARTIALPASTE_COLORDENOISE;Farebné odÅ¡umenie +PARTIALPASTE_COLORGROUP;Nastavenia súvisiace s farbou +PARTIALPASTE_COLORMIXER;Mixér farieb +PARTIALPASTE_COLORSHIFT;Farebný posun +PARTIALPASTE_COMPOSITIONGROUP;Nastavenia kompozície +PARTIALPASTE_CROP;Orez +PARTIALPASTE_DIALOGLABEL;Profil spracovania ÄiastoÄného vloženia +PARTIALPASTE_DISTORTION;Korekcia skreslenia +PARTIALPASTE_EXIFCHANGES;Zmeny v EXIF údajochChanges to exif data +PARTIALPASTE_EXPOSURE;Expozícia +PARTIALPASTE_HLRECOVERY;Obnova najvyšších svetiel +PARTIALPASTE_ICMSETTINGS;Nastavenia ICM +PARTIALPASTE_IPTCINFO;IPTC informácie +PARTIALPASTE_LENSGROUP;Nastavenia súvisiace s objektívom +PARTIALPASTE_LUMACURVE;Krivka svietivosti +PARTIALPASTE_LUMADENOISE;Redukcia Å¡umu v oblasti svietivosti +PARTIALPASTE_LUMINANCEGROUP;Nastavenia súvisiace so svietivosÅ¥ou +PARTIALPASTE_METAICMGROUP;Nastavenia metadát/ICM +PARTIALPASTE_RESIZE;ZmeniÅ¥ veľkosÅ¥ +PARTIALPASTE_ROTATION;OtoÄenie +PARTIALPASTE_SHADOWSHIGHLIGHTS;Tiene/Najvyššie svetlá +PARTIALPASTE_SHARPENING;Doostrenie +PARTIALPASTE_VIGNETTING;Korekcia vignetácie +PARTIALPASTE_WHITEBALANCE;Vyváženie bielej +PREFERENCES_APPLNEXTSTARTUP;Aplikovaný pri ÄalÅ¡om spustení +PREFERENCES_BLINKCLIPPED;BlikaÅ¥ orezanými miestami +PREFERENCES_CACHECLEARALL;VyÄistiÅ¥ vÅ¡etko +PREFERENCES_CACHECLEARPROFILES;VyÄistiÅ¥ profily +PREFERENCES_CACHECLEARTHUMBS;VyÄistiÅ¥ zmenÅ¡eniny +PREFERENCES_CACHEFORMAT1;Vlastné (rýchlejÅ¡ie a kvalitnejÅ¡ie) +PREFERENCES_CACHEFORMAT2;JPEG (menÅ¡ia veľkosÅ¥ na disku) +PREFERENCES_CACHEMAXENTRIES;Maximálny poÄet vstupov v cache +PREFERENCES_CACHEOPTS;Možnosti cache +PREFERENCES_CACHESTRAT1;UprednostniÅ¥ rýchlosÅ¥ pred malou spotrebou pamäte +PREFERENCES_CACHESTRAT2;UprednostniÅ¥ malú spotrebu pamäte pred rýchlosÅ¥ou +PREFERENCES_CACHESTRAT;Stratégia použitia cache +PREFERENCES_CACHETHUMBFORM;Formát zmenÅ¡enín pre cache +PREFERENCES_CACHETHUMBHEIGHT;Maximálna výška zmenÅ¡enín +PREFERENCES_CLEARDLG_LINE1;ÄŒistím cache +PREFERENCES_CLEARDLG_LINE2;Môže to pár sekúnd trvaÅ¥. +PREFERENCES_CLEARDLG_TITLE;Prosím, Äakajte. +PREFERENCES_CLIPPINGIND;Indikácia orezu +PREFERENCES_CMETRICINTENT;Kolorimetrický zámer +PREFERENCES_DATEFORMAT;Formát dátumu +PREFERENCES_DATEFORMATHINT;Môžete použiÅ¥ nasledujúce formátovacie reÅ¥azce:\n%y : rok\n%m : mesiac\n%d : deň\n\nNapríklad, slovenský formát je:\n%d.%m.%y +PREFERENCES_DEFAULTLANG;Predvolený jazyk +PREFERENCES_DEFAULTTHEME;Predvolený vzhľad +PREFERENCES_DEMOSAICINGALGO;Demozaikovací algoritmus +PREFERENCES_DIRHOME;Domovský adresár +PREFERENCES_DIRLAST;Posledný navÅ¡tívený adresár +PREFERENCES_DIROTHER;Iný +PREFERENCES_DIRSELECTDLG;VybraÅ¥ adresár s obrázkami pri spustení... +PREFERENCES_DIRSOFTWARE;InÅ¡talaÄný adresár +PREFERENCES_DMETHOD;Metóda +PREFERENCES_EDITORCMDLINE;Iný príkazový riadok +PREFERENCES_EXTERNALEDITOR;Externý editor +PREFERENCES_FALSECOLOR;Kroky potlaÄenia chybných farieb +PREFERENCES_FBROWSEROPTS;Voľby prehliadaÄa súborov +PREFERENCES_FILEFORMAT;Formát súborov +PREFERENCES_FORIMAGE;Pre obrazové súbory +PREFERENCES_FORRAW;Pre RAW súbory +PREFERENCES_GIMPPATH;InÅ¡talaÄný adresár GIMPu +PREFERENCES_GTKTHEME;GTK predvolený +PREFERENCES_HINT;Tip +PREFERENCES_HLTHRESHOLD;Prah pre orezanie najvyšších svetiel +PREFERENCES_ICCDIR;Adresár s ICC profilmy +PREFERENCES_IMPROCPARAMS;Predvolené parametre spracovania obrazu +PREFERENCES_INTENT_ABSOLUTE;Absolútny kolorimetrický +PREFERENCES_INTENT_PERCEPTUAL;Vnímaný +PREFERENCES_INTENT_RELATIVE;Relatívny kolorimetrický +PREFERENCES_INTENT_SATURATION;SýtosÅ¥ +PREFERENCES_LIVETHUMBNAILS;Živé zmenÅ¡eniny (pomalÅ¡ie) +PREFERENCES_MONITORICC;Profil monitora +PREFERENCES_OUTDIR;Výstupný adresár +PREFERENCES_OUTDIRFOLDER;UložiÅ¥ do adresára +PREFERENCES_OUTDIRFOLDERHINT;UložiÅ¥ obrázky do vybraného adresára +PREFERENCES_OUTDIRHINT;Môžete použiÅ¥ nasledujúce formátovacie reÅ¥azce:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nTieto formátovacie reÅ¥azce odkazujú na adresáre a Äasti cesty k raw súboru.\n\nNapríklad, ak bol /home/tom/image/02-09-2006/dsc0012.nefotvorený, význam formátovacích reÅ¥azcov je:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nAk chcete uložiÅ¥ výstupný obraz tam, kde je originál, napíšte:\n%p1/%f\n\nAk chcete uložiÅ¥ výstupný obraz v adresári 'converted' nachádzajúcom sa v adresári s originálom, napíšte:\n%p1/converted/%f\n\nAk chcete uložiÅ¥ výstupný obraz v adresári '/home/tom/converted' pri zachovaní toho istého podadresára s dátumami, napíšte:\n%p2/converted/%d1/%f +PREFERENCES_OUTDIRTEMPLATE;PoužiÅ¥ Å¡ablónu +PREFERENCES_OUTDIRTEMPLATEHINT;Môžete použiÅ¥ nasledujúce formátovacie reÅ¥azce:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nTieto formátovacie reÅ¥azce odkazujú na adresáre a Äasti cesty k raw súboru.\n\nNapríklad, ak bol /home/tom/image/02-09-2006/dsc0012.nefotvorený, význam formátovacích reÅ¥azcov je:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nIf you want to save the output image where the original is, write:\n%p1/%f\n\nIf you want to save the output image in a directory 'converted' located the directory of the original, write:\n%p1/converted/%f\n\nAk chcete uložiÅ¥ výstupný obraz tam, kde je originál, napíšte:\n%p1/%f\n\nAk chcete uložiÅ¥ výstupný obraz v adresári 'converted' nachádzajúcom sa v adresári s originálom, napíšte:\n%p1/converted/%f\n\nAk chcete uložiÅ¥ výstupný obraz v adresári '/home/tom/converted' pri zachovaní toho istého podadresára s dátumami, napíšte:\n%p2/converted/%d1/%f +PREFERENCES_PARSEDEXT;Spracúvané prípony +PREFERENCES_PARSEDEXTADD;PridaÅ¥ príponu +PREFERENCES_PARSEDEXTADDHINT;Napíšte príponu a stlaÄte tento gombík pre pripojenie k zoznamu +PREFERENCES_PARSEDEXTDELHINT;OdstrániÅ¥ vybranú príponu zo zoznamu +PREFERENCES_PROFILEHANDLING;Zaobchádzanie s profilom spracovania +PREFERENCES_PROFILELOADPR;Priorita naÄítavania profilu +PREFERENCES_PROFILEPRCACHE;Profil v cache +PREFERENCES_PROFILEPRFILE;Profil pri vstupnom súbore +PREFERENCES_PROFILESAVECACHE;UložiÅ¥ parametre spracovania do cache +PREFERENCES_PROFILESAVEINPUT;UložiÅ¥ parametre spracovania k vstupnému súboru +PREFERENCES_PSPATH;InÅ¡talaÄný adresár Adobe Photoshop +PREFERENCES_SELECTICCDIRDLG;VybraÅ¥ adresár s ICC profilmi... +PREFERENCES_SELECTLANG;VybraÅ¥ si jazyk +PREFERENCES_SELECTMONITORPROFDLG;VybraÅ¥ ICC profil monitora... +PREFERENCES_SELECTTHEME;VybraÅ¥ vzhľad +PREFERENCES_SHOWBASICEXIF;ZobrazovaÅ¥ základné EXIF informácie +PREFERENCES_SHOWDATETIME;UkázovaÅ¥ dátum a Äas +PREFERENCES_SHOWONLYRAW;UkazovaÅ¥ len RAW súbory +PREFERENCES_SHTHRESHOLD;Prah pre orezané tiene +PREFERENCES_STARTUPIMDIR;Adresár s obrázkami pri spustení +PREFERENCES_TAB_BROWSER;PrehliadaÄ súborov +PREFERENCES_TAB_COLORMGR;Správa farieb +PREFERENCES_TAB_GENERAL;VÅ¡eobecné +PREFERENCES_TAB_IMPROC;Spracovanie obrazu +PREFERENCES_TAB_OUTPUT;Výstupné možnosti +PREFERENCES_THUMBSIZE;VeľkosÅ¥ zmenÅ¡eniny +PROFILEPANEL_FILEDLGFILTERANY;VÅ¡etky súbory +PROFILEPANEL_FILEDLGFILTERPP;Profily spracovania +PROFILEPANEL_LABEL;Profily spracovania +PROFILEPANEL_LOADDLGLABEL;NaÄítaÅ¥ parametre spracovania... +PROFILEPANEL_PCUSTOM;Vlastné +PROFILEPANEL_PFILE;Zo súboru +PROFILEPANEL_PLASTPHOTO;Posledná fotka +PROFILEPANEL_PLASTSAVED;Posledné uložené +PROFILEPANEL_PROFILE;Profil +PROFILEPANEL_SAVEDLGLABEL;UložiÅ¥ parametre spracovania... +PROFILEPANEL_TOOLTIPCOPY;KopírovaÅ¥ súÄasný profil do schránky +PROFILEPANEL_TOOLTIPLOAD;NaÄítaÅ¥ profil zo súboru +PROFILEPANEL_TOOLTIPPASTE;VložiÅ¥ profil zo schránky +PROFILEPANEL_TOOLTIPSAVE;UložiÅ¥ súÄasný profil +PROGRESSBAR_DECODING;Dekódujem raw súbor... +PROGRESSBAR_DEMOSAICING;Demozaikujem... +PROGRESSBAR_LOADING;NaÄítavam obrázok... +PROGRESSBAR_LOADJPEG;Ukladám JPEG súbor... +PROGRESSBAR_LOADPNG;Ukladám PNG súbor... +PROGRESSBAR_LOADTIFF;Ukladám TIFF súbor... +PROGRESSBAR_PROCESSING;Spracúvam obrázok... +PROGRESSBAR_READY;Pripravený. +PROGRESSBAR_SAVEJPEG;Ukladám JPEG súbor... +PROGRESSBAR_SAVEPNG;Ukladám PNG súbor... +PROGRESSBAR_SAVETIFF;Ukladám TIFF súbor... +PROGRESSDLG_LOADING;NaÄítava sa súbor... +PROGRESSDLG_PROCESSING;Spracúva sa obrázok... +PROGRESSDLG_SAVING;Ukladá sa súbor... +QINFO_FOCALLENGTH;Ohnisková vzdialenosÅ¥ +QINFO_ISO;ISO +QINFO_LENS;Objektív +QINFO_NOEXIF;Exif údaje sú nedostupné. +SAVEDLG_FILEFORMAT;Formát súboru +SAVEDLG_JPEGQUAL;JPEG Kvalita +SAVEDLG_JPGFILTER;JPEG súbory +SAVEDLG_PNGCOMPR;PNG Kompresia +SAVEDLG_PNGFILTER;PNG súbory +SAVEDLG_PUTTOQUEUE;VložiÅ¥ do radu na spracovanie +SAVEDLG_PUTTOQUEUEHEAD;Put to the head of the processing queue +SAVEDLG_PUTTOQUEUETAIL;Put to the end of the processing queue +SAVEDLG_SAVEIMMEDIATELY;UložiÅ¥ okamžite +SAVEDLG_SAVESPP;UložiÅ¥ parametre spracovania s obrázkom +SAVEDLG_TIFFFILTER;TIFF súbory +TOOLBAR_TOOLTIP_CROP;Orezanie výberu (shortcut key: C) +TOOLBAR_TOOLTIP_HAND;Nástroj ruka (shortcut key: N) +TOOLBAR_TOOLTIP_STRAIGHTEN;Výber rovnej Äiary (shortcut key: S) +TOOLBAR_TOOLTIP_WB;Bodové vyváženie bielej (shortcut key: W) +TP_CACORRECTION_BLUE;Modrá +TP_CACORRECTION_LABEL;Korekcia chromatickej aberácie +TP_CACORRECTION_RED;ÄŒervená +TP_CHMIXER_BLUE;Modrá +TP_CHMIXER_GREEN;Zelená +TP_CHMIXER_LABEL;Mixér kanálov +TP_CHMIXER_RED;ÄŒervená +TP_COARSETRAF_DEGREE;stupeň: +TP_COARSETRAF_TOOLTIP_HFLIP;PrevrátiÅ¥ horizontálne +TP_COARSETRAF_TOOLTIP_ROTLEFT;OtoÄiÅ¥ doľava +TP_COARSETRAF_TOOLTIP_ROTRIGHT;OtoÄiÅ¥ doprava +TP_COARSETRAF_TOOLTIP_VFLIP;PrevrátiÅ¥ vertikálne +TP_COLORBOOST_ACHANNEL;kanál "a" +TP_COLORBOOST_AMOUNT;Množstvo +TP_COLORBOOST_AVOIDCOLORCLIP;Vyhnúť sa orezaniu farieb +TP_COLORBOOST_BCHANNEL;kanál "b" +TP_COLORBOOST_CHAB;a & b +TP_COLORBOOST_CHANNEL;Kanál +TP_COLORBOOST_CHSEPARATE;oddelené +TP_COLORBOOST_ENABLESATLIMITER;PovoliÅ¥ obmedzovaÅ¥ sýtosti +TP_COLORBOOST_LABEL;Zosilnenie farieb +TP_COLORBOOST_SATLIMIT;Hranica sýtosti +TP_COLORDENOISE_EDGESENSITIVE;Citlivá na okraje +TP_COLORDENOISE_EDGETOLERANCE;Tolerancia okrajov +TP_COLORDENOISE_LABEL;Redukcia farebného Å¡umu +TP_COLORDENOISE_RADIUS;Polomer +TP_COLORSHIFT_BLUEYELLOW;Modrá-žltá +TP_COLORSHIFT_GREENMAGENTA;Zelená-fialová +TP_COLORSHIFT_LABEL;Farebný posun +TP_CROP_DPI;DPI= +TP_CROP_FIXRATIO;Pevný pomer: +TP_CROP_GTDIAGONALS;Pravidlo diagonál +TP_CROP_GTHARMMEANS1;Harmonický priemer 1 +TP_CROP_GTHARMMEANS2;Harmonický priemer 2 +TP_CROP_GTHARMMEANS3;Harmonický priemer 3 +TP_CROP_GTHARMMEANS4;Harmonický priemer 4 +TP_CROP_GTNONE;Žiadne +TP_CROP_GTRULETHIRDS;Pravidlo tretín +TP_CROP_GUIDETYPE;Type vodidiel: +TP_CROP_H;V +TP_CROP_LABEL;Orezanie +TP_CROP_SELECTCROP; Vyberte Orez +TP_CROP_W;Å  +TP_CROP_X;x +TP_CROP_Y;y +TP_DISTORTION_AMOUNT;Množstvo +TP_DISTORTION_LABEL;Zakrivenie +TP_EXPOSURE_AUTOLEVELS;Auto úrovne +TP_EXPOSURE_BLACKLEVEL;ÄŒierna +TP_EXPOSURE_BRIGHTNESS;Jas +TP_EXPOSURE_CLIP;OrezaÅ¥ +TP_EXPOSURE_COMPRHIGHLIGHTS;Kompresia najvyšších svetiel +TP_EXPOSURE_COMPRSHADOWS;Kompresia tieňov +TP_EXPOSURE_CONTRAST;Kontrast +TP_EXPOSURE_CURVEEDITOR;Krivka tónov +TP_EXPOSURE_EXPCOMP;Kompenzácia expozície +TP_EXPOSURE_LABEL;Expozícia +TP_HLREC_CIELAB;CIELab Blending +TP_HLREC_COLOR;Šírenie farieb +TP_HLREC_LABEL;Obnova najvyšších svetiel +TP_HLREC_LUMINANCE;Obnova svietivosti +TP_HLREC_METHOD;Metóda: +TP_ICM_FILEDLGFILTERANY;VÅ¡etky súbory +TP_ICM_FILEDLGFILTERICM;Súbory ICC profilu +TP_ICM_GAMMABEFOREINPUT;Profil aplikuje Gamu +TP_ICM_INPUTCAMERA;Predvolený aparátu +TP_ICM_INPUTCUSTOM;Vlastný +TP_ICM_INPUTDLGLABEL;VybraÅ¥ vstupný ICC profil... +TP_ICM_INPUTEMBEDDED;PoužiÅ¥ vstavaný, ak je to možné +TP_ICM_INPUTPROFILE;Vstupný profil +TP_ICM_LABEL;ICM +TP_ICM_NOICM;Bez správy farieb: sRGB výstup +TP_ICM_OUTPUTDLGLABEL;VybraÅ¥ výstupný ICC profil... +TP_ICM_OUTPUTPROFILE;Výstupný profil +TP_ICM_SAVEREFERENCE;UložiÅ¥ referenÄný obrázok pre tvorbu profilu +TP_ICM_WORKINGPROFILE;Pracovný profil +TP_LUMACURVE_BLACKLEVEL;ÄŒierna +TP_LUMACURVE_BRIGHTNESS;Jas +TP_LUMACURVE_COMPRHIGHLIGHTS;Kompresia najvyšších svetiel +TP_LUMACURVE_COMPRSHADOWS;Kompresia tieňov +TP_LUMACURVE_CONTRAST;Kontrast +TP_LUMACURVE_CURVEEDITOR;Krivka svietivosti +TP_LUMACURVE_LABEL;Krivka svietivosti +TP_LUMADENOISE_EDGETOLERANCE;Tolerancia okrajov +TP_LUMADENOISE_LABEL;Redukcia Å¡umu v oblasti svietivosti +TP_LUMADENOISE_RADIUS;Polomer +TP_RESIZE_BICUBIC;Bikubická +TP_RESIZE_BICUBICSF;Bikubická (MäkÅ¡ia) +TP_RESIZE_BICUBICSH;Bikubická (OstrejÅ¡ia) +TP_RESIZE_BILINEAR;Bilineárna +TP_RESIZE_FULLSIZE;Celá veľkosÅ¥ obrázka: +TP_RESIZE_H;V: +TP_RESIZE_LABEL;ZmeniÅ¥ veľkosÅ¥ +TP_RESIZE_METHOD;Metóda: +TP_RESIZE_NEAREST;Najbližšie +TP_RESIZE_SCALE;Rozmer +TP_RESIZE_W;Å : +TP_ROTATE_AUTOCROP;Automatické orezanie +TP_ROTATE_DEGREE;Stupeň +TP_ROTATE_FILL;Výplň +TP_ROTATE_LABEL;OtoÄiÅ¥ +TP_ROTATE_SELECTLINE;VybraÅ¥ rovnú Äiaru +TP_SHADOWSHLIGHTS_HIGHLIGHTS;Najvyššie svetlá +TP_SHADOWSHLIGHTS_HLTONALW;Tonálna šírka +TP_SHADOWSHLIGHTS_LABEL;Tiene/Najvyššie svetlá +TP_SHADOWSHLIGHTS_LOCALCONTR;Miestny kontrast +TP_SHADOWSHLIGHTS_RADIUS;Polomer +TP_SHADOWSHLIGHTS_SHADOWS;Tiene +TP_SHADOWSHLIGHTS_SHTONALW;Tonálna šírka +TP_SHARPENING_AMOUNT;Množstvo +TP_SHARPENING_EDRADIUS;Polomer +TP_SHARPENING_EDTOLERANCE;Tolerancia okrajov +TP_SHARPENING_HALOCONTROL;Kontrola svätožiary +TP_SHARPENING_HCAMOUNT;Množstvo +TP_SHARPENING_LABEL;Doostrenie +TP_SHARPENING_METHOD;Metóda +TP_SHARPENING_ONLYEDGES;DoostriÅ¥ len okraje +TP_SHARPENING_RADIUS;Polomer +TP_SHARPENING_RLD;RL Dekonvolúcia +TP_SHARPENING_RLD_AMOUNT;Množstvo +TP_SHARPENING_RLD_DAMPING;Tlmenie +TP_SHARPENING_RLD_ITERATIONS;Iterácie +TP_SHARPENING_THRESHOLD;Prah +TP_SHARPENING_USM;Unsharp Mask +TP_VIGNETTING_AMOUNT;Množstvo +TP_VIGNETTING_LABEL;Korekcia vignetácie +TP_VIGNETTING_RADIUS;Polomer +TP_WBALANCE_AUTO;Automatické +TP_WBALANCE_CAMERA;Fotoaparát +TP_WBALANCE_CUSTOM;Vlastné +TP_WBALANCE_GREEN;Nádych +TP_WBALANCE_LABEL;Vyváženie bielej +TP_WBALANCE_METHOD;Metóda +TP_WBALANCE_SIZE;VeľkosÅ¥: +TP_WBALANCE_SPOTWB;Bodové VB +TP_WBALANCE_TEMPERATURE;Teplota +ZOOMBAR_DETAIL;Detail +ZOOMBAR_HUGE;Obrovský +ZOOMBAR_LARGE;Veľký +ZOOMBAR_NORMAL;Normálny +ZOOMBAR_PREVIEW;Náhľad +ZOOMBAR_SCALE;Rozmer +ZOOMBAR_SMALL;Malý diff --git a/release/languages/suomi b/release/languages/suomi new file mode 100755 index 000000000..b97257eb6 --- /dev/null +++ b/release/languages/suomi @@ -0,0 +1,576 @@ +# Finnish language file for Raw Therapee v2.4m1 (www.rawtherapee.com) +# Compiled by T.Kauppinen 31.7.2008 +ADJUSTER_RESET_TO_DEFAULT;Palauta oletusasetukset +CURVEEDITOR_FILEDLGFILTERANY;Kaikki tiedostot +CURVEEDITOR_FILEDLGFILTERCURVE;Käyrä tiedostot +CURVEEDITOR_LINEAR;Suora +CURVEEDITOR_LOADDLGLABEL;Lataa käyrä... +CURVEEDITOR_SAVEDLGLABEL;Tallenna käyrä... +CURVEEDITOR_TOOLTIPLINEAR;Palauta suoraksi +CURVEEDITOR_TOOLTIPLOAD;Lataa käyrä tiedostosta +CURVEEDITOR_TOOLTIPSAVE;Tallenna käyrä +EXIFFILTER_APERTURE;Aperture +EXIFFILTER_CAMERA;Camera +EXIFFILTER_DIALOGLABEL;Exif Filter +EXIFFILTER_FOCALLEN;Focal Length +EXIFFILTER_ISO;ISO +EXIFFILTER_LENS;Lens +EXIFFILTER_SHUTTER;Shutter +EXIFPANEL_ADDEDIT;Lisää/Muokkaa +EXIFPANEL_ADDEDITHINT;Lisää uusi tai muokkaa +EXIFPANEL_ADDTAGDLG_ENTERVALUE; +EXIFPANEL_ADDTAGDLG_SELECTTAG;Valitse +EXIFPANEL_ADDTAGDLG_TITLE;Lisää/Muokkaa +EXIFPANEL_KEEP;Pidä +EXIFPANEL_KEEPHINT;Pidä valitut tallennettaessa +EXIFPANEL_REMOVE;Poista +EXIFPANEL_REMOVEHINT;Poista valitut tallennettaessa +EXIFPANEL_RESET;Palauta +EXIFPANEL_RESETALL;Palauta kaikki +EXIFPANEL_RESETALLHINT;Palauta kaikki alkuperäisiksi +EXIFPANEL_RESETHINT;Palauta valitut alkuperäisiksi +EXIFPANEL_SUBDIRECTORY;Alihakemisto +FILEBROWSER_APPLYPROFILE;Apply profile +FILEBROWSER_ARRANGEMENTHINT;Change between vertical/horizontal alignment of thumbnails +FILEBROWSER_CLEARPROFILE;Clear profile +FILEBROWSER_COPYPROFILE;Copy profile +FILEBROWSER_DELETEDLGLABEL;File delete confirmation +FILEBROWSER_DELETEDLGMSG;Are you sure you want to delete the selected %1 files? +FILEBROWSER_EMPTYTRASH;Empty Trash +FILEBROWSER_EMPTYTRASHHINT;Permanently delete the files of the trash +FILEBROWSER_EXIFFILTERAPPLY;Apply +FILEBROWSER_EXIFFILTERAPPLYHINT;Switch on/off exif filter of the file browser +FILEBROWSER_EXIFFILTERLABEL;Exif Filter +FILEBROWSER_EXIFFILTERSETTINGS;Setup +FILEBROWSER_EXIFFILTERSETTINGSHINT;Change settings of the exif filter +FILEBROWSER_PARTIALPASTEPROFILE;Partial paste +FILEBROWSER_PASTEPROFILE;Paste profile +FILEBROWSER_POPUPCANCELJOB;Cancel job +FILEBROWSER_POPUPMOVEEND;Move to end of queue +FILEBROWSER_POPUPMOVEHEAD;Move to head of queue +FILEBROWSER_POPUPOPEN;Open +FILEBROWSER_POPUPPROCESS;Put to processing queue +FILEBROWSER_POPUPRANK1;Rank 1 +FILEBROWSER_POPUPRANK2;Rank 2 +FILEBROWSER_POPUPRANK3;Rank 3 +FILEBROWSER_POPUPRANK4;Rank 4 +FILEBROWSER_POPUPRANK5;Rank 5 +FILEBROWSER_POPUPREMOVE;Remove from filesystem +FILEBROWSER_POPUPRENAME;Rename +FILEBROWSER_POPUPSELECTALL;Select all +FILEBROWSER_POPUPTRASH;Move to trash +FILEBROWSER_POPUPUNRANK;Unrank +FILEBROWSER_POPUPUNTRASH;Remove from trash +FILEBROWSER_PROCESSINGSETTINGS;Settings +FILEBROWSER_PROCESSINGSETTINGSHINT;Set the file format and output directory +FILEBROWSER_RENAMEDLGLABEL;Rename file +FILEBROWSER_RENAMEDLGMSG;Rename file "%1" to: +FILEBROWSER_SHOWDIRHINT;Show all images of the directory +FILEBROWSER_SHOWQUEUEHINT;Show content of the processing queue +FILEBROWSER_SHOWRANK1HINT;Show images ranked as 1 star +FILEBROWSER_SHOWRANK2HINT;Show images ranked as 2 star +FILEBROWSER_SHOWRANK3HINT;Show images ranked as 3 star +FILEBROWSER_SHOWRANK4HINT;Show images ranked as 4 star +FILEBROWSER_SHOWRANK5HINT;Show images ranked as 5 star +FILEBROWSER_SHOWTRASHHINT;Show content of the trash +FILEBROWSER_SHOWUNRANKHINT;Show unranked images +FILEBROWSER_STARTPROCESSING;Start Processing +FILEBROWSER_STARTPROCESSINGHINT;Start processing/saving of images in the queue +FILEBROWSER_STOPPROCESSING;Stop processing +FILEBROWSER_STOPPROCESSINGHINT;Stop processing of images +FILEBROWSER_THUMBSIZE;Thumb. size +FILEBROWSER_ZOOMINHINT;Increase thumbnail size +FILEBROWSER_ZOOMOUTHINT;Decrease thumbnail size +GENERAL_ABOUT;Tietoja +GENERAL_CANCEL;Peruuta +GENERAL_DISABLE;Pois +GENERAL_DISABLED;Pois +GENERAL_ENABLE;Päälle +GENERAL_ENABLED;Päällä +GENERAL_LANDSCAPE;Vaaka +GENERAL_LOAD;Lataa +GENERAL_NA;- +GENERAL_NO;Ei +GENERAL_OK;OK +GENERAL_PORTRAIT;Pysty +GENERAL_SAVE;Tallenna +GENERAL_YES;Kyllä +HISTOGRAM_LABEL;Histogram +HISTOGRAM_TOOLTIP_B;Näytä/piilota SININEN +HISTOGRAM_TOOLTIP_G;Näytä/piilota VIHREÄ +HISTOGRAM_TOOLTIP_L;Näytä/piilota CIELAB luminanssi +HISTOGRAM_TOOLTIP_R;Näytä/piilota PUNAINEN +HISTORY_CHANGED;Muutettu +HISTORY_CUSTOMCURVE;Oma käyrä +HISTORY_DELSNAPSHOT;Poista pikakuva +HISTORY_FROMCLIPBOARD;From clipboard +HISTORY_LABEL;Historia +HISTORY_MSG_10;Valotus\nTummien alueiden vaimennus +HISTORY_MSG_11;Valotus\nSävykäyrä +HISTORY_MSG_12;Valotus\nAutomaattinen +HISTORY_MSG_13;Valotus\nAutomaattisen valotuksen raja +HISTORY_MSG_14;Luminanssi\nKirkkaus +HISTORY_MSG_15;Luminanssi\nKontrasti +HISTORY_MSG_16;Luminanssi\nTummuus +HISTORY_MSG_17;Luminanssi\nVaaleiden alueiden vaimennus +HISTORY_MSG_18;Luminanssi\nTummien alueiden vaimennus +HISTORY_MSG_19;Luminanssi\nKäyrä +HISTORY_MSG_1;Kuva ladattu +HISTORY_MSG_20;Terävöinti +HISTORY_MSG_21;Terävöinti\nEpäterävä maski: Säde +HISTORY_MSG_22;Terävöinti\nEpäterävä maski: Määrä +HISTORY_MSG_23;Terävöinti\nEpäterävä maski: Kynnys +HISTORY_MSG_24;Terävöinti\nEpäterävä maski: Vain reunat +HISTORY_MSG_25;Terävöinti\nEpäterävä maski: Reunatunnistuksen säde +HISTORY_MSG_26;Terävöinti\nEpäterävä maski: Reunatunnistuksen herkkyys +HISTORY_MSG_27;Terävöinti\nEpäterävä maski: Halo-ilmiön esto +HISTORY_MSG_28;Terävöinti\nEpäterävä maski: Halo-ilmiön eston määrä +HISTORY_MSG_29;Terävöinti\nMenetelmä +HISTORY_MSG_2;Profiili ladattu +HISTORY_MSG_30;Terävöinti\nDekonvoluutio: Säde +HISTORY_MSG_31;Terävöinti\nDekonvoluutio: Määrä +HISTORY_MSG_32;Terävöinti\nDekonvoluutio: Vaimennus +HISTORY_MSG_33;Terävöinti\nDekonvoluutio: Iteraatiot +HISTORY_MSG_34;Värikylläisyys\nVältä leikkautuminen +HISTORY_MSG_35;Värikylläisyys\nEstä kyllästyminen +HISTORY_MSG_36;Värikylläisyys\nKyllästymisraja +HISTORY_MSG_37;Värikylläisyys +HISTORY_MSG_38;Valkotasapaino\nMenetelmä +HISTORY_MSG_39;Valkotasapaino\nVärilämpötila +HISTORY_MSG_3;Profiili vaihdettu +HISTORY_MSG_40;Valkotasapaino\nValkoisen sävy +HISTORY_MSG_41;Värisävy\nvihreä-punainen +HISTORY_MSG_42;Värisävy\nsininen-keltainen +HISTORY_MSG_43;Luminanssin kohinanvaimennus +HISTORY_MSG_44;Luminanssin kohinanvaimennus\nSäde +HISTORY_MSG_45;Luminanssin kohinanvaimennus\nReunan tunnistusherkkyys +HISTORY_MSG_46;Värin kohinanvaimennus +HISTORY_MSG_47;Värin kohinanvaimennus\nSäde +HISTORY_MSG_48;Värin kohinanvaimennus\nReunan tunnistusherkkyys +HISTORY_MSG_49;Värin kohinanvaimennus\nReunaherkkä +HISTORY_MSG_4;Historian selaus +HISTORY_MSG_50;Tummat/vaaleat alueet +HISTORY_MSG_51;Tummat/vaaleat alueet\nVaaleiden alueiden vaimennus +HISTORY_MSG_52;Tummat/vaaleat alueet\nTummien alueiden vaimennus +HISTORY_MSG_53;Tummat/vaaleat alueet\nVaalean sävyalueen leveys +HISTORY_MSG_54;Tummat/vaaleat alueet\nTumman sävyalueen leveys +HISTORY_MSG_55;Tummat/vaaleat alueet\nPaikallinen kontrasti +HISTORY_MSG_56;Tummat/vaaleat alueet\nSäde +HISTORY_MSG_57;Kääntö +HISTORY_MSG_58;Peilaa vaakasuunnassa +HISTORY_MSG_59;Peilaa pystysuunnassa +HISTORY_MSG_5;Valotus\nKirkkaus +HISTORY_MSG_60;Kääntö +HISTORY_MSG_61;Kääntö +HISTORY_MSG_62;Linssivääristymän korjaus +HISTORY_MSG_63;Pikakuva valittu +HISTORY_MSG_64;Rajaus +HISTORY_MSG_65;Värivääristymän korjaus +HISTORY_MSG_66;Huippuvaloalueiden palautus +HISTORY_MSG_67;Huippuvaloalueiden palautus\nMäärä +HISTORY_MSG_68;Huippuvaloalueiden palautus\nMenetelmä +HISTORY_MSG_69;Työväriprofiili +HISTORY_MSG_6;Valotus\nKontrasti +HISTORY_MSG_70;Tulosväriprofiili +HISTORY_MSG_71;Lähdeväriprofiili +HISTORY_MSG_72;Vinjetoinnin korjaus +HISTORY_MSG_73;Kanavat +HISTORY_MSG_74;Koko +HISTORY_MSG_75;Koko\nMenetelmä +HISTORY_MSG_76;Exif-tiedot +HISTORY_MSG_77;IPTC-tiedot +HISTORY_MSG_7;Valotus\nTummuus +HISTORY_MSG_8;Valotus\nKompensointi +HISTORY_MSG_9;Valotus\nVaaleiden alueiden vaimennus +HISTORY_NEWSNAPSHOT;Uusi pikakuva +HISTORY_NEWSNAPSHOTAS;... +HISTORY_NEWSSDIALOGLABEL;Pikakuvan nimi: +HISTORY_NEWSSDIALOGTITLE;Lisää uusi pikakuva +HISTORY_SETTO;Aseta +HISTORY_SNAPSHOT;Pikakuva +HISTORY_SNAPSHOTS;Pikakuvat +ICMPANEL_FILEDLGFILTERANY;kaikki tiedostot +ICMPANEL_FILEDLGFILTERICM;ICC-profiilitiedostot +ICMPANEL_GAMMABEFOREINPUT;Käytä profiilin gammaa +ICMPANEL_INPUTCAMERA;Kameran oletus +ICMPANEL_INPUTCUSTOM;Oma +ICMPANEL_INPUTDLGLABEL;Valitse lähteen ICC-profiili... +ICMPANEL_INPUTEMBEDDED;Käytä kuvan omaa, jos mahdollista +ICMPANEL_INPUTPROFILE;Lähdeväriprofiili +ICMPANEL_NOICM;Ei ICM-profiilia: sRGB +ICMPANEL_OUTPUTDLGLABEL;Valitse tuloksen ICC-profiili... +ICMPANEL_OUTPUTPROFILE;Tulosväriprofiili +ICMPANEL_SAVEREFERENCE;Tallenna mallikuva\nprofilointia varten +ICMPANEL_WORKINGPROFILE;Työväriprofiili +IMAGEAREA_DETAILVIEW;Suurennos +IPTCPANEL_AUTHOR;Kuvaaja +IPTCPANEL_AUTHORHINT;(Author) Kuvaajan nimi. +IPTCPANEL_AUTHORSPOSITION;Kuvaajan titteli +IPTCPANEL_AUTHORSPOSITIONHINT;(Author position) Kuvaajan titteli. +IPTCPANEL_CAPTION;Aihe +IPTCPANEL_CAPTIONHINT;(Caption) Kuvaus kohteesta. +IPTCPANEL_CAPTIONWRITER;Kuvauksen kirjoittaja +IPTCPANEL_CAPTIONWRITERHINT;(Caption Writer) Kuvauksen kirjoittajan nimi. +IPTCPANEL_CATEGORY;Aiheryhmä +IPTCPANEL_CATEGORYHINT;(Category) Aiheryhmän 3-kirjaiminen koodi. +IPTCPANEL_CITY;Kaupunki +IPTCPANEL_CITYHINT;(City) Kaupunki jossa kuva on otettu. +IPTCPANEL_COPYHINT;Kopioi IPTC asetukset leikepöydälle +IPTCPANEL_COPYRIGHT;Tekijänoikeudet +IPTCPANEL_COPYRIGHTHINT;(Copyright) Tekijänoikeustiedot. +IPTCPANEL_COUNTRY;Maa +IPTCPANEL_COUNTRYHINT;(Country) Maa jossa kuva on otettu. +IPTCPANEL_CREDIT;Välittäjä +IPTCPANEL_CREDITHINT;(Credit) Välittäjän tiedot. +IPTCPANEL_DATECREATED;Päivämäärä +IPTCPANEL_DATECREATEDHINT;(Date Created) Päivämäärä jolloin kuva on otettu. +IPTCPANEL_EMBEDDED;Kuvan oma +IPTCPANEL_EMBEDDEDHINT;Palauta kuvan IPTC tiedot +IPTCPANEL_HEADLINE;Julkaistava otsikko +IPTCPANEL_HEADLINEHINT;(Headline) Julkaistava otsikko. +IPTCPANEL_INSTRUCTIONS;Ohjeet +IPTCPANEL_INSTRUCTIONSHINT;(Instructions) Ohjeet ja rajoitukset. +IPTCPANEL_KEYWORDS;Avainsanat +IPTCPANEL_KEYWORDSHINT;(Keywords) Kohdetta kuvaavia avainsanoja. +IPTCPANEL_PASTEHINT;Liitä IPTC asetukset leikepöydältä +IPTCPANEL_PROVINCE;Maakunta +IPTCPANEL_PROVINCEHINT;(Province) Maakunta jossa kuva on otettu. +IPTCPANEL_RESET;Palauta +IPTCPANEL_RESETHINT;Palauta profiilin oletukseen +IPTCPANEL_SOURCE;Lähde +IPTCPANEL_SOURCEHINT;(Source) Kuvan lähde. +IPTCPANEL_SUPPCATEGORIES;Tarkempi aiheryhmä +IPTCPANEL_SUPPCATEGORIESHINT;(Supplemental Categories) Tarkempi aiheryhmä. +IPTCPANEL_TITLE;Otsikko +IPTCPANEL_TITLEHINT;(Title) Otsikko. +IPTCPANEL_TRANSREFERENCE;Alkuperäviite +IPTCPANEL_TRANSREFERENCEHINT;(Original Transmission Reference) Alkuperäviite. +MAIN_BUTTON_PREFERENCES;Asetukset +MAIN_BUTTON_SAVE;Tallenna kuva +MAIN_BUTTON_SAVEAS;... +MAIN_BUTTON_SENDTOEDITOR;Send to editor +MAIN_MSG_ALREADYEXISTS;Tiedosto on jo olemassa. +MAIN_MSG_CANNOTLOAD;Kuvaa ei voi avata +MAIN_MSG_CANNOTSAVE;Tiedoston tallennusongelma +MAIN_MSG_CANNOTSTARTEDITOR;Can not start editor. +MAIN_MSG_CANNOTSTARTEDITOR_SECONDARY;Please set the correct path in the "Preferences" dialog. +MAIN_MSG_EXITJOBSINQUEUEINFO;Unprocessed images in the queue will be lost on exit. +MAIN_MSG_EXITJOBSINQUEUEQUEST;Are you sure you want to exit? There are unprocessed images waiting in the queue. +MAIN_MSG_JOBSINQUEUE;työtä jonossa +MAIN_MSG_QOVERWRITE;Haluatko tallentaa päälle? +MAIN_TAB_BASIC;Säädöt +MAIN_TAB_COLOR;Color +MAIN_TAB_DETAIL;Detail +MAIN_TAB_EXIF;Exif +MAIN_TAB_EXPOSURE;Exposure +MAIN_TAB_ICM;ICM +MAIN_TAB_IPTC;IPTC +MAIN_TAB_METADATA;Metadata +MAIN_TAB_TRANSFORM;Muunnokset +MAIN_TOOLTIP_HIDEFP;Näytä/piilota alaikkuna (shortcut key: F) +MAIN_TOOLTIP_HIDEHP;Näytä/piilota vasen ikkuna (shortcut key: H) +MAIN_TOOLTIP_INDCLIPPEDH;Näytä leikkautuvat\nvaaleat alueet +MAIN_TOOLTIP_INDCLIPPEDS;Näytä leikkautuvat\ntummat alueet +MAIN_TOOLTIP_PREFERENCES;Muuta asetuksia +MAIN_TOOLTIP_QINFO;Kuvan tiedot +MAIN_TOOLTIP_SAVE;Tallenna kuva\noletuskansioon +MAIN_TOOLTIP_SAVEAS;Tallenna kuva\nvalittuun kansioon +PARTIALPASTE_BASICGROUP;Basic settings +PARTIALPASTE_CACORRECTION;C/A correction +PARTIALPASTE_COARSETRANS;90 deg rotation / flipping +PARTIALPASTE_COLORBOOST;Color boost +PARTIALPASTE_COLORDENOISE;Color denoise +PARTIALPASTE_COLORGROUP;Color related settings +PARTIALPASTE_COLORMIXER;Color mixer +PARTIALPASTE_COLORSHIFT;Color shift +PARTIALPASTE_COMPOSITIONGROUP;Composition settings +PARTIALPASTE_CROP;Crop +PARTIALPASTE_DIALOGLABEL;Partial paste processing profile +PARTIALPASTE_DISTORTION;Distortion correction +PARTIALPASTE_EXIFCHANGES;Changes to exif data +PARTIALPASTE_EXPOSURE;Exposure +PARTIALPASTE_HLRECOVERY;Highlight recovery +PARTIALPASTE_ICMSETTINGS;ICM settings +PARTIALPASTE_IPTCINFO;IPTC info +PARTIALPASTE_LENSGROUP;Lens related settings +PARTIALPASTE_LUMACURVE;Luminance curve +PARTIALPASTE_LUMADENOISE;Luminance noise reduction +PARTIALPASTE_LUMINANCEGROUP;Luminance related settings +PARTIALPASTE_METAICMGROUP;Metadata/ICM settings +PARTIALPASTE_RESIZE;Resize +PARTIALPASTE_ROTATION;Rotation +PARTIALPASTE_SHADOWSHIGHLIGHTS;Shadows/Highlights +PARTIALPASTE_SHARPENING;Sharpening +PARTIALPASTE_VIGNETTING;Vignetting correction +PARTIALPASTE_WHITEBALANCE;White balance +PREFERENCES_APPLNEXTSTARTUP;käytössä käynnistyksen jälkeen +PREFERENCES_BLINKCLIPPED;Välkytä leikkautuvia alueita +PREFERENCES_CACHECLEARALL;Clear All +PREFERENCES_CACHECLEARPROFILES;Clear Profiles +PREFERENCES_CACHECLEARTHUMBS;Clear Thumbnails +PREFERENCES_CACHEFORMAT1;Proprietary (faster and better quality) +PREFERENCES_CACHEFORMAT2;JPEG (smaller disk footprint) +PREFERENCES_CACHEMAXENTRIES;Maximal Number of Cache Entries +PREFERENCES_CACHEOPTS;Cache Options +PREFERENCES_CACHESTRAT1;Prefer Speed to Low Memory Consumption +PREFERENCES_CACHESTRAT2;Prefer Low Memory Consumption to Speed +PREFERENCES_CACHESTRAT;Cache Strategy +PREFERENCES_CACHETHUMBFORM;Cache Thumbnail Format +PREFERENCES_CACHETHUMBHEIGHT;Maximal Thumbnail Height +PREFERENCES_CLEARDLG_LINE1;Clearing cache +PREFERENCES_CLEARDLG_LINE2;This may take a few seconds. +PREFERENCES_CLEARDLG_TITLE;Please wait +PREFERENCES_CLIPPINGIND;Leikkautuminen +PREFERENCES_CMETRICINTENT;Näköistystapa +PREFERENCES_DATEFORMAT;Päivämäärän muoto +PREFERENCES_DATEFORMATHINT;Voit käyttää seuraavia komentoja:\n%y : vuosi\n%m : kuukausi\n%d : päivä\n\nEsimerkiksi, pp.kk.vvvv:\n%d.%m.%y +PREFERENCES_DEFAULTLANG;Oletuskieli +PREFERENCES_DEFAULTTHEME;Oletus +PREFERENCES_DEMOSAICINGALGO;Koostamismenetelmä (interpolointi) +PREFERENCES_DIRHOME;Kotihakemisto +PREFERENCES_DIRLAST;Viimeksi käytetty hakemisto +PREFERENCES_DIROTHER;Muu +PREFERENCES_DIRSELECTDLG;Valitse kuvahakemisto käynnistettäessä... +PREFERENCES_DIRSOFTWARE;Asennushakemisto +PREFERENCES_DMETHOD;Menetelmä +PREFERENCES_EDITORCMDLINE;Other command line +PREFERENCES_EXTERNALEDITOR;External editor +PREFERENCES_FALSECOLOR;Värivääristymien eston määrä +PREFERENCES_FBROWSEROPTS;Tiedostojen valinnat +PREFERENCES_FILEFORMAT;Tiedoston tyyppi +PREFERENCES_FORIMAGE;Kuvatiedostoille +PREFERENCES_FORRAW;RAW tiedostoille +PREFERENCES_GIMPPATH;GIMP installation directory +PREFERENCES_GTKTHEME;GTK oletus +PREFERENCES_HINT;Neuvo +PREFERENCES_HLTHRESHOLD;Kynnysarvo vaaleille alueille +PREFERENCES_ICCDIR;ICC-profiilien hakemisto +PREFERENCES_IMPROCPARAMS;Oletusasetukset +PREFERENCES_INTENT_ABSOLUTE;Absoluuttinen kolorimetrinen +PREFERENCES_INTENT_PERCEPTUAL;Havainnollinen +PREFERENCES_INTENT_RELATIVE;Suhteellinen kolorimetrinen +PREFERENCES_INTENT_SATURATION;Kylläisyyden säilyttävä +PREFERENCES_LIVETHUMBNAILS;Live Thumbnails (slower) +PREFERENCES_MONITORICC;Näytön profiili +PREFERENCES_OUTDIR;Tallennushakemisto +PREFERENCES_OUTDIRFOLDER;Save to folder +PREFERENCES_OUTDIRFOLDERHINT;Put the saved images to the seledted folder +PREFERENCES_OUTDIRHINT;Voit käyttää seuraavia komentoja:\n%f tiedosto\n%p1, %p2, ... polku\n%d1, %d2, ..., hakemisto\nNämä komennot viittaavat RAW-tiedoston hakemistoihin ja polkuihin.\n\nEsimerkiksi: jos /home/tom/image/02-09-2006/dsc0012.nefon avattu, komennot tarkoittavat seuraavaa:\n%f=dsc0012\n%d1=02-09-2006, %d2=image,...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nJos haluat tallentaa alkuperäisen kuvan hakemistoon:\n%p1/%f\n\nJos haluat tallentaa hakemistoon nimeltä 'converted' joka sijaitsee alkuperäisen kuvan hakemistossa:\n%p1/converted/%f\n\nJos haluat tallentaa hakemistoon '/home/tom/converted' ja pitää päivämäärähakemistot:\n%p2/converted/%d1/%f +PREFERENCES_OUTDIRTEMPLATE;Use Template +PREFERENCES_OUTDIRTEMPLATEHINT;You can use the following formatting strings:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nThese formatting strings refer to the directories and sub-paths of the path of the raw file.\n\nFor example, if /home/tom/image/02-09-2006/dsc0012.nefhas been opened, the meaning of the formatting strings are:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nIf you want to save the output image where the original is, write:\n%p1/%f\n\nIf you want to save the output image in a directory 'converted' located the directory of the original, write:\n%p1/converted/%f\n\nIf you want to save the output image in directory '/home/tom/converted' with keeping the same subdirectory of dates, write:\n%p2/converted/%d1/%f +PREFERENCES_PARSEDEXT;Parsed Extensions +PREFERENCES_PARSEDEXTADD;Add Extension +PREFERENCES_PARSEDEXTADDHINT;Type an extension and press this button to append list +PREFERENCES_PARSEDEXTDELHINT;Delete selected extension from the list +PREFERENCES_PROFILEHANDLING;Processing Profile Handling +PREFERENCES_PROFILELOADPR;Profile Loading Priority +PREFERENCES_PROFILEPRCACHE;Profile in Cache +PREFERENCES_PROFILEPRFILE;Profile Next to the Input File +PREFERENCES_PROFILESAVECACHE;Save Processing Parameters to the Cache +PREFERENCES_PROFILESAVEINPUT;Save Processing Parameters Next to the Input File +PREFERENCES_PSPATH;Adobe Photoshop installation directory +PREFERENCES_SELECTICCDIRDLG;Valitse ICC-profiilin hakemisto... +PREFERENCES_SELECTLANG;Valitse kieli +PREFERENCES_SELECTMONITORPROFDLG;Valitse näytön ICC-profiili... +PREFERENCES_SELECTTHEME;Valitse teema +PREFERENCES_SHOWBASICEXIF;Näytä perus Exif-tiedot +PREFERENCES_SHOWDATETIME;Näytä päivämäärä ja aika +PREFERENCES_SHOWONLYRAW;Näytä vain RAW-tiedostot +PREFERENCES_SHTHRESHOLD;Kynnysarvo tummille alueille +PREFERENCES_STARTUPIMDIR;Kuvahakemisto käynnistettäessä +PREFERENCES_TAB_BROWSER;Tiedostot +PREFERENCES_TAB_COLORMGR;Värit +PREFERENCES_TAB_GENERAL;Yleiset +PREFERENCES_TAB_IMPROC;Kuvankäsittely +PREFERENCES_TAB_OUTPUT;Tallennus +PREFERENCES_THUMBSIZE;Esikatselukuvien koko +PROFILEPANEL_FILEDLGFILTERANY;Kaikki tiedostot +PROFILEPANEL_FILEDLGFILTERPP;Profiilitiedostot +PROFILEPANEL_LABEL;Käsittelyprofiili +PROFILEPANEL_LOADDLGLABEL;Lataa käsittelyprofiili... +PROFILEPANEL_PCUSTOM;Oma +PROFILEPANEL_PFILE;Tiedostosta +PROFILEPANEL_PLASTPHOTO;Viimeisimmästä kuvasta +PROFILEPANEL_PLASTSAVED;Viimeisin tallennettu +PROFILEPANEL_PROFILE;Profiili +PROFILEPANEL_SAVEDLGLABEL;Tallenna käsittelyprofiili... +PROFILEPANEL_TOOLTIPCOPY;Copy current profile to clipboard +PROFILEPANEL_TOOLTIPLOAD;Lataa profiili tiedostosta +PROFILEPANEL_TOOLTIPPASTE; Paste profile from clipboard +PROFILEPANEL_TOOLTIPSAVE;Tallenna profiili +PROGRESSBAR_DECODING;RAW-tiedostoa puretaan... +PROGRESSBAR_DEMOSAICING;Kuvaa koostetaan... +PROGRESSBAR_LOADING;Kuvaa ladataan... +PROGRESSBAR_LOADJPEG;JPEG-tiedostoa ladataan... +PROGRESSBAR_LOADPNG;PNG-tiedostoa ladataan... +PROGRESSBAR_LOADTIFF;TIFF-tiedostoa ladataan... +PROGRESSBAR_PROCESSING;Kuvaa käsitellään... +PROGRESSBAR_READY;Valmis. +PROGRESSBAR_SAVEJPEG;JPEG-tiedostoa tallennetaan... +PROGRESSBAR_SAVEPNG;PNG-tiedostoa tallennetaan... +PROGRESSBAR_SAVETIFF;TIFF-tiedostoa tallennetaan... +PROGRESSDLG_LOADING;Loading file... +PROGRESSDLG_PROCESSING;Processing image... +PROGRESSDLG_SAVING;Saving file... +QINFO_FOCALLENGTH;Polttoväli +QINFO_ISO;ISO +QINFO_LENS;Lens +QINFO_NOEXIF;Exif tietoja ei saatavilla. +SAVEDLG_FILEFORMAT;Tiedoston tyyppi +SAVEDLG_JPEGQUAL;JPEG laatu (suurempi luku, parempi laatu) +SAVEDLG_JPGFILTER;JPEG tiedostot +SAVEDLG_PNGCOMPR;PNG pakkaus (suurempi luku, enemmän pakkausta) +SAVEDLG_PNGFILTER;PNG tiedostot +SAVEDLG_PUTTOQUEUE;Put into processing queue +SAVEDLG_PUTTOQUEUEHEAD;Put to the head of the processing queue +SAVEDLG_PUTTOQUEUETAIL;Put to the end of the processing queue +SAVEDLG_SAVEIMMEDIATELY;Save immediately +SAVEDLG_SAVESPP;Tallenna kuvankäsittelytiedot kuvan mukana +SAVEDLG_TIFFFILTER;TIFF tiedostot +TOOLBAR_TOOLTIP_CROP;Valitse rajattava alue (shortcut key: C) +TOOLBAR_TOOLTIP_HAND;Kuvan siirtotyökalu (shortcut key: N) +TOOLBAR_TOOLTIP_STRAIGHTEN;Valitse suora linja (shortcut key: S) +TOOLBAR_TOOLTIP_WB;Valitse valkotasapainon\nvalkea piste kuvasta (shortcut key: W) +TP_CACORRECTION_BLUE;Sininen +TP_CACORRECTION_LABEL;Väripoikkeaman korjaus +TP_CACORRECTION_RED;Punainen +TP_CHMIXER_BLUE;Sininen +TP_CHMIXER_GREEN;Vihreä +TP_CHMIXER_LABEL;Kanavat +TP_CHMIXER_RED;Punainen +TP_COARSETRAF_DEGREE;astetta +TP_COARSETRAF_TOOLTIP_HFLIP;Peilaa vaakasuunnassa +TP_COARSETRAF_TOOLTIP_ROTLEFT;Käännä vasemmalle +TP_COARSETRAF_TOOLTIP_ROTRIGHT;Käännä oikealle +TP_COARSETRAF_TOOLTIP_VFLIP;Peilaa pystysuunnassa +TP_COLORBOOST_ACHANNEL;a* +TP_COLORBOOST_AMOUNT;Määrä +TP_COLORBOOST_AVOIDCOLORCLIP;Vältä leikkautuminen +TP_COLORBOOST_BCHANNEL;b* +TP_COLORBOOST_CHAB;a* ja b* +TP_COLORBOOST_CHANNEL;Kanava +TP_COLORBOOST_CHSEPARATE;säädä erikseen +TP_COLORBOOST_ENABLESATLIMITER;Estä kyllästyminen +TP_COLORBOOST_LABEL;Värikylläisyys +TP_COLORBOOST_SATLIMIT;Kyllästymisraja +TP_COLORDENOISE_EDGESENSITIVE;Reunaherkkä +TP_COLORDENOISE_EDGETOLERANCE;Reunan tunnistusherkkyys +TP_COLORDENOISE_LABEL;Värin kohinanvaimennus +TP_COLORDENOISE_RADIUS;Säde +TP_COLORSHIFT_BLUEYELLOW;sininen-keltainen +TP_COLORSHIFT_GREENMAGENTA;vihreä-punainen +TP_COLORSHIFT_LABEL;Värisävy +TP_CROP_DPI;Erottelutarkkuus (DPI): +TP_CROP_FIXRATIO;Pidä kuvasuhde: +TP_CROP_GTDIAGONALS;Kulmien puolittajat +TP_CROP_GTHARMMEANS1;Kultainen leikkaus 1 +TP_CROP_GTHARMMEANS2;Kultainen leikkaus 2 +TP_CROP_GTHARMMEANS3;Kultainen leikkaus 3 +TP_CROP_GTHARMMEANS4;Kultainen leikkaus 4 +TP_CROP_GTNONE;Ei mikään +TP_CROP_GTRULETHIRDS;Kolmijako +TP_CROP_GUIDETYPE;Sommittelumalli: +TP_CROP_H;Kork. +TP_CROP_LABEL;Rajaus +TP_CROP_SELECTCROP;Valitse alue +TP_CROP_W;Lev. +TP_CROP_X; x +TP_CROP_Y; y +TP_DISTORTION_AMOUNT;Määrä +TP_DISTORTION_LABEL;Linssivääristymän korjaus +TP_EXPOSURE_AUTOLEVELS;Automaattinen +TP_EXPOSURE_BLACKLEVEL;Tummuus +TP_EXPOSURE_BRIGHTNESS;Kirkkaus +TP_EXPOSURE_CLIP;Raja +TP_EXPOSURE_COMPRHIGHLIGHTS;Vaaleiden alueiden vaimennus +TP_EXPOSURE_COMPRSHADOWS;Tummien alueiden vaimennus +TP_EXPOSURE_CONTRAST;Kontrasti +TP_EXPOSURE_CURVEEDITOR;Sävykäyrä +TP_EXPOSURE_EXPCOMP;Kompensointi +TP_EXPOSURE_LABEL;Valotus +TP_HLREC_CIELAB;CIELAB värisekoitus +TP_HLREC_COLOR;Värin palautus +TP_HLREC_LABEL;Huippuvaloalueiden palautus +TP_HLREC_LUMINANCE;Luminanssin palautus +TP_HLREC_METHOD;Menetelmä: +TP_ICM_FILEDLGFILTERANY;kaikki tiedostot +TP_ICM_FILEDLGFILTERICM;ICC-profiilitiedostot +TP_ICM_GAMMABEFOREINPUT;Käytä profiilin gammaa +TP_ICM_INPUTCAMERA;Kameran oletus +TP_ICM_INPUTCUSTOM;Oma +TP_ICM_INPUTDLGLABEL;Valitse lähteen ICC-profiili... +TP_ICM_INPUTEMBEDDED;Käytä kuvan omaa, jos mahdollista +TP_ICM_INPUTPROFILE;Lähdeväriprofiili +TP_ICM_LABEL;ICM +TP_ICM_NOICM;Ei ICM-profiilia: sRGB +TP_ICM_OUTPUTDLGLABEL;Valitse tuloksen ICC-profiili... +TP_ICM_OUTPUTPROFILE;Tulosväriprofiili +TP_ICM_SAVEREFERENCE;Tallenna mallikuva\nprofilointia varten +TP_ICM_WORKINGPROFILE;Työväriprofiili +TP_LUMACURVE_BLACKLEVEL;Tummuus +TP_LUMACURVE_BRIGHTNESS;Kirkkaus +TP_LUMACURVE_COMPRHIGHLIGHTS;Vaaleiden alueiden vaimennus +TP_LUMACURVE_COMPRSHADOWS;Tummien alueiden vaimennus +TP_LUMACURVE_CONTRAST;Kontrasti +TP_LUMACURVE_CURVEEDITOR;Luminanssin käyrä +TP_LUMACURVE_LABEL;Luminanssi +TP_LUMADENOISE_EDGETOLERANCE;Reunan tunnistusherkkyys +TP_LUMADENOISE_LABEL;Luminanssin kohinanvaimennus +TP_LUMADENOISE_RADIUS;Säde +TP_RESIZE_BICUBIC;Bikuutiollinen +TP_RESIZE_BICUBICSF;Bikuutiollinen (Pehmeämpi) +TP_RESIZE_BICUBICSH;Bikuutiollinen (Terävämpi) +TP_RESIZE_BILINEAR;Bilineaarinen +TP_RESIZE_FULLSIZE;Kuvan koko: +TP_RESIZE_H;Kork.: +TP_RESIZE_LABEL;Koko +TP_RESIZE_METHOD;Menetelmä: +TP_RESIZE_NEAREST;Lähin +TP_RESIZE_SCALE;Mittakaava +TP_RESIZE_W;Lev.: +TP_ROTATE_AUTOCROP;Aseta rajaus +TP_ROTATE_DEGREE;Astetta +TP_ROTATE_FILL;Suurenna/pienennä kuva automaattisesti +TP_ROTATE_LABEL;Kääntö +TP_ROTATE_SELECTLINE;Valitse suora linja +TP_SHADOWSHLIGHTS_HIGHLIGHTS;Vaaleiden alueiden vaimennus +TP_SHADOWSHLIGHTS_HLTONALW;Vaalean sävyalueen leveys +TP_SHADOWSHLIGHTS_LABEL;Tummat/vaaleat alueet +TP_SHADOWSHLIGHTS_LOCALCONTR;Paikallinen kontrasti +TP_SHADOWSHLIGHTS_RADIUS;Säde +TP_SHADOWSHLIGHTS_SHADOWS;Tummien alueiden vaimennus +TP_SHADOWSHLIGHTS_SHTONALW;Tumman sävyalueen leveys +TP_SHARPENING_AMOUNT;Määrä +TP_SHARPENING_EDRADIUS;Säde +TP_SHARPENING_EDTOLERANCE;Reunan tunnistusherkkyys +TP_SHARPENING_HALOCONTROL;Halo-ilmiön esto +TP_SHARPENING_HCAMOUNT;Määrä +TP_SHARPENING_LABEL;Terävöinti +TP_SHARPENING_METHOD;Menetelmä +TP_SHARPENING_ONLYEDGES;Terävöi vain reunat +TP_SHARPENING_RADIUS;Säde +TP_SHARPENING_RLD;RL dekonvoluutio +TP_SHARPENING_RLD_AMOUNT;Määrä +TP_SHARPENING_RLD_DAMPING;Vaimennus +TP_SHARPENING_RLD_ITERATIONS;Iteraatiot +TP_SHARPENING_THRESHOLD;Kynnys +TP_SHARPENING_USM;Epäterävä maski +TP_VIGNETTING_AMOUNT;Määrä +TP_VIGNETTING_LABEL;Vinjetoinnin korjaus +TP_VIGNETTING_RADIUS;Säde +TP_WBALANCE_AUTO;Automaattinen +TP_WBALANCE_CAMERA;Kamera +TP_WBALANCE_CUSTOM;Oma +TP_WBALANCE_GREEN;Valkoisen sävy +TP_WBALANCE_LABEL;Valkotasapaino +TP_WBALANCE_METHOD;Menetelmä +TP_WBALANCE_SIZE;Koko: +TP_WBALANCE_SPOTWB;Valitse valkoinen kuvasta +TP_WBALANCE_TEMPERATURE;Lämpötila [K] +ZOOMBAR_DETAIL; +ZOOMBAR_HUGE;Suurin +ZOOMBAR_LARGE;Suuri +ZOOMBAR_NORMAL;Normaali +ZOOMBAR_PREVIEW; +ZOOMBAR_SCALE; +ZOOMBAR_SMALL;Pieni diff --git a/release/languages/swedish b/release/languages/swedish new file mode 100755 index 000000000..28bc70e84 --- /dev/null +++ b/release/languages/swedish @@ -0,0 +1,577 @@ +# Swedish translation of RawTherapee +# Translated by Emil Ericsson +# 2008-01-22 +ADJUSTER_RESET_TO_DEFAULT;Ã…terställ till standard +CURVEEDITOR_FILEDLGFILTERANY;Vilka filer som helst +CURVEEDITOR_FILEDLGFILTERCURVE;Kurvfiler +CURVEEDITOR_LINEAR;Linjär +CURVEEDITOR_LOADDLGLABEL;Ladda kurva... +CURVEEDITOR_SAVEDLGLABEL;Spara kurva... +CURVEEDITOR_TOOLTIPLINEAR;Ã…terställ kurva till linjär +CURVEEDITOR_TOOLTIPLOAD;Ladda kurva frÃ¥n fil +CURVEEDITOR_TOOLTIPSAVE;Spara nuvarande kurva +EXIFFILTER_APERTURE;Aperture +EXIFFILTER_CAMERA;Camera +EXIFFILTER_DIALOGLABEL;Exif Filter +EXIFFILTER_FOCALLEN;Focal Length +EXIFFILTER_ISO;ISO +EXIFFILTER_LENS;Lens +EXIFFILTER_SHUTTER;Shutter +EXIFPANEL_ADDEDIT;Add/Edit +EXIFPANEL_ADDEDITHINT;Add new tag or edit tag +EXIFPANEL_ADDTAGDLG_ENTERVALUE;Enter value +EXIFPANEL_ADDTAGDLG_SELECTTAG;Select tag +EXIFPANEL_ADDTAGDLG_TITLE;Add/Edit Tag +EXIFPANEL_KEEP;Keep +EXIFPANEL_KEEPHINT;Keep the selected tags when writing output file +EXIFPANEL_REMOVE;Remove +EXIFPANEL_REMOVEHINT;Remove the selected tags when writing output file +EXIFPANEL_RESET;Reset +EXIFPANEL_RESETALL;Reset All +EXIFPANEL_RESETALLHINT;Reset all tags to their original values +EXIFPANEL_RESETHINT;Reset the selected tags to their original values +EXIFPANEL_SUBDIRECTORY;Subdirectory +FILEBROWSER_APPLYPROFILE;Apply profile +FILEBROWSER_ARRANGEMENTHINT;Change between vertical/horizontal alignment of thumbnails +FILEBROWSER_CLEARPROFILE;Clear profile +FILEBROWSER_COPYPROFILE;Copy profile +FILEBROWSER_DELETEDLGLABEL;File delete confirmation +FILEBROWSER_DELETEDLGMSG;Are you sure you want to delete the selected %1 files? +FILEBROWSER_EMPTYTRASH;Empty Trash +FILEBROWSER_EMPTYTRASHHINT;Permanently delete the files of the trash +FILEBROWSER_EXIFFILTERAPPLY;Apply +FILEBROWSER_EXIFFILTERAPPLYHINT;Switch on/off exif filter of the file browser +FILEBROWSER_EXIFFILTERLABEL;Exif Filter +FILEBROWSER_EXIFFILTERSETTINGS;Setup +FILEBROWSER_EXIFFILTERSETTINGSHINT;Change settings of the exif filter +FILEBROWSER_PARTIALPASTEPROFILE;Partial paste +FILEBROWSER_PASTEPROFILE;Paste profile +FILEBROWSER_POPUPCANCELJOB;Cancel job +FILEBROWSER_POPUPMOVEEND;Move to end of queue +FILEBROWSER_POPUPMOVEHEAD;Move to head of queue +FILEBROWSER_POPUPOPEN;Open +FILEBROWSER_POPUPPROCESS;Put to processing queue +FILEBROWSER_POPUPRANK1;Rank 1 +FILEBROWSER_POPUPRANK2;Rank 2 +FILEBROWSER_POPUPRANK3;Rank 3 +FILEBROWSER_POPUPRANK4;Rank 4 +FILEBROWSER_POPUPRANK5;Rank 5 +FILEBROWSER_POPUPREMOVE;Remove from filesystem +FILEBROWSER_POPUPRENAME;Rename +FILEBROWSER_POPUPSELECTALL;Select all +FILEBROWSER_POPUPTRASH;Move to trash +FILEBROWSER_POPUPUNRANK;Unrank +FILEBROWSER_POPUPUNTRASH;Remove from trash +FILEBROWSER_PROCESSINGSETTINGS;Settings +FILEBROWSER_PROCESSINGSETTINGSHINT;Set the file format and output directory +FILEBROWSER_RENAMEDLGLABEL;Rename file +FILEBROWSER_RENAMEDLGMSG;Rename file "%1" to: +FILEBROWSER_SHOWDIRHINT;Show all images of the directory +FILEBROWSER_SHOWQUEUEHINT;Show content of the processing queue +FILEBROWSER_SHOWRANK1HINT;Show images ranked as 1 star +FILEBROWSER_SHOWRANK2HINT;Show images ranked as 2 star +FILEBROWSER_SHOWRANK3HINT;Show images ranked as 3 star +FILEBROWSER_SHOWRANK4HINT;Show images ranked as 4 star +FILEBROWSER_SHOWRANK5HINT;Show images ranked as 5 star +FILEBROWSER_SHOWTRASHHINT;Show content of the trash +FILEBROWSER_SHOWUNRANKHINT;Show unranked images +FILEBROWSER_STARTPROCESSING;Start Processing +FILEBROWSER_STARTPROCESSINGHINT;Start processing/saving of images in the queue +FILEBROWSER_STOPPROCESSING;Stop processing +FILEBROWSER_STOPPROCESSINGHINT;Stop processing of images +FILEBROWSER_THUMBSIZE;Thumb. size +FILEBROWSER_ZOOMINHINT;Increase thumbnail size +FILEBROWSER_ZOOMOUTHINT;Decrease thumbnail size +GENERAL_ABOUT;Om +GENERAL_CANCEL;Avbryt +GENERAL_DISABLE;Avaktivera +GENERAL_DISABLED;Avaktivera +GENERAL_ENABLE;Verkställ +GENERAL_ENABLED;Verkställ +GENERAL_LANDSCAPE;Landskap +GENERAL_LOAD;Ladda +GENERAL_NA;n/a +GENERAL_NO;Nej +GENERAL_OK;Ok +GENERAL_PORTRAIT;Porträtt +GENERAL_SAVE;Spara +GENERAL_YES;Ja +HISTOGRAM_LABEL;Histogram +HISTOGRAM_TOOLTIP_B;Visa/göm blÃ¥tt histogram +HISTOGRAM_TOOLTIP_G;Visa/göm grönt histogram +HISTOGRAM_TOOLTIP_L;Visa/göm CIELAB Luminans histogram +HISTOGRAM_TOOLTIP_R;Visa/göm rött histogram +HISTORY_CHANGED;Changed +HISTORY_CUSTOMCURVE;Egen kurva +HISTORY_DELSNAPSHOT;Ta bort bokmärke +HISTORY_FROMCLIPBOARD;From clipboard +HISTORY_LABEL;Historia +HISTORY_MSG_10;Skuggkomprimering +HISTORY_MSG_11;Tonkurva +HISTORY_MSG_12;Autoexponering +HISTORY_MSG_13;Exponeringsmarkering +HISTORY_MSG_14;Luminansljusstyrka +HISTORY_MSG_15;Luminanskontrast +HISTORY_MSG_16;Svart luminans +HISTORY_MSG_17;Luminans högdager kompr. +HISTORY_MSG_18;Luminans skugg kompr. +HISTORY_MSG_19;Luminanskurva +HISTORY_MSG_1;Foto laddat +HISTORY_MSG_20;Skärpning +HISTORY_MSG_21;Skärpningsradie +HISTORY_MSG_22;Skärpningsmängd +HISTORY_MSG_23;Skärpningströskelvärde +HISTORY_MSG_24;Skärp bara kanter +HISTORY_MSG_25;Kantupptäckningsradie-skärpning +HISTORY_MSG_26;Kantskärpningstolerans +HISTORY_MSG_27;Halo-skärpningskontroll +HISTORY_MSG_28;Halo-kontrollstorlek +HISTORY_MSG_29;Skärpningsmetod +HISTORY_MSG_2;Profil laddad +HISTORY_MSG_30;Deconvolution-radie +HISTORY_MSG_31;Deconvolution-storlek +HISTORY_MSG_32;Deconvolution-dämpning +HISTORY_MSG_33;Deconvolution-upprepning +HISTORY_MSG_34;Undvik färgmarkeringar +HISTORY_MSG_35;Mättnadsbegränsning +HISTORY_MSG_36;Mättnadsgräns +HISTORY_MSG_37;Färgförstärkning +HISTORY_MSG_38;Vitbalansmetod +HISTORY_MSG_39;Färgtemperatur +HISTORY_MSG_3;Profil ändrad +HISTORY_MSG_40;Vitbalansnyans +HISTORY_MSG_41;Färgskiftning "A" +HISTORY_MSG_42;Färgskiftning "B" +HISTORY_MSG_43;Luminans brusborttagning +HISTORY_MSG_44;Lum. brusborttagnings-radie +HISTORY_MSG_45;Lum. brusborttagnings kanttolerans +HISTORY_MSG_46;Färgbrusborttagning +HISTORY_MSG_47;Färgbrusborttagnings-radie +HISTORY_MSG_48;Färgbrusborttagnings-kanttolerans +HISTORY_MSG_49;Kantkänslig färgbrusborttagning +HISTORY_MSG_4;Historia-bläddrande +HISTORY_MSG_50;Skugg/högdager verktyg +HISTORY_MSG_51;Högdager-förstärkning +HISTORY_MSG_52;Skuggförstärkning +HISTORY_MSG_53;Högdager-tonvidd +HISTORY_MSG_54;Skugg-tonvidd +HISTORY_MSG_55;Lokal kontrast +HISTORY_MSG_56;Skugg/högdager -radie +HISTORY_MSG_57;Enkel rotation +HISTORY_MSG_58;Vänd horisontellt +HISTORY_MSG_59;Vänd vertikalt +HISTORY_MSG_5;Ljusstyrka +HISTORY_MSG_60;Rotation +HISTORY_MSG_61;Rotation +HISTORY_MSG_62;Objektivdistorsions-korrigering +HISTORY_MSG_63;Valt bokmärke +HISTORY_MSG_64;Beskär foto +HISTORY_MSG_65;C/A korrigering +HISTORY_MSG_66;Högdager-förbättring +HISTORY_MSG_67;Högdager-förbättringsstorlek +HISTORY_MSG_68;Högdager-förbättringsmetod +HISTORY_MSG_69;Arbetsfärgrymd +HISTORY_MSG_6;Kontrast +HISTORY_MSG_70;Utmatningsfärgrymd +HISTORY_MSG_71;Inmatningsfärgrymd +HISTORY_MSG_72;Vinjettering-korrigering +HISTORY_MSG_73;Kanalmixer +HISTORY_MSG_74;Ändra storleksskala +HISTORY_MSG_75;Ändra storleks metod +HISTORY_MSG_76;Exif Metadata +HISTORY_MSG_77;IPTC Metadata +HISTORY_MSG_7;Svart +HISTORY_MSG_8;Exponerings-komprimering +HISTORY_MSG_9;Högdager-komprimering +HISTORY_NEWSNAPSHOT;Nytt bokmärke +HISTORY_NEWSNAPSHOTAS;Som... +HISTORY_NEWSSDIALOGLABEL;Namn pÃ¥ bokmärket: +HISTORY_NEWSSDIALOGTITLE;Lägg till nytt bokmärke +HISTORY_SETTO;Ställ in till +HISTORY_SNAPSHOT;Bokmärke +HISTORY_SNAPSHOTS;Bokmärken +ICMPANEL_FILEDLGFILTERANY;Vilka filer som helst +ICMPANEL_FILEDLGFILTERICM;ICC profilfiler +ICMPANEL_GAMMABEFOREINPUT;Profile applies Gamma +ICMPANEL_INPUTCAMERA;Kameraval +ICMPANEL_INPUTCUSTOM;Egen +ICMPANEL_INPUTDLGLABEL;Välj inmatnings ICC-profil... +ICMPANEL_INPUTEMBEDDED;Använd inbäddad, om möjligt +ICMPANEL_INPUTPROFILE;Inmatningsprofil +ICMPANEL_NOICM;Ingen ICM: sRGB-utmatning +ICMPANEL_OUTPUTDLGLABEL;Välj utmatnings ICC-profil... +ICMPANEL_OUTPUTPROFILE;Utmatningsprofil +ICMPANEL_SAVEREFERENCE;Save reference image for profiling +ICMPANEL_WORKINGPROFILE;Arbetsprofil +IMAGEAREA_DETAILVIEW;Detalj +IPTCPANEL_AUTHOR;Author +IPTCPANEL_AUTHORHINT;Name of the creator of the object, e.g. writer, photographer or graphic artist (By-line). +IPTCPANEL_AUTHORSPOSITION;Author's position +IPTCPANEL_AUTHORSPOSITIONHINT;Title of the creator or creators of the object (By-line Title). +IPTCPANEL_CAPTION;Caption +IPTCPANEL_CAPTIONHINT;A textual description of the data (Caption - Abstract). +IPTCPANEL_CAPTIONWRITER;Caption Writer +IPTCPANEL_CAPTIONWRITERHINT;The name of the person involved in the writing, editing or correcting the image or caption/abstract (Writer - Editor). +IPTCPANEL_CATEGORY;Category +IPTCPANEL_CATEGORYHINT;Identifies the subject of the image in the opinion of the provider (Category). +IPTCPANEL_CITY;City +IPTCPANEL_CITYHINT;City of image origin (City). +IPTCPANEL_COPYHINT;Copy IPTC settings to clipboard +IPTCPANEL_COPYRIGHT;Copyright +IPTCPANEL_COPYRIGHTHINT;Any necessary copyright notice (Copyright Notice). +IPTCPANEL_COUNTRY;Country +IPTCPANEL_COUNTRYHINT;The name of the country/primary location where the image was created (Country - Primary Location Name). +IPTCPANEL_CREDIT;Credit +IPTCPANEL_CREDITHINT;Identifies the provider of the image, not necessarily the owner/creator (Credit). +IPTCPANEL_DATECREATED;Date Created +IPTCPANEL_DATECREATEDHINT;The date the intellectual content of the image was created; Format: JJJJMMTT (Date Created). +IPTCPANEL_EMBEDDED;Embedded +IPTCPANEL_EMBEDDEDHINT;Reset to IPTC data embedded in the image file +IPTCPANEL_HEADLINE;Headline +IPTCPANEL_HEADLINEHINT;A publishable entry providing a synopsis of the contents of the image (Headline). +IPTCPANEL_INSTRUCTIONS;Instructions +IPTCPANEL_INSTRUCTIONSHINT;Other editorial instructions concerning the use of the image (Special Instructions). +IPTCPANEL_KEYWORDS;Keywords +IPTCPANEL_KEYWORDSHINT;Used to indicate specific information retrieval words (Keywords). +IPTCPANEL_PASTEHINT;Paste IPTC settings from clipboard +IPTCPANEL_PROVINCE;Province +IPTCPANEL_PROVINCEHINT;The Province/State where the image originates (Province-State). +IPTCPANEL_RESET;Reset +IPTCPANEL_RESETHINT;Reset to profile default +IPTCPANEL_SOURCE;Source +IPTCPANEL_SOURCEHINT;The original owner of the intellectual content of the image (Source). +IPTCPANEL_SUPPCATEGORIES;Suppl. Categories +IPTCPANEL_SUPPCATEGORIESHINT;Further refines the subject of the image (Supplemental Categories). +IPTCPANEL_TITLE;Title +IPTCPANEL_TITLEHINT;A shorthand reference for the image (Object Name). +IPTCPANEL_TRANSREFERENCE;Trans. Reference +IPTCPANEL_TRANSREFERENCEHINT;A code representing the location of original transmission (Original Transmission Reference). +MAIN_BUTTON_PREFERENCES;Inställningar +MAIN_BUTTON_SAVE;Spara bild +MAIN_BUTTON_SAVEAS;Som... +MAIN_BUTTON_SENDTOEDITOR;Send to editor +MAIN_MSG_ALREADYEXISTS;Filen existerar redan. +MAIN_MSG_CANNOTLOAD;Kan inte ladda bilden +MAIN_MSG_CANNOTSAVE;Filsparningsfel +MAIN_MSG_CANNOTSTARTEDITOR;Can not start editor. +MAIN_MSG_CANNOTSTARTEDITOR_SECONDARY;Please set the correct path in the "Preferences" dialog. +MAIN_MSG_EXITJOBSINQUEUEINFO;Unprocessed images in the queue will be lost on exit. +MAIN_MSG_EXITJOBSINQUEUEQUEST;Are you sure you want to exit? There are unprocessed images waiting in the queue. +MAIN_MSG_JOBSINQUEUE;Arbete(n) i kö +MAIN_MSG_QOVERWRITE;Vill du skriva över den? +MAIN_TAB_BASIC;Grund +MAIN_TAB_COLOR;Color +MAIN_TAB_DETAIL;Detail +MAIN_TAB_EXIF;Exif +MAIN_TAB_EXPOSURE;Exposure +MAIN_TAB_ICM;ICM +MAIN_TAB_IPTC;IPTC +MAIN_TAB_METADATA;Metadata +MAIN_TAB_TRANSFORM;Omvandla +MAIN_TOOLTIP_HIDEFP;Visa/göm den nedre panelen (katalog och filbläddrare, shortcut key: F) +MAIN_TOOLTIP_HIDEHP;Visa/göm den vänstra panelen (innehÃ¥ller historiken, shortcut key: H) +MAIN_TOOLTIP_INDCLIPPEDH;Markerad högdager-indikation +MAIN_TOOLTIP_INDCLIPPEDS;Markerad skugg-indikation +MAIN_TOOLTIP_PREFERENCES;Ställ in inställningar +MAIN_TOOLTIP_QINFO;Snabb info om bilden +MAIN_TOOLTIP_SAVE;Spara bilden till standardmappen +MAIN_TOOLTIP_SAVEAS;Spara bilden till en vald mapp +PARTIALPASTE_BASICGROUP;Basic settings +PARTIALPASTE_CACORRECTION;C/A correction +PARTIALPASTE_COARSETRANS;90 deg rotation / flipping +PARTIALPASTE_COLORBOOST;Color boost +PARTIALPASTE_COLORDENOISE;Color denoise +PARTIALPASTE_COLORGROUP;Color related settings +PARTIALPASTE_COLORMIXER;Color mixer +PARTIALPASTE_COLORSHIFT;Color shift +PARTIALPASTE_COMPOSITIONGROUP;Composition settings +PARTIALPASTE_CROP;Crop +PARTIALPASTE_DIALOGLABEL;Partial paste processing profile +PARTIALPASTE_DISTORTION;Distortion correction +PARTIALPASTE_EXIFCHANGES;Changes to exif data +PARTIALPASTE_EXPOSURE;Exposure +PARTIALPASTE_HLRECOVERY;Highlight recovery +PARTIALPASTE_ICMSETTINGS;ICM settings +PARTIALPASTE_IPTCINFO;IPTC info +PARTIALPASTE_LENSGROUP;Lens related settings +PARTIALPASTE_LUMACURVE;Luminance curve +PARTIALPASTE_LUMADENOISE;Luminance noise reduction +PARTIALPASTE_LUMINANCEGROUP;Luminance related settings +PARTIALPASTE_METAICMGROUP;Metadata/ICM settings +PARTIALPASTE_RESIZE;Resize +PARTIALPASTE_ROTATION;Rotation +PARTIALPASTE_SHADOWSHIGHLIGHTS;Shadows/Highlights +PARTIALPASTE_SHARPENING;Sharpening +PARTIALPASTE_VIGNETTING;Vignetting correction +PARTIALPASTE_WHITEBALANCE;White balance +PREFERENCES_APPLNEXTSTARTUP;ändras vid nästa uppstart +PREFERENCES_BLINKCLIPPED;Blinka markerade omrÃ¥den +PREFERENCES_CACHECLEARALL;Clear All +PREFERENCES_CACHECLEARPROFILES;Clear Profiles +PREFERENCES_CACHECLEARTHUMBS;Clear Thumbnails +PREFERENCES_CACHEFORMAT1;Proprietary (faster and better quality) +PREFERENCES_CACHEFORMAT2;JPEG (smaller disk footprint) +PREFERENCES_CACHEMAXENTRIES;Maximal Number of Cache Entries +PREFERENCES_CACHEOPTS;Cache Options +PREFERENCES_CACHESTRAT1;Prefer Speed to Low Memory Consumption +PREFERENCES_CACHESTRAT2;Prefer Low Memory Consumption to Speed +PREFERENCES_CACHESTRAT;Cache Strategy +PREFERENCES_CACHETHUMBFORM;Cache Thumbnail Format +PREFERENCES_CACHETHUMBHEIGHT;Maximal Thumbnail Height +PREFERENCES_CLEARDLG_LINE1;Clearing cache +PREFERENCES_CLEARDLG_LINE2;This may take a few seconds. +PREFERENCES_CLEARDLG_TITLE;Please wait +PREFERENCES_CLIPPINGIND;Markerings-indikation +PREFERENCES_CMETRICINTENT;Colorimetric Intent +PREFERENCES_DATEFORMAT;Datumformat +PREFERENCES_DATEFORMATHINT;You can use the following formatting strings:\n%y : year\n%m : month\n%d : day\n\nFor example, the hungarian date format is:\n%y/%m/%d +PREFERENCES_DEFAULTLANG;Förvalt sprÃ¥k +PREFERENCES_DEFAULTTHEME;Default theme +PREFERENCES_DEMOSAICINGALGO;Demosaicing Algorithm +PREFERENCES_DIRHOME;Hemkatalog +PREFERENCES_DIRLAST;Senaste besökta katalog +PREFERENCES_DIROTHER;Annan +PREFERENCES_DIRSELECTDLG;Välj Bildkatalog vid uppstart... +PREFERENCES_DIRSOFTWARE;Installations-katalog +PREFERENCES_DMETHOD;Metod +PREFERENCES_EDITORCMDLINE;Other command line +PREFERENCES_EXTERNALEDITOR;External editor +PREFERENCES_FALSECOLOR;Falskt färgbortträngningssteg +PREFERENCES_FBROWSEROPTS;Filbläddrar-inställningar +PREFERENCES_FILEFORMAT;Filformat +PREFERENCES_FORIMAGE;För bildfiler +PREFERENCES_FORRAW;För RAW-filer +PREFERENCES_GIMPPATH;GIMP installation directory +PREFERENCES_GTKTHEME;GTK default +PREFERENCES_HINT;Tips +PREFERENCES_HLTHRESHOLD;Tröskelvärde för markerade högdager +PREFERENCES_ICCDIR;Katalog för ICC-profiler +PREFERENCES_IMPROCPARAMS;Standard-bildbehandlingsparametrar +PREFERENCES_INTENT_ABSOLUTE;Total colorimetric +PREFERENCES_INTENT_PERCEPTUAL;Perceptual +PREFERENCES_INTENT_RELATIVE;Relativ colorimetric +PREFERENCES_INTENT_SATURATION;Mättnad +PREFERENCES_LIVETHUMBNAILS;Live Thumbnails (slower) +PREFERENCES_MONITORICC;Skärmprofil +PREFERENCES_OUTDIR;Utmatningskatalog +PREFERENCES_OUTDIRFOLDER;Save to folder +PREFERENCES_OUTDIRFOLDERHINT;Put the saved images to the seledted folder +PREFERENCES_OUTDIRHINT;You can use the following formatting strings:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nThese formatting strings refer to the directories and sub-paths of the path of the raw file.\n\nFor example, if /home/tom/image/02-09-2006/dsc0012.nefhas been opened, the meaning of the formatting strings are:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nIf you want to save the output image where the original is, write:\n%p1/%f\n\nIf you want to save the output image in a directory 'converted' located the directory of the original, write:\n%p1/converted/%f\n\nIf you want to save the output image in directory '/home/tom/converted' with keeping the same subdirectory of dates, write:\n%p2/converted/%d1/%f +PREFERENCES_OUTDIRTEMPLATE;Use Template +PREFERENCES_OUTDIRTEMPLATEHINT;You can use the following formatting strings:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nThese formatting strings refer to the directories and sub-paths of the path of the raw file.\n\nFor example, if /home/tom/image/02-09-2006/dsc0012.nefhas been opened, the meaning of the formatting strings are:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nIf you want to save the output image where the original is, write:\n%p1/%f\n\nIf you want to save the output image in a directory 'converted' located the directory of the original, write:\n%p1/converted/%f\n\nIf you want to save the output image in directory '/home/tom/converted' with keeping the same subdirectory of dates, write:\n%p2/converted/%d1/%f +PREFERENCES_PARSEDEXT;Parsed Extensions +PREFERENCES_PARSEDEXTADD;Add Extension +PREFERENCES_PARSEDEXTADDHINT;Type an extension and press this button to append list +PREFERENCES_PARSEDEXTDELHINT;Delete selected extension from the list +PREFERENCES_PROFILEHANDLING;Processing Profile Handling +PREFERENCES_PROFILELOADPR;Profile Loading Priority +PREFERENCES_PROFILEPRCACHE;Profile in Cache +PREFERENCES_PROFILEPRFILE;Profile Next to the Input File +PREFERENCES_PROFILESAVECACHE;Save Processing Parameters to the Cache +PREFERENCES_PROFILESAVEINPUT;Save Processing Parameters Next to the Input File +PREFERENCES_PSPATH;Adobe Photoshop installation directory +PREFERENCES_SELECTICCDIRDLG;Välj ICC-profil katalog... +PREFERENCES_SELECTLANG;Välj sprÃ¥k +PREFERENCES_SELECTMONITORPROFDLG;Välj ICC-profil för skärmen... +PREFERENCES_SELECTTHEME;Select theme +PREFERENCES_SHOWBASICEXIF;Visa grundlig Exif-information +PREFERENCES_SHOWDATETIME;Visa datum och tid +PREFERENCES_SHOWONLYRAW;Visa bara RAW-filer +PREFERENCES_SHTHRESHOLD;Tröskelvärde för markerade skuggor +PREFERENCES_STARTUPIMDIR;Bildkatalog som visas vid uppstart +PREFERENCES_TAB_BROWSER;Filbläddrare +PREFERENCES_TAB_COLORMGR;Färghantering +PREFERENCES_TAB_GENERAL;Allmän +PREFERENCES_TAB_IMPROC;Bildbehandling +PREFERENCES_TAB_OUTPUT;Utmatnings-inställningar +PREFERENCES_THUMBSIZE;Miniatyrbildstorlek +PROFILEPANEL_FILEDLGFILTERANY;Vilka filer som helst +PROFILEPANEL_FILEDLGFILTERPP;Postbehandlar profiler +PROFILEPANEL_LABEL;Postbehandlar profiler +PROFILEPANEL_LOADDLGLABEL;Ladda Postbehandlingsparametrar... +PROFILEPANEL_PCUSTOM;Egen +PROFILEPANEL_PFILE;FrÃ¥n fil +PROFILEPANEL_PLASTPHOTO;Senaste foto +PROFILEPANEL_PLASTSAVED;Senast sparad +PROFILEPANEL_PROFILE;Profil +PROFILEPANEL_SAVEDLGLABEL;Spara Postbehandlingsparametrar... +PROFILEPANEL_TOOLTIPCOPY;Copy current profile to clipboard +PROFILEPANEL_TOOLTIPLOAD;Ladda profil frÃ¥n fil +PROFILEPANEL_TOOLTIPPASTE; Paste profile from clipboard +PROFILEPANEL_TOOLTIPSAVE;Spara nuvarande profil +PROGRESSBAR_DECODING;Avkodar Raw-fil... +PROGRESSBAR_DEMOSAICING;Demosaicing... +PROGRESSBAR_LOADING;Laddar bild... +PROGRESSBAR_LOADJPEG;Laddar JPEG-fil... +PROGRESSBAR_LOADPNG;Laddar PNG-fil... +PROGRESSBAR_LOADTIFF;Laddar TIFF-fil... +PROGRESSBAR_PROCESSING;Bearbetar Bild... +PROGRESSBAR_READY;Klar. +PROGRESSBAR_SAVEJPEG;Sparar JPEG-fil... +PROGRESSBAR_SAVEPNG;Sparar PNG-fil... +PROGRESSBAR_SAVETIFF;Sparar TIFF-fil... +PROGRESSDLG_LOADING;Loading file... +PROGRESSDLG_PROCESSING;Processing image... +PROGRESSDLG_SAVING;Saving file... +QINFO_FOCALLENGTH;Brännvidd +QINFO_ISO;ISO +QINFO_LENS;Lens +QINFO_NOEXIF;Exifdata otillgänglig. +SAVEDLG_FILEFORMAT;Filformat +SAVEDLG_JPEGQUAL;JPEG-kvalitet +SAVEDLG_JPGFILTER;JPEG-filer +SAVEDLG_PNGCOMPR;PNG-komprimering +SAVEDLG_PNGFILTER;PNG-filer +SAVEDLG_PUTTOQUEUE;Put into processing queue +SAVEDLG_PUTTOQUEUEHEAD;Put to the head of the processing queue +SAVEDLG_PUTTOQUEUETAIL;Put to the end of the processing queue +SAVEDLG_SAVEIMMEDIATELY;Save immediately +SAVEDLG_SAVESPP;Spara behandlingsparametrarna med bilderna +SAVEDLG_TIFFFILTER;TIFF-filer +TOOLBAR_TOOLTIP_CROP;Välj beskärningsomrÃ¥de (shortcut key: C) +TOOLBAR_TOOLTIP_HAND;Handverktyg (shortcut key: N) +TOOLBAR_TOOLTIP_STRAIGHTEN;Räta ut (shortcut key: S) +TOOLBAR_TOOLTIP_WB;Punkt-vitbalans (shortcut key: W) +TP_CACORRECTION_BLUE;BlÃ¥ +TP_CACORRECTION_LABEL;C/A justering +TP_CACORRECTION_RED;Röd +TP_CHMIXER_BLUE;BlÃ¥ +TP_CHMIXER_GREEN;Grön +TP_CHMIXER_LABEL;Kanalmixer +TP_CHMIXER_RED;Röd +TP_COARSETRAF_DEGREE;grad: +TP_COARSETRAF_TOOLTIP_HFLIP;Vänd horisontellt +TP_COARSETRAF_TOOLTIP_ROTLEFT;Rotera Ã¥t vänster +TP_COARSETRAF_TOOLTIP_ROTRIGHT;Rotera Ã¥t höger +TP_COARSETRAF_TOOLTIP_VFLIP;Vänd vertikalt +TP_COLORBOOST_ACHANNEL;kanal "a" +TP_COLORBOOST_AMOUNT;Mängd +TP_COLORBOOST_AVOIDCOLORCLIP;Undvik färgclipping +TP_COLORBOOST_BCHANNEL;kanal "b" +TP_COLORBOOST_CHAB;a & b +TP_COLORBOOST_CHANNEL;Kanal +TP_COLORBOOST_CHSEPARATE;separat +TP_COLORBOOST_ENABLESATLIMITER;Verkställ mättnadsgräns +TP_COLORBOOST_LABEL;Färgförstärkning +TP_COLORBOOST_SATLIMIT;Mättnadsgräns +TP_COLORDENOISE_EDGESENSITIVE;Kantkänslighet +TP_COLORDENOISE_EDGETOLERANCE;Kanttolerans +TP_COLORDENOISE_LABEL;Färgbrus-reducering +TP_COLORDENOISE_RADIUS;Radie +TP_COLORSHIFT_BLUEYELLOW;BlÃ¥-Gul +TP_COLORSHIFT_GREENMAGENTA;Grön-Magenta +TP_COLORSHIFT_LABEL;Färgskiftningar +TP_CROP_DPI;DPI= +TP_CROP_FIXRATIO;Fixa proportion +TP_CROP_GTDIAGONALS;Diagonalregeln +TP_CROP_GTHARMMEANS1;Harmonic means 1 +TP_CROP_GTHARMMEANS2;Harmonic means 2 +TP_CROP_GTHARMMEANS3;Harmonic means 3 +TP_CROP_GTHARMMEANS4;Harmonic means 4 +TP_CROP_GTNONE;Ingen +TP_CROP_GTRULETHIRDS;Tredjedelsregeln +TP_CROP_GUIDETYPE;Guidetyp: +TP_CROP_H;H +TP_CROP_LABEL;Beskär +TP_CROP_SELECTCROP; Välj beskärningsomrÃ¥de +TP_CROP_W;B +TP_CROP_X;x +TP_CROP_Y;y +TP_DISTORTION_AMOUNT;Mängd +TP_DISTORTION_LABEL;Distorsion +TP_EXPOSURE_AUTOLEVELS;AutonivÃ¥er +TP_EXPOSURE_BLACKLEVEL;Svart +TP_EXPOSURE_BRIGHTNESS;Ljusstyrka +TP_EXPOSURE_CLIP;Clip +TP_EXPOSURE_COMPRHIGHLIGHTS;Högdagerkomprimering +TP_EXPOSURE_COMPRSHADOWS;Skuggkomprimering +TP_EXPOSURE_CONTRAST;Kontrast +TP_EXPOSURE_CURVEEDITOR;Tonkurva +TP_EXPOSURE_EXPCOMP;Exp. Comp. +TP_EXPOSURE_LABEL;Exponering +TP_HLREC_CIELAB;CIELab Blending +TP_HLREC_COLOR;Färgspridning +TP_HLREC_LABEL;Högdager-förbättring +TP_HLREC_LUMINANCE;Bättring av luminans +TP_HLREC_METHOD;Metod: +TP_ICM_FILEDLGFILTERANY;Vilka filer som helst +TP_ICM_FILEDLGFILTERICM;ICC profilfiler +TP_ICM_GAMMABEFOREINPUT;Profile applies Gamma +TP_ICM_INPUTCAMERA;Kameraval +TP_ICM_INPUTCUSTOM;Egen +TP_ICM_INPUTDLGLABEL;Välj inmatnings ICC-profil... +TP_ICM_INPUTEMBEDDED;Använd inbäddad, om möjligt +TP_ICM_INPUTPROFILE;Inmatningsprofil +TP_ICM_LABEL;ICM +TP_ICM_NOICM;Ingen ICM: sRGB-utmatning +TP_ICM_OUTPUTDLGLABEL;Välj utmatnings ICC-profil... +TP_ICM_OUTPUTPROFILE;Utmatningsprofil +TP_ICM_SAVEREFERENCE;Save reference image for profiling +TP_ICM_WORKINGPROFILE;Arbetsprofil +TP_LUMACURVE_BLACKLEVEL;Svart +TP_LUMACURVE_BRIGHTNESS;Ljusstyrka +TP_LUMACURVE_COMPRHIGHLIGHTS;Högdagerkomprimering +TP_LUMACURVE_COMPRSHADOWS;Skuggkomprimering +TP_LUMACURVE_CONTRAST;Kontrast +TP_LUMACURVE_CURVEEDITOR;Luminanskurva +TP_LUMACURVE_LABEL;Luminanskurva +TP_LUMADENOISE_EDGETOLERANCE;Kanttolerans +TP_LUMADENOISE_LABEL;Luminans-brusreducering +TP_LUMADENOISE_RADIUS;Radie +TP_RESIZE_BICUBIC;Bicubic +TP_RESIZE_BICUBICSF;Bicubic (Mjukare) +TP_RESIZE_BICUBICSH;Bicubic (Skarpare) +TP_RESIZE_BILINEAR;Bilinjär +TP_RESIZE_FULLSIZE;Full bildstorlek: +TP_RESIZE_H;H: +TP_RESIZE_LABEL;Ändra storlek +TP_RESIZE_METHOD;Metod: +TP_RESIZE_NEAREST;Närmast +TP_RESIZE_SCALE;Skala +TP_RESIZE_W;B: +TP_ROTATE_AUTOCROP;Autobeskär +TP_ROTATE_DEGREE;Antal grader +TP_ROTATE_FILL;Fyll +TP_ROTATE_LABEL;Räta ut +TP_ROTATE_SELECTLINE; Välj rak linje +TP_SHADOWSHLIGHTS_HIGHLIGHTS;Högdager +TP_SHADOWSHLIGHTS_HLTONALW;Tonvidd +TP_SHADOWSHLIGHTS_LABEL;Skuggor/högdager +TP_SHADOWSHLIGHTS_LOCALCONTR;Lokal konstrast +TP_SHADOWSHLIGHTS_RADIUS;Radie +TP_SHADOWSHLIGHTS_SHADOWS;Skuggor +TP_SHADOWSHLIGHTS_SHTONALW;Tonvidd +TP_SHARPENING_AMOUNT;Mängd +TP_SHARPENING_EDRADIUS;Radie +TP_SHARPENING_EDTOLERANCE;Kanttolerans +TP_SHARPENING_HALOCONTROL;Halo-kontrol +TP_SHARPENING_HCAMOUNT;Mängd +TP_SHARPENING_LABEL;Skärpa +TP_SHARPENING_METHOD;Metod +TP_SHARPENING_ONLYEDGES;Skärp bara kanter +TP_SHARPENING_RADIUS;Radie +TP_SHARPENING_RLD;RL Deconvolution +TP_SHARPENING_RLD_AMOUNT;Mängd +TP_SHARPENING_RLD_DAMPING;Dämpning +TP_SHARPENING_RLD_ITERATIONS;Upprepningar +TP_SHARPENING_THRESHOLD;Tröskelvärde +TP_SHARPENING_USM;Oskarp mask +TP_VIGNETTING_AMOUNT;Mängd +TP_VIGNETTING_LABEL;Vinjettering-korrigering +TP_VIGNETTING_RADIUS;Radie +TP_WBALANCE_AUTO;Auto +TP_WBALANCE_CAMERA;Kamera +TP_WBALANCE_CUSTOM;Egen +TP_WBALANCE_GREEN;Nyans +TP_WBALANCE_LABEL;Vitbalans +TP_WBALANCE_METHOD;Metod +TP_WBALANCE_SIZE;Storlek: +TP_WBALANCE_SPOTWB;Punkt VB +TP_WBALANCE_TEMPERATURE;Temperatur +ZOOMBAR_DETAIL;Lupp +ZOOMBAR_HUGE;Enorm +ZOOMBAR_LARGE;Stor +ZOOMBAR_NORMAL;Normal +ZOOMBAR_PREVIEW;Förhandsvisning +ZOOMBAR_SCALE;Skala +ZOOMBAR_SMALL;Liten diff --git a/release/languages/turkish b/release/languages/turkish new file mode 100755 index 000000000..d1a07cf48 --- /dev/null +++ b/release/languages/turkish @@ -0,0 +1,577 @@ +# Turkish +# 2.3.2008 +# Oguz +ADJUSTER_RESET_TO_DEFAULT;Varsayılana dön +CURVEEDITOR_FILEDLGFILTERANY;Bütün dosyalar +CURVEEDITOR_FILEDLGFILTERCURVE;EÄŸri dosyaları +CURVEEDITOR_LINEAR;DoÄŸrusal +CURVEEDITOR_LOADDLGLABEL;EÄŸriyi yükle... +CURVEEDITOR_SAVEDLGLABEL;EÄŸriyi kaydet... +CURVEEDITOR_TOOLTIPLINEAR;EÄŸriyi düzelt +CURVEEDITOR_TOOLTIPLOAD;Kayıtlı bir eÄŸriyi yü +CURVEEDITOR_TOOLTIPSAVE;Kullanılan eÄŸriyi kaydet +EXIFFILTER_APERTURE;Aperture +EXIFFILTER_CAMERA;Camera +EXIFFILTER_DIALOGLABEL;Exif Filter +EXIFFILTER_FOCALLEN;Focal Length +EXIFFILTER_ISO;ISO +EXIFFILTER_LENS;Lens +EXIFFILTER_SHUTTER;Shutter +EXIFPANEL_ADDEDIT;Add/Edit +EXIFPANEL_ADDEDITHINT;Add new tag or edit tag +EXIFPANEL_ADDTAGDLG_ENTERVALUE;Enter value +EXIFPANEL_ADDTAGDLG_SELECTTAG;Select tag +EXIFPANEL_ADDTAGDLG_TITLE;Add/Edit Tag +EXIFPANEL_KEEP;Keep +EXIFPANEL_KEEPHINT;Keep the selected tags when writing output file +EXIFPANEL_REMOVE;Remove +EXIFPANEL_REMOVEHINT;Remove the selected tags when writing output file +EXIFPANEL_RESET;Reset +EXIFPANEL_RESETALL;Reset All +EXIFPANEL_RESETALLHINT;Reset all tags to their original values +EXIFPANEL_RESETHINT;Reset the selected tags to their original values +EXIFPANEL_SUBDIRECTORY;Subdirectory +FILEBROWSER_APPLYPROFILE;Apply profile +FILEBROWSER_ARRANGEMENTHINT;Change between vertical/horizontal alignment of thumbnails +FILEBROWSER_CLEARPROFILE;Clear profile +FILEBROWSER_COPYPROFILE;Copy profile +FILEBROWSER_DELETEDLGLABEL;File delete confirmation +FILEBROWSER_DELETEDLGMSG;Are you sure you want to delete the selected %1 files? +FILEBROWSER_EMPTYTRASH;Empty Trash +FILEBROWSER_EMPTYTRASHHINT;Permanently delete the files of the trash +FILEBROWSER_EXIFFILTERAPPLY;Apply +FILEBROWSER_EXIFFILTERAPPLYHINT;Switch on/off exif filter of the file browser +FILEBROWSER_EXIFFILTERLABEL;Exif Filter +FILEBROWSER_EXIFFILTERSETTINGS;Setup +FILEBROWSER_EXIFFILTERSETTINGSHINT;Change settings of the exif filter +FILEBROWSER_PARTIALPASTEPROFILE;Partial paste +FILEBROWSER_PASTEPROFILE;Paste profile +FILEBROWSER_POPUPCANCELJOB;Cancel job +FILEBROWSER_POPUPMOVEEND;Move to end of queue +FILEBROWSER_POPUPMOVEHEAD;Move to head of queue +FILEBROWSER_POPUPOPEN;Open +FILEBROWSER_POPUPPROCESS;Put to processing queue +FILEBROWSER_POPUPRANK1;Rank 1 +FILEBROWSER_POPUPRANK2;Rank 2 +FILEBROWSER_POPUPRANK3;Rank 3 +FILEBROWSER_POPUPRANK4;Rank 4 +FILEBROWSER_POPUPRANK5;Rank 5 +FILEBROWSER_POPUPREMOVE;Remove from filesystem +FILEBROWSER_POPUPRENAME;Rename +FILEBROWSER_POPUPSELECTALL;Select all +FILEBROWSER_POPUPTRASH;Move to trash +FILEBROWSER_POPUPUNRANK;Unrank +FILEBROWSER_POPUPUNTRASH;Remove from trash +FILEBROWSER_PROCESSINGSETTINGS;Settings +FILEBROWSER_PROCESSINGSETTINGSHINT;Set the file format and output directory +FILEBROWSER_RENAMEDLGLABEL;Rename file +FILEBROWSER_RENAMEDLGMSG;Rename file "%1" to: +FILEBROWSER_SHOWDIRHINT;Show all images of the directory +FILEBROWSER_SHOWQUEUEHINT;Show content of the processing queue +FILEBROWSER_SHOWRANK1HINT;Show images ranked as 1 star +FILEBROWSER_SHOWRANK2HINT;Show images ranked as 2 star +FILEBROWSER_SHOWRANK3HINT;Show images ranked as 3 star +FILEBROWSER_SHOWRANK4HINT;Show images ranked as 4 star +FILEBROWSER_SHOWRANK5HINT;Show images ranked as 5 star +FILEBROWSER_SHOWTRASHHINT;Show content of the trash +FILEBROWSER_SHOWUNRANKHINT;Show unranked images +FILEBROWSER_STARTPROCESSING;Start Processing +FILEBROWSER_STARTPROCESSINGHINT;Start processing/saving of images in the queue +FILEBROWSER_STOPPROCESSING;Stop processing +FILEBROWSER_STOPPROCESSINGHINT;Stop processing of images +FILEBROWSER_THUMBSIZE;Thumb. size +FILEBROWSER_ZOOMINHINT;Increase thumbnail size +FILEBROWSER_ZOOMOUTHINT;Decrease thumbnail size +GENERAL_ABOUT;Hakkında +GENERAL_CANCEL;İptal +GENERAL_DISABLE;EtkisizleÅŸtir +GENERAL_DISABLED;Devre dışı +GENERAL_ENABLE;EtkinleÅŸtir +GENERAL_ENABLED;Etkin +GENERAL_LANDSCAPE;Yatay +GENERAL_LOAD;Yükle +GENERAL_NA;Uygun deÄŸil +GENERAL_NO;Hayır +GENERAL_OK;Tamam +GENERAL_PORTRAIT;Dikey +GENERAL_SAVE;Kaydet +GENERAL_YES;Evet +HISTOGRAM_LABEL;Histogram +HISTOGRAM_TOOLTIP_B;Mavi histogramını göster/gizle +HISTOGRAM_TOOLTIP_G;YeÅŸil histogramını göster/gizle +HISTOGRAM_TOOLTIP_L;CIELAB aydınlık histogramını göster/gizle +HISTOGRAM_TOOLTIP_R;Kırmızı histogramını göster/gizle +HISTORY_CHANGED;Changed +HISTORY_CUSTOMCURVE;Özel eÄŸri +HISTORY_DELSNAPSHOT;ÅžipÅŸağı sil +HISTORY_FROMCLIPBOARD;From clipboard +HISTORY_LABEL;GeçmiÅŸ +HISTORY_MSG_10;Karaltı sıkıştırma +HISTORY_MSG_11;Ton eÄŸrisi +HISTORY_MSG_12;Otomatik pozlama +HISTORY_MSG_13;Pozlama kırpma +HISTORY_MSG_14;Aydınlık - parlaklık +HISTORY_MSG_15;Aydınlık - zıtlık +HISTORY_MSG_16;Aydınlık - siyah +HISTORY_MSG_17;Aydınlık - parıltı sıkıştırma +HISTORY_MSG_18;Aydınlık - karaltı sıkıştırma +HISTORY_MSG_19;Aydınlık eÄŸrisi +HISTORY_MSG_1;FotoÄŸraf yüklendi +HISTORY_MSG_20;KeskinleÅŸtirme +HISTORY_MSG_21;KeskinleÅŸtirme - çap +HISTORY_MSG_22;KeskinleÅŸtirme - miktar +HISTORY_MSG_23;KeskinleÅŸtirme - eÅŸik +HISTORY_MSG_24;Sadece kenarları keskinleÅŸtir +HISTORY_MSG_25;KeskinleÅŸtirme - kenar bulma kuralları +HISTORY_MSG_26;KeskinleÅŸtirme - kenar payı +HISTORY_MSG_27;KeskinleÅŸtirme - hale denetimi +HISTORY_MSG_28;Hale denetimi - miktar +HISTORY_MSG_29;KeskinleÅŸtirme - yöntem +HISTORY_MSG_2;Profil yüklendi +HISTORY_MSG_30;Ters evriÅŸim - çap +HISTORY_MSG_31;Ters evriÅŸim - miktar +HISTORY_MSG_32;Ters evriÅŸim - düşürme +HISTORY_MSG_33;Ters evriÅŸim - yineleme +HISTORY_MSG_34;Renk kırpmayı önle +HISTORY_MSG_35;Doygunluk kısıtlayıcı +HISTORY_MSG_36;Doygunluk sınırı +HISTORY_MSG_37;Renk iteleme +HISTORY_MSG_38;Beyaz ayarı - yöntem +HISTORY_MSG_39;Renk ısısı +HISTORY_MSG_3;Profil deÄŸiÅŸti +HISTORY_MSG_40;Beyaz ayarı - tint +HISTORY_MSG_41;"A" renk kayması +HISTORY_MSG_42;"B" kayması +HISTORY_MSG_43;Aydınlık gürültü giderme +HISTORY_MSG_44;Aydınlık gürültü giderme - çap +HISTORY_MSG_45;Aydınlık gürültü giderme - kenar payı +HISTORY_MSG_46;Renk gürültü giderme +HISTORY_MSG_47;Renk gürültü giderme - çap +HISTORY_MSG_48;Renk gürültü giderme - kenar payı +HISTORY_MSG_49;Kenar duyarlı renk gürültüsü giderme +HISTORY_MSG_4;GeçmiÅŸte gezinti +HISTORY_MSG_50;Karaltı/parıltı aracı +HISTORY_MSG_51;Parıltı iteleme +HISTORY_MSG_52;Karaltı iteleme +HISTORY_MSG_53;Parıltı - ton geniÅŸliÄŸi +HISTORY_MSG_54;Karaltı - ton geniÅŸliÄŸi +HISTORY_MSG_55;Bölgesel zıtlık +HISTORY_MSG_56;Karaltı/parıltı - zıtlık +HISTORY_MSG_57;Döndürme +HISTORY_MSG_58;Yatayda çevirme +HISTORY_MSG_59;Dikeyde çevirme +HISTORY_MSG_5;Parlaklık +HISTORY_MSG_60;Döndürme +HISTORY_MSG_61;Döndürme +HISTORY_MSG_62;Lens bükülmesi düzeltme +HISTORY_MSG_63;Yer imi seçildi +HISTORY_MSG_64;FotoÄŸrafı kırp +HISTORY_MSG_65;Renk kayması düzeltme +HISTORY_MSG_66;Parıltı kurtarma +HISTORY_MSG_67;Parıltı kurtarma - miktar +HISTORY_MSG_68;Parıltı kurtarma - yöntem +HISTORY_MSG_69;Çalışma renk uzayı +HISTORY_MSG_6;Zıtlık +HISTORY_MSG_70;Çıktı renk uzayı +HISTORY_MSG_71;Girdi renk uzayı +HISTORY_MSG_72;Çerçeve etkisi düzeltme +HISTORY_MSG_73;Kanal karıştırıcı +HISTORY_MSG_74;Yeniden boyutlandırma - ölçek +HISTORY_MSG_75;Yeniden boyutlandırma - yöntem +HISTORY_MSG_76;Exif Metadata +HISTORY_MSG_77;IPTC Metadata +HISTORY_MSG_7;Siyah +HISTORY_MSG_8;Pozlama telafisi +HISTORY_MSG_9;Parıltı sıkıştırma +HISTORY_NEWSNAPSHOT;Yeni ÅŸipÅŸak +HISTORY_NEWSNAPSHOTAS;... olarak +HISTORY_NEWSSDIALOGLABEL;ÅžipÅŸak etiketi: +HISTORY_NEWSSDIALOGTITLE;Yeni ÅŸipÅŸak ekle +HISTORY_SETTO;Belirle +HISTORY_SNAPSHOT;ÅžipÅŸak +HISTORY_SNAPSHOTS;ÅžipÅŸaklar +ICMPANEL_FILEDLGFILTERANY;Bütün dosyalar +ICMPANEL_FILEDLGFILTERICM;ICC profil dosyaları +ICMPANEL_GAMMABEFOREINPUT;Profile applies Gamma +ICMPANEL_INPUTCAMERA;Kamera varsayılanı +ICMPANEL_INPUTCUSTOM;Özel +ICMPANEL_INPUTDLGLABEL;Girdi ICC profilini seç... +ICMPANEL_INPUTEMBEDDED;Mümkün olduÄŸunda gömülü profili kullan +ICMPANEL_INPUTPROFILE;Girdi Profili +ICMPANEL_NOICM;No ICM: sRGB çıktı +ICMPANEL_OUTPUTDLGLABEL;Çıktı ICC profilini seç... +ICMPANEL_OUTPUTPROFILE;Çıktı profili +ICMPANEL_SAVEREFERENCE;Save reference image for profiling +ICMPANEL_WORKINGPROFILE;Çalışma profili +IMAGEAREA_DETAILVIEW;Detay görünümü +IPTCPANEL_AUTHOR;Author +IPTCPANEL_AUTHORHINT;Name of the creator of the object, e.g. writer, photographer or graphic artist (By-line). +IPTCPANEL_AUTHORSPOSITION;Author's position +IPTCPANEL_AUTHORSPOSITIONHINT;Title of the creator or creators of the object (By-line Title). +IPTCPANEL_CAPTION;Caption +IPTCPANEL_CAPTIONHINT;A textual description of the data (Caption - Abstract). +IPTCPANEL_CAPTIONWRITER;Caption Writer +IPTCPANEL_CAPTIONWRITERHINT;The name of the person involved in the writing, editing or correcting the image or caption/abstract (Writer - Editor). +IPTCPANEL_CATEGORY;Category +IPTCPANEL_CATEGORYHINT;Identifies the subject of the image in the opinion of the provider (Category). +IPTCPANEL_CITY;City +IPTCPANEL_CITYHINT;City of image origin (City). +IPTCPANEL_COPYHINT;Copy IPTC settings to clipboard +IPTCPANEL_COPYRIGHT;Copyright +IPTCPANEL_COPYRIGHTHINT;Any necessary copyright notice (Copyright Notice). +IPTCPANEL_COUNTRY;Country +IPTCPANEL_COUNTRYHINT;The name of the country/primary location where the image was created (Country - Primary Location Name). +IPTCPANEL_CREDIT;Credit +IPTCPANEL_CREDITHINT;Identifies the provider of the image, not necessarily the owner/creator (Credit). +IPTCPANEL_DATECREATED;Date Created +IPTCPANEL_DATECREATEDHINT;The date the intellectual content of the image was created; Format: JJJJMMTT (Date Created). +IPTCPANEL_EMBEDDED;Embedded +IPTCPANEL_EMBEDDEDHINT;Reset to IPTC data embedded in the image file +IPTCPANEL_HEADLINE;Headline +IPTCPANEL_HEADLINEHINT;A publishable entry providing a synopsis of the contents of the image (Headline). +IPTCPANEL_INSTRUCTIONS;Instructions +IPTCPANEL_INSTRUCTIONSHINT;Other editorial instructions concerning the use of the image (Special Instructions). +IPTCPANEL_KEYWORDS;Keywords +IPTCPANEL_KEYWORDSHINT;Used to indicate specific information retrieval words (Keywords). +IPTCPANEL_PASTEHINT;Paste IPTC settings from clipboard +IPTCPANEL_PROVINCE;Province +IPTCPANEL_PROVINCEHINT;The Province/State where the image originates (Province-State). +IPTCPANEL_RESET;Reset +IPTCPANEL_RESETHINT;Reset to profile default +IPTCPANEL_SOURCE;Source +IPTCPANEL_SOURCEHINT;The original owner of the intellectual content of the image (Source). +IPTCPANEL_SUPPCATEGORIES;Suppl. Categories +IPTCPANEL_SUPPCATEGORIESHINT;Further refines the subject of the image (Supplemental Categories). +IPTCPANEL_TITLE;Title +IPTCPANEL_TITLEHINT;A shorthand reference for the image (Object Name). +IPTCPANEL_TRANSREFERENCE;Trans. Reference +IPTCPANEL_TRANSREFERENCEHINT;A code representing the location of original transmission (Original Transmission Reference). +MAIN_BUTTON_PREFERENCES;Seçenekler +MAIN_BUTTON_SAVE;Görüntüyü kaydet +MAIN_BUTTON_SAVEAS;... olarak +MAIN_BUTTON_SENDTOEDITOR;Send to editor +MAIN_MSG_ALREADYEXISTS;Dosya zaten var. +MAIN_MSG_CANNOTLOAD;Görüntü yüklenemiyor +MAIN_MSG_CANNOTSAVE;Dosya kaydetmede hata +MAIN_MSG_CANNOTSTARTEDITOR;Can not start editor. +MAIN_MSG_CANNOTSTARTEDITOR_SECONDARY;Please set the correct path in the "Preferences" dialog. +MAIN_MSG_EXITJOBSINQUEUEINFO;Unprocessed images in the queue will be lost on exit. +MAIN_MSG_EXITJOBSINQUEUEQUEST;Are you sure you want to exit? There are unprocessed images waiting in the queue. +MAIN_MSG_JOBSINQUEUE;iÅŸ sırada +MAIN_MSG_QOVERWRITE;Üzerine yazmak ister misiniz? +MAIN_TAB_BASIC;Temel +MAIN_TAB_COLOR;Color +MAIN_TAB_DETAIL;Detail +MAIN_TAB_EXIF;Exif +MAIN_TAB_EXPOSURE;Exposure +MAIN_TAB_ICM;Renk yönetimi +MAIN_TAB_IPTC;IPTC +MAIN_TAB_METADATA;Metadata +MAIN_TAB_TRANSFORM;Dönüşüm +MAIN_TOOLTIP_HIDEFP;Alt tablayı göster/gizle (dizin ve dosya gezgni, shortcut key: F) +MAIN_TOOLTIP_HIDEHP;Sol tablayı göster/gizle (geçmiÅŸ ile birlikte, shortcut key: H) +MAIN_TOOLTIP_INDCLIPPEDH;Kırpılmış parıltı gösterme +MAIN_TOOLTIP_INDCLIPPEDS;Kırpılmış karaltı gösterme +MAIN_TOOLTIP_PREFERENCES;Seçenekleri belirle +MAIN_TOOLTIP_QINFO;Görüntü hakkında kısa bilgi +MAIN_TOOLTIP_SAVE;Görüntüyü varsayılan klasöre kaydet +MAIN_TOOLTIP_SAVEAS;Görüntüyü seçili klasöre kaydet +PARTIALPASTE_BASICGROUP;Basic settings +PARTIALPASTE_CACORRECTION;C/A correction +PARTIALPASTE_COARSETRANS;90 deg rotation / flipping +PARTIALPASTE_COLORBOOST;Color boost +PARTIALPASTE_COLORDENOISE;Color denoise +PARTIALPASTE_COLORGROUP;Color related settings +PARTIALPASTE_COLORMIXER;Color mixer +PARTIALPASTE_COLORSHIFT;Color shift +PARTIALPASTE_COMPOSITIONGROUP;Composition settings +PARTIALPASTE_CROP;Crop +PARTIALPASTE_DIALOGLABEL;Partial paste processing profile +PARTIALPASTE_DISTORTION;Distortion correction +PARTIALPASTE_EXIFCHANGES;Changes to exif data +PARTIALPASTE_EXPOSURE;Exposure +PARTIALPASTE_HLRECOVERY;Highlight recovery +PARTIALPASTE_ICMSETTINGS;ICM settings +PARTIALPASTE_IPTCINFO;IPTC info +PARTIALPASTE_LENSGROUP;Lens related settings +PARTIALPASTE_LUMACURVE;Luminance curve +PARTIALPASTE_LUMADENOISE;Luminance noise reduction +PARTIALPASTE_LUMINANCEGROUP;Luminance related settings +PARTIALPASTE_METAICMGROUP;Metadata/ICM settings +PARTIALPASTE_RESIZE;Resize +PARTIALPASTE_ROTATION;Rotation +PARTIALPASTE_SHADOWSHIGHLIGHTS;Shadows/Highlights +PARTIALPASTE_SHARPENING;Sharpening +PARTIALPASTE_VIGNETTING;Vignetting correction +PARTIALPASTE_WHITEBALANCE;White balance +PREFERENCES_APPLNEXTSTARTUP;Bir sonraki baÅŸlamada uygulacacak. +PREFERENCES_BLINKCLIPPED;Kırpılan alanlar yanıp-sönsün +PREFERENCES_CACHECLEARALL;Clear All +PREFERENCES_CACHECLEARPROFILES;Clear Profiles +PREFERENCES_CACHECLEARTHUMBS;Clear Thumbnails +PREFERENCES_CACHEFORMAT1;Proprietary (faster and better quality) +PREFERENCES_CACHEFORMAT2;JPEG (smaller disk footprint) +PREFERENCES_CACHEMAXENTRIES;Maximal Number of Cache Entries +PREFERENCES_CACHEOPTS;Cache Options +PREFERENCES_CACHESTRAT1;Prefer Speed to Low Memory Consumption +PREFERENCES_CACHESTRAT2;Prefer Low Memory Consumption to Speed +PREFERENCES_CACHESTRAT;Cache Strategy +PREFERENCES_CACHETHUMBFORM;Cache Thumbnail Format +PREFERENCES_CACHETHUMBHEIGHT;Maximal Thumbnail Height +PREFERENCES_CLEARDLG_LINE1;Clearing cache +PREFERENCES_CLEARDLG_LINE2;This may take a few seconds. +PREFERENCES_CLEARDLG_TITLE;Please wait +PREFERENCES_CLIPPINGIND;Kırpma gösterme +PREFERENCES_CMETRICINTENT;Renkölçer +PREFERENCES_DATEFORMAT;Tarih biçimi +PREFERENCES_DATEFORMATHINT;You can use the following formatting strings:\n%y : year\n%m : month\n%d : day\n\nFor example, the hungarian date format is:\n%y/%m/%d +PREFERENCES_DEFAULTLANG;Varsayılan dil +PREFERENCES_DEFAULTTHEME;Default theme +PREFERENCES_DEMOSAICINGALGO;Demozaikleme algoritması +PREFERENCES_DIRHOME;Kullanıcı dizini +PREFERENCES_DIRLAST;Son gidilen dizin +PREFERENCES_DIROTHER;DiÄŸer +PREFERENCES_DIRSELECTDLG;BaÅŸlangıç görüntü dizinini seç... +PREFERENCES_DIRSOFTWARE;Kurulum dizini +PREFERENCES_DMETHOD;Yöntem +PREFERENCES_EDITORCMDLINE;Other command line +PREFERENCES_EXTERNALEDITOR;External editor +PREFERENCES_FALSECOLOR;Hatalı-renk bastırma deÄŸerleri +PREFERENCES_FBROWSEROPTS;Dosya gezgini seçenekleri +PREFERENCES_FILEFORMAT;Dosya biçimi +PREFERENCES_FORIMAGE;Gürüntü dosyaları için +PREFERENCES_FORRAW;RAW dosyaları için +PREFERENCES_GIMPPATH;GIMP installation directory +PREFERENCES_GTKTHEME;GTK default +PREFERENCES_HINT;İpucu +PREFERENCES_HLTHRESHOLD;Kırpılmış parıltılar için eÅŸik +PREFERENCES_ICCDIR;ICC profilleri dizini +PREFERENCES_IMPROCPARAMS;Varsayılan görüntü iÅŸleme deÄŸiÅŸkenleri +PREFERENCES_INTENT_ABSOLUTE;Mutlak +PREFERENCES_INTENT_PERCEPTUAL;Algısal +PREFERENCES_INTENT_RELATIVE;Bağıl +PREFERENCES_INTENT_SATURATION;Doyum +PREFERENCES_LIVETHUMBNAILS;Live Thumbnails (slower) +PREFERENCES_MONITORICC;Ekran profili +PREFERENCES_OUTDIR;Çıktı dizini +PREFERENCES_OUTDIRFOLDER;Save to folder +PREFERENCES_OUTDIRFOLDERHINT;Put the saved images to the seledted folder +PREFERENCES_OUTDIRHINT;You can use the following formatting strings:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nThese formatting strings refer to the directories and sub-paths of the path of the raw file.\n\nFor example, if /home/tom/image/02-09-2006/dsc0012.nefhas been opened, the meaning of the formatting strings are:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nIf you want to save the output image where the original is, write:\n%p1/%f\n\nIf you want to save the output image in a directory 'converted' located the directory of the original, write:\n%p1/converted/%f\n\nIf you want to save the output image in directory '/home/tom/converted' with keeping the same subdirectory of dates, write:\n%p2/converted/%d1/%f +PREFERENCES_OUTDIRTEMPLATE;Use Template +PREFERENCES_OUTDIRTEMPLATEHINT;You can use the following formatting strings:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nThese formatting strings refer to the directories and sub-paths of the path of the raw file.\n\nFor example, if /home/tom/image/02-09-2006/dsc0012.nefhas been opened, the meaning of the formatting strings are:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\nIf you want to save the output image where the original is, write:\n%p1/%f\n\nIf you want to save the output image in a directory 'converted' located the directory of the original, write:\n%p1/converted/%f\n\nIf you want to save the output image in directory '/home/tom/converted' with keeping the same subdirectory of dates, write:\n%p2/converted/%d1/%f +PREFERENCES_PARSEDEXT;Parsed Extensions +PREFERENCES_PARSEDEXTADD;Add Extension +PREFERENCES_PARSEDEXTADDHINT;Type an extension and press this button to append list +PREFERENCES_PARSEDEXTDELHINT;Delete selected extension from the list +PREFERENCES_PROFILEHANDLING;Processing Profile Handling +PREFERENCES_PROFILELOADPR;Profile Loading Priority +PREFERENCES_PROFILEPRCACHE;Profile in Cache +PREFERENCES_PROFILEPRFILE;Profile Next to the Input File +PREFERENCES_PROFILESAVECACHE;Save Processing Parameters to the Cache +PREFERENCES_PROFILESAVEINPUT;Save Processing Parameters Next to the Input File +PREFERENCES_PSPATH;Adobe Photoshop installation directory +PREFERENCES_SELECTICCDIRDLG;ICC profil dizinini seç... +PREFERENCES_SELECTLANG;Dil seç +PREFERENCES_SELECTMONITORPROFDLG;Ekrana ait ICC profilini seç... +PREFERENCES_SELECTTHEME;Select theme +PREFERENCES_SHOWBASICEXIF;Temel exif bilgisini göster +PREFERENCES_SHOWDATETIME;Tarih ve saati göster +PREFERENCES_SHOWONLYRAW;Sadece RAW dosyalarını göster +PREFERENCES_SHTHRESHOLD;Kırpılmış karaltılar için eÅŸik +PREFERENCES_STARTUPIMDIR;BaÅŸlangıç görüntü dizini +PREFERENCES_TAB_BROWSER;Dosya gezgini +PREFERENCES_TAB_COLORMGR;Renk yönetimi +PREFERENCES_TAB_GENERAL;Genel +PREFERENCES_TAB_IMPROC;Görüntü iÅŸleme +PREFERENCES_TAB_OUTPUT;Çıktı seçenekleri +PREFERENCES_THUMBSIZE;Küçük-resim boyutu +PROFILEPANEL_FILEDLGFILTERANY;Bütün dosyalar +PROFILEPANEL_FILEDLGFILTERPP;Art-iÅŸleme profilleri +PROFILEPANEL_LABEL;Art-iÅŸleme profilleri +PROFILEPANEL_LOADDLGLABEL;Art-iÅŸleme deÄŸiÅŸkenlerini yükle... +PROFILEPANEL_PCUSTOM;Özel +PROFILEPANEL_PFILE;Dosyadan +PROFILEPANEL_PLASTPHOTO;Son FotoÄŸraf +PROFILEPANEL_PLASTSAVED;Son kaydedilen +PROFILEPANEL_PROFILE;Profil +PROFILEPANEL_SAVEDLGLABEL;Art-iÅŸleme deÄŸiÅŸkenlerini kaydet... +PROFILEPANEL_TOOLTIPCOPY;Copy current profile to clipboard +PROFILEPANEL_TOOLTIPLOAD;Kayıtlı bir profil yükle +PROFILEPANEL_TOOLTIPPASTE; Paste profile from clipboard +PROFILEPANEL_TOOLTIPSAVE;Geçerli profili kaydet +PROGRESSBAR_DECODING;Raw dosyası açılıyor... +PROGRESSBAR_DEMOSAICING;Demozaikleniyor... +PROGRESSBAR_LOADING;Görüntü yükleniyor... +PROGRESSBAR_LOADJPEG;JPEG dosyası yükleniyor... +PROGRESSBAR_LOADPNG;PNG dosyası yükleniyor... +PROGRESSBAR_LOADTIFF;TIFF dosyası yükleniyor... +PROGRESSBAR_PROCESSING;Görüntü iÅŸleniyor... +PROGRESSBAR_READY;Hazır. +PROGRESSBAR_SAVEJPEG;JPEG dosyası kaydediliyor... +PROGRESSBAR_SAVEPNG;PNG dosyası kaydediliyor... +PROGRESSBAR_SAVETIFF;TIFF dosyası kaydediliyor... +PROGRESSDLG_LOADING;Loading file... +PROGRESSDLG_PROCESSING;Processing image... +PROGRESSDLG_SAVING;Saving file... +QINFO_FOCALLENGTH;Odak uzunluÄŸu +QINFO_ISO;ISO +QINFO_LENS;Lens +QINFO_NOEXIF;Exif bilgisi yok. +SAVEDLG_FILEFORMAT;Dosya biçimi +SAVEDLG_JPEGQUAL;JPEG kalitesi +SAVEDLG_JPGFILTER;JPEG dosyaları +SAVEDLG_PNGCOMPR;PNG sıkıştırma düzeyi +SAVEDLG_PNGFILTER;PNG dosyaları +SAVEDLG_PUTTOQUEUE;Put into processing queue +SAVEDLG_PUTTOQUEUEHEAD;Put to the head of the processing queue +SAVEDLG_PUTTOQUEUETAIL;Put to the end of the processing queue +SAVEDLG_SAVEIMMEDIATELY;Save immediately +SAVEDLG_SAVESPP;İşeme deÄŸiÅŸkenlerini görüntü ile birlikte kaydet +SAVEDLG_TIFFFILTER;TIFF dosyaları +TOOLBAR_TOOLTIP_CROP;Seçimi kırp (shorcut key: C) +TOOLBAR_TOOLTIP_HAND;El aracı (shortcut key: N) +TOOLBAR_TOOLTIP_STRAIGHTEN;Düz çizgi seçimi (shortcut key: S) +TOOLBAR_TOOLTIP_WB;Nokta beyaz ayarı (shortcut key: W) +TP_CACORRECTION_BLUE;Mavi +TP_CACORRECTION_LABEL;Renk sapması düzeltme +TP_CACORRECTION_RED;Kırmızı +TP_CHMIXER_BLUE;Mavi +TP_CHMIXER_GREEN;YeÅŸil +TP_CHMIXER_LABEL;Kanal karıştırıcı +TP_CHMIXER_RED;Kırmızı +TP_COARSETRAF_DEGREE;açı: +TP_COARSETRAF_TOOLTIP_HFLIP;Yatayda çevir +TP_COARSETRAF_TOOLTIP_ROTLEFT;Sola döndür +TP_COARSETRAF_TOOLTIP_ROTRIGHT;SaÄŸa döndür +TP_COARSETRAF_TOOLTIP_VFLIP;Dikeyde çevir +TP_COLORBOOST_ACHANNEL;"a" kanalı +TP_COLORBOOST_AMOUNT;Miktar +TP_COLORBOOST_AVOIDCOLORCLIP;Renk kırpılasını önle +TP_COLORBOOST_BCHANNEL;"b" kanalı +TP_COLORBOOST_CHAB;a ve b +TP_COLORBOOST_CHANNEL;Kanal +TP_COLORBOOST_CHSEPARATE;ayrık +TP_COLORBOOST_ENABLESATLIMITER;Doygunluk sınırlamayı etkinleÅŸtir +TP_COLORBOOST_LABEL;Renk iteleme +TP_COLORBOOST_SATLIMIT;Doygunluk sınırı +TP_COLORDENOISE_EDGESENSITIVE;Kenar duyarlı +TP_COLORDENOISE_EDGETOLERANCE;Kenar payı +TP_COLORDENOISE_LABEL;Renk gürültüsü azaltma +TP_COLORDENOISE_RADIUS;Çap +TP_COLORSHIFT_BLUEYELLOW;Mavi-sarı +TP_COLORSHIFT_GREENMAGENTA;YeÅŸil-macenta +TP_COLORSHIFT_LABEL;Renk kayması +TP_CROP_DPI;DPI= +TP_CROP_FIXRATIO;En-boy oranını düzelt: +TP_CROP_GTDIAGONALS;Çaprazlar kuralı +TP_CROP_GTHARMMEANS1;Harmonik ortalamalar 1 +TP_CROP_GTHARMMEANS2;Harmonik ortalamalar 2 +TP_CROP_GTHARMMEANS3;Harmonik ortalamalar 3 +TP_CROP_GTHARMMEANS4;Harmonik ortalamalar 4 +TP_CROP_GTNONE;Yok +TP_CROP_GTRULETHIRDS;Üçler kuralı +TP_CROP_GUIDETYPE;Kılavuz türü: +TP_CROP_H;Y +TP_CROP_LABEL;Kırp +TP_CROP_SELECTCROP; Kırpma alanı seç +TP_CROP_W;G +TP_CROP_X;x +TP_CROP_Y;y +TP_DISTORTION_AMOUNT;Miktar +TP_DISTORTION_LABEL;Bükme +TP_EXPOSURE_AUTOLEVELS;Otomatik seviyeler +TP_EXPOSURE_BLACKLEVEL;Siyah +TP_EXPOSURE_BRIGHTNESS;Parlaklık +TP_EXPOSURE_CLIP;Kırpma +TP_EXPOSURE_COMPRHIGHLIGHTS;Parıltı sıkıştırma +TP_EXPOSURE_COMPRSHADOWS;Karaltı sıkıştırma +TP_EXPOSURE_CONTRAST;Zıtlık +TP_EXPOSURE_CURVEEDITOR;Ton eÄŸrisi +TP_EXPOSURE_EXPCOMP;Poz. telafisi +TP_EXPOSURE_LABEL;Pozlama +TP_HLREC_CIELAB;CIELab Blending +TP_HLREC_COLOR;Renk yayılımı +TP_HLREC_LABEL;Parıltı kurtarma +TP_HLREC_LUMINANCE;Aydınlık kurtarma +TP_HLREC_METHOD;Yöntem: +TP_ICM_FILEDLGFILTERANY;Bütün dosyalar +TP_ICM_FILEDLGFILTERICM;ICC profil dosyaları +TP_ICM_GAMMABEFOREINPUT;Profile applies Gamma +TP_ICM_INPUTCAMERA;Kamera varsayılanı +TP_ICM_INPUTCUSTOM;Özel +TP_ICM_INPUTDLGLABEL;Girdi ICC profilini seç... +TP_ICM_INPUTEMBEDDED;Mümkün olduÄŸunda gömülü profili kullan +TP_ICM_INPUTPROFILE;Girdi Profili +TP_ICM_LABEL;ICM +TP_ICM_NOICM;No ICM: sRGB çıktı +TP_ICM_OUTPUTDLGLABEL;Çıktı ICC profilini seç... +TP_ICM_OUTPUTPROFILE;Çıktı profili +TP_ICM_SAVEREFERENCE;Save reference image for profiling +TP_ICM_WORKINGPROFILE;Çalışma profili +TP_LUMACURVE_BLACKLEVEL;Siyah +TP_LUMACURVE_BRIGHTNESS;Parlaklık +TP_LUMACURVE_COMPRHIGHLIGHTS;Parıltı sıkıştırma +TP_LUMACURVE_COMPRSHADOWS;Karaltı sıkıştırma +TP_LUMACURVE_CONTRAST;Zıtlık +TP_LUMACURVE_CURVEEDITOR;Aydınlık eÄŸrisi +TP_LUMACURVE_LABEL;Aydınlık eÄŸrisi +TP_LUMADENOISE_EDGETOLERANCE;Kenar payı +TP_LUMADENOISE_LABEL;Aydınlık gürültüsü azaltma +TP_LUMADENOISE_RADIUS;Çap +TP_RESIZE_BICUBIC;Bikübik +TP_RESIZE_BICUBICSF;Bikübik (yumuÅŸak) +TP_RESIZE_BICUBICSH;Bikübik (keskin) +TP_RESIZE_BILINEAR;Çift-doÄŸrusal +TP_RESIZE_FULLSIZE;Tam gürüntü boyutu: +TP_RESIZE_H;Y: +TP_RESIZE_LABEL;Boyutları deÄŸiÅŸtir +TP_RESIZE_METHOD;Yöntem: +TP_RESIZE_NEAREST;En yakın +TP_RESIZE_SCALE;Ölçekle +TP_RESIZE_W;G: +TP_ROTATE_AUTOCROP;Otomatik kırpma +TP_ROTATE_DEGREE;Açı +TP_ROTATE_FILL;Doldur +TP_ROTATE_LABEL;Döndür +TP_ROTATE_SELECTLINE; Düz çizgi seç +TP_SHADOWSHLIGHTS_HIGHLIGHTS;Parıltılar +TP_SHADOWSHLIGHTS_HLTONALW;Tonsal geniÅŸlik +TP_SHADOWSHLIGHTS_LABEL;Karaltılar/parıltılar +TP_SHADOWSHLIGHTS_LOCALCONTR;Bölgesel zıtlık +TP_SHADOWSHLIGHTS_RADIUS;Çap +TP_SHADOWSHLIGHTS_SHADOWS;Karaltılar +TP_SHADOWSHLIGHTS_SHTONALW;Tonsal geniÅŸlik +TP_SHARPENING_AMOUNT;Miktar +TP_SHARPENING_EDRADIUS;Çap +TP_SHARPENING_EDTOLERANCE;Kenar payı +TP_SHARPENING_HALOCONTROL;Hale denetimi +TP_SHARPENING_HCAMOUNT;Miktar +TP_SHARPENING_LABEL;KeskinleÅŸtirme +TP_SHARPENING_METHOD;Yöntem +TP_SHARPENING_ONLYEDGES;Sadece kenarları keskinleÅŸtir +TP_SHARPENING_RADIUS;Çap +TP_SHARPENING_RLD;R-L Ters evriÅŸimi +TP_SHARPENING_RLD_AMOUNT;Miktar +TP_SHARPENING_RLD_DAMPING;Düşürme +TP_SHARPENING_RLD_ITERATIONS;Yineleme +TP_SHARPENING_THRESHOLD;EÅŸik +TP_SHARPENING_USM;Bulanıklık Maskesi +TP_VIGNETTING_AMOUNT;Miktar +TP_VIGNETTING_LABEL;Çerçeve etkisi giderme +TP_VIGNETTING_RADIUS;Çap +TP_WBALANCE_AUTO;Otomatik +TP_WBALANCE_CAMERA;Kamera +TP_WBALANCE_CUSTOM;Özel +TP_WBALANCE_GREEN;Tint +TP_WBALANCE_LABEL;Beyaz ayarı +TP_WBALANCE_METHOD;Yöntem +TP_WBALANCE_SIZE;Boyut: +TP_WBALANCE_SPOTWB;Spot BA +TP_WBALANCE_TEMPERATURE;Isı +ZOOMBAR_DETAIL;Detay +ZOOMBAR_HUGE;Devasa +ZOOMBAR_LARGE;Büyük +ZOOMBAR_NORMAL;Normal +ZOOMBAR_PREVIEW;Önizleme +ZOOMBAR_SCALE;Ölçek +ZOOMBAR_SMALL;Küçük diff --git a/release/profiles/crisp.pp2 b/release/profiles/crisp.pp2 new file mode 100755 index 000000000..b49fe52b4 --- /dev/null +++ b/release/profiles/crisp.pp2 @@ -0,0 +1,124 @@ + +[Version] +Version=231 + +[Exposure] +Auto=true +Clip=0.02 +Compensation=0 +Brightness=0 +Contrast=12 +Black=0 +HighlightCompr=100 +ShadowCompr=100 +Curve=1;0;0;1;1; + +[Channel Mixer] +Red=100;0;0; +Green=0;100;0; +Blue=0;0;100; + +[Luminance Curve] +Brightness=0 +Contrast=0 +Black=0 +HighlightCompr=0 +ShadowCompr=0 +Curve=1;0;0;1;1; + +[Sharpening] +Enabled=true +Method=usm +Radius=0.9 +Amount=135 +Threshold=768 +OnlyEdges=false +EdgedetectionRadius=1.9 +EdgeTolerance=1800 +HalocontrolEnabled=false +HalocontrolAmount=85 +DeconvRadius=0.75 +DeconvAmount=75 +DeconvDamping=20 +DeconvIterations=30 + +[Color Boost] +ChannelA=12 +ChannelB=12 +AvoidColorClipping=false +SaturationLimiter=false +SaturationLimit=75 + +[White Balance] +Setting=Camera +Temperature=6504 +Green=1.0 + +[Color Shift] +ChannelA=0 +ChannelB=0 + +[Luminance Denoising] +Enabled=false +Radius=2.5 +EdgeTolerance=1500 + +[Chrominance Denoising] +Enabled=false +EdgeSensitive=false +Radius=2 +EdgeTolerance=3500 + +[Shadows & Highlights] +Enabled=false +Highlights=10 +HighlightTonalWidth=80 +Shadows=10 +ShadowTonalWidth=80 +LocalContrast=0 +Radius=30 + +[Crop] +Enabled=false +X=0 +Y=0 +W=10000 +H=10000 +FixedRatio=true +Ratio=3:2 +Orientation=Landscape +Guide=None + +[Coarse Transformation] +Rotate=0 +HorizontalFlip=false +VerticalFlip=false + +[Rotation] +Degree=0 +Fill=1 + +[Distortion] +Amount=0 + +[CACorrection] +Red=0 +Blue=0 + +[Vignetting Correction] +Amount=0 +Radius=50 + +[HLRecovery] +Enabled=true +Method=Luminance + +[Resize] +Scale=1 +Method=Bicubic + +[Color Management] +InputProfile=(camera) +ApplyGammaBeforeInputProfile=false +WorkingProfile=sRGB +OutputProfile=No ICM: sRGB output diff --git a/release/profiles/default.pp2 b/release/profiles/default.pp2 new file mode 100755 index 000000000..a76f8d10c --- /dev/null +++ b/release/profiles/default.pp2 @@ -0,0 +1,125 @@ + +[Version] +Version=231 + +[Exposure] +Auto=true +Clip=0.01 +Compensation=0 +Brightness=0 +Contrast=0 +Black=0 +HighlightCompr=100 +ShadowCompr=100 +Curve=1;0;0;1;1; + +[Channel Mixer] +Red=100;0;0; +Green=0;100;0; +Blue=0;0;100; + +[Luminance Curve] +Brightness=0 +Contrast=0 +Black=0 +HighlightCompr=0 +ShadowCompr=0 +Curve=1;0;0;1;1; + +[Sharpening] +Enabled=true +Method=usm +Radius=0.8 +Amount=120 +Threshold=512 +OnlyEdges=false +EdgedetectionRadius=1.9 +EdgeTolerance=1800 +HalocontrolEnabled=false +HalocontrolAmount=85 +DeconvRadius=0.75 +DeconvAmount=75 +DeconvDamping=20 +DeconvIterations=30 + +[Color Boost] +ChannelA=0 +ChannelB=0 +AvoidColorClipping=false +SaturationLimiter=false +SaturationLimit=75 + +[White Balance] +Setting=Camera +Temperature=6504 +Green=1.0 + +[Color Shift] +ChannelA=0 +ChannelB=0 + +[Luminance Denoising] +Enabled=false +Radius=2.5 +EdgeTolerance=1500 + +[Chrominance Denoising] +Enabled=false +EdgeSensitive=false +Radius=2 +EdgeTolerance=3500 + +[Shadows & Highlights] +Enabled=false +Highlights=10 +HighlightTonalWidth=80 +Shadows=10 +ShadowTonalWidth=80 +LocalContrast=0 +Radius=30 + +[Crop] +Enabled=false +X=0 +Y=0 +W=10000 +H=10000 +FixedRatio=true +Ratio=3:2 +Orientation=Landscape +Guide=None + +[Coarse Transformation] +Rotate=0 +HorizontalFlip=false +VerticalFlip=false + +[Rotation] +Degree=0 +Fill=1 + +[Distortion] +Amount=0 + +[CACorrection] +Red=0 +Blue=0 + +[Vignetting Correction] +Amount=0 +Radius=50 + +[HLRecovery] +Enabled=true +Method=Luminance + +[Resize] +Scale=1 +Method=Bicubic + +[Color Management] +InputProfile=(camera) +ApplyGammaBeforeInputProfile=false +WorkingProfile=sRGB +OutputProfile=No ICM: sRGB output + diff --git a/release/profiles/neutral.pp2 b/release/profiles/neutral.pp2 new file mode 100755 index 000000000..7d9000170 --- /dev/null +++ b/release/profiles/neutral.pp2 @@ -0,0 +1,124 @@ + +[Version] +Version=231 + +[Exposure] +Auto=false +Clip=0.01 +Compensation=0 +Brightness=0 +Contrast=0 +Black=0 +HighlightCompr=100 +ShadowCompr=100 +Curve=1;0;0;1;1; + +[Channel Mixer] +Red=100;0;0; +Green=0;100;0; +Blue=0;0;100; + +[Luminance Curve] +Brightness=0 +Contrast=0 +Black=0 +HighlightCompr=0 +ShadowCompr=0 +Curve=1;0;0;1;1; + +[Sharpening] +Enabled=false +Method=usm +Radius=0.8 +Amount=120 +Threshold=512 +OnlyEdges=false +EdgedetectionRadius=1.9 +EdgeTolerance=1800 +HalocontrolEnabled=false +HalocontrolAmount=85 +DeconvRadius=0.75 +DeconvAmount=75 +DeconvDamping=20 +DeconvIterations=30 + +[Color Boost] +ChannelA=0 +ChannelB=0 +AvoidColorClipping=false +SaturationLimiter=false +SaturationLimit=75 + +[White Balance] +Setting=Camera +Temperature=6504 +Green=1.0 + +[Color Shift] +ChannelA=0 +ChannelB=0 + +[Luminance Denoising] +Enabled=false +Radius=2.5 +EdgeTolerance=1500 + +[Chrominance Denoising] +Enabled=false +EdgeSensitive=false +Radius=2 +EdgeTolerance=3500 + +[Shadows & Highlights] +Enabled=false +Highlights=10 +HighlightTonalWidth=80 +Shadows=10 +ShadowTonalWidth=80 +LocalContrast=0 +Radius=30 + +[Crop] +Enabled=false +X=0 +Y=0 +W=10000 +H=10000 +FixedRatio=true +Ratio=3:2 +Orientation=Landscape +Guide=None + +[Coarse Transformation] +Rotate=0 +HorizontalFlip=false +VerticalFlip=false + +[Rotation] +Degree=0 +Fill=1 + +[Distortion] +Amount=0 + +[CACorrection] +Red=0 +Blue=0 + +[Vignetting Correction] +Amount=0 +Radius=50 + +[HLRecovery] +Enabled=true +Method=Luminance + +[Resize] +Scale=1 +Method=Bicubic + +[Color Management] +InputProfile=(camera) +ApplyGammaBeforeInputProfile=false +WorkingProfile=sRGB +OutputProfile=No ICM: sRGB output diff --git a/release/themes/dark b/release/themes/dark new file mode 100755 index 000000000..dd4392c73 --- /dev/null +++ b/release/themes/dark @@ -0,0 +1,194 @@ +# colour scheme (RT Dark) by Bytec ( http://bytec.vitanet.lv ) +# based on the default gtkrc for +# rawtherapee ( http://www.rawtherapee.com ) +# which is based on Bluecurve +# Created by Richard Stellingwerff, Emil Jacobs and Daniel Borgmann. + + +style "clearlooks-default" +{ + font_name = "tahoma 8" + GtkButton ::default_border = { 0, 0, 0, 0 } + GtkComboBox ::default_border = { 0, 0, 0, 0 } + GtkRange ::trough_border = 0 + GtkPaned ::handle_size = 6 + GtkRange ::slider_width = 12 + GtkRange ::stepper_size = 12 + GtkScrollbar ::min_slider_length = 30 + GtkCheckButton ::indicator_size = 12 + GtkMenuBar ::internal-padding = 2 + GtkTreeView ::expander_size = 11 + GtkExpander ::expander_size = 11 + + xthickness = 1 + ythickness = 1 + + fg[NORMAL] = "#808080" + fg[PRELIGHT] = "#d0d0d0" + fg[ACTIVE] = "#808080" + fg[SELECTED] = "#404040" + fg[INSENSITIVE] = "#2d2d2d" + + bg[NORMAL] = "#2d2d2d" + bg[PRELIGHT] = "#404040" + bg[ACTIVE] = "#2d2d2d" + bg[SELECTED] = "#606060" + bg[INSENSITIVE] = "#2d2d2d" + + base[NORMAL] = "#404040" + base[PRELIGHT] = "#404040" + base[ACTIVE] = "#404040" + base[SELECTED] = "#606060" + base[INSENSITIVE] = "#2d2d2d" + + text[NORMAL] = "#a0a0a0" + text[PRELIGHT] = "#d0d0d0" + text[ACTIVE] = "#a0a0a0" + text[SELECTED] = "#101010" + text[INSENSITIVE] = "#101010" + + engine "clearlooks" { + sunkenmenubar = 0 # 0 = disable, 1 = enable + menuitemstyle = 0 # 0 = flat, 1 = 3d-ish (button) + listviewitemstyle = 0 # 0 = flat, 1 = 3d-ish (gradient) + progressbarstyle = 1 # 0 = candy bar, 1 = flat + radius = 10.0 + } +} + +style "clearlooks-wide" = "clearlooks-default" +{ + xthickness = 1 + ythickness = 1 +} + +style "clearlooks-toggle" = "clearlooks-default" +{ + xthickness = 1 + ythickness = 1 + + bg[ACTIVE] = "#606060" + text[ACTIVE] = "#000000" + bg[SELECTED] = "#606060" + text[SELECTED] = "#000000" +} + +style "clearlooks-combo" = "clearlooks-default" +{ + xthickness = 0 + ythickness = 0 +} + +style "clearlooks-notebook" = "clearlooks-wide" +{ + bg[NORMAL] = "#2d2d2d" +} + +style "clearlooks-tasklist" = "clearlooks-default" +{ + xthickness = 5 + ythickness = 3 +} + +style "clearlooks-menu" = "clearlooks-default" +{ + xthickness = 2 + ythickness = 1 + bg[NORMAL] = "#2d2d2d" +} + +style "clearlooks-menu-item" = "clearlooks-default" +{ + xthickness = 1 + ythickness = 1 + fg[PRELIGHT] = "#404040" + text[PRELIGHT] = "#000000" +} + +style "clearlooks-menu-itembar" = "clearlooks-default" +{ + xthickness = 1 + ythickness = 1 +} + +style "clearlooks-tree" = "clearlooks-default" +{ + xthickness = 1 + ythickness = 1 +} + +style "clearlooks-frame-title" = "clearlooks-default" +{ + fg[NORMAL] = "#404040" +} + +style "clearlooks-panel" = "clearlooks-default" +{ + xthickness = 3 + ythickness = 3 +} + +style "clearlooks-tooltips" = "clearlooks-default" +{ + xthickness = 4 + ythickness = 4 + bg[NORMAL] = {1.0, 1.0, 1.0} + fg[NORMAL] = {0.0, 0.0, 0.0} + + fg[NORMAL] = "#000000" + fg[PRELIGHT] = "#000000" + fg[ACTIVE] = "#000000" + fg[SELECTED] = "#000000" + fg[INSENSITIVE] = "#000000" + + bg[NORMAL] = "#ffffff" + bg[PRELIGHT] = "#ffffff" + bg[ACTIVE] = "#ffffff" + bg[SELECTED] = "#ffffff" + bg[INSENSITIVE] = "#ffffff" + + base[NORMAL] = "#000000" + base[PRELIGHT] = "#000000" + base[ACTIVE] = "#000000" + base[SELECTED] = "#000000" + base[INSENSITIVE] = "#000000" + + text[NORMAL] = "#000000" + text[PRELIGHT] = "#000000" + text[ACTIVE] = "#000000" + text[SELECTED] = "#000000" + text[INSENSITIVE] = "#000000" + + +} + +style "clearlooks-progressbar" = "clearlooks-default" +{ + xthickness = 1 + ythickness = 1 + fg[PRELIGHT] = "#000000" +} + +class "GtkWidget" style "clearlooks-default" +class "GtkTreeView" style "clearlooks-default" +class "GtkButton" style "clearlooks-wide" +class "GtkToggleButton" style "clearlooks-toggle" +class "GtkRange" style "clearlooks-wide" +class "GtkFrame" style "clearlooks-wide" +class "GtkStatusbar" style "clearlooks-wide" +class "GtkMenu" style "clearlooks-menu" +class "GtkMenuItem" style "clearlooks-menu-item" +widget_class "*MenuItem.*" style "clearlooks-menu-item" +class "GtkEntry" style "clearlooks-wide" +widget_class "*.tooltip.*.GtkToggleButton" style "clearlooks-tasklist" +widget "gtk-tooltip" style "clearlooks-tooltips" +widget_class "*.GtkTreeView.GtkButton" style "clearlooks-tree" +widget_class "*.GtkCTree.GtkButton" style "clearlooks-tree" +widget_class "*.GtkList.GtkButton" style "clearlooks-tree" +widget_class "*.GtkCList.GtkButton" style "clearlooks-tree" +widget_class "*.GtkFrame.GtkLabel" style "clearlooks-frame-title" +widget_class "BasePWidget.GtkEventBox.GtkTable.GtkFrame" style "clearlooks-panel" +class "GtkNotebook" style "clearlooks-notebook" +class "GtkProgressBar" style "clearlooks-progressbar" +widget_class "*.GtkComboBox.GtkButton" style "clearlooks-combo" +widget_class "*.GtkCombo.GtkButton" style "clearlooks-combo" diff --git a/release/themes/default b/release/themes/default new file mode 100755 index 000000000..c6ea6e375 --- /dev/null +++ b/release/themes/default @@ -0,0 +1,151 @@ +# colour scheme by Bytec ( http://bytec.vitanet.lv ) +# based on the default gtkrc for +# rawtherapee ( http://www.rawtherapee.com ) +# which is based on Bluecurve +# Created by Richard Stellingwerff, Emil Jacobs and Daniel Borgmann. + + +style "clearlooks-default" +{ +font_name = "tahoma 8" + GtkButton ::default_border = { 0, 0, 0, 0 } + GtkRange ::trough_border = 0 + GtkPaned ::handle_size = 6 + GtkRange ::slider_width = 12 + GtkRange ::stepper_size = 12 + GtkScrollbar ::min_slider_length = 30 + GtkCheckButton ::indicator_size = 12 + GtkMenuBar ::internal-padding = 0 + GtkTreeView ::expander_size = 11 + GtkExpander ::expander_size = 11 + + xthickness = 1 + ythickness = 1 + + fg[NORMAL] = "#101010" + fg[PRELIGHT] = "#101010" + fg[ACTIVE] = "#000000" + fg[SELECTED] = "#999999" + fg[INSENSITIVE] = "#808080" + + bg[NORMAL] = "#808080" + bg[PRELIGHT] = "#999999" + bg[ACTIVE] = "#808080" + bg[SELECTED] = "#999999" + bg[INSENSITIVE] = "#808080" + + base[NORMAL] = "#999999" + base[PRELIGHT] = "#999999" + base[ACTIVE] = "#999999" + base[SELECTED] = "#606060" + base[INSENSITIVE] = "#808080" + + text[NORMAL] = "#000000" + text[PRELIGHT] = "#000000" + text[ACTIVE] = "#000000" + text[SELECTED] = "#000000" + text[INSENSITIVE] = "#000000" + + engine "clearlooks" { + sunkenmenubar = 1 # 0 = disable, 1 = enable + menuitemstyle = 0 # 0 = flat, 1 = 3d-ish (button) + listviewitemstyle = 0 # 0 = flat, 1 = 3d-ish (gradient) + progressbarstyle = 0 # 0 = candy bar, 1 = flat + } +} + +style "clearlooks-wide" = "clearlooks-default" +{ + xthickness = 1 + ythickness = 1 +} + +style "clearlooks-notebook" = "clearlooks-wide" +{ + bg[NORMAL] = "#808080" +} + +style "clearlooks-tasklist" = "clearlooks-default" +{ + xthickness = 5 + ythickness = 3 +} + +style "clearlooks-menu" = "clearlooks-default" +{ + xthickness = 2 + ythickness = 1 + bg[NORMAL] = "#808080" +} + +style "clearlooks-menu-item" = "clearlooks-default" +{ + xthickness = 1 + ythickness = 1 +} + +style "clearlooks-menu-itembar" = "clearlooks-default" +{ + xthickness = 1 + ythickness = 1 +} + +style "clearlooks-tree" = "clearlooks-default" +{ + xthickness = 1 + ythickness = 1 +} + +style "clearlooks-frame-title" = "clearlooks-default" +{ + fg[NORMAL] = "#404040" +} + +style "clearlooks-panel" = "clearlooks-default" +{ + xthickness = 3 + ythickness = 3 +} + +style "clearlooks-tooltips" = "clearlooks-default" +{ + xthickness = 4 + ythickness = 4 + bg[NORMAL] = { 1.0,1.0,0.75 } +} + +style "clearlooks-progressbar" = "clearlooks-default" +{ + xthickness = 1 + ythickness = 0 + + fg[PRELIGHT] = "#000000" +} + +style "clearlooks-combo" = "clearlooks-default" +{ + xthickness = 0 + ythickness = 0 +} + +class "GtkWidget" style "clearlooks-default" +class "GtkButton" style "clearlooks-wide" +class "GtkRange" style "clearlooks-wide" +class "GtkFrame" style "clearlooks-wide" +class "GtkStatusbar" style "clearlooks-wide" +class "GtkMenu" style "clearlooks-menu" +class "GtkMenuItem" style "clearlooks-menu-item" +widget_class "*MenuItem.*" style "clearlooks-menu-item" +class "GtkEntry" style "clearlooks-wide" +widget_class "*.tooltips.*.GtkToggleButton" style "clearlooks-tasklist" +widget_class "*.GtkTreeView.GtkButton" style "clearlooks-tree" +widget_class "*.GtkCTree.GtkButton" style "clearlooks-tree" +widget_class "*.GtkList.GtkButton" style "clearlooks-tree" +widget_class "*.GtkCList.GtkButton" style "clearlooks-tree" +widget_class "*.GtkFrame.GtkLabel" style "clearlooks-frame-title" +widget_class "BasePWidget.GtkEventBox.GtkTable.GtkFrame" style "clearlooks-panel" +widget "gtk-tooltip" style "clearlooks-tooltips" +class "GtkNotebook" style "clearlooks-notebook" +class "GtkProgressBar" style "clearlooks-progressbar" +widget_class "*.GtkComboBox.GtkButton" style "clearlooks-combo" +widget_class "*.GtkCombo.GtkButton" style "clearlooks-combo" \ No newline at end of file diff --git a/release/themes/gray b/release/themes/gray new file mode 100755 index 000000000..930444fdd --- /dev/null +++ b/release/themes/gray @@ -0,0 +1,230 @@ +# DarknessReturns GTK+ Theme for Clearlooks GTK Engine +# +# Created for CrunchBang Linux by Philip Newborough +# http://crunchbang.org/projects/linux/ + +style "theme-default" { + + font_name = "tahoma 8" + + GtkButton ::default_border = { 0, 0, 0, 0 } + GtkRange ::trough_border = 1 + GtkPaned ::handle_size = 6 + GtkRange ::slider_width = 12 + GtkRange ::stepper_size = 12 + GtkScrollbar ::min_slider_length = 30 + GtkCheckButton ::indicator_size = 13 + GtkMenuBar ::internal-padding = 0 + GtkTreeView ::expander_size = 12 + GtkExpander ::expander_size = 12 + + xthickness = 1 + ythickness = 1 + + fg[NORMAL] = "#101010" + fg[PRELIGHT] = "#101010" + fg[ACTIVE] = "#31353A" + fg[SELECTED] = "#B2B2B2" + fg[INSENSITIVE] = "#9E9C9E" + + bg[NORMAL] = "#A1A1A1" + bg[PRELIGHT] = "#B2B2B2" + bg[ACTIVE] = "#B2B2B2" + bg[SELECTED] = "#31353A" + bg[INSENSITIVE] = "#B2B2B2" + + base[NORMAL] = "#B2B2B2" + base[PRELIGHT] = "#31353A" + base[SELECTED] = "#31353A" + base[INSENSITIVE] = "#fbf8f1" + base[ACTIVE] = "#31353A" + base[PRELIGHT] = "#729fcf" + + text[NORMAL] = "#101010" + text[PRELIGHT] = "#d0d0d0" + text[ACTIVE] = "#E2E2E2" + text[SELECTED] = "#E2E2E2" + text[INSENSITIVE] = "#E2E2E2" + + engine "clearlooks" { + menubarstyle = 0 + } +} + +style "theme-wide" = "theme-default" { + xthickness = 3 + ythickness = 3 +} + +style "theme-text" = "theme-default" { + #base[SELECTED] = "#fc9747" # Outline? +} + +style "theme-toolbar" = "theme-default" { + bg[NORMAL] = "#A1A1A1" +} + +style "theme-tasklist" = "theme-default" { + xthickness = 5 + ythickness = 3 +} + +style "theme-menu" = "theme-default" { + xthickness = 2 + ythickness = 2 + bg[NORMAL] = "#A1A1A1" +} + +style "theme-menu-item" = "theme-default" { + xthickness = 1 + ythickness = 1 + fg[PRELIGHT] = "#ffffff" + text[PRELIGHT] = "#ffffff" + base[PRELIGHT] = "#A1A1A1" +} + +style "theme-menu-itembar" = "theme-default" { + xthickness = 0 + ythickness = 0 +} + +style "theme-tree" = "theme-default" { + xthickness = 2 + ythickness = 2 + GtkTreeView::odd_row_color = "#f7f7ff" + GtkTreeView::even_row_color = "#ffffff" +} + +style "theme-frame-title" = "theme-default" { + fg[NORMAL] = "#2a2a2a" +} + +style "theme-panel" = "theme-default" { + xthickness = 3 + ythickness = 3 +} + +style "theme-tooltips" = "theme-default" { + xthickness = 4 + ythickness = 4 + bg[NORMAL] = { 1.0,1.0,0.75 } +} + +style "theme-progressbar" = "theme-default" { + xthickness = 1 + ythickness = 1 + fg[PRELIGHT] = "#ffffff" +} + +style "theme-combo" = "theme-default" { + xthickness = 2 + ythickness = 0 +} + +style "theme-button" = "theme-wide" { + xthickness = 1 + ythickness = 1 + #bg[NORMAL] = "#31353A" + #bg[PRELIGHT] = "#555555" + #bg[NORMAL] = "#31353A" +} +style "theme-check" = "theme-button" { +} + +style "theme-panel" = "theme-default" { + xthickness = 3 + ythickness = 3 +} + +style "theme-notebook" = "theme-wide" { + base[SELECTED] = "#A1A1A1" + bg[ACTIVE] = "#A1A1A1" + base[PRELIGHT] = "#A1A1A1" + bg[PRELIGHT] = "#A1A1A1" +} + +style "metacity-frame" { + bg[SELECTED] = "#5c82b5" +} + +style "theme-slab" = "theme-default" { + bg[SELECTED] = "#84b0da" + bg[NORMAL] = "#fdfbf7" + bg[ACTIVE] = "#e9eef5" + fg[NORMAL] = "#6a97c5" + fg[INSENSITIVE] = "#5c8dbf" +} + +style "theme-slab-group" = "theme-default" { + #bg[SELECTED] = "#adc09b" # Slab group text +} + +style "theme-shell" = "theme-default" { + bg[ACTIVE] = "#e9eef5" # Left side bg color + fg[NORMAL] = "#5c8dbf" # Left side text color + fg[INSENSITIVE] = "#bdcce1" # Left side line + + base[NORMAL] = "#fdfbf7" # Base bg color + text[INSENSITIVE] = "#6a97c5" # Base text color +} + +style "evolution-hack" = "clearlooks-default" { + bg[ACTIVE] = "#96b9d5" + bg[SELECTED] = "#6798cb" + fg[ACTIVE] = "#000000" + fg[SELECTED] = "#ffffff" +} + +style "theme-shell-highlight" = "theme-default" { +} + +style "extra-view" { + bg[NORMAL] = "#729fcf" + font = "Sans 6" +} + +style "rox" = "theme-default" { + bg[NORMAL] = "#ffffff" + bg[ACTIVE] = "#ffffff" + fg[NORMAL] = "#000000" + fg[ACTIVE] = "#000000" +} + +class "GtkWidget" style "theme-default" +class "GtkButton" style "theme-button" +class "GtkCombo" style "theme-button" +class "GtkRange" style "theme-wide" +class "GtkFrame" style "theme-wide" +class "GtkMenu" style "theme-menu" +class "GtkEntry" style "theme-button" +class "GtkMenuItem" style "theme-menu-item" +class "GtkStatusbar" style "theme-wide" +class "GtkNotebook" style "theme-notebook" +class "GtkProgressBar" style "theme-progressbar" +class "GtkCheckButton" style "theme-check" +class "GtkRadioButton" style "theme-check" + +widget_class "*MenuItem.*" style "theme-menu-item" +widget_class "*.GtkComboBox.GtkButton" style "theme-combo" +widget_class "*.GtkCombo.GtkButton" style "theme-combo" +widget_class "*.tooltips.*.GtkToggleButton" style "theme-tasklist" +widget "gtk-tooltip" style "theme-tooltips" +widget_class "*.GtkTreeView.GtkButton" style "theme-tree" +widget_class "*.GtkCTree.GtkButton" style "theme-tree" +widget_class "*.GtkList.GtkButton" style "theme-tree" +widget_class "*.GtkCList.GtkButton" style "theme-tree" +widget_class "*.GtkFrame.GtkLabel" style "theme-frame-title" +widget_class "*.GtkNotebook.*.GtkEventBox" style "theme-notebook" +widget_class "*.GtkNotebook.*.GtkViewport" style "theme-notebook" +class "MetaFrames" style "metacity-frame" +widget_class "BasePWidget.GtkEventBox.GtkTable.GtkFrame" style "theme-panel" +widget "*.nautilus-extra-view-widget" style:highest "extra-view" +class "SlabWindow" style "theme-slab" +class "ShellWindow" style "theme-shell" +widget_class "ShellWindow.*.GtkEventBox" style "theme-shell-highlight" +widget_class "*GtkCTree*" style "evolution-hack" +widget_class "*GtkList*" style "evolution-hack" +widget_class "*GtkCList*" style "evolution-hack" +widget_class "*.ETree.*" style "evolution-hack" +widget_class "*Collection*" style "rox" + diff --git a/release/themes/light b/release/themes/light new file mode 100755 index 000000000..9ef5cc5e0 --- /dev/null +++ b/release/themes/light @@ -0,0 +1,150 @@ +# Based on Bluecurve +# Created by Richard Stellingwerff, Emil Jacobs and Daniel Borgmann. + + +style "clearlooks-default" +{ +font_name = "sans 8" + GtkButton ::default_border = { 0, 0, 0, 0 } + GtkRange ::trough_border = 0 + GtkPaned ::handle_size = 6 + GtkRange ::slider_width = 12 + GtkRange ::stepper_size = 12 + GtkScrollbar ::min_slider_length = 30 + GtkCheckButton ::indicator_size = 12 + GtkMenuBar ::internal-padding = 0 + GtkTreeView ::expander_size = 11 + GtkExpander ::expander_size = 11 + + xthickness = 1 + ythickness = 1 + + fg[NORMAL] = "#101010" # very dark gray #101010 + fg[PRELIGHT] = "#101010" # dark grey + fg[ACTIVE] = "#000000" # black + fg[SELECTED] = "#ffffff" # white + fg[INSENSITIVE] = "#b5b3ac" # dark beige / grey + + bg[NORMAL] = "#efebe7" # light beige / grey + bg[PRELIGHT] = "#f5f3f0" # very light beige + bg[ACTIVE] = "#d4cfca" # mid beige / grey + bg[SELECTED] = "#7c99ad" # blueish + bg[INSENSITIVE] = "#efebe7" # light beige / grey + + base[NORMAL] = "#ffffff" # white + base[PRELIGHT] = "#7c99ad" # blueish + base[ACTIVE] = "#a29e8e" # dark beige / grey + base[SELECTED] = "#7c99ad" # blueish + base[INSENSITIVE] = "#efebe7" #light beige / grey + + text[NORMAL] = "#000000" # black + text[PRELIGHT] = "#000000" # black + text[ACTIVE] = "#ffffff" # white + text[SELECTED] = "#ffffff" # white + text[INSENSITIVE] = "#b5b3ac" # dark beige / grey + + engine "clearlooks" { + sunkenmenubar = 1 # 0 = disable, 1 = enable + menuitemstyle = 0 # 0 = flat, 1 = 3d-ish (button) + listviewitemstyle = 0 # 0 = flat, 1 = 3d-ish (gradient) + progressbarstyle = 0 # 0 = candy bar, 1 = flat + } +} + +style "clearlooks-wide" = "clearlooks-default" +{ + xthickness = 1 + ythickness = 1 +} + +style "clearlooks-notebook" = "clearlooks-wide" +{ + bg[NORMAL] = "#eae4df" +} + +style "clearlooks-tasklist" = "clearlooks-default" +{ + xthickness = 5 + ythickness = 3 +} + +style "clearlooks-menu" = "clearlooks-default" +{ + xthickness = 2 + ythickness = 1 + bg[NORMAL] = "#f8f5f2" +} + +style "clearlooks-menu-item" = "clearlooks-default" +{ + xthickness = 1 + ythickness = 1 + fg[PRELIGHT] = "#ffffff" + text[PRELIGHT] = "#ffffff" +} + +style "clearlooks-menu-itembar" = "clearlooks-default" +{ + xthickness = 1 + ythickness = 1 +} + +style "clearlooks-tree" = "clearlooks-default" +{ + xthickness = 1 + ythickness = 1 +} + +style "clearlooks-frame-title" = "clearlooks-default" +{ + fg[NORMAL] = "#404040" +} + +style "clearlooks-panel" = "clearlooks-default" +{ + xthickness = 3 + ythickness = 3 +} + +style "clearlooks-tooltips" = "clearlooks-default" +{ + xthickness = 4 + ythickness = 4 + bg[NORMAL] = { 1.0,1.0,0.75 } +} + +style "clearlooks-progressbar" = "clearlooks-default" +{ + xthickness = 1 + ythickness = 0 + + fg[PRELIGHT] = "#ffffff" +} + +style "clearlooks-combo" = "clearlooks-default" +{ + xthickness = 1 + ythickness = 1 +} + +class "GtkWidget" style "clearlooks-default" +class "GtkButton" style "clearlooks-wide" +class "GtkRange" style "clearlooks-wide" +class "GtkFrame" style "clearlooks-wide" +class "GtkStatusbar" style "clearlooks-wide" +class "GtkMenu" style "clearlooks-menu" +class "GtkMenuItem" style "clearlooks-menu-item" +widget_class "*MenuItem.*" style "clearlooks-menu-item" +class "GtkEntry" style "clearlooks-wide" +widget_class "*.tooltips.*.GtkToggleButton" style "clearlooks-tasklist" +widget_class "*.GtkTreeView.GtkButton" style "clearlooks-tree" +widget_class "*.GtkCTree.GtkButton" style "clearlooks-tree" +widget_class "*.GtkList.GtkButton" style "clearlooks-tree" +widget_class "*.GtkCList.GtkButton" style "clearlooks-tree" +widget_class "*.GtkFrame.GtkLabel" style "clearlooks-frame-title" +widget_class "BasePWidget.GtkEventBox.GtkTable.GtkFrame" style "clearlooks-panel" +widget "gtk-tooltip" style "clearlooks-tooltips" +class "GtkNotebook" style "clearlooks-notebook" +class "GtkProgressBar" style "clearlooks-progressbar" +widget_class "*.GtkComboBox.GtkButton" style "clearlooks-combo" +widget_class "*.GtkCombo.GtkButton" style "clearlooks-combo" diff --git a/release/themes/test b/release/themes/test new file mode 100755 index 000000000..6ba09ab0f --- /dev/null +++ b/release/themes/test @@ -0,0 +1,259 @@ +# DarknessReturns GTK+ Theme for Clearlooks GTK Engine +# +# Created for CrunchBang Linux by Philip Newborough +# http://crunchbang.org/projects/linux/ + +style "theme-default" { + + font_name = "tahoma 8" + + GtkButton ::default_border = { 0, 0, 0, 0 } + GtkRange ::trough_border = 1 + GtkPaned ::handle_size = 6 + GtkRange ::slider_width = 12 + GtkRange ::stepper_size = 12 + GtkScrollbar ::min_slider_length = 30 + GtkCheckButton ::indicator_size = 13 + GtkMenuBar ::internal-padding = 0 + GtkTreeView ::expander_size = 12 + GtkExpander ::expander_size = 12 + + xthickness = 1 + ythickness = 1 + + fg[NORMAL] = "#101010" + fg[PRELIGHT] = "#101010" + fg[ACTIVE] = "#31353A" + fg[SELECTED] = "#B2B2B2" + fg[INSENSITIVE] = "#9E9C9E" + + bg[NORMAL] = "#A1A1A1" + bg[PRELIGHT] = "#B2B2B2" + bg[ACTIVE] = "#B2B2B2" + bg[SELECTED] = "#31353A" + bg[INSENSITIVE] = "#B2B2B2" + + base[NORMAL] = "#B2B2B2" + base[PRELIGHT] = "#31353A" + base[SELECTED] = "#31353A" + base[INSENSITIVE] = "#fbf8f1" + base[ACTIVE] = "#31353A" + base[PRELIGHT] = "#729fcf" + + text[NORMAL] = "#101010" + text[PRELIGHT] = "#d0d0d0" + text[ACTIVE] = "#E2E2E2" + text[SELECTED] = "#E2E2E2" + text[INSENSITIVE] = "#E2E2E2" + + engine "clearlooks" { + menubarstyle = 0 + } +} + +style "theme-wide" = "theme-default" { + xthickness = 3 + ythickness = 3 +} + +style "theme-text" = "theme-default" { + #base[SELECTED] = "#fc9747" # Outline? +} + +style "theme-toolbar" = "theme-default" { + bg[NORMAL] = "#A1A1A1" +} + +style "theme-tasklist" = "theme-default" { + xthickness = 5 + ythickness = 3 +} + +style "theme-menu" = "theme-default" { + xthickness = 2 + ythickness = 2 + bg[NORMAL] = "#A1A1A1" +} + +style "theme-menu-item" = "theme-default" { + xthickness = 1 + ythickness = 1 + fg[PRELIGHT] = "#ffffff" + text[PRELIGHT] = "#ffffff" + base[PRELIGHT] = "#A1A1A1" +} + +style "tpstyle" = "theme-default" { + + bg[NORMAL] = "#000000" + bg[PRELIGHT] = "#000000" + bg[ACTIVE] = "#000000" + bg[SELECTED] = "#000000" + bg[INSENSITIVE] = "#000000" + fg[NORMAL] = "#000000" + fg[PRELIGHT] = "#000000" + fg[ACTIVE] = "#000000" + fg[SELECTED] = "#000000" + bg[INSENSITIVE] = "#000000" + base[NORMAL] = "#000000" + base[PRELIGHT] = "#000000" + base[ACTIVE] = "#000000" + base[SELECTED] = "#000000" + base[INSENSITIVE] = "#000000" + text[NORMAL] = "#000000" + text[PRELIGHT] = "#000000" + text[ACTIVE] = "#000000" + text[SELECTED] = "#000000" + text[INSENSITIVE] = "#000000" +} + +style "theme-menu-itembar" = "theme-default" { + xthickness = 0 + ythickness = 0 +} + +style "theme-tree" = "theme-default" { + xthickness = 2 + ythickness = 2 + GtkTreeView::odd_row_color = "#f7f7ff" + GtkTreeView::even_row_color = "#ffffff" +} + +style "theme-frame-title" = "theme-default" { + fg[NORMAL] = "#2a2a2a" +} + +style "theme-panel" = "theme-default" { + xthickness = 3 + ythickness = 3 +} + +style "theme-tooltips" = "theme-default" { + xthickness = 4 + ythickness = 4 + bg[NORMAL] = { 1.0,1.0,0.75 } +} + +style "theme-progressbar" = "theme-default" { + xthickness = 1 + ythickness = 1 + fg[PRELIGHT] = "#ffffff" +} + +style "theme-combo" = "theme-default" { + xthickness = 2 + ythickness = 0 +} + +style "theme-button" = "theme-wide" { + xthickness = 1 + ythickness = 1 + #bg[NORMAL] = "#31353A" + #bg[PRELIGHT] = "#555555" + #bg[NORMAL] = "#31353A" +} +style "theme-check" = "theme-button" { +} + +style "theme-panel" = "theme-default" { + xthickness = 3 + ythickness = 3 +} + +style "theme-notebook" = "theme-wide" { + base[SELECTED] = "#A1A1A1" + bg[ACTIVE] = "#A1A1A1" + base[PRELIGHT] = "#A1A1A1" + bg[PRELIGHT] = "#A1A1A1" +} + +style "metacity-frame" { + bg[SELECTED] = "#5c82b5" +} + +style "theme-slab" = "theme-default" { + bg[SELECTED] = "#84b0da" + bg[NORMAL] = "#fdfbf7" + bg[ACTIVE] = "#e9eef5" + fg[NORMAL] = "#6a97c5" + fg[INSENSITIVE] = "#5c8dbf" +} + +style "theme-slab-group" = "theme-default" { + #bg[SELECTED] = "#adc09b" # Slab group text +} + +style "theme-shell" = "theme-default" { + bg[ACTIVE] = "#e9eef5" # Left side bg color + fg[NORMAL] = "#5c8dbf" # Left side text color + fg[INSENSITIVE] = "#bdcce1" # Left side line + + base[NORMAL] = "#fdfbf7" # Base bg color + text[INSENSITIVE] = "#6a97c5" # Base text color +} + +style "evolution-hack" = "clearlooks-default" { + bg[ACTIVE] = "#96b9d5" + bg[SELECTED] = "#6798cb" + fg[ACTIVE] = "#000000" + fg[SELECTED] = "#ffffff" +} + +style "theme-shell-highlight" = "theme-default" { +} + +style "extra-view" { + bg[NORMAL] = "#729fcf" + font = "Sans 6" +} + +style "rox" = "theme-default" { + bg[NORMAL] = "#ffffff" + bg[ACTIVE] = "#ffffff" + fg[NORMAL] = "#000000" + fg[ACTIVE] = "#000000" +} + +class "GtkWidget" style "theme-default" +class "GtkButton" style "theme-button" +class "GtkCombo" style "theme-button" +class "GtkRange" style "theme-wide" +class "GtkFrame" style "theme-wide" +class "GtkMenu" style "theme-menu" +class "GtkEntry" style "theme-button" +class "GtkMenuItem" style "theme-menu-item" +class "GtkStatusbar" style "theme-wide" +class "GtkNotebook" style "theme-notebook" +class "GtkProgressBar" style "theme-progressbar" +class "GtkCheckButton" style "theme-check" +class "GtkRadioButton" style "theme-check" + +widget_class "*MenuItem.*" style "theme-menu-item" +widget_class "*.GtkComboBox.GtkButton" style "theme-combo" +widget_class "*.GtkCombo.GtkButton" style "theme-combo" +widget_class "*.tooltips.*.GtkToggleButton" style "theme-tasklist" +widget "gtk-tooltip" style "theme-tooltips" +widget_class "*.GtkTreeView.GtkButton" style "theme-tree" +widget_class "*.GtkCTree.GtkButton" style "theme-tree" +widget_class "*.GtkList.GtkButton" style "theme-tree" +widget_class "*.GtkCList.GtkButton" style "theme-tree" +widget_class "*.GtkFrame.GtkLabel" style "theme-frame-title" +widget_class "*.GtkNotebook.*.GtkEventBox" style "theme-notebook" +widget_class "*.GtkNotebook.*.GtkViewport" style "theme-notebook" +class "MetaFrames" style "metacity-frame" +widget_class "BasePWidget.GtkEventBox.GtkTable.GtkFrame" style "theme-panel" +widget "*.nautilus-extra-view-widget" style:highest "extra-view" +class "SlabWindow" style "theme-slab" +class "ShellWindow" style "theme-shell" +widget_class "ShellWindow.*.GtkEventBox" style "theme-shell-highlight" +widget_class "*GtkCTree*" style "evolution-hack" +widget_class "*GtkList*" style "evolution-hack" +widget_class "*GtkCList*" style "evolution-hack" +widget_class "*.ETree.*" style "evolution-hack" +widget_class "*Collection*" style "rox" +widget_class "*ToolPanel" style "tpstyle" +widget_class "*ToolPanel*" style "tpstyle" +widget_class "*ToolPanel.*" style "tpstyle" +widget_class "*.ToolPanel.*" style "tpstyle" +widget_class "*.ToolPanel" style "tpstyle" + diff --git a/rtengine/CMakeCache.txt b/rtengine/CMakeCache.txt new file mode 100755 index 000000000..3baf1ec23 --- /dev/null +++ b/rtengine/CMakeCache.txt @@ -0,0 +1,401 @@ +# This is the CMakeCache file. +# For build in directory: /home/hgabor/RawTherapee/2.5/gui88/rtengine +# It was generated by CMake: /usr/bin/cmake +# You can edit this file to change values found and used by cmake. +# If you do not want to change any of the values, simply exit the editor. +# If you do want to change a value, simply edit, save, and exit the editor. +# The syntax for the file is as follows: +# KEY:TYPE=VALUE +# KEY is the name of a variable in the cache. +# TYPE is a hint to GUI's for the type of VALUE, DO NOT EDIT TYPE!. +# VALUE is the current value for the KEY. + +######################## +# EXTERNAL cache entries +######################## + +//Path to a program. +CMAKE_AR:FILEPATH=/usr/bin/ar + +//For backwards compatibility, what version of CMake commands and +// syntax should this version of CMake try to support. +CMAKE_BACKWARDS_COMPATIBILITY:STRING=2.4 + +//Choose the type of build, options are: None(CMAKE_CXX_FLAGS or +// CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel. +CMAKE_BUILD_TYPE:STRING= + +//Enable/Disable color output during build. +CMAKE_COLOR_MAKEFILE:BOOL=ON + +//CXX compiler. +CMAKE_CXX_COMPILER:FILEPATH=/usr/bin/c++ + +//Flags used by the compiler during all build types. +CMAKE_CXX_FLAGS:STRING= + +//Flags used by the compiler during debug builds. +CMAKE_CXX_FLAGS_DEBUG:STRING=-g + +//Flags used by the compiler during release minsize builds. +CMAKE_CXX_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG + +//Flags used by the compiler during release builds (/MD /Ob1 /Oi +// /Ot /Oy /Gs will produce slightly less optimized but smaller +// files). +CMAKE_CXX_FLAGS_RELEASE:STRING=-O3 -DNDEBUG + +//Flags used by the compiler during Release with Debug Info builds. +CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=-O2 -g + +//C compiler. +CMAKE_C_COMPILER:FILEPATH=/usr/bin/gcc + +//Flags used by the compiler during all build types. +CMAKE_C_FLAGS:STRING= + +//Flags used by the compiler during debug builds. +CMAKE_C_FLAGS_DEBUG:STRING=-g + +//Flags used by the compiler during release minsize builds. +CMAKE_C_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG + +//Flags used by the compiler during release builds (/MD /Ob1 /Oi +// /Ot /Oy /Gs will produce slightly less optimized but smaller +// files). +CMAKE_C_FLAGS_RELEASE:STRING=-O3 -DNDEBUG + +//Flags used by the compiler during Release with Debug Info builds. +CMAKE_C_FLAGS_RELWITHDEBINFO:STRING=-O2 -g + +//Flags used by the linker. +CMAKE_EXE_LINKER_FLAGS:STRING= + +//Flags used by the linker during debug builds. +CMAKE_EXE_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during release minsize builds. +CMAKE_EXE_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during release builds. +CMAKE_EXE_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during Release with Debug Info builds. +CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//Install path prefix, prepended onto install directories. +CMAKE_INSTALL_PREFIX:PATH=/usr/local + +//Path to a program. +CMAKE_LINKER:FILEPATH=/usr/bin/ld + +//Path to a program. +CMAKE_MAKE_PROGRAM:FILEPATH=/usr/bin/make + +//Flags used by the linker during the creation of modules. +CMAKE_MODULE_LINKER_FLAGS:STRING= + +//Flags used by the linker during debug builds. +CMAKE_MODULE_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during release minsize builds. +CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during release builds. +CMAKE_MODULE_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during Release with Debug Info builds. +CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//Path to a program. +CMAKE_NM:FILEPATH=/usr/bin/nm + +//Path to a program. +CMAKE_OBJCOPY:FILEPATH=/usr/bin/objcopy + +//Path to a program. +CMAKE_OBJDUMP:FILEPATH=/usr/bin/objdump + +//Path to a program. +CMAKE_RANLIB:FILEPATH=/usr/bin/ranlib + +//Flags used by the linker during the creation of dll's. +CMAKE_SHARED_LINKER_FLAGS:STRING= + +//Flags used by the linker during debug builds. +CMAKE_SHARED_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during release minsize builds. +CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during release builds. +CMAKE_SHARED_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during Release with Debug Info builds. +CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//If set, runtime paths are not added when using shared libraries. +CMAKE_SKIP_RPATH:BOOL=NO + +//Path to a program. +CMAKE_STRIP:FILEPATH=/usr/bin/strip + +//If true, cmake will use relative paths in makefiles and projects. +CMAKE_USE_RELATIVE_PATHS:BOOL=OFF + +//If this value is on, makefiles will be generated without the +// .SILENT directive, and all commands will be echoed to the console +// during the make. This is useful for debugging only. With Visual +// Studio IDE projects all commands are done without /nologo. +CMAKE_VERBOSE_MAKEFILE:BOOL=FALSE + +//Single output directory for building all executables. +EXECUTABLE_OUTPUT_PATH:PATH= + +//Single output directory for building all libraries. +LIBRARY_OUTPUT_PATH:PATH= + +//pkg-config executable +PKG_CONFIG_EXECUTABLE:FILEPATH=/usr/bin/pkg-config + +//Value Computed by CMake +Project_BINARY_DIR:STATIC=/home/hgabor/RawTherapee/2.5/gui88/rtengine + +//Value Computed by CMake +Project_SOURCE_DIR:STATIC=/home/hgabor/RawTherapee/2.5/gui88/rtengine + +//Dependencies for the target +rtengine_LIB_DEPENDS:STATIC=general;rtexif;general;lcms;general;iptcdata -lrwz_sdk;general;gthread-2.0;general;gobject-2.0;general;glib-2.0;general;glibmm-2.4;general;gobject-2.0;general;sigc-2.0;general;glib-2.0; + + +######################## +# INTERNAL cache entries +######################## + +//Advanced flag for variable: CMAKE_AR +CMAKE_AR-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_BUILD_TOOL +CMAKE_BUILD_TOOL-ADVANCED:INTERNAL=1 +//What is the target build tool cmake is generating for. +CMAKE_BUILD_TOOL:INTERNAL=/usr/bin/make +//This is the directory where this CMakeCahe.txt was created +CMAKE_CACHEFILE_DIR:INTERNAL=/home/hgabor/RawTherapee/2.5/gui88/rtengine +//Major version of cmake used to create the current loaded cache +CMAKE_CACHE_MAJOR_VERSION:INTERNAL=2 +//Minor version of cmake used to create the current loaded cache +CMAKE_CACHE_MINOR_VERSION:INTERNAL=6 +//Major version of cmake used to create the current loaded cache +CMAKE_CACHE_RELEASE_VERSION:INTERNAL=patch 0 +//Advanced flag for variable: CMAKE_COLOR_MAKEFILE +CMAKE_COLOR_MAKEFILE-ADVANCED:INTERNAL=1 +//Path to CMake executable. +CMAKE_COMMAND:INTERNAL=/usr/bin/cmake +//Path to cpack program executable. +CMAKE_CPACK_COMMAND:INTERNAL=/usr/bin/cpack +//Path to ctest program executable. +CMAKE_CTEST_COMMAND:INTERNAL=/usr/bin/ctest +//Advanced flag for variable: CMAKE_CXX_COMPILER +CMAKE_CXX_COMPILER-ADVANCED:INTERNAL=1 +CMAKE_CXX_COMPILER_WORKS:INTERNAL=1 +//Advanced flag for variable: CMAKE_CXX_FLAGS +CMAKE_CXX_FLAGS-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_CXX_FLAGS_DEBUG +CMAKE_CXX_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_CXX_FLAGS_MINSIZEREL +CMAKE_CXX_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_CXX_FLAGS_RELEASE +CMAKE_CXX_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_CXX_FLAGS_RELWITHDEBINFO +CMAKE_CXX_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_C_COMPILER +CMAKE_C_COMPILER-ADVANCED:INTERNAL=1 +CMAKE_C_COMPILER_WORKS:INTERNAL=1 +//Advanced flag for variable: CMAKE_C_FLAGS +CMAKE_C_FLAGS-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_C_FLAGS_DEBUG +CMAKE_C_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_C_FLAGS_MINSIZEREL +CMAKE_C_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_C_FLAGS_RELEASE +CMAKE_C_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_C_FLAGS_RELWITHDEBINFO +CMAKE_C_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//Result of TRY_COMPILE +CMAKE_DETERMINE_CXX_ABI_COMPILED:INTERNAL=TRUE +//Result of TRY_COMPILE +CMAKE_DETERMINE_C_ABI_COMPILED:INTERNAL=TRUE +//Path to cache edit program executable. +CMAKE_EDIT_COMMAND:INTERNAL=/usr/bin/ccmake +//Executable file format +CMAKE_EXECUTABLE_FORMAT:INTERNAL=ELF +//Advanced flag for variable: CMAKE_EXE_LINKER_FLAGS +CMAKE_EXE_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_EXE_LINKER_FLAGS_DEBUG +CMAKE_EXE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_EXE_LINKER_FLAGS_MINSIZEREL +CMAKE_EXE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_EXE_LINKER_FLAGS_RELEASE +CMAKE_EXE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//Name of generator. +CMAKE_GENERATOR:INTERNAL=Unix Makefiles +//Start directory with the top level CMakeLists.txt file for this +// project +CMAKE_HOME_DIRECTORY:INTERNAL=/home/hgabor/RawTherapee/2.5/gui88/rtengine +//Install .so files without execute permission. +CMAKE_INSTALL_SO_NO_EXE:INTERNAL=1 +//Advanced flag for variable: CMAKE_LINKER +CMAKE_LINKER-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_MAKE_PROGRAM +CMAKE_MAKE_PROGRAM-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_MODULE_LINKER_FLAGS +CMAKE_MODULE_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_MODULE_LINKER_FLAGS_DEBUG +CMAKE_MODULE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL +CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_MODULE_LINKER_FLAGS_RELEASE +CMAKE_MODULE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_NM +CMAKE_NM-ADVANCED:INTERNAL=1 +//number of local generators +CMAKE_NUMBER_OF_LOCAL_GENERATORS:INTERNAL=1 +//Advanced flag for variable: CMAKE_OBJCOPY +CMAKE_OBJCOPY-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_OBJDUMP +CMAKE_OBJDUMP-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_RANLIB +CMAKE_RANLIB-ADVANCED:INTERNAL=1 +//Path to CMake installation. +CMAKE_ROOT:INTERNAL=/usr/share/cmake-2.6 +//Advanced flag for variable: CMAKE_SHARED_LINKER_FLAGS +CMAKE_SHARED_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_SHARED_LINKER_FLAGS_DEBUG +CMAKE_SHARED_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL +CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_SHARED_LINKER_FLAGS_RELEASE +CMAKE_SHARED_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_SKIP_RPATH +CMAKE_SKIP_RPATH-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_STRIP +CMAKE_STRIP-ADVANCED:INTERNAL=1 +//uname command +CMAKE_UNAME:INTERNAL=/bin/uname +//Advanced flag for variable: CMAKE_USE_RELATIVE_PATHS +CMAKE_USE_RELATIVE_PATHS-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_VERBOSE_MAKEFILE +CMAKE_VERBOSE_MAKEFILE-ADVANCED:INTERNAL=1 +GLIB2_CFLAGS:INTERNAL=-I/usr/include/glib-2.0;-I/usr/lib/glib-2.0/include +GLIB2_CFLAGS_I:INTERNAL= +GLIB2_CFLAGS_OTHER:INTERNAL= +GLIB2_FOUND:INTERNAL=1 +GLIB2_INCLUDEDIR:INTERNAL=/usr/include +GLIB2_INCLUDE_DIRS:INTERNAL=/usr/include/glib-2.0;/usr/lib/glib-2.0/include +GLIB2_LDFLAGS:INTERNAL=-lglib-2.0 +GLIB2_LDFLAGS_OTHER:INTERNAL= +GLIB2_LIBDIR:INTERNAL=/usr/lib +GLIB2_LIBRARIES:INTERNAL=glib-2.0 +GLIB2_LIBRARY_DIRS:INTERNAL= +GLIB2_LIBS:INTERNAL= +GLIB2_LIBS_L:INTERNAL= +GLIB2_LIBS_OTHER:INTERNAL= +GLIB2_LIBS_PATHS:INTERNAL= +GLIB2_PREFIX:INTERNAL=/usr +GLIB2_STATIC_CFLAGS:INTERNAL=-I/usr/include/glib-2.0;-I/usr/lib/glib-2.0/include +GLIB2_STATIC_CFLAGS_I:INTERNAL= +GLIB2_STATIC_CFLAGS_OTHER:INTERNAL= +GLIB2_STATIC_INCLUDE_DIRS:INTERNAL=/usr/include/glib-2.0;/usr/lib/glib-2.0/include +GLIB2_STATIC_LDFLAGS:INTERNAL=-lglib-2.0 +GLIB2_STATIC_LDFLAGS_OTHER:INTERNAL= +GLIB2_STATIC_LIBDIR:INTERNAL= +GLIB2_STATIC_LIBRARIES:INTERNAL=glib-2.0 +GLIB2_STATIC_LIBRARY_DIRS:INTERNAL= +GLIB2_STATIC_LIBS:INTERNAL= +GLIB2_STATIC_LIBS_L:INTERNAL= +GLIB2_STATIC_LIBS_OTHER:INTERNAL= +GLIB2_STATIC_LIBS_PATHS:INTERNAL= +GLIB2_VERSION:INTERNAL=2.18.2 +GLIB2_glib-2.0_INCLUDEDIR:INTERNAL= +GLIB2_glib-2.0_LIBDIR:INTERNAL= +GLIB2_glib-2.0_PREFIX:INTERNAL= +GLIB2_glib-2.0_VERSION:INTERNAL= +GLIBMM_CFLAGS:INTERNAL=-I/usr/include/glibmm-2.4;-I/usr/lib/glibmm-2.4/include;-I/usr/include/sigc++-2.0;-I/usr/lib/sigc++-2.0/include;-I/usr/include/glib-2.0;-I/usr/lib/glib-2.0/include +GLIBMM_CFLAGS_I:INTERNAL= +GLIBMM_CFLAGS_OTHER:INTERNAL= +GLIBMM_FOUND:INTERNAL=1 +GLIBMM_INCLUDEDIR:INTERNAL=/usr/include +GLIBMM_INCLUDE_DIRS:INTERNAL=/usr/include/glibmm-2.4;/usr/lib/glibmm-2.4/include;/usr/include/sigc++-2.0;/usr/lib/sigc++-2.0/include;/usr/include/glib-2.0;/usr/lib/glib-2.0/include +GLIBMM_LDFLAGS:INTERNAL=-lglibmm-2.4;-lgobject-2.0;-lsigc-2.0;-lglib-2.0 +GLIBMM_LDFLAGS_OTHER:INTERNAL= +GLIBMM_LIBDIR:INTERNAL=/usr/lib +GLIBMM_LIBRARIES:INTERNAL=glibmm-2.4;gobject-2.0;sigc-2.0;glib-2.0 +GLIBMM_LIBRARY_DIRS:INTERNAL= +GLIBMM_LIBS:INTERNAL= +GLIBMM_LIBS_L:INTERNAL= +GLIBMM_LIBS_OTHER:INTERNAL= +GLIBMM_LIBS_PATHS:INTERNAL= +GLIBMM_PREFIX:INTERNAL=/usr +GLIBMM_STATIC_CFLAGS:INTERNAL=-I/usr/include/glibmm-2.4;-I/usr/lib/glibmm-2.4/include;-I/usr/include/sigc++-2.0;-I/usr/lib/sigc++-2.0/include;-I/usr/include/glib-2.0;-I/usr/lib/glib-2.0/include +GLIBMM_STATIC_CFLAGS_I:INTERNAL= +GLIBMM_STATIC_CFLAGS_OTHER:INTERNAL= +GLIBMM_STATIC_INCLUDE_DIRS:INTERNAL=/usr/include/glibmm-2.4;/usr/lib/glibmm-2.4/include;/usr/include/sigc++-2.0;/usr/lib/sigc++-2.0/include;/usr/include/glib-2.0;/usr/lib/glib-2.0/include +GLIBMM_STATIC_LDFLAGS:INTERNAL=-lglibmm-2.4;-lgobject-2.0;-lsigc-2.0;-lglib-2.0 +GLIBMM_STATIC_LDFLAGS_OTHER:INTERNAL= +GLIBMM_STATIC_LIBDIR:INTERNAL= +GLIBMM_STATIC_LIBRARIES:INTERNAL=glibmm-2.4;gobject-2.0;sigc-2.0;glib-2.0 +GLIBMM_STATIC_LIBRARY_DIRS:INTERNAL= +GLIBMM_STATIC_LIBS:INTERNAL= +GLIBMM_STATIC_LIBS_L:INTERNAL= +GLIBMM_STATIC_LIBS_OTHER:INTERNAL= +GLIBMM_STATIC_LIBS_PATHS:INTERNAL= +GLIBMM_VERSION:INTERNAL=2.18.1 +GLIBMM_glibmm-2.4_INCLUDEDIR:INTERNAL= +GLIBMM_glibmm-2.4_LIBDIR:INTERNAL= +GLIBMM_glibmm-2.4_PREFIX:INTERNAL= +GLIBMM_glibmm-2.4_VERSION:INTERNAL= +//Advanced flag for variable: PKG_CONFIG_EXECUTABLE +PKG_CONFIG_EXECUTABLE-ADVANCED:INTERNAL=1 +SIGC_CFLAGS:INTERNAL=-I/usr/include/sigc++-2.0;-I/usr/lib/sigc++-2.0/include +SIGC_CFLAGS_I:INTERNAL= +SIGC_CFLAGS_OTHER:INTERNAL= +SIGC_FOUND:INTERNAL=1 +SIGC_INCLUDEDIR:INTERNAL=/usr/include +SIGC_INCLUDE_DIRS:INTERNAL=/usr/include/sigc++-2.0;/usr/lib/sigc++-2.0/include +SIGC_LDFLAGS:INTERNAL=-lsigc-2.0 +SIGC_LDFLAGS_OTHER:INTERNAL= +SIGC_LIBDIR:INTERNAL=/usr/lib +SIGC_LIBRARIES:INTERNAL=sigc-2.0 +SIGC_LIBRARY_DIRS:INTERNAL= +SIGC_LIBS:INTERNAL= +SIGC_LIBS_L:INTERNAL= +SIGC_LIBS_OTHER:INTERNAL= +SIGC_LIBS_PATHS:INTERNAL= +SIGC_PREFIX:INTERNAL=/usr +SIGC_STATIC_CFLAGS:INTERNAL=-I/usr/include/sigc++-2.0;-I/usr/lib/sigc++-2.0/include +SIGC_STATIC_CFLAGS_I:INTERNAL= +SIGC_STATIC_CFLAGS_OTHER:INTERNAL= +SIGC_STATIC_INCLUDE_DIRS:INTERNAL=/usr/include/sigc++-2.0;/usr/lib/sigc++-2.0/include +SIGC_STATIC_LDFLAGS:INTERNAL=-lsigc-2.0 +SIGC_STATIC_LDFLAGS_OTHER:INTERNAL= +SIGC_STATIC_LIBDIR:INTERNAL= +SIGC_STATIC_LIBRARIES:INTERNAL=sigc-2.0 +SIGC_STATIC_LIBRARY_DIRS:INTERNAL= +SIGC_STATIC_LIBS:INTERNAL= +SIGC_STATIC_LIBS_L:INTERNAL= +SIGC_STATIC_LIBS_OTHER:INTERNAL= +SIGC_STATIC_LIBS_PATHS:INTERNAL= +SIGC_VERSION:INTERNAL=2.0.18 +SIGC_sigc++-2.0_INCLUDEDIR:INTERNAL= +SIGC_sigc++-2.0_LIBDIR:INTERNAL= +SIGC_sigc++-2.0_PREFIX:INTERNAL= +SIGC_sigc++-2.0_VERSION:INTERNAL= +__pkg_config_checked_GLIB2:INTERNAL=1 +__pkg_config_checked_GLIBMM:INTERNAL=1 +__pkg_config_checked_SIGC:INTERNAL=1 + diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt new file mode 100755 index 000000000..f07fd960c --- /dev/null +++ b/rtengine/CMakeLists.txt @@ -0,0 +1,49 @@ +cmake_minimum_required(VERSION 2.6) +find_package(PkgConfig) + +pkg_check_modules (GLIB2 glib-2.0>=2.16) +pkg_check_modules (GLIBMM glibmm-2.4>=2.16) +pkg_check_modules (SIGC sigc++-2.0) + +IF (WIN32) + SET (EXTRA_LIBDIR "../lib; ../rawzor_win") + SET (EXTRA_INCDIR "../winclude; ../rawzor_win") + SET (EXTRA_LIB "ws2_32 ../lib/libiptcdata.a ../lib/libjpeg.a ../lib/libpng.a ../lib/libtiff.a ../lib/libz.a ../rawzor_win/rwz_sdk_s.a") + ADD_DEFINITIONS (-DRAWZOR_SUPPORT) +ELSE (WIN32) + IF (CMAKE_SIZEOF_VOID_P EQUAL 4) + SET (EXTRA_INCDIR "../rawzor_lin32") + SET (EXTRA_LIBDIR "../rawzor_lin32") + ELSEIF (CMAKE_SIZEOF_VOID_P EQUAL 8) + SET (EXTRA_INCDIR "../rawzor_lin64") + SET (EXTRA_LIBDIR "../rawzor_lin64") + ENDIF (CMAKE_SIZEOF_VOID_P EQUAL 4) + SET (EXTRA_LIB "iptcdata -lrwz_sdk") + ADD_DEFINITIONS (-DRAWZOR_SUPPORT) +ENDIF (WIN32) + +include_directories (. ../rtexif ${EXTRA_INCDIR} ${GLIB2_INCLUDE_DIRS} ${GLIBMM_INCLUDE_DIRS}) +link_directories (../rtexif ${EXTRA_LIBDIR} ${GLIB2_LIBRARY_DIRS} ${GLIBMM_LIBRARY_DIRS}) + +add_library (rtengine SHARED colortemp.cc curves.cc dcraw.cc gauss.cc iccstore.cc + image8.cc image16.cc imagedata.cc imageio.cc improcfun.cc init.cc dcrop.cc + loadinitial.cc procparams.cc rawimagesource.cc shmap.cc simpleprocess.cc refreshmap.cc + stdimagesource.cc myfile.cc iccjpeg.c hlmultipliers.cc improccoordinator.cc + helpers.cc processingjob.cc rtthumbnail.cc utils.cc hlmultipliers.cc bilateral2.cc) + +set_target_properties (rtengine PROPERTIES COMPILE_FLAGS "-O3 -ffast-math -fexpensive-optimizations -funroll-loops -msse") + +#add_executable (rtcmd rtetest.cc) +#add_executable (ppmap pparamsmap.cc) + +target_link_libraries (rtengine rtexif lcms ${EXTRA_LIB} gthread-2.0 gobject-2.0 ${GLIB2_LIBRARIES} ${GLIBMM_LIBRARIES}) +#target_link_libraries (rtcmd rtengine) +#target_link_libraries (ppmap rtengine) + +IF (WIN32) +install (FILES librtengine.dll DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/../release + PERMISSIONS OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ ) +ELSE (WIN32) +install (FILES librtengine.so DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/../release + PERMISSIONS OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ ) +ENDIF (WIN32) diff --git a/rtengine/Doxyfile b/rtengine/Doxyfile new file mode 100755 index 000000000..5eb3c98fc --- /dev/null +++ b/rtengine/Doxyfile @@ -0,0 +1,1356 @@ +# Doxyfile 1.5.5 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = RawTherapee Image Processing Engine (RIPE) + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = 1.0 + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = doc + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, +# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, +# Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, +# and Ukrainian. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. + +DETAILS_AT_TOP = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentstion. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = YES + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is enabled by default, which results in a transparent +# background. Warning: Depending on the platform used, enabling this option +# may lead to badly anti-aliased labels on the edges of a graph (i.e. they +# become hard to read). + +DOT_TRANSPARENT = YES + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff --git a/rtengine/alignedbuffer.h b/rtengine/alignedbuffer.h new file mode 100755 index 000000000..4eabe5665 --- /dev/null +++ b/rtengine/alignedbuffer.h @@ -0,0 +1,40 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _ALIGNEDBUFFER_ +#define _ALIGNEDBUFFER_ + +template class AlignedBuffer { + + private: + T* real ; + + public: + T* data ; + + AlignedBuffer (int size, int align=16) { + real = new T[size+2*align]; + data = (T*)((long)real + (align-((long)real)%align)); + } + + ~AlignedBuffer () { + delete [] real; + } +}; + +#endif diff --git a/rtengine/bilateral2.cc b/rtengine/bilateral2.cc new file mode 100755 index 000000000..956f661e4 --- /dev/null +++ b/rtengine/bilateral2.cc @@ -0,0 +1,35 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +void bilateral_unsigned (unsigned short** src, unsigned short** dst, unsigned short** buffer, Dim dim, double sigma, double sens) { + + bilateral (src, dst, buffer, dim, sigma, sens); +} + +void bilateral_signed (short** src, short** dst, short** buffer, Dim dim, double sigma, double sens) { + + bilateral (src, dst, buffer, dim, sigma, sens); +} + +void bilateral_box_unsigned (unsigned short** src, unsigned short** dst, int W, int H, int sigmar, double sigmas, bilateralparams row) { + + bilateral (src, dst, W, H, sigmar, sigmas, row.row_from, row.row_to); +} + diff --git a/rtengine/bilateral2.h b/rtengine/bilateral2.h new file mode 100755 index 000000000..4aea99d23 --- /dev/null +++ b/rtengine/bilateral2.h @@ -0,0 +1,750 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _BILATERAL2_ +#define _BILATERAL2_ + +#include +#include +#include +#include +#include +#include + +#define MAX(a,b) ((a)<(b)?(b):(a)) +#define MIN(a,b) ((a)>(b)?(b):(a)) + +#define ELEM(a,b) (src[i-a][j-b] * ec[src[i-a][j-b]-src[i][j]+0x10000]) +#define SULY(a,b) (ec[src[i-a][j-b]-src[i][j]+0x10000]) + +#define BL_BEGIN(a,b) double scale = (a); \ + int* ec = new int [0x20000]; \ + for (int i=0; i<0x20000; i++) \ + ec[i] = (int)(exp(-(double)(i-0x10000)*(double)(i-0x10000) / (2.0*sens*sens))*scale); \ + int start = row_from; \ + if (start<(b)) start = (b); \ + int end = row_to; \ + if (end>H-(b)) end = H-(b); \ + for (int i=start; i=end || j>=W-(b)) \ + dst[i][j] = src[i][j]; \ + else \ + dst[i][j] = buffer[i][j]; + +#define BL_OPER3(a11,a12,a21,a22) A v = a11*ELEM(-1,-1) + a12*ELEM(-1,0) + a11*ELEM(-1,1) + \ + a21*ELEM(0,-1) + a22*ELEM(0,0) + a21*ELEM(0,1) + \ + a11*ELEM(1,-1) + a12*ELEM(1,0) + a11*ELEM(1,1); \ + v /= a11*SULY(-1,-1) + a12*SULY(-1,0) + a11*SULY(-1,1) + \ + a21*SULY(0,-1) + a22*SULY(0,0) + a21*SULY(0,1) + \ + a11*SULY(1,-1) + a12*SULY(1,0) + a11*SULY(1,1); + + +#define BL_OPER5(a11,a12,a13,a21,a22,a23,a31,a32,a33) A v = a11*ELEM(-2,-2) + a12*ELEM(-2,-1) + a13*ELEM(-2,0) + a12*ELEM(-2,1) + a11*ELEM(-2,2) + \ + a21*ELEM(-1,-2) + a22*ELEM(-1,-1) + a23*ELEM(-1,0) + a22*ELEM(-1,1) + a21*ELEM(-1,2) + \ + a31*ELEM(0,-2) + a32*ELEM(0,-1) + a33*ELEM(0,0) + a32*ELEM(0,1) + a31*ELEM(0,2) + \ + a21*ELEM(1,-2) + a22*ELEM(1,-1) + a23*ELEM(1,0) + a22*ELEM(1,1) + a21*ELEM(1,2) + \ + a11*ELEM(2,-2) + a12*ELEM(2,-1) + a13*ELEM(2,0) + a12*ELEM(2,1) + a11*ELEM(2,2); \ + v /= a11*SULY(-2,-2) + a12*SULY(-2,-1) + a13*SULY(-2,0) + a12*SULY(-2,1) + a11*SULY(-2,2) + \ + a21*SULY(-1,-2) + a22*SULY(-1,-1) + a23*SULY(-1,0) + a22*SULY(-1,1) + a21*SULY(-1,2) + \ + a31*SULY(0,-2) + a32*SULY(0,-1) + a33*SULY(0,0) + a32*SULY(0,1) + a31*SULY(0,2) + \ + a21*SULY(1,-2) + a22*SULY(1,-1) + a23*SULY(1,0) + a22*SULY(1,1) + a21*SULY(1,2) + \ + a11*SULY(2,-2) + a12*SULY(2,-1) + a13*SULY(2,0) + a12*SULY(2,1) + a11*SULY(2,2); + +#define BL_OPER7(a11,a12,a13,a14,a21,a22,a23,a24,a31,a32,a33,a34,a41,a42,a43,a44) \ + A v = a11*ELEM(-3,-3) + a12*ELEM(-3,-2) + a13*ELEM(-3,-1) + a14*ELEM(-3,0) + a13*ELEM(-3,1) + a12*ELEM(-3,2) + a11*ELEM(-3,3) + \ + a21*ELEM(-2,-3) + a22*ELEM(-2,-2) + a23*ELEM(-2,-1) + a24*ELEM(-2,0) + a23*ELEM(-2,1) + a22*ELEM(-2,2) + a21*ELEM(-2,3) + \ + a31*ELEM(-1,-3) + a32*ELEM(-1,-2) + a33*ELEM(-1,-1) + a34*ELEM(-1,0) + a33*ELEM(-1,1) + a32*ELEM(-1,2) + a31*ELEM(-1,3) + \ + a41*ELEM(0,-3) + a42*ELEM(0,-2) + a43*ELEM(0,-1) + a44*ELEM(0,0) + a43*ELEM(0,1) + a42*ELEM(0,2) + a41*ELEM(0,3) + \ + a31*ELEM(1,-3) + a32*ELEM(1,-2) + a33*ELEM(1,-1) + a34*ELEM(1,0) + a33*ELEM(1,1) + a32*ELEM(1,2) + a31*ELEM(1,3) + \ + a21*ELEM(2,-3) + a22*ELEM(2,-2) + a23*ELEM(2,-1) + a24*ELEM(2,0) + a23*ELEM(2,1) + a22*ELEM(2,2) + a21*ELEM(2,3) + \ + a11*ELEM(3,-3) + a12*ELEM(3,-2) + a13*ELEM(3,-1) + a14*ELEM(3,0) + a13*ELEM(3,1) + a12*ELEM(3,2) + a11*ELEM(3,3); \ + v /= a11*SULY(-3,-3) + a12*SULY(-3,-2) + a13*SULY(-3,-1) + a14*SULY(-3,0) + a13*SULY(-3,1) + a12*SULY(-3,2) + a11*SULY(-3,3) + \ + a21*SULY(-2,-3) + a22*SULY(-2,-2) + a23*SULY(-2,-1) + a24*SULY(-2,0) + a23*SULY(-2,1) + a22*SULY(-2,2) + a21*SULY(-2,3) + \ + a31*SULY(-1,-3) + a32*SULY(-1,-2) + a33*SULY(-1,-1) + a34*SULY(-1,0) + a33*SULY(-1,1) + a32*SULY(-1,2) + a31*SULY(-1,3) + \ + a41*SULY(0,-3) + a42*SULY(0,-2) + a43*SULY(0,-1) + a44*SULY(0,0) + a43*SULY(0,1) + a42*SULY(0,2) + a41*SULY(0,3) + \ + a31*SULY(1,-3) + a32*SULY(1,-2) + a33*SULY(1,-1) + a34*SULY(1,0) + a33*SULY(1,1) + a32*SULY(1,2) + a31*SULY(1,3) + \ + a21*SULY(2,-3) + a22*SULY(2,-2) + a23*SULY(2,-1) + a24*SULY(2,0) + a23*SULY(2,1) + a22*SULY(2,2) + a21*SULY(2,3) + \ + a11*SULY(3,-3) + a12*SULY(3,-2) + a13*SULY(3,-1) + a14*SULY(3,0) + a13*SULY(3,1) + a12*SULY(3,2) + a11*SULY(3,3); + + +#define BL_OPER9(a11,a12,a13,a14,a15,a21,a22,a23,a24,a25,a31,a32,a33,a34,a35,a41,a42,a43,a44,a45,a51,a52,a53,a54,a55) \ + A v = a11*ELEM(-4,-4) + a12*ELEM(-4,-3) + a13*ELEM(-4,-2) + a14*ELEM(-4,-1) + a15*ELEM(-4,0) + a14*ELEM(-4,1) + a13*ELEM(-4,2) + a12*ELEM(-4,3) + a11*ELEM(-4,4) + \ + a21*ELEM(-3,-4) + a22*ELEM(-3,-3) + a23*ELEM(-3,-2) + a24*ELEM(-3,-1) + a25*ELEM(-3,0) + a24*ELEM(-3,1) + a23*ELEM(-3,2) + a22*ELEM(-3,3) + a21*ELEM(-3,4) + \ + a31*ELEM(-2,-4) + a32*ELEM(-2,-3) + a33*ELEM(-2,-2) + a34*ELEM(-2,-1) + a35*ELEM(-2,0) + a34*ELEM(-2,1) + a33*ELEM(-2,2) + a32*ELEM(-2,3) + a31*ELEM(-2,4) + \ + a41*ELEM(-1,-4) + a42*ELEM(-1,-3) + a43*ELEM(-1,-2) + a44*ELEM(-1,-1) + a45*ELEM(-1,0) + a44*ELEM(-1,1) + a43*ELEM(-1,2) + a42*ELEM(-1,3) + a41*ELEM(-1,4) + \ + a51*ELEM(0,-4) + a52*ELEM(0,-3) + a53*ELEM(0,-2) + a54*ELEM(0,-1) + a55*ELEM(0,0) + a54*ELEM(0,1) + a53*ELEM(0,2) + a52*ELEM(0,3) + a51*ELEM(0,4) + \ + a41*ELEM(1,-4) + a42*ELEM(1,-3) + a43*ELEM(1,-2) + a44*ELEM(1,-1) + a45*ELEM(1,0) + a44*ELEM(1,1) + a43*ELEM(1,2) + a42*ELEM(1,3) + a41*ELEM(1,4) + \ + a31*ELEM(2,-4) + a32*ELEM(2,-3) + a33*ELEM(2,-2) + a34*ELEM(2,-1) + a35*ELEM(2,0) + a34*ELEM(2,1) + a33*ELEM(2,2) + a32*ELEM(2,3) + a31*ELEM(2,4) + \ + a21*ELEM(3,-4) + a22*ELEM(3,-3) + a23*ELEM(3,-2) + a24*ELEM(3,-1) + a25*ELEM(3,0) + a24*ELEM(3,1) + a23*ELEM(3,2) + a22*ELEM(3,3) + a21*ELEM(3,4) + \ + a11*ELEM(4,-4) + a12*ELEM(4,-3) + a13*ELEM(4,-2) + a14*ELEM(4,-1) + a15*ELEM(4,0) + a14*ELEM(4,1) + a13*ELEM(4,2) + a12*ELEM(4,3) + a11*ELEM(4,4); \ + v /= a11*SULY(-4,-4) + a12*SULY(-4,-3) + a13*SULY(-4,-2) + a14*SULY(-4,-1) + a15*SULY(-4,0) + a14*SULY(-4,1) + a13*SULY(-4,2) + a12*SULY(-4,3) + a11*SULY(-4,4) + \ + a21*SULY(-3,-4) + a22*SULY(-3,-3) + a23*SULY(-3,-2) + a24*SULY(-3,-1) + a25*SULY(-3,0) + a24*SULY(-3,1) + a23*SULY(-3,2) + a22*SULY(-3,3) + a21*SULY(-3,4) + \ + a31*SULY(-2,-4) + a32*SULY(-2,-3) + a33*SULY(-2,-2) + a34*SULY(-2,-1) + a35*SULY(-2,0) + a34*SULY(-2,1) + a33*SULY(-2,2) + a32*SULY(-2,3) + a31*SULY(-2,4) + \ + a41*SULY(-1,-4) + a42*SULY(-1,-3) + a43*SULY(-1,-2) + a44*SULY(-1,-1) + a45*SULY(-1,0) + a44*SULY(-1,1) + a43*SULY(-1,2) + a42*SULY(-1,3) + a41*SULY(-1,4) + \ + a51*SULY(0,-4) + a52*SULY(0,-3) + a53*SULY(0,-2) + a54*SULY(0,-1) + a55*SULY(0,0) + a54*SULY(0,1) + a53*SULY(0,2) + a52*SULY(0,3) + a51*SULY(0,4) + \ + a41*SULY(1,-4) + a42*SULY(1,-3) + a43*SULY(1,-2) + a44*SULY(1,-1) + a45*SULY(1,0) + a44*SULY(1,1) + a43*SULY(1,2) + a42*SULY(1,3) + a41*SULY(1,4) + \ + a31*SULY(2,-4) + a32*SULY(2,-3) + a33*SULY(2,-2) + a34*SULY(2,-1) + a35*SULY(2,0) + a34*SULY(2,1) + a33*SULY(2,2) + a32*SULY(2,3) + a31*SULY(2,4) + \ + a21*SULY(3,-4) + a22*SULY(3,-3) + a23*SULY(3,-2) + a24*SULY(3,-1) + a25*SULY(3,0) + a24*SULY(3,1) + a23*SULY(3,2) + a22*SULY(3,3) + a21*SULY(3,4) + \ + a11*SULY(4,-4) + a12*SULY(4,-3) + a13*SULY(4,-2) + a14*SULY(4,-1) + a15*SULY(4,0) + a14*SULY(4,1) + a13*SULY(4,2) + a12*SULY(4,3) + a11*SULY(4,4); + +#define BL_OPER11(a11,a12,a13,a14,a15,a16,a21,a22,a23,a24,a25,a26,a31,a32,a33,a34,a35,a36,a41,a42,a43,a44,a45,a46,a51,a52,a53,a54,a55,a56,a61,a62,a63,a64,a65,a66) \ + A v = a11*ELEM(-5,-5) + a12*ELEM(-5,-4) + a13*ELEM(-5,-3) + a14*ELEM(-5,-2) + a15*ELEM(-5,-1) + a16*ELEM(-5,0) + a15*ELEM(-5,1) + a14*ELEM(-5,2) + a13*ELEM(-5,3) + a12*ELEM(-5,4) + a11*ELEM(-5,5) + \ + a21*ELEM(-4,-5) + a22*ELEM(-4,-4) + a23*ELEM(-4,-3) + a24*ELEM(-4,-2) + a25*ELEM(-4,-1) + a26*ELEM(-4,0) + a25*ELEM(-4,1) + a24*ELEM(-4,2) + a23*ELEM(-4,3) + a22*ELEM(-4,4) + a21*ELEM(-4,5) + \ + a31*ELEM(-3,-5) + a32*ELEM(-3,-4) + a33*ELEM(-3,-3) + a34*ELEM(-3,-2) + a35*ELEM(-3,-1) + a36*ELEM(-3,0) + a35*ELEM(-3,1) + a34*ELEM(-3,2) + a33*ELEM(-3,3) + a32*ELEM(-3,4) + a31*ELEM(-3,5) + \ + a41*ELEM(-2,-5) + a42*ELEM(-2,-4) + a43*ELEM(-2,-3) + a44*ELEM(-2,-2) + a45*ELEM(-2,-1) + a46*ELEM(-2,0) + a45*ELEM(-2,1) + a44*ELEM(-2,2) + a43*ELEM(-2,3) + a42*ELEM(-2,4) + a41*ELEM(-4,5) + \ + a51*ELEM(-1,-5) + a52*ELEM(-1,-4) + a53*ELEM(-1,-3) + a54*ELEM(-1,-2) + a55*ELEM(-1,-1) + a56*ELEM(-1,0) + a55*ELEM(-1,1) + a54*ELEM(-1,2) + a53*ELEM(-1,3) + a52*ELEM(-1,4) + a51*ELEM(-1,5) + \ + a61*ELEM(0,-5) + a62*ELEM(0,-4) + a63*ELEM(0,-3) + a64*ELEM(0,-2) + a65*ELEM(0,-1) + a66*ELEM(0,0) + a65*ELEM(0,1) + a64*ELEM(0,2) + a63*ELEM(0,3) + a62*ELEM(0,4) + a61*ELEM(0,5) + \ + a51*ELEM(1,-5) + a52*ELEM(1,-4) + a53*ELEM(1,-3) + a54*ELEM(1,-2) + a55*ELEM(1,-1) + a56*ELEM(1,0) + a55*ELEM(1,1) + a54*ELEM(1,2) + a53*ELEM(1,3) + a52*ELEM(1,4) + a51*ELEM(1,5) + \ + a41*ELEM(2,-5) + a42*ELEM(2,-4) + a43*ELEM(2,-3) + a44*ELEM(2,-2) + a45*ELEM(2,-1) + a46*ELEM(2,0) + a45*ELEM(2,1) + a44*ELEM(2,2) + a43*ELEM(2,3) + a42*ELEM(2,4) + a41*ELEM(2,5) + \ + a31*ELEM(3,-5) + a32*ELEM(3,-4) + a33*ELEM(3,-3) + a34*ELEM(3,-2) + a35*ELEM(3,-1) + a36*ELEM(3,0) + a35*ELEM(3,1) + a34*ELEM(3,2) + a33*ELEM(3,3) + a32*ELEM(3,4) + a31*ELEM(3,5) + \ + a21*ELEM(4,-5) + a22*ELEM(4,-4) + a23*ELEM(4,-3) + a24*ELEM(4,-2) + a25*ELEM(4,-1) + a26*ELEM(4,0) + a25*ELEM(4,1) + a24*ELEM(4,2) + a23*ELEM(4,3) + a22*ELEM(4,4) + a21*ELEM(4,5) + \ + a11*ELEM(5,-5) + a12*ELEM(5,-4) + a13*ELEM(5,-3) + a14*ELEM(5,-2) + a15*ELEM(5,-1) + a16*ELEM(5,0) + a15*ELEM(5,1) + a14*ELEM(5,2) + a13*ELEM(5,3) + a12*ELEM(5,4) + a11*ELEM(5,5); \ + v /= a11*SULY(-5,-5) + a12*SULY(-5,-4) + a13*SULY(-5,-3) + a14*SULY(-5,-2) + a15*SULY(-5,-1) + a16*SULY(-5,0) + a15*SULY(-5,1) + a14*SULY(-5,2) + a13*SULY(-5,3) + a12*SULY(-5,4) + a11*SULY(-5,5) + \ + a21*SULY(-4,-5) + a22*SULY(-4,-4) + a23*SULY(-4,-3) + a24*SULY(-4,-2) + a25*SULY(-4,-1) + a26*SULY(-4,0) + a25*SULY(-4,1) + a24*SULY(-4,2) + a23*SULY(-4,3) + a22*SULY(-4,4) + a21*SULY(-4,5) + \ + a31*SULY(-3,-5) + a32*SULY(-3,-4) + a33*SULY(-3,-3) + a34*SULY(-3,-2) + a35*SULY(-3,-1) + a36*SULY(-3,0) + a35*SULY(-3,1) + a34*SULY(-3,2) + a33*SULY(-3,3) + a32*SULY(-3,4) + a31*SULY(-3,5) + \ + a41*SULY(-2,-5) + a42*SULY(-2,-4) + a43*SULY(-2,-3) + a44*SULY(-2,-2) + a45*SULY(-2,-1) + a46*SULY(-2,0) + a45*SULY(-2,1) + a44*SULY(-2,2) + a43*SULY(-2,3) + a42*SULY(-2,4) + a41*SULY(-4,5) + \ + a51*SULY(-1,-5) + a52*SULY(-1,-4) + a53*SULY(-1,-3) + a54*SULY(-1,-2) + a55*SULY(-1,-1) + a56*SULY(-1,0) + a55*SULY(-1,1) + a54*SULY(-1,2) + a53*SULY(-1,3) + a52*SULY(-1,4) + a51*SULY(-1,5) + \ + a61*SULY(0,-5) + a62*SULY(0,-4) + a63*SULY(0,-3) + a64*SULY(0,-2) + a65*SULY(0,-1) + a66*SULY(0,0) + a65*SULY(0,1) + a64*SULY(0,2) + a63*SULY(0,3) + a62*SULY(0,4) + a61*SULY(0,5) + \ + a51*SULY(1,-5) + a52*SULY(1,-4) + a53*SULY(1,-3) + a54*SULY(1,-2) + a55*SULY(1,-1) + a56*SULY(1,0) + a55*SULY(1,1) + a54*SULY(1,2) + a53*SULY(1,3) + a52*SULY(1,4) + a51*SULY(1,5) + \ + a41*SULY(2,-5) + a42*SULY(2,-4) + a43*SULY(2,-3) + a44*SULY(2,-2) + a45*SULY(2,-1) + a46*SULY(2,0) + a45*SULY(2,1) + a44*SULY(2,2) + a43*SULY(2,3) + a42*SULY(2,4) + a41*SULY(2,5) + \ + a31*SULY(3,-5) + a32*SULY(3,-4) + a33*SULY(3,-3) + a34*SULY(3,-2) + a35*SULY(3,-1) + a36*SULY(3,0) + a35*SULY(3,1) + a34*SULY(3,2) + a33*SULY(3,3) + a32*SULY(3,4) + a31*SULY(3,5) + \ + a21*SULY(4,-5) + a22*SULY(4,-4) + a23*SULY(4,-3) + a24*SULY(4,-2) + a25*SULY(4,-1) + a26*SULY(4,0) + a25*SULY(4,1) + a24*SULY(4,2) + a23*SULY(4,3) + a22*SULY(4,4) + a21*SULY(4,5) + \ + a11*SULY(5,-5) + a12*SULY(5,-4) + a13*SULY(5,-3) + a14*SULY(5,-2) + a15*SULY(5,-1) + a16*SULY(5,0) + a15*SULY(5,1) + a14*SULY(5,2) + a13*SULY(5,3) + a12*SULY(5,4) + a11*SULY(5,5); \ + + +// sigma = 0.5 +template void bilateral05 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(318,1) + BL_OPER3(1,7,7,55) + BL_END(1) +} + +// sigma = 0.6 +template void bilateral06 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(768,1) + BL_OPER3(1,4,4,16) + BL_END(1) +} + +// sigma = 0.7 +template void bilateral07 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(366,2) + BL_OPER5(0,0,1,0,8,21,1,21,59) + BL_END(2) +} + +// sigma = 0.8 +template void bilateral08 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(753,2) + BL_OPER5(0,0,1,0,5,10,1,10,23) + BL_END(2) +} + +// sigma = 0.9 +template void bilateral09 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(595,2) + BL_OPER5(0,1,2,1,6,12,2,12,22) + BL_END(2) +} + +// sigma = 1.0 +template void bilateral10 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(910,2) + BL_OPER5(0,1,2,1,4,7,2,7,12) + BL_END(2) +} + +// sigma = 1.1 +template void bilateral11 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(209,3) + BL_OPER7(0,0,1,1,0,2,5,8,1,5,18,27,1,8,27,41) + BL_END(3) +} + +// sigma = 1.2 +template void bilateral12 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(322,3) + BL_OPER7(0,0,1,1,0,1,4,6,1,4,11,16,1,6,16,23) + BL_END(3) +} + +// sigma = 1.3 +template void bilateral13 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(336,3) + BL_OPER7(0,0,1,1,0,2,4,6,1,4,11,14,1,6,14,19) + BL_END(3) +} + +// sigma = 1.4 +template void bilateral14 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(195,3) + BL_OPER7(0,1,2,3,1,4,8,10,2,8,17,21,3,10,21,28) + BL_END(3) +} + +// sigma = 1.5 +template void bilateral15 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(132,4) + BL_OPER9(0,0,0,1,1,0,1,2,4,5,0,2,6,12,14,1,4,12,22,28,1,5,14,28,35) + BL_END(4) +} + +// sigma = 1.6 +template void bilateral16 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(180,4) + BL_OPER9(0,0,0,1,1,0,1,2,3,4,0,2,5,9,10,1,3,9,15,19,1,4,10,19,23) + BL_END(4) +} + +// sigma = 1.7 +template void bilateral17 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(195,4) + BL_OPER9(0,0,1,1,1,0,1,2,3,4,1,2,5,8,9,1,3,8,13,16,1,4,9,16,19) + BL_END(4) +} + +// sigma = 1.8 +template void bilateral18 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(151,4) + BL_OPER9(0,0,1,2,2,0,1,3,5,5,1,3,6,10,12,2,5,10,16,19,2,5,12,19,22) + BL_END(4) +} + +// sigma = 1.9 +template void bilateral19 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(151,4) + BL_OPER9(0,0,1,2,2,0,1,3,4,5,1,3,5,8,9,2,4,8,12,14,2,5,9,14,16) + BL_END(4) +} + +// sigma = 2 +template void bilateral20 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(116,5) + BL_OPER11(0,0,0,1,1,1,0,0,1,2,3,3,0,1,2,4,7,7,1,2,4,8,12,14,1,3,7,12,18,20,1,3,7,14,20,23) + BL_END(5) +} + +// sigma = 2.1 +template void bilateral21 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(127,5) + BL_OPER11(0,0,0,1,1,1,0,0,1,2,3,3,0,1,2,4,6,7,1,2,4,8,11,12,1,3,6,11,15,17,1,3,7,12,17,19) + BL_END(5) +} + +// sigma = 2.2 +template void bilateral22 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(109,5) + BL_OPER11(0,0,0,1,1,2,0,1,2,3,3,4,1,2,3,5,7,8,1,3,5,9,12,13,1,3,7,12,16,18,2,4,8,13,18,20) + BL_END(5) +} + +// sigma = 2.3 +template void bilateral23 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(132,5) + BL_OPER11(0,0,1,1,1,1,0,1,1,2,3,3,1,1,3,5,6,7,1,2,5,7,10,11,1,3,6,10,13,14,1,3,7,11,14,16) + BL_END(5) +} + +// sigma = 2.4 +template void bilateral24 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(156,5) + BL_OPER11(0,0,1,1,1,1,0,1,1,2,3,3,1,1,3,4,5,6,1,2,4,6,8,9,1,3,5,8,10,11,1,3,6,9,11,12) + BL_END(5) +} + +// sigma = 2.5 +template void bilateral25 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(173,5) + BL_OPER11(0,0,1,1,1,1,0,1,1,2,3,3,1,1,2,4,5,5,1,2,4,5,7,7,1,3,5,7,9,9,1,3,5,7,9,10) + BL_END(5) +} + +class Dim { + + public: + int W, H, row_from, row_to; + + Dim (int w, int h, int rf, int rt) : W(w), H(h), row_from(rf), row_to(rt) {} + +}; + +// main bilateral filter +template void bilateral (T** src, T** dst, T** buffer, Dim dim, double sigma, double sens) { + + int W = dim.W; + int H = dim.H; + int row_from = dim.row_from; + int row_to = dim.row_to; + + if (sigma<0.45) + for (int i=row_from; i (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<0.65) + bilateral06 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<0.75) + bilateral07 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<0.85) + bilateral08 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<0.95) + bilateral09 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<1.05) + bilateral10 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<1.15) + bilateral11 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<1.25) + bilateral12 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<1.35) + bilateral13 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<1.45) + bilateral14 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<1.55) + bilateral15 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<1.65) + bilateral16 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<1.75) + bilateral17 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<1.85) + bilateral18 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<1.95) + bilateral19 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<2.05) + bilateral20 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<2.15) + bilateral21 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<2.25) + bilateral22 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<2.35) + bilateral23 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<2.45) + bilateral24 (src, dst, buffer, W, H, row_from, row_to, sens); + else + bilateral25 (src, dst, buffer, W, H, row_from, row_to, sens); +} + +void bilateral_unsigned (unsigned short** src, unsigned short** dst, unsigned short** buffer, Dim dim, double sigma, double sens); +void bilateral_signed (short** src, short** dst, short** buffer, Dim dim, double sigma, double sens); + +/* +template void bilateral (T** src, int** dst, int W, int H, int sigmar, double sigmas) { + + time_t t1 = clock (); + + int r = 2.0*sigmas + 0.5; + + double scaleg = 1024.0; + + double MAXINT = 65536.0*65536.0; + double sgmax = 275000/(MAXINT/2.0/sigmar/sigmar+(r+1)*(r+1)/sigmas/sigmas); + printf ("sgmax = %lf\n", sgmax); + if (scaleg>sgmax) + scaleg = sgmax; + + // kernel vector for the spatial gaussian filter * 1024 + int* kernel = new int[1+2*r]; + for (int i=0; i<2*r+1; i++) { + kernel[i] = scaleg / (2.0*sigmas*sigmas) * (i-r)*(i-r) + 0.25; + printf ("kerneli = %d\n", kernel[i]); + } + + // exponential lookup table + int scale = (2.0*sigmar*sigmar) / scaleg; + int scalem = 65535/((1+2*r)*(1+2*r)); + int ec[256000]; + for (int i=0; i<256000; i++) + ec[i] = exp (-i/scaleg) * scalem; + + for (int i=r; i0?((a) void bilateral (T** src, T** dst, AlignedBuffer* buffer, int W, int H, double sigmar, double sigmas) { + + time_t t1 = clock (); + + float alpha = 0.5 / sigmar / sigmar; + + // buffer for the final image + float** buff_final = new float*[H]; + for (int i=0; i void bilateral (T** src, T** dst, int W, int H, int sigmar, double sigmas, int row_from, int row_to) { + + // range weights + double* ec = new double [0x20000]; + for (int i=0; i<0x20000; i++) + ec[i] = exp(-(double)(i-0x10000)*(double)(i-0x10000) / (2.0*sigmar*sigmar)); + + // histogram + unsigned short* hist = new unsigned short[1<>TRANSBIT]++; + + sigmar*=2; + + for (int i=row_from; ir) + for (int x = 0; x>TRANSBIT]--; + if (i>TRANSBIT]++; + + memcpy (hist, rhist, (1<r) + for (int x=MAX(0,i-r); x<=MIN(i+r,H-1); x++) + hist[src[x][j-r-1]>>TRANSBIT]--; + if (j>TRANSBIT]++; + + // calculate pixel value + float weight = 0.0; + for (int k=0; k<=(sigmar>>TRANSBIT); k++) { + float w = 1.0 - (double)k/(sigmar>>TRANSBIT); + int v = src[i][j]>>TRANSBIT; + if (v-k >= 0) { + weight += hist [v-k] * w; + buff_final[i][j] += hist [v-k] * w * (src[i][j]-(k< void bilateral (T** src, T** dst, AlignedBuffer* buffer, int W, int H, int sigmar, double sigmas) { + + time_t t1 = clock (); + + unsigned short** rowhist = new unsigned short* [H]; + for (int i=0; i>TRANSBIT]++; + + // let the game begin... + for (int j=r+1; j>TRANSBIT]--; + rowhist[i][src[i][j+r]>>TRANSBIT]++; + } + // sum up upper histograms + memset (hist, 0, (1<>TRANSBIT); k++) { + float w = 1.0 - (double)k/(sigmar>>TRANSBIT); + int v = src[i][j]>>TRANSBIT; + if (v-k >= 0) { + weight += hist [v-k] * w; + buff_final[i][j] += hist [v-k] * w * (src[i][j]-(k<H-r-1 || jW-r-1) + dst[i][j] = src[i][j]; + else + dst[i][j] = (T)CLIP(buff_final[i][j]); + + delete [] hist; + for (int i=0; i + * + * 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 +#include +#define MAXVAL 0xffff +#define CLIP(a) ((a)>0?((a)>8)+1)<<8) / ((src[i][j]>>8)+1)]) +//#define ELEM(a,b) (src[i-a][j-b] * ec[src[i-a][j-b]-src[i][j]+0x10000]) +//#define SULY(a,b) (ec[src[i-a][j-b]-src[i][j]+0x10000]) +#define SULY(a,b) (ec[(((src[i-a][j-b]>>8)+1)<<8) / ((src[i][j]>>8)+1)]) + +#define BL_BEGIN(a,b) double scale = (a); \ + int* ec = new int [0x10001]; \ + ec[0] = 1; \ + for (int i=1; i<0x10001; i++) \ + ec[i] = (int)(exp(-log(i/256.0)*log(i/256.0) / (2.0*sens/1000*sens/1000*i/256.0))*scale); \ +/* ec[i] = (int)(exp(-(double)(i-0x10000)*(double)(i-0x10000) / (2.0*sens*sens))*scale); */\ + int start = row_from; \ + if (start<(b)) start = (b); \ + int end = row_to; \ + if (end>H-(b)) end = H-(b); \ + for (int i=start; i=end || j>=W-(b)) \ + dst[i][j] = src[i][j]; \ + else \ + dst[i][j] = buffer[i][j]; + +#define BL_OPER3(a11,a12,a21,a22) A v = a11*ELEM(-1,-1) + a12*ELEM(-1,0) + a11*ELEM(-1,1) + \ + a21*ELEM(0,-1) + a22*ELEM(0,0) + a21*ELEM(0,1) + \ + a11*ELEM(1,-1) + a12*ELEM(1,0) + a11*ELEM(1,1); \ + v /= a11*SULY(-1,-1) + a12*SULY(-1,0) + a11*SULY(-1,1) + \ + a21*SULY(0,-1) + a22*SULY(0,0) + a21*SULY(0,1) + \ + a11*SULY(1,-1) + a12*SULY(1,0) + a11*SULY(1,1); + + +#define BL_OPER5(a11,a12,a13,a21,a22,a23,a31,a32,a33) A v = a11*ELEM(-2,-2) + a12*ELEM(-2,-1) + a13*ELEM(-2,0) + a12*ELEM(-2,1) + a11*ELEM(-2,2) + \ + a21*ELEM(-1,-2) + a22*ELEM(-1,-1) + a23*ELEM(-1,0) + a22*ELEM(-1,1) + a21*ELEM(-1,2) + \ + a31*ELEM(0,-2) + a32*ELEM(0,-1) + a33*ELEM(0,0) + a32*ELEM(0,1) + a31*ELEM(0,2) + \ + a21*ELEM(1,-2) + a22*ELEM(1,-1) + a23*ELEM(1,0) + a22*ELEM(1,1) + a21*ELEM(1,2) + \ + a11*ELEM(2,-2) + a12*ELEM(2,-1) + a13*ELEM(2,0) + a12*ELEM(2,1) + a11*ELEM(2,2); \ + v /= a11*SULY(-2,-2) + a12*SULY(-2,-1) + a13*SULY(-2,0) + a12*SULY(-2,1) + a11*SULY(-2,2) + \ + a21*SULY(-1,-2) + a22*SULY(-1,-1) + a23*SULY(-1,0) + a22*SULY(-1,1) + a21*SULY(-1,2) + \ + a31*SULY(0,-2) + a32*SULY(0,-1) + a33*SULY(0,0) + a32*SULY(0,1) + a31*SULY(0,2) + \ + a21*SULY(1,-2) + a22*SULY(1,-1) + a23*SULY(1,0) + a22*SULY(1,1) + a21*SULY(1,2) + \ + a11*SULY(2,-2) + a12*SULY(2,-1) + a13*SULY(2,0) + a12*SULY(2,1) + a11*SULY(2,2); + +#define BL_OPER7(a11,a12,a13,a14,a21,a22,a23,a24,a31,a32,a33,a34,a41,a42,a43,a44) \ + A v = a11*ELEM(-3,-3) + a12*ELEM(-3,-2) + a13*ELEM(-3,-1) + a14*ELEM(-3,0) + a13*ELEM(-3,1) + a12*ELEM(-3,2) + a11*ELEM(-3,3) + \ + a21*ELEM(-2,-3) + a22*ELEM(-2,-2) + a23*ELEM(-2,-1) + a24*ELEM(-2,0) + a23*ELEM(-2,1) + a22*ELEM(-2,2) + a21*ELEM(-2,3) + \ + a31*ELEM(-1,-3) + a32*ELEM(-1,-2) + a33*ELEM(-1,-1) + a34*ELEM(-1,0) + a33*ELEM(-1,1) + a32*ELEM(-1,2) + a31*ELEM(-1,3) + \ + a41*ELEM(0,-3) + a42*ELEM(0,-2) + a43*ELEM(0,-1) + a44*ELEM(0,0) + a43*ELEM(0,1) + a42*ELEM(0,2) + a41*ELEM(0,3) + \ + a31*ELEM(1,-3) + a32*ELEM(1,-2) + a33*ELEM(1,-1) + a34*ELEM(1,0) + a33*ELEM(1,1) + a32*ELEM(1,2) + a31*ELEM(1,3) + \ + a21*ELEM(2,-3) + a22*ELEM(2,-2) + a23*ELEM(2,-1) + a24*ELEM(2,0) + a23*ELEM(2,1) + a22*ELEM(2,2) + a21*ELEM(2,3) + \ + a11*ELEM(3,-3) + a12*ELEM(3,-2) + a13*ELEM(3,-1) + a14*ELEM(3,0) + a13*ELEM(3,1) + a12*ELEM(3,2) + a11*ELEM(3,3); \ + v /= a11*SULY(-3,-3) + a12*SULY(-3,-2) + a13*SULY(-3,-1) + a14*SULY(-3,0) + a13*SULY(-3,1) + a12*SULY(-3,2) + a11*SULY(-3,3) + \ + a21*SULY(-2,-3) + a22*SULY(-2,-2) + a23*SULY(-2,-1) + a24*SULY(-2,0) + a23*SULY(-2,1) + a22*SULY(-2,2) + a21*SULY(-2,3) + \ + a31*SULY(-1,-3) + a32*SULY(-1,-2) + a33*SULY(-1,-1) + a34*SULY(-1,0) + a33*SULY(-1,1) + a32*SULY(-1,2) + a31*SULY(-1,3) + \ + a41*SULY(0,-3) + a42*SULY(0,-2) + a43*SULY(0,-1) + a44*SULY(0,0) + a43*SULY(0,1) + a42*SULY(0,2) + a41*SULY(0,3) + \ + a31*SULY(1,-3) + a32*SULY(1,-2) + a33*SULY(1,-1) + a34*SULY(1,0) + a33*SULY(1,1) + a32*SULY(1,2) + a31*SULY(1,3) + \ + a21*SULY(2,-3) + a22*SULY(2,-2) + a23*SULY(2,-1) + a24*SULY(2,0) + a23*SULY(2,1) + a22*SULY(2,2) + a21*SULY(2,3) + \ + a11*SULY(3,-3) + a12*SULY(3,-2) + a13*SULY(3,-1) + a14*SULY(3,0) + a13*SULY(3,1) + a12*SULY(3,2) + a11*SULY(3,3); + + +#define BL_OPER9(a11,a12,a13,a14,a15,a21,a22,a23,a24,a25,a31,a32,a33,a34,a35,a41,a42,a43,a44,a45,a51,a52,a53,a54,a55) \ + A v = a11*ELEM(-4,-4) + a12*ELEM(-4,-3) + a13*ELEM(-4,-2) + a14*ELEM(-4,-1) + a15*ELEM(-4,0) + a14*ELEM(-4,1) + a13*ELEM(-4,2) + a12*ELEM(-4,3) + a11*ELEM(-4,4) + \ + a21*ELEM(-3,-4) + a22*ELEM(-3,-3) + a23*ELEM(-3,-2) + a24*ELEM(-3,-1) + a25*ELEM(-3,0) + a24*ELEM(-3,1) + a23*ELEM(-3,2) + a22*ELEM(-3,3) + a21*ELEM(-3,4) + \ + a31*ELEM(-2,-4) + a32*ELEM(-2,-3) + a33*ELEM(-2,-2) + a34*ELEM(-2,-1) + a35*ELEM(-2,0) + a34*ELEM(-2,1) + a33*ELEM(-2,2) + a32*ELEM(-2,3) + a31*ELEM(-2,4) + \ + a41*ELEM(-1,-4) + a42*ELEM(-1,-3) + a43*ELEM(-1,-2) + a44*ELEM(-1,-1) + a45*ELEM(-1,0) + a44*ELEM(-1,1) + a43*ELEM(-1,2) + a42*ELEM(-1,3) + a41*ELEM(-1,4) + \ + a51*ELEM(0,-4) + a52*ELEM(0,-3) + a53*ELEM(0,-2) + a54*ELEM(0,-1) + a55*ELEM(0,0) + a54*ELEM(0,1) + a53*ELEM(0,2) + a52*ELEM(0,3) + a51*ELEM(0,4) + \ + a41*ELEM(1,-4) + a42*ELEM(1,-3) + a43*ELEM(1,-2) + a44*ELEM(1,-1) + a45*ELEM(1,0) + a44*ELEM(1,1) + a43*ELEM(1,2) + a42*ELEM(1,3) + a41*ELEM(1,4) + \ + a31*ELEM(2,-4) + a32*ELEM(2,-3) + a33*ELEM(2,-2) + a34*ELEM(2,-1) + a35*ELEM(2,0) + a34*ELEM(2,1) + a33*ELEM(2,2) + a32*ELEM(2,3) + a31*ELEM(2,4) + \ + a21*ELEM(3,-4) + a22*ELEM(3,-3) + a23*ELEM(3,-2) + a24*ELEM(3,-1) + a25*ELEM(3,0) + a24*ELEM(3,1) + a23*ELEM(3,2) + a22*ELEM(3,3) + a21*ELEM(3,4) + \ + a11*ELEM(4,-4) + a12*ELEM(4,-3) + a13*ELEM(4,-2) + a14*ELEM(4,-1) + a15*ELEM(4,0) + a14*ELEM(4,1) + a13*ELEM(4,2) + a12*ELEM(4,3) + a11*ELEM(4,4); \ + v /= a11*SULY(-4,-4) + a12*SULY(-4,-3) + a13*SULY(-4,-2) + a14*SULY(-4,-1) + a15*SULY(-4,0) + a14*SULY(-4,1) + a13*SULY(-4,2) + a12*SULY(-4,3) + a11*SULY(-4,4) + \ + a21*SULY(-3,-4) + a22*SULY(-3,-3) + a23*SULY(-3,-2) + a24*SULY(-3,-1) + a25*SULY(-3,0) + a24*SULY(-3,1) + a23*SULY(-3,2) + a22*SULY(-3,3) + a21*SULY(-3,4) + \ + a31*SULY(-2,-4) + a32*SULY(-2,-3) + a33*SULY(-2,-2) + a34*SULY(-2,-1) + a35*SULY(-2,0) + a34*SULY(-2,1) + a33*SULY(-2,2) + a32*SULY(-2,3) + a31*SULY(-2,4) + \ + a41*SULY(-1,-4) + a42*SULY(-1,-3) + a43*SULY(-1,-2) + a44*SULY(-1,-1) + a45*SULY(-1,0) + a44*SULY(-1,1) + a43*SULY(-1,2) + a42*SULY(-1,3) + a41*SULY(-1,4) + \ + a51*SULY(0,-4) + a52*SULY(0,-3) + a53*SULY(0,-2) + a54*SULY(0,-1) + a55*SULY(0,0) + a54*SULY(0,1) + a53*SULY(0,2) + a52*SULY(0,3) + a51*SULY(0,4) + \ + a41*SULY(1,-4) + a42*SULY(1,-3) + a43*SULY(1,-2) + a44*SULY(1,-1) + a45*SULY(1,0) + a44*SULY(1,1) + a43*SULY(1,2) + a42*SULY(1,3) + a41*SULY(1,4) + \ + a31*SULY(2,-4) + a32*SULY(2,-3) + a33*SULY(2,-2) + a34*SULY(2,-1) + a35*SULY(2,0) + a34*SULY(2,1) + a33*SULY(2,2) + a32*SULY(2,3) + a31*SULY(2,4) + \ + a21*SULY(3,-4) + a22*SULY(3,-3) + a23*SULY(3,-2) + a24*SULY(3,-1) + a25*SULY(3,0) + a24*SULY(3,1) + a23*SULY(3,2) + a22*SULY(3,3) + a21*SULY(3,4) + \ + a11*SULY(4,-4) + a12*SULY(4,-3) + a13*SULY(4,-2) + a14*SULY(4,-1) + a15*SULY(4,0) + a14*SULY(4,1) + a13*SULY(4,2) + a12*SULY(4,3) + a11*SULY(4,4); + +#define BL_OPER11(a11,a12,a13,a14,a15,a16,a21,a22,a23,a24,a25,a26,a31,a32,a33,a34,a35,a36,a41,a42,a43,a44,a45,a46,a51,a52,a53,a54,a55,a56,a61,a62,a63,a64,a65,a66) \ + A v = a11*ELEM(-5,-5) + a12*ELEM(-5,-4) + a13*ELEM(-5,-3) + a14*ELEM(-5,-2) + a15*ELEM(-5,-1) + a16*ELEM(-5,0) + a15*ELEM(-5,1) + a14*ELEM(-5,2) + a13*ELEM(-5,3) + a12*ELEM(-5,4) + a11*ELEM(-5,5) + \ + a21*ELEM(-4,-5) + a22*ELEM(-4,-4) + a23*ELEM(-4,-3) + a24*ELEM(-4,-2) + a25*ELEM(-4,-1) + a26*ELEM(-4,0) + a25*ELEM(-4,1) + a24*ELEM(-4,2) + a23*ELEM(-4,3) + a22*ELEM(-4,4) + a21*ELEM(-4,5) + \ + a31*ELEM(-3,-5) + a32*ELEM(-3,-4) + a33*ELEM(-3,-3) + a34*ELEM(-3,-2) + a35*ELEM(-3,-1) + a36*ELEM(-3,0) + a35*ELEM(-3,1) + a34*ELEM(-3,2) + a33*ELEM(-3,3) + a32*ELEM(-3,4) + a31*ELEM(-3,5) + \ + a41*ELEM(-2,-5) + a42*ELEM(-2,-4) + a43*ELEM(-2,-3) + a44*ELEM(-2,-2) + a45*ELEM(-2,-1) + a46*ELEM(-2,0) + a45*ELEM(-2,1) + a44*ELEM(-2,2) + a43*ELEM(-2,3) + a42*ELEM(-2,4) + a41*ELEM(-4,5) + \ + a51*ELEM(-1,-5) + a52*ELEM(-1,-4) + a53*ELEM(-1,-3) + a54*ELEM(-1,-2) + a55*ELEM(-1,-1) + a56*ELEM(-1,0) + a55*ELEM(-1,1) + a54*ELEM(-1,2) + a53*ELEM(-1,3) + a52*ELEM(-1,4) + a51*ELEM(-1,5) + \ + a61*ELEM(0,-5) + a62*ELEM(0,-4) + a63*ELEM(0,-3) + a64*ELEM(0,-2) + a65*ELEM(0,-1) + a66*ELEM(0,0) + a65*ELEM(0,1) + a64*ELEM(0,2) + a63*ELEM(0,3) + a62*ELEM(0,4) + a61*ELEM(0,5) + \ + a51*ELEM(1,-5) + a52*ELEM(1,-4) + a53*ELEM(1,-3) + a54*ELEM(1,-2) + a55*ELEM(1,-1) + a56*ELEM(1,0) + a55*ELEM(1,1) + a54*ELEM(1,2) + a53*ELEM(1,3) + a52*ELEM(1,4) + a51*ELEM(1,5) + \ + a41*ELEM(2,-5) + a42*ELEM(2,-4) + a43*ELEM(2,-3) + a44*ELEM(2,-2) + a45*ELEM(2,-1) + a46*ELEM(2,0) + a45*ELEM(2,1) + a44*ELEM(2,2) + a43*ELEM(2,3) + a42*ELEM(2,4) + a41*ELEM(2,5) + \ + a31*ELEM(3,-5) + a32*ELEM(3,-4) + a33*ELEM(3,-3) + a34*ELEM(3,-2) + a35*ELEM(3,-1) + a36*ELEM(3,0) + a35*ELEM(3,1) + a34*ELEM(3,2) + a33*ELEM(3,3) + a32*ELEM(3,4) + a31*ELEM(3,5) + \ + a21*ELEM(4,-5) + a22*ELEM(4,-4) + a23*ELEM(4,-3) + a24*ELEM(4,-2) + a25*ELEM(4,-1) + a26*ELEM(4,0) + a25*ELEM(4,1) + a24*ELEM(4,2) + a23*ELEM(4,3) + a22*ELEM(4,4) + a21*ELEM(4,5) + \ + a11*ELEM(5,-5) + a12*ELEM(5,-4) + a13*ELEM(5,-3) + a14*ELEM(5,-2) + a15*ELEM(5,-1) + a16*ELEM(5,0) + a15*ELEM(5,1) + a14*ELEM(5,2) + a13*ELEM(5,3) + a12*ELEM(5,4) + a11*ELEM(5,5); \ + v /= a11*SULY(-5,-5) + a12*SULY(-5,-4) + a13*SULY(-5,-3) + a14*SULY(-5,-2) + a15*SULY(-5,-1) + a16*SULY(-5,0) + a15*SULY(-5,1) + a14*SULY(-5,2) + a13*SULY(-5,3) + a12*SULY(-5,4) + a11*SULY(-5,5) + \ + a21*SULY(-4,-5) + a22*SULY(-4,-4) + a23*SULY(-4,-3) + a24*SULY(-4,-2) + a25*SULY(-4,-1) + a26*SULY(-4,0) + a25*SULY(-4,1) + a24*SULY(-4,2) + a23*SULY(-4,3) + a22*SULY(-4,4) + a21*SULY(-4,5) + \ + a31*SULY(-3,-5) + a32*SULY(-3,-4) + a33*SULY(-3,-3) + a34*SULY(-3,-2) + a35*SULY(-3,-1) + a36*SULY(-3,0) + a35*SULY(-3,1) + a34*SULY(-3,2) + a33*SULY(-3,3) + a32*SULY(-3,4) + a31*SULY(-3,5) + \ + a41*SULY(-2,-5) + a42*SULY(-2,-4) + a43*SULY(-2,-3) + a44*SULY(-2,-2) + a45*SULY(-2,-1) + a46*SULY(-2,0) + a45*SULY(-2,1) + a44*SULY(-2,2) + a43*SULY(-2,3) + a42*SULY(-2,4) + a41*SULY(-4,5) + \ + a51*SULY(-1,-5) + a52*SULY(-1,-4) + a53*SULY(-1,-3) + a54*SULY(-1,-2) + a55*SULY(-1,-1) + a56*SULY(-1,0) + a55*SULY(-1,1) + a54*SULY(-1,2) + a53*SULY(-1,3) + a52*SULY(-1,4) + a51*SULY(-1,5) + \ + a61*SULY(0,-5) + a62*SULY(0,-4) + a63*SULY(0,-3) + a64*SULY(0,-2) + a65*SULY(0,-1) + a66*SULY(0,0) + a65*SULY(0,1) + a64*SULY(0,2) + a63*SULY(0,3) + a62*SULY(0,4) + a61*SULY(0,5) + \ + a51*SULY(1,-5) + a52*SULY(1,-4) + a53*SULY(1,-3) + a54*SULY(1,-2) + a55*SULY(1,-1) + a56*SULY(1,0) + a55*SULY(1,1) + a54*SULY(1,2) + a53*SULY(1,3) + a52*SULY(1,4) + a51*SULY(1,5) + \ + a41*SULY(2,-5) + a42*SULY(2,-4) + a43*SULY(2,-3) + a44*SULY(2,-2) + a45*SULY(2,-1) + a46*SULY(2,0) + a45*SULY(2,1) + a44*SULY(2,2) + a43*SULY(2,3) + a42*SULY(2,4) + a41*SULY(2,5) + \ + a31*SULY(3,-5) + a32*SULY(3,-4) + a33*SULY(3,-3) + a34*SULY(3,-2) + a35*SULY(3,-1) + a36*SULY(3,0) + a35*SULY(3,1) + a34*SULY(3,2) + a33*SULY(3,3) + a32*SULY(3,4) + a31*SULY(3,5) + \ + a21*SULY(4,-5) + a22*SULY(4,-4) + a23*SULY(4,-3) + a24*SULY(4,-2) + a25*SULY(4,-1) + a26*SULY(4,0) + a25*SULY(4,1) + a24*SULY(4,2) + a23*SULY(4,3) + a22*SULY(4,4) + a21*SULY(4,5) + \ + a11*SULY(5,-5) + a12*SULY(5,-4) + a13*SULY(5,-3) + a14*SULY(5,-2) + a15*SULY(5,-1) + a16*SULY(5,0) + a15*SULY(5,1) + a14*SULY(5,2) + a13*SULY(5,3) + a12*SULY(5,4) + a11*SULY(5,5); \ + + +// sigma = 0.5 +template void bilateral05 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(318,1) + BL_OPER3(1,7,7,55) + BL_END(1) +} + +// sigma = 0.6 +template void bilateral06 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(768,1) + BL_OPER3(1,4,4,16) + BL_END(1) +} + +// sigma = 0.7 +template void bilateral07 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(366,2) + BL_OPER5(0,0,1,0,8,21,1,21,59) + BL_END(2) +} + +// sigma = 0.8 +template void bilateral08 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(753,2) + BL_OPER5(0,0,1,0,5,10,1,10,23) + BL_END(2) +} + +// sigma = 0.9 +template void bilateral09 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(595,2) + BL_OPER5(0,1,2,1,6,12,2,12,22) + BL_END(2) +} + +// sigma = 1.0 +template void bilateral10 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(910,2) + BL_OPER5(0,1,2,1,4,7,2,7,12) + BL_END(2) +} + +// sigma = 1.1 +template void bilateral11 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(209,3) + BL_OPER7(0,0,1,1,0,2,5,8,1,5,18,27,1,8,27,41) + BL_END(3) +} + +// sigma = 1.2 +template void bilateral12 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(322,3) + BL_OPER7(0,0,1,1,0,1,4,6,1,4,11,16,1,6,16,23) + BL_END(3) +} + +// sigma = 1.3 +template void bilateral13 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(336,3) + BL_OPER7(0,0,1,1,0,2,4,6,1,4,11,14,1,6,14,19) + BL_END(3) +} + +// sigma = 1.4 +template void bilateral14 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(195,3) + BL_OPER7(0,1,2,3,1,4,8,10,2,8,17,21,3,10,21,28) + BL_END(3) +} + +// sigma = 1.5 +template void bilateral15 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(132,4) + BL_OPER9(0,0,0,1,1,0,1,2,4,5,0,2,6,12,14,1,4,12,22,28,1,5,14,28,35) + BL_END(4) +} + +// sigma = 1.6 +template void bilateral16 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(180,4) + BL_OPER9(0,0,0,1,1,0,1,2,3,4,0,2,5,9,10,1,3,9,15,19,1,4,10,19,23) + BL_END(4) +} + +// sigma = 1.7 +template void bilateral17 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(195,4) + BL_OPER9(0,0,1,1,1,0,1,2,3,4,1,2,5,8,9,1,3,8,13,16,1,4,9,16,19) + BL_END(4) +} + +// sigma = 1.8 +template void bilateral18 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(151,4) + BL_OPER9(0,0,1,2,2,0,1,3,5,5,1,3,6,10,12,2,5,10,16,19,2,5,12,19,22) + BL_END(4) +} + +// sigma = 1.9 +template void bilateral19 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(151,4) + BL_OPER9(0,0,1,2,2,0,1,3,4,5,1,3,5,8,9,2,4,8,12,14,2,5,9,14,16) + BL_END(4) +} + +// sigma = 2 +template void bilateral20 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(116,5) + BL_OPER11(0,0,0,1,1,1,0,0,1,2,3,3,0,1,2,4,7,7,1,2,4,8,12,14,1,3,7,12,18,20,1,3,7,14,20,23) + BL_END(5) +} + +// sigma = 2.1 +template void bilateral21 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(127,5) + BL_OPER11(0,0,0,1,1,1,0,0,1,2,3,3,0,1,2,4,6,7,1,2,4,8,11,12,1,3,6,11,15,17,1,3,7,12,17,19) + BL_END(5) +} + +// sigma = 2.2 +template void bilateral22 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(109,5) + BL_OPER11(0,0,0,1,1,2,0,1,2,3,3,4,1,2,3,5,7,8,1,3,5,9,12,13,1,3,7,12,16,18,2,4,8,13,18,20) + BL_END(5) +} + +// sigma = 2.3 +template void bilateral23 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(132,5) + BL_OPER11(0,0,1,1,1,1,0,1,1,2,3,3,1,1,3,5,6,7,1,2,5,7,10,11,1,3,6,10,13,14,1,3,7,11,14,16) + BL_END(5) +} + +// sigma = 2.4 +template void bilateral24 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(156,5) + BL_OPER11(0,0,1,1,1,1,0,1,1,2,3,3,1,1,3,4,5,6,1,2,4,6,8,9,1,3,5,8,10,11,1,3,6,9,11,12) + BL_END(5) +} + +// sigma = 2.5 +template void bilateral25 (T** src, T** dst, T** buffer, int W, int H, int row_from, int row_to, double sens) { + + BL_BEGIN(173,5) + BL_OPER11(0,0,1,1,1,1,0,1,1,2,3,3,1,1,2,4,5,5,1,2,4,5,7,7,1,3,5,7,9,9,1,3,5,7,9,10) + BL_END(5) +} + +class Dim { + + public: + int W, H, row_from, row_to; + + Dim (int w, int h, int rf, int rt) : W(w), H(h), row_from(rf), row_to(rt) {} + +}; + +// main bilateral filter +template void bilateral (T** src, T** dst, T** buffer, Dim dim, double sigma, double sens) { + + int W = dim.W; + int H = dim.H; + int row_from = dim.row_from; + int row_to = dim.row_to; + + if (sigma<0.45) + for (int i=row_from; i (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<0.65) + bilateral06 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<0.75) + bilateral07 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<0.85) + bilateral08 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<0.95) + bilateral09 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<1.05) + bilateral10 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<1.15) + bilateral11 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<1.25) + bilateral12 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<1.35) + bilateral13 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<1.45) + bilateral14 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<1.55) + bilateral15 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<1.65) + bilateral16 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<1.75) + bilateral17 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<1.85) + bilateral18 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<1.95) + bilateral19 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<2.05) + bilateral20 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<2.15) + bilateral21 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<2.25) + bilateral22 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<2.35) + bilateral23 (src, dst, buffer, W, H, row_from, row_to, sens); + else if (sigma<2.45) + bilateral24 (src, dst, buffer, W, H, row_from, row_to, sens); + else + bilateral25 (src, dst, buffer, W, H, row_from, row_to, sens); +} + +void bilateral_unsigned (unsigned short** src, unsigned short** dst, unsigned short** buffer, Dim dim, double sigma, double sens) { + + bilateral (src, dst, buffer, dim, sigma, sens); +} + +void bilateral_signed (short** src, short** dst, short** buffer, Dim dim, double sigma, double sens) { + + bilateral (src, dst, buffer, dim, sigma, sens); +} + + + +/* +template void bilateral (T** src, int** dst, int W, int H, int sigmar, double sigmas) { + + time_t t1 = clock (); + + int r = 2.0*sigmas + 0.5; + + double scaleg = 1024.0; + + double MAXINT = 65536.0*65536.0; + double sgmax = 275000/(MAXINT/2.0/sigmar/sigmar+(r+1)*(r+1)/sigmas/sigmas); + printf ("sgmax = %lf\n", sgmax); + if (scaleg>sgmax) + scaleg = sgmax; + + // kernel vector for the spatial gaussian filter * 1024 + int* kernel = new int[1+2*r]; + for (int i=0; i<2*r+1; i++) { + kernel[i] = scaleg / (2.0*sigmas*sigmas) * (i-r)*(i-r) + 0.25; + printf ("kerneli = %d\n", kernel[i]); + } + + // exponential lookup table + int scale = (2.0*sigmar*sigmar) / scaleg; + int scalem = 65535/((1+2*r)*(1+2*r)); + int ec[256000]; + for (int i=0; i<256000; i++) + ec[i] = exp (-i/scaleg) * scalem; + + for (int i=r; i void bilateral (T** src, T** dst, T** buffer, int W, int H, int sigmar, double sigmas) { + + time_t t1 = clock (); + + // buffer for the final image + float** buff_final = new float*[H]; + for (int i=0; i + * + * 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 . + */ +inline double tightestroot (double L, double a, double b, double r1, double r2, double r3); + +#ifndef __COLORCLIP__ +#define __COLORCLIP__ + +#include +#include "median.h" + +// gives back the tightest >0 amplification by which color clipping occures + +inline double tightestroot (double L, double a, double b, double r1, double r2, double r3) { + + register double an = a/500.0, bn = b/200.0, p = (L+16.0)/116.0; + + double coeff3 = r1*an*an*an - r3*bn*bn*bn; + double coeff2 = 3.0 * p * (r1*an*an + r3*bn*bn); + double coeff1 = 3.0 * p*p * (r1*an - r3*bn); + double coeff0 = p*p*p*(r1+r2+r3) - 1.0; + + double a1 = coeff2 / coeff3; + double a2 = coeff1 / coeff3; + double a3 = coeff0 / coeff3; + + double Q = (a1 * a1 - 3.0 * a2) / 9.0; + double R = (2.0 * a1 * a1 * a1 - 9.0 * a1 * a2 + 27.0 * a3) / 54.0; + double Qcubed = Q * Q * Q; + double d = Qcubed - R * R; + +// printf ("input L=%g, a=%g, b=%g\n", L, a, b); +// printf ("c1=%g, c2=%g, c3=%g, c4=%g\n", coeff3, coeff2, coeff1, coeff0); + + + /* Three real roots */ + if (d >= 0) { + double theta = acos(R / sqrt(Qcubed)); + double sqrtQ = sqrt(Q); + double x0 = -2.0 * sqrtQ * cos( theta / 3.0) - a1 / 3.0; + double x1 = -2.0 * sqrtQ * cos((theta + 2.0 * M_PI) / 3.0) - a1 / 3.0; + double x2 = -2.0 * sqrtQ * cos((theta + 4.0 * M_PI) / 3.0) - a1 / 3.0; + +// printf ("3 roots: %g, %g, %g\n", x0, x1, x2); + + SORT3 (x0,x1,x2,a1,a2,a3); + if (a1>0) + return a1; + if (a2>0) + return a2; + if (a3>0) + return a3; + return -1; + } + + /* One real root */ + else { +// double e = pow(sqrt(-d) + fabs(R), 1.0 / 3.0); + double e = exp (1.0 / 3.0 * log (sqrt(-d) + fabs(R))); + + if (R > 0) + e = -e; + + double x0 = (e + Q / e) - a1 / 3.0; + +// printf ("1 root: %g\n", x0); + + if (x0<0) + return -1; + else + return x0; + } +} + + +/******************************************************************************* + * FindCubicRoots + * + * Solve: + * coeff[3] * x^3 + coeff[2] * x^2 + coeff[1] * x + coeff[0] = 0 + * + * returns: + * 3 - 3 real roots + * 1 - 1 real root (2 complex conjugate) + *******************************************************************************/ + +/*long +FindCubicRoots(const FLOAT coeff[4], FLOAT x[3]) +{ + FLOAT a1 = coeff[2] / coeff[3]; + FLOAT a2 = coeff[1] / coeff[3]; + FLOAT a3 = coeff[0] / coeff[3]; + + double_t Q = (a1 * a1 - 3 * a2) / 9; + double_t R = (2 * a1 * a1 * a1 - 9 * a1 * a2 + 27 * a3) / 54; + double_t Qcubed = Q * Q * Q; + double_t d = Qcubed - R * R; + + if (d >= 0) { + double_t theta = acos(R / sqrt(Qcubed)); + double_t sqrtQ = sqrt(Q); + x[0] = -2 * sqrtQ * cos( theta / 3) - a1 / 3; + x[1] = -2 * sqrtQ * cos((theta + 2 * pi) / 3) - a1 / 3; + x[2] = -2 * sqrtQ * cos((theta + 4 * pi) / 3) - a1 / 3; + return (3); + } + + else { + double_t e = pow(sqrt(-d) + fabs(R), 1. / 3.); + if (R > 0) + e = -e; + x[0] = (e + Q / e) - a1 / 3.; + return (1); + } +} +*/ +#endif diff --git a/rtengine/colortemp.cc b/rtengine/colortemp.cc new file mode 100755 index 000000000..92a72c07c --- /dev/null +++ b/rtengine/colortemp.cc @@ -0,0 +1,87 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +using namespace rtengine; + +ColorTemp::ColorTemp (double t, double g) : temp(t), green(g) { + + clip (temp, green); +} + +void ColorTemp::clip (double &temp, double &green) { + + if (temp < MINTEMP) + temp = MINTEMP; + else if (temp > MAXTEMP) + temp = MAXTEMP; + + if (green < MINGREEN) + green = MINGREEN; + else if (green > MAXGREEN) + green = MAXGREEN; +} + +void ColorTemp::mul2temp (double rmul, double gmul, double bmul, double& temp, double& green) { + + double maxtemp=20000, mintemp=1000; + double tmpr, tmpg, tmpb; + temp=(maxtemp+mintemp)/2; + while (maxtemp-mintemp>1) { + temp2mul (temp, 1.0, tmpr, tmpg, tmpb); + if (tmpb/tmpr > bmul/rmul) + maxtemp = temp; + else + mintemp = temp; + temp=(maxtemp+mintemp)/2; + } + green = (tmpg/tmpr) / (gmul/rmul); + clip (temp, green); +} + +void ColorTemp::temp2mul (double temp, double green, double& rmul, double& gmul, double& bmul) { + + clip (temp, green); + + double xD; + if (temp<=4000) { + xD = 0.27475e9/(temp*temp*temp) - 0.98598e6/(temp*temp) + 1.17444e3/temp + 0.145986; + } else if (temp<=7000) { + xD = -4.6070e9/(temp*temp*temp) + 2.9678e6/(temp*temp) + 0.09911e3/temp + 0.244063; + } else { + xD = -2.0064e9/(temp*temp*temp) + 1.9018e6/(temp*temp) + 0.24748e3/temp + 0.237040; + } + double yD = -3.0*xD*xD + 2.87*xD - 0.275; + + double X = xD/yD; + double Y = 1.0; + double Z = (1.0-xD-yD)/yD; + + rmul = X * 3.24071 - Y * 1.53726 - Z * 0.498571; + gmul = - X * 0.969258 + Y * 1.87599 + Z * 0.0415557; + bmul = X * 0.0556352 - Y * 0.203996 + Z * 1.05707; + gmul /= green; + + double max = rmul; + if (gmul>max) max = gmul; + if (bmul>max) max = bmul; + rmul /= max; + gmul /= max; + bmul /= max; +} diff --git a/rtengine/colortemp.h b/rtengine/colortemp.h new file mode 100755 index 000000000..8cae8c965 --- /dev/null +++ b/rtengine/colortemp.h @@ -0,0 +1,57 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _COLORTEMP_ +#define _COLORTEMP_ + +#include + +namespace rtengine { + +#define MINTEMP 1200 +#define MAXTEMP 12000 +#define MINGREEN 0.02 +#define MAXGREEN 5.0 + +class ColorTemp { + + private: + double temp; + double green; + + static void clip (double &temp, double &green); + + public: + + ColorTemp () : temp(-1), green(-1) {} + ColorTemp (double t, double g); + ColorTemp (double mulr, double mulg, double mulb) { mul2temp (mulr, mulg, mulb, temp, green); } + + inline double getTemp () { return temp; } + inline double getGreen () { return green; } + + void getMultipliers (double &mulr, double &mulg, double &mulb) { temp2mul (temp, green, mulr, mulg, mulb); } + + static void mul2temp (double rmul, double gmul, double bmul, double& temp, double& green); + static void temp2mul (double temp, double green, double& rmul, double& gmul, double& bmul); + + bool operator== (const ColorTemp& other) { return fabs(temp-other.temp)<1e-10 && fabs(green-other.green)<1e-10; } + bool operator!= (const ColorTemp& other) { return !(*this==other); } +}; +}; +#endif diff --git a/rtengine/common.h b/rtengine/common.h new file mode 100755 index 000000000..6f76831d7 --- /dev/null +++ b/rtengine/common.h @@ -0,0 +1,76 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _COMMON_ +#define _COMMON_ + +#define ISRED(image,row,col) \ + ((image->filters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3)==0) +#define ISGREEN(image,row,col) \ + ((image->filters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3)==1) +#define ISBLUE(image,row,col) \ + ((image->filters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3)==2) + +#define FISRED(filter,row,col) \ + ((filter >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3)==0 || !filter) +#define FISGREEN(filter,row,col) \ + ((filter >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3)==1 || !filter) +#define FISBLUE(filter,row,col) \ + ((filter >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3)==2 || !filter) + +#define CMAXVAL 65535 + +#include + +struct RawImage { + + int width; + int height; + + unsigned filters; + + double red_multiplier; + double green_multiplier; + double blue_multiplier; + + double camwb_red; + double camwb_green; + double camwb_blue; + + int blackpoint; + int rgb_max; + int rotate_deg; + int fuji_width; + + double defgain; + + char *make, *model; + + int exifbase, prefilters, ciff_base, ciff_len; + + unsigned short* allocation; + unsigned short** data; // holds pixel values, data[i][j] corresponds to the ith row and jth column + + float coeff[3][3]; + float icoeff[3][3]; + + int profile_len; + char* profile_data; +}; + +#endif diff --git a/rtengine/coord2d.h b/rtengine/coord2d.h new file mode 100755 index 000000000..a78caf124 --- /dev/null +++ b/rtengine/coord2d.h @@ -0,0 +1,33 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef __COORD2D__ +#define __COORD2D__ + +namespace rtengine { + +class Coord2D { + + public: + double x, y; + Coord2D (double x_, double y_) : x(x_), y(y_) {} + Coord2D () {} + void set (double x_, double y_) { x = x_; y = y_; } +}; +}; +#endif diff --git a/rtengine/cubic.cc b/rtengine/cubic.cc new file mode 100755 index 000000000..9f576d0c8 --- /dev/null +++ b/rtengine/cubic.cc @@ -0,0 +1,82 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +/* Copyright (C) 1997-2001 Ken Turkowski. + * + * All rights reserved. + * + * Warranty Information + * Even though I have reviewed this software, I make no warranty + * or representation, either express or implied, with respect to this + * software, its quality, accuracy, merchantability, or fitness for a + * particular purpose. As a result, this software is provided "as is," + * and you, its user, are assuming the entire risk as to its quality + * and accuracy. + * + * This code may be used and freely distributed as long as it includes + * this copyright notice and the above warranty information. + */ + +#include + + +#define FLOAT float +#define double_t double + +/******************************************************************************* + * FindCubicRoots + * + * Solve: + * coeff[3] * x^3 + coeff[2] * x^2 + coeff[1] * x + coeff[0] = 0 + * + * returns: + * 3 - 3 real roots + * 1 - 1 real root (2 complex conjugate) + *******************************************************************************/ + +long +FindCubicRoots(const FLOAT coeff[4], FLOAT x[3]) +{ + FLOAT a1 = coeff[2] / coeff[3]; + FLOAT a2 = coeff[1] / coeff[3]; + FLOAT a3 = coeff[0] / coeff[3]; + + double_t Q = (a1 * a1 - 3 * a2) / 9; + double_t R = (2 * a1 * a1 * a1 - 9 * a1 * a2 + 27 * a3) / 54; + double_t Qcubed = Q * Q * Q; + double_t d = Qcubed - R * R; + + /* Three real roots */ + if (d >= 0) { + double_t theta = acos(R / sqrt(Qcubed)); + double_t sqrtQ = sqrt(Q); + x[0] = -2 * sqrtQ * cos( theta / 3) - a1 / 3; + x[1] = -2 * sqrtQ * cos((theta + 2 * 3.14159265) / 3) - a1 / 3; + x[2] = -2 * sqrtQ * cos((theta + 4 * 3.14159265) / 3) - a1 / 3; + return (3); + } + + /* One real root */ + else { + double_t e = pow(sqrt(-d) + fabs(R), 1. / 3.); + if (R > 0) + e = -e; + x[0] = (e + Q / e) - a1 / 3.; + return (1); + } +} diff --git a/rtengine/cubint.cc b/rtengine/cubint.cc new file mode 100755 index 000000000..220b6c1c7 --- /dev/null +++ b/rtengine/cubint.cc @@ -0,0 +1,75 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#define A (-0.85) +//#define CLIP(a) ((a>CMAXVAL)?a=CMAXVAL:((a<0)?0:a)) + +inline void cubint (Image16* src, int xs, int ys, double Dx, double Dy, unsigned short *r, unsigned short *g, unsigned short *b, double mul) { + + register double w[4]; + + { register double t1, t2; + t1 = -A*(Dx-1.0)*Dx; + t2 = (3.0-2.0*Dx)*Dx*Dx; + w[3] = t1*Dx; + w[2] = t1*(Dx-1.0) + t2; + w[1] = -t1*Dx + 1.0 - t2; + w[0] = -t1*(Dx-1.0); + } + + register double rd, gd, bd; + double yr[4], yg[4], yb[4]; + + for (int k=ys, kx=0; kr[k][i] * w[ix]; + gd += src->g[k][i] * w[ix]; + bd += src->b[k][i] * w[ix]; + } + yr[kx] = rd; yg[kx] = gd; yb[kx] = bd; + } + + + { register double t1, t2; + t1 = -A*(Dy-1.0)*Dy; + t2 = (3.0-2.0*Dy)*Dy*Dy; + w[3] = t1*Dy; + w[2] = t1*(Dy-1.0) + t2; + w[1] = -t1*Dy + 1.0 - t2; + w[0] = -t1*(Dy-1.0); + } + + rd = gd = bd = 0.0; + for (int i=0; i<4; i++) { + rd += yr[i] * w[i]; + gd += yg[i] * w[i]; + bd += yb[i] * w[i]; + } + + rd*=mul; + gd*=mul; + bd*=mul; + + *r = (int)CLIP(rd); + *g = (int)CLIP(gd); + *b = (int)CLIP(bd); + +// if (xs==100 && ys==100) +// printf ("r=%g, g=%g\n", *r, *g); +} diff --git a/rtengine/cubintch.cc b/rtengine/cubintch.cc new file mode 100755 index 000000000..5e0aa9207 --- /dev/null +++ b/rtengine/cubintch.cc @@ -0,0 +1,61 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ + +inline void cubintch (unsigned short** src, int xs, int ys, double Dx, double Dy, unsigned short *r, double mul) { + + register double w[4]; + + { register double t1, t2; + t1 = -A*(Dx-1.0)*Dx; + t2 = (3.0-2.0*Dx)*Dx*Dx; + w[3] = t1*Dx; + w[2] = t1*(Dx-1.0) + t2; + w[1] = -t1*Dx + 1.0 - t2; + w[0] = -t1*(Dx-1.0); + } + + register double rd; + double yr[4]; + + for (int k=ys, kx=0; k + * + * 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 +#include +#include +#include +#include +#include + +namespace rtengine { + +Curve::Curve (const char* iname, const char* descr) : islinear(false), isempty(false) { + + ypp = NULL; + name = iname; + char* buffer = new char[strlen(descr)+1]; + strcpy (buffer, descr); + char* token = strtok (buffer, ",; \t\n"); + std::vector xv; + std::vector yv; + while (token) { + double xd = atof (token); + token = strtok (NULL, ",; \t\n"); + if (token) { + double yd = atof (token); + xv.push_back (xd); + yv.push_back (yd); + } + token = strtok (NULL, ",; \t\n"); + } + N = xv.size (); + x = new double[N]; + y = new double[N]; + for (int i=0; i& p) { + + x = NULL; + y = NULL; + ypp = NULL; + name = "custom"; + isempty = true; + N = p.size()/2; + if (N<2) + return; + int ix = 0; + islinear = p[ix++]<0; + x = new double[N]; + y = new double[N]; + for (int i=0; i= 0; --k) + ypp[k] = ypp[k] * ypp[k + 1] + u[k]; + + delete [] u; + +} + +double Curve::getVal (double t) { +// +// Determine the interval [ T(I), T(I+1) ] that contains TVAL. +// Values below T[0] or above T[N-1] use extrapolation. +// + if (isempty) + return t; + + if (t>x[N-1]) + return y[N-1]; + else if (t 1){ + int k = (k_hi + k_lo) / 2; + if (x[k] > t) + k_hi = k; + else + k_lo = k; + } + + double h = x[k_hi] - x[k_lo]; + if (islinear) + return y[k_lo] + (t - x[k_lo]) * ( y[k_hi] - y[k_lo] ) / h; + else { + double a = (x[k_hi] - t) / h; + double b = (t - x[k_lo]) / h; + return a*y[k_lo] + b*y[k_hi] + ((a*a*a - a)*ypp[k_lo] + (b*b*b - b)*ypp[k_hi]) * (h*h)/6.0; + } + +/* + if (t>x[N-1]) + return y[N-1]; + else if (t CurveFactory::curves; + +/*double CurveFactory::centercontrast (double x, double b, double m) { + + if (b==0) + return x; + if (b>0) { + if (x>m) + return m + (1.0-m) * tanh (b*(x-m)/(1.0-m)) / tanh (b); + else + return m - m * tanh (b*(m-x)/m) / tanh (b); + } + else { + if (x>m) + return 2.0*x - m - (1.0-m) * tanh (b*(x-m)/(1.0-m)) / tanh (b); + else + return 2.0*x - m + m * tanh (b*(m-x)/m) / tanh (b); + } +} +*/ + +double CurveFactory::centercontrast (double x, double b, double m) { + + if (b==0) + return x; + if (b>0) { + if (x>m) + return m + (1.0-m) * tanh (b*(x-m)/(1.0-m)) / tanh (b); + else + return m + m * tanh (b*(x-m)/m) / tanh (b); + } + else { + if (x>m) + return 2.0*x - m - (1.0-m) * tanh (b*(x-m)/(1.0-m)) / tanh (b); + else + return 2.0*x - m - m * tanh (b*(x-m)/m) / tanh (b); + } +} + + + +double CurveFactory::contrast (double x, double a) { + + if (a==0) + return x; + else if (a>0) { + double s = (1.0+exp(-0.5*a)) / (1.0+exp(-(x-0.5)*a)) * (exp(0.5*a)-exp(-(x-0.5)*a)) / (exp(0.5*a)-exp(-0.5*a)); + return s; + } + else { + double s = (1.0+exp(-0.5*a)) / (1.0+exp(-(x-0.5)*a)) * (exp(0.5*a)-exp(-(x-0.5)*a)) / (exp(0.5*a)-exp(-0.5*a)); + return 2*x - s; + } +} + +double CurveFactory::brightness (double x, double a, double bd1, double bd2) { + + if (a==1) + return x; + else if (a<1) + return a*x; + else { + if (x < 1.0/a-bd1) + return a*x; + else if (x > 1.0/a+bd2) + return 1; + else { + double d = bd1+bd2; + double s = - (-a*d*(1.0+a*(bd2-x))*(1.0+a*(bd2-x))*(-1.0+a*(bd1+x))-(2.0+a*(bd1+3.0*bd2-2.0*x))*(-1.0+a*(bd1+x))*(-1.0+a*(bd1+x)) + (-1.0+a*bd1)*(1.0+a*(bd2-x))*(1.0+a*(bd2-x))*(-2.0+a*(3.0*bd1+bd2+2.0*x))) / (a*a*a*d*d*d); + return s; + } + } +} + +double CurveFactory::softClip (double x, double d1, double d2, double a, double b, double c, double d) { + + if (x<1.0-d1) + return x; + else if (x>1.0+d2) + return 1.0; + else + return a*x*x*x + b*x*x + c*x + d; +} + +double CurveFactory::dlower (const double b, const double m, const double c) { + + return b / (tanh(b) * 2.0 * m); +} + +double CurveFactory::dupper (const double b, const double m, const double c) { + + return b / (tanh(b) * 2.0 * (c-m)); +} + +double CurveFactory::solve_lower (double m, double c, double deriv) { + + double b_u = 2.0*m*deriv; + double b_l = 0.0; + + double b; + while (b_u-b_l > 0.0000001) { + b = (b_u+b_l) / 2.0; + if (dlower(b,m,c) 0.0000001) { + b = (b_u+b_l) / 2.0; + if (dupper(b,m,c)& points, double defmul, double ecomp, int black, double hlcompr, double shcompr, double br, double contr, double gamma_, bool igamma, int skip) { + + double def_mul = pow (2.0, defmul); + + // compute parameters of the gamma curve + double start = exp(gamma_*log( -0.099 / ((1.0/gamma_-1.0)*1.099 ))); + double slope = 1.099 * pow (start, 1.0/gamma_-1) - 0.099/start; + double mul = 1.099; + double add = 0.099; + + // theoretical maximum of the curve + double D = gamma_>0 ? gamma (def_mul, gamma_, start, slope, mul, add) : def_mul; + + double a = pow (2.0, ecomp); + double b = black / 65535.0; + + // curve without contrast + double* dcurve = new double[65536]; + + bool needcontrast = contr>0.00001 || contr<-0.00001; + bool needigamma = !needcontrast && igamma && gamma_>0; + + for (int i=0; i<=0xffff; i+= i<0xffff-skip ? skip : 1 ) { + + double val = (double)i / 65535.0; + val *= def_mul; + if (gamma_>0) + val = gamma (val, gamma_, start, slope, mul, add); + + val = basecurve (val, a, b, D, hlcompr/100.0, shcompr/100.0); + val = brightness (val, br/100.0); + +// if (tcurve) +// val = tcurve->getVal (val); + + if (needigamma) + val = igamma2 (val); + + if (val>1.0) + val = 1.0; + else if (val<0.0) + val = 0.0; + dcurve[i] = val; + } +/* +if (igamma) { + FILE* f = fopen ("curve.txt","wt"); + for (int i=0; i<65536; i++) +// fprintf (f, "%g\t%g\n", i/65535.0, basel(i/65535.0, 2, 0)); + fprintf (f, "%g\t%g\n", i/65535.0, clower(i/65535.0, 0.500015/0.5, 1.5)); +// fprintf (f, "%g\t%g\n", i/65535.0, basecurve(i/65535.0, 1.25701, 0, 1.47694, 1.0, 1.0)); +// fprintf (f, "%g\t%g\n", i/65535.0, dcurve[i]); + fclose (f); +} +*/ + + int prev = 0; + for (int i=1; i<=0xffff-skip; i++) { + if (i%skip==0) { + prev+=skip; + continue; + } + dcurve[i] = ( dcurve[prev] * (skip - i%skip) + dcurve[prev+skip] * (i%skip) ) / skip; + } + + if (needcontrast) { + // compute mean luminance of the image with the curve applied + int sum = 0; + double avg = 0; + for (int i=0; i<=0xffff; i++) { + avg += dcurve[i] * ohistogram[i]; + sum += ohistogram[i]; + } + avg /= sum; + + // compute contrast parameter + double contr_b = contr / 20; + if (contr_b>=0 && contr_b < 0.00001) + contr_b = 0.00001; + else if (contr_b<0 && contr_b > -0.00001) + contr_b = -0.00001; + + // apply contrast enhancement + for (int i=0; i<=0xffff; i++) { + double val = centercontrast (dcurve[i], contr_b, avg); + if (igamma && gamma_>0) + val = igamma2 (val); + if (val>1.0) val = 1.0; + if (val<0.0) val = 0.0; + curve[i] = (int) (65535.0 * val); + } + } + else + for (int i=0; i<=0xffff; i++) + curve[i] = (int) (65535.0 * dcurve[i]); + delete [] dcurve; +} + +void CurveFactory::updateCurve2 (int* curve, int* ohistogram, const std::vector& points, double ecomp, double br, int black, double hlcompr, double shcompr, double contr, double gamma_, bool igamma, int skip) { + + double ec_mul = pow (2, ecomp); + double bl = black / 65535.0; + double hi = pow (2.0,-br) + bl; + + // compute parameters of the gamma curve + double start = exp(gamma_*log( -0.099 / ((1.0/gamma_-1.0)*1.099 ))); + double slope = 1.099 * pow (start, 1.0/gamma_-1) - 0.099/start; + double mul = 1.099; + double add = 0.099; + + // compute parameters of the "levels" curve + shcompr /= 100.0; + hlcompr /= 100.0; + double correction = hlcompr<0.85 ? 1.0 : hlcompr+0.15; + correction = 1.0; + double d = pow (2.0,br); + double m = 0.5 / d + bl; + double c = (gamma_>0 ? gamma (ec_mul, gamma_, start, slope, mul, add) : ec_mul) * correction; +// double c = (gamma_>0 ? gamma (ec_mul, gamma_, start, slope, mul, add) : gamma2(ec_mul)) * correction; + + double b_upper = solve_upper (m, c, d); + double b_lower = solve_lower (m, c, d); + + // generate curve without contrast (in double) + +// Curve* tcurve = curves[type]; + Curve* tcurve = new Curve (points); + if (tcurve->isEmpty()) { + delete tcurve; + tcurve = NULL; + } + + double* dcurve = new double[65536]; + + double bltanh = tanh (b_lower); + double butanh = tanh (b_upper); + + if (d * (c - bl) < 1) + hlcompr = 0; + + bool needcontrast = contr>0.00001 || contr<-0.00001; + bool needigamma = !needcontrast && igamma && gamma_>0; + + for (int i=0; i<=0xffff; i+= i<0xffff-skip ? skip : 1 ) { + double val = (double)i / 65535.0; + val *= ec_mul; + if (gamma_>0) + val = gamma (val, gamma_, start, slope, mul, add); + +// double sval = levels (val, b_lower, b_upper, m, c); +// Acceleration: + double sval; + if (val <= m) { + double ttag = 2.0 / (1.0 + exp (-2.0*b_lower*(val-m)/m)) - 1.0; +// sval = (1.0 + tanh (b_lower*(val-m)/m) / bltanh) / 2.0; + sval = (1.0 + ttag / bltanh) / 2.0; + } + else { + double ttag = 2.0 / (1.0 + exp (-2.0*b_upper*(val-m)/(c-m))) - 1.0; +// sval = (1.0 + tanh (b_upper*(val-m)/(c-m)) / butanh) / 2.0; + sval = (1.0 + ttag / butanh) / 2.0; + } + + if (valhi) + val = (1.0 - hlcompr) + hlcompr * sval; + else if (valgetVal (val); + + if (needigamma) + val = igamma2 (val); + + if (val>1.0) + val = 1.0; + else if (val<0.0) + val = 0.0; + dcurve[i] = val; + } + +int prev = 0; +for (int i=1; i<=0xffff-skip; i++) { + if (i%skip==0) { + prev+=skip; + continue; + } + dcurve[i] = ( dcurve[prev] * (skip - i%skip) + dcurve[prev+skip] * (i%skip) ) / skip; +} + + if (needcontrast) { + // compute mean luminance of the image with the curve applied + int sum = 0; + double avg = 0; + for (int i=0; i<=0xffff; i++) { + avg += dcurve[i] * ohistogram[i]; + sum += ohistogram[i]; + } + avg /= sum; + + // compute contrast parameter + double contr_b = contr / 20; + if (contr_b>=0 && contr_b < 0.00001) + contr_b = 0.00001; + else if (contr_b<0 && contr_b > -0.00001) + contr_b = -0.00001; + + // apply contrast enhancement + for (int i=0; i<=0xffff; i++) { + double val = centercontrast (dcurve[i], contr_b, avg); + if (igamma && gamma_>0) + val = igamma2 (val); + if (val>1.0) val = 1.0; + if (val<0.0) val = 0.0; + curve[i] = (int) (65535.0 * val); + } + } + else + for (int i=0; i<=0xffff; i++) + curve[i] = (int) (65535.0 * dcurve[i]); +//if (igamma) { +// FILE* f = fopen ("curve.txt","wt"); +// for (int i=0; i<65536; i++) +// fprintf (f, "%d\t%d\n", i, curve[i]); +// fclose (f); +//} + + delete [] dcurve; +} + +int CurveFactory::gammatab [65536]; +int CurveFactory::igammatab_srgb [65536]; +int CurveFactory::gammatab_srgb [65536]; + +void CurveFactory::loadCurves (Glib::ustring fname) { + + for (int i=0; i<65536; i++) + gammatab_srgb[i] = (int)(65535 * gamma2 (i/65535.0)); + for (int i=0; i<65536; i++) + igammatab_srgb[i] = (int)(65535 * igamma2 (i/65535.0)); + for (int i=0; i<65536; i++) + gammatab[i] = (int)(65535 * pow (i/65535.0, 0.454545)); + + FILE* f = g_fopen (fname.c_str(), "rt"); + if (!f) + return; + + setlocale (LC_ALL, "C"); + + char* buffer = new char[1024]; + while (buffer = fgets(buffer, 1024, f)) { + int es = 0; + int llen = strlen(buffer); + for (es = 0; esgetName()] = c; + } + } + delete buffer; + + setlocale (LC_ALL, ""); +} + +std::vector CurveFactory::curveNames () { + + std::vector ret; + + int ix = 0; + for (std::map::iterator i = curves.begin(); i!=curves.end(); i++) + ret.push_back (i->second->getName()); + + return ret; +} +} + diff --git a/rtengine/curves.h b/rtengine/curves.h new file mode 100755 index 000000000..a8e82c8d7 --- /dev/null +++ b/rtengine/curves.h @@ -0,0 +1,147 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef __CURVES_H__ +#define __CURVES_H__ + +#include +#include +#include +#include + +namespace rtengine { + +class Curve { + + protected: + int N; + double* x; + double* y; + double* ypp; + Glib::ustring name; + bool islinear; + bool isempty; + + protected: + void d3_np_fs (double a[], double b[]); + void spline_cubic_set (); + + public: + + Curve (const char* iname, int iN, double ix[], double iy[]); + Curve (const char* iname, const char* descr); + Curve (const std::vector& points); + ~Curve (); + + double getVal (double x); + Glib::ustring getName (); + bool isEmpty () { return isempty; } +}; + +class CurveFactory { + + protected: + + static std::map curves; + static int gammatab[65536]; + static int igammatab_srgb[65536]; + static int gammatab_srgb[65536]; + static double solve_upper (double m, double c, double deriv); + static double solve_lower (double m, double c, double deriv); + static double dupper (const double b, const double m, const double c); + static double dlower (const double b, const double m, const double c); + + static inline double basel (double x, double m1, double m2) { + if (x==0.0) + return 0.0; + double k = sqrt ((m1-1.0)*(m1-m2)/2) / (1.0-m2); + double l = (m1-m2) / (1.0-m2) + k; + double lx = log(x); + return m2*x + (1.0-m2)*(2.0 - exp(k*lx))*exp(l*lx); + } + static inline double baseu (double x, double m1, double m2) { + return 1.0 - basel(1.0-x, m1, m2); + } + static inline double cupper (double x, double m, double hr) { + if (hr>1.0) + return baseu (x, m, 2.0*(hr-1.0)/m); + double x1 = (1.0-hr)/m; + double x2 = x1 + hr; + if (x>=x2) return 1.0; + if (x0) + return brightnessbase (x, amount); + else + return 1.0 - brightnessbase (1.0-x, -amount); + } + + + public: + + static inline double softClip (double x, double d1, double d2, double a, double b, double c, double d); + static inline double contrast (double x, double a); + static inline double centercontrast (double x, double b, double m); + static inline double brightness (double x, double a, double bd1, double bd2); + static inline double gamma (double x, double gamma, double start, double slope, double mul, double add){ + return (x <= start ? x*slope : exp(log(x)/gamma)*mul-add); + } + static inline double gamma2 (double x) { + return x <= 0.00304 ? x*12.92 : 1.055*exp(log(x)/2.4)-0.055; + } + static inline int gamma_srgb (int x) { return gammatab_srgb[x]; } + static inline int gamma (int x) { return gammatab[x]; } + static inline int igamma_srgb (int x) { return igammatab_srgb[x]; } + static inline double igamma2 (double x) { + return x <= 0.03928 ? x/12.92 : exp(log((x+0.055)/1.055)*2.4); + } + static inline double levels (double x, double b_lower, double b_upper, double m, double cmax); + + + public: + static void loadCurves (Glib::ustring fname); + static void updateCurve2 (int* curve, int* ohistogram, const std::vector& cpoints, double ecomp, double br, int black, double hlcompr, double shcompr, double contr, double gamma_, bool igamma, int skip=1); + static void updateCurve3 (int* curve, int* ohistogram, const std::vector& cpoints, double defmul, double ecomp, int black, double hlcompr, double shcompr, double br, double contr, double gamma_, bool igamma, int skip=1); + static std::vector curveNames (); +}; +}; + +#endif diff --git a/rtengine/dcraw.c b/rtengine/dcraw.c new file mode 100755 index 000000000..338d0cd92 --- /dev/null +++ b/rtengine/dcraw.c @@ -0,0 +1,8784 @@ +/* + dcraw.c -- Dave Coffin's raw photo decoder + Copyright 1997-2009 by Dave Coffin, dcoffin a cybercom o net + + This is a command-line ANSI C program to convert raw photos from + any digital camera on any computer running any operating system. + + No license is required to download and use dcraw.c. However, + to lawfully redistribute dcraw, you must either (a) offer, at + no extra charge, full source code* for all executable files + containing RESTRICTED functions, (b) distribute this code under + the GPL Version 2 or later, (c) remove all RESTRICTED functions, + re-implement them, or copy them from an earlier, unrestricted + Revision of dcraw.c, or (d) purchase a license from the author. + + The functions that process Foveon images have been RESTRICTED + since Revision 1.237. All other code remains free for all uses. + + *If you have not modified dcraw.c in any way, a link to my + homepage qualifies as "full source code". + + $Revision: 1.432 $ + $Date: 2009/12/25 18:51:16 $ + */ + +#define VERSION "8.99" + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#define _USE_MATH_DEFINES +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* + NO_JPEG disables decoding of compressed Kodak DC120 files. + NO_LCMS disables the "-p" option. + */ +#ifndef NO_JPEG +#include +#endif +#ifndef NO_LCMS +#include +#endif +#ifdef LOCALEDIR +#include +#define _(String) gettext(String) +#else +#define _(String) (String) +#endif +#ifdef DJGPP +#define fseeko fseek +#define ftello ftell +#else +#define fgetc getc_unlocked +#endif +#ifdef __CYGWIN__ +#include +#endif +#ifdef WIN32 +#include +#include +#pragma comment(lib, "ws2_32.lib") +#define snprintf _snprintf +#define strcasecmp stricmp +#define strncasecmp strnicmp +typedef __int64 INT64; +typedef unsigned __int64 UINT64; +#else +#include +#include +#include +typedef long long INT64; +typedef unsigned long long UINT64; +#endif + +#ifdef LJPEG_DECODE +#error Please compile dcraw.c by itself. +#error Do not link it with ljpeg_decode. +#endif + +#ifndef LONG_BIT +#define LONG_BIT (8 * sizeof (long)) +#endif + +#define ushort UshORt +typedef unsigned char uchar; +typedef unsigned short ushort; + +/* + All global variables are defined here, and all functions that + access them are prefixed with "CLASS". Note that a thread-safe + C++ class cannot have non-const static local variables. + */ +FILE *ifp, *ofp; +short order; +const char *ifname; +char *meta_data; +char cdesc[5], desc[512], make[64], model[64], model2[64], artist[64]; +float flash_used, canon_ev, iso_speed, shutter, aperture, focal_len; +time_t timestamp; +unsigned shot_order, kodak_cbpp, filters, exif_cfa, unique_id; +off_t strip_offset, data_offset; +off_t thumb_offset, meta_offset, profile_offset; +unsigned thumb_length, meta_length, profile_length; +unsigned thumb_misc, *oprof, fuji_layout, shot_select=0, multi_out=0; +unsigned tiff_nifds, tiff_samples, tiff_bps, tiff_compress; +unsigned black, maximum, mix_green, raw_color, zero_is_bad; +unsigned zero_after_ff, is_raw, dng_version, is_foveon, data_error; +unsigned tile_width, tile_length, gpsdata[32], load_flags; +ushort raw_height, raw_width, height, width, top_margin, left_margin; +ushort shrink, iheight, iwidth, fuji_width, thumb_width, thumb_height; +int flip, tiff_flip, colors; +double pixel_aspect, aber[4]={1,1,1,1}, gamm[6]={ 0.45,4.5,0,0,0,0 }; +ushort (*image)[4], white[8][8], curve[0x10000], cr2_slice[3], sraw_mul[4]; +float bright=1, user_mul[4]={0,0,0,0}, threshold=0; +int half_size=0, four_color_rgb=0, document_mode=0, highlight=0; +int verbose=0, use_auto_wb=0, use_camera_wb=0, use_camera_matrix=-1; +int output_color=1, output_bps=8, output_tiff=0, med_passes=0; +int no_auto_bright=0; +unsigned greybox[4] = { 0, 0, UINT_MAX, UINT_MAX }; +float cam_mul[4], pre_mul[4], cmatrix[3][4], rgb_cam[3][4]; +const double xyz_rgb[3][3] = { /* XYZ from RGB */ + { 0.412453, 0.357580, 0.180423 }, + { 0.212671, 0.715160, 0.072169 }, + { 0.019334, 0.119193, 0.950227 } }; +const float d65_white[3] = { 0.950456, 1, 1.088754 }; +int histogram[4][0x2000]; +void (*write_thumb)(), (*write_fun)(); +void (*load_raw)(), (*thumb_load_raw)(); +jmp_buf failure; + +struct decode { + struct decode *branch[2]; + int leaf; +} first_decode[2048], *second_decode, *free_decode; + +struct tiff_ifd { + int width, height, bps, comp, phint, offset, flip, samples, bytes; +} tiff_ifd[10]; + +struct ph1 { + int format, key_off, black, black_off, split_col, tag_21a; + float tag_210; +} ph1; + +#define CLASS + +#define FORC(cnt) for (c=0; c < cnt; c++) +#define FORC3 FORC(3) +#define FORC4 FORC(4) +#define FORCC FORC(colors) + +#define SQR(x) ((x)*(x)) +#define ABS(x) (((int)(x) ^ ((int)(x) >> 31)) - ((int)(x) >> 31)) +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#define LIM(x,min,max) MAX(min,MIN(x,max)) +#define ULIM(x,y,z) ((y) < (z) ? LIM(x,y,z) : LIM(x,z,y)) +#define CLIP(x) LIM(x,0,65535) +#define SWAP(a,b) { a ^= b; a ^= (b ^= a); } + +/* + In order to inline this calculation, I make the risky + assumption that all filter patterns can be described + by a repeating pattern of eight rows and two columns + + Do not use the FC or BAYER macros with the Leaf CatchLight, + because its pattern is 16x16, not 2x8. + + Return values are either 0/1/2/3 = G/M/C/Y or 0/1/2/3 = R/G1/B/G2 + + PowerShot 600 PowerShot A50 PowerShot Pro70 Pro90 & G1 + 0xe1e4e1e4: 0x1b4e4b1e: 0x1e4b4e1b: 0xb4b4b4b4: + + 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 + 0 G M G M G M 0 C Y C Y C Y 0 Y C Y C Y C 0 G M G M G M + 1 C Y C Y C Y 1 M G M G M G 1 M G M G M G 1 Y C Y C Y C + 2 M G M G M G 2 Y C Y C Y C 2 C Y C Y C Y + 3 C Y C Y C Y 3 G M G M G M 3 G M G M G M + 4 C Y C Y C Y 4 Y C Y C Y C + PowerShot A5 5 G M G M G M 5 G M G M G M + 0x1e4e1e4e: 6 Y C Y C Y C 6 C Y C Y C Y + 7 M G M G M G 7 M G M G M G + 0 1 2 3 4 5 + 0 C Y C Y C Y + 1 G M G M G M + 2 C Y C Y C Y + 3 M G M G M G + + All RGB cameras use one of these Bayer grids: + + 0x16161616: 0x61616161: 0x49494949: 0x94949494: + + 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 + 0 B G B G B G 0 G R G R G R 0 G B G B G B 0 R G R G R G + 1 G R G R G R 1 B G B G B G 1 R G R G R G 1 G B G B G B + 2 B G B G B G 2 G R G R G R 2 G B G B G B 2 R G R G R G + 3 G R G R G R 3 B G B G B G 3 R G R G R G 3 G B G B G B + */ + +#define FC(row,col) \ + (filters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3) + +#define BAYER(row,col) \ + image[((row) >> shrink)*iwidth + ((col) >> shrink)][FC(row,col)] + +#define BAYER2(row,col) \ + image[((row) >> shrink)*iwidth + ((col) >> shrink)][fc(row,col)] + +int CLASS fc (int row, int col) +{ + static const char filter[16][16] = + { { 2,1,1,3,2,3,2,0,3,2,3,0,1,2,1,0 }, + { 0,3,0,2,0,1,3,1,0,1,1,2,0,3,3,2 }, + { 2,3,3,2,3,1,1,3,3,1,2,1,2,0,0,3 }, + { 0,1,0,1,0,2,0,2,2,0,3,0,1,3,2,1 }, + { 3,1,1,2,0,1,0,2,1,3,1,3,0,1,3,0 }, + { 2,0,0,3,3,2,3,1,2,0,2,0,3,2,2,1 }, + { 2,3,3,1,2,1,2,1,2,1,1,2,3,0,0,1 }, + { 1,0,0,2,3,0,0,3,0,3,0,3,2,1,2,3 }, + { 2,3,3,1,1,2,1,0,3,2,3,0,2,3,1,3 }, + { 1,0,2,0,3,0,3,2,0,1,1,2,0,1,0,2 }, + { 0,1,1,3,3,2,2,1,1,3,3,0,2,1,3,2 }, + { 2,3,2,0,0,1,3,0,2,0,1,2,3,0,1,0 }, + { 1,3,1,2,3,2,3,2,0,2,0,1,1,0,3,0 }, + { 0,2,0,3,1,0,0,1,1,3,3,2,3,2,2,1 }, + { 2,1,3,2,3,1,2,1,0,3,0,2,0,2,0,2 }, + { 0,3,1,0,0,2,0,3,2,1,3,1,1,3,1,3 } }; + + if (filters != 1) return FC(row,col); + return filter[(row+top_margin) & 15][(col+left_margin) & 15]; +} + +#ifndef __GLIBC__ +char *my_memmem (char *haystack, size_t haystacklen, + char *needle, size_t needlelen) +{ + char *c; + for (c = haystack; c <= haystack + haystacklen - needlelen; c++) + if (!memcmp (c, needle, needlelen)) + return c; + return 0; +} +#define memmem my_memmem +#endif + +void CLASS merror (void *ptr, const char *where) +{ + if (ptr) return; + fprintf (stderr,_("%s: Out of memory in %s\n"), ifname, where); + longjmp (failure, 1); +} + +void CLASS derror() +{ + if (!data_error) { + fprintf (stderr, "%s: ", ifname); + if (feof(ifp)) + fprintf (stderr,_("Unexpected end of file\n")); + else + fprintf (stderr,_("Corrupt data near 0x%llx\n"), (INT64) ftello(ifp)); + } + data_error++; +} + +ushort CLASS sget2 (uchar *s) +{ + if (order == 0x4949) /* "II" means little-endian */ + return s[0] | s[1] << 8; + else /* "MM" means big-endian */ + return s[0] << 8 | s[1]; +} + +ushort CLASS get2() +{ + uchar str[2] = { 0xff,0xff }; + fread (str, 1, 2, ifp); + return sget2(str); +} + +unsigned CLASS sget4 (uchar *s) +{ + if (order == 0x4949) + return s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24; + else + return s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]; +} +#define sget4(s) sget4((uchar *)s) + +unsigned CLASS get4() +{ + uchar str[4] = { 0xff,0xff,0xff,0xff }; + fread (str, 1, 4, ifp); + return sget4(str); +} + +unsigned CLASS getint (int type) +{ + return type == 3 ? get2() : get4(); +} + +float CLASS int_to_float (int i) +{ + union { int i; float f; } u; + u.i = i; + return u.f; +} + +double CLASS getreal (int type) +{ + union { char c[8]; double d; } u; + int i, rev; + + switch (type) { + case 3: return (unsigned short) get2(); + case 4: return (unsigned int) get4(); + case 5: u.d = (unsigned int) get4(); + return u.d / (unsigned int) get4(); + case 8: return (signed short) get2(); + case 9: return (signed int) get4(); + case 10: u.d = (signed int) get4(); + return u.d / (signed int) get4(); + case 11: return int_to_float (get4()); + case 12: + rev = 7 * ((order == 0x4949) == (ntohs(0x1234) == 0x1234)); + for (i=0; i < 8; i++) + u.c[i ^ rev] = fgetc(ifp); + return u.d; + default: return fgetc(ifp); + } +} + +void CLASS read_shorts (ushort *pixel, int count) +{ + if (fread (pixel, 2, count, ifp) < count) derror(); + if ((order == 0x4949) == (ntohs(0x1234) == 0x1234)) + swab (pixel, pixel, count*2); +} + +void CLASS canon_black (double dark[2], int nblack) +{ + int c, diff, row, col; + + if (!nblack) return; + FORC(2) dark[c] /= nblack >> 1; + if ((diff = dark[0] - dark[1])) + for (row=0; row < height; row++) + for (col=1; col < width; col+=2) + BAYER(row,col) += diff; + dark[1] += diff; + black = (dark[0] + dark[1] + 1) / 2; +} + +void CLASS canon_600_fixed_wb (int temp) +{ + static const short mul[4][5] = { + { 667, 358,397,565,452 }, + { 731, 390,367,499,517 }, + { 1119, 396,348,448,537 }, + { 1399, 485,431,508,688 } }; + int lo, hi, i; + float frac=0; + + for (lo=4; --lo; ) + if (*mul[lo] <= temp) break; + for (hi=0; hi < 3; hi++) + if (*mul[hi] >= temp) break; + if (lo != hi) + frac = (float) (temp - *mul[lo]) / (*mul[hi] - *mul[lo]); + for (i=1; i < 5; i++) + pre_mul[i-1] = 1 / (frac * mul[hi][i] + (1-frac) * mul[lo][i]); +} + +/* Return values: 0 = white 1 = near white 2 = not white */ +int CLASS canon_600_color (int ratio[2], int mar) +{ + int clipped=0, target, miss; + + if (flash_used) { + if (ratio[1] < -104) + { ratio[1] = -104; clipped = 1; } + if (ratio[1] > 12) + { ratio[1] = 12; clipped = 1; } + } else { + if (ratio[1] < -264 || ratio[1] > 461) return 2; + if (ratio[1] < -50) + { ratio[1] = -50; clipped = 1; } + if (ratio[1] > 307) + { ratio[1] = 307; clipped = 1; } + } + target = flash_used || ratio[1] < 197 + ? -38 - (398 * ratio[1] >> 10) + : -123 + (48 * ratio[1] >> 10); + if (target - mar <= ratio[0] && + target + 20 >= ratio[0] && !clipped) return 0; + miss = target - ratio[0]; + if (abs(miss) >= mar*4) return 2; + if (miss < -20) miss = -20; + if (miss > mar) miss = mar; + ratio[0] = target - miss; + return 1; +} + +void CLASS canon_600_auto_wb() +{ + int mar, row, col, i, j, st, count[] = { 0,0 }; + int test[8], total[2][8], ratio[2][2], stat[2]; + + memset (&total, 0, sizeof total); + i = canon_ev + 0.5; + if (i < 10) mar = 150; + else if (i > 12) mar = 20; + else mar = 280 - 20 * i; + if (flash_used) mar = 80; + for (row=14; row < height-14; row+=4) + for (col=10; col < width; col+=2) { + for (i=0; i < 8; i++) + test[(i & 4) + FC(row+(i >> 1),col+(i & 1))] = + BAYER(row+(i >> 1),col+(i & 1)); + for (i=0; i < 8; i++) + if (test[i] < 150 || test[i] > 1500) goto next; + for (i=0; i < 4; i++) + if (abs(test[i] - test[i+4]) > 50) goto next; + for (i=0; i < 2; i++) { + for (j=0; j < 4; j+=2) + ratio[i][j >> 1] = ((test[i*4+j+1]-test[i*4+j]) << 10) / test[i*4+j]; + stat[i] = canon_600_color (ratio[i], mar); + } + if ((st = stat[0] | stat[1]) > 1) goto next; + for (i=0; i < 2; i++) + if (stat[i]) + for (j=0; j < 2; j++) + test[i*4+j*2+1] = test[i*4+j*2] * (0x400 + ratio[i][j]) >> 10; + for (i=0; i < 8; i++) + total[st][i] += test[i]; + count[st]++; +next: ; + } + if (count[0] | count[1]) { + st = count[0]*200 < count[1]; + for (i=0; i < 4; i++) + pre_mul[i] = 1.0 / (total[st][i] + total[st][i+4]); + } +} + +void CLASS canon_600_coeff() +{ + static const short table[6][12] = { + { -190,702,-1878,2390, 1861,-1349,905,-393, -432,944,2617,-2105 }, + { -1203,1715,-1136,1648, 1388,-876,267,245, -1641,2153,3921,-3409 }, + { -615,1127,-1563,2075, 1437,-925,509,3, -756,1268,2519,-2007 }, + { -190,702,-1886,2398, 2153,-1641,763,-251, -452,964,3040,-2528 }, + { -190,702,-1878,2390, 1861,-1349,905,-393, -432,944,2617,-2105 }, + { -807,1319,-1785,2297, 1388,-876,769,-257, -230,742,2067,-1555 } }; + int t=0, i, c; + float mc, yc; + + mc = pre_mul[1] / pre_mul[2]; + yc = pre_mul[3] / pre_mul[2]; + if (mc > 1 && mc <= 1.28 && yc < 0.8789) t=1; + if (mc > 1.28 && mc <= 2) { + if (yc < 0.8789) t=3; + else if (yc <= 2) t=4; + } + if (flash_used) t=5; + for (raw_color = i=0; i < 3; i++) + FORCC rgb_cam[i][c] = table[t][i*4 + c] / 1024.0; +} + +void CLASS canon_600_load_raw() +{ + uchar data[1120], *dp; + ushort pixel[896], *pix; + int irow, row, col, val; + static const short mul[4][2] = + { { 1141,1145 }, { 1128,1109 }, { 1178,1149 }, { 1128,1109 } }; + + for (irow=row=0; irow < height; irow++) { + if (fread (data, 1, raw_width*5/4, ifp) < raw_width*5/4) derror(); + for (dp=data, pix=pixel; dp < data+1120; dp+=10, pix+=8) { + pix[0] = (dp[0] << 2) + (dp[1] >> 6 ); + pix[1] = (dp[2] << 2) + (dp[1] >> 4 & 3); + pix[2] = (dp[3] << 2) + (dp[1] >> 2 & 3); + pix[3] = (dp[4] << 2) + (dp[1] & 3); + pix[4] = (dp[5] << 2) + (dp[9] & 3); + pix[5] = (dp[6] << 2) + (dp[9] >> 2 & 3); + pix[6] = (dp[7] << 2) + (dp[9] >> 4 & 3); + pix[7] = (dp[8] << 2) + (dp[9] >> 6 ); + } + for (col=0; col < width; col++) + BAYER(row,col) = pixel[col]; + for (col=width; col < raw_width; col++) + black += pixel[col]; + if ((row+=2) > height) row = 1; + } + if (raw_width > width) + black = black / ((raw_width - width) * height) - 4; + for (row=0; row < height; row++) + for (col=0; col < width; col++) { + if ((val = BAYER(row,col) - black) < 0) val = 0; + val = val * mul[row & 3][col & 1] >> 9; + BAYER(row,col) = val; + } + canon_600_fixed_wb(1311); + canon_600_auto_wb(); + canon_600_coeff(); + maximum = (0x3ff - black) * 1109 >> 9; + black = 0; +} + +void CLASS remove_zeroes() +{ + unsigned row, col, tot, n, r, c; + + for (row=0; row < height; row++) + for (col=0; col < width; col++) + if (BAYER(row,col) == 0) { + tot = n = 0; + for (r = row-2; r <= row+2; r++) + for (c = col-2; c <= col+2; c++) + if (r < height && c < width && + FC(r,c) == FC(row,col) && BAYER(r,c)) + tot += (n++,BAYER(r,c)); + if (n) BAYER(row,col) = tot/n; + } +} + +int CLASS canon_s2is() +{ + unsigned row; + + for (row=0; row < 100; row++) { + fseek (ifp, row*3340 + 3284, SEEK_SET); + if (getc(ifp) > 15) return 1; + } + return 0; +} + +/* + getbits(-1) initializes the buffer + getbits(n) where 0 <= n <= 25 returns an n-bit integer + */ +unsigned CLASS getbithuff (int nbits, ushort *huff) +{ + static unsigned bitbuf=0; + static int vbits=0, reset=0; + unsigned c; + + if (nbits == -1) + return bitbuf = vbits = reset = 0; + if (nbits == 0 || vbits < 0) return 0; + while (!reset && vbits < nbits && (c = fgetc(ifp)) != EOF && + !(reset = zero_after_ff && c == 0xff && fgetc(ifp))) { + bitbuf = (bitbuf << 8) + (uchar) c; + vbits += 8; + } + c = bitbuf << (32-vbits) >> (32-nbits); + if (huff) { + vbits -= huff[c] >> 8; + c = (uchar) huff[c]; + } else + vbits -= nbits; + if (vbits < 0) derror(); + return c; +} + +#define getbits(n) getbithuff(n,0) +#define gethuff(h) getbithuff(*h,h+1) + +/* + Construct a decode tree according the specification in *source. + The first 16 bytes specify how many codes should be 1-bit, 2-bit + 3-bit, etc. Bytes after that are the leaf values. + + For example, if the source is + + { 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0, + 0x04,0x03,0x05,0x06,0x02,0x07,0x01,0x08,0x09,0x00,0x0a,0x0b,0xff }, + + then the code is + + 00 0x04 + 010 0x03 + 011 0x05 + 100 0x06 + 101 0x02 + 1100 0x07 + 1101 0x01 + 11100 0x08 + 11101 0x09 + 11110 0x00 + 111110 0x0a + 1111110 0x0b + 1111111 0xff + */ +ushort * CLASS make_decoder_ref (const uchar **source) +{ + int max, len, h, i, j; + const uchar *count; + ushort *huff; + + count = (*source += 16) - 17; + for (max=16; max && !count[max]; max--); + huff = (ushort *) calloc (1 + (1 << max), sizeof *huff); + merror (huff, "make_decoder()"); + huff[0] = max; + for (h=len=1; len <= max; len++) + for (i=0; i < count[len]; i++, ++*source) + for (j=0; j < 1 << (max-len); j++) + if (h <= 1 << max) + huff[h++] = len << 8 | **source; + return huff; +} + +ushort * CLASS make_decoder (const uchar *source) +{ + return make_decoder_ref (&source); +} + +void CLASS crw_init_tables (unsigned table, ushort *huff[2]) +{ + static const uchar first_tree[3][29] = { + { 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0, + 0x04,0x03,0x05,0x06,0x02,0x07,0x01,0x08,0x09,0x00,0x0a,0x0b,0xff }, + { 0,2,2,3,1,1,1,1,2,0,0,0,0,0,0,0, + 0x03,0x02,0x04,0x01,0x05,0x00,0x06,0x07,0x09,0x08,0x0a,0x0b,0xff }, + { 0,0,6,3,1,1,2,0,0,0,0,0,0,0,0,0, + 0x06,0x05,0x07,0x04,0x08,0x03,0x09,0x02,0x00,0x0a,0x01,0x0b,0xff }, + }; + static const uchar second_tree[3][180] = { + { 0,2,2,2,1,4,2,1,2,5,1,1,0,0,0,139, + 0x03,0x04,0x02,0x05,0x01,0x06,0x07,0x08, + 0x12,0x13,0x11,0x14,0x09,0x15,0x22,0x00,0x21,0x16,0x0a,0xf0, + 0x23,0x17,0x24,0x31,0x32,0x18,0x19,0x33,0x25,0x41,0x34,0x42, + 0x35,0x51,0x36,0x37,0x38,0x29,0x79,0x26,0x1a,0x39,0x56,0x57, + 0x28,0x27,0x52,0x55,0x58,0x43,0x76,0x59,0x77,0x54,0x61,0xf9, + 0x71,0x78,0x75,0x96,0x97,0x49,0xb7,0x53,0xd7,0x74,0xb6,0x98, + 0x47,0x48,0x95,0x69,0x99,0x91,0xfa,0xb8,0x68,0xb5,0xb9,0xd6, + 0xf7,0xd8,0x67,0x46,0x45,0x94,0x89,0xf8,0x81,0xd5,0xf6,0xb4, + 0x88,0xb1,0x2a,0x44,0x72,0xd9,0x87,0x66,0xd4,0xf5,0x3a,0xa7, + 0x73,0xa9,0xa8,0x86,0x62,0xc7,0x65,0xc8,0xc9,0xa1,0xf4,0xd1, + 0xe9,0x5a,0x92,0x85,0xa6,0xe7,0x93,0xe8,0xc1,0xc6,0x7a,0x64, + 0xe1,0x4a,0x6a,0xe6,0xb3,0xf1,0xd3,0xa5,0x8a,0xb2,0x9a,0xba, + 0x84,0xa4,0x63,0xe5,0xc5,0xf3,0xd2,0xc4,0x82,0xaa,0xda,0xe4, + 0xf2,0xca,0x83,0xa3,0xa2,0xc3,0xea,0xc2,0xe2,0xe3,0xff,0xff }, + { 0,2,2,1,4,1,4,1,3,3,1,0,0,0,0,140, + 0x02,0x03,0x01,0x04,0x05,0x12,0x11,0x06, + 0x13,0x07,0x08,0x14,0x22,0x09,0x21,0x00,0x23,0x15,0x31,0x32, + 0x0a,0x16,0xf0,0x24,0x33,0x41,0x42,0x19,0x17,0x25,0x18,0x51, + 0x34,0x43,0x52,0x29,0x35,0x61,0x39,0x71,0x62,0x36,0x53,0x26, + 0x38,0x1a,0x37,0x81,0x27,0x91,0x79,0x55,0x45,0x28,0x72,0x59, + 0xa1,0xb1,0x44,0x69,0x54,0x58,0xd1,0xfa,0x57,0xe1,0xf1,0xb9, + 0x49,0x47,0x63,0x6a,0xf9,0x56,0x46,0xa8,0x2a,0x4a,0x78,0x99, + 0x3a,0x75,0x74,0x86,0x65,0xc1,0x76,0xb6,0x96,0xd6,0x89,0x85, + 0xc9,0xf5,0x95,0xb4,0xc7,0xf7,0x8a,0x97,0xb8,0x73,0xb7,0xd8, + 0xd9,0x87,0xa7,0x7a,0x48,0x82,0x84,0xea,0xf4,0xa6,0xc5,0x5a, + 0x94,0xa4,0xc6,0x92,0xc3,0x68,0xb5,0xc8,0xe4,0xe5,0xe6,0xe9, + 0xa2,0xa3,0xe3,0xc2,0x66,0x67,0x93,0xaa,0xd4,0xd5,0xe7,0xf8, + 0x88,0x9a,0xd7,0x77,0xc4,0x64,0xe2,0x98,0xa5,0xca,0xda,0xe8, + 0xf3,0xf6,0xa9,0xb2,0xb3,0xf2,0xd2,0x83,0xba,0xd3,0xff,0xff }, + { 0,0,6,2,1,3,3,2,5,1,2,2,8,10,0,117, + 0x04,0x05,0x03,0x06,0x02,0x07,0x01,0x08, + 0x09,0x12,0x13,0x14,0x11,0x15,0x0a,0x16,0x17,0xf0,0x00,0x22, + 0x21,0x18,0x23,0x19,0x24,0x32,0x31,0x25,0x33,0x38,0x37,0x34, + 0x35,0x36,0x39,0x79,0x57,0x58,0x59,0x28,0x56,0x78,0x27,0x41, + 0x29,0x77,0x26,0x42,0x76,0x99,0x1a,0x55,0x98,0x97,0xf9,0x48, + 0x54,0x96,0x89,0x47,0xb7,0x49,0xfa,0x75,0x68,0xb6,0x67,0x69, + 0xb9,0xb8,0xd8,0x52,0xd7,0x88,0xb5,0x74,0x51,0x46,0xd9,0xf8, + 0x3a,0xd6,0x87,0x45,0x7a,0x95,0xd5,0xf6,0x86,0xb4,0xa9,0x94, + 0x53,0x2a,0xa8,0x43,0xf5,0xf7,0xd4,0x66,0xa7,0x5a,0x44,0x8a, + 0xc9,0xe8,0xc8,0xe7,0x9a,0x6a,0x73,0x4a,0x61,0xc7,0xf4,0xc6, + 0x65,0xe9,0x72,0xe6,0x71,0x91,0x93,0xa6,0xda,0x92,0x85,0x62, + 0xf3,0xc5,0xb2,0xa4,0x84,0xba,0x64,0xa5,0xb3,0xd2,0x81,0xe5, + 0xd3,0xaa,0xc4,0xca,0xf2,0xb1,0xe4,0xd1,0x83,0x63,0xea,0xc3, + 0xe2,0x82,0xf1,0xa3,0xc2,0xa1,0xc1,0xe3,0xa2,0xe1,0xff,0xff } + }; + if (table > 2) table = 2; + huff[0] = make_decoder ( first_tree[table]); + huff[1] = make_decoder (second_tree[table]); +} + +/* + Return 0 if the image starts with compressed data, + 1 if it starts with uncompressed low-order bits. + + In Canon compressed data, 0xff is always followed by 0x00. + */ +int CLASS canon_has_lowbits() +{ + uchar test[0x4000]; + int ret=1, i; + + fseek (ifp, 0, SEEK_SET); + fread (test, 1, sizeof test, ifp); + for (i=540; i < sizeof test - 1; i++) + if (test[i] == 0xff) { + if (test[i+1]) return 1; + ret=0; + } + return ret; +} + +void CLASS canon_compressed_load_raw() +{ + ushort *pixel, *prow, *huff[2]; + int nblocks, lowbits, i, c, row, r, col, save, val, nblack=0; + unsigned irow, icol; + int block, diffbuf[64], leaf, len, diff, carry=0, pnum=0, base[2]; + double dark[2] = { 0,0 }; + + crw_init_tables (tiff_compress, huff); + pixel = (ushort *) calloc (raw_width*8, sizeof *pixel); + merror (pixel, "canon_compressed_load_raw()"); + lowbits = canon_has_lowbits(); + if (!lowbits) maximum = 0x3ff; + fseek (ifp, 540 + lowbits*raw_height*raw_width/4, SEEK_SET); + zero_after_ff = 1; + getbits(-1); + for (row=0; row < raw_height; row+=8) { + nblocks = MIN (8, raw_height-row) * raw_width >> 6; + for (block=0; block < nblocks; block++) { + memset (diffbuf, 0, sizeof diffbuf); + for (i=0; i < 64; i++ ) { + leaf = gethuff(huff[i > 0]); + if (leaf == 0 && i) break; + if (leaf == 0xff) continue; + i += leaf >> 4; + len = leaf & 15; + if (len == 0) continue; + diff = getbits(len); + if ((diff & (1 << (len-1))) == 0) + diff -= (1 << len) - 1; + if (i < 64) diffbuf[i] = diff; + } + diffbuf[0] += carry; + carry = diffbuf[0]; + for (i=0; i < 64; i++ ) { + if (pnum++ % raw_width == 0) + base[0] = base[1] = 512; + if ((pixel[(block << 6) + i] = base[i & 1] += diffbuf[i]) >> 10) + derror(); + } + } + if (lowbits) { + save = ftell(ifp); + fseek (ifp, 26 + row*raw_width/4, SEEK_SET); + for (prow=pixel, i=0; i < raw_width*2; i++) { + c = fgetc(ifp); + for (r=0; r < 8; r+=2, prow++) { + val = (*prow << 2) + ((c >> r) & 3); + if (raw_width == 2672 && val < 512) val += 2; + *prow = val; + } + } + fseek (ifp, save, SEEK_SET); + } + for (r=0; r < 8; r++) { + irow = row - top_margin + r; + if (irow >= height) continue; + for (col=0; col < raw_width; col++) { + icol = col - left_margin; + if (icol < width) + BAYER(irow,icol) = pixel[r*raw_width+col]; + else if (col > 1 && (unsigned) (col-left_margin+2) > width+3) + dark[icol & 1] += (nblack++,pixel[r*raw_width+col]); + } + } + } + free (pixel); + FORC(2) free (huff[c]); + canon_black (dark, nblack); +} + +/* + Not a full implementation of Lossless JPEG, just + enough to decode Canon, Kodak and Adobe DNG images. + */ +struct jhead { + int bits, high, wide, clrs, sraw, psv, restart, vpred[6]; + ushort *huff[6], *free[4], *row; +}; + +int CLASS ljpeg_start (struct jhead *jh, int info_only) +{ + int c, tag, len; + uchar data[0x10000]; + const uchar *dp; + + memset (jh, 0, sizeof *jh); + jh->restart = INT_MAX; + fread (data, 2, 1, ifp); + if (data[1] != 0xd8) return 0; + do { + fread (data, 2, 2, ifp); + tag = data[0] << 8 | data[1]; + len = (data[2] << 8 | data[3]) - 2; + if (tag <= 0xff00) return 0; + fread (data, 1, len, ifp); + switch (tag) { + case 0xffc3: + jh->sraw = ((data[7] >> 4) * (data[7] & 15) - 1) & 3; + case 0xffc0: + jh->bits = data[0]; + jh->high = data[1] << 8 | data[2]; + jh->wide = data[3] << 8 | data[4]; + jh->clrs = data[5] + jh->sraw; + if (len == 9 && !dng_version) getc(ifp); + break; + case 0xffc4: + if (info_only) break; + for (dp = data; dp < data+len && (c = *dp++) < 4; ) + jh->free[c] = jh->huff[c] = make_decoder_ref (&dp); + break; + case 0xffda: + jh->psv = data[1+data[0]*2]; + jh->bits -= data[3+data[0]*2] & 15; + break; + case 0xffdd: + jh->restart = data[0] << 8 | data[1]; + } + } while (tag != 0xffda); + if (info_only) return 1; + FORC(5) if (!jh->huff[c+1]) jh->huff[c+1] = jh->huff[c]; + if (jh->sraw) { + FORC(4) jh->huff[2+c] = jh->huff[1]; + FORC(jh->sraw) jh->huff[1+c] = jh->huff[0]; + } + jh->row = (ushort *) calloc (jh->wide*jh->clrs, 4); + merror (jh->row, "ljpeg_start()"); + return zero_after_ff = 1; +} + +void CLASS ljpeg_end (struct jhead *jh) +{ + int c; + FORC4 if (jh->free[c]) free (jh->free[c]); + free (jh->row); +} + +int CLASS ljpeg_diff (ushort *huff) +{ + int len, diff; + + len = gethuff(huff); + if (len == 16 && (!dng_version || dng_version >= 0x1010000)) + return -32768; + diff = getbits(len); + if ((diff & (1 << (len-1))) == 0) + diff -= (1 << len) - 1; + return diff; +} + +ushort * CLASS ljpeg_row (int jrow, struct jhead *jh) +{ + int col, c, diff, pred, spred=0; + ushort mark=0, *row[3]; + + if (jrow * jh->wide % jh->restart == 0) { + FORC(6) jh->vpred[c] = 1 << (jh->bits-1); + if (jrow) { + fseek (ifp, -2, SEEK_CUR); + do mark = (mark << 8) + (c = fgetc(ifp)); + while (c != EOF && mark >> 4 != 0xffd); + } + getbits(-1); + } + FORC3 row[c] = jh->row + jh->wide*jh->clrs*((jrow+c) & 1); + for (col=0; col < jh->wide; col++) + FORC(jh->clrs) { + diff = ljpeg_diff (jh->huff[c]); + if (jh->sraw && c <= jh->sraw && (col | c)) + pred = spred; + else if (col) pred = row[0][-jh->clrs]; + else pred = (jh->vpred[c] += diff) - diff; + if (jrow && col) switch (jh->psv) { + case 1: break; + case 2: pred = row[1][0]; break; + case 3: pred = row[1][-jh->clrs]; break; + case 4: pred = pred + row[1][0] - row[1][-jh->clrs]; break; + case 5: pred = pred + ((row[1][0] - row[1][-jh->clrs]) >> 1); break; + case 6: pred = row[1][0] + ((pred - row[1][-jh->clrs]) >> 1); break; + case 7: pred = (pred + row[1][0]) >> 1; break; + default: pred = 0; + } + if ((**row = pred + diff) >> jh->bits) derror(); + if (c <= jh->sraw) spred = **row; + row[0]++; row[1]++; + } + return row[2]; +} + +void CLASS lossless_jpeg_load_raw() +{ + int jwide, jrow, jcol, val, jidx, i, j, row=0, col=0, nblack=0; + double dark[2] = { 0,0 }; + struct jhead jh; + int min=INT_MAX; + ushort *rp; + + if (!ljpeg_start (&jh, 0)) return; + jwide = jh.wide * jh.clrs; + + for (jrow=0; jrow < jh.high; jrow++) { + rp = ljpeg_row (jrow, &jh); + for (jcol=0; jcol < jwide; jcol++) { + val = *rp++; + if (jh.bits <= 12) + val = curve[val & 0xfff]; + if (cr2_slice[0]) { + jidx = jrow*jwide + jcol; + i = jidx / (cr2_slice[1]*jh.high); + if ((j = i >= cr2_slice[0])) + i = cr2_slice[0]; + jidx -= i * (cr2_slice[1]*jh.high); + row = jidx / cr2_slice[1+j]; + col = jidx % cr2_slice[1+j] + i*cr2_slice[1]; + } + if (raw_width == 3984 && (col -= 2) < 0) + col += (row--,raw_width); + if ((unsigned) (row-top_margin) < height) { + if ((unsigned) (col-left_margin) < width) { + BAYER(row-top_margin,col-left_margin) = val; + if (min > val) min = val; + } else if (col > 1 && (unsigned) (col-left_margin+2) > width+3) + dark[(col-left_margin) & 1] += (nblack++,val); + } + if (++col >= raw_width) + col = (row++,0); + } + } + ljpeg_end (&jh); + canon_black (dark, nblack); + if (!strcasecmp(make,"KODAK")) + black = min; +} + +void CLASS canon_sraw_load_raw() +{ + struct jhead jh; + short *rp=0, (*ip)[4]; + int jwide, slice, scol, ecol, row, col, jrow=0, jcol=0, pix[3], c; + int v[3]={0,0,0}, ver, hue; + char *cp; + + if (!ljpeg_start (&jh, 0)) return; + jwide = (jh.wide >>= 1) * jh.clrs; + + for (ecol=slice=0; slice <= cr2_slice[0]; slice++) { + scol = ecol; + ecol += cr2_slice[1] * 2 / jh.clrs; + if (!cr2_slice[0] || ecol > raw_width-1) ecol = raw_width & -2; + for (row=0; row < height; row += (jh.clrs >> 1) - 1) { + ip = (short (*)[4]) image + row*width; + for (col=scol; col < ecol; col+=2, jcol+=jh.clrs) { + if ((jcol %= jwide) == 0) + rp = (short *) ljpeg_row (jrow++, &jh); + if (col >= width) continue; + FORC (jh.clrs-2) + ip[col + (c >> 1)*width + (c & 1)][0] = rp[jcol+c]; + ip[col][1] = rp[jcol+jh.clrs-2] - 16384; + ip[col][2] = rp[jcol+jh.clrs-1] - 16384; + } + } + } + for (cp=model2; *cp && !isdigit(*cp); cp++); + sscanf (cp, "%d.%d.%d", v, v+1, v+2); + ver = (v[0]*1000 + v[1])*1000 + v[2]; + hue = (jh.sraw+1) << 2; + if (unique_id == 0x80000218 && ver > 1000006 && ver < 3000000) + hue = jh.sraw << 1; + ip = (short (*)[4]) image; + rp = ip[0]; + for (row=0; row < height; row++, ip+=width) { + if (row & (jh.sraw >> 1)) + for (col=0; col < width; col+=2) + for (c=1; c < 3; c++) + if (row == height-1) + ip[col][c] = ip[col-width][c]; + else ip[col][c] = (ip[col-width][c] + ip[col+width][c] + 1) >> 1; + for (col=1; col < width; col+=2) + for (c=1; c < 3; c++) + if (col == width-1) + ip[col][c] = ip[col-1][c]; + else ip[col][c] = (ip[col-1][c] + ip[col+1][c] + 1) >> 1; + } + for ( ; rp < ip[0]; rp+=4) { + if (unique_id < 0x80000218) { + pix[0] = rp[0] + rp[2] - 512; + pix[2] = rp[0] + rp[1] - 512; + pix[1] = rp[0] + ((-778*rp[1] - (rp[2] << 11)) >> 12) - 512; + } else { + rp[1] = (rp[1] << 2) + hue; + rp[2] = (rp[2] << 2) + hue; + pix[0] = rp[0] + (( 200*rp[1] + 22929*rp[2]) >> 14); + pix[1] = rp[0] + ((-5640*rp[1] - 11751*rp[2]) >> 14); + pix[2] = rp[0] + ((29040*rp[1] - 101*rp[2]) >> 14); + } + FORC3 rp[c] = CLIP(pix[c] * sraw_mul[c] >> 10); + } + ljpeg_end (&jh); + maximum = 0x3fff; +} + +void CLASS adobe_copy_pixel (int row, int col, ushort **rp) +{ + unsigned r, c; + + r = row -= top_margin; + c = col -= left_margin; + if (is_raw == 2 && shot_select) (*rp)++; + if (filters) { + if (fuji_width) { + r = row + fuji_width - 1 - (col >> 1); + c = row + ((col+1) >> 1); + } + if (r < height && c < width) + BAYER(r,c) = **rp < 0x1000 ? curve[**rp] : **rp; + *rp += is_raw; + } else { + if (r < height && c < width) + FORC(tiff_samples) + image[row*width+col][c] = (*rp)[c] < 0x1000 ? curve[(*rp)[c]]:(*rp)[c]; + *rp += tiff_samples; + } + if (is_raw == 2 && shot_select) (*rp)--; +} + +void CLASS adobe_dng_load_raw_lj() +{ + unsigned save, trow=0, tcol=0, jwide, jrow, jcol, row, col; + struct jhead jh; + ushort *rp; + + while (trow < raw_height) { + save = ftell(ifp); + if (tile_length < INT_MAX) + fseek (ifp, get4(), SEEK_SET); + if (!ljpeg_start (&jh, 0)) break; + jwide = jh.wide; + if (filters) jwide *= jh.clrs; + jwide /= is_raw; + for (row=col=jrow=0; jrow < jh.high; jrow++) { + rp = ljpeg_row (jrow, &jh); + for (jcol=0; jcol < jwide; jcol++) { + adobe_copy_pixel (trow+row, tcol+col, &rp); + if (++col >= tile_width || col >= raw_width) + row += 1 + (col = 0); + } + } + fseek (ifp, save+4, SEEK_SET); + if ((tcol += tile_width) >= raw_width) + trow += tile_length + (tcol = 0); + ljpeg_end (&jh); + } +} + +void CLASS adobe_dng_load_raw_nc() +{ + ushort *pixel, *rp; + int row, col; + + pixel = (ushort *) calloc (raw_width * tiff_samples, sizeof *pixel); + merror (pixel, "adobe_dng_load_raw_nc()"); + for (row=0; row < raw_height; row++) { + if (tiff_bps == 16) + read_shorts (pixel, raw_width * tiff_samples); + else { + getbits(-1); + for (col=0; col < raw_width * tiff_samples; col++) + pixel[col] = getbits(tiff_bps); + } + for (rp=pixel, col=0; col < raw_width; col++) + adobe_copy_pixel (row, col, &rp); + } + free (pixel); +} + +void CLASS pentax_load_raw() +{ + ushort bit[2][13], huff[4097]; + int row, col, diff, c, i; + ushort vpred[2][2] = {{0,0},{0,0}}, hpred[2]; + + fseek (ifp, meta_offset, SEEK_SET); + FORC(13) bit[0][c] = get2(); + FORC(13) bit[1][c] = fgetc(ifp); + FORC(13) + for (i=bit[0][c]; i <= ((bit[0][c]+(4096 >> bit[1][c])-1) & 4095); ) + huff[++i] = bit[1][c] << 8 | c; + huff[0] = 12; + fseek (ifp, data_offset, SEEK_SET); + getbits(-1); + for (row=0; row < raw_height; row++) + for (col=0; col < raw_width; col++) { + diff = ljpeg_diff (huff); + if (col < 2) hpred[col] = vpred[row & 1][col] += diff; + else hpred[col & 1] += diff; + if ((unsigned) (row-top_margin) < height && col < width) + BAYER(row-top_margin,col) = hpred[col & 1]; + if (hpred[col & 1] >> 12) derror(); + } +} + +void CLASS nikon_compressed_load_raw() +{ + static const uchar nikon_tree[][32] = { + { 0,1,5,1,1,1,1,1,1,2,0,0,0,0,0,0, /* 12-bit lossy */ + 5,4,3,6,2,7,1,0,8,9,11,10,12 }, + { 0,1,5,1,1,1,1,1,1,2,0,0,0,0,0,0, /* 12-bit lossy after split */ + 0x39,0x5a,0x38,0x27,0x16,5,4,3,2,1,0,11,12,12 }, + { 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0, /* 12-bit lossless */ + 5,4,6,3,7,2,8,1,9,0,10,11,12 }, + { 0,1,4,3,1,1,1,1,1,2,0,0,0,0,0,0, /* 14-bit lossy */ + 5,6,4,7,8,3,9,2,1,0,10,11,12,13,14 }, + { 0,1,5,1,1,1,1,1,1,1,2,0,0,0,0,0, /* 14-bit lossy after split */ + 8,0x5c,0x4b,0x3a,0x29,7,6,5,4,3,2,1,0,13,14 }, + { 0,1,4,2,2,3,1,2,0,0,0,0,0,0,0,0, /* 14-bit lossless */ + 7,6,8,5,9,4,10,3,11,12,2,0,1,13,14 } }; + ushort *huff, ver0, ver1, vpred[2][2], hpred[2], csize; + int i, min, max, step=0, tree=0, split=0, row, col, len, shl, diff; + + fseek (ifp, meta_offset, SEEK_SET); + ver0 = fgetc(ifp); + ver1 = fgetc(ifp); + if (ver0 == 0x49 || ver1 == 0x58) + fseek (ifp, 2110, SEEK_CUR); + if (ver0 == 0x46) tree = 2; + if (tiff_bps == 14) tree += 3; + read_shorts (vpred[0], 4); + max = 1 << tiff_bps & 0x7fff; + if ((csize = get2()) > 1) + step = max / (csize-1); + if (ver0 == 0x44 && ver1 == 0x20 && step > 0) { + for (i=0; i < csize; i++) + curve[i*step] = get2(); + for (i=0; i < max; i++) + curve[i] = ( curve[i-i%step]*(step-i%step) + + curve[i-i%step+step]*(i%step) ) / step; + fseek (ifp, meta_offset+562, SEEK_SET); + split = get2(); + } else if (ver0 != 0x46 && csize <= 0x4001) + read_shorts (curve, max=csize); + while (curve[max-2] == curve[max-1]) max--; + huff = make_decoder (nikon_tree[tree]); + fseek (ifp, data_offset, SEEK_SET); + getbits(-1); + for (min=row=0; row < height; row++) { + if (split && row == split) { + free (huff); + huff = make_decoder (nikon_tree[tree+1]); + max += (min = 16) << 1; + } + for (col=0; col < raw_width; col++) { + i = gethuff(huff); + len = i & 15; + shl = i >> 4; + diff = ((getbits(len-shl) << 1) + 1) << shl >> 1; + if ((diff & (1 << (len-1))) == 0) + diff -= (1 << len) - !shl; + if (col < 2) hpred[col] = vpred[row & 1][col] += diff; + else hpred[col & 1] += diff; + if ((ushort)(hpred[col & 1] + min) >= max) derror(); + if ((unsigned) (col-left_margin) < width) + BAYER(row,col-left_margin) = curve[LIM((short)hpred[col & 1],0,0x3fff)]; + } + } + free (huff); +} + +/* + Figure out if a NEF file is compressed. These fancy heuristics + are only needed for the D100, thanks to a bug in some cameras + that tags all images as "compressed". + */ +int CLASS nikon_is_compressed() +{ + uchar test[256]; + int i; + + fseek (ifp, data_offset, SEEK_SET); + fread (test, 1, 256, ifp); + for (i=15; i < 256; i+=16) + if (test[i]) return 1; + return 0; +} + +/* + Returns 1 for a Coolpix 995, 0 for anything else. + */ +int CLASS nikon_e995() +{ + int i, histo[256]; + const uchar often[] = { 0x00, 0x55, 0xaa, 0xff }; + + memset (histo, 0, sizeof histo); + fseek (ifp, -2000, SEEK_END); + for (i=0; i < 2000; i++) + histo[fgetc(ifp)]++; + for (i=0; i < 4; i++) + if (histo[often[i]] < 200) + return 0; + return 1; +} + +/* + Returns 1 for a Coolpix 2100, 0 for anything else. + */ +int CLASS nikon_e2100() +{ + uchar t[12]; + int i; + + fseek (ifp, 0, SEEK_SET); + for (i=0; i < 1024; i++) { + fread (t, 1, 12, ifp); + if (((t[2] & t[4] & t[7] & t[9]) >> 4 + & t[1] & t[6] & t[8] & t[11] & 3) != 3) + return 0; + } + return 1; +} + +void CLASS nikon_3700() +{ + int bits, i; + uchar dp[24]; + static const struct { + int bits; + char make[12], model[15]; + } table[] = { + { 0x00, "PENTAX", "Optio 33WR" }, + { 0x03, "NIKON", "E3200" }, + { 0x32, "NIKON", "E3700" }, + { 0x33, "OLYMPUS", "C740UZ" } }; + + fseek (ifp, 3072, SEEK_SET); + fread (dp, 1, 24, ifp); + bits = (dp[8] & 3) << 4 | (dp[20] & 3); + for (i=0; i < sizeof table / sizeof *table; i++) + if (bits == table[i].bits) { + strcpy (make, table[i].make ); + strcpy (model, table[i].model); + } +} + +/* + Separates a Minolta DiMAGE Z2 from a Nikon E4300. + */ +int CLASS minolta_z2() +{ + int i, nz; + char tail[424]; + + fseek (ifp, -sizeof tail, SEEK_END); + fread (tail, 1, sizeof tail, ifp); + for (nz=i=0; i < sizeof tail; i++) + if (tail[i]) nz++; + return nz > 20; +} + +/* + The Fuji Super CCD is just a Bayer grid rotated 45 degrees. + */ +void CLASS fuji_load_raw() +{ + ushort *pixel; + int wide, row, col, r, c; + + fseek (ifp, (top_margin*raw_width + left_margin) * 2, SEEK_CUR); + wide = fuji_width << !fuji_layout; + pixel = (ushort *) calloc (wide, sizeof *pixel); + merror (pixel, "fuji_load_raw()"); + for (row=0; row < raw_height; row++) { + read_shorts (pixel, wide); + fseek (ifp, 2*(raw_width - wide), SEEK_CUR); + for (col=0; col < wide; col++) { + if (fuji_layout) { + r = fuji_width - 1 - col + (row >> 1); + c = col + ((row+1) >> 1); + } else { + r = fuji_width - 1 + row - (col >> 1); + c = row + ((col+1) >> 1); + } + BAYER(r,c) = pixel[col]; + } + } + free (pixel); +} + +void CLASS jpeg_thumb(); + +void CLASS ppm_thumb() +{ + char *thumb; + thumb_length = thumb_width*thumb_height*3; + thumb = (char *) malloc (thumb_length); + merror (thumb, "ppm_thumb()"); + fprintf (ofp, "P6\n%d %d\n255\n", thumb_width, thumb_height); + fread (thumb, 1, thumb_length, ifp); + fwrite (thumb, 1, thumb_length, ofp); + free (thumb); +} + +void CLASS layer_thumb() +{ + int i, c; + char *thumb, map[][4] = { "012","102" }; + + colors = thumb_misc >> 5 & 7; + thumb_length = thumb_width*thumb_height; + thumb = (char *) calloc (colors, thumb_length); + merror (thumb, "layer_thumb()"); + fprintf (ofp, "P%d\n%d %d\n255\n", + 5 + (colors >> 1), thumb_width, thumb_height); + fread (thumb, thumb_length, colors, ifp); + for (i=0; i < thumb_length; i++) + FORCC putc (thumb[i+thumb_length*(map[thumb_misc >> 8][c]-'0')], ofp); + free (thumb); +} + +void CLASS rollei_thumb() +{ + unsigned i; + ushort *thumb; + + thumb_length = thumb_width * thumb_height; + thumb = (ushort *) calloc (thumb_length, 2); + merror (thumb, "rollei_thumb()"); + fprintf (ofp, "P6\n%d %d\n255\n", thumb_width, thumb_height); + read_shorts (thumb, thumb_length); + for (i=0; i < thumb_length; i++) { + putc (thumb[i] << 3, ofp); + putc (thumb[i] >> 5 << 2, ofp); + putc (thumb[i] >> 11 << 3, ofp); + } + free (thumb); +} + +void CLASS rollei_load_raw() +{ + uchar pixel[10]; + unsigned iten=0, isix, i, buffer=0, row, col, todo[16]; + + isix = raw_width * raw_height * 5 / 8; + while (fread (pixel, 1, 10, ifp) == 10) { + for (i=0; i < 10; i+=2) { + todo[i] = iten++; + todo[i+1] = pixel[i] << 8 | pixel[i+1]; + buffer = pixel[i] >> 2 | buffer << 6; + } + for ( ; i < 16; i+=2) { + todo[i] = isix++; + todo[i+1] = buffer >> (14-i)*5; + } + for (i=0; i < 16; i+=2) { + row = todo[i] / raw_width - top_margin; + col = todo[i] % raw_width - left_margin; + if (row < height && col < width) + BAYER(row,col) = (todo[i+1] & 0x3ff); + } + } + maximum = 0x3ff; +} + +int CLASS bayer (unsigned row, unsigned col) +{ + return (row < height && col < width) ? BAYER(row,col) : 0; +} + +void CLASS phase_one_flat_field (int is_float, int nc) +{ + ushort head[8]; + unsigned wide, y, x, c, rend, cend, row, col; + float *mrow, num, mult[4]; + + read_shorts (head, 8); + wide = head[2] / head[4]; + mrow = (float *) calloc (nc*wide, sizeof *mrow); + merror (mrow, "phase_one_flat_field()"); + for (y=0; y < head[3] / head[5]; y++) { + for (x=0; x < wide; x++) + for (c=0; c < nc; c+=2) { + num = is_float ? getreal(11) : get2()/32768.0; + if (y==0) mrow[c*wide+x] = num; + else mrow[(c+1)*wide+x] = (num - mrow[c*wide+x]) / head[5]; + } + if (y==0) continue; + rend = head[1]-top_margin + y*head[5]; + for (row = rend-head[5]; row < height && row < rend; row++) { + for (x=1; x < wide; x++) { + for (c=0; c < nc; c+=2) { + mult[c] = mrow[c*wide+x-1]; + mult[c+1] = (mrow[c*wide+x] - mult[c]) / head[4]; + } + cend = head[0]-left_margin + x*head[4]; + for (col = cend-head[4]; col < width && col < cend; col++) { + c = nc > 2 ? FC(row,col) : 0; + if (!(c & 1)) { + c = BAYER(row,col) * mult[c]; + BAYER(row,col) = LIM(c,0,65535); + } + for (c=0; c < nc; c+=2) + mult[c] += mult[c+1]; + } + } + for (x=0; x < wide; x++) + for (c=0; c < nc; c+=2) + mrow[c*wide+x] += mrow[(c+1)*wide+x]; + } + } + free (mrow); +} + +void CLASS phase_one_correct() +{ + unsigned entries, tag, data, save, col, row, type; + int len, i, j, k, cip, val[4], dev[4], sum, max; + int head[9], diff, mindiff=INT_MAX, off_412=0; + static const signed char dir[12][2] = + { {-1,-1}, {-1,1}, {1,-1}, {1,1}, {-2,0}, {0,-2}, {0,2}, {2,0}, + {-2,-2}, {-2,2}, {2,-2}, {2,2} }; + float poly[8], num, cfrac, frac, mult[2], *yval[2]; + ushort *xval[2]; + + if (half_size || !meta_length) return; + if (verbose) fprintf (stderr,_("Phase One correction...\n")); + fseek (ifp, meta_offset, SEEK_SET); + order = get2(); + fseek (ifp, 6, SEEK_CUR); + fseek (ifp, meta_offset+get4(), SEEK_SET); + entries = get4(); get4(); + while (entries--) { + tag = get4(); + len = get4(); + data = get4(); + save = ftell(ifp); + fseek (ifp, meta_offset+data, SEEK_SET); + if (tag == 0x419) { /* Polynomial curve */ + for (get4(), i=0; i < 8; i++) + poly[i] = getreal(11); + poly[3] += (ph1.tag_210 - poly[7]) * poly[6] + 1; + for (i=0; i < 0x10000; i++) { + num = (poly[5]*i + poly[3])*i + poly[1]; + curve[i] = LIM(num,0,65535); + } goto apply; /* apply to right half */ + } else if (tag == 0x41a) { /* Polynomial curve */ + for (i=0; i < 4; i++) + poly[i] = getreal(11); + for (i=0; i < 0x10000; i++) { + for (num=0, j=4; j--; ) + num = num * i + poly[j]; + curve[i] = LIM(num+i,0,65535); + } apply: /* apply to whole image */ + for (row=0; row < height; row++) + for (col = (tag & 1)*ph1.split_col; col < width; col++) + BAYER(row,col) = curve[BAYER(row,col)]; + } else if (tag == 0x400) { /* Sensor defects */ + while ((len -= 8) >= 0) { + col = get2() - left_margin; + row = get2() - top_margin; + type = get2(); get2(); + if (col >= width) continue; + if (type == 131) /* Bad column */ + for (row=0; row < height; row++) + if (FC(row,col) == 1) { + for (sum=i=0; i < 4; i++) + sum += val[i] = bayer (row+dir[i][0], col+dir[i][1]); + for (max=i=0; i < 4; i++) { + dev[i] = abs((val[i] << 2) - sum); + if (dev[max] < dev[i]) max = i; + } + BAYER(row,col) = (sum - val[max])/3.0 + 0.5; + } else { + for (sum=0, i=8; i < 12; i++) + sum += bayer (row+dir[i][0], col+dir[i][1]); + BAYER(row,col) = 0.5 + sum * 0.0732233 + + (bayer(row,col-2) + bayer(row,col+2)) * 0.3535534; + } + else if (type == 129) { /* Bad pixel */ + if (row >= height) continue; + j = (FC(row,col) != 1) * 4; + for (sum=0, i=j; i < j+8; i++) + sum += bayer (row+dir[i][0], col+dir[i][1]); + BAYER(row,col) = (sum + 4) >> 3; + } + } + } else if (tag == 0x401) { /* All-color flat fields */ + phase_one_flat_field (1, 2); + } else if (tag == 0x416 || tag == 0x410) { + phase_one_flat_field (0, 2); + } else if (tag == 0x40b) { /* Red+blue flat field */ + phase_one_flat_field (0, 4); + } else if (tag == 0x412) { + fseek (ifp, 36, SEEK_CUR); + diff = abs (get2() - ph1.tag_21a); + if (mindiff > diff) { + mindiff = diff; + off_412 = ftell(ifp) - 38; + } + } + fseek (ifp, save, SEEK_SET); + } + if (off_412) { + fseek (ifp, off_412, SEEK_SET); + for (i=0; i < 9; i++) head[i] = get4() & 0x7fff; + yval[0] = (float *) calloc (head[1]*head[3] + head[2]*head[4], 6); + merror (yval[0], "phase_one_correct()"); + yval[1] = (float *) (yval[0] + head[1]*head[3]); + xval[0] = (ushort *) (yval[1] + head[2]*head[4]); + xval[1] = (ushort *) (xval[0] + head[1]*head[3]); + get2(); + for (i=0; i < 2; i++) + for (j=0; j < head[i+1]*head[i+3]; j++) + yval[i][j] = getreal(11); + for (i=0; i < 2; i++) + for (j=0; j < head[i+1]*head[i+3]; j++) + xval[i][j] = get2(); + for (row=0; row < height; row++) + for (col=0; col < width; col++) { + cfrac = (float) col * head[3] / raw_width; + cfrac -= cip = cfrac; + num = BAYER(row,col) * 0.5; + for (i=cip; i < cip+2; i++) { + for (k=j=0; j < head[1]; j++) + if (num < xval[0][k = head[1]*i+j]) break; + frac = (j == 0 || j == head[1]) ? 0 : + (xval[0][k] - num) / (xval[0][k] - xval[0][k-1]); + mult[i-cip] = yval[0][k-1] * frac + yval[0][k] * (1-frac); + } + i = ((mult[0] * (1-cfrac) + mult[1] * cfrac) + * (row + top_margin) + num) * 2; + BAYER(row,col) = LIM(i,0,65535); + } + free (yval[0]); + } +} + +void CLASS phase_one_load_raw() +{ + int row, col, a, b; + ushort *pixel, akey, bkey, mask; + + fseek (ifp, ph1.key_off, SEEK_SET); + akey = get2(); + bkey = get2(); + mask = ph1.format == 1 ? 0x5555:0x1354; + fseek (ifp, data_offset + top_margin*raw_width*2, SEEK_SET); + pixel = (ushort *) calloc (raw_width, sizeof *pixel); + merror (pixel, "phase_one_load_raw()"); + for (row=0; row < height; row++) { + read_shorts (pixel, raw_width); + for (col=0; col < raw_width; col+=2) { + a = pixel[col+0] ^ akey; + b = pixel[col+1] ^ bkey; + pixel[col+0] = (a & mask) | (b & ~mask); + pixel[col+1] = (b & mask) | (a & ~mask); + } + for (col=0; col < width; col++) + BAYER(row,col) = pixel[col+left_margin]; + } + free (pixel); + phase_one_correct(); +} + +unsigned CLASS ph1_bithuff (int nbits, ushort *huff) +{ + static UINT64 bitbuf=0; + static int vbits=0; + unsigned c; + + if (nbits == -1) + return bitbuf = vbits = 0; + if (nbits == 0) return 0; + if (vbits < nbits) { + bitbuf = bitbuf << 32 | get4(); + vbits += 32; + } + c = bitbuf << (64-vbits) >> (64-nbits); + if (huff) { + vbits -= huff[c] >> 8; + return (uchar) huff[c]; + } + vbits -= nbits; + return c; +} +#define ph1_bits(n) ph1_bithuff(n,0) +#define ph1_huff(h) ph1_bithuff(*h,h+1) + +void CLASS phase_one_load_raw_c() +{ + static const int length[] = { 8,7,6,9,11,10,5,12,14,13 }; + int *offset, len[2], pred[2], row, col, i, j; + ushort *pixel; + short (*black)[2]; + + pixel = (ushort *) calloc (raw_width + raw_height*4, 2); + merror (pixel, "phase_one_load_raw_c()"); + offset = (int *) (pixel + raw_width); + fseek (ifp, strip_offset, SEEK_SET); + for (row=0; row < raw_height; row++) + offset[row] = get4(); + black = (short (*)[2]) offset + raw_height; + fseek (ifp, ph1.black_off, SEEK_SET); + if (ph1.black_off) + read_shorts ((ushort *) black[0], raw_height*2); + for (i=0; i < 256; i++) + curve[i] = i*i / 3.969 + 0.5; + for (row=0; row < raw_height; row++) { + fseek (ifp, data_offset + offset[row], SEEK_SET); + ph1_bits(-1); + pred[0] = pred[1] = 0; + for (col=0; col < raw_width; col++) { + if (col >= (raw_width & -8)) + len[0] = len[1] = 14; + else if ((col & 7) == 0) + for (i=0; i < 2; i++) { + for (j=0; j < 5 && !ph1_bits(1); j++); + if (j--) len[i] = length[j*2 + ph1_bits(1)]; + } + if ((i = len[col & 1]) == 14) + pixel[col] = pred[col & 1] = ph1_bits(16); + else + pixel[col] = pred[col & 1] += ph1_bits(i) + 1 - (1 << (i - 1)); + if (pred[col & 1] >> 16) derror(); + if (ph1.format == 5 && pixel[col] < 256) + pixel[col] = curve[pixel[col]]; + } + if ((unsigned) (row-top_margin) < height) + for (col=0; col < width; col++) { + i = (pixel[col+left_margin] << 2) + - ph1.black + black[row][col >= ph1.split_col]; + if (i > 0) BAYER(row-top_margin,col) = i; + } + } + free (pixel); + phase_one_correct(); + maximum = 0xfffc - ph1.black; +} + +void CLASS hasselblad_load_raw() +{ + struct jhead jh; + int row, col, pred[2], len[2], diff, c; + + if (!ljpeg_start (&jh, 0)) return; + order = 0x4949; + ph1_bits(-1); + for (row=-top_margin; row < height; row++) { + pred[0] = pred[1] = 0x8000; + for (col=-left_margin; col < raw_width-left_margin; col+=2) { + FORC(2) len[c] = ph1_huff(jh.huff[0]); + FORC(2) { + diff = ph1_bits(len[c]); + if ((diff & (1 << (len[c]-1))) == 0) + diff -= (1 << len[c]) - 1; + if (diff == 65535) diff = -32768; + pred[c] += diff; + if (row >= 0 && (unsigned)(col+c) < width) + BAYER(row,col+c) = pred[c]; + } + } + } + ljpeg_end (&jh); + maximum = 0xffff; +} + +void CLASS leaf_hdr_load_raw() +{ + ushort *pixel; + unsigned tile=0, r, c, row, col; + + pixel = (ushort *) calloc (raw_width, sizeof *pixel); + merror (pixel, "leaf_hdr_load_raw()"); + FORC(tiff_samples) + for (r=0; r < raw_height; r++) { + if (r % tile_length == 0) { + fseek (ifp, data_offset + 4*tile++, SEEK_SET); + fseek (ifp, get4() + 2*left_margin, SEEK_SET); + } + if (filters && c != shot_select) continue; + read_shorts (pixel, raw_width); + if ((row = r - top_margin) >= height) continue; + for (col=0; col < width; col++) + if (filters) BAYER(row,col) = pixel[col]; + else image[row*width+col][c] = pixel[col]; + } + free (pixel); + if (!filters) { + maximum = 0xffff; + raw_color = 1; + } +} + +void CLASS unpacked_load_raw(); + +void CLASS sinar_4shot_load_raw() +{ + ushort *pixel; + unsigned shot, row, col, r, c; + + if ((shot = shot_select) || half_size) { + if (shot) shot--; + if (shot > 3) shot = 3; + fseek (ifp, data_offset + shot*4, SEEK_SET); + fseek (ifp, get4(), SEEK_SET); + unpacked_load_raw(); + return; + } + free (image); + image = (ushort (*)[4]) + calloc ((iheight=height)*(iwidth=width), sizeof *image); + merror (image, "sinar_4shot_load_raw()"); + pixel = (ushort *) calloc (raw_width, sizeof *pixel); + merror (pixel, "sinar_4shot_load_raw()"); + for (shot=0; shot < 4; shot++) { + fseek (ifp, data_offset + shot*4, SEEK_SET); + fseek (ifp, get4(), SEEK_SET); + for (row=0; row < raw_height; row++) { + read_shorts (pixel, raw_width); + if ((r = row-top_margin - (shot >> 1 & 1)) >= height) continue; + for (col=0; col < raw_width; col++) { + if ((c = col-left_margin - (shot & 1)) >= width) continue; + image[r*width+c][FC(row,col)] = pixel[col]; + } + } + } + free (pixel); + shrink = filters = 0; +} + +void CLASS imacon_full_load_raw() +{ + int row, col; + + for (row=0; row < height; row++) + for (col=0; col < width; col++) + read_shorts (image[row*width+col], 3); +} + +void CLASS packed_load_raw() +{ + int vbits=0, bwide, pwide, rbits, bite, half, irow, row, col, val, i; + UINT64 bitbuf=0; + + if (raw_width * 8 >= width * tiff_bps) /* Is raw_width in bytes? */ + pwide = (bwide = raw_width) * 8 / tiff_bps; + else bwide = (pwide = raw_width) * tiff_bps / 8; + rbits = bwide * 8 - pwide * tiff_bps; + if (load_flags & 1) bwide = bwide * 16 / 15; + fseek (ifp, top_margin*bwide, SEEK_CUR); + bite = 8 + (load_flags & 24); + half = (height+1) >> 1; + for (irow=0; irow < height; irow++) { + row = irow; + if (load_flags & 2 && + (row = irow % half * 2 + irow / half) == 1 && + load_flags & 4) { + if (vbits=0, tiff_compress) + fseek (ifp, data_offset - (-half*bwide & -2048), SEEK_SET); + else { + fseek (ifp, 0, SEEK_END); + fseek (ifp, ftell(ifp) >> 3 << 2, SEEK_SET); + } + } + for (col=0; col < pwide; col++) { + for (vbits -= tiff_bps; vbits < 0; vbits += bite) { + bitbuf <<= bite; + for (i=0; i < bite; i+=8) + bitbuf |= (unsigned) (fgetc(ifp) << i); + } + val = bitbuf << (64-tiff_bps-vbits) >> (64-tiff_bps); + i = (col ^ (bite == 24)) - left_margin; + if ((unsigned) i < width) + BAYER(row,i) = val << (load_flags >> 6); + else if (load_flags & 32) + black += val; + if (load_flags & 1 && (col % 10) == 9 && + fgetc(ifp) && col < width+left_margin) derror(); + } + vbits -= rbits; + } + if (load_flags & 32 && pwide > width) + black /= (pwide - width) * height; +} + +void CLASS unpacked_load_raw() +{ + ushort *pixel; + int row, col, bits=0; + + while (1 << ++bits < maximum); + fseek (ifp, (top_margin*raw_width + left_margin) * 2, SEEK_CUR); + pixel = (ushort *) calloc (width, sizeof *pixel); + merror (pixel, "unpacked_load_raw()"); + for (row=0; row < height; row++) { + read_shorts (pixel, width); + fseek (ifp, 2*(raw_width - width), SEEK_CUR); + for (col=0; col < width; col++) + if ((BAYER2(row,col) = pixel[col]) >> bits) derror(); + } + free (pixel); +} + +void CLASS nokia_load_raw() +{ + uchar *data, *dp; + ushort *pixel, *pix; + int dwide, row, c; + + dwide = raw_width * 5 / 4; + data = (uchar *) malloc (dwide + raw_width*2); + merror (data, "nokia_load_raw()"); + pixel = (ushort *) (data + dwide); + for (row=0; row < raw_height; row++) { + if (fread (data, 1, dwide, ifp) < dwide) derror(); + for (dp=data, pix=pixel; pix < pixel+raw_width; dp+=5, pix+=4) + FORC4 pix[c] = (dp[c] << 2) | (dp[4] >> (c << 1) & 3); + if (row < top_margin) + FORC(width) black += pixel[c]; + else + FORC(width) BAYER(row-top_margin,c) = pixel[c]; + } + free (data); + if (top_margin) black /= top_margin * width; + maximum = 0x3ff; +} + +unsigned CLASS pana_bits (int nbits) +{ + static uchar buf[0x4000]; + static int vbits; + int byte; + + if (!nbits) return vbits=0; + if (!vbits) { + fread (buf+load_flags, 1, 0x4000-load_flags, ifp); + fread (buf, 1, load_flags, ifp); + } + vbits = (vbits - nbits) & 0x1ffff; + byte = vbits >> 3 ^ 0x3ff0; + return (buf[byte] | buf[byte+1] << 8) >> (vbits & 7) & ~(-1 << nbits); +} + +void CLASS panasonic_load_raw() +{ + int row, col, i, j, sh=0, pred[2], nonz[2]; + + pana_bits(0); + for (row=0; row < height; row++) + for (col=0; col < raw_width; col++) { + if ((i = col % 14) == 0) + pred[0] = pred[1] = nonz[0] = nonz[1] = 0; + if (i % 3 == 2) sh = 4 >> (3 - pana_bits(2)); + if (nonz[i & 1]) { + if ((j = pana_bits(8))) { + if ((pred[i & 1] -= 0x80 << sh) < 0 || sh == 4) + pred[i & 1] &= ~(-1 << sh); + pred[i & 1] += j << sh; + } + } else if ((nonz[i & 1] = pana_bits(8)) || i > 11) + pred[i & 1] = nonz[i & 1] << 4 | pana_bits(4); + if (col < width) + if ((BAYER(row,col) = pred[col & 1]) > 4098) derror(); + } +} + +void CLASS olympus_load_raw() +{ + ushort huff[4096]; + int row, col, nbits, sign, low, high, i, c, w, n, nw; + int acarry[2][3], *carry, pred, diff; + + huff[n=0] = 0xc0c; + for (i=12; i--; ) + FORC(2048 >> i) huff[++n] = (i+1) << 8 | i; + fseek (ifp, 7, SEEK_CUR); + getbits(-1); + for (row=0; row < height; row++) { + memset (acarry, 0, sizeof acarry); + for (col=0; col < raw_width; col++) { + carry = acarry[col & 1]; + i = 2 * (carry[2] < 3); + for (nbits=2+i; (ushort) carry[0] >> (nbits+i); nbits++); + low = (sign = getbits(3)) & 3; + sign = sign << 29 >> 31; + if ((high = getbithuff(12,huff)) == 12) + high = getbits(16-nbits) >> 1; + carry[0] = (high << nbits) | getbits(nbits); + diff = (carry[0] ^ sign) + carry[1]; + carry[1] = (diff*3 + carry[1]) >> 5; + carry[2] = carry[0] > 16 ? 0 : carry[2]+1; + if (col >= width) continue; + if (row < 2 && col < 2) pred = 0; + else if (row < 2) pred = BAYER(row,col-2); + else if (col < 2) pred = BAYER(row-2,col); + else { + w = BAYER(row,col-2); + n = BAYER(row-2,col); + nw = BAYER(row-2,col-2); + if ((w < nw && nw < n) || (n < nw && nw < w)) { + if (ABS(w-nw) > 32 || ABS(n-nw) > 32) + pred = w + n - nw; + else pred = (w + n) >> 1; + } else pred = ABS(w-nw) > ABS(n-nw) ? w : n; + } + if ((BAYER(row,col) = pred + ((diff << 2) | low)) >> 12) derror(); + } + } +} + +void CLASS minolta_rd175_load_raw() +{ + uchar pixel[768]; + unsigned irow, box, row, col; + + for (irow=0; irow < 1481; irow++) { + if (fread (pixel, 1, 768, ifp) < 768) derror(); + box = irow / 82; + row = irow % 82 * 12 + ((box < 12) ? box | 1 : (box-12)*2); + switch (irow) { + case 1477: case 1479: continue; + case 1476: row = 984; break; + case 1480: row = 985; break; + case 1478: row = 985; box = 1; + } + if ((box < 12) && (box & 1)) { + for (col=0; col < 1533; col++, row ^= 1) + if (col != 1) BAYER(row,col) = (col+1) & 2 ? + pixel[col/2-1] + pixel[col/2+1] : pixel[col/2] << 1; + BAYER(row,1) = pixel[1] << 1; + BAYER(row,1533) = pixel[765] << 1; + } else + for (col=row & 1; col < 1534; col+=2) + BAYER(row,col) = pixel[col/2] << 1; + } + maximum = 0xff << 1; +} + +void CLASS quicktake_100_load_raw() +{ + uchar pixel[484][644]; + static const short gstep[16] = + { -89,-60,-44,-32,-22,-15,-8,-2,2,8,15,22,32,44,60,89 }; + static const short rstep[6][4] = + { { -3,-1,1,3 }, { -5,-1,1,5 }, { -8,-2,2,8 }, + { -13,-3,3,13 }, { -19,-4,4,19 }, { -28,-6,6,28 } }; + static const short curve[256] = + { 0,1,2,3,4,5,6,7,8,9,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27, + 28,29,30,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,53, + 54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,74,75,76,77,78, + 79,80,81,82,83,84,86,88,90,92,94,97,99,101,103,105,107,110,112,114,116, + 118,120,123,125,127,129,131,134,136,138,140,142,144,147,149,151,153,155, + 158,160,162,164,166,168,171,173,175,177,179,181,184,186,188,190,192,195, + 197,199,201,203,205,208,210,212,214,216,218,221,223,226,230,235,239,244, + 248,252,257,261,265,270,274,278,283,287,291,296,300,305,309,313,318,322, + 326,331,335,339,344,348,352,357,361,365,370,374,379,383,387,392,396,400, + 405,409,413,418,422,426,431,435,440,444,448,453,457,461,466,470,474,479, + 483,487,492,496,500,508,519,531,542,553,564,575,587,598,609,620,631,643, + 654,665,676,687,698,710,721,732,743,754,766,777,788,799,810,822,833,844, + 855,866,878,889,900,911,922,933,945,956,967,978,989,1001,1012,1023 }; + int rb, row, col, sharp, val=0; + + getbits(-1); + memset (pixel, 0x80, sizeof pixel); + for (row=2; row < height+2; row++) { + for (col=2+(row & 1); col < width+2; col+=2) { + val = ((pixel[row-1][col-1] + 2*pixel[row-1][col+1] + + pixel[row][col-2]) >> 2) + gstep[getbits(4)]; + pixel[row][col] = val = LIM(val,0,255); + if (col < 4) + pixel[row][col-2] = pixel[row+1][~row & 1] = val; + if (row == 2) + pixel[row-1][col+1] = pixel[row-1][col+3] = val; + } + pixel[row][col] = val; + } + for (rb=0; rb < 2; rb++) + for (row=2+rb; row < height+2; row+=2) + for (col=3-(row & 1); col < width+2; col+=2) { + if (row < 4 || col < 4) sharp = 2; + else { + val = ABS(pixel[row-2][col] - pixel[row][col-2]) + + ABS(pixel[row-2][col] - pixel[row-2][col-2]) + + ABS(pixel[row][col-2] - pixel[row-2][col-2]); + sharp = val < 4 ? 0 : val < 8 ? 1 : val < 16 ? 2 : + val < 32 ? 3 : val < 48 ? 4 : 5; + } + val = ((pixel[row-2][col] + pixel[row][col-2]) >> 1) + + rstep[sharp][getbits(2)]; + pixel[row][col] = val = LIM(val,0,255); + if (row < 4) pixel[row-2][col+2] = val; + if (col < 4) pixel[row+2][col-2] = val; + } + for (row=2; row < height+2; row++) + for (col=3-(row & 1); col < width+2; col+=2) { + val = ((pixel[row][col-1] + (pixel[row][col] << 2) + + pixel[row][col+1]) >> 1) - 0x100; + pixel[row][col] = LIM(val,0,255); + } + for (row=0; row < height; row++) + for (col=0; col < width; col++) + BAYER(row,col) = curve[pixel[row+2][col+2]]; + maximum = 0x3ff; +} + +#define radc_token(tree) ((signed char) getbithuff(8,huff[tree])) + +#define FORYX for (y=1; y < 3; y++) for (x=col+1; x >= col; x--) + +#define PREDICTOR (c ? (buf[c][y-1][x] + buf[c][y][x+1]) / 2 \ +: (buf[c][y-1][x+1] + 2*buf[c][y-1][x] + buf[c][y][x+1]) / 4) + +void CLASS kodak_radc_load_raw() +{ + static const char src[] = { + 1,1, 2,3, 3,4, 4,2, 5,7, 6,5, 7,6, 7,8, + 1,0, 2,1, 3,3, 4,4, 5,2, 6,7, 7,6, 8,5, 8,8, + 2,1, 2,3, 3,0, 3,2, 3,4, 4,6, 5,5, 6,7, 6,8, + 2,0, 2,1, 2,3, 3,2, 4,4, 5,6, 6,7, 7,5, 7,8, + 2,1, 2,4, 3,0, 3,2, 3,3, 4,7, 5,5, 6,6, 6,8, + 2,3, 3,1, 3,2, 3,4, 3,5, 3,6, 4,7, 5,0, 5,8, + 2,3, 2,6, 3,0, 3,1, 4,4, 4,5, 4,7, 5,2, 5,8, + 2,4, 2,7, 3,3, 3,6, 4,1, 4,2, 4,5, 5,0, 5,8, + 2,6, 3,1, 3,3, 3,5, 3,7, 3,8, 4,0, 5,2, 5,4, + 2,0, 2,1, 3,2, 3,3, 4,4, 4,5, 5,6, 5,7, 4,8, + 1,0, 2,2, 2,-2, + 1,-3, 1,3, + 2,-17, 2,-5, 2,5, 2,17, + 2,-7, 2,2, 2,9, 2,18, + 2,-18, 2,-9, 2,-2, 2,7, + 2,-28, 2,28, 3,-49, 3,-9, 3,9, 4,49, 5,-79, 5,79, + 2,-1, 2,13, 2,26, 3,39, 4,-16, 5,55, 6,-37, 6,76, + 2,-26, 2,-13, 2,1, 3,-39, 4,16, 5,-55, 6,-76, 6,37 + }; + ushort huff[19][256]; + int row, col, tree, nreps, rep, step, i, c, s, r, x, y, val; + short last[3] = { 16,16,16 }, mul[3], buf[3][3][386]; + static const ushort pt[] = + { 0,0, 1280,1344, 2320,3616, 3328,8000, 4095,16383, 65535,16383 }; + + for (i=2; i < 12; i+=2) + for (c=pt[i-2]; c <= pt[i]; c++) + curve[c] = (float) + (c-pt[i-2]) / (pt[i]-pt[i-2]) * (pt[i+1]-pt[i-1]) + pt[i-1] + 0.5; + for (s=i=0; i < sizeof src; i+=2) + FORC(256 >> src[i]) + huff[0][s++] = src[i] << 8 | (uchar) src[i+1]; + s = kodak_cbpp == 243 ? 2 : 3; + FORC(256) huff[18][c] = (8-s) << 8 | c >> s << s | 1 << (s-1); + getbits(-1); + for (i=0; i < sizeof(buf)/sizeof(short); i++) + buf[0][0][i] = 2048; + for (row=0; row < height; row+=4) { + FORC3 mul[c] = getbits(6); + FORC3 { + val = ((0x1000000/last[c] + 0x7ff) >> 12) * mul[c]; + s = val > 65564 ? 10:12; + x = ~(-1 << (s-1)); + val <<= 12-s; + for (i=0; i < sizeof(buf[0])/sizeof(short); i++) + buf[c][0][i] = (buf[c][0][i] * val + x) >> s; + last[c] = mul[c]; + for (r=0; r <= !c; r++) { + buf[c][1][width/2] = buf[c][2][width/2] = mul[c] << 7; + for (tree=1, col=width/2; col > 0; ) { + if ((tree = radc_token(tree))) { + col -= 2; + if (tree == 8) + FORYX buf[c][y][x] = (uchar) radc_token(18) * mul[c]; + else + FORYX buf[c][y][x] = radc_token(tree+10) * 16 + PREDICTOR; + } else + do { + nreps = (col > 2) ? radc_token(9) + 1 : 1; + for (rep=0; rep < 8 && rep < nreps && col > 0; rep++) { + col -= 2; + FORYX buf[c][y][x] = PREDICTOR; + if (rep & 1) { + step = radc_token(10) << 4; + FORYX buf[c][y][x] += step; + } + } + } while (nreps == 9); + } + for (y=0; y < 2; y++) + for (x=0; x < width/2; x++) { + val = (buf[c][y+1][x] << 4) / mul[c]; + if (val < 0) val = 0; + if (c) BAYER(row+y*2+c-1,x*2+2-c) = val; + else BAYER(row+r*2+y,x*2+y) = val; + } + memcpy (buf[c][0]+!c, buf[c][2], sizeof buf[c][0]-2*!c); + } + } + for (y=row; y < row+4; y++) + for (x=0; x < width; x++) + if ((x+y) & 1) { + r = x ? x-1 : x+1; + s = x+1 < width ? x+1 : x-1; + val = (BAYER(y,x)-2048)*2 + (BAYER(y,r)+BAYER(y,s))/2; + if (val < 0) val = 0; + BAYER(y,x) = val; + } + } + for (i=0; i < iheight*iwidth*4; i++) + image[0][i] = curve[image[0][i]]; + maximum = 0x3fff; +} + +#undef FORYX +#undef PREDICTOR + +#ifdef NO_JPEG +void CLASS kodak_jpeg_load_raw() {} +#else + +METHODDEF(boolean) +fill_input_buffer (j_decompress_ptr cinfo) +{ + static uchar jpeg_buffer[4096]; + size_t nbytes; + + nbytes = fread (jpeg_buffer, 1, 4096, ifp); + swab (jpeg_buffer, jpeg_buffer, nbytes); + cinfo->src->next_input_byte = jpeg_buffer; + cinfo->src->bytes_in_buffer = nbytes; + return TRUE; +} + +void CLASS kodak_jpeg_load_raw() +{ + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + JSAMPARRAY buf; + JSAMPLE (*pixel)[3]; + int row, col; + + cinfo.err = jpeg_std_error (&jerr); + jpeg_create_decompress (&cinfo); + jpeg_stdio_src (&cinfo, ifp); + cinfo.src->fill_input_buffer = fill_input_buffer; + jpeg_read_header (&cinfo, TRUE); + jpeg_start_decompress (&cinfo); + if ((cinfo.output_width != width ) || + (cinfo.output_height*2 != height ) || + (cinfo.output_components != 3 )) { + fprintf (stderr,_("%s: incorrect JPEG dimensions\n"), ifname); + jpeg_destroy_decompress (&cinfo); + longjmp (failure, 3); + } + buf = (*cinfo.mem->alloc_sarray) + ((j_common_ptr) &cinfo, JPOOL_IMAGE, width*3, 1); + + while (cinfo.output_scanline < cinfo.output_height) { + row = cinfo.output_scanline * 2; + jpeg_read_scanlines (&cinfo, buf, 1); + pixel = (JSAMPLE (*)[3]) buf[0]; + for (col=0; col < width; col+=2) { + BAYER(row+0,col+0) = pixel[col+0][1] << 1; + BAYER(row+1,col+1) = pixel[col+1][1] << 1; + BAYER(row+0,col+1) = pixel[col][0] + pixel[col+1][0]; + BAYER(row+1,col+0) = pixel[col][2] + pixel[col+1][2]; + } + } + jpeg_finish_decompress (&cinfo); + jpeg_destroy_decompress (&cinfo); + maximum = 0xff << 1; +} +#endif + +void CLASS kodak_dc120_load_raw() +{ + static const int mul[4] = { 162, 192, 187, 92 }; + static const int add[4] = { 0, 636, 424, 212 }; + uchar pixel[848]; + int row, shift, col; + + for (row=0; row < height; row++) { + if (fread (pixel, 1, 848, ifp) < 848) derror(); + shift = row * mul[row & 3] + add[row & 3]; + for (col=0; col < width; col++) + BAYER(row,col) = (ushort) pixel[(col + shift) % 848]; + } + maximum = 0xff; +} + +void CLASS eight_bit_load_raw() +{ + uchar *pixel; + unsigned row, col, val, lblack=0; + + pixel = (uchar *) calloc (raw_width, sizeof *pixel); + merror (pixel, "eight_bit_load_raw()"); + fseek (ifp, top_margin*raw_width, SEEK_CUR); + for (row=0; row < height; row++) { + if (fread (pixel, 1, raw_width, ifp) < raw_width) derror(); + for (col=0; col < raw_width; col++) { + val = curve[pixel[col]]; + if ((unsigned) (col-left_margin) < width) + BAYER(row,col-left_margin) = val; + else lblack += val; + } + } + free (pixel); + if (raw_width > width+1) + black = lblack / ((raw_width - width) * height); + if (!strncmp(model,"DC2",3)) + black = 0; + maximum = curve[0xff]; +} + +void CLASS kodak_yrgb_load_raw() +{ + uchar *pixel; + int row, col, y, cb, cr, rgb[3], c; + + pixel = (uchar *) calloc (raw_width, 3*sizeof *pixel); + merror (pixel, "kodak_yrgb_load_raw()"); + for (row=0; row < height; row++) { + if (~row & 1) + if (fread (pixel, raw_width, 3, ifp) < 3) derror(); + for (col=0; col < raw_width; col++) { + y = pixel[width*2*(row & 1) + col]; + cb = pixel[width + (col & -2)] - 128; + cr = pixel[width + (col & -2)+1] - 128; + rgb[1] = y-((cb + cr + 2) >> 2); + rgb[2] = rgb[1] + cb; + rgb[0] = rgb[1] + cr; + FORC3 image[row*width+col][c] = curve[LIM(rgb[c],0,255)]; + } + } + free (pixel); + maximum = curve[0xff]; +} + +void CLASS kodak_262_load_raw() +{ + static const uchar kodak_tree[2][26] = + { { 0,1,5,1,1,2,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9 }, + { 0,3,1,1,1,1,1,2,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9 } }; + ushort *huff[2]; + uchar *pixel; + int *strip, ns, c, row, col, chess, pi=0, pi1, pi2, pred, val; + + FORC(2) huff[c] = make_decoder (kodak_tree[c]); + ns = (raw_height+63) >> 5; + pixel = (uchar *) malloc (raw_width*32 + ns*4); + merror (pixel, "kodak_262_load_raw()"); + strip = (int *) (pixel + raw_width*32); + order = 0x4d4d; + FORC(ns) strip[c] = get4(); + for (row=0; row < raw_height; row++) { + if ((row & 31) == 0) { + fseek (ifp, strip[row >> 5], SEEK_SET); + getbits(-1); + pi = 0; + } + for (col=0; col < raw_width; col++) { + chess = (row + col) & 1; + pi1 = chess ? pi-2 : pi-raw_width-1; + pi2 = chess ? pi-2*raw_width : pi-raw_width+1; + if (col <= chess) pi1 = -1; + if (pi1 < 0) pi1 = pi2; + if (pi2 < 0) pi2 = pi1; + if (pi1 < 0 && col > 1) pi1 = pi2 = pi-2; + pred = (pi1 < 0) ? 0 : (pixel[pi1] + pixel[pi2]) >> 1; + pixel[pi] = val = pred + ljpeg_diff (huff[chess]); + if (val >> 8) derror(); + val = curve[pixel[pi++]]; + if ((unsigned) (col-left_margin) < width) + BAYER(row,col-left_margin) = val; + else black += val; + } + } + free (pixel); + FORC(2) free (huff[c]); + if (raw_width > width) + black /= (raw_width - width) * height; +} + +int CLASS kodak_65000_decode (short *out, int bsize) +{ + uchar c, blen[768]; + ushort raw[6]; + INT64 bitbuf=0; + int save, bits=0, i, j, len, diff; + + save = ftell(ifp); + bsize = (bsize + 3) & -4; + for (i=0; i < bsize; i+=2) { + c = fgetc(ifp); + if ((blen[i ] = c & 15) > 12 || + (blen[i+1] = c >> 4) > 12 ) { + fseek (ifp, save, SEEK_SET); + for (i=0; i < bsize; i+=8) { + read_shorts (raw, 6); + out[i ] = raw[0] >> 12 << 8 | raw[2] >> 12 << 4 | raw[4] >> 12; + out[i+1] = raw[1] >> 12 << 8 | raw[3] >> 12 << 4 | raw[5] >> 12; + for (j=0; j < 6; j++) + out[i+2+j] = raw[j] & 0xfff; + } + return 1; + } + } + if ((bsize & 7) == 4) { + bitbuf = fgetc(ifp) << 8; + bitbuf += fgetc(ifp); + bits = 16; + } + for (i=0; i < bsize; i++) { + len = blen[i]; + if (bits < len) { + for (j=0; j < 32; j+=8) + bitbuf += (INT64) fgetc(ifp) << (bits+(j^8)); + bits += 32; + } + diff = bitbuf & (0xffff >> (16-len)); + bitbuf >>= len; + bits -= len; + if ((diff & (1 << (len-1))) == 0) + diff -= (1 << len) - 1; + out[i] = diff; + } + return 0; +} + +void CLASS kodak_65000_load_raw() +{ + short buf[256]; + int row, col, len, pred[2], ret, i; + + for (row=0; row < height; row++) + for (col=0; col < width; col+=256) { + pred[0] = pred[1] = 0; + len = MIN (256, width-col); + ret = kodak_65000_decode (buf, len); + for (i=0; i < len; i++) + if ((BAYER(row,col+i) = curve[ret ? buf[i] : + (pred[i & 1] += buf[i])]) >> 12) derror(); + } +} + +void CLASS kodak_ycbcr_load_raw() +{ + short buf[384], *bp; + int row, col, len, c, i, j, k, y[2][2], cb, cr, rgb[3]; + ushort *ip; + + for (row=0; row < height; row+=2) + for (col=0; col < width; col+=128) { + len = MIN (128, width-col); + kodak_65000_decode (buf, len*3); + y[0][1] = y[1][1] = cb = cr = 0; + for (bp=buf, i=0; i < len; i+=2, bp+=2) { + cb += bp[4]; + cr += bp[5]; + rgb[1] = -((cb + cr + 2) >> 2); + rgb[2] = rgb[1] + cb; + rgb[0] = rgb[1] + cr; + for (j=0; j < 2; j++) + for (k=0; k < 2; k++) { + if ((y[j][k] = y[j][k^1] + *bp++) >> 10) derror(); + ip = image[(row+j)*width + col+i+k]; + FORC3 ip[c] = curve[LIM(y[j][k]+rgb[c], 0, 0xfff)]; + } + } + } +} + +void CLASS kodak_rgb_load_raw() +{ + short buf[768], *bp; + int row, col, len, c, i, rgb[3]; + ushort *ip=image[0]; + + for (row=0; row < height; row++) + for (col=0; col < width; col+=256) { + len = MIN (256, width-col); + kodak_65000_decode (buf, len*3); + memset (rgb, 0, sizeof rgb); + for (bp=buf, i=0; i < len; i++, ip+=4) + FORC3 if ((ip[c] = rgb[c] += *bp++) >> 12) derror(); + } +} + +void CLASS kodak_thumb_load_raw() +{ + int row, col; + colors = thumb_misc >> 5; + for (row=0; row < height; row++) + for (col=0; col < width; col++) + read_shorts (image[row*width+col], colors); + maximum = (1 << (thumb_misc & 31)) - 1; +} + +void CLASS sony_decrypt (unsigned *data, int len, int start, int key) +{ + static unsigned pad[128], p; + + if (start) { + for (p=0; p < 4; p++) + pad[p] = key = key * 48828125 + 1; + pad[3] = pad[3] << 1 | (pad[0]^pad[2]) >> 31; + for (p=4; p < 127; p++) + pad[p] = (pad[p-4]^pad[p-2]) << 1 | (pad[p-3]^pad[p-1]) >> 31; + for (p=0; p < 127; p++) + pad[p] = htonl(pad[p]); + } + while (len--) + *data++ ^= pad[p++ & 127] = pad[(p+1) & 127] ^ pad[(p+65) & 127]; +} + +void CLASS sony_load_raw() +{ + uchar head[40]; + ushort *pixel; + unsigned i, key, row, col; + + fseek (ifp, 200896, SEEK_SET); + fseek (ifp, (unsigned) fgetc(ifp)*4 - 1, SEEK_CUR); + order = 0x4d4d; + key = get4(); + fseek (ifp, 164600, SEEK_SET); + fread (head, 1, 40, ifp); + sony_decrypt ((unsigned int *) head, 10, 1, key); + for (i=26; i-- > 22; ) + key = key << 8 | head[i]; + fseek (ifp, data_offset, SEEK_SET); + pixel = (ushort *) calloc (raw_width, sizeof *pixel); + merror (pixel, "sony_load_raw()"); + for (row=0; row < height; row++) { + if (fread (pixel, 2, raw_width, ifp) < raw_width) derror(); + sony_decrypt ((unsigned int *) pixel, raw_width/2, !row, key); + for (col=9; col < left_margin; col++) + black += ntohs(pixel[col]); + for (col=0; col < width; col++) + if ((BAYER(row,col) = ntohs(pixel[col+left_margin])) >> 14) + derror(); + } + free (pixel); + if (left_margin > 9) + black /= (left_margin-9) * height; + maximum = 0x3ff0; +} + +void CLASS sony_arw_load_raw() +{ + ushort huff[32768]; + static const ushort tab[18] = + { 0xf11,0xf10,0xe0f,0xd0e,0xc0d,0xb0c,0xa0b,0x90a,0x809, + 0x708,0x607,0x506,0x405,0x304,0x303,0x300,0x202,0x201 }; + int i, c, n, col, row, len, diff, sum=0; + + for (n=i=0; i < 18; i++) + FORC(32768 >> (tab[i] >> 8)) huff[n++] = tab[i]; + getbits(-1); + for (col = raw_width; col--; ) + for (row=0; row < raw_height+1; row+=2) { + if (row == raw_height) row = 1; + len = getbithuff(15,huff); + diff = getbits(len); + if ((diff & (1 << (len-1))) == 0) + diff -= (1 << len) - 1; + if ((sum += diff) >> 12) derror(); + if (row < height) BAYER(row,col) = sum; + } +} + +void CLASS sony_arw2_load_raw() +{ + uchar *data, *dp; + ushort pix[16]; + int row, col, val, max, min, imax, imin, sh, bit, i; + + data = (uchar *) malloc (raw_width); + merror (data, "sony_arw2_load_raw()"); + for (row=0; row < height; row++) { + fread (data, 1, raw_width, ifp); + for (dp=data, col=0; col < width-30; dp+=16) { + max = 0x7ff & (val = sget4(dp)); + min = 0x7ff & val >> 11; + imax = 0x0f & val >> 22; + imin = 0x0f & val >> 26; + for (sh=0; sh < 4 && 0x80 << sh <= max-min; sh++); + for (bit=30, i=0; i < 16; i++) + if (i == imax) pix[i] = max; + else if (i == imin) pix[i] = min; + else { + pix[i] = ((sget2(dp+(bit >> 3)) >> (bit & 7) & 0x7f) << sh) + min; + if (pix[i] > 0x7ff) pix[i] = 0x7ff; + bit += 7; + } + for (i=0; i < 16; i++, col+=2) + BAYER(row,col) = curve[pix[i] << 1] >> 1; + col -= col & 1 ? 1:31; + } + } + free (data); +} + +#define HOLE(row) ((holes >> (((row) - raw_height) & 7)) & 1) + +/* Kudos to Rich Taylor for figuring out SMaL's compression algorithm. */ +void CLASS smal_decode_segment (unsigned seg[2][2], int holes) +{ + uchar hist[3][13] = { + { 7, 7, 0, 0, 63, 55, 47, 39, 31, 23, 15, 7, 0 }, + { 7, 7, 0, 0, 63, 55, 47, 39, 31, 23, 15, 7, 0 }, + { 3, 3, 0, 0, 63, 47, 31, 15, 0 } }; + int low, high=0xff, carry=0, nbits=8; + int s, count, bin, next, i, sym[3]; + uchar diff, pred[]={0,0}; + ushort data=0, range=0; + unsigned pix, row, col; + + fseek (ifp, seg[0][1]+1, SEEK_SET); + getbits(-1); + for (pix=seg[0][0]; pix < seg[1][0]; pix++) { + for (s=0; s < 3; s++) { + data = data << nbits | getbits(nbits); + if (carry < 0) + carry = (nbits += carry+1) < 1 ? nbits-1 : 0; + while (--nbits >= 0) + if ((data >> nbits & 0xff) == 0xff) break; + if (nbits > 0) + data = ((data & ((1 << (nbits-1)) - 1)) << 1) | + ((data + (((data & (1 << (nbits-1)))) << 1)) & (-1 << nbits)); + if (nbits >= 0) { + data += getbits(1); + carry = nbits - 8; + } + count = ((((data-range+1) & 0xffff) << 2) - 1) / (high >> 4); + for (bin=0; hist[s][bin+5] > count; bin++); + low = hist[s][bin+5] * (high >> 4) >> 2; + if (bin) high = hist[s][bin+4] * (high >> 4) >> 2; + high -= low; + for (nbits=0; high << nbits < 128; nbits++); + range = (range+low) << nbits; + high <<= nbits; + next = hist[s][1]; + if (++hist[s][2] > hist[s][3]) { + next = (next+1) & hist[s][0]; + hist[s][3] = (hist[s][next+4] - hist[s][next+5]) >> 2; + hist[s][2] = 1; + } + if (hist[s][hist[s][1]+4] - hist[s][hist[s][1]+5] > 1) { + if (bin < hist[s][1]) + for (i=bin; i < hist[s][1]; i++) hist[s][i+5]--; + else if (next <= bin) + for (i=hist[s][1]; i < bin; i++) hist[s][i+5]++; + } + hist[s][1] = next; + sym[s] = bin; + } + diff = sym[2] << 5 | sym[1] << 2 | (sym[0] & 3); + if (sym[0] & 4) + diff = diff ? -diff : 0x80; + if (ftell(ifp) + 12 >= seg[1][1]) + diff = 0; + pred[pix & 1] += diff; + row = pix / raw_width - top_margin; + col = pix % raw_width - left_margin; + if (row < height && col < width) + BAYER(row,col) = pred[pix & 1]; + if (!(pix & 1) && HOLE(row)) pix += 2; + } + maximum = 0xff; +} + +void CLASS smal_v6_load_raw() +{ + unsigned seg[2][2]; + + fseek (ifp, 16, SEEK_SET); + seg[0][0] = 0; + seg[0][1] = get2(); + seg[1][0] = raw_width * raw_height; + seg[1][1] = INT_MAX; + smal_decode_segment (seg, 0); +} + +int CLASS median4 (int *p) +{ + int min, max, sum, i; + + min = max = sum = p[0]; + for (i=1; i < 4; i++) { + sum += p[i]; + if (min > p[i]) min = p[i]; + if (max < p[i]) max = p[i]; + } + return (sum - min - max) >> 1; +} + +void CLASS fill_holes (int holes) +{ + int row, col, val[4]; + + for (row=2; row < height-2; row++) { + if (!HOLE(row)) continue; + for (col=1; col < width-1; col+=4) { + val[0] = BAYER(row-1,col-1); + val[1] = BAYER(row-1,col+1); + val[2] = BAYER(row+1,col-1); + val[3] = BAYER(row+1,col+1); + BAYER(row,col) = median4(val); + } + for (col=2; col < width-2; col+=4) + if (HOLE(row-2) || HOLE(row+2)) + BAYER(row,col) = (BAYER(row,col-2) + BAYER(row,col+2)) >> 1; + else { + val[0] = BAYER(row,col-2); + val[1] = BAYER(row,col+2); + val[2] = BAYER(row-2,col); + val[3] = BAYER(row+2,col); + BAYER(row,col) = median4(val); + } + } +} + +void CLASS smal_v9_load_raw() +{ + unsigned seg[256][2], offset, nseg, holes, i; + + fseek (ifp, 67, SEEK_SET); + offset = get4(); + nseg = fgetc(ifp); + fseek (ifp, offset, SEEK_SET); + for (i=0; i < nseg*2; i++) + seg[0][i] = get4() + data_offset*(i & 1); + fseek (ifp, 78, SEEK_SET); + holes = fgetc(ifp); + fseek (ifp, 88, SEEK_SET); + seg[nseg][0] = raw_height * raw_width; + seg[nseg][1] = get4() + data_offset; + for (i=0; i < nseg; i++) + smal_decode_segment (seg+i, holes); + if (holes) fill_holes (holes); +} + +/* RESTRICTED code starts here */ + +void CLASS foveon_decoder (unsigned size, unsigned code) +{ + static unsigned huff[1024]; + struct decode *cur; + int i, len; + + if (!code) { + for (i=0; i < size; i++) + huff[i] = get4(); + memset (first_decode, 0, sizeof first_decode); + free_decode = first_decode; + } + cur = free_decode++; + if (free_decode > first_decode+2048) { + fprintf (stderr,_("%s: decoder table overflow\n"), ifname); + longjmp (failure, 2); + } + if (code) + for (i=0; i < size; i++) + if (huff[i] == code) { + cur->leaf = i; + return; + } + if ((len = code >> 27) > 26) return; + code = (len+1) << 27 | (code & 0x3ffffff) << 1; + + cur->branch[0] = free_decode; + foveon_decoder (size, code); + cur->branch[1] = free_decode; + foveon_decoder (size, code+1); +} + +void CLASS foveon_thumb() +{ + unsigned bwide, row, col, bitbuf=0, bit=1, c, i; + char *buf; + struct decode *dindex; + short pred[3]; + + bwide = get4(); + fprintf (ofp, "P6\n%d %d\n255\n", thumb_width, thumb_height); + if (bwide > 0) { + if (bwide < thumb_width*3) return; + buf = (char *) malloc (bwide); + merror (buf, "foveon_thumb()"); + for (row=0; row < thumb_height; row++) { + fread (buf, 1, bwide, ifp); + fwrite (buf, 3, thumb_width, ofp); + } + free (buf); + return; + } + foveon_decoder (256, 0); + + for (row=0; row < thumb_height; row++) { + memset (pred, 0, sizeof pred); + if (!bit) get4(); + for (bit=col=0; col < thumb_width; col++) + FORC3 { + for (dindex=first_decode; dindex->branch[0]; ) { + if ((bit = (bit-1) & 31) == 31) + for (i=0; i < 4; i++) + bitbuf = (bitbuf << 8) + fgetc(ifp); + dindex = dindex->branch[bitbuf >> bit & 1]; + } + pred[c] += dindex->leaf; + fputc (pred[c], ofp); + } + } +} + +void CLASS foveon_load_camf() +{ + unsigned key, i, val; + + fseek (ifp, meta_offset, SEEK_SET); + key = get4(); + fread (meta_data, 1, meta_length, ifp); + for (i=0; i < meta_length; i++) { + key = (key * 1597 + 51749) % 244944; + val = key * (INT64) 301593171 >> 24; + meta_data[i] ^= ((((key << 8) - val) >> 1) + val) >> 17; + } +} + +void CLASS foveon_load_raw() +{ + struct decode *dindex; + short diff[1024]; + unsigned bitbuf=0; + int pred[3], fixed, row, col, bit=-1, c, i; + + fixed = get4(); + read_shorts ((ushort *) diff, 1024); + if (!fixed) foveon_decoder (1024, 0); + + for (row=0; row < height; row++) { + memset (pred, 0, sizeof pred); + if (!bit && !fixed && atoi(model+2) < 14) get4(); + for (col=bit=0; col < width; col++) { + if (fixed) { + bitbuf = get4(); + FORC3 pred[2-c] += diff[bitbuf >> c*10 & 0x3ff]; + } + else FORC3 { + for (dindex=first_decode; dindex->branch[0]; ) { + if ((bit = (bit-1) & 31) == 31) + for (i=0; i < 4; i++) + bitbuf = (bitbuf << 8) + fgetc(ifp); + dindex = dindex->branch[bitbuf >> bit & 1]; + } + pred[c] += diff[dindex->leaf]; + if (pred[c] >> 16 && ~pred[c] >> 16) derror(); + } + FORC3 image[row*width+col][c] = pred[c]; + } + } + if (document_mode) + for (i=0; i < height*width*4; i++) + if ((short) image[0][i] < 0) image[0][i] = 0; + foveon_load_camf(); +} + +const char * CLASS foveon_camf_param (const char *block, const char *param) +{ + unsigned idx, num; + char *pos, *cp, *dp; + + for (idx=0; idx < meta_length; idx += sget4(pos+8)) { + pos = meta_data + idx; + if (strncmp (pos, "CMb", 3)) break; + if (pos[3] != 'P') continue; + if (strcmp (block, pos+sget4(pos+12))) continue; + cp = pos + sget4(pos+16); + num = sget4(cp); + dp = pos + sget4(cp+4); + while (num--) { + cp += 8; + if (!strcmp (param, dp+sget4(cp))) + return dp+sget4(cp+4); + } + } + return 0; +} + +void * CLASS foveon_camf_matrix (unsigned dim[3], const char *name) +{ + unsigned i, idx, type, ndim, size, *mat; + char *pos, *cp, *dp; + double dsize; + + for (idx=0; idx < meta_length; idx += sget4(pos+8)) { + pos = meta_data + idx; + if (strncmp (pos, "CMb", 3)) break; + if (pos[3] != 'M') continue; + if (strcmp (name, pos+sget4(pos+12))) continue; + dim[0] = dim[1] = dim[2] = 1; + cp = pos + sget4(pos+16); + type = sget4(cp); + if ((ndim = sget4(cp+4)) > 3) break; + dp = pos + sget4(cp+8); + for (i=ndim; i--; ) { + cp += 12; + dim[i] = sget4(cp); + } + if ((dsize = (double) dim[0]*dim[1]*dim[2]) > meta_length/4) break; + mat = (unsigned *) malloc ((size = dsize) * 4); + merror (mat, "foveon_camf_matrix()"); + for (i=0; i < size; i++) + if (type && type != 6) + mat[i] = sget4(dp + i*4); + else + mat[i] = sget4(dp + i*2) & 0xffff; + return mat; + } + fprintf (stderr,_("%s: \"%s\" matrix not found!\n"), ifname, name); + return 0; +} + +int CLASS foveon_fixed (void *ptr, int size, const char *name) +{ + void *dp; + unsigned dim[3]; + + dp = foveon_camf_matrix (dim, name); + if (!dp) return 0; + memcpy (ptr, dp, size*4); + free (dp); + return 1; +} + +float CLASS foveon_avg (short *pix, int range[2], float cfilt) +{ + int i; + float val, min=FLT_MAX, max=-FLT_MAX, sum=0; + + for (i=range[0]; i <= range[1]; i++) { + sum += val = pix[i*4] + (pix[i*4]-pix[(i-1)*4]) * cfilt; + if (min > val) min = val; + if (max < val) max = val; + } + if (range[1] - range[0] == 1) return sum/2; + return (sum - min - max) / (range[1] - range[0] - 1); +} + +short * CLASS foveon_make_curve (double max, double mul, double filt) +{ + short *curve; + unsigned i, size; + double x; + + if (!filt) filt = 0.8; + size = 4*M_PI*max / filt; + if (size == UINT_MAX) size--; + curve = (short *) calloc (size+1, sizeof *curve); + merror (curve, "foveon_make_curve()"); + curve[0] = size; + for (i=0; i < size; i++) { + x = i*filt/max/4; + curve[i+1] = (cos(x)+1)/2 * tanh(i*filt/mul) * mul + 0.5; + } + return curve; +} + +void CLASS foveon_make_curves + (short **curvep, float dq[3], float div[3], float filt) +{ + double mul[3], max=0; + int c; + + FORC3 mul[c] = dq[c]/div[c]; + FORC3 if (max < mul[c]) max = mul[c]; + FORC3 curvep[c] = foveon_make_curve (max, mul[c], filt); +} + +int CLASS foveon_apply_curve (short *curve, int i) +{ + if (abs(i) >= curve[0]) return 0; + return i < 0 ? -curve[1-i] : curve[1+i]; +} + +#define image ((short (*)[4]) image) + +void CLASS foveon_interpolate() +{ + static const short hood[] = { -1,-1, -1,0, -1,1, 0,-1, 0,1, 1,-1, 1,0, 1,1 }; + short *pix, prev[3], *curve[8], (*shrink)[3]; + float cfilt=0, ddft[3][3][2], ppm[3][3][3]; + float cam_xyz[3][3], correct[3][3], last[3][3], trans[3][3]; + float chroma_dq[3], color_dq[3], diag[3][3], div[3]; + float (*black)[3], (*sgain)[3], (*sgrow)[3]; + float fsum[3], val, frow, num; + int row, col, c, i, j, diff, sgx, irow, sum, min, max, limit; + int dscr[2][2], dstb[4], (*smrow[7])[3], total[4], ipix[3]; + int work[3][3], smlast, smred, smred_p=0, dev[3]; + int satlev[3], keep[4], active[4]; + unsigned dim[3], *badpix; + double dsum=0, trsum[3]; + char str[128]; + const char* cp; + + if (verbose) + fprintf (stderr,_("Foveon interpolation...\n")); + + foveon_fixed (dscr, 4, "DarkShieldColRange"); + foveon_fixed (ppm[0][0], 27, "PostPolyMatrix"); + foveon_fixed (satlev, 3, "SaturationLevel"); + foveon_fixed (keep, 4, "KeepImageArea"); + foveon_fixed (active, 4, "ActiveImageArea"); + foveon_fixed (chroma_dq, 3, "ChromaDQ"); + foveon_fixed (color_dq, 3, + foveon_camf_param ("IncludeBlocks", "ColorDQ") ? + "ColorDQ" : "ColorDQCamRGB"); + if (foveon_camf_param ("IncludeBlocks", "ColumnFilter")) + foveon_fixed (&cfilt, 1, "ColumnFilter"); + + memset (ddft, 0, sizeof ddft); + if (!foveon_camf_param ("IncludeBlocks", "DarkDrift") + || !foveon_fixed (ddft[1][0], 12, "DarkDrift")) + for (i=0; i < 2; i++) { + foveon_fixed (dstb, 4, i ? "DarkShieldBottom":"DarkShieldTop"); + for (row = dstb[1]; row <= dstb[3]; row++) + for (col = dstb[0]; col <= dstb[2]; col++) + FORC3 ddft[i+1][c][1] += (short) image[row*width+col][c]; + FORC3 ddft[i+1][c][1] /= (dstb[3]-dstb[1]+1) * (dstb[2]-dstb[0]+1); + } + + if (!(cp = foveon_camf_param ("WhiteBalanceIlluminants", model2))) + { fprintf (stderr,_("%s: Invalid white balance \"%s\"\n"), ifname, model2); + return; } + foveon_fixed (cam_xyz, 9, cp); + foveon_fixed (correct, 9, + foveon_camf_param ("WhiteBalanceCorrections", model2)); + memset (last, 0, sizeof last); + for (i=0; i < 3; i++) + for (j=0; j < 3; j++) + FORC3 last[i][j] += correct[i][c] * cam_xyz[c][j]; + + #define LAST(x,y) last[(i+x)%3][(c+y)%3] + for (i=0; i < 3; i++) + FORC3 diag[c][i] = LAST(1,1)*LAST(2,2) - LAST(1,2)*LAST(2,1); + #undef LAST + FORC3 div[c] = diag[c][0]*0.3127 + diag[c][1]*0.329 + diag[c][2]*0.3583; + sprintf (str, "%sRGBNeutral", model2); + if (foveon_camf_param ("IncludeBlocks", str)) + foveon_fixed (div, 3, str); + num = 0; + FORC3 if (num < div[c]) num = div[c]; + FORC3 div[c] /= num; + + memset (trans, 0, sizeof trans); + for (i=0; i < 3; i++) + for (j=0; j < 3; j++) + FORC3 trans[i][j] += rgb_cam[i][c] * last[c][j] * div[j]; + FORC3 trsum[c] = trans[c][0] + trans[c][1] + trans[c][2]; + dsum = (6*trsum[0] + 11*trsum[1] + 3*trsum[2]) / 20; + for (i=0; i < 3; i++) + FORC3 last[i][c] = trans[i][c] * dsum / trsum[i]; + memset (trans, 0, sizeof trans); + for (i=0; i < 3; i++) + for (j=0; j < 3; j++) + FORC3 trans[i][j] += (i==c ? 32 : -1) * last[c][j] / 30; + + foveon_make_curves (curve, color_dq, div, cfilt); + FORC3 chroma_dq[c] /= 3; + foveon_make_curves (curve+3, chroma_dq, div, cfilt); + FORC3 dsum += chroma_dq[c] / div[c]; + curve[6] = foveon_make_curve (dsum, dsum, cfilt); + curve[7] = foveon_make_curve (dsum*2, dsum*2, cfilt); + + sgain = (float (*)[3]) foveon_camf_matrix (dim, "SpatialGain"); + if (!sgain) return; + sgrow = (float (*)[3]) calloc (dim[1], sizeof *sgrow); + sgx = (width + dim[1]-2) / (dim[1]-1); + + black = (float (*)[3]) calloc (height, sizeof *black); + for (row=0; row < height; row++) { + for (i=0; i < 6; i++) + ddft[0][0][i] = ddft[1][0][i] + + row / (height-1.0) * (ddft[2][0][i] - ddft[1][0][i]); + FORC3 black[row][c] = + ( foveon_avg (image[row*width]+c, dscr[0], cfilt) + + foveon_avg (image[row*width]+c, dscr[1], cfilt) * 3 + - ddft[0][c][0] ) / 4 - ddft[0][c][1]; + } + memcpy (black, black+8, sizeof *black*8); + memcpy (black+height-11, black+height-22, 11*sizeof *black); + memcpy (last, black, sizeof last); + + for (row=1; row < height-1; row++) { + FORC3 if (last[1][c] > last[0][c]) { + if (last[1][c] > last[2][c]) + black[row][c] = (last[0][c] > last[2][c]) ? last[0][c]:last[2][c]; + } else + if (last[1][c] < last[2][c]) + black[row][c] = (last[0][c] < last[2][c]) ? last[0][c]:last[2][c]; + memmove (last, last+1, 2*sizeof last[0]); + memcpy (last[2], black[row+1], sizeof last[2]); + } + FORC3 black[row][c] = (last[0][c] + last[1][c])/2; + FORC3 black[0][c] = (black[1][c] + black[3][c])/2; + + val = 1 - exp(-1/24.0); + memcpy (fsum, black, sizeof fsum); + for (row=1; row < height; row++) + FORC3 fsum[c] += black[row][c] = + (black[row][c] - black[row-1][c])*val + black[row-1][c]; + memcpy (last[0], black[height-1], sizeof last[0]); + FORC3 fsum[c] /= height; + for (row = height; row--; ) + FORC3 last[0][c] = black[row][c] = + (black[row][c] - fsum[c] - last[0][c])*val + last[0][c]; + + memset (total, 0, sizeof total); + for (row=2; row < height; row+=4) + for (col=2; col < width; col+=4) { + FORC3 total[c] += (short) image[row*width+col][c]; + total[3]++; + } + for (row=0; row < height; row++) + FORC3 black[row][c] += fsum[c]/2 + total[c]/(total[3]*100.0); + + for (row=0; row < height; row++) { + for (i=0; i < 6; i++) + ddft[0][0][i] = ddft[1][0][i] + + row / (height-1.0) * (ddft[2][0][i] - ddft[1][0][i]); + pix = image[row*width]; + memcpy (prev, pix, sizeof prev); + frow = row / (height-1.0) * (dim[2]-1); + if ((irow = frow) == dim[2]-1) irow--; + frow -= irow; + for (i=0; i < dim[1]; i++) + FORC3 sgrow[i][c] = sgain[ irow *dim[1]+i][c] * (1-frow) + + sgain[(irow+1)*dim[1]+i][c] * frow; + for (col=0; col < width; col++) { + FORC3 { + diff = pix[c] - prev[c]; + prev[c] = pix[c]; + ipix[c] = pix[c] + floor ((diff + (diff*diff >> 14)) * cfilt + - ddft[0][c][1] - ddft[0][c][0] * ((float) col/width - 0.5) + - black[row][c] ); + } + FORC3 { + work[0][c] = ipix[c] * ipix[c] >> 14; + work[2][c] = ipix[c] * work[0][c] >> 14; + work[1][2-c] = ipix[(c+1) % 3] * ipix[(c+2) % 3] >> 14; + } + FORC3 { + for (val=i=0; i < 3; i++) + for ( j=0; j < 3; j++) + val += ppm[c][i][j] * work[i][j]; + ipix[c] = floor ((ipix[c] + floor(val)) * + ( sgrow[col/sgx ][c] * (sgx - col%sgx) + + sgrow[col/sgx+1][c] * (col%sgx) ) / sgx / div[c]); + if (ipix[c] > 32000) ipix[c] = 32000; + pix[c] = ipix[c]; + } + pix += 4; + } + } + free (black); + free (sgrow); + free (sgain); + + if ((badpix = (unsigned int *) foveon_camf_matrix (dim, "BadPixels"))) { + for (i=0; i < dim[0]; i++) { + col = (badpix[i] >> 8 & 0xfff) - keep[0]; + row = (badpix[i] >> 20 ) - keep[1]; + if ((unsigned)(row-1) > height-3 || (unsigned)(col-1) > width-3) + continue; + memset (fsum, 0, sizeof fsum); + for (sum=j=0; j < 8; j++) + if (badpix[i] & (1 << j)) { + FORC3 fsum[c] += (short) + image[(row+hood[j*2])*width+col+hood[j*2+1]][c]; + sum++; + } + if (sum) FORC3 image[row*width+col][c] = fsum[c]/sum; + } + free (badpix); + } + + /* Array for 5x5 Gaussian averaging of red values */ + smrow[6] = (int (*)[3]) calloc (width*5, sizeof **smrow); + merror (smrow[6], "foveon_interpolate()"); + for (i=0; i < 5; i++) + smrow[i] = smrow[6] + i*width; + + /* Sharpen the reds against these Gaussian averages */ + for (smlast=-1, row=2; row < height-2; row++) { + while (smlast < row+2) { + for (i=0; i < 6; i++) + smrow[(i+5) % 6] = smrow[i]; + pix = image[++smlast*width+2]; + for (col=2; col < width-2; col++) { + smrow[4][col][0] = + (pix[0]*6 + (pix[-4]+pix[4])*4 + pix[-8]+pix[8] + 8) >> 4; + pix += 4; + } + } + pix = image[row*width+2]; + for (col=2; col < width-2; col++) { + smred = ( 6 * smrow[2][col][0] + + 4 * (smrow[1][col][0] + smrow[3][col][0]) + + smrow[0][col][0] + smrow[4][col][0] + 8 ) >> 4; + if (col == 2) + smred_p = smred; + i = pix[0] + ((pix[0] - ((smred*7 + smred_p) >> 3)) >> 3); + if (i > 32000) i = 32000; + pix[0] = i; + smred_p = smred; + pix += 4; + } + } + + /* Adjust the brighter pixels for better linearity */ + min = 0xffff; + FORC3 { + i = satlev[c] / div[c]; + if (min > i) min = i; + } + limit = min * 9 >> 4; + for (pix=image[0]; pix < image[height*width]; pix+=4) { + if (pix[0] <= limit || pix[1] <= limit || pix[2] <= limit) + continue; + min = max = pix[0]; + for (c=1; c < 3; c++) { + if (min > pix[c]) min = pix[c]; + if (max < pix[c]) max = pix[c]; + } + if (min >= limit*2) { + pix[0] = pix[1] = pix[2] = max; + } else { + i = 0x4000 - ((min - limit) << 14) / limit; + i = 0x4000 - (i*i >> 14); + i = i*i >> 14; + FORC3 pix[c] += (max - pix[c]) * i >> 14; + } + } +/* + Because photons that miss one detector often hit another, + the sum R+G+B is much less noisy than the individual colors. + So smooth the hues without smoothing the total. + */ + for (smlast=-1, row=2; row < height-2; row++) { + while (smlast < row+2) { + for (i=0; i < 6; i++) + smrow[(i+5) % 6] = smrow[i]; + pix = image[++smlast*width+2]; + for (col=2; col < width-2; col++) { + FORC3 smrow[4][col][c] = (pix[c-4]+2*pix[c]+pix[c+4]+2) >> 2; + pix += 4; + } + } + pix = image[row*width+2]; + for (col=2; col < width-2; col++) { + FORC3 dev[c] = -foveon_apply_curve (curve[7], pix[c] - + ((smrow[1][col][c] + 2*smrow[2][col][c] + smrow[3][col][c]) >> 2)); + sum = (dev[0] + dev[1] + dev[2]) >> 3; + FORC3 pix[c] += dev[c] - sum; + pix += 4; + } + } + for (smlast=-1, row=2; row < height-2; row++) { + while (smlast < row+2) { + for (i=0; i < 6; i++) + smrow[(i+5) % 6] = smrow[i]; + pix = image[++smlast*width+2]; + for (col=2; col < width-2; col++) { + FORC3 smrow[4][col][c] = + (pix[c-8]+pix[c-4]+pix[c]+pix[c+4]+pix[c+8]+2) >> 2; + pix += 4; + } + } + pix = image[row*width+2]; + for (col=2; col < width-2; col++) { + for (total[3]=375, sum=60, c=0; c < 3; c++) { + for (total[c]=i=0; i < 5; i++) + total[c] += smrow[i][col][c]; + total[3] += total[c]; + sum += pix[c]; + } + if (sum < 0) sum = 0; + j = total[3] > 375 ? (sum << 16) / total[3] : sum * 174; + FORC3 pix[c] += foveon_apply_curve (curve[6], + ((j*total[c] + 0x8000) >> 16) - pix[c]); + pix += 4; + } + } + + /* Transform the image to a different colorspace */ + for (pix=image[0]; pix < image[height*width]; pix+=4) { + FORC3 pix[c] -= foveon_apply_curve (curve[c], pix[c]); + sum = (pix[0]+pix[1]+pix[1]+pix[2]) >> 2; + FORC3 pix[c] -= foveon_apply_curve (curve[c], pix[c]-sum); + FORC3 { + for (dsum=i=0; i < 3; i++) + dsum += trans[c][i] * pix[i]; + if (dsum < 0) dsum = 0; + if (dsum > 24000) dsum = 24000; + ipix[c] = dsum + 0.5; + } + FORC3 pix[c] = ipix[c]; + } + + /* Smooth the image bottom-to-top and save at 1/4 scale */ + shrink = (short (*)[3]) calloc ((width/4) * (height/4), sizeof *shrink); + merror (shrink, "foveon_interpolate()"); + for (row = height/4; row--; ) + for (col=0; col < width/4; col++) { + ipix[0] = ipix[1] = ipix[2] = 0; + for (i=0; i < 4; i++) + for (j=0; j < 4; j++) + FORC3 ipix[c] += image[(row*4+i)*width+col*4+j][c]; + FORC3 + if (row+2 > height/4) + shrink[row*(width/4)+col][c] = ipix[c] >> 4; + else + shrink[row*(width/4)+col][c] = + (shrink[(row+1)*(width/4)+col][c]*1840 + ipix[c]*141 + 2048) >> 12; + } + /* From the 1/4-scale image, smooth right-to-left */ + for (row=0; row < (height & ~3); row++) { + ipix[0] = ipix[1] = ipix[2] = 0; + if ((row & 3) == 0) + for (col = width & ~3 ; col--; ) + FORC3 smrow[0][col][c] = ipix[c] = + (shrink[(row/4)*(width/4)+col/4][c]*1485 + ipix[c]*6707 + 4096) >> 13; + + /* Then smooth left-to-right */ + ipix[0] = ipix[1] = ipix[2] = 0; + for (col=0; col < (width & ~3); col++) + FORC3 smrow[1][col][c] = ipix[c] = + (smrow[0][col][c]*1485 + ipix[c]*6707 + 4096) >> 13; + + /* Smooth top-to-bottom */ + if (row == 0) + memcpy (smrow[2], smrow[1], sizeof **smrow * width); + else + for (col=0; col < (width & ~3); col++) + FORC3 smrow[2][col][c] = + (smrow[2][col][c]*6707 + smrow[1][col][c]*1485 + 4096) >> 13; + + /* Adjust the chroma toward the smooth values */ + for (col=0; col < (width & ~3); col++) { + for (i=j=30, c=0; c < 3; c++) { + i += smrow[2][col][c]; + j += image[row*width+col][c]; + } + j = (j << 16) / i; + for (sum=c=0; c < 3; c++) { + ipix[c] = foveon_apply_curve (curve[c+3], + ((smrow[2][col][c] * j + 0x8000) >> 16) - image[row*width+col][c]); + sum += ipix[c]; + } + sum >>= 3; + FORC3 { + i = image[row*width+col][c] + ipix[c] - sum; + if (i < 0) i = 0; + image[row*width+col][c] = i; + } + } + } + free (shrink); + free (smrow[6]); + for (i=0; i < 8; i++) + free (curve[i]); + + /* Trim off the black border */ + active[1] -= keep[1]; + active[3] -= 2; + i = active[2] - active[0]; + for (row=0; row < active[3]-active[1]; row++) + memcpy (image[row*i], image[(row+active[1])*width+active[0]], + i * sizeof *image); + width = i; + height = row; +} +#undef image + +/* RESTRICTED code ends here */ + +/* + Seach from the current directory up to the root looking for + a ".badpixels" file, and fix those pixels now. + */ +void CLASS bad_pixels (const char *cfname) +{ + FILE *fp=0; + char *fname, *cp, line[128]; + int len, time, row, col, r, c, rad, tot, n, fixed=0; + + if (!filters) return; + if (cfname) + fp = fopen (cfname, "r"); + else { + for (len=32 ; ; len *= 2) { + fname = (char *) malloc (len); + if (!fname) return; + if (getcwd (fname, len-16)) break; + free (fname); + if (errno != ERANGE) return; + } +#if defined(WIN32) || defined(DJGPP) + if (fname[1] == ':') + memmove (fname, fname+2, len-2); + for (cp=fname; *cp; cp++) + if (*cp == '\\') *cp = '/'; +#endif + cp = fname + strlen(fname); + if (cp[-1] == '/') cp--; + while (*fname == '/') { + strcpy (cp, "/.badpixels"); + if ((fp = fopen (fname, "r"))) break; + if (cp == fname) break; + while (*--cp != '/'); + } + free (fname); + } + if (!fp) return; + while (fgets (line, 128, fp)) { + cp = strchr (line, '#'); + if (cp) *cp = 0; + if (sscanf (line, "%d %d %d", &col, &row, &time) != 3) continue; + if ((unsigned) col >= width || (unsigned) row >= height) continue; + if (time > timestamp) continue; + for (tot=n=0, rad=1; rad < 3 && n==0; rad++) + for (r = row-rad; r <= row+rad; r++) + for (c = col-rad; c <= col+rad; c++) + if ((unsigned) r < height && (unsigned) c < width && + (r != row || c != col) && fc(r,c) == fc(row,col)) { + tot += BAYER2(r,c); + n++; + } + BAYER2(row,col) = tot/n; + if (verbose) { + if (!fixed++) + fprintf (stderr,_("Fixed dead pixels at:")); + fprintf (stderr, " %d,%d", col, row); + } + } + if (fixed) fputc ('\n', stderr); + fclose (fp); +} + +void CLASS subtract (const char *fname) +{ + FILE *fp; + int dim[3]={0,0,0}, comment=0, number=0, error=0, nd=0, c, row, col; + ushort *pixel; + + if (!(fp = fopen (fname, "rb"))) { + perror (fname); return; + } + if (fgetc(fp) != 'P' || fgetc(fp) != '5') error = 1; + while (!error && nd < 3 && (c = fgetc(fp)) != EOF) { + if (c == '#') comment = 1; + if (c == '\n') comment = 0; + if (comment) continue; + if (isdigit(c)) number = 1; + if (number) { + if (isdigit(c)) dim[nd] = dim[nd]*10 + c -'0'; + else if (isspace(c)) { + number = 0; nd++; + } else error = 1; + } + } + if (error || nd < 3) { + fprintf (stderr,_("%s is not a valid PGM file!\n"), fname); + fclose (fp); return; + } else if (dim[0] != width || dim[1] != height || dim[2] != 65535) { + fprintf (stderr,_("%s has the wrong dimensions!\n"), fname); + fclose (fp); return; + } + pixel = (ushort *) calloc (width, sizeof *pixel); + merror (pixel, "subtract()"); + for (row=0; row < height; row++) { + fread (pixel, 2, width, fp); + for (col=0; col < width; col++) + BAYER(row,col) = MAX (BAYER(row,col) - ntohs(pixel[col]), 0); + } + free (pixel); + black = 0; +} + +void CLASS gamma_curve (double pwr, double ts, int mode, int imax) +{ + int i; + double g[6], bnd[2]={0,0}, r; + + g[0] = pwr; + g[1] = ts; + g[2] = g[3] = g[4] = 0; + bnd[g[1] >= 1] = 1; + if (g[1] && (g[1]-1)*(g[0]-1) <= 0) { + for (i=0; i < 48; i++) { + g[2] = (bnd[0] + bnd[1])/2; + if (g[0]) bnd[(pow(g[2]/g[1],-g[0]) - 1)/g[0] - 1/g[2] > -1] = g[2]; + else bnd[g[2]/exp(1-1/g[2]) < g[1]] = g[2]; + } + g[3] = g[2] / g[1]; + if (g[0]) g[4] = g[2] * (1/g[0] - 1); + } + if (g[0]) g[5] = 1 / (g[1]*SQR(g[3])/2 - g[4]*(1 - g[3]) + + (1 - pow(g[3],1+g[0]))*(1 + g[4])/(1 + g[0])) - 1; + else g[5] = 1 / (g[1]*SQR(g[3])/2 + 1 + - g[2] - g[3] - g[2]*g[3]*(log(g[3]) - 1)) - 1; + if (!mode--) { + memcpy (gamm, g, sizeof gamm); + return; + } + for (i=0; i < 0x10000; i++) { + curve[i] = 0xffff; + if ((r = (double) i / imax) < 1) + curve[i] = 0x10000 * ( mode + ? (r < g[3] ? r*g[1] : (g[0] ? pow( r,g[0])*(1+g[4])-g[4] : log(r)*g[2]+1)) + : (r < g[2] ? r/g[1] : (g[0] ? pow((r+g[4])/(1+g[4]),1/g[0]) : exp((r-1)/g[2])))); + } +} + +void CLASS pseudoinverse (double (*in)[3], double (*out)[3], int size) +{ + double work[3][6], num; + int i, j, k; + + for (i=0; i < 3; i++) { + for (j=0; j < 6; j++) + work[i][j] = j == i+3; + for (j=0; j < 3; j++) + for (k=0; k < size; k++) + work[i][j] += in[k][i] * in[k][j]; + } + for (i=0; i < 3; i++) { + num = work[i][i]; + for (j=0; j < 6; j++) + work[i][j] /= num; + for (k=0; k < 3; k++) { + if (k==i) continue; + num = work[k][i]; + for (j=0; j < 6; j++) + work[k][j] -= work[i][j] * num; + } + } + for (i=0; i < size; i++) + for (j=0; j < 3; j++) + for (out[i][j]=k=0; k < 3; k++) + out[i][j] += work[j][k+3] * in[i][k]; +} + +void CLASS cam_xyz_coeff (double cam_xyz[4][3]) +{ + double cam_rgb[4][3], inverse[4][3], num; + int i, j, k; + + for (i=0; i < colors; i++) /* Multiply out XYZ colorspace */ + for (j=0; j < 3; j++) + for (cam_rgb[i][j] = k=0; k < 3; k++) + cam_rgb[i][j] += cam_xyz[i][k] * xyz_rgb[k][j]; + + for (i=0; i < colors; i++) { /* Normalize cam_rgb so that */ + for (num=j=0; j < 3; j++) /* cam_rgb * (1,1,1) is (1,1,1,1) */ + num += cam_rgb[i][j]; + for (j=0; j < 3; j++) + cam_rgb[i][j] /= num; + pre_mul[i] = 1 / num; + } + pseudoinverse (cam_rgb, inverse, colors); + for (raw_color = i=0; i < 3; i++) + for (j=0; j < colors; j++) + rgb_cam[i][j] = inverse[j][i]; +} + +#ifdef COLORCHECK +void CLASS colorcheck() +{ +#define NSQ 24 +// Coordinates of the GretagMacbeth ColorChecker squares +// width, height, 1st_column, 1st_row + int cut[NSQ][4]; // you must set these +// ColorChecker Chart under 6500-kelvin illumination + static const double gmb_xyY[NSQ][3] = { + { 0.400, 0.350, 10.1 }, // Dark Skin + { 0.377, 0.345, 35.8 }, // Light Skin + { 0.247, 0.251, 19.3 }, // Blue Sky + { 0.337, 0.422, 13.3 }, // Foliage + { 0.265, 0.240, 24.3 }, // Blue Flower + { 0.261, 0.343, 43.1 }, // Bluish Green + { 0.506, 0.407, 30.1 }, // Orange + { 0.211, 0.175, 12.0 }, // Purplish Blue + { 0.453, 0.306, 19.8 }, // Moderate Red + { 0.285, 0.202, 6.6 }, // Purple + { 0.380, 0.489, 44.3 }, // Yellow Green + { 0.473, 0.438, 43.1 }, // Orange Yellow + { 0.187, 0.129, 6.1 }, // Blue + { 0.305, 0.478, 23.4 }, // Green + { 0.539, 0.313, 12.0 }, // Red + { 0.448, 0.470, 59.1 }, // Yellow + { 0.364, 0.233, 19.8 }, // Magenta + { 0.196, 0.252, 19.8 }, // Cyan + { 0.310, 0.316, 90.0 }, // White + { 0.310, 0.316, 59.1 }, // Neutral 8 + { 0.310, 0.316, 36.2 }, // Neutral 6.5 + { 0.310, 0.316, 19.8 }, // Neutral 5 + { 0.310, 0.316, 9.0 }, // Neutral 3.5 + { 0.310, 0.316, 3.1 } }; // Black + double gmb_cam[NSQ][4], gmb_xyz[NSQ][3]; + double inverse[NSQ][3], cam_xyz[4][3], num; + int c, i, j, k, sq, row, col, count[4]; + + memset (gmb_cam, 0, sizeof gmb_cam); + for (sq=0; sq < NSQ; sq++) { + FORCC count[c] = 0; + for (row=cut[sq][3]; row < cut[sq][3]+cut[sq][1]; row++) + for (col=cut[sq][2]; col < cut[sq][2]+cut[sq][0]; col++) { + c = FC(row,col); + if (c >= colors) c -= 2; + gmb_cam[sq][c] += BAYER(row,col); + count[c]++; + } + FORCC gmb_cam[sq][c] = gmb_cam[sq][c]/count[c] - black; + gmb_xyz[sq][0] = gmb_xyY[sq][2] * gmb_xyY[sq][0] / gmb_xyY[sq][1]; + gmb_xyz[sq][1] = gmb_xyY[sq][2]; + gmb_xyz[sq][2] = gmb_xyY[sq][2] * + (1 - gmb_xyY[sq][0] - gmb_xyY[sq][1]) / gmb_xyY[sq][1]; + } + pseudoinverse (gmb_xyz, inverse, NSQ); + for (i=0; i < colors; i++) + for (j=0; j < 3; j++) + for (cam_xyz[i][j] = k=0; k < NSQ; k++) + cam_xyz[i][j] += gmb_cam[k][i] * inverse[k][j]; + cam_xyz_coeff (cam_xyz); + if (verbose) { + printf (" { \"%s %s\", %d,\n\t{", make, model, black); + num = 10000 / (cam_xyz[1][0] + cam_xyz[1][1] + cam_xyz[1][2]); + FORCC for (j=0; j < 3; j++) + printf ("%c%d", (c | j) ? ',':' ', (int) (cam_xyz[c][j] * num + 0.5)); + puts (" } },"); + } +#undef NSQ +} +#endif + +void CLASS hat_transform (float *temp, float *base, int st, int size, int sc) +{ + int i; + for (i=0; i < sc; i++) + temp[i] = 2*base[st*i] + base[st*(sc-i)] + base[st*(i+sc)]; + for (; i+sc < size; i++) + temp[i] = 2*base[st*i] + base[st*(i-sc)] + base[st*(i+sc)]; + for (; i < size; i++) + temp[i] = 2*base[st*i] + base[st*(i-sc)] + base[st*(2*size-2-(i+sc))]; +} + +void CLASS wavelet_denoise() +{ + float *fimg=0, *temp, thold, mul[2], avg, diff; + int scale=1, size, lev, hpass, lpass, row, col, nc, c, i, wlast; + ushort *window[4]; + static const float noise[] = + { 0.8002,0.2735,0.1202,0.0585,0.0291,0.0152,0.0080,0.0044 }; + + if (verbose) fprintf (stderr,_("Wavelet denoising...\n")); + + while (maximum << scale < 0x10000) scale++; + maximum <<= --scale; + black <<= scale; + if ((size = iheight*iwidth) < 0x15550000) + fimg = (float *) malloc ((size*3 + iheight + iwidth) * sizeof *fimg); + merror (fimg, "wavelet_denoise()"); + temp = fimg + size*3; + if ((nc = colors) == 3 && filters) nc++; + FORC(nc) { /* denoise R,G1,B,G3 individually */ + for (i=0; i < size; i++) + fimg[i] = 256 * sqrt(image[i][c] << scale); + for (hpass=lev=0; lev < 5; lev++) { + lpass = size*((lev & 1)+1); + for (row=0; row < iheight; row++) { + hat_transform (temp, fimg+hpass+row*iwidth, 1, iwidth, 1 << lev); + for (col=0; col < iwidth; col++) + fimg[lpass + row*iwidth + col] = temp[col] * 0.25; + } + for (col=0; col < iwidth; col++) { + hat_transform (temp, fimg+lpass+col, iwidth, iheight, 1 << lev); + for (row=0; row < iheight; row++) + fimg[lpass + row*iwidth + col] = temp[row] * 0.25; + } + thold = threshold * noise[lev]; + for (i=0; i < size; i++) { + fimg[hpass+i] -= fimg[lpass+i]; + if (fimg[hpass+i] < -thold) fimg[hpass+i] += thold; + else if (fimg[hpass+i] > thold) fimg[hpass+i] -= thold; + else fimg[hpass+i] = 0; + if (hpass) fimg[i] += fimg[hpass+i]; + } + hpass = lpass; + } + for (i=0; i < size; i++) + image[i][c] = CLIP(SQR(fimg[i]+fimg[lpass+i])/0x10000); + } + if (filters && colors == 3) { /* pull G1 and G3 closer together */ + for (row=0; row < 2; row++) + mul[row] = 0.125 * pre_mul[FC(row+1,0) | 1] / pre_mul[FC(row,0) | 1]; + for (i=0; i < 4; i++) + window[i] = (ushort *) fimg + width*i; + for (wlast=-1, row=1; row < height-1; row++) { + while (wlast < row+1) { + for (wlast++, i=0; i < 4; i++) + window[(i+3) & 3] = window[i]; + for (col = FC(wlast,1) & 1; col < width; col+=2) + window[2][col] = BAYER(wlast,col); + } + thold = threshold/512; + for (col = (FC(row,0) & 1)+1; col < width-1; col+=2) { + avg = ( window[0][col-1] + window[0][col+1] + + window[2][col-1] + window[2][col+1] - black*4 ) + * mul[row & 1] + (window[1][col] - black) * 0.5 + black; + avg = avg < 0 ? 0 : sqrt(avg); + diff = sqrt(BAYER(row,col)) - avg; + if (diff < -thold) diff += thold; + else if (diff > thold) diff -= thold; + else diff = 0; + BAYER(row,col) = CLIP(SQR(avg+diff) + 0.5); + } + } + } + free (fimg); +} + +void CLASS scale_colors() +{ + unsigned bottom, right, size, row, col, ur, uc, i, x, y, c, sum[8]; + int val, dark, sat; + double dsum[8], dmin, dmax; + float scale_mul[4], fr, fc; + ushort *img=0, *pix; + + if (user_mul[0]) + memcpy (pre_mul, user_mul, sizeof pre_mul); + if (use_auto_wb || (use_camera_wb && cam_mul[0] == -1)) { + memset (dsum, 0, sizeof dsum); + bottom = MIN (greybox[1]+greybox[3], height); + right = MIN (greybox[0]+greybox[2], width); + for (row=greybox[1]; row < bottom; row += 8) + for (col=greybox[0]; col < right; col += 8) { + memset (sum, 0, sizeof sum); + for (y=row; y < row+8 && y < bottom; y++) + for (x=col; x < col+8 && x < right; x++) + FORC4 { + if (filters) { + c = FC(y,x); + val = BAYER(y,x); + } else + val = image[y*width+x][c]; + if (val > maximum-25) goto skip_block; + if ((val -= black) < 0) val = 0; + sum[c] += val; + sum[c+4]++; + if (filters) break; + } + FORC(8) dsum[c] += sum[c]; +skip_block: ; + } + FORC4 if (dsum[c]) pre_mul[c] = dsum[c+4] / dsum[c]; + } + if (use_camera_wb && cam_mul[0] != -1) { + memset (sum, 0, sizeof sum); + for (row=0; row < 8; row++) + for (col=0; col < 8; col++) { + c = FC(row,col); + if ((val = white[row][col] - black) > 0) + sum[c] += val; + sum[c+4]++; + } + if (sum[0] && sum[1] && sum[2] && sum[3]) + FORC4 pre_mul[c] = (float) sum[c+4] / sum[c]; + else if (cam_mul[0] && cam_mul[2]) + memcpy (pre_mul, cam_mul, sizeof pre_mul); + else + fprintf (stderr,_("%s: Cannot use camera white balance.\n"), ifname); + } + if (pre_mul[3] == 0) pre_mul[3] = colors < 4 ? pre_mul[1] : 1; + dark = black; + sat = maximum; + if (threshold) wavelet_denoise(); + maximum -= black; + for (dmin=DBL_MAX, dmax=c=0; c < 4; c++) { + if (dmin > pre_mul[c]) + dmin = pre_mul[c]; + if (dmax < pre_mul[c]) + dmax = pre_mul[c]; + } + if (!highlight) dmax = dmin; + FORC4 scale_mul[c] = (pre_mul[c] /= dmax) * 65535.0 / maximum; + if (verbose) { + fprintf (stderr, + _("Scaling with darkness %d, saturation %d, and\nmultipliers"), dark, sat); + FORC4 fprintf (stderr, " %f", pre_mul[c]); + fputc ('\n', stderr); + } + size = iheight*iwidth; + for (i=0; i < size*4; i++) { + val = image[0][i]; + if (!val) continue; + val -= black; + val *= scale_mul[i & 3]; + image[0][i] = CLIP(val); + } + if ((aber[0] != 1 || aber[2] != 1) && colors == 3) { + if (verbose) + fprintf (stderr,_("Correcting chromatic aberration...\n")); + for (c=0; c < 4; c+=2) { + if (aber[c] == 1) continue; + img = (ushort *) malloc (size * sizeof *img); + merror (img, "scale_colors()"); + for (i=0; i < size; i++) + img[i] = image[i][c]; + for (row=0; row < iheight; row++) { + ur = fr = (row - iheight*0.5) * aber[c] + iheight*0.5; + if (ur > iheight-2) continue; + fr -= ur; + for (col=0; col < iwidth; col++) { + uc = fc = (col - iwidth*0.5) * aber[c] + iwidth*0.5; + if (uc > iwidth-2) continue; + fc -= uc; + pix = img + ur*iwidth + uc; + image[row*iwidth+col][c] = + (pix[ 0]*(1-fc) + pix[ 1]*fc) * (1-fr) + + (pix[iwidth]*(1-fc) + pix[iwidth+1]*fc) * fr; + } + } + free(img); + } + } +} + +void CLASS pre_interpolate() +{ + ushort (*img)[4]; + int row, col, c; + + if (shrink) { + if (half_size) { + height = iheight; + width = iwidth; + } else { + img = (ushort (*)[4]) calloc (height*width, sizeof *img); + merror (img, "pre_interpolate()"); + for (row=0; row < height; row++) + for (col=0; col < width; col++) { + c = fc(row,col); + img[row*width+col][c] = image[(row >> 1)*iwidth+(col >> 1)][c]; + } + free (image); + image = img; + shrink = 0; + } + } + if (filters && colors == 3) { + if ((mix_green = four_color_rgb)) colors++; + else { + for (row = FC(1,0) >> 1; row < height; row+=2) + for (col = FC(row,1) & 1; col < width; col+=2) + image[row*width+col][1] = image[row*width+col][3]; + filters &= ~((filters & 0x55555555) << 1); + } + } + if (half_size) filters = 0; +} + +void CLASS border_interpolate (int border) +{ + unsigned row, col, y, x, f, c, sum[8]; + + for (row=0; row < height; row++) + for (col=0; col < width; col++) { + if (col==border && row >= border && row < height-border) + col = width-border; + memset (sum, 0, sizeof sum); + for (y=row-1; y != row+2; y++) + for (x=col-1; x != col+2; x++) + if (y < height && x < width) { + f = fc(y,x); + sum[f] += image[y*width+x][f]; + sum[f+4]++; + } + f = fc(row,col); + FORCC if (c != f && sum[c+4]) + image[row*width+col][c] = sum[c] / sum[c+4]; + } +} + +void CLASS lin_interpolate() +{ + int code[16][16][32], *ip, sum[4]; + int c, i, x, y, row, col, shift, color; + ushort *pix; + + if (verbose) fprintf (stderr,_("Bilinear interpolation...\n")); + + border_interpolate(1); + for (row=0; row < 16; row++) + for (col=0; col < 16; col++) { + ip = code[row][col]; + memset (sum, 0, sizeof sum); + for (y=-1; y <= 1; y++) + for (x=-1; x <= 1; x++) { + shift = (y==0) + (x==0); + if (shift == 2) continue; + color = fc(row+y,col+x); + *ip++ = (width*y + x)*4 + color; + *ip++ = shift; + *ip++ = color; + sum[color] += 1 << shift; + } + FORCC + if (c != fc(row,col)) { + *ip++ = c; + *ip++ = 256 / sum[c]; + } + } + for (row=1; row < height-1; row++) + for (col=1; col < width-1; col++) { + pix = image[row*width+col]; + ip = code[row & 15][col & 15]; + memset (sum, 0, sizeof sum); + for (i=8; i--; ip+=3) + sum[ip[2]] += pix[ip[0]] << ip[1]; + for (i=colors; --i; ip+=2) + pix[ip[0]] = sum[ip[0]] * ip[1] >> 8; + } +} + +/* + This algorithm is officially called: + + "Interpolation using a Threshold-based variable number of gradients" + + described in http://scien.stanford.edu/class/psych221/projects/99/tingchen/algodep/vargra.html + + I've extended the basic idea to work with non-Bayer filter arrays. + Gradients are numbered clockwise from NW=0 to W=7. + */ +void CLASS vng_interpolate() +{ + static const signed char *cp, terms[] = { + -2,-2,+0,-1,0,0x01, -2,-2,+0,+0,1,0x01, -2,-1,-1,+0,0,0x01, + -2,-1,+0,-1,0,0x02, -2,-1,+0,+0,0,0x03, -2,-1,+0,+1,1,0x01, + -2,+0,+0,-1,0,0x06, -2,+0,+0,+0,1,0x02, -2,+0,+0,+1,0,0x03, + -2,+1,-1,+0,0,0x04, -2,+1,+0,-1,1,0x04, -2,+1,+0,+0,0,0x06, + -2,+1,+0,+1,0,0x02, -2,+2,+0,+0,1,0x04, -2,+2,+0,+1,0,0x04, + -1,-2,-1,+0,0,0x80, -1,-2,+0,-1,0,0x01, -1,-2,+1,-1,0,0x01, + -1,-2,+1,+0,1,0x01, -1,-1,-1,+1,0,0x88, -1,-1,+1,-2,0,0x40, + -1,-1,+1,-1,0,0x22, -1,-1,+1,+0,0,0x33, -1,-1,+1,+1,1,0x11, + -1,+0,-1,+2,0,0x08, -1,+0,+0,-1,0,0x44, -1,+0,+0,+1,0,0x11, + -1,+0,+1,-2,1,0x40, -1,+0,+1,-1,0,0x66, -1,+0,+1,+0,1,0x22, + -1,+0,+1,+1,0,0x33, -1,+0,+1,+2,1,0x10, -1,+1,+1,-1,1,0x44, + -1,+1,+1,+0,0,0x66, -1,+1,+1,+1,0,0x22, -1,+1,+1,+2,0,0x10, + -1,+2,+0,+1,0,0x04, -1,+2,+1,+0,1,0x04, -1,+2,+1,+1,0,0x04, + +0,-2,+0,+0,1,0x80, +0,-1,+0,+1,1,0x88, +0,-1,+1,-2,0,0x40, + +0,-1,+1,+0,0,0x11, +0,-1,+2,-2,0,0x40, +0,-1,+2,-1,0,0x20, + +0,-1,+2,+0,0,0x30, +0,-1,+2,+1,1,0x10, +0,+0,+0,+2,1,0x08, + +0,+0,+2,-2,1,0x40, +0,+0,+2,-1,0,0x60, +0,+0,+2,+0,1,0x20, + +0,+0,+2,+1,0,0x30, +0,+0,+2,+2,1,0x10, +0,+1,+1,+0,0,0x44, + +0,+1,+1,+2,0,0x10, +0,+1,+2,-1,1,0x40, +0,+1,+2,+0,0,0x60, + +0,+1,+2,+1,0,0x20, +0,+1,+2,+2,0,0x10, +1,-2,+1,+0,0,0x80, + +1,-1,+1,+1,0,0x88, +1,+0,+1,+2,0,0x08, +1,+0,+2,-1,0,0x40, + +1,+0,+2,+1,0,0x10 + }, chood[] = { -1,-1, -1,0, -1,+1, 0,+1, +1,+1, +1,0, +1,-1, 0,-1 }; + ushort (*brow[5])[4], *pix; + int prow=7, pcol=1, *ip, *code[16][16], gval[8], gmin, gmax, sum[4]; + int row, col, x, y, x1, x2, y1, y2, t, weight, grads, color, diag; + int g, diff, thold, num, c; + + lin_interpolate(); + if (verbose) fprintf (stderr,_("VNG interpolation...\n")); + + if (filters == 1) prow = pcol = 15; + ip = (int *) calloc ((prow+1)*(pcol+1), 1280); + merror (ip, "vng_interpolate()"); + for (row=0; row <= prow; row++) /* Precalculate for VNG */ + for (col=0; col <= pcol; col++) { + code[row][col] = ip; + for (cp=terms, t=0; t < 64; t++) { + y1 = *cp++; x1 = *cp++; + y2 = *cp++; x2 = *cp++; + weight = *cp++; + grads = *cp++; + color = fc(row+y1,col+x1); + if (fc(row+y2,col+x2) != color) continue; + diag = (fc(row,col+1) == color && fc(row+1,col) == color) ? 2:1; + if (abs(y1-y2) == diag && abs(x1-x2) == diag) continue; + *ip++ = (y1*width + x1)*4 + color; + *ip++ = (y2*width + x2)*4 + color; + *ip++ = weight; + for (g=0; g < 8; g++) + if (grads & 1< gval[g]) gmin = gval[g]; + if (gmax < gval[g]) gmax = gval[g]; + } + if (gmax == 0) { + memcpy (brow[2][col], pix, sizeof *image); + continue; + } + thold = gmin + (gmax >> 1); + memset (sum, 0, sizeof sum); + color = fc(row,col); + for (num=g=0; g < 8; g++,ip+=2) { /* Average the neighbors */ + if (gval[g] <= thold) { + FORCC + if (c == color && ip[1]) + sum[c] += (pix[c] + pix[ip[1]]) >> 1; + else + sum[c] += pix[ip[0] + c]; + num++; + } + } + FORCC { /* Save to buffer */ + t = pix[color]; + if (c != color) + t += (sum[c] - sum[color]) / num; + brow[2][col][c] = CLIP(t); + } + } + if (row > 3) /* Write buffer to image */ + memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image); + for (g=0; g < 4; g++) + brow[(g-1) & 3] = brow[g]; + } + memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image); + memcpy (image[(row-1)*width+2], brow[1]+2, (width-4)*sizeof *image); + free (brow[4]); + free (code[0][0]); +} + +/* + Patterned Pixel Grouping Interpolation by Alain Desbiolles +*/ +void CLASS ppg_interpolate() +{ + int dir[5] = { 1, width, -1, -width, 1 }; + int row, col, diff[2], guess[2], c, d, i; + ushort (*pix)[4]; + + border_interpolate(3); + if (verbose) fprintf (stderr,_("PPG interpolation...\n")); + +/* Fill in the green layer with gradients and pattern recognition: */ + for (row=3; row < height-3; row++) + for (col=3+(FC(row,3) & 1), c=FC(row,col); col < width-3; col+=2) { + pix = image + row*width+col; + for (i=0; (d=dir[i]) > 0; i++) { + guess[i] = (pix[-d][1] + pix[0][c] + pix[d][1]) * 2 + - pix[-2*d][c] - pix[2*d][c]; + diff[i] = ( ABS(pix[-2*d][c] - pix[ 0][c]) + + ABS(pix[ 2*d][c] - pix[ 0][c]) + + ABS(pix[ -d][1] - pix[ d][1]) ) * 3 + + ( ABS(pix[ 3*d][1] - pix[ d][1]) + + ABS(pix[-3*d][1] - pix[-d][1]) ) * 2; + } + d = dir[i = diff[0] > diff[1]]; + pix[0][1] = ULIM(guess[i] >> 2, pix[d][1], pix[-d][1]); + } +/* Calculate red and blue for each green pixel: */ + for (row=1; row < height-1; row++) + for (col=1+(FC(row,2) & 1), c=FC(row,col+1); col < width-1; col+=2) { + pix = image + row*width+col; + for (i=0; (d=dir[i]) > 0; c=2-c, i++) + pix[0][c] = CLIP((pix[-d][c] + pix[d][c] + 2*pix[0][1] + - pix[-d][1] - pix[d][1]) >> 1); + } +/* Calculate blue for red pixels and vice versa: */ + for (row=1; row < height-1; row++) + for (col=1+(FC(row,1) & 1), c=2-FC(row,col); col < width-1; col+=2) { + pix = image + row*width+col; + for (i=0; (d=dir[i]+dir[i+1]) > 0; i++) { + diff[i] = ABS(pix[-d][c] - pix[d][c]) + + ABS(pix[-d][1] - pix[0][1]) + + ABS(pix[ d][1] - pix[0][1]); + guess[i] = pix[-d][c] + pix[d][c] + 2*pix[0][1] + - pix[-d][1] - pix[d][1]; + } + if (diff[0] != diff[1]) + pix[0][c] = CLIP(guess[diff[0] > diff[1]] >> 1); + else + pix[0][c] = CLIP((guess[0]+guess[1]) >> 2); + } +} + +/* + Adaptive Homogeneity-Directed interpolation is based on + the work of Keigo Hirakawa, Thomas Parks, and Paul Lee. + */ +#define TS 256 /* Tile Size */ + +void CLASS ahd_interpolate() +{ + int i, j, k, top, left, row, col, tr, tc, c, d, val, hm[2]; + ushort (*pix)[4], (*rix)[3]; + static const int dir[4] = { -1, 1, -TS, TS }; + unsigned ldiff[2][4], abdiff[2][4], leps, abeps; + float r, cbrt[0x10000], xyz[3], xyz_cam[3][4]; + ushort (*rgb)[TS][TS][3]; + short (*lab)[TS][TS][3], (*lix)[3]; + char (*homo)[TS][TS], *buffer; + + if (verbose) fprintf (stderr,_("AHD interpolation...\n")); + + for (i=0; i < 0x10000; i++) { + r = i / 65535.0; + cbrt[i] = r > 0.008856 ? pow(r,1/3.0) : 7.787*r + 16/116.0; + } + for (i=0; i < 3; i++) + for (j=0; j < colors; j++) + for (xyz_cam[i][j] = k=0; k < 3; k++) + xyz_cam[i][j] += xyz_rgb[i][k] * rgb_cam[k][j] / d65_white[i]; + + border_interpolate(5); + buffer = (char *) malloc (26*TS*TS); /* 1664 kB */ + merror (buffer, "ahd_interpolate()"); + rgb = (ushort(*)[TS][TS][3]) buffer; + lab = (short (*)[TS][TS][3])(buffer + 12*TS*TS); + homo = (char (*)[TS][TS]) (buffer + 24*TS*TS); + + for (top=2; top < height-5; top += TS-6) + for (left=2; left < width-5; left += TS-6) { + +/* Interpolate green horizontally and vertically: */ + for (row = top; row < top+TS && row < height-2; row++) { + col = left + (FC(row,left) & 1); + for (c = FC(row,col); col < left+TS && col < width-2; col+=2) { + pix = image + row*width+col; + val = ((pix[-1][1] + pix[0][c] + pix[1][1]) * 2 + - pix[-2][c] - pix[2][c]) >> 2; + rgb[0][row-top][col-left][1] = ULIM(val,pix[-1][1],pix[1][1]); + val = ((pix[-width][1] + pix[0][c] + pix[width][1]) * 2 + - pix[-2*width][c] - pix[2*width][c]) >> 2; + rgb[1][row-top][col-left][1] = ULIM(val,pix[-width][1],pix[width][1]); + } + } +/* Interpolate red and blue, and convert to CIELab: */ + for (d=0; d < 2; d++) + for (row=top+1; row < top+TS-1 && row < height-3; row++) + for (col=left+1; col < left+TS-1 && col < width-3; col++) { + pix = image + row*width+col; + rix = &rgb[d][row-top][col-left]; + lix = &lab[d][row-top][col-left]; + if ((c = 2 - FC(row,col)) == 1) { + c = FC(row+1,col); + val = pix[0][1] + (( pix[-1][2-c] + pix[1][2-c] + - rix[-1][1] - rix[1][1] ) >> 1); + rix[0][2-c] = CLIP(val); + val = pix[0][1] + (( pix[-width][c] + pix[width][c] + - rix[-TS][1] - rix[TS][1] ) >> 1); + } else + val = rix[0][1] + (( pix[-width-1][c] + pix[-width+1][c] + + pix[+width-1][c] + pix[+width+1][c] + - rix[-TS-1][1] - rix[-TS+1][1] + - rix[+TS-1][1] - rix[+TS+1][1] + 1) >> 2); + rix[0][c] = CLIP(val); + c = FC(row,col); + rix[0][c] = pix[0][c]; + xyz[0] = xyz[1] = xyz[2] = 0.5; + FORCC { + xyz[0] += xyz_cam[0][c] * rix[0][c]; + xyz[1] += xyz_cam[1][c] * rix[0][c]; + xyz[2] += xyz_cam[2][c] * rix[0][c]; + } + xyz[0] = cbrt[CLIP((int) xyz[0])]; + xyz[1] = cbrt[CLIP((int) xyz[1])]; + xyz[2] = cbrt[CLIP((int) xyz[2])]; + lix[0][0] = 64 * (116 * xyz[1] - 16); + lix[0][1] = 64 * 500 * (xyz[0] - xyz[1]); + lix[0][2] = 64 * 200 * (xyz[1] - xyz[2]); + } +/* Build homogeneity maps from the CIELab images: */ + memset (homo, 0, 2*TS*TS); + for (row=top+2; row < top+TS-2 && row < height-4; row++) { + tr = row-top; + for (col=left+2; col < left+TS-2 && col < width-4; col++) { + tc = col-left; + for (d=0; d < 2; d++) { + lix = &lab[d][tr][tc]; + for (i=0; i < 4; i++) { + ldiff[d][i] = ABS(lix[0][0]-lix[dir[i]][0]); + abdiff[d][i] = SQR(lix[0][1]-lix[dir[i]][1]) + + SQR(lix[0][2]-lix[dir[i]][2]); + } + } + leps = MIN(MAX(ldiff[0][0],ldiff[0][1]), + MAX(ldiff[1][2],ldiff[1][3])); + abeps = MIN(MAX(abdiff[0][0],abdiff[0][1]), + MAX(abdiff[1][2],abdiff[1][3])); + for (d=0; d < 2; d++) + for (i=0; i < 4; i++) + if (ldiff[d][i] <= leps && abdiff[d][i] <= abeps) + homo[d][tr][tc]++; + } + } +/* Combine the most homogenous pixels for the final result: */ + for (row=top+3; row < top+TS-3 && row < height-5; row++) { + tr = row-top; + for (col=left+3; col < left+TS-3 && col < width-5; col++) { + tc = col-left; + for (d=0; d < 2; d++) + for (hm[d]=0, i=tr-1; i <= tr+1; i++) + for (j=tc-1; j <= tc+1; j++) + hm[d] += homo[d][i][j]; + if (hm[0] != hm[1]) + FORC3 image[row*width+col][c] = rgb[hm[1] > hm[0]][tr][tc][c]; + else + FORC3 image[row*width+col][c] = + (rgb[0][tr][tc][c] + rgb[1][tr][tc][c]) >> 1; + } + } + } + free (buffer); +} +#undef TS + +void CLASS median_filter() +{ + ushort (*pix)[4]; + int pass, c, i, j, k, med[9]; + static const uchar opt[] = /* Optimal 9-element median search */ + { 1,2, 4,5, 7,8, 0,1, 3,4, 6,7, 1,2, 4,5, 7,8, + 0,3, 5,8, 4,7, 3,6, 1,4, 2,5, 4,7, 4,2, 6,4, 4,2 }; + + for (pass=1; pass <= med_passes; pass++) { + if (verbose) + fprintf (stderr,_("Median filter pass %d...\n"), pass); + for (c=0; c < 3; c+=2) { + for (pix = image; pix < image+width*height; pix++) + pix[0][3] = pix[0][c]; + for (pix = image+width; pix < image+width*(height-1); pix++) { + if ((pix-image+1) % width < 2) continue; + for (k=0, i = -width; i <= width; i += width) + for (j = i-1; j <= i+1; j++) + med[k++] = pix[j][3] - pix[j][1]; + for (i=0; i < sizeof opt; i+=2) + if (med[opt[i]] > med[opt[i+1]]) + SWAP (med[opt[i]] , med[opt[i+1]]); + pix[0][c] = CLIP(med[4] + pix[0][1]); + } + } + } +} + +void CLASS blend_highlights() +{ + int clip=INT_MAX, row, col, c, i, j; + static const float trans[2][4][4] = + { { { 1,1,1 }, { 1.7320508,-1.7320508,0 }, { -1,-1,2 } }, + { { 1,1,1,1 }, { 1,-1,1,-1 }, { 1,1,-1,-1 }, { 1,-1,-1,1 } } }; + static const float itrans[2][4][4] = + { { { 1,0.8660254,-0.5 }, { 1,-0.8660254,-0.5 }, { 1,0,1 } }, + { { 1,1,1,1 }, { 1,-1,1,-1 }, { 1,1,-1,-1 }, { 1,-1,-1,1 } } }; + float cam[2][4], lab[2][4], sum[2], chratio; + + if ((unsigned) (colors-3) > 1) return; + if (verbose) fprintf (stderr,_("Blending highlights...\n")); + FORCC if (clip > (i = 65535*pre_mul[c])) clip = i; + for (row=0; row < height; row++) + for (col=0; col < width; col++) { + FORCC if (image[row*width+col][c] > clip) break; + if (c == colors) continue; + FORCC { + cam[0][c] = image[row*width+col][c]; + cam[1][c] = MIN(cam[0][c],clip); + } + for (i=0; i < 2; i++) { + FORCC for (lab[i][c]=j=0; j < colors; j++) + lab[i][c] += trans[colors-3][c][j] * cam[i][j]; + for (sum[i]=0,c=1; c < colors; c++) + sum[i] += SQR(lab[i][c]); + } + chratio = sqrt(sum[1]/sum[0]); + for (c=1; c < colors; c++) + lab[0][c] *= chratio; + FORCC for (cam[0][c]=j=0; j < colors; j++) + cam[0][c] += itrans[colors-3][c][j] * lab[0][j]; + FORCC image[row*width+col][c] = cam[0][c] / colors; + } +} + +#define SCALE (4 >> shrink) +void CLASS recover_highlights() +{ + float *map, sum, wgt, grow; + int hsat[4], count, spread, change, val, i; + unsigned high, wide, mrow, mcol, row, col, kc, c, d, y, x; + ushort *pixel; + static const signed char dir[8][2] = + { {-1,-1}, {-1,0}, {-1,1}, {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1} }; + + if (verbose) fprintf (stderr,_("Rebuilding highlights...\n")); + + grow = pow (2, 4-highlight); + FORCC hsat[c] = 32000 * pre_mul[c]; + for (kc=0, c=1; c < colors; c++) + if (pre_mul[kc] < pre_mul[c]) kc = c; + high = height / SCALE; + wide = width / SCALE; + map = (float *) calloc (high*wide, sizeof *map); + merror (map, "recover_highlights()"); + FORCC if (c != kc) { + memset (map, 0, high*wide*sizeof *map); + for (mrow=0; mrow < high; mrow++) + for (mcol=0; mcol < wide; mcol++) { + sum = wgt = count = 0; + for (row = mrow*SCALE; row < (mrow+1)*SCALE; row++) + for (col = mcol*SCALE; col < (mcol+1)*SCALE; col++) { + pixel = image[row*width+col]; + if (pixel[c] / hsat[c] == 1 && pixel[kc] > 24000) { + sum += pixel[c]; + wgt += pixel[kc]; + count++; + } + } + if (count == SCALE*SCALE) + map[mrow*wide+mcol] = sum / wgt; + } + for (spread = 32/grow; spread--; ) { + for (mrow=0; mrow < high; mrow++) + for (mcol=0; mcol < wide; mcol++) { + if (map[mrow*wide+mcol]) continue; + sum = count = 0; + for (d=0; d < 8; d++) { + y = mrow + dir[d][0]; + x = mcol + dir[d][1]; + if (y < high && x < wide && map[y*wide+x] > 0) { + sum += (1 + (d & 1)) * map[y*wide+x]; + count += 1 + (d & 1); + } + } + if (count > 3) + map[mrow*wide+mcol] = - (sum+grow) / (count+grow); + } + for (change=i=0; i < high*wide; i++) + if (map[i] < 0) { + map[i] = -map[i]; + change = 1; + } + if (!change) break; + } + for (i=0; i < high*wide; i++) + if (map[i] == 0) map[i] = 1; + for (mrow=0; mrow < high; mrow++) + for (mcol=0; mcol < wide; mcol++) { + for (row = mrow*SCALE; row < (mrow+1)*SCALE; row++) + for (col = mcol*SCALE; col < (mcol+1)*SCALE; col++) { + pixel = image[row*width+col]; + if (pixel[c] / hsat[c] > 1) { + val = pixel[kc] * map[mrow*wide+mcol]; + if (pixel[c] < val) pixel[c] = CLIP(val); + } + } + } + } + free (map); +} +#undef SCALE + +void CLASS tiff_get (unsigned base, + unsigned *tag, unsigned *type, unsigned *len, unsigned *save) +{ + *tag = get2(); + *type = get2(); + *len = get4(); + *save = ftell(ifp) + 4; + if (*len * ("11124811248488"[*type < 14 ? *type:0]-'0') > 4) + fseek (ifp, get4()+base, SEEK_SET); +} + +void CLASS parse_thumb_note (int base, unsigned toff, unsigned tlen) +{ + unsigned entries, tag, type, len, save; + + entries = get2(); + while (entries--) { + tiff_get (base, &tag, &type, &len, &save); + if (tag == toff) thumb_offset = get4()+base; + if (tag == tlen) thumb_length = get4(); + fseek (ifp, save, SEEK_SET); + } +} + +int CLASS parse_tiff_ifd (int base); + +void CLASS parse_makernote (int base, int uptag) +{ + static const uchar xlat[2][256] = { + { 0xc1,0xbf,0x6d,0x0d,0x59,0xc5,0x13,0x9d,0x83,0x61,0x6b,0x4f,0xc7,0x7f,0x3d,0x3d, + 0x53,0x59,0xe3,0xc7,0xe9,0x2f,0x95,0xa7,0x95,0x1f,0xdf,0x7f,0x2b,0x29,0xc7,0x0d, + 0xdf,0x07,0xef,0x71,0x89,0x3d,0x13,0x3d,0x3b,0x13,0xfb,0x0d,0x89,0xc1,0x65,0x1f, + 0xb3,0x0d,0x6b,0x29,0xe3,0xfb,0xef,0xa3,0x6b,0x47,0x7f,0x95,0x35,0xa7,0x47,0x4f, + 0xc7,0xf1,0x59,0x95,0x35,0x11,0x29,0x61,0xf1,0x3d,0xb3,0x2b,0x0d,0x43,0x89,0xc1, + 0x9d,0x9d,0x89,0x65,0xf1,0xe9,0xdf,0xbf,0x3d,0x7f,0x53,0x97,0xe5,0xe9,0x95,0x17, + 0x1d,0x3d,0x8b,0xfb,0xc7,0xe3,0x67,0xa7,0x07,0xf1,0x71,0xa7,0x53,0xb5,0x29,0x89, + 0xe5,0x2b,0xa7,0x17,0x29,0xe9,0x4f,0xc5,0x65,0x6d,0x6b,0xef,0x0d,0x89,0x49,0x2f, + 0xb3,0x43,0x53,0x65,0x1d,0x49,0xa3,0x13,0x89,0x59,0xef,0x6b,0xef,0x65,0x1d,0x0b, + 0x59,0x13,0xe3,0x4f,0x9d,0xb3,0x29,0x43,0x2b,0x07,0x1d,0x95,0x59,0x59,0x47,0xfb, + 0xe5,0xe9,0x61,0x47,0x2f,0x35,0x7f,0x17,0x7f,0xef,0x7f,0x95,0x95,0x71,0xd3,0xa3, + 0x0b,0x71,0xa3,0xad,0x0b,0x3b,0xb5,0xfb,0xa3,0xbf,0x4f,0x83,0x1d,0xad,0xe9,0x2f, + 0x71,0x65,0xa3,0xe5,0x07,0x35,0x3d,0x0d,0xb5,0xe9,0xe5,0x47,0x3b,0x9d,0xef,0x35, + 0xa3,0xbf,0xb3,0xdf,0x53,0xd3,0x97,0x53,0x49,0x71,0x07,0x35,0x61,0x71,0x2f,0x43, + 0x2f,0x11,0xdf,0x17,0x97,0xfb,0x95,0x3b,0x7f,0x6b,0xd3,0x25,0xbf,0xad,0xc7,0xc5, + 0xc5,0xb5,0x8b,0xef,0x2f,0xd3,0x07,0x6b,0x25,0x49,0x95,0x25,0x49,0x6d,0x71,0xc7 }, + { 0xa7,0xbc,0xc9,0xad,0x91,0xdf,0x85,0xe5,0xd4,0x78,0xd5,0x17,0x46,0x7c,0x29,0x4c, + 0x4d,0x03,0xe9,0x25,0x68,0x11,0x86,0xb3,0xbd,0xf7,0x6f,0x61,0x22,0xa2,0x26,0x34, + 0x2a,0xbe,0x1e,0x46,0x14,0x68,0x9d,0x44,0x18,0xc2,0x40,0xf4,0x7e,0x5f,0x1b,0xad, + 0x0b,0x94,0xb6,0x67,0xb4,0x0b,0xe1,0xea,0x95,0x9c,0x66,0xdc,0xe7,0x5d,0x6c,0x05, + 0xda,0xd5,0xdf,0x7a,0xef,0xf6,0xdb,0x1f,0x82,0x4c,0xc0,0x68,0x47,0xa1,0xbd,0xee, + 0x39,0x50,0x56,0x4a,0xdd,0xdf,0xa5,0xf8,0xc6,0xda,0xca,0x90,0xca,0x01,0x42,0x9d, + 0x8b,0x0c,0x73,0x43,0x75,0x05,0x94,0xde,0x24,0xb3,0x80,0x34,0xe5,0x2c,0xdc,0x9b, + 0x3f,0xca,0x33,0x45,0xd0,0xdb,0x5f,0xf5,0x52,0xc3,0x21,0xda,0xe2,0x22,0x72,0x6b, + 0x3e,0xd0,0x5b,0xa8,0x87,0x8c,0x06,0x5d,0x0f,0xdd,0x09,0x19,0x93,0xd0,0xb9,0xfc, + 0x8b,0x0f,0x84,0x60,0x33,0x1c,0x9b,0x45,0xf1,0xf0,0xa3,0x94,0x3a,0x12,0x77,0x33, + 0x4d,0x44,0x78,0x28,0x3c,0x9e,0xfd,0x65,0x57,0x16,0x94,0x6b,0xfb,0x59,0xd0,0xc8, + 0x22,0x36,0xdb,0xd2,0x63,0x98,0x43,0xa1,0x04,0x87,0x86,0xf7,0xa6,0x26,0xbb,0xd6, + 0x59,0x4d,0xbf,0x6a,0x2e,0xaa,0x2b,0xef,0xe6,0x78,0xb6,0x4e,0xe0,0x2f,0xdc,0x7c, + 0xbe,0x57,0x19,0x32,0x7e,0x2a,0xd0,0xb8,0xba,0x29,0x00,0x3c,0x52,0x7d,0xa8,0x49, + 0x3b,0x2d,0xeb,0x25,0x49,0xfa,0xa3,0xaa,0x39,0xa7,0xc5,0xa7,0x50,0x11,0x36,0xfb, + 0xc6,0x67,0x4a,0xf5,0xa5,0x12,0x65,0x7e,0xb0,0xdf,0xaf,0x4e,0xb3,0x61,0x7f,0x2f } }; + unsigned offset=0, entries, tag, type, len, save, c; + unsigned ver97=0, serial=0, i, wbi=0, wb[4]={0,0,0,0}; + uchar buf97[324], ci, cj, ck; + short sorder=order; + char buf[10]; +/* + The MakerNote might have its own TIFF header (possibly with + its own byte-order!), or it might just be a table. + */ + fread (buf, 1, 10, ifp); + if (!strncmp (buf,"KDK" ,3) || /* these aren't TIFF tables */ + !strncmp (buf,"VER" ,3) || + !strncmp (buf,"IIII",4) || + !strncmp (buf,"MMMM",4)) return; + if (!strncmp (buf,"KC" ,2) || /* Konica KD-400Z, KD-510Z */ + !strncmp (buf,"MLY" ,3)) { /* Minolta DiMAGE G series */ + order = 0x4d4d; + while ((i=ftell(ifp)) < data_offset && i < 16384) { + wb[0] = wb[2]; wb[2] = wb[1]; wb[1] = wb[3]; + wb[3] = get2(); + if (wb[1] == 256 && wb[3] == 256 && + wb[0] > 256 && wb[0] < 640 && wb[2] > 256 && wb[2] < 640) + FORC4 cam_mul[c] = wb[c]; + } + goto quit; + } + if (!strcmp (buf,"Nikon")) { + base = ftell(ifp); + order = get2(); + if (get2() != 42) goto quit; + offset = get4(); + fseek (ifp, offset-8, SEEK_CUR); + } else if (!strcmp (buf,"OLYMPUS")) { + base = ftell(ifp)-10; + fseek (ifp, -2, SEEK_CUR); + order = get2(); get2(); + } else if (!strncmp (buf,"FUJIFILM",8) || + !strncmp (buf,"SONY",4) || + !strcmp (buf,"Panasonic")) { + order = 0x4949; + fseek (ifp, 2, SEEK_CUR); + } else if (!strcmp (buf,"OLYMP") || + !strcmp (buf,"LEICA") || + !strcmp (buf,"Ricoh") || + !strcmp (buf,"EPSON")) + fseek (ifp, -2, SEEK_CUR); + else if (!strcmp (buf,"AOC") || + !strcmp (buf,"QVC")) + fseek (ifp, -4, SEEK_CUR); + else fseek (ifp, -10, SEEK_CUR); + + entries = get2(); + if (entries > 1000) return; + while (entries--) { + tiff_get (base, &tag, &type, &len, &save); + tag |= uptag << 16; + if (tag == 2 && strstr(make,"NIKON")) + iso_speed = (get2(),get2()); + if (tag == 4 && len > 26 && len < 35) { + if ((i=(get4(),get2())) != 0x7fff && !iso_speed) + iso_speed = 50 * pow (2, i/32.0 - 4); + if ((i=(get2(),get2())) != 0x7fff && !aperture) + aperture = pow (2, i/64.0); + if ((i=get2()) != 0xffff && !shutter) + shutter = pow (2, (short) i/-32.0); + wbi = (get2(),get2()); + shot_order = (get2(),get2()); + } + if ((tag == 4 || tag == 0x114) && !strncmp(make,"KONICA",6)) { + fseek (ifp, tag == 4 ? 140:160, SEEK_CUR); + switch (get2()) { + case 72: flip = 0; break; + case 76: flip = 6; break; + case 82: flip = 5; break; + } + } + if (tag == 7 && type == 2 && len > 20) + fgets (model2, 64, ifp); + if (tag == 8 && type == 4) + shot_order = get4(); + if (tag == 9 && !strcmp(make,"Canon")) + fread (artist, 64, 1, ifp); + if (tag == 0xc && len == 4) { + cam_mul[0] = getreal(type); + cam_mul[2] = getreal(type); + } + if (tag == 0x10 && type == 4) + unique_id = get4(); + if (tag == 0x11 && is_raw && !strncmp(make,"NIKON",5)) { + fseek (ifp, get4()+base, SEEK_SET); + parse_tiff_ifd (base); + } + if (tag == 0x14 && len == 2560 && type == 7) { + fseek (ifp, 1248, SEEK_CUR); + goto get2_256; + } + if (tag == 0x15 && type == 2 && is_raw) + fread (model, 64, 1, ifp); + if (strstr(make,"PENTAX")) { + if (tag == 0x1b) tag = 0x1018; + if (tag == 0x1c) tag = 0x1017; + } + if (tag == 0x1d) + while ((c = fgetc(ifp)) && c != EOF) + serial = serial*10 + (isdigit(c) ? c - '0' : c % 10); + if (tag == 0x81 && type == 4) { + data_offset = get4(); + fseek (ifp, data_offset + 41, SEEK_SET); + raw_height = get2() * 2; + raw_width = get2(); + filters = 0x61616161; + } + if (tag == 0x29 && type == 1) { + c = wbi < 18 ? "012347800000005896"[wbi]-'0' : 0; + fseek (ifp, 8 + c*32, SEEK_CUR); + FORC4 cam_mul[c ^ (c >> 1) ^ 1] = get4(); + } + if ((tag == 0x81 && type == 7) || + (tag == 0x100 && type == 7) || + (tag == 0x280 && type == 1)) { + thumb_offset = ftell(ifp); + thumb_length = len; + } + if (tag == 0x88 && type == 4 && (thumb_offset = get4())) + thumb_offset += base; + if (tag == 0x89 && type == 4) + thumb_length = get4(); + if (tag == 0x8c || tag == 0x96) + meta_offset = ftell(ifp); + if (tag == 0x97) { + for (i=0; i < 4; i++) + ver97 = ver97 * 10 + fgetc(ifp)-'0'; + switch (ver97) { + case 100: + fseek (ifp, 68, SEEK_CUR); + FORC4 cam_mul[(c >> 1) | ((c & 1) << 1)] = get2(); + break; + case 102: + fseek (ifp, 6, SEEK_CUR); + goto get2_rggb; + case 103: + fseek (ifp, 16, SEEK_CUR); + FORC4 cam_mul[c] = get2(); + } + if (ver97 >= 200) { + if (ver97 != 205) fseek (ifp, 280, SEEK_CUR); + fread (buf97, 324, 1, ifp); + } + } + if (tag == 0xa4 && type == 3) { + fseek (ifp, wbi*48, SEEK_CUR); + FORC3 cam_mul[c] = get2(); + } + if (tag == 0xa7 && (unsigned) (ver97-200) < 12 && !cam_mul[0]) { + ci = xlat[0][serial & 0xff]; + cj = xlat[1][fgetc(ifp)^fgetc(ifp)^fgetc(ifp)^fgetc(ifp)]; + ck = 0x60; + for (i=0; i < 324; i++) + buf97[i] ^= (cj += ci * ck++); + i = "66666>666;6A"[ver97-200] - '0'; + FORC4 cam_mul[c ^ (c >> 1) ^ (i & 1)] = + sget2 (buf97 + (i & -2) + c*2); + } + if (tag == 0x200 && len == 3) + shot_order = (get4(),get4()); + if (tag == 0x200 && len == 4) + black = (get2()+get2()+get2()+get2())/4; + if (tag == 0x201 && len == 4) + goto get2_rggb; + if (tag == 0x220 && len == 53) + meta_offset = ftell(ifp) + 14; + if (tag == 0x401 && type == 4 && len == 4) { + black = (get4()+get4()+get4()+get4())/4; + } + if (tag == 0xe01) { /* Nikon Capture Note */ + type = order; + order = 0x4949; + fseek (ifp, 22, SEEK_CUR); + for (offset=22; offset+22 < len; offset += 22+i) { + tag = get4(); + fseek (ifp, 14, SEEK_CUR); + i = get4()-4; + if (tag == 0x76a43207) flip = get2(); + else fseek (ifp, i, SEEK_CUR); + } + order = type; + } + if (tag == 0xe80 && len == 256 && type == 7) { + fseek (ifp, 48, SEEK_CUR); + cam_mul[0] = get2() * 508 * 1.078 / 0x10000; + cam_mul[2] = get2() * 382 * 1.173 / 0x10000; + } + if (tag == 0xf00 && type == 7) { + if (len == 614) + fseek (ifp, 176, SEEK_CUR); + else if (len == 734 || len == 1502) + fseek (ifp, 148, SEEK_CUR); + else goto next; + goto get2_256; + } + if ((tag == 0x1011 && len == 9) || tag == 0x20400200) + for (i=0; i < 3; i++) + FORC3 cmatrix[i][c] = ((short) get2()) / 256.0; + if ((tag == 0x1012 || tag == 0x20400600) && len == 4) + for (black = i=0; i < 4; i++) + black += get2() << 2; + if (tag == 0x1017 || tag == 0x20400100) + cam_mul[0] = get2() / 256.0; + if (tag == 0x1018 || tag == 0x20400100) + cam_mul[2] = get2() / 256.0; + if (tag == 0x2011 && len == 2) { +get2_256: + order = 0x4d4d; + cam_mul[0] = get2() / 256.0; + cam_mul[2] = get2() / 256.0; + } + if ((tag | 0x70) == 0x2070 && type == 4) + fseek (ifp, get4()+base, SEEK_SET); + if (tag == 0x2010 && type != 7) + load_raw = &CLASS olympus_load_raw; + if (tag == 0x2020) + parse_thumb_note (base, 257, 258); + if (tag == 0x2040) + parse_makernote (base, 0x2040); + if (tag == 0xb028) { + fseek (ifp, get4(), SEEK_SET); + parse_thumb_note (base, 136, 137); + } + if (tag == 0x4001 && len > 500) { + i = len == 582 ? 50 : len == 653 ? 68 : len == 5120 ? 142 : 126; + fseek (ifp, i, SEEK_CUR); +get2_rggb: + FORC4 cam_mul[c ^ (c >> 1)] = get2(); + fseek (ifp, 22, SEEK_CUR); + FORC4 sraw_mul[c ^ (c >> 1)] = get2(); + } +next: + fseek (ifp, save, SEEK_SET); + } +quit: + order = sorder; +} + +/* + Since the TIFF DateTime string has no timezone information, + assume that the camera's clock was set to Universal Time. + */ +void CLASS get_timestamp (int reversed) +{ + struct tm t; + char str[20]; + int i; + + str[19] = 0; + if (reversed) + for (i=19; i--; ) str[i] = fgetc(ifp); + else + fread (str, 19, 1, ifp); + memset (&t, 0, sizeof t); + if (sscanf (str, "%d:%d:%d %d:%d:%d", &t.tm_year, &t.tm_mon, + &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec) != 6) + return; + t.tm_year -= 1900; + t.tm_mon -= 1; + if (mktime(&t) > 0) + timestamp = mktime(&t); +} + +void CLASS parse_exif (int base) +{ + unsigned kodak, entries, tag, type, len, save, c; + double expo; + + kodak = !strncmp(make,"EASTMAN",7); + entries = get2(); + while (entries--) { + tiff_get (base, &tag, &type, &len, &save); + switch (tag) { + case 33434: shutter = getreal(type); break; + case 33437: aperture = getreal(type); break; + case 34855: iso_speed = get2(); break; + case 36867: + case 36868: get_timestamp(0); break; + case 37377: if ((expo = -getreal(type)) < 128) + shutter = pow (2, expo); break; + case 37378: aperture = pow (2, getreal(type)/2); break; + case 37386: focal_len = getreal(type); break; + case 37500: parse_makernote (base, 0); break; + case 40962: if (kodak) raw_width = get4(); break; + case 40963: if (kodak) raw_height = get4(); break; + case 41730: + if (get4() == 0x20002) + for (exif_cfa=c=0; c < 8; c+=2) + exif_cfa |= fgetc(ifp) * 0x01010101 << c; + } + fseek (ifp, save, SEEK_SET); + } +} + +void CLASS parse_gps (int base) +{ + unsigned entries, tag, type, len, save, c; + + entries = get2(); + while (entries--) { + tiff_get (base, &tag, &type, &len, &save); + switch (tag) { + case 1: case 3: case 5: + gpsdata[29+tag/2] = getc(ifp); break; + case 2: case 4: case 7: + FORC(6) gpsdata[tag/3*6+c] = get4(); break; + case 6: + FORC(2) gpsdata[18+c] = get4(); break; + case 18: case 29: + fgets ((char *) (gpsdata+14+tag/3), MIN(len,12), ifp); + } + fseek (ifp, save, SEEK_SET); + } +} + +void CLASS romm_coeff (float romm_cam[3][3]) +{ + static const float rgb_romm[3][3] = /* ROMM == Kodak ProPhoto */ + { { 2.034193, -0.727420, -0.306766 }, + { -0.228811, 1.231729, -0.002922 }, + { -0.008565, -0.153273, 1.161839 } }; + int i, j, k; + + for (i=0; i < 3; i++) + for (j=0; j < 3; j++) + for (cmatrix[i][j] = k=0; k < 3; k++) + cmatrix[i][j] += rgb_romm[i][k] * romm_cam[k][j]; +} + +void CLASS parse_mos (int offset) +{ + char data[40]; + int skip, from, i, c, neut[4], planes=0, frot=0; + static const char *mod[] = + { "","DCB2","Volare","Cantare","CMost","Valeo 6","Valeo 11","Valeo 22", + "Valeo 11p","Valeo 17","","Aptus 17","Aptus 22","Aptus 75","Aptus 65", + "Aptus 54S","Aptus 65S","Aptus 75S","AFi 5","AFi 6","AFi 7" }; + float romm_cam[3][3]; + + fseek (ifp, offset, SEEK_SET); + while (1) { + if (get4() != 0x504b5453) break; + get4(); + fread (data, 1, 40, ifp); + skip = get4(); + from = ftell(ifp); + if (!strcmp(data,"JPEG_preview_data")) { + thumb_offset = from; + thumb_length = skip; + } + if (!strcmp(data,"icc_camera_profile")) { + profile_offset = from; + profile_length = skip; + } + if (!strcmp(data,"ShootObj_back_type")) { + fscanf (ifp, "%d", &i); + if ((unsigned) i < sizeof mod / sizeof (*mod)) + strcpy (model, mod[i]); + } + if (!strcmp(data,"icc_camera_to_tone_matrix")) { + for (i=0; i < 9; i++) + romm_cam[0][i] = int_to_float(get4()); + romm_coeff (romm_cam); + } + if (!strcmp(data,"CaptProf_color_matrix")) { + for (i=0; i < 9; i++) + fscanf (ifp, "%f", &romm_cam[0][i]); + romm_coeff (romm_cam); + } + if (!strcmp(data,"CaptProf_number_of_planes")) + fscanf (ifp, "%d", &planes); + if (!strcmp(data,"CaptProf_raw_data_rotation")) + fscanf (ifp, "%d", &flip); + if (!strcmp(data,"CaptProf_mosaic_pattern")) + FORC4 { + fscanf (ifp, "%d", &i); + if (i == 1) frot = c ^ (c >> 1); + } + if (!strcmp(data,"ImgProf_rotation_angle")) { + fscanf (ifp, "%d", &i); + flip = i - flip; + } + if (!strcmp(data,"NeutObj_neutrals") && !cam_mul[0]) { + FORC4 fscanf (ifp, "%d", neut+c); + FORC3 cam_mul[c] = (float) neut[0] / neut[c+1]; + } + parse_mos (from); + fseek (ifp, skip+from, SEEK_SET); + } + if (planes) + filters = (planes == 1) * 0x01010101 * + (uchar) "\x94\x61\x16\x49"[(flip/90 + frot) & 3]; +} + +void CLASS linear_table (unsigned len) +{ + int i; + if (len > 0x1000) len = 0x1000; + read_shorts (curve, len); + for (i=len; i < 0x1000; i++) + curve[i] = curve[i-1]; + maximum = curve[0xfff]; +} + +void CLASS parse_kodak_ifd (int base) +{ + unsigned entries, tag, type, len, save; + int i, c, wbi=-2, wbtemp=6500; + float mul[3]={1,1,1}, num; + static const int wbtag[]={ 0xfa25,0xfa28,0xfa27,0xfa29,-1,-1,0xfa2a }; + + entries = get2(); + if (entries > 1024) return; + while (entries--) { + tiff_get (base, &tag, &type, &len, &save); + if (tag == 1020) wbi = getint(type); + if (tag == 1021 && len == 72) { /* WB set in software */ + fseek (ifp, 40, SEEK_CUR); + FORC3 cam_mul[c] = 2048.0 / get2(); + wbi = -2; + } + if (tag == 2118) wbtemp = getint(type); + if (tag == 2130 + wbi) + FORC3 mul[c] = getreal(type); + if (tag == 2140 + wbi && wbi >= 0) + FORC3 { + for (num=i=0; i < 4; i++) + num += getreal(type) * pow (wbtemp/100.0, i); + cam_mul[c] = 2048 / (num * mul[c]); + } + if (tag == 2317) linear_table (len); + if (tag == 6020) iso_speed = getint(type); + if (tag == 0xfa0d) wbi = fgetc(ifp); + if ((unsigned) wbi < 7 && tag == wbtag[wbi]) + FORC3 cam_mul[c] = get4(); + fseek (ifp, save, SEEK_SET); + } +} + +void CLASS parse_minolta (int base); + +int CLASS parse_tiff_ifd (int base) +{ + unsigned entries, tag, type, len, plen=16, save; + int ifd, use_cm=0, cfa, i, j, c, ima_len=0; + char software[64], *cbuf, *cp; + uchar cfa_pat[16], cfa_pc[] = { 0,1,2,3 }, tab[256]; + double dblack, cc[4][4], cm[4][3], cam_xyz[4][3], num; + double ab[]={ 1,1,1,1 }, asn[] = { 0,0,0,0 }, xyz[] = { 1,1,1 }; + unsigned sony_curve[] = { 0,0,0,0,0,4095 }; + unsigned *buf, sony_offset=0, sony_length=0, sony_key=0; + struct jhead jh; + FILE *sfp; + + if (tiff_nifds >= sizeof tiff_ifd / sizeof tiff_ifd[0]) + return 1; + ifd = tiff_nifds++; + for (j=0; j < 4; j++) + for (i=0; i < 4; i++) + cc[j][i] = i == j; + entries = get2(); + if (entries > 512) return 1; + while (entries--) { + tiff_get (base, &tag, &type, &len, &save); + switch (tag) { + case 17: case 18: + if (type == 3 && len == 1) + cam_mul[(tag-17)*2] = get2() / 256.0; + break; + case 23: + if (type == 3) iso_speed = get2(); + break; + case 36: case 37: case 38: + cam_mul[tag-0x24] = get2(); + break; + case 39: + if (len < 50 || cam_mul[0]) break; + fseek (ifp, 12, SEEK_CUR); + FORC3 cam_mul[c] = get2(); + break; + case 46: + if (type != 7 || fgetc(ifp) != 0xff || fgetc(ifp) != 0xd8) break; + thumb_offset = ftell(ifp) - 2; + thumb_length = len; + break; + case 2: case 256: /* ImageWidth */ + tiff_ifd[ifd].width = getint(type); + break; + case 3: case 257: /* ImageHeight */ + tiff_ifd[ifd].height = getint(type); + break; + case 258: /* BitsPerSample */ + tiff_ifd[ifd].samples = len & 7; + tiff_ifd[ifd].bps = get2(); + break; + case 259: /* Compression */ + tiff_ifd[ifd].comp = get2(); + break; + case 262: /* PhotometricInterpretation */ + tiff_ifd[ifd].phint = get2(); + break; + case 270: /* ImageDescription */ + fread (desc, 512, 1, ifp); + break; + case 271: /* Make */ + fgets (make, 64, ifp); + break; + case 272: /* Model */ + fgets (model, 64, ifp); + break; + case 280: /* Panasonic RW2 offset */ + if (type != 4) break; + load_raw = &CLASS panasonic_load_raw; + load_flags = 0x2008; + case 273: /* StripOffset */ + case 513: + tiff_ifd[ifd].offset = get4()+base; + if (!tiff_ifd[ifd].bps) { + fseek (ifp, tiff_ifd[ifd].offset, SEEK_SET); + if (ljpeg_start (&jh, 1)) { + tiff_ifd[ifd].comp = 6; + tiff_ifd[ifd].width = jh.wide << (jh.clrs == 2); + tiff_ifd[ifd].height = jh.high; + tiff_ifd[ifd].bps = jh.bits; + tiff_ifd[ifd].samples = jh.clrs; + } + } + break; + case 274: /* Orientation */ + tiff_ifd[ifd].flip = "50132467"[get2() & 7]-'0'; + break; + case 277: /* SamplesPerPixel */ + tiff_ifd[ifd].samples = getint(type) & 7; + break; + case 279: /* StripByteCounts */ + case 514: + tiff_ifd[ifd].bytes = get4(); + break; + case 305: case 11: /* Software */ + fgets (software, 64, ifp); + if (!strncmp(software,"Adobe",5) || + !strncmp(software,"dcraw",5) || + !strncmp(software,"UFRaw",5) || + !strncmp(software,"Bibble",6) || + !strncmp(software,"Nikon Scan",10) || + !strcmp (software,"Digital Photo Professional")) + is_raw = 0; + break; + case 306: /* DateTime */ + get_timestamp(0); + break; + case 315: /* Artist */ + fread (artist, 64, 1, ifp); + break; + case 322: /* TileWidth */ + tile_width = getint(type); + break; + case 323: /* TileLength */ + tile_length = getint(type); + break; + case 324: /* TileOffsets */ + tiff_ifd[ifd].offset = len > 1 ? ftell(ifp) : get4(); + if (len == 4) { + load_raw = &CLASS sinar_4shot_load_raw; + is_raw = 5; + } + break; + case 330: /* SubIFDs */ + if (!strcmp(model,"DSLR-A100") && tiff_ifd[ifd].width == 3872) { + load_raw = &CLASS sony_arw_load_raw; + data_offset = get4()+base; + ifd++; break; + } + while (len--) { + i = ftell(ifp); + fseek (ifp, get4()+base, SEEK_SET); + if (parse_tiff_ifd (base)) break; + fseek (ifp, i+4, SEEK_SET); + } + break; + case 400: + strcpy (make, "Sarnoff"); + maximum = 0xfff; + break; + case 28688: + FORC4 sony_curve[c+1] = get2() >> 2 & 0xfff; + for (i=0; i < 5; i++) + for (j = sony_curve[i]+1; j <= sony_curve[i+1]; j++) + curve[j] = curve[j-1] + (1 << i); + break; + case 29184: sony_offset = get4(); break; + case 29185: sony_length = get4(); break; + case 29217: sony_key = get4(); break; + case 29264: + parse_minolta (ftell(ifp)); + raw_width = 0; + break; + case 29443: + FORC4 cam_mul[c ^ (c < 2)] = get2(); + break; + case 29459: + FORC4 cam_mul[c ^ (c >> 1)] = get2(); + break; + case 33405: /* Model2 */ + fgets (model2, 64, ifp); + break; + case 33422: /* CFAPattern */ + case 64777: /* Kodak P-series */ + if ((plen=len) > 16) plen = 16; + fread (cfa_pat, 1, plen, ifp); + for (colors=cfa=i=0; i < plen; i++) { + colors += !(cfa & (1 << cfa_pat[i])); + cfa |= 1 << cfa_pat[i]; + } + if (cfa == 070) memcpy (cfa_pc,"\003\004\005",3); /* CMY */ + if (cfa == 072) memcpy (cfa_pc,"\005\003\004\001",4); /* GMCY */ + goto guess_cfa_pc; + case 33424: + case 65024: + fseek (ifp, get4()+base, SEEK_SET); + parse_kodak_ifd (base); + break; + case 33434: /* ExposureTime */ + shutter = getreal(type); + break; + case 33437: /* FNumber */ + aperture = getreal(type); + break; + case 34306: /* Leaf white balance */ + FORC4 cam_mul[c ^ 1] = 4096.0 / get2(); + break; + case 34307: /* Leaf CatchLight color matrix */ + fread (software, 1, 7, ifp); + if (strncmp(software,"MATRIX",6)) break; + colors = 4; + for (raw_color = i=0; i < 3; i++) { + FORC4 fscanf (ifp, "%f", &rgb_cam[i][c^1]); + if (!use_camera_wb) continue; + num = 0; + FORC4 num += rgb_cam[i][c]; + FORC4 rgb_cam[i][c] /= num; + } + break; + case 34310: /* Leaf metadata */ + parse_mos (ftell(ifp)); + case 34303: + strcpy (make, "Leaf"); + break; + case 34665: /* EXIF tag */ + fseek (ifp, get4()+base, SEEK_SET); + parse_exif (base); + break; + case 34853: /* GPSInfo tag */ + fseek (ifp, get4()+base, SEEK_SET); + parse_gps (base); + break; + case 34675: /* InterColorProfile */ + case 50831: /* AsShotICCProfile */ + profile_offset = ftell(ifp); + profile_length = len; + break; + case 37122: /* CompressedBitsPerPixel */ + kodak_cbpp = get4(); + break; + case 37386: /* FocalLength */ + focal_len = getreal(type); + break; + case 37393: /* ImageNumber */ + shot_order = getint(type); + break; + case 37400: /* old Kodak KDC tag */ + for (raw_color = i=0; i < 3; i++) { + getreal(type); + FORC3 rgb_cam[i][c] = getreal(type); + } + break; + case 46275: /* Imacon tags */ + strcpy (make, "Imacon"); + data_offset = ftell(ifp); + ima_len = len; + break; + case 46279: + if (!ima_len) break; + fseek (ifp, 78, SEEK_CUR); + raw_width = get4(); + raw_height = get4(); + left_margin = get4() & 7; + width = raw_width - left_margin - (get4() & 7); + top_margin = get4() & 7; + height = raw_height - top_margin - (get4() & 7); + if (raw_width == 7262) { + height = 5444; + width = 7244; + left_margin = 7; + } + fseek (ifp, 52, SEEK_CUR); + FORC3 cam_mul[c] = getreal(11); + fseek (ifp, 114, SEEK_CUR); + flip = (get2() >> 7) * 90; + if (width * height * 6 == ima_len) { + if (flip % 180 == 90) SWAP(width,height); + filters = flip = 0; + } + sprintf (model, "Ixpress %d-Mp", height*width/1000000); + load_raw = &CLASS imacon_full_load_raw; + if (filters) { + if (left_margin & 1) filters = 0x61616161; + load_raw = &CLASS unpacked_load_raw; + } + maximum = 0xffff; + break; + case 50454: /* Sinar tag */ + case 50455: + if (!(cbuf = (char *) malloc(len))) break; + fread (cbuf, 1, len, ifp); + for (cp = cbuf-1; cp && cp < cbuf+len; cp = strchr(cp,'\n')) + if (!strncmp (++cp,"Neutral ",8)) + sscanf (cp+8, "%f %f %f", cam_mul, cam_mul+1, cam_mul+2); + free (cbuf); + break; + case 50458: + if (!make[0]) strcpy (make, "Hasselblad"); + break; + case 50459: /* Hasselblad tag */ + i = order; + j = ftell(ifp); + c = tiff_nifds; + order = get2(); + fseek (ifp, j+(get2(),get4()), SEEK_SET); + parse_tiff_ifd (j); + maximum = 0xffff; + tiff_nifds = c; + order = i; + break; + case 50706: /* DNGVersion */ + FORC4 dng_version = (dng_version << 8) + fgetc(ifp); + if (!make[0]) strcpy (make, "DNG"); + is_raw = 1; + break; + case 50710: /* CFAPlaneColor */ + if (len > 4) len = 4; + colors = len; + fread (cfa_pc, 1, colors, ifp); +guess_cfa_pc: + FORCC tab[cfa_pc[c]] = c; + cdesc[c] = 0; + for (i=16; i--; ) + filters = filters << 2 | tab[cfa_pat[i % plen]]; + break; + case 50711: /* CFALayout */ + if (get2() == 2) { + fuji_width = 1; + filters = 0x49494949; + } + break; + case 291: + case 50712: /* LinearizationTable */ + linear_table (len); + break; + case 50714: /* BlackLevel */ + case 50715: /* BlackLevelDeltaH */ + case 50716: /* BlackLevelDeltaV */ + for (dblack=i=0; i < len; i++) + dblack += getreal(type); + black += dblack/len + 0.5; + break; + case 50717: /* WhiteLevel */ + maximum = getint(type); + break; + case 50718: /* DefaultScale */ + pixel_aspect = getreal(type); + pixel_aspect /= getreal(type); + break; + case 50721: /* ColorMatrix1 */ + case 50722: /* ColorMatrix2 */ + FORCC for (j=0; j < 3; j++) + cm[c][j] = getreal(type); + use_cm = 1; + break; + case 50723: /* CameraCalibration1 */ + case 50724: /* CameraCalibration2 */ + for (i=0; i < colors; i++) + FORCC cc[i][c] = getreal(type); + break; + case 50727: /* AnalogBalance */ + FORCC ab[c] = getreal(type); + break; + case 50728: /* AsShotNeutral */ + FORCC asn[c] = getreal(type); + break; + case 50729: /* AsShotWhiteXY */ + xyz[0] = getreal(type); + xyz[1] = getreal(type); + xyz[2] = 1 - xyz[0] - xyz[1]; + FORC3 xyz[c] /= d65_white[c]; + break; + case 50740: /* DNGPrivateData */ + if (dng_version) break; + parse_minolta (j = get4()+base); + fseek (ifp, j, SEEK_SET); + parse_tiff_ifd (base); + break; + case 50752: + read_shorts (cr2_slice, 3); + break; + case 50829: /* ActiveArea */ + top_margin = getint(type); + left_margin = getint(type); + height = getint(type) - top_margin; + width = getint(type) - left_margin; + break; + case 64772: /* Kodak P-series */ + if (len < 13) break; + fseek (ifp, 16, SEEK_CUR); + data_offset = get4(); + fseek (ifp, 28, SEEK_CUR); + data_offset += get4(); + load_raw = &CLASS packed_load_raw; + break; + case 65026: + if (type == 2) fgets (model2, 64, ifp); + } + fseek (ifp, save, SEEK_SET); + } + if (sony_length && (buf = (unsigned *) malloc(sony_length))) { + fseek (ifp, sony_offset, SEEK_SET); + fread (buf, sony_length, 1, ifp); + sony_decrypt (buf, sony_length/4, 1, sony_key); + sfp = ifp; + if ((ifp = tmpfile())) { + fwrite (buf, sony_length, 1, ifp); + fseek (ifp, 0, SEEK_SET); + parse_tiff_ifd (-sony_offset); + fclose (ifp); + } + ifp = sfp; + free (buf); + } + for (i=0; i < colors; i++) + FORCC cc[i][c] *= ab[i]; + if (use_cm) { + FORCC for (i=0; i < 3; i++) + for (cam_xyz[c][i]=j=0; j < colors; j++) + cam_xyz[c][i] += cc[c][j] * cm[j][i] * xyz[i]; + cam_xyz_coeff (cam_xyz); + } + if (asn[0]) { + cam_mul[3] = 0; + FORCC cam_mul[c] = 1 / asn[c]; + } + if (!use_cm) + FORCC pre_mul[c] /= cc[c][c]; + return 0; +} + +void CLASS parse_tiff (int base) +{ + int doff, max_samp=0, raw=-1, thm=-1, i; + struct jhead jh; + + fseek (ifp, base, SEEK_SET); + order = get2(); + if (order != 0x4949 && order != 0x4d4d) return; + get2(); + memset (tiff_ifd, 0, sizeof tiff_ifd); + tiff_nifds = 0; + while ((doff = get4())) { + fseek (ifp, doff+base, SEEK_SET); + if (parse_tiff_ifd (base)) break; + } + thumb_misc = 16; + if (thumb_offset) { + fseek (ifp, thumb_offset, SEEK_SET); + if (ljpeg_start (&jh, 1)) { + thumb_misc = jh.bits; + thumb_width = jh.wide; + thumb_height = jh.high; + } + } + for (i=0; i < tiff_nifds; i++) { + if (max_samp < tiff_ifd[i].samples) + max_samp = tiff_ifd[i].samples; + if (max_samp > 3) max_samp = 3; + if ((tiff_ifd[i].comp != 6 || tiff_ifd[i].samples != 3) && + (tiff_ifd[i].width | tiff_ifd[i].height) < 0x10000 && + tiff_ifd[i].width*tiff_ifd[i].height > raw_width*raw_height) { + raw_width = tiff_ifd[i].width; + raw_height = tiff_ifd[i].height; + tiff_bps = tiff_ifd[i].bps; + tiff_compress = tiff_ifd[i].comp; + data_offset = tiff_ifd[i].offset; + tiff_flip = tiff_ifd[i].flip; + tiff_samples = tiff_ifd[i].samples; + raw = i; + } + } + fuji_width *= (raw_width+1)/2; + if (tiff_ifd[0].flip) tiff_flip = tiff_ifd[0].flip; + if (raw >= 0 && !load_raw) + switch (tiff_compress) { + case 0: case 1: + switch (tiff_bps) { + case 8: load_raw = &CLASS eight_bit_load_raw; break; + case 12: load_raw = &CLASS packed_load_raw; + if (tiff_ifd[raw].phint == 2) + load_flags = 6; + if (strncmp(make,"PENTAX",6)) break; + case 14: + case 16: load_raw = &CLASS unpacked_load_raw; break; + } + if (tiff_ifd[raw].bytes*5 == raw_width*raw_height*8) { + tiff_bps = 12; + maximum = 0xffff; + load_raw = &CLASS packed_load_raw; + load_flags = 273; + } + break; + case 6: case 7: case 99: + load_raw = &CLASS lossless_jpeg_load_raw; break; + case 262: + load_raw = &CLASS kodak_262_load_raw; break; + case 32767: + if (tiff_ifd[raw].bytes == raw_width*raw_height) { + tiff_bps = 12; + load_raw = &CLASS sony_arw2_load_raw; break; + } + if (tiff_ifd[raw].bytes*8 != raw_width*raw_height*tiff_bps) { + raw_height += 8; + load_raw = &CLASS sony_arw_load_raw; break; + } + load_flags = 79; + case 32769: + load_flags++; + case 32773: + load_raw = &CLASS packed_load_raw; break; + case 34713: + load_raw = &CLASS nikon_compressed_load_raw; break; + case 65535: + load_raw = &CLASS pentax_load_raw; break; + case 65000: + switch (tiff_ifd[raw].phint) { + case 2: load_raw = &CLASS kodak_rgb_load_raw; filters = 0; break; + case 6: load_raw = &CLASS kodak_ycbcr_load_raw; filters = 0; break; + case 32803: load_raw = &CLASS kodak_65000_load_raw; + } + case 32867: break; + default: is_raw = 0; + } + if (!dng_version) + if ( (tiff_samples == 3 && tiff_ifd[raw].bytes && + tiff_bps != 14 && tiff_bps != 2048) + || (tiff_bps == 8 && !strstr(make,"KODAK") && !strstr(make,"Kodak") && + !strstr(model2,"DEBUG RAW"))) + is_raw = 0; + for (i=0; i < tiff_nifds; i++) + if (i != raw && tiff_ifd[i].samples == max_samp && + tiff_ifd[i].width * tiff_ifd[i].height / SQR(tiff_ifd[i].bps+1) > + thumb_width * thumb_height / SQR(thumb_misc+1)) { + thumb_width = tiff_ifd[i].width; + thumb_height = tiff_ifd[i].height; + thumb_offset = tiff_ifd[i].offset; + thumb_length = tiff_ifd[i].bytes; + thumb_misc = tiff_ifd[i].bps; + thm = i; + } + if (thm >= 0) { + thumb_misc |= tiff_ifd[thm].samples << 5; + switch (tiff_ifd[thm].comp) { + case 0: + write_thumb = &CLASS layer_thumb; + break; + case 1: + if (tiff_ifd[thm].bps > 8) + thumb_load_raw = &CLASS kodak_thumb_load_raw; + else + write_thumb = &CLASS ppm_thumb; + break; + case 65000: + thumb_load_raw = tiff_ifd[thm].phint == 6 ? + &CLASS kodak_ycbcr_load_raw : &CLASS kodak_rgb_load_raw; + } + } +} + +void CLASS parse_minolta (int base) +{ + int save, tag, len, offset, high=0, wide=0, i, c; + short sorder=order; + + fseek (ifp, base, SEEK_SET); + if (fgetc(ifp) || fgetc(ifp)-'M' || fgetc(ifp)-'R') return; + order = fgetc(ifp) * 0x101; + offset = base + get4() + 8; + while ((save=ftell(ifp)) < offset) { + for (tag=i=0; i < 4; i++) + tag = tag << 8 | fgetc(ifp); + len = get4(); + switch (tag) { + case 0x505244: /* PRD */ + fseek (ifp, 8, SEEK_CUR); + high = get2(); + wide = get2(); + break; + case 0x574247: /* WBG */ + get4(); + i = strcmp(model,"DiMAGE A200") ? 0:3; + FORC4 cam_mul[c ^ (c >> 1) ^ i] = get2(); + break; + case 0x545457: /* TTW */ + parse_tiff (ftell(ifp)); + data_offset = offset; + } + fseek (ifp, save+len+8, SEEK_SET); + } + raw_height = high; + raw_width = wide; + order = sorder; +} + +/* + Many cameras have a "debug mode" that writes JPEG and raw + at the same time. The raw file has no header, so try to + to open the matching JPEG file and read its metadata. + */ +void CLASS parse_external_jpeg() +{ + const char *file, *ext; + char *jname, *jfile, *jext; + FILE *save=ifp; + + ext = strrchr (ifname, '.'); + file = strrchr (ifname, '/'); + if (!file) file = strrchr (ifname, '\\'); + if (!file) file = ifname-1; + file++; + if (!ext || strlen(ext) != 4 || ext-file != 8) return; + jname = (char *) malloc (strlen(ifname) + 1); + merror (jname, "parse_external_jpeg()"); + strcpy (jname, ifname); + jfile = file - ifname + jname; + jext = ext - ifname + jname; + if (strcasecmp (ext, ".jpg")) { + strcpy (jext, isupper(ext[1]) ? ".JPG":".jpg"); + if (isdigit(*file)) { + memcpy (jfile, file+4, 4); + memcpy (jfile+4, file, 4); + } + } else + while (isdigit(*--jext)) { + if (*jext != '9') { + (*jext)++; + break; + } + *jext = '0'; + } + if (strcmp (jname, ifname)) { + if ((ifp = fopen (jname, "rb"))) { + if (verbose) + fprintf (stderr,_("Reading metadata from %s ...\n"), jname); + parse_tiff (12); + thumb_offset = 0; + is_raw = 1; + fclose (ifp); + } + } + if (!timestamp) + fprintf (stderr,_("Failed to read metadata from %s\n"), jname); + free (jname); + ifp = save; +} + +/* + CIFF block 0x1030 contains an 8x8 white sample. + Load this into white[][] for use in scale_colors(). + */ +void CLASS ciff_block_1030() +{ + static const ushort key[] = { 0x410, 0x45f3 }; + int i, bpp, row, col, vbits=0; + unsigned long bitbuf=0; + + if ((get2(),get4()) != 0x80008 || !get4()) return; + bpp = get2(); + if (bpp != 10 && bpp != 12) return; + for (i=row=0; row < 8; row++) + for (col=0; col < 8; col++) { + if (vbits < bpp) { + bitbuf = bitbuf << 16 | (get2() ^ key[i++ & 1]); + vbits += 16; + } + white[row][col] = + bitbuf << (LONG_BIT - vbits) >> (LONG_BIT - bpp); + vbits -= bpp; + } +} + +/* + Parse a CIFF file, better known as Canon CRW format. + */ +void CLASS parse_ciff (int offset, int length) +{ + int tboff, nrecs, c, type, len, save, wbi=-1; + ushort key[] = { 0x410, 0x45f3 }; + + fseek (ifp, offset+length-4, SEEK_SET); + tboff = get4() + offset; + fseek (ifp, tboff, SEEK_SET); + nrecs = get2(); + if (nrecs > 100) return; + while (nrecs--) { + type = get2(); + len = get4(); + save = ftell(ifp) + 4; + fseek (ifp, offset+get4(), SEEK_SET); + if ((((type >> 8) + 8) | 8) == 0x38) + parse_ciff (ftell(ifp), len); /* Parse a sub-table */ + + if (type == 0x0810) + fread (artist, 64, 1, ifp); + if (type == 0x080a) { + fread (make, 64, 1, ifp); + fseek (ifp, strlen(make) - 63, SEEK_CUR); + fread (model, 64, 1, ifp); + } + if (type == 0x1810) { + fseek (ifp, 12, SEEK_CUR); + flip = get4(); + } + if (type == 0x1835) /* Get the decoder table */ + tiff_compress = get4(); + if (type == 0x2007) { + thumb_offset = ftell(ifp); + thumb_length = len; + } + if (type == 0x1818) { + shutter = pow (2, -int_to_float((get4(),get4()))); + aperture = pow (2, int_to_float(get4())/2); + } + if (type == 0x102a) { + iso_speed = pow (2, (get4(),get2())/32.0 - 4) * 50; + aperture = pow (2, (get2(),(short)get2())/64.0); + shutter = pow (2,-((short)get2())/32.0); + wbi = (get2(),get2()); + if (wbi > 17) wbi = 0; + fseek (ifp, 32, SEEK_CUR); + if (shutter > 1e6) shutter = get2()/10.0; + } + if (type == 0x102c) { + if (get2() > 512) { /* Pro90, G1 */ + fseek (ifp, 118, SEEK_CUR); + FORC4 cam_mul[c ^ 2] = get2(); + } else { /* G2, S30, S40 */ + fseek (ifp, 98, SEEK_CUR); + FORC4 cam_mul[c ^ (c >> 1) ^ 1] = get2(); + } + } + if (type == 0x0032) { + if (len == 768) { /* EOS D30 */ + fseek (ifp, 72, SEEK_CUR); + FORC4 cam_mul[c ^ (c >> 1)] = 1024.0 / get2(); + if (!wbi) cam_mul[0] = -1; /* use my auto white balance */ + } else if (!cam_mul[0]) { + if (get2() == key[0]) /* Pro1, G6, S60, S70 */ + c = (strstr(model,"Pro1") ? + "012346000000000000":"01345:000000006008")[wbi]-'0'+ 2; + else { /* G3, G5, S45, S50 */ + c = "023457000000006000"[wbi]-'0'; + key[0] = key[1] = 0; + } + fseek (ifp, 78 + c*8, SEEK_CUR); + FORC4 cam_mul[c ^ (c >> 1) ^ 1] = get2() ^ key[c & 1]; + if (!wbi) cam_mul[0] = -1; + } + } + if (type == 0x10a9) { /* D60, 10D, 300D, and clones */ + if (len > 66) wbi = "0134567028"[wbi]-'0'; + fseek (ifp, 2 + wbi*8, SEEK_CUR); + FORC4 cam_mul[c ^ (c >> 1)] = get2(); + } + if (type == 0x1030 && (0x18040 >> wbi & 1)) + ciff_block_1030(); /* all that don't have 0x10a9 */ + if (type == 0x1031) { + raw_width = (get2(),get2()); + raw_height = get2(); + } + if (type == 0x5029) { + focal_len = len >> 16; + if ((len & 0xffff) == 2) focal_len /= 32; + } + if (type == 0x5813) flash_used = int_to_float(len); + if (type == 0x5814) canon_ev = int_to_float(len); + if (type == 0x5817) shot_order = len; + if (type == 0x5834) unique_id = len; + if (type == 0x580e) timestamp = len; + if (type == 0x180e) timestamp = get4(); +#ifdef LOCALTIME + if ((type | 0x4000) == 0x580e) + timestamp = mktime (gmtime (×tamp)); +#endif + fseek (ifp, save, SEEK_SET); + } +} + +void CLASS parse_rollei() +{ + char line[128], *val; + struct tm t; + + fseek (ifp, 0, SEEK_SET); + memset (&t, 0, sizeof t); + do { + fgets (line, 128, ifp); + if ((val = strchr(line,'='))) + *val++ = 0; + else + val = line + strlen(line); + if (!strcmp(line,"DAT")) + sscanf (val, "%d.%d.%d", &t.tm_mday, &t.tm_mon, &t.tm_year); + if (!strcmp(line,"TIM")) + sscanf (val, "%d:%d:%d", &t.tm_hour, &t.tm_min, &t.tm_sec); + if (!strcmp(line,"HDR")) + thumb_offset = atoi(val); + if (!strcmp(line,"X ")) + raw_width = atoi(val); + if (!strcmp(line,"Y ")) + raw_height = atoi(val); + if (!strcmp(line,"TX ")) + thumb_width = atoi(val); + if (!strcmp(line,"TY ")) + thumb_height = atoi(val); + } while (strncmp(line,"EOHD",4)); + data_offset = thumb_offset + thumb_width * thumb_height * 2; + t.tm_year -= 1900; + t.tm_mon -= 1; + if (mktime(&t) > 0) + timestamp = mktime(&t); + strcpy (make, "Rollei"); + strcpy (model,"d530flex"); + write_thumb = &CLASS rollei_thumb; +} + +void CLASS parse_sinar_ia() +{ + int entries, off; + char str[8], *cp; + + order = 0x4949; + fseek (ifp, 4, SEEK_SET); + entries = get4(); + fseek (ifp, get4(), SEEK_SET); + while (entries--) { + off = get4(); get4(); + fread (str, 8, 1, ifp); + if (!strcmp(str,"META")) meta_offset = off; + if (!strcmp(str,"THUMB")) thumb_offset = off; + if (!strcmp(str,"RAW0")) data_offset = off; + } + fseek (ifp, meta_offset+20, SEEK_SET); + fread (make, 64, 1, ifp); + make[63] = 0; + if ((cp = strchr(make,' '))) { + strcpy (model, cp+1); + *cp = 0; + } + raw_width = get2(); + raw_height = get2(); + load_raw = &CLASS unpacked_load_raw; + thumb_width = (get4(),get2()); + thumb_height = get2(); + write_thumb = &CLASS ppm_thumb; + maximum = 0x3fff; +} + +void CLASS parse_phase_one (int base) +{ + unsigned entries, tag, type, len, data, save, i, c; + float romm_cam[3][3]; + char *cp; + + memset (&ph1, 0, sizeof ph1); + fseek (ifp, base, SEEK_SET); + order = get4() & 0xffff; + if (get4() >> 8 != 0x526177) return; /* "Raw" */ + fseek (ifp, get4()+base, SEEK_SET); + entries = get4(); + get4(); + while (entries--) { + tag = get4(); + type = get4(); + len = get4(); + data = get4(); + save = ftell(ifp); + fseek (ifp, base+data, SEEK_SET); + switch (tag) { + case 0x100: flip = "0653"[data & 3]-'0'; break; + case 0x106: + for (i=0; i < 9; i++) + romm_cam[0][i] = getreal(11); + romm_coeff (romm_cam); + break; + case 0x107: + FORC3 cam_mul[c] = getreal(11); + break; + case 0x108: raw_width = data; break; + case 0x109: raw_height = data; break; + case 0x10a: left_margin = data; break; + case 0x10b: top_margin = data; break; + case 0x10c: width = data; break; + case 0x10d: height = data; break; + case 0x10e: ph1.format = data; break; + case 0x10f: data_offset = data+base; break; + case 0x110: meta_offset = data+base; + meta_length = len; break; + case 0x112: ph1.key_off = save - 4; break; + case 0x210: ph1.tag_210 = int_to_float(data); break; + case 0x21a: ph1.tag_21a = data; break; + case 0x21c: strip_offset = data+base; break; + case 0x21d: ph1.black = data; break; + case 0x222: ph1.split_col = data - left_margin; break; + case 0x223: ph1.black_off = data+base; break; + case 0x301: + model[63] = 0; + fread (model, 1, 63, ifp); + if ((cp = strstr(model," camera"))) *cp = 0; + } + fseek (ifp, save, SEEK_SET); + } + load_raw = ph1.format < 3 ? + &CLASS phase_one_load_raw : &CLASS phase_one_load_raw_c; + maximum = 0xffff; + strcpy (make, "Phase One"); + if (model[0]) return; + switch (raw_height) { + case 2060: strcpy (model,"LightPhase"); break; + case 2682: strcpy (model,"H 10"); break; + case 4128: strcpy (model,"H 20"); break; + case 5488: strcpy (model,"H 25"); break; + } +} + +void CLASS parse_fuji (int offset) +{ + unsigned entries, tag, len, save, c; + + fseek (ifp, offset, SEEK_SET); + entries = get4(); + if (entries > 255) return; + while (entries--) { + tag = get2(); + len = get2(); + save = ftell(ifp); + if (tag == 0x100) { + raw_height = get2(); + raw_width = get2(); + } else if (tag == 0x121) { + height = get2(); + if ((width = get2()) == 4284) width += 3; + } else if (tag == 0x130) { + fuji_layout = fgetc(ifp) >> 7; + load_raw = fgetc(ifp) & 8 ? + &CLASS unpacked_load_raw : &CLASS fuji_load_raw; + } + if (tag == 0x2ff0) + FORC4 cam_mul[c ^ 1] = get2(); + fseek (ifp, save+len, SEEK_SET); + } + height <<= fuji_layout; + width >>= fuji_layout; +} + +int CLASS parse_jpeg (int offset) +{ + int len, save, hlen, mark; + + fseek (ifp, offset, SEEK_SET); + if (fgetc(ifp) != 0xff || fgetc(ifp) != 0xd8) return 0; + + while (fgetc(ifp) == 0xff && (mark = fgetc(ifp)) != 0xda) { + order = 0x4d4d; + len = get2() - 2; + save = ftell(ifp); + if (mark == 0xc0 || mark == 0xc3) { + fgetc(ifp); + raw_height = get2(); + raw_width = get2(); + } + order = get2(); + hlen = get4(); + if (get4() == 0x48454150) /* "HEAP" */ + parse_ciff (save+hlen, len-hlen); + parse_tiff (save+6); + fseek (ifp, save+len, SEEK_SET); + } + return 1; +} + +void CLASS parse_riff() +{ + unsigned i, size, end; + char tag[4], date[64], month[64]; + static const char mon[12][4] = + { "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" }; + struct tm t; + + order = 0x4949; + fread (tag, 4, 1, ifp); + size = get4(); + end = ftell(ifp) + size; + if (!memcmp(tag,"RIFF",4) || !memcmp(tag,"LIST",4)) { + get4(); + while (ftell(ifp)+7 < end) + parse_riff(); + } else if (!memcmp(tag,"nctg",4)) { + while (ftell(ifp)+7 < end) { + i = get2(); + size = get2(); + if ((i+1) >> 1 == 10 && size == 20) + get_timestamp(0); + else fseek (ifp, size, SEEK_CUR); + } + } else if (!memcmp(tag,"IDIT",4) && size < 64) { + fread (date, 64, 1, ifp); + date[size] = 0; + memset (&t, 0, sizeof t); + if (sscanf (date, "%*s %s %d %d:%d:%d %d", month, &t.tm_mday, + &t.tm_hour, &t.tm_min, &t.tm_sec, &t.tm_year) == 6) { + for (i=0; i < 12 && strcasecmp(mon[i],month); i++); + t.tm_mon = i; + t.tm_year -= 1900; + if (mktime(&t) > 0) + timestamp = mktime(&t); + } + } else + fseek (ifp, size, SEEK_CUR); +} + +void CLASS parse_smal (int offset, int fsize) +{ + int ver; + + fseek (ifp, offset+2, SEEK_SET); + order = 0x4949; + ver = fgetc(ifp); + if (ver == 6) + fseek (ifp, 5, SEEK_CUR); + if (get4() != fsize) return; + if (ver > 6) data_offset = get4(); + raw_height = height = get2(); + raw_width = width = get2(); + strcpy (make, "SMaL"); + sprintf (model, "v%d %dx%d", ver, width, height); + if (ver == 6) load_raw = &CLASS smal_v6_load_raw; + if (ver == 9) load_raw = &CLASS smal_v9_load_raw; +} + +void CLASS parse_cine() +{ + unsigned off_head, off_setup, off_image, i; + + order = 0x4949; + fseek (ifp, 4, SEEK_SET); + is_raw = get2() == 2; + fseek (ifp, 14, SEEK_CUR); + is_raw *= get4(); + off_head = get4(); + off_setup = get4(); + off_image = get4(); + timestamp = get4(); + if ((i = get4())) timestamp = i; + fseek (ifp, off_head+4, SEEK_SET); + raw_width = get4(); + raw_height = get4(); + switch (get2(),get2()) { + case 8: load_raw = &CLASS eight_bit_load_raw; break; + case 16: load_raw = &CLASS unpacked_load_raw; + } + fseek (ifp, off_setup+792, SEEK_SET); + strcpy (make, "CINE"); + sprintf (model, "%d", get4()); + fseek (ifp, 12, SEEK_CUR); + switch ((i=get4()) & 0xffffff) { + case 3: filters = 0x94949494; break; + case 4: filters = 0x49494949; break; + default: is_raw = 0; + } + fseek (ifp, 72, SEEK_CUR); + switch ((get4()+3600) % 360) { + case 270: flip = 4; break; + case 180: flip = 1; break; + case 90: flip = 7; break; + case 0: flip = 2; + } + cam_mul[0] = getreal(11); + cam_mul[2] = getreal(11); + maximum = ~(-1 << get4()); + fseek (ifp, 668, SEEK_CUR); + shutter = get4()/1000000000.0; + fseek (ifp, off_image, SEEK_SET); + if (shot_select < is_raw) + fseek (ifp, shot_select*8, SEEK_CUR); + data_offset = (INT64) get4() + 8; + data_offset += (INT64) get4() << 32; +} + +char * CLASS foveon_gets (int offset, char *str, int len) +{ + int i; + fseek (ifp, offset, SEEK_SET); + for (i=0; i < len-1; i++) + if ((str[i] = get2()) == 0) break; + str[i] = 0; + return str; +} + +void CLASS parse_foveon() +{ + int entries, img=0, off, len, tag, save, i, wide, high, pent, poff[256][2]; + char name[64], value[64]; + + order = 0x4949; /* Little-endian */ + fseek (ifp, 36, SEEK_SET); + flip = get4(); + fseek (ifp, -4, SEEK_END); + fseek (ifp, get4(), SEEK_SET); + if (get4() != 0x64434553) return; /* SECd */ + entries = (get4(),get4()); + while (entries--) { + off = get4(); + len = get4(); + tag = get4(); + save = ftell(ifp); + fseek (ifp, off, SEEK_SET); + if (get4() != (0x20434553 | (tag << 24))) return; + switch (tag) { + case 0x47414d49: /* IMAG */ + case 0x32414d49: /* IMA2 */ + fseek (ifp, 12, SEEK_CUR); + wide = get4(); + high = get4(); + if (wide > raw_width && high > raw_height) { + raw_width = wide; + raw_height = high; + data_offset = off+24; + } + fseek (ifp, off+28, SEEK_SET); + if (fgetc(ifp) == 0xff && fgetc(ifp) == 0xd8 + && thumb_length < len-28) { + thumb_offset = off+28; + thumb_length = len-28; + write_thumb = &CLASS jpeg_thumb; + } + if (++img == 2 && !thumb_length) { + thumb_offset = off+24; + thumb_width = wide; + thumb_height = high; + write_thumb = &CLASS foveon_thumb; + } + break; + case 0x464d4143: /* CAMF */ + meta_offset = off+24; + meta_length = len-28; + if (meta_length > 0x20000) + meta_length = 0x20000; + break; + case 0x504f5250: /* PROP */ + pent = (get4(),get4()); + fseek (ifp, 12, SEEK_CUR); + off += pent*8 + 24; + if ((unsigned) pent > 256) pent=256; + for (i=0; i < pent*2; i++) + poff[0][i] = off + get4()*2; + for (i=0; i < pent; i++) { + foveon_gets (poff[i][0], name, 64); + foveon_gets (poff[i][1], value, 64); + if (!strcmp (name, "ISO")) + iso_speed = atoi(value); + if (!strcmp (name, "CAMMANUF")) + strcpy (make, value); + if (!strcmp (name, "CAMMODEL")) + strcpy (model, value); + if (!strcmp (name, "WB_DESC")) + strcpy (model2, value); + if (!strcmp (name, "TIME")) + timestamp = atoi(value); + if (!strcmp (name, "EXPTIME")) + shutter = atoi(value) / 1000000.0; + if (!strcmp (name, "APERTURE")) + aperture = atof(value); + if (!strcmp (name, "FLENGTH")) + focal_len = atof(value); + } +#ifdef LOCALTIME + timestamp = mktime (gmtime (×tamp)); +#endif + } + fseek (ifp, save, SEEK_SET); + } + is_foveon = 1; +} + +/* + All matrices are from Adobe DNG Converter unless otherwise noted. + */ +void CLASS adobe_coeff (const char *make, const char *model) +{ + static const struct { + const char *prefix; + short black, maximum, trans[12]; + } table[] = { + { "AGFAPHOTO DC-833m", 0, 0, /* DJC */ + { 11438,-3762,-1115,-2409,9914,2497,-1227,2295,5300 } }, + { "Apple QuickTake", 0, 0, /* DJC */ + { 21392,-5653,-3353,2406,8010,-415,7166,1427,2078 } }, + { "Canon EOS D2000", 0, 0, + { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } }, + { "Canon EOS D6000", 0, 0, + { 20482,-7172,-3125,-1033,10410,-285,2542,226,3136 } }, + { "Canon EOS D30", 0, 0, + { 9805,-2689,-1312,-5803,13064,3068,-2438,3075,8775 } }, + { "Canon EOS D60", 0, 0xfa0, + { 6188,-1341,-890,-7168,14489,2937,-2640,3228,8483 } }, + { "Canon EOS 5D Mark II", 0, 0x3cf0, + { 4716,603,-830,-7798,15474,2480,-1496,1937,6651 } }, + { "Canon EOS 5D", 0, 0xe6c, + { 6347,-479,-972,-8297,15954,2480,-1968,2131,7649 } }, + { "Canon EOS 7D", 0, 0x3510, + { 6844,-996,-856,-3876,11761,2396,-593,1772,6198 } }, + { "Canon EOS 10D", 0, 0xfa0, + { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } }, + { "Canon EOS 20Da", 0, 0, + { 14155,-5065,-1382,-6550,14633,2039,-1623,1824,6561 } }, + { "Canon EOS 20D", 0, 0xfff, + { 6599,-537,-891,-8071,15783,2424,-1983,2234,7462 } }, + { "Canon EOS 30D", 0, 0, + { 6257,-303,-1000,-7880,15621,2396,-1714,1904,7046 } }, + { "Canon EOS 40D", 0, 0x3f60, + { 6071,-747,-856,-7653,15365,2441,-2025,2553,7315 } }, + { "Canon EOS 50D", 0, 0x3d93, + { 4920,616,-593,-6493,13964,2784,-1774,3178,7005 } }, + { "Canon EOS 300D", 0, 0xfa0, + { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } }, + { "Canon EOS 350D", 0, 0xfff, + { 6018,-617,-965,-8645,15881,2975,-1530,1719,7642 } }, + { "Canon EOS 400D", 0, 0xe8e, + { 7054,-1501,-990,-8156,15544,2812,-1278,1414,7796 } }, + { "Canon EOS 450D", 0, 0x390d, + { 5784,-262,-821,-7539,15064,2672,-1982,2681,7427 } }, + { "Canon EOS 500D", 0, 0x3479, + { 4763,712,-646,-6821,14399,2640,-1921,3276,6561 } }, + { "Canon EOS 1000D", 0, 0xe43, + { 6771,-1139,-977,-7818,15123,2928,-1244,1437,7533 } }, + { "Canon EOS-1Ds Mark III", 0, 0x3bb0, + { 5859,-211,-930,-8255,16017,2353,-1732,1887,7448 } }, + { "Canon EOS-1Ds Mark II", 0, 0xe80, + { 6517,-602,-867,-8180,15926,2378,-1618,1771,7633 } }, + { "Canon EOS-1D Mark IV", 0, 0x3bb0, + { 6014,-220,-795,-4109,12014,2361,-561,1824,5787 } }, + { "Canon EOS-1D Mark III", 0, 0x3bb0, + { 6291,-540,-976,-8350,16145,2311,-1714,1858,7326 } }, + { "Canon EOS-1D Mark II N", 0, 0xe80, + { 6240,-466,-822,-8180,15825,2500,-1801,1938,8042 } }, + { "Canon EOS-1D Mark II", 0, 0xe80, + { 6264,-582,-724,-8312,15948,2504,-1744,1919,8664 } }, + { "Canon EOS-1DS", 0, 0xe20, + { 4374,3631,-1743,-7520,15212,2472,-2892,3632,8161 } }, + { "Canon EOS-1D", 0, 0xe20, + { 6806,-179,-1020,-8097,16415,1687,-3267,4236,7690 } }, + { "Canon EOS", 0, 0, + { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } }, + { "Canon PowerShot A530", 0, 0, + { 0 } }, /* don't want the A5 matrix */ + { "Canon PowerShot A50", 0, 0, + { -5300,9846,1776,3436,684,3939,-5540,9879,6200,-1404,11175,217 } }, + { "Canon PowerShot A5", 0, 0, + { -4801,9475,1952,2926,1611,4094,-5259,10164,5947,-1554,10883,547 } }, + { "Canon PowerShot G10", 0, 0, + { 11093,-3906,-1028,-5047,12492,2879,-1003,1750,5561 } }, + { "Canon PowerShot G11", 0, 0, + { 12177,-4817,-1069,-1612,9864,2049,-98,850,4471 } }, + { "Canon PowerShot G1", 0, 0, + { -4778,9467,2172,4743,-1141,4344,-5146,9908,6077,-1566,11051,557 } }, + { "Canon PowerShot G2", 0, 0, + { 9087,-2693,-1049,-6715,14382,2537,-2291,2819,7790 } }, + { "Canon PowerShot G3", 0, 0, + { 9212,-2781,-1073,-6573,14189,2605,-2300,2844,7664 } }, + { "Canon PowerShot G5", 0, 0, + { 9757,-2872,-933,-5972,13861,2301,-1622,2328,7212 } }, + { "Canon PowerShot G6", 0, 0, + { 9877,-3775,-871,-7613,14807,3072,-1448,1305,7485 } }, + { "Canon PowerShot G9", 0, 0, + { 7368,-2141,-598,-5621,13254,2625,-1418,1696,5743 } }, + { "Canon PowerShot Pro1", 0, 0, + { 10062,-3522,-999,-7643,15117,2730,-765,817,7323 } }, + { "Canon PowerShot Pro70", 34, 0, + { -4155,9818,1529,3939,-25,4522,-5521,9870,6610,-2238,10873,1342 } }, + { "Canon PowerShot Pro90", 0, 0, + { -4963,9896,2235,4642,-987,4294,-5162,10011,5859,-1770,11230,577 } }, + { "Canon PowerShot S30", 0, 0, + { 10566,-3652,-1129,-6552,14662,2006,-2197,2581,7670 } }, + { "Canon PowerShot S40", 0, 0, + { 8510,-2487,-940,-6869,14231,2900,-2318,2829,9013 } }, + { "Canon PowerShot S45", 0, 0, + { 8163,-2333,-955,-6682,14174,2751,-2077,2597,8041 } }, + { "Canon PowerShot S50", 0, 0, + { 8882,-2571,-863,-6348,14234,2288,-1516,2172,6569 } }, + { "Canon PowerShot S60", 0, 0, + { 8795,-2482,-797,-7804,15403,2573,-1422,1996,7082 } }, + { "Canon PowerShot S70", 0, 0, + { 9976,-3810,-832,-7115,14463,2906,-901,989,7889 } }, + { "Canon PowerShot S90", 0, 0, + { 12374,-5016,-1049,-1677,9902,2078,-83,852,4683 } }, + { "Canon PowerShot A470", 0, 0, /* DJC */ + { 12513,-4407,-1242,-2680,10276,2405,-878,2215,4734 } }, + { "Canon PowerShot A610", 0, 0, /* DJC */ + { 15591,-6402,-1592,-5365,13198,2168,-1300,1824,5075 } }, + { "Canon PowerShot A620", 0, 0, /* DJC */ + { 15265,-6193,-1558,-4125,12116,2010,-888,1639,5220 } }, + { "Canon PowerShot A630", 0, 0, /* DJC */ + { 14201,-5308,-1757,-6087,14472,1617,-2191,3105,5348 } }, + { "Canon PowerShot A640", 0, 0, /* DJC */ + { 13124,-5329,-1390,-3602,11658,1944,-1612,2863,4885 } }, + { "Canon PowerShot A650", 0, 0, /* DJC */ + { 9427,-3036,-959,-2581,10671,1911,-1039,1982,4430 } }, + { "Canon PowerShot A720", 0, 0, /* DJC */ + { 14573,-5482,-1546,-1266,9799,1468,-1040,1912,3810 } }, + { "Canon PowerShot S3 IS", 0, 0, /* DJC */ + { 14062,-5199,-1446,-4712,12470,2243,-1286,2028,4836 } }, + { "Canon PowerShot SX1 IS", 0, 0, + { 6578,-259,-502,-5974,13030,3309,-308,1058,4970 } }, + { "Canon PowerShot SX110 IS", 0, 0, /* DJC */ + { 14134,-5576,-1527,-1991,10719,1273,-1158,1929,3581 } }, + { "CASIO EX-S20", 0, 0, /* DJC */ + { 11634,-3924,-1128,-4968,12954,2015,-1588,2648,7206 } }, + { "CASIO EX-Z750", 0, 0, /* DJC */ + { 10819,-3873,-1099,-4903,13730,1175,-1755,3751,4632 } }, + { "CINE 650", 0, 0, + { 3390,480,-500,-800,3610,340,-550,2336,1192 } }, + { "CINE 660", 0, 0, + { 3390,480,-500,-800,3610,340,-550,2336,1192 } }, + { "CINE", 0, 0, + { 20183,-4295,-423,-3940,15330,3985,-280,4870,9800 } }, + { "Contax N Digital", 0, 0xf1e, + { 7777,1285,-1053,-9280,16543,2916,-3677,5679,7060 } }, + { "EPSON R-D1", 0, 0, + { 6827,-1878,-732,-8429,16012,2564,-704,592,7145 } }, + { "FUJIFILM FinePix E550", 0, 0, + { 11044,-3888,-1120,-7248,15168,2208,-1531,2277,8069 } }, + { "FUJIFILM FinePix E900", 0, 0, + { 9183,-2526,-1078,-7461,15071,2574,-2022,2440,8639 } }, + { "FUJIFILM FinePix F8", 0, 0, + { 11044,-3888,-1120,-7248,15168,2208,-1531,2277,8069 } }, + { "FUJIFILM FinePix F7", 0, 0, + { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } }, + { "FUJIFILM FinePix S100FS", 514, 0, + { 11521,-4355,-1065,-6524,13767,3058,-1466,1984,6045 } }, + { "FUJIFILM FinePix S20Pro", 0, 0, + { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } }, + { "FUJIFILM FinePix S2Pro", 128, 0, + { 12492,-4690,-1402,-7033,15423,1647,-1507,2111,7697 } }, + { "FUJIFILM FinePix S3Pro", 0, 0, + { 11807,-4612,-1294,-8927,16968,1988,-2120,2741,8006 } }, + { "FUJIFILM FinePix S5Pro", 0, 0, + { 12300,-5110,-1304,-9117,17143,1998,-1947,2448,8100 } }, + { "FUJIFILM FinePix S5000", 0, 0, + { 8754,-2732,-1019,-7204,15069,2276,-1702,2334,6982 } }, + { "FUJIFILM FinePix S5100", 0, 0x3e00, + { 11940,-4431,-1255,-6766,14428,2542,-993,1165,7421 } }, + { "FUJIFILM FinePix S5500", 0, 0x3e00, + { 11940,-4431,-1255,-6766,14428,2542,-993,1165,7421 } }, + { "FUJIFILM FinePix S5200", 0, 0, + { 9636,-2804,-988,-7442,15040,2589,-1803,2311,8621 } }, + { "FUJIFILM FinePix S5600", 0, 0, + { 9636,-2804,-988,-7442,15040,2589,-1803,2311,8621 } }, + { "FUJIFILM FinePix S6", 0, 0, + { 12628,-4887,-1401,-6861,14996,1962,-2198,2782,7091 } }, + { "FUJIFILM FinePix S7000", 0, 0, + { 10190,-3506,-1312,-7153,15051,2238,-2003,2399,7505 } }, + { "FUJIFILM FinePix S9000", 0, 0, + { 10491,-3423,-1145,-7385,15027,2538,-1809,2275,8692 } }, + { "FUJIFILM FinePix S9500", 0, 0, + { 10491,-3423,-1145,-7385,15027,2538,-1809,2275,8692 } }, + { "FUJIFILM FinePix S9100", 0, 0, + { 12343,-4515,-1285,-7165,14899,2435,-1895,2496,8800 } }, + { "FUJIFILM FinePix S9600", 0, 0, + { 12343,-4515,-1285,-7165,14899,2435,-1895,2496,8800 } }, + { "FUJIFILM IS-1", 0, 0, + { 21461,-10807,-1441,-2332,10599,1999,289,875,7703 } }, + { "FUJIFILM IS Pro", 0, 0, + { 12300,-5110,-1304,-9117,17143,1998,-1947,2448,8100 } }, + { "Imacon Ixpress", 0, 0, /* DJC */ + { 7025,-1415,-704,-5188,13765,1424,-1248,2742,6038 } }, + { "KODAK NC2000", 0, 0, + { 13891,-6055,-803,-465,9919,642,2121,82,1291 } }, + { "Kodak DCS315C", 8, 0, + { 17523,-4827,-2510,756,8546,-137,6113,1649,2250 } }, + { "Kodak DCS330C", 8, 0, + { 20620,-7572,-2801,-103,10073,-396,3551,-233,2220 } }, + { "KODAK DCS420", 0, 0, + { 10868,-1852,-644,-1537,11083,484,2343,628,2216 } }, + { "KODAK DCS460", 0, 0, + { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } }, + { "KODAK EOSDCS1", 0, 0, + { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } }, + { "KODAK EOSDCS3B", 0, 0, + { 9898,-2700,-940,-2478,12219,206,1985,634,1031 } }, + { "Kodak DCS520C", 180, 0, + { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } }, + { "Kodak DCS560C", 188, 0, + { 20482,-7172,-3125,-1033,10410,-285,2542,226,3136 } }, + { "Kodak DCS620C", 180, 0, + { 23617,-10175,-3149,-2054,11749,-272,2586,-489,3453 } }, + { "Kodak DCS620X", 185, 0, + { 13095,-6231,154,12221,-21,-2137,895,4602,2258 } }, + { "Kodak DCS660C", 214, 0, + { 18244,-6351,-2739,-791,11193,-521,3711,-129,2802 } }, + { "Kodak DCS720X", 0, 0, + { 11775,-5884,950,9556,1846,-1286,-1019,6221,2728 } }, + { "Kodak DCS760C", 0, 0, + { 16623,-6309,-1411,-4344,13923,323,2285,274,2926 } }, + { "Kodak DCS Pro SLR", 0, 0, + { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } }, + { "Kodak DCS Pro 14nx", 0, 0, + { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } }, + { "Kodak DCS Pro 14", 0, 0, + { 7791,3128,-776,-8588,16458,2039,-2455,4006,6198 } }, + { "Kodak ProBack645", 0, 0, + { 16414,-6060,-1470,-3555,13037,473,2545,122,4948 } }, + { "Kodak ProBack", 0, 0, + { 21179,-8316,-2918,-915,11019,-165,3477,-180,4210 } }, + { "KODAK P712", 0, 0, + { 9658,-3314,-823,-5163,12695,2768,-1342,1843,6044 } }, + { "KODAK P850", 0, 0xf7c, + { 10511,-3836,-1102,-6946,14587,2558,-1481,1792,6246 } }, + { "KODAK P880", 0, 0xfff, + { 12805,-4662,-1376,-7480,15267,2360,-1626,2194,7904 } }, + { "KODAK EasyShare Z980", 0, 0, + { 11313,-3559,-1101,-3893,11891,2257,-1214,2398,4908 } }, + { "KODAK EASYSHARE Z1015", 0, 0xef1, + { 11265,-4286,-992,-4694,12343,2647,-1090,1523,5447 } }, + { "Leaf CMost", 0, 0, + { 3952,2189,449,-6701,14585,2275,-4536,7349,6536 } }, + { "Leaf Valeo 6", 0, 0, + { 3952,2189,449,-6701,14585,2275,-4536,7349,6536 } }, + { "Leaf Aptus 54S", 0, 0, + { 8236,1746,-1314,-8251,15953,2428,-3673,5786,5771 } }, + { "Leaf Aptus 65", 0, 0, + { 7914,1414,-1190,-8777,16582,2280,-2811,4605,5562 } }, + { "Leaf Aptus 75", 0, 0, + { 7914,1414,-1190,-8777,16582,2280,-2811,4605,5562 } }, + { "Leaf", 0, 0, + { 8236,1746,-1314,-8251,15953,2428,-3673,5786,5771 } }, + { "Mamiya ZD", 0, 0, + { 7645,2579,-1363,-8689,16717,2015,-3712,5941,5961 } }, + { "Micron 2010", 110, 0, /* DJC */ + { 16695,-3761,-2151,155,9682,163,3433,951,4904 } }, + { "Minolta DiMAGE 5", 0, 0xf7d, + { 8983,-2942,-963,-6556,14476,2237,-2426,2887,8014 } }, + { "Minolta DiMAGE 7Hi", 0, 0xf7d, + { 11368,-3894,-1242,-6521,14358,2339,-2475,3056,7285 } }, + { "Minolta DiMAGE 7", 0, 0xf7d, + { 9144,-2777,-998,-6676,14556,2281,-2470,3019,7744 } }, + { "Minolta DiMAGE A1", 0, 0xf8b, + { 9274,-2547,-1167,-8220,16323,1943,-2273,2720,8340 } }, + { "MINOLTA DiMAGE A200", 0, 0, + { 8560,-2487,-986,-8112,15535,2771,-1209,1324,7743 } }, + { "Minolta DiMAGE A2", 0, 0xf8f, + { 9097,-2726,-1053,-8073,15506,2762,-966,981,7763 } }, + { "Minolta DiMAGE Z2", 0, 0, /* DJC */ + { 11280,-3564,-1370,-4655,12374,2282,-1423,2168,5396 } }, + { "MINOLTA DYNAX 5", 0, 0xffb, + { 10284,-3283,-1086,-7957,15762,2316,-829,882,6644 } }, + { "MINOLTA DYNAX 7", 0, 0xffb, + { 10239,-3104,-1099,-8037,15727,2451,-927,925,6871 } }, + { "MOTOROLA PIXL", 0, 0, /* DJC */ + { 8898,-989,-1033,-3292,11619,1674,-661,3178,5216 } }, + { "NIKON D100", 0, 0, + { 5902,-933,-782,-8983,16719,2354,-1402,1455,6464 } }, + { "NIKON D1H", 0, 0, + { 7577,-2166,-926,-7454,15592,1934,-2377,2808,8606 } }, + { "NIKON D1X", 0, 0, + { 7702,-2245,-975,-9114,17242,1875,-2679,3055,8521 } }, + { "NIKON D1", 0, 0, /* multiplied by 2.218750, 1.0, 1.148438 */ + { 16772,-4726,-2141,-7611,15713,1972,-2846,3494,9521 } }, + { "NIKON D200", 0, 0xfbc, + { 8367,-2248,-763,-8758,16447,2422,-1527,1550,8053 } }, + { "NIKON D2H", 0, 0, + { 5710,-901,-615,-8594,16617,2024,-2975,4120,6830 } }, + { "NIKON D2X", 0, 0, + { 10231,-2769,-1255,-8301,15900,2552,-797,680,7148 } }, + { "NIKON D3000", 0, 0, + { 8736,-2458,-935,-9075,16894,2251,-1354,1242,8263 } }, + { "NIKON D300", 0, 0, + { 9030,-1992,-715,-8465,16302,2255,-2689,3217,8069 } }, + { "NIKON D3X", 0, 0, + { 7171,-1986,-648,-8085,15555,2718,-2170,2512,7457 } }, + { "NIKON D3S", 0, 0, + { 8828,-2406,-694,-4874,12603,2541,-660,1509,7587 } }, + { "NIKON D3", 0, 0, + { 8139,-2171,-663,-8747,16541,2295,-1925,2008,8093 } }, + { "NIKON D40X", 0, 0, + { 8819,-2543,-911,-9025,16928,2151,-1329,1213,8449 } }, + { "NIKON D40", 0, 0, + { 6992,-1668,-806,-8138,15748,2543,-874,850,7897 } }, + { "NIKON D5000", 0, 0xf00, + { 7309,-1403,-519,-8474,16008,2622,-2433,2826,8064 } }, + { "NIKON D50", 0, 0, + { 7732,-2422,-789,-8238,15884,2498,-859,783,7330 } }, + { "NIKON D60", 0, 0, + { 8736,-2458,-935,-9075,16894,2251,-1354,1242,8263 } }, + { "NIKON D700", 0, 0, + { 8139,-2171,-663,-8747,16541,2295,-1925,2008,8093 } }, + { "NIKON D70", 0, 0, + { 7732,-2422,-789,-8238,15884,2498,-859,783,7330 } }, + { "NIKON D80", 0, 0, + { 8629,-2410,-883,-9055,16940,2171,-1490,1363,8520 } }, + { "NIKON D90", 0, 0xf00, + { 7309,-1403,-519,-8474,16008,2622,-2434,2826,8064 } }, + { "NIKON E950", 0, 0x3dd, /* DJC */ + { -3746,10611,1665,9621,-1734,2114,-2389,7082,3064,3406,6116,-244 } }, + { "NIKON E995", 0, 0, /* copied from E5000 */ + { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, + { "NIKON E2100", 0, 0, /* copied from Z2, new white balance */ + { 13142,-4152,-1596,-4655,12374,2282,-1769,2696,6711} }, + { "NIKON E2500", 0, 0, + { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, + { "NIKON E4300", 0, 0, /* copied from Minolta DiMAGE Z2 */ + { 11280,-3564,-1370,-4655,12374,2282,-1423,2168,5396 } }, + { "NIKON E4500", 0, 0, + { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, + { "NIKON E5000", 0, 0, + { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, + { "NIKON E5400", 0, 0, + { 9349,-2987,-1001,-7919,15766,2266,-2098,2680,6839 } }, + { "NIKON E5700", 0, 0, + { -5368,11478,2368,5537,-113,3148,-4969,10021,5782,778,9028,211 } }, + { "NIKON E8400", 0, 0, + { 7842,-2320,-992,-8154,15718,2599,-1098,1342,7560 } }, + { "NIKON E8700", 0, 0, + { 8489,-2583,-1036,-8051,15583,2643,-1307,1407,7354 } }, + { "NIKON E8800", 0, 0, + { 7971,-2314,-913,-8451,15762,2894,-1442,1520,7610 } }, + { "NIKON COOLPIX P6000", 0, 0, + { 9698,-3367,-914,-4706,12584,2368,-837,968,5801 } }, + { "OLYMPUS C5050", 0, 0, + { 10508,-3124,-1273,-6079,14294,1901,-1653,2306,6237 } }, + { "OLYMPUS C5060", 0, 0, + { 10445,-3362,-1307,-7662,15690,2058,-1135,1176,7602 } }, + { "OLYMPUS C7070", 0, 0, + { 10252,-3531,-1095,-7114,14850,2436,-1451,1723,6365 } }, + { "OLYMPUS C70", 0, 0, + { 10793,-3791,-1146,-7498,15177,2488,-1390,1577,7321 } }, + { "OLYMPUS C80", 0, 0, + { 8606,-2509,-1014,-8238,15714,2703,-942,979,7760 } }, + { "OLYMPUS E-10", 0, 0xffc0, + { 12745,-4500,-1416,-6062,14542,1580,-1934,2256,6603 } }, + { "OLYMPUS E-1", 0, 0xfff0, + { 11846,-4767,-945,-7027,15878,1089,-2699,4122,8311 } }, + { "OLYMPUS E-20", 0, 0xffc0, + { 13173,-4732,-1499,-5807,14036,1895,-2045,2452,7142 } }, + { "OLYMPUS E-300", 0, 0, + { 7828,-1761,-348,-5788,14071,1830,-2853,4518,6557 } }, + { "OLYMPUS E-330", 0, 0, + { 8961,-2473,-1084,-7979,15990,2067,-2319,3035,8249 } }, + { "OLYMPUS E-30", 0, 0xfbc, + { 8144,-1861,-1111,-7763,15894,1929,-1865,2542,7607 } }, + { "OLYMPUS E-3", 0, 0xf99, + { 9487,-2875,-1115,-7533,15606,2010,-1618,2100,7389 } }, + { "OLYMPUS E-400", 0, 0xfff0, + { 6169,-1483,-21,-7107,14761,2536,-2904,3580,8568 } }, + { "OLYMPUS E-410", 0, 0xf6a, + { 8856,-2582,-1026,-7761,15766,2082,-2009,2575,7469 } }, + { "OLYMPUS E-420", 0, 0xfd7, + { 8746,-2425,-1095,-7594,15612,2073,-1780,2309,7416 } }, + { "OLYMPUS E-450", 0, 0xfd2, + { 8745,-2425,-1095,-7594,15613,2073,-1780,2309,7416 } }, + { "OLYMPUS E-500", 0, 0xfff0, + { 8136,-1968,-299,-5481,13742,1871,-2556,4205,6630 } }, + { "OLYMPUS E-510", 0, 0xf6a, + { 8785,-2529,-1033,-7639,15624,2112,-1783,2300,7817 } }, + { "OLYMPUS E-520", 0, 0xfd2, + { 8344,-2322,-1020,-7596,15635,2048,-1748,2269,7287 } }, + { "OLYMPUS E-620", 0, 0xfb9, + { 8453,-2198,-1092,-7609,15681,2008,-1725,2337,7824 } }, + { "OLYMPUS E-P1", 0, 0xffd, + { 8343,-2050,-1021,-7715,15705,2103,-1831,2380,8235 } }, + { "OLYMPUS SP350", 0, 0, + { 12078,-4836,-1069,-6671,14306,2578,-786,939,7418 } }, + { "OLYMPUS SP3", 0, 0, + { 11766,-4445,-1067,-6901,14421,2707,-1029,1217,7572 } }, + { "OLYMPUS SP500UZ", 0, 0xfff, + { 9493,-3415,-666,-5211,12334,3260,-1548,2262,6482 } }, + { "OLYMPUS SP510UZ", 0, 0xffe, + { 10593,-3607,-1010,-5881,13127,3084,-1200,1805,6721 } }, + { "OLYMPUS SP550UZ", 0, 0xffe, + { 11597,-4006,-1049,-5432,12799,2957,-1029,1750,6516 } }, + { "OLYMPUS SP560UZ", 0, 0xff9, + { 10915,-3677,-982,-5587,12986,2911,-1168,1968,6223 } }, + { "OLYMPUS SP570UZ", 0, 0, + { 11522,-4044,-1146,-4736,12172,2904,-988,1829,6039 } }, + { "PENTAX *ist DL2", 0, 0, + { 10504,-2438,-1189,-8603,16207,2531,-1022,863,12242 } }, + { "PENTAX *ist DL", 0, 0, + { 10829,-2838,-1115,-8339,15817,2696,-837,680,11939 } }, + { "PENTAX *ist DS2", 0, 0, + { 10504,-2438,-1189,-8603,16207,2531,-1022,863,12242 } }, + { "PENTAX *ist DS", 0, 0, + { 10371,-2333,-1206,-8688,16231,2602,-1230,1116,11282 } }, + { "PENTAX *ist D", 0, 0, + { 9651,-2059,-1189,-8881,16512,2487,-1460,1345,10687 } }, + { "PENTAX K10D", 0, 0, + { 9566,-2863,-803,-7170,15172,2112,-818,803,9705 } }, + { "PENTAX K1", 0, 0, + { 11095,-3157,-1324,-8377,15834,2720,-1108,947,11688 } }, + { "PENTAX K20D", 0, 0, + { 9427,-2714,-868,-7493,16092,1373,-2199,3264,7180 } }, + { "PENTAX K200D", 0, 0, + { 9186,-2678,-907,-8693,16517,2260,-1129,1094,8524 } }, + { "PENTAX K2000", 0, 0, + { 11057,-3604,-1155,-5152,13046,2329,-282,375,8104 } }, + { "PENTAX K-m", 0, 0, + { 11057,-3604,-1155,-5152,13046,2329,-282,375,8104 } }, + { "PENTAX K-x", 0, 0, + { 8843,-2837,-625,-5025,12644,2668,-411,1234,7410 } }, + { "PENTAX K-7", 0, 0, + { 9142,-2947,-678,-8648,16967,1663,-2224,2898,8615 } }, + { "Panasonic DMC-FZ8", 0, 0xf7f0, + { 8986,-2755,-802,-6341,13575,3077,-1476,2144,6379 } }, + { "Panasonic DMC-FZ18", 0, 0, + { 9932,-3060,-935,-5809,13331,2753,-1267,2155,5575 } }, + { "Panasonic DMC-FZ28", 15, 0xfff, + { 10109,-3488,-993,-5412,12812,2916,-1305,2140,5543 } }, + { "Panasonic DMC-FZ30", 0, 0xf94c, + { 10976,-4029,-1141,-7918,15491,2600,-1670,2071,8246 } }, + { "Panasonic DMC-FZ35", 147, 0xfff, + { 9938,-2780,-890,-4604,12393,2480,-1117,2304,4620 } }, + { "Panasonic DMC-FZ50", 0, 0xfff0, /* aka "LEICA V-LUX1" */ + { 7906,-2709,-594,-6231,13351,3220,-1922,2631,6537 } }, + { "Panasonic DMC-L10", 15, 0xf96, + { 8025,-1942,-1050,-7920,15904,2100,-2456,3005,7039 } }, + { "Panasonic DMC-L1", 0, 0xf7fc, /* aka "LEICA DIGILUX 3" */ + { 8054,-1885,-1025,-8349,16367,2040,-2805,3542,7629 } }, + { "Panasonic DMC-LC1", 0, 0, /* aka "LEICA DIGILUX 2" */ + { 11340,-4069,-1275,-7555,15266,2448,-2960,3426,7685 } }, + { "Panasonic DMC-LX1", 0, 0xf7f0, /* aka "LEICA D-LUX2" */ + { 10704,-4187,-1230,-8314,15952,2501,-920,945,8927 } }, + { "Panasonic DMC-LX2", 0, 0, /* aka "LEICA D-LUX3" */ + { 8048,-2810,-623,-6450,13519,3272,-1700,2146,7049 } }, + { "Panasonic DMC-LX3", 15, 0xfff, /* aka "LEICA D-LUX4" */ + { 8128,-2668,-655,-6134,13307,3161,-1782,2568,6083 } }, + { "Panasonic DMC-FX150", 15, 0xfff, + { 9082,-2907,-925,-6119,13377,3058,-1797,2641,5609 } }, + { "Panasonic DMC-G1", 15, 0xfff, + { 8199,-2065,-1056,-8124,16156,2033,-2458,3022,7220 } }, + { "Panasonic DMC-GF1", 15, 0xf92, + { 7888,-1902,-1011,-8106,16085,2099,-2353,2866,7330 } }, + { "Panasonic DMC-GH1", 15, 0xf92, + { 6299,-1466,-532,-6535,13852,2969,-2331,3112,5984 } }, + { "Phase One H 20", 0, 0, /* DJC */ + { 1313,1855,-109,-6715,15908,808,-327,1840,6020 } }, + { "Phase One P 2", 0, 0, + { 2905,732,-237,-8134,16626,1476,-3038,4253,7517 } }, + { "Phase One P 30", 0, 0, + { 4516,-245,-37,-7020,14976,2173,-3206,4671,7087 } }, + { "Phase One P 45", 0, 0, + { 5053,-24,-117,-5684,14076,1702,-2619,4492,5849 } }, + { "Phase One P65", 0, 0, /* DJC */ + { 8522,1268,-1916,-7706,16350,1358,-2397,4344,4923 } }, + { "SAMSUNG GX-1", 0, 0, + { 10504,-2438,-1189,-8603,16207,2531,-1022,863,12242 } }, + { "SAMSUNG S85", 0, 0, /* DJC */ + { 11885,-3968,-1473,-4214,12299,1916,-835,1655,5549 } }, + { "Sinar", 0, 0, /* DJC */ + { 16442,-2956,-2422,-2877,12128,750,-1136,6066,4559 } }, + { "SONY DSC-F828", 491, 0, + { 7924,-1910,-777,-8226,15459,2998,-1517,2199,6818,-7242,11401,3481 } }, + { "SONY DSC-R1", 512, 0, + { 8512,-2641,-694,-8042,15670,2526,-1821,2117,7414 } }, + { "SONY DSC-V3", 0, 0, + { 7511,-2571,-692,-7894,15088,3060,-948,1111,8128 } }, + { "SONY DSLR-A100", 0, 0xfeb, + { 9437,-2811,-774,-8405,16215,2290,-710,596,7181 } }, + { "SONY DSLR-A200", 0, 0, + { 9847,-3091,-928,-8485,16345,2225,-715,595,7103 } }, + { "SONY DSLR-A230", 0, 0, /* copied */ + { 9847,-3091,-928,-8485,16345,2225,-715,595,7103 } }, + { "SONY DSLR-A300", 0, 0, + { 9847,-3091,-928,-8485,16345,2225,-715,595,7103 } }, + { "SONY DSLR-A330", 0, 0, + { 9847,-3091,-929,-8485,16346,2225,-714,595,7103 } }, + { "SONY DSLR-A350", 0, 0xffc, + { 6038,-1484,-578,-9146,16746,2513,-875,746,7217 } }, + { "SONY DSLR-A380", 0, 0, + { 6038,-1484,-579,-9145,16746,2512,-875,746,7218 } }, + { "SONY DSLR-A5", 254, 0x1ffe, + { 4950,-580,-103,-5228,12542,3029,-709,1435,7371 } }, + { "SONY DSLR-A700", 254, 0x1ffe, + { 5775,-805,-359,-8574,16295,2391,-1943,2341,7249 } }, + { "SONY DSLR-A850", 256, 0x1ffe, + { 5413,-1162,-365,-5665,13098,2866,-608,1179,8440 } }, + { "SONY DSLR-A900", 254, 0x1ffe, + { 5209,-1072,-397,-8845,16120,2919,-1618,1803,8654 } } + }; + double cam_xyz[4][3]; + char name[130]; + int i, j; + + sprintf (name, "%s %s", make, model); + for (i=0; i < sizeof table / sizeof *table; i++) + if (!strncmp (name, table[i].prefix, strlen(table[i].prefix))) { + if (table[i].black) black = (ushort) table[i].black; + if (table[i].maximum) maximum = (ushort) table[i].maximum; + if (table[i].trans[0]) { + for (j=0; j < 12; j++) + cam_xyz[0][j] = table[i].trans[j] / 10000.0; + cam_xyz_coeff (cam_xyz); + } + break; + } +} + +void CLASS simple_coeff (int index) +{ + static const float table[][12] = { + /* index 0 -- all Foveon cameras */ + { 1.4032,-0.2231,-0.1016,-0.5263,1.4816,0.017,-0.0112,0.0183,0.9113 }, + /* index 1 -- Kodak DC20 and DC25 */ + { 2.25,0.75,-1.75,-0.25,-0.25,0.75,0.75,-0.25,-0.25,-1.75,0.75,2.25 }, + /* index 2 -- Logitech Fotoman Pixtura */ + { 1.893,-0.418,-0.476,-0.495,1.773,-0.278,-1.017,-0.655,2.672 }, + /* index 3 -- Nikon E880, E900, and E990 */ + { -1.936280, 1.800443, -1.448486, 2.584324, + 1.405365, -0.524955, -0.289090, 0.408680, + -1.204965, 1.082304, 2.941367, -1.818705 } + }; + int i, c; + + for (raw_color = i=0; i < 3; i++) + FORCC rgb_cam[i][c] = table[index][i*colors+c]; +} + +short CLASS guess_byte_order (int words) +{ + uchar test[4][2]; + int t=2, msb; + double diff, sum[2] = {0,0}; + + fread (test[0], 2, 2, ifp); + for (words-=2; words--; ) { + fread (test[t], 2, 1, ifp); + for (msb=0; msb < 2; msb++) { + diff = (test[t^2][msb] << 8 | test[t^2][!msb]) + - (test[t ][msb] << 8 | test[t ][!msb]); + sum[msb] += diff*diff; + } + t = (t+1) & 3; + } + return sum[0] < sum[1] ? 0x4d4d : 0x4949; +} + +float CLASS find_green (int bps, int bite, int off0, int off1) +{ + UINT64 bitbuf=0; + int vbits, col, i, c; + ushort img[2][2064]; + double sum[]={0,0}; + + FORC(2) { + fseek (ifp, c ? off1:off0, SEEK_SET); + for (vbits=col=0; col < width; col++) { + for (vbits -= bps; vbits < 0; vbits += bite) { + bitbuf <<= bite; + for (i=0; i < bite; i+=8) + bitbuf |= (unsigned) (fgetc(ifp) << i); + } + img[c][col] = bitbuf << (64-bps-vbits) >> (64-bps); + } + } + FORC(width-1) { + sum[ c & 1] += ABS(img[0][c]-img[1][c+1]); + sum[~c & 1] += ABS(img[1][c]-img[0][c+1]); + } + return 100 * log(sum[0]/sum[1]); +} + +/* + Identify which camera created this file, and set global variables + accordingly. + */ +void CLASS identify() +{ + char head[32], *cp; + int hlen, fsize, i, c, is_canon; + struct jhead jh; + static const struct { + int fsize; + char make[12], model[19], withjpeg; + } table[] = { + { 62464, "Kodak", "DC20" ,0 }, + { 124928, "Kodak", "DC20" ,0 }, + { 1652736, "Kodak", "DCS200" ,0 }, + { 4159302, "Kodak", "C330" ,0 }, + { 4162462, "Kodak", "C330" ,0 }, + { 460800, "Kodak", "C603v" ,0 }, + { 614400, "Kodak", "C603v" ,0 }, + { 6163328, "Kodak", "C603" ,0 }, + { 6166488, "Kodak", "C603" ,0 }, + { 9116448, "Kodak", "C603y" ,0 }, + { 311696, "ST Micro", "STV680 VGA" ,0 }, /* SPYz */ + { 787456, "Creative", "PC-CAM 600" ,0 }, + { 1138688, "Minolta", "RD175" ,0 }, + { 3840000, "Foculus", "531C" ,0 }, + { 786432, "AVT", "F-080C" ,0 }, + { 1447680, "AVT", "F-145C" ,0 }, + { 1920000, "AVT", "F-201C" ,0 }, + { 5067304, "AVT", "F-510C" ,0 }, + { 10134608, "AVT", "F-510C" ,0 }, + { 16157136, "AVT", "F-810C" ,0 }, + { 1409024, "Sony", "XCD-SX910CR" ,0 }, + { 2818048, "Sony", "XCD-SX910CR" ,0 }, + { 3884928, "Micron", "2010" ,0 }, + { 6624000, "Pixelink", "A782" ,0 }, + { 13248000, "Pixelink", "A782" ,0 }, + { 6291456, "RoverShot","3320AF" ,0 }, + { 6553440, "Canon", "PowerShot A460" ,0 }, + { 6653280, "Canon", "PowerShot A530" ,0 }, + { 6573120, "Canon", "PowerShot A610" ,0 }, + { 9219600, "Canon", "PowerShot A620" ,0 }, + { 9243240, "Canon", "PowerShot A470" ,0 }, + { 10341600, "Canon", "PowerShot A720" ,0 }, + { 10383120, "Canon", "PowerShot A630" ,0 }, + { 12945240, "Canon", "PowerShot A640" ,0 }, + { 15636240, "Canon", "PowerShot A650" ,0 }, + { 5298000, "Canon", "PowerShot SD300" ,0 }, + { 7710960, "Canon", "PowerShot S3 IS" ,0 }, + { 15467760, "Canon", "PowerShot SX110 IS",0 }, + { 5939200, "OLYMPUS", "C770UZ" ,0 }, + { 1581060, "NIKON", "E900" ,1 }, /* or E900s,E910 */ + { 2465792, "NIKON", "E950" ,1 }, /* or E800,E700 */ + { 2940928, "NIKON", "E2100" ,1 }, /* or E2500 */ + { 4771840, "NIKON", "E990" ,1 }, /* or E995, Oly C3030Z */ + { 4775936, "NIKON", "E3700" ,1 }, /* or Optio 33WR */ + { 5869568, "NIKON", "E4300" ,1 }, /* or DiMAGE Z2 */ + { 5865472, "NIKON", "E4500" ,1 }, + { 7438336, "NIKON", "E5000" ,1 }, /* or E5700 */ + { 8998912, "NIKON", "COOLPIX S6" ,1 }, + { 1976352, "CASIO", "QV-2000UX" ,1 }, + { 3217760, "CASIO", "QV-3*00EX" ,1 }, + { 6218368, "CASIO", "QV-5700" ,1 }, + { 6054400, "CASIO", "QV-R41" ,1 }, + { 7530816, "CASIO", "QV-R51" ,1 }, + { 7684000, "CASIO", "QV-4000" ,1 }, + { 2937856, "CASIO", "EX-S20" ,1 }, + { 4948608, "CASIO", "EX-S100" ,1 }, + { 7542528, "CASIO", "EX-Z50" ,1 }, + { 7753344, "CASIO", "EX-Z55" ,1 }, + { 7816704, "CASIO", "EX-Z60" ,1 }, + { 10843712, "CASIO", "EX-Z75" ,1 }, + { 10834368, "CASIO", "EX-Z750" ,1 }, + { 12310144, "CASIO", "EX-Z850" ,1 }, + { 7426656, "CASIO", "EX-P505" ,1 }, + { 9313536, "CASIO", "EX-P600" ,1 }, + { 10979200, "CASIO", "EX-P700" ,1 }, + { 3178560, "PENTAX", "Optio S" ,1 }, + { 4841984, "PENTAX", "Optio S" ,1 }, + { 6114240, "PENTAX", "Optio S4" ,1 }, /* or S4i, CASIO EX-Z4 */ + { 10702848, "PENTAX", "Optio 750Z" ,1 }, + { 15980544, "AGFAPHOTO","DC-833m" ,1 }, + { 16098048, "SAMSUNG", "S85" ,1 }, + { 16215552, "SAMSUNG", "S85" ,1 }, + { 12582980, "Sinar", "" ,0 }, + { 33292868, "Sinar", "" ,0 }, + { 44390468, "Sinar", "" ,0 } }; + static const char *corp[] = + { "Canon", "NIKON", "EPSON", "KODAK", "Kodak", "OLYMPUS", "PENTAX", + "MINOLTA", "Minolta", "Konica", "CASIO", "Sinar", "Phase One", + "SAMSUNG", "Mamiya", "MOTOROLA" }; + + tiff_flip = flip = filters = -1; /* 0 is valid, so -1 is unknown */ + raw_height = raw_width = fuji_width = fuji_layout = cr2_slice[0] = 0; + maximum = height = width = top_margin = left_margin = 0; + cdesc[0] = desc[0] = artist[0] = make[0] = model[0] = model2[0] = 0; + iso_speed = shutter = aperture = focal_len = unique_id = 0; + memset (gpsdata, 0, sizeof gpsdata); + memset (white, 0, sizeof white); + thumb_offset = thumb_length = thumb_width = thumb_height = 0; + load_raw = thumb_load_raw = 0; + write_thumb = &CLASS jpeg_thumb; + data_offset = meta_length = tiff_bps = tiff_compress = 0; + kodak_cbpp = zero_after_ff = dng_version = load_flags = 0; + timestamp = shot_order = tiff_samples = black = is_foveon = 0; + mix_green = profile_length = data_error = zero_is_bad = 0; + pixel_aspect = is_raw = raw_color = 1; + tile_width = tile_length = INT_MAX; + for (i=0; i < 4; i++) { + cam_mul[i] = i == 1; + pre_mul[i] = i < 3; + FORC3 cmatrix[c][i] = 0; + FORC3 rgb_cam[c][i] = c == i; + } + colors = 3; + for (i=0; i < 0x4000; i++) curve[i] = i; + + order = get2(); + hlen = get4(); + fseek (ifp, 0, SEEK_SET); + fread (head, 1, 32, ifp); + fseek (ifp, 0, SEEK_END); + fsize = ftell(ifp); + if ((cp = (char *) memmem (head, 32, "MMMM", 4)) || + (cp = (char *) memmem (head, 32, "IIII", 4))) { + parse_phase_one (cp-head); + if (cp-head) parse_tiff(0); + } else if (order == 0x4949 || order == 0x4d4d) { + if (!memcmp (head+6,"HEAPCCDR",8)) { + data_offset = hlen; + parse_ciff (hlen, fsize - hlen); + } else { + parse_tiff(0); + } + } else if (!memcmp (head,"\xff\xd8\xff\xe1",4) && + !memcmp (head+6,"Exif",4)) { + fseek (ifp, 4, SEEK_SET); + data_offset = 4 + get2(); + fseek (ifp, data_offset, SEEK_SET); + if (fgetc(ifp) != 0xff) + parse_tiff(12); + thumb_offset = 0; + } else if (!memcmp (head+25,"ARECOYK",7)) { + strcpy (make, "Contax"); + strcpy (model,"N Digital"); + fseek (ifp, 33, SEEK_SET); + get_timestamp(1); + fseek (ifp, 60, SEEK_SET); + FORC4 cam_mul[c ^ (c >> 1)] = get4(); + } else if (!strcmp (head, "PXN")) { + strcpy (make, "Logitech"); + strcpy (model,"Fotoman Pixtura"); + } else if (!strcmp (head, "qktk")) { + strcpy (make, "Apple"); + strcpy (model,"QuickTake 100"); + } else if (!strcmp (head, "qktn")) { + strcpy (make, "Apple"); + strcpy (model,"QuickTake 150"); + } else if (!memcmp (head,"FUJIFILM",8)) { + fseek (ifp, 84, SEEK_SET); + thumb_offset = get4(); + thumb_length = get4(); + fseek (ifp, 92, SEEK_SET); + parse_fuji (get4()); + if (thumb_offset > 120) { + fseek (ifp, 120, SEEK_SET); + is_raw += (i = get4()) && 1; + if (is_raw == 2 && shot_select) + parse_fuji (i); + } + fseek (ifp, 100, SEEK_SET); + data_offset = get4(); + parse_tiff (thumb_offset+12); + } else if (!memcmp (head,"RIFF",4)) { + fseek (ifp, 0, SEEK_SET); + parse_riff(); + } else if (!memcmp (head,"\0\001\0\001\0@",6)) { + fseek (ifp, 6, SEEK_SET); + fread (make, 1, 8, ifp); + fread (model, 1, 8, ifp); + fread (model2, 1, 16, ifp); + data_offset = get2(); + get2(); + raw_width = get2(); + raw_height = get2(); + load_raw = &CLASS nokia_load_raw; + filters = 0x61616161; + } else if (!memcmp (head,"DSC-Image",9)) + parse_rollei(); + else if (!memcmp (head,"PWAD",4)) + parse_sinar_ia(); + else if (!memcmp (head,"\0MRM",4)) + parse_minolta(0); + else if (!memcmp (head,"FOVb",4)) + parse_foveon(); + else if (!memcmp (head,"CI",2)) + parse_cine(); + else + for (i=0; i < sizeof table / sizeof *table; i++) + if (fsize == table[i].fsize) { + strcpy (make, table[i].make ); + strcpy (model, table[i].model); + if (table[i].withjpeg) + parse_external_jpeg(); + } + if (make[0] == 0) parse_smal (0, fsize); + if (make[0] == 0) parse_jpeg (is_raw = 0); + + for (i=0; i < sizeof corp / sizeof *corp; i++) + if (strstr (make, corp[i])) /* Simplify company names */ + strcpy (make, corp[i]); + if (!strncmp (make,"KODAK",5) && + ((cp = strstr(model," DIGITAL CAMERA")) || + (cp = strstr(model," Digital Camera")) || + (cp = strstr(model,"FILE VERSION")))) + *cp = 0; + cp = make + strlen(make); /* Remove trailing spaces */ + while (*--cp == ' ') *cp = 0; + cp = model + strlen(model); + while (*--cp == ' ') *cp = 0; + i = strlen(make); /* Remove make from model */ + if (!strncasecmp (model, make, i) && model[i++] == ' ') + memmove (model, model+i, 64-i); + if (!strncmp (model,"Digital Camera ",15)) + strcpy (model, model+15); + desc[511] = artist[63] = make[63] = model[63] = model2[63] = 0; + if (!is_raw) goto notraw; + + if (!height) height = raw_height; + if (!width) width = raw_width; + if (fuji_width) { + width = height + fuji_width; + height = width - 1; + pixel_aspect = 1; + } + if (height == 2624 && width == 3936) /* Pentax K10D and Samsung GX10 */ + { height = 2616; width = 3896; } + if (height == 3136 && width == 4864) /* Pentax K20D */ + { height = 3124; width = 4688; } + if (height == 3136 && width == 4736) /* Pentax K-7 */ + { height = 3122; width = 4684; + top_margin = 2; filters = 0x16161616; } + if (height == 3014 && width == 4096) /* Ricoh GX200 */ + width = 4014; + if (dng_version) { + if (filters == UINT_MAX) filters = 0; + if (filters) is_raw = tiff_samples; + else colors = tiff_samples; + if (tiff_compress == 1) + load_raw = &CLASS adobe_dng_load_raw_nc; + if (tiff_compress == 7) + load_raw = &CLASS adobe_dng_load_raw_lj; + goto dng_skip; + } + if ((is_canon = !strcmp(make,"Canon"))) + load_raw = memcmp (head+6,"HEAPCCDR",8) ? + &CLASS lossless_jpeg_load_raw : &CLASS canon_compressed_load_raw; + if (!strcmp(make,"NIKON")) { + if (!load_raw) + load_raw = &CLASS packed_load_raw; + if (model[0] == 'E') + load_flags |= !data_offset << 2 | 2; + } + if (!strcmp(make,"CASIO")) { + load_raw = &CLASS packed_load_raw; + maximum = 0xf7f; + } + +/* Set parameters based on camera name (for non-DNG files). */ + + if (is_foveon) { + if (height*2 < width) pixel_aspect = 0.5; + if (height > width) pixel_aspect = 2; + filters = 0; + load_raw = &CLASS foveon_load_raw; + simple_coeff(0); + } else if (is_canon && tiff_bps == 15) { + switch (width) { + case 3344: width -= 66; + case 3872: width -= 6; + } + filters = 0; + load_raw = &CLASS canon_sraw_load_raw; + } else if (!strcmp(model,"PowerShot 600")) { + height = 613; + width = 854; + raw_width = 896; + pixel_aspect = 607/628.0; + colors = 4; + filters = 0xe1e4e1e4; + load_raw = &CLASS canon_600_load_raw; + } else if (!strcmp(model,"PowerShot A5") || + !strcmp(model,"PowerShot A5 Zoom")) { + height = 773; + width = 960; + raw_width = 992; + pixel_aspect = 256/235.0; + colors = 4; + filters = 0x1e4e1e4e; + goto canon_a5; + } else if (!strcmp(model,"PowerShot A50")) { + height = 968; + width = 1290; + raw_width = 1320; + colors = 4; + filters = 0x1b4e4b1e; + goto canon_a5; + } else if (!strcmp(model,"PowerShot Pro70")) { + height = 1024; + width = 1552; + colors = 4; + filters = 0x1e4b4e1b; + goto canon_a5; + } else if (!strcmp(model,"PowerShot SD300")) { + height = 1752; + width = 2344; + raw_height = 1766; + raw_width = 2400; + top_margin = 12; + left_margin = 12; + goto canon_a5; + } else if (!strcmp(model,"PowerShot A460")) { + height = 1960; + width = 2616; + raw_height = 1968; + raw_width = 2664; + top_margin = 4; + left_margin = 4; + goto canon_a5; + } else if (!strcmp(model,"PowerShot A530")) { + height = 1984; + width = 2620; + raw_height = 1992; + raw_width = 2672; + top_margin = 6; + left_margin = 10; + goto canon_a5; + } else if (!strcmp(model,"PowerShot A610")) { + if (canon_s2is()) strcpy (model+10, "S2 IS"); + height = 1960; + width = 2616; + raw_height = 1968; + raw_width = 2672; + top_margin = 8; + left_margin = 12; + goto canon_a5; + } else if (!strcmp(model,"PowerShot A620")) { + height = 2328; + width = 3112; + raw_height = 2340; + raw_width = 3152; + top_margin = 12; + left_margin = 36; + goto canon_a5; + } else if (!strcmp(model,"PowerShot A470")) { + height = 2328; + width = 3096; + raw_height = 2346; + raw_width = 3152; + top_margin = 6; + left_margin = 12; + goto canon_a5; + } else if (!strcmp(model,"PowerShot A720")) { + height = 2472; + width = 3298; + raw_height = 2480; + raw_width = 3336; + top_margin = 5; + left_margin = 6; + goto canon_a5; + } else if (!strcmp(model,"PowerShot A630")) { + height = 2472; + width = 3288; + raw_height = 2484; + raw_width = 3344; + top_margin = 6; + left_margin = 12; + goto canon_a5; + } else if (!strcmp(model,"PowerShot A640")) { + height = 2760; + width = 3672; + raw_height = 2772; + raw_width = 3736; + top_margin = 6; + left_margin = 12; + goto canon_a5; + } else if (!strcmp(model,"PowerShot A650")) { + height = 3024; + width = 4032; + raw_height = 3048; + raw_width = 4104; + top_margin = 12; + left_margin = 48; + goto canon_a5; + } else if (!strcmp(model,"PowerShot S3 IS")) { + height = 2128; + width = 2840; + raw_height = 2136; + raw_width = 2888; + top_margin = 8; + left_margin = 44; +canon_a5: + tiff_bps = 10; + load_raw = &CLASS packed_load_raw; + load_flags = 40; + if (raw_width > 1600) zero_is_bad = 1; + } else if (!strcmp(model,"PowerShot SX110 IS")) { + height = 2760; + width = 3684; + raw_height = 2772; + raw_width = 3720; + top_margin = 12; + left_margin = 6; + load_raw = &CLASS packed_load_raw; + load_flags = 40; + zero_is_bad = 1; + } else if (!strcmp(model,"PowerShot Pro90 IS")) { + width = 1896; + colors = 4; + filters = 0xb4b4b4b4; + } else if (is_canon && raw_width == 2144) { + height = 1550; + width = 2088; + top_margin = 8; + left_margin = 4; + if (!strcmp(model,"PowerShot G1")) { + colors = 4; + filters = 0xb4b4b4b4; + } + } else if (is_canon && raw_width == 2224) { + height = 1448; + width = 2176; + top_margin = 6; + left_margin = 48; + } else if (is_canon && raw_width == 2376) { + height = 1720; + width = 2312; + top_margin = 6; + left_margin = 12; + } else if (is_canon && raw_width == 2672) { + height = 1960; + width = 2616; + top_margin = 6; + left_margin = 12; + } else if (is_canon && raw_width == 3152) { + height = 2056; + width = 3088; + top_margin = 12; + left_margin = 64; + if (unique_id == 0x80000170) + adobe_coeff ("Canon","EOS 300D"); + } else if (is_canon && raw_width == 3160) { + height = 2328; + width = 3112; + top_margin = 12; + left_margin = 44; + } else if (is_canon && raw_width == 3344) { + height = 2472; + width = 3288; + top_margin = 6; + left_margin = 4; + } else if (!strcmp(model,"EOS D2000C")) { + filters = 0x61616161; + black = curve[200]; + } else if (is_canon && raw_width == 3516) { + top_margin = 14; + left_margin = 42; + if (unique_id == 0x80000189) + adobe_coeff ("Canon","EOS 350D"); + goto canon_cr2; + } else if (is_canon && raw_width == 3596) { + top_margin = 12; + left_margin = 74; + goto canon_cr2; + } else if (is_canon && raw_width == 3744) { + height = 2760; + width = 3684; + top_margin = 16; + left_margin = 8; + } else if (is_canon && raw_width == 3944) { + height = 2602; + width = 3908; + top_margin = 18; + left_margin = 30; + } else if (is_canon && raw_width == 3948) { + top_margin = 18; + left_margin = 42; + height -= 2; + if (unique_id == 0x80000236) + adobe_coeff ("Canon","EOS 400D"); + if (unique_id == 0x80000254) + adobe_coeff ("Canon","EOS 1000D"); + goto canon_cr2; + } else if (is_canon && raw_width == 3984) { + top_margin = 20; + left_margin = 76; + height -= 2; + goto canon_cr2; + } else if (is_canon && raw_width == 4104) { + height = 3024; + width = 4032; + top_margin = 12; + left_margin = 48; + } else if (is_canon && raw_width == 4152) { + top_margin = 12; + left_margin = 192; + goto canon_cr2; + } else if (is_canon && raw_width == 4312) { + top_margin = 18; + left_margin = 22; + height -= 2; + if (unique_id == 0x80000176) + adobe_coeff ("Canon","EOS 450D"); + goto canon_cr2; + } else if (is_canon && raw_width == 4476) { + top_margin = 34; + left_margin = 90; + goto canon_cr2; + } else if (is_canon && raw_width == 4480) { + height = 3326; + width = 4432; + top_margin = 10; + left_margin = 12; + filters = 0x49494949; + } else if (is_canon && raw_width == 1208) { + top_margin = unique_id == 0x80000261 ? 51:26; + left_margin = 62; + raw_width = width *= 4; + if (unique_id == 0x80000252) + adobe_coeff ("Canon","EOS 500D"); + goto canon_cr2; + } else if (is_canon && raw_width == 1280) { + height -= top_margin = 45; + left_margin = 142; + raw_width *= 4; + width = 4916; + } else if (is_canon && raw_width == 1340) { + top_margin = 51; + left_margin = 158; + raw_width = width *= 4; + goto canon_cr2; + } else if (is_canon && raw_width == 1448) { + top_margin = 51; + left_margin = 158; + raw_width = width *= 4; + goto canon_cr2; + } else if (is_canon && raw_width == 5108) { + top_margin = 13; + left_margin = 98; +canon_cr2: + height -= top_margin; + width -= left_margin; + } else if (is_canon && raw_width == 5712) { + height = 3752; + width = 5640; + top_margin = 20; + left_margin = 62; + } else if (!strcmp(model,"D1")) { + cam_mul[0] *= 256/527.0; + cam_mul[2] *= 256/317.0; + } else if (!strcmp(model,"D1X")) { + width -= 4; + pixel_aspect = 0.5; + } else if (!strcmp(model,"D40X") || + !strcmp(model,"D60") || + !strcmp(model,"D80") || + !strcmp(model,"D3000")) { + height -= 3; + width -= 4; + } else if (!strcmp(model,"D3") || + !strcmp(model,"D3S") || + !strcmp(model,"D700")) { + width -= 4; + left_margin = 2; + } else if (!strcmp(model,"D5000")) { + width -= 42; + } else if (!strncmp(model,"D40",3) || + !strncmp(model,"D50",3) || + !strncmp(model,"D70",3)) { + width--; + } else if (!strcmp(model,"D90")) { + width -= 42; + } else if (!strcmp(model,"D100")) { + if (tiff_compress == 34713 && !nikon_is_compressed()) { + load_raw = &CLASS packed_load_raw; + load_flags |= 1; + raw_width = (width += 3) + 3; + } + } else if (!strcmp(model,"D200")) { + left_margin = 1; + width -= 4; + filters = 0x94949494; + } else if (!strncmp(model,"D2H",3)) { + left_margin = 6; + width -= 14; + } else if (!strncmp(model,"D2X",3)) { + if (width == 3264) width -= 32; + else width -= 8; + } else if (!strncmp(model,"D300",4)) { + width -= 32; + } else if (!strcmp(model,"COOLPIX P6000")) { + load_flags = 24; + filters = 0x94949494; + } else if (fsize == 1581060) { + height = 963; + width = 1287; + raw_width = 1632; + maximum = 0x3f4; + colors = 4; + filters = 0x1e1e1e1e; + simple_coeff(3); + pre_mul[0] = 1.2085; + pre_mul[1] = 1.0943; + pre_mul[3] = 1.1103; + goto e900; + } else if (fsize == 2465792) { + height = 1203; + width = 1616; + raw_width = 2048; + colors = 4; + filters = 0x4b4b4b4b; + adobe_coeff ("NIKON","E950"); +e900: + tiff_bps = 10; + load_raw = &CLASS packed_load_raw; + load_flags = 6; + } else if (fsize == 4771840) { + height = 1540; + width = 2064; + colors = 4; + filters = 0xe1e1e1e1; + load_raw = &CLASS packed_load_raw; + load_flags = 6; + if (!timestamp && nikon_e995()) + strcpy (model, "E995"); + if (strcmp(model,"E995")) { + filters = 0xb4b4b4b4; + simple_coeff(3); + pre_mul[0] = 1.196; + pre_mul[1] = 1.246; + pre_mul[2] = 1.018; + } + } else if (!strcmp(model,"E2100")) { + if (!timestamp && !nikon_e2100()) goto cp_e2500; + height = 1206; + width = 1616; + load_flags = 30; + } else if (!strcmp(model,"E2500")) { +cp_e2500: + strcpy (model, "E2500"); + height = 1204; + width = 1616; + colors = 4; + filters = 0x4b4b4b4b; + } else if (fsize == 4775936) { + height = 1542; + width = 2064; + load_raw = &CLASS packed_load_raw; + load_flags = 30; + if (!timestamp) nikon_3700(); + if (model[0] == 'E' && atoi(model+1) < 3700) + filters = 0x49494949; + if (!strcmp(model,"Optio 33WR")) { + flip = 1; + filters = 0x16161616; + } + if (make[0] == 'O') { + i = find_green (12, 32, 0, fsize/2); + c = find_green (12, 32, 0, 3096); + if (abs(i) < abs(c)) { + SWAP(i,c); + load_flags = 24; + } + if (i < 0) filters = 0x61616161; + } + } else if (fsize == 5869568) { + height = 1710; + width = 2288; + filters = 0x16161616; + if (!timestamp && minolta_z2()) { + strcpy (make, "Minolta"); + strcpy (model,"DiMAGE Z2"); + } + load_raw = &CLASS packed_load_raw; + load_flags = 6 + 24*(make[0] == 'M'); + } else if (!strcmp(model,"E4500")) { + height = 1708; + width = 2288; + colors = 4; + filters = 0xb4b4b4b4; + } else if (fsize == 7438336) { + height = 1924; + width = 2576; + colors = 4; + filters = 0xb4b4b4b4; + } else if (fsize == 8998912) { + height = 2118; + width = 2832; + maximum = 0xf83; + load_raw = &CLASS packed_load_raw; + load_flags = 30; + } else if (!strcmp(make,"FUJIFILM")) { + if (!strcmp(model+7,"S2Pro")) { + strcpy (model+7," S2Pro"); + height = 2144; + width = 2880; + flip = 6; + } else + maximum = 0x3e00; + if (is_raw == 2 && shot_select) + maximum = 0x2f00; + top_margin = (raw_height - height)/2; + left_margin = (raw_width - width )/2; + if (is_raw == 2) + data_offset += (shot_select > 0) * ( fuji_layout ? + (raw_width *= 2) : raw_height*raw_width*2 ); + if (load_raw == &CLASS fuji_load_raw) { + fuji_width = width >> !fuji_layout; + width = (height >> fuji_layout) + fuji_width; + raw_height = height; + height = width - 1; + if (~fuji_width & 1) filters = 0x49494949; + } + } else if (!strcmp(model,"RD175")) { + height = 986; + width = 1534; + data_offset = 513; + filters = 0x61616161; + load_raw = &CLASS minolta_rd175_load_raw; + } else if (!strcmp(model,"KD-400Z")) { + height = 1712; + width = 2312; + raw_width = 2336; + goto konica_400z; + } else if (!strcmp(model,"KD-510Z")) { + goto konica_510z; + } else if (!strcasecmp(make,"MINOLTA")) { + load_raw = &CLASS unpacked_load_raw; + maximum = 0xfff; + if (!strncmp(model,"DiMAGE A",8)) { + if (!strcmp(model,"DiMAGE A200")) + filters = 0x49494949; + tiff_bps = 12; + load_raw = &CLASS packed_load_raw; + } else if (!strncmp(model,"ALPHA",5) || + !strncmp(model,"DYNAX",5) || + !strncmp(model,"MAXXUM",6)) { + sprintf (model+20, "DYNAX %-10s", model+6+(model[0]=='M')); + adobe_coeff (make, model+20); + load_raw = &CLASS packed_load_raw; + } else if (!strncmp(model,"DiMAGE G",8)) { + if (model[8] == '4') { + height = 1716; + width = 2304; + } else if (model[8] == '5') { +konica_510z: + height = 1956; + width = 2607; + raw_width = 2624; + } else if (model[8] == '6') { + height = 2136; + width = 2848; + } + data_offset += 14; + filters = 0x61616161; +konica_400z: + load_raw = &CLASS unpacked_load_raw; + maximum = 0x3df; + order = 0x4d4d; + } + } else if (!strcmp(model,"*ist D")) { + data_error = -1; + } else if (!strcmp(model,"*ist DS")) { + height -= 2; + } else if (!strcmp(model,"K20D")) { + filters = 0x16161616; + } else if (!strcmp(model,"K-x")) { + width = 4309; + filters = 0x16161616; + } else if (!strcmp(model,"Optio S")) { + if (fsize == 3178560) { + height = 1540; + width = 2064; + load_raw = &CLASS eight_bit_load_raw; + cam_mul[0] *= 4; + cam_mul[2] *= 4; + } else { + height = 1544; + width = 2068; + raw_width = 3136; + load_raw = &CLASS packed_load_raw; + maximum = 0xf7c; + } + } else if (fsize == 6114240) { + height = 1737; + width = 2324; + raw_width = 3520; + load_raw = &CLASS packed_load_raw; + maximum = 0xf7a; + } else if (!strcmp(model,"Optio 750Z")) { + height = 2302; + width = 3072; + load_raw = &CLASS packed_load_raw; + load_flags = 30; + } else if (!strcmp(model,"DC-833m")) { + height = 2448; + width = 3264; + order = 0x4949; + filters = 0x61616161; + load_raw = &CLASS unpacked_load_raw; + maximum = 0xfc00; + } else if (!strncmp(model,"S85",3)) { + height = 2448; + width = 3264; + raw_width = fsize/height/2; + order = 0x4d4d; + load_raw = &CLASS unpacked_load_raw; + maximum = 0xffff; + } else if (!strcmp(model,"STV680 VGA")) { + height = 484; + width = 644; + load_raw = &CLASS eight_bit_load_raw; + flip = 2; + filters = 0x16161616; + black = 16; + } else if (!strcmp(model,"N95")) { + height = raw_height - (top_margin = 2); + } else if (!strcmp(model,"531C")) { + height = 1200; + width = 1600; + load_raw = &CLASS unpacked_load_raw; + filters = 0x49494949; + } else if (!strcmp(model,"F-080C")) { + height = 768; + width = 1024; + load_raw = &CLASS eight_bit_load_raw; + } else if (!strcmp(model,"F-145C")) { + height = 1040; + width = 1392; + load_raw = &CLASS eight_bit_load_raw; + } else if (!strcmp(model,"F-201C")) { + height = 1200; + width = 1600; + load_raw = &CLASS eight_bit_load_raw; + } else if (!strcmp(model,"F-510C")) { + height = 1958; + width = 2588; + load_raw = fsize < 7500000 ? + &CLASS eight_bit_load_raw : &CLASS unpacked_load_raw; + maximum = 0xfff0; + } else if (!strcmp(model,"F-810C")) { + height = 2469; + width = 3272; + load_raw = &CLASS unpacked_load_raw; + maximum = 0xfff0; + } else if (!strcmp(model,"XCD-SX910CR")) { + height = 1024; + width = 1375; + raw_width = 1376; + filters = 0x49494949; + maximum = 0x3ff; + load_raw = fsize < 2000000 ? + &CLASS eight_bit_load_raw : &CLASS unpacked_load_raw; + } else if (!strcmp(model,"2010")) { + height = 1207; + width = 1608; + order = 0x4949; + filters = 0x16161616; + data_offset = 3212; + maximum = 0x3ff; + load_raw = &CLASS unpacked_load_raw; + } else if (!strcmp(model,"A782")) { + height = 3000; + width = 2208; + filters = 0x61616161; + load_raw = fsize < 10000000 ? + &CLASS eight_bit_load_raw : &CLASS unpacked_load_raw; + maximum = 0xffc0; + } else if (!strcmp(model,"3320AF")) { + height = 1536; + raw_width = width = 2048; + filters = 0x61616161; + load_raw = &CLASS unpacked_load_raw; + maximum = 0x3ff; + fseek (ifp, 0x300000, SEEK_SET); + if ((order = guess_byte_order(0x10000)) == 0x4d4d) { + height -= (top_margin = 16); + width -= (left_margin = 28); + maximum = 0xf5c0; + strcpy (make, "ISG"); + model[0] = 0; + } + } else if (!strcmp(make,"Hasselblad")) { + if (load_raw == &CLASS lossless_jpeg_load_raw) + load_raw = &CLASS hasselblad_load_raw; + if (raw_width == 7262) { + height = 5444; + width = 7248; + top_margin = 4; + left_margin = 7; + filters = 0x61616161; + } else if (raw_width == 4090) { + strcpy (model, "V96C"); + height -= (top_margin = 6); + width -= (left_margin = 3) + 7; + filters = 0x61616161; + } + } else if (!strcmp(make,"Sinar")) { + if (!memcmp(head,"8BPS",4)) { + fseek (ifp, 14, SEEK_SET); + height = get4(); + width = get4(); + filters = 0x61616161; + data_offset = 68; + } + if (!load_raw) load_raw = &CLASS unpacked_load_raw; + maximum = 0x3fff; + } else if (!strcmp(make,"Leaf")) { + maximum = 0x3fff; + fseek (ifp, data_offset, SEEK_SET); + if (ljpeg_start (&jh, 1) && jh.bits == 15) + maximum = 0x1fff; + if (tiff_samples > 1) filters = 0; + if (tiff_samples > 1 || tile_length < raw_height) + load_raw = &CLASS leaf_hdr_load_raw; + if ((width | height) == 2048) { + if (tiff_samples == 1) { + filters = 1; + strcpy (cdesc, "RBTG"); + strcpy (model, "CatchLight"); + top_margin = 8; left_margin = 18; height = 2032; width = 2016; + } else { + strcpy (model, "DCB2"); + top_margin = 10; left_margin = 16; height = 2028; width = 2022; + } + } else if (width+height == 3144+2060) { + if (!model[0]) strcpy (model, "Cantare"); + if (width > height) { + top_margin = 6; left_margin = 32; height = 2048; width = 3072; + filters = 0x61616161; + } else { + left_margin = 6; top_margin = 32; width = 2048; height = 3072; + filters = 0x16161616; + } + if (!cam_mul[0] || model[0] == 'V') filters = 0; + else is_raw = tiff_samples; + } else if (width == 2116) { + strcpy (model, "Valeo 6"); + height -= 2 * (top_margin = 30); + width -= 2 * (left_margin = 55); + filters = 0x49494949; + } else if (width == 3171) { + strcpy (model, "Valeo 6"); + height -= 2 * (top_margin = 24); + width -= 2 * (left_margin = 24); + filters = 0x16161616; + } + } else if (!strcmp(make,"LEICA") || !strcmp(make,"Panasonic")) { + maximum = 0xfff0; + if ((fsize-data_offset) / (width*8/7) == height) + load_raw = &CLASS panasonic_load_raw; + if (!load_raw) load_raw = &CLASS unpacked_load_raw; + switch (width) { + case 2568: + adobe_coeff ("Panasonic","DMC-LC1"); break; + case 3130: + left_margin = -14; + case 3170: + left_margin += 18; + width = 3096; + if (height > 2326) { + height = 2326; + top_margin = 13; + filters = 0x49494949; + } + zero_is_bad = 1; + adobe_coeff ("Panasonic","DMC-FZ8"); break; + case 3213: + width -= 27; + case 3177: + width -= 10; + filters = 0x49494949; + zero_is_bad = 1; + adobe_coeff ("Panasonic","DMC-L1"); break; + case 3304: + width -= 17; + zero_is_bad = 1; + adobe_coeff ("Panasonic","DMC-FZ30"); break; + case 3330: + width += 43; + left_margin = -6; + maximum = 0xf7f0; + case 3370: + width -= 82; + left_margin += 15; + if (height > 2480) + height = 2480 - (top_margin = 10); + filters = 0x49494949; + zero_is_bad = 1; + adobe_coeff ("Panasonic","DMC-FZ18"); break; + case 3690: + height -= 2; + left_margin = -14; + maximum = 0xf7f0; + case 3770: + width = 3672; + if (--height == 2798 && (height = 2760)) + top_margin = 15; + else filters = 0x49494949; + left_margin += 17; + zero_is_bad = 1; + adobe_coeff ("Panasonic","DMC-FZ50"); break; + case 3710: + width = 3682; + filters = 0x49494949; + adobe_coeff ("Panasonic","DMC-L10"); break; + case 3724: + width -= 14; + if (height == 2450) height -= 2; + case 3836: + width -= 42; +lx3: filters = 0x16161616; + if (make[0] != 'P') + adobe_coeff ("Panasonic","DMC-LX3"); + break; + case 3880: + width -= 22; + left_margin = 6; + zero_is_bad = 1; + adobe_coeff ("Panasonic","DMC-LX1"); break; + case 4060: + width = 3982; + if (height == 2250) goto lx3; + width = 4018; + filters = 0x16161616; + if (!strncmp(model,"DMC-FZ3",7)) { + height -= 2; + adobe_coeff ("Panasonic","DMC-FZ35"); break; + } + filters = 0x49494949; + if (!strcmp(model,"DMC-GH1")) break; + zero_is_bad = 1; + adobe_coeff ("Panasonic","DMC-G1"); break; + case 4172: + case 4396: + width -= 28; + filters = 0x49494949; + adobe_coeff ("Panasonic","DMC-GH1"); break; + case 4290: + height += 38; + left_margin = -14; + filters = 0x49494949; + case 4330: + width = 4248; + if ((height -= 39) == 2400) + top_margin = 15; + left_margin += 17; + adobe_coeff ("Panasonic","DMC-LX2"); break; + case 4508: + height -= 6; + width = 4429; + filters = 0x16161616; + adobe_coeff ("Panasonic","DMC-FX150"); break; + } + } else if (!strcmp(model,"C770UZ")) { + height = 1718; + width = 2304; + filters = 0x16161616; + load_raw = &CLASS packed_load_raw; + load_flags = 30; + } else if (!strcmp(make,"OLYMPUS")) { + height += height & 1; + filters = exif_cfa; + if (width == 4100) width -= 4; + if (load_raw == &CLASS olympus_load_raw) { + tiff_bps = 12; + black >>= 4; + } else if (!strcmp(model,"E-10") || + !strncmp(model,"E-20",4)) { + black <<= 2; + } else if (!strcmp(model,"E-300") || + !strcmp(model,"E-500")) { + width -= 20; + if (load_raw == &CLASS unpacked_load_raw) { + maximum = 0xfc30; + black = 0; + } + } else if (!strcmp(model,"E-330")) { + width -= 30; + if (load_raw == &CLASS unpacked_load_raw) + maximum = 0xf790; + } else if (!strcmp(model,"SP550UZ")) { + thumb_length = fsize - (thumb_offset = 0xa39800); + thumb_height = 480; + thumb_width = 640; + } + } else if (!strcmp(model,"N Digital")) { + height = 2047; + width = 3072; + filters = 0x61616161; + data_offset = 0x1a00; + load_raw = &CLASS packed_load_raw; + } else if (!strcmp(model,"DSC-F828")) { + width = 3288; + left_margin = 5; + data_offset = 862144; + load_raw = &CLASS sony_load_raw; + filters = 0x9c9c9c9c; + colors = 4; + strcpy (cdesc, "RGBE"); + } else if (!strcmp(model,"DSC-V3")) { + width = 3109; + left_margin = 59; + data_offset = 787392; + load_raw = &CLASS sony_load_raw; + } else if (!strcmp(make,"SONY") && raw_width == 3984) { + adobe_coeff ("SONY","DSC-R1"); + width = 3925; + order = 0x4d4d; + } else if (!strcmp(model,"DSLR-A100")) { + height--; + width = ++raw_width; + filters = 0x61616161; + } else if (!strcmp(model,"DSLR-A350")) { + height -= 4; + } else if (!strcmp(model,"PIXL")) { + height -= top_margin = 4; + width -= left_margin = 32; + gamma_curve (0, 7, 1, 255); + } else if (!strcmp(model,"C603v")) { + height = 480; + width = 640; + if (fsize < 614400 || find_green (16, 16, 3840, 5120) < 25) goto c603v; + strcpy (model,"KAI-0340"); + height -= 3; + data_offset = 3840; + order = 0x4949; + load_raw = &CLASS unpacked_load_raw; + } else if (!strcmp(model,"C603y")) { + height = 2134; + width = 2848; +c603v: + filters = 0; + load_raw = &CLASS kodak_yrgb_load_raw; + gamma_curve (0, 3.875, 1, 255); + } else if (!strcmp(model,"C603")) { + raw_height = height = 2152; + raw_width = width = 2864; + goto c603; + } else if (!strcmp(model,"C330")) { + height = 1744; + width = 2336; + raw_height = 1779; + raw_width = 2338; + top_margin = 33; + left_margin = 1; +c603: + order = 0x4949; + if ((data_offset = fsize - raw_height*raw_width)) { + fseek (ifp, 168, SEEK_SET); + read_shorts (curve, 256); + } else gamma_curve (0, 3.875, 1, 255); + load_raw = &CLASS eight_bit_load_raw; + } else if (!strcmp(model,"EASYSHARE Z1015 IS")) { + height = 2742; + width = 3664; + goto ezshare; + } else if (!strcmp(model,"EasyShare Z980")) { + height = 3006; + width = 4016; +ezshare: + data_offset = 0x15000; + load_raw = &CLASS packed_load_raw; + } else if (!strcasecmp(make,"KODAK")) { + if (filters == UINT_MAX) filters = 0x61616161; + if (!strncmp(model,"NC2000",6)) { + width -= 4; + left_margin = 2; + } else if (!strcmp(model,"EOSDCS3B")) { + width -= 4; + left_margin = 2; + } else if (!strcmp(model,"EOSDCS1")) { + width -= 4; + left_margin = 2; + } else if (!strcmp(model,"DCS420")) { + width -= 4; + left_margin = 2; + } else if (!strncmp(model,"DCS460 ",7)) { + model[6] = 0; + width -= 4; + left_margin = 2; + } else if (!strcmp(model,"DCS460A")) { + width -= 4; + left_margin = 2; + colors = 1; + filters = 0; + } else if (!strcmp(model,"DCS660M")) { + black = 214; + colors = 1; + filters = 0; + } else if (!strcmp(model,"DCS760M")) { + colors = 1; + filters = 0; + } + if (!strcmp(model+4,"20X")) + strcpy (cdesc, "MYCY"); + if (strstr(model,"DC25")) { + strcpy (model, "DC25"); + data_offset = 15424; + } + if (!strncmp(model,"DC2",3)) { + height = 242; + if (fsize < 100000) { + raw_width = 256; width = 249; + pixel_aspect = (4.0*height) / (3.0*width); + } else { + raw_width = 512; width = 501; + pixel_aspect = (493.0*height) / (373.0*width); + } + data_offset += raw_width + 1; + colors = 4; + filters = 0x8d8d8d8d; + simple_coeff(1); + pre_mul[1] = 1.179; + pre_mul[2] = 1.209; + pre_mul[3] = 1.036; + load_raw = &CLASS eight_bit_load_raw; + } else if (!strcmp(model,"40")) { + strcpy (model, "DC40"); + height = 512; + width = 768; + data_offset = 1152; + load_raw = &CLASS kodak_radc_load_raw; + } else if (strstr(model,"DC50")) { + strcpy (model, "DC50"); + height = 512; + width = 768; + data_offset = 19712; + load_raw = &CLASS kodak_radc_load_raw; + } else if (strstr(model,"DC120")) { + strcpy (model, "DC120"); + height = 976; + width = 848; + pixel_aspect = height/0.75/width; + load_raw = tiff_compress == 7 ? + &CLASS kodak_jpeg_load_raw : &CLASS kodak_dc120_load_raw; + } else if (!strcmp(model,"DCS200")) { + thumb_height = 128; + thumb_width = 192; + thumb_offset = 6144; + thumb_misc = 360; + write_thumb = &CLASS layer_thumb; + height = 1024; + width = 1536; + data_offset = 79872; + load_raw = &CLASS eight_bit_load_raw; + black = 17; + } + } else if (!strcmp(model,"Fotoman Pixtura")) { + height = 512; + width = 768; + data_offset = 3632; + load_raw = &CLASS kodak_radc_load_raw; + filters = 0x61616161; + simple_coeff(2); + } else if (!strcmp(model,"QuickTake 100")) { + fseek (ifp, 544, SEEK_SET); + height = get2(); + width = get2(); + data_offset = (get4(),get2()) == 30 ? 738:736; + if (height > width) { + SWAP(height,width); + fseek (ifp, data_offset-6, SEEK_SET); + flip = ~get2() & 3 ? 5:6; + } + load_raw = &CLASS quicktake_100_load_raw; + filters = 0x61616161; + } else if (!strcmp(model,"QuickTake 150")) { + data_offset = 738 - head[5]; + if (head[5]) strcpy (model+10, "200"); + load_raw = &CLASS kodak_radc_load_raw; + height = 480; + width = 640; + filters = 0x61616161; + } else if (!strcmp(make,"Rollei") && !load_raw) { + switch (raw_width) { + case 1316: + height = 1030; + width = 1300; + top_margin = 1; + left_margin = 6; + break; + case 2568: + height = 1960; + width = 2560; + top_margin = 2; + left_margin = 8; + } + filters = 0x16161616; + load_raw = &CLASS rollei_load_raw; + } else if (!strcmp(model,"PC-CAM 600")) { + height = 768; + data_offset = width = 1024; + filters = 0x49494949; + load_raw = &CLASS eight_bit_load_raw; + } else if (!strcmp(model,"QV-2000UX")) { + height = 1208; + width = 1632; + data_offset = width * 2; + load_raw = &CLASS eight_bit_load_raw; + } else if (fsize == 3217760) { + height = 1546; + width = 2070; + raw_width = 2080; + load_raw = &CLASS eight_bit_load_raw; + } else if (!strcmp(model,"QV-4000")) { + height = 1700; + width = 2260; + load_raw = &CLASS unpacked_load_raw; + maximum = 0xffff; + } else if (!strcmp(model,"QV-5700")) { + height = 1924; + width = 2576; + raw_width = 3232; + tiff_bps = 10; + } else if (!strcmp(model,"QV-R41")) { + height = 1720; + width = 2312; + raw_width = 3520; + left_margin = 2; + } else if (!strcmp(model,"QV-R51")) { + height = 1926; + width = 2580; + raw_width = 3904; + } else if (!strcmp(model,"EX-S20")) { + height = 1208; + width = 1620; + raw_width = 2432; + flip = 3; + } else if (!strcmp(model,"EX-S100")) { + height = 1544; + width = 2058; + raw_width = 3136; + } else if (!strcmp(model,"EX-Z50")) { + height = 1931; + width = 2570; + raw_width = 3904; + } else if (!strcmp(model,"EX-Z55")) { + height = 1960; + width = 2570; + raw_width = 3904; + } else if (!strcmp(model,"EX-Z60")) { + height = 2145; + width = 2833; + raw_width = 3584; + filters = 0x16161616; + tiff_bps = 10; + } else if (!strcmp(model,"EX-Z75")) { + height = 2321; + width = 3089; + raw_width = 4672; + maximum = 0xfff; + } else if (!strcmp(model,"EX-Z750")) { + height = 2319; + width = 3087; + raw_width = 4672; + maximum = 0xfff; + } else if (!strcmp(model,"EX-Z850")) { + height = 2468; + width = 3279; + raw_width = 4928; + maximum = 0xfff; + } else if (!strcmp(model,"EX-P505")) { + height = 1928; + width = 2568; + raw_width = 3852; + maximum = 0xfff; + } else if (fsize == 9313536) { /* EX-P600 or QV-R61 */ + height = 2142; + width = 2844; + raw_width = 4288; + } else if (!strcmp(model,"EX-P700")) { + height = 2318; + width = 3082; + raw_width = 4672; + } + if (!model[0]) + sprintf (model, "%dx%d", width, height); + if (filters == UINT_MAX) filters = 0x94949494; + if (raw_color) adobe_coeff (make, model); + if (load_raw == &CLASS kodak_radc_load_raw) + if (raw_color) adobe_coeff ("Apple","Quicktake"); + if (thumb_offset && !thumb_height) { + fseek (ifp, thumb_offset, SEEK_SET); + if (ljpeg_start (&jh, 1)) { + thumb_width = jh.wide; + thumb_height = jh.high; + } + } +dng_skip: + if (!tiff_bps) tiff_bps = 12; + if (!maximum) maximum = (1 << tiff_bps) - 1; + if (!load_raw || height < 22) is_raw = 0; +#ifdef NO_JPEG + if (load_raw == &CLASS kodak_jpeg_load_raw) { + fprintf (stderr,_("%s: You must link dcraw with libjpeg!!\n"), ifname); + is_raw = 0; + } +#endif + if (!cdesc[0]) + strcpy (cdesc, colors == 3 ? "RGB":"GMCY"); + if (!raw_height) raw_height = height; + if (!raw_width ) raw_width = width; + if (filters && colors == 3) + for (i=0; i < 32; i+=4) { + if ((filters >> i & 15) == 9) + filters |= 2 << i; + if ((filters >> i & 15) == 6) + filters |= 8 << i; + } +notraw: + if (flip == -1) flip = tiff_flip; + if (flip == -1) flip = 0; +} + +#ifndef NO_LCMS +void CLASS apply_profile (const char *input, const char *output) +{ + char *prof; + cmsHPROFILE hInProfile=0, hOutProfile=0; + cmsHTRANSFORM hTransform; + FILE *fp; + unsigned size; + + cmsErrorAction (LCMS_ERROR_SHOW); + if (strcmp (input, "embed")) + hInProfile = cmsOpenProfileFromFile (input, "r"); + else if (profile_length) { + prof = (char *) malloc (profile_length); + merror (prof, "apply_profile()"); + fseek (ifp, profile_offset, SEEK_SET); + fread (prof, 1, profile_length, ifp); + hInProfile = cmsOpenProfileFromMem (prof, profile_length); + free (prof); + } else + fprintf (stderr,_("%s has no embedded profile.\n"), ifname); + if (!hInProfile) return; + if (!output) + hOutProfile = cmsCreate_sRGBProfile(); + else if ((fp = fopen (output, "rb"))) { + fread (&size, 4, 1, fp); + fseek (fp, 0, SEEK_SET); + oprof = (unsigned *) malloc (size = ntohl(size)); + merror (oprof, "apply_profile()"); + fread (oprof, 1, size, fp); + fclose (fp); + if (!(hOutProfile = cmsOpenProfileFromMem (oprof, size))) { + free (oprof); + oprof = 0; + } + } else + fprintf (stderr,_("Cannot open file %s!\n"), output); + if (!hOutProfile) goto quit; + if (verbose) + fprintf (stderr,_("Applying color profile...\n")); + hTransform = cmsCreateTransform (hInProfile, TYPE_RGBA_16, + hOutProfile, TYPE_RGBA_16, INTENT_PERCEPTUAL, 0); + cmsDoTransform (hTransform, image, image, width*height); + raw_color = 1; /* Don't use rgb_cam with a profile */ + cmsDeleteTransform (hTransform); + cmsCloseProfile (hOutProfile); +quit: + cmsCloseProfile (hInProfile); +} +#endif + +void CLASS convert_to_rgb() +{ + int row, col, c, i, j, k; + ushort *img; + float out[3], out_cam[3][4]; + double num, inverse[3][3]; + static const double xyzd50_srgb[3][3] = + { { 0.436083, 0.385083, 0.143055 }, + { 0.222507, 0.716888, 0.060608 }, + { 0.013930, 0.097097, 0.714022 } }; + static const double rgb_rgb[3][3] = + { { 1,0,0 }, { 0,1,0 }, { 0,0,1 } }; + static const double adobe_rgb[3][3] = + { { 0.715146, 0.284856, 0.000000 }, + { 0.000000, 1.000000, 0.000000 }, + { 0.000000, 0.041166, 0.958839 } }; + static const double wide_rgb[3][3] = + { { 0.593087, 0.404710, 0.002206 }, + { 0.095413, 0.843149, 0.061439 }, + { 0.011621, 0.069091, 0.919288 } }; + static const double prophoto_rgb[3][3] = + { { 0.529317, 0.330092, 0.140588 }, + { 0.098368, 0.873465, 0.028169 }, + { 0.016879, 0.117663, 0.865457 } }; + static const double (*out_rgb[])[3] = + { rgb_rgb, adobe_rgb, wide_rgb, prophoto_rgb, xyz_rgb }; + static const char *name[] = + { "sRGB", "Adobe RGB (1998)", "WideGamut D65", "ProPhoto D65", "XYZ" }; + static const unsigned phead[] = + { 1024, 0, 0x2100000, 0x6d6e7472, 0x52474220, 0x58595a20, 0, 0, 0, + 0x61637370, 0, 0, 0x6e6f6e65, 0, 0, 0, 0, 0xf6d6, 0x10000, 0xd32d }; + unsigned pbody[] = + { 10, 0x63707274, 0, 36, /* cprt */ + 0x64657363, 0, 40, /* desc */ + 0x77747074, 0, 20, /* wtpt */ + 0x626b7074, 0, 20, /* bkpt */ + 0x72545243, 0, 14, /* rTRC */ + 0x67545243, 0, 14, /* gTRC */ + 0x62545243, 0, 14, /* bTRC */ + 0x7258595a, 0, 20, /* rXYZ */ + 0x6758595a, 0, 20, /* gXYZ */ + 0x6258595a, 0, 20 }; /* bXYZ */ + static const unsigned pwhite[] = { 0xf351, 0x10000, 0x116cc }; + unsigned pcurve[] = { 0x63757276, 0, 1, 0x1000000 }; + + gamma_curve (gamm[0], gamm[1], 0, 0); + memcpy (out_cam, rgb_cam, sizeof out_cam); + raw_color |= colors == 1 || document_mode || + output_color < 1 || output_color > 5; + if (!raw_color) { + oprof = (unsigned *) calloc (phead[0], 1); + merror (oprof, "convert_to_rgb()"); + memcpy (oprof, phead, sizeof phead); + if (output_color == 5) oprof[4] = oprof[5]; + oprof[0] = 132 + 12*pbody[0]; + for (i=0; i < pbody[0]; i++) { + oprof[oprof[0]/4] = i ? (i > 1 ? 0x58595a20 : 0x64657363) : 0x74657874; + pbody[i*3+2] = oprof[0]; + oprof[0] += (pbody[i*3+3] + 3) & -4; + } + memcpy (oprof+32, pbody, sizeof pbody); + oprof[pbody[5]/4+2] = strlen(name[output_color-1]) + 1; + memcpy ((char *)oprof+pbody[8]+8, pwhite, sizeof pwhite); + pcurve[3] = (short)(256/gamm[5]+0.5) << 16; + for (i=4; i < 7; i++) + memcpy ((char *)oprof+pbody[i*3+2], pcurve, sizeof pcurve); + pseudoinverse ((double (*)[3]) out_rgb[output_color-1], inverse, 3); + for (i=0; i < 3; i++) + for (j=0; j < 3; j++) { + for (num = k=0; k < 3; k++) + num += xyzd50_srgb[i][k] * inverse[j][k]; + oprof[pbody[j*3+23]/4+i+2] = num * 0x10000 + 0.5; + } + for (i=0; i < phead[0]/4; i++) + oprof[i] = htonl(oprof[i]); + strcpy ((char *)oprof+pbody[2]+8, "auto-generated by dcraw"); + strcpy ((char *)oprof+pbody[5]+12, name[output_color-1]); + for (i=0; i < 3; i++) + for (j=0; j < colors; j++) + for (out_cam[i][j] = k=0; k < 3; k++) + out_cam[i][j] += out_rgb[output_color-1][i][k] * rgb_cam[k][j]; + } + if (verbose) + fprintf (stderr, raw_color ? _("Building histograms...\n") : + _("Converting to %s colorspace...\n"), name[output_color-1]); + + memset (histogram, 0, sizeof histogram); + for (img=image[0], row=0; row < height; row++) + for (col=0; col < width; col++, img+=4) { + if (!raw_color) { + out[0] = out[1] = out[2] = 0; + FORCC { + out[0] += out_cam[0][c] * img[c]; + out[1] += out_cam[1][c] * img[c]; + out[2] += out_cam[2][c] * img[c]; + } + FORC3 img[c] = CLIP((int) out[c]); + } + else if (document_mode) + img[0] = img[FC(row,col)]; + FORCC histogram[c][img[c] >> 3]++; + } + if (colors == 4 && output_color) colors = 3; + if (document_mode && filters) colors = 1; +} + +void CLASS fuji_rotate() +{ + int i, row, col; + double step; + float r, c, fr, fc; + unsigned ur, uc; + ushort wide, high, (*img)[4], (*pix)[4]; + + if (!fuji_width) return; + if (verbose) + fprintf (stderr,_("Rotating image 45 degrees...\n")); + fuji_width = (fuji_width - 1 + shrink) >> shrink; + step = sqrt(0.5); + wide = fuji_width / step; + high = (height - fuji_width) / step; + img = (ushort (*)[4]) calloc (wide*high, sizeof *img); + merror (img, "fuji_rotate()"); + + for (row=0; row < high; row++) + for (col=0; col < wide; col++) { + ur = r = fuji_width + (row-col)*step; + uc = c = (row+col)*step; + if (ur > height-2 || uc > width-2) continue; + fr = r - ur; + fc = c - uc; + pix = image + ur*width + uc; + for (i=0; i < colors; i++) + img[row*wide+col][i] = + (pix[ 0][i]*(1-fc) + pix[ 1][i]*fc) * (1-fr) + + (pix[width][i]*(1-fc) + pix[width+1][i]*fc) * fr; + } + free (image); + width = wide; + height = high; + image = img; + fuji_width = 0; +} + +void CLASS stretch() +{ + ushort newdim, (*img)[4], *pix0, *pix1; + int row, col, c; + double rc, frac; + + if (pixel_aspect == 1) return; + if (verbose) fprintf (stderr,_("Stretching the image...\n")); + if (pixel_aspect < 1) { + newdim = height / pixel_aspect + 0.5; + img = (ushort (*)[4]) calloc (width*newdim, sizeof *img); + merror (img, "stretch()"); + for (rc=row=0; row < newdim; row++, rc+=pixel_aspect) { + frac = rc - (c = rc); + pix0 = pix1 = image[c*width]; + if (c+1 < height) pix1 += width*4; + for (col=0; col < width; col++, pix0+=4, pix1+=4) + FORCC img[row*width+col][c] = pix0[c]*(1-frac) + pix1[c]*frac + 0.5; + } + height = newdim; + } else { + newdim = width * pixel_aspect + 0.5; + img = (ushort (*)[4]) calloc (height*newdim, sizeof *img); + merror (img, "stretch()"); + for (rc=col=0; col < newdim; col++, rc+=1/pixel_aspect) { + frac = rc - (c = rc); + pix0 = pix1 = image[c]; + if (c+1 < width) pix1 += 4; + for (row=0; row < height; row++, pix0+=width*4, pix1+=width*4) + FORCC img[row*newdim+col][c] = pix0[c]*(1-frac) + pix1[c]*frac + 0.5; + } + width = newdim; + } + free (image); + image = img; +} + +int CLASS flip_index (int row, int col) +{ + if (flip & 4) SWAP(row,col); + if (flip & 2) row = iheight - 1 - row; + if (flip & 1) col = iwidth - 1 - col; + return row * iwidth + col; +} + +struct tiff_tag { + ushort tag, type; + int count; + union { char c[4]; short s[2]; int i; } val; +}; + +struct tiff_hdr { + ushort order, magic; + int ifd; + ushort pad, ntag; + struct tiff_tag tag[23]; + int nextifd; + ushort pad2, nexif; + struct tiff_tag exif[4]; + ushort pad3, ngps; + struct tiff_tag gpst[10]; + short bps[4]; + int rat[10]; + unsigned gps[26]; + char desc[512], make[64], model[64], soft[32], date[20], artist[64]; +}; + +void CLASS tiff_set (ushort *ntag, + ushort tag, ushort type, int count, int val) +{ + struct tiff_tag *tt; + int c; + + tt = (struct tiff_tag *)(ntag+1) + (*ntag)++; + tt->tag = tag; + tt->type = type; + tt->count = count; + if (type < 3 && count <= 4) + FORC(4) tt->val.c[c] = val >> (c << 3); + else if (type == 3 && count <= 2) + FORC(2) tt->val.s[c] = val >> (c << 4); + else tt->val.i = val; +} + +#define TOFF(ptr) ((char *)(&(ptr)) - (char *)th) + +void CLASS tiff_head (struct tiff_hdr *th, int full) +{ + int c, psize=0; + struct tm *t; + + memset (th, 0, sizeof *th); + th->order = htonl(0x4d4d4949) >> 16; + th->magic = 42; + th->ifd = 10; + if (full) { + tiff_set (&th->ntag, 254, 4, 1, 0); + tiff_set (&th->ntag, 256, 4, 1, width); + tiff_set (&th->ntag, 257, 4, 1, height); + tiff_set (&th->ntag, 258, 3, colors, output_bps); + if (colors > 2) + th->tag[th->ntag-1].val.i = TOFF(th->bps); + FORC4 th->bps[c] = output_bps; + tiff_set (&th->ntag, 259, 3, 1, 1); + tiff_set (&th->ntag, 262, 3, 1, 1 + (colors > 1)); + } + tiff_set (&th->ntag, 270, 2, 512, TOFF(th->desc)); + tiff_set (&th->ntag, 271, 2, 64, TOFF(th->make)); + tiff_set (&th->ntag, 272, 2, 64, TOFF(th->model)); + if (full) { + if (oprof) psize = ntohl(oprof[0]); + tiff_set (&th->ntag, 273, 4, 1, sizeof *th + psize); + tiff_set (&th->ntag, 277, 3, 1, colors); + tiff_set (&th->ntag, 278, 4, 1, height); + tiff_set (&th->ntag, 279, 4, 1, height*width*colors*output_bps/8); + } else + tiff_set (&th->ntag, 274, 3, 1, "12435867"[flip]-'0'); + tiff_set (&th->ntag, 282, 5, 1, TOFF(th->rat[0])); + tiff_set (&th->ntag, 283, 5, 1, TOFF(th->rat[2])); + tiff_set (&th->ntag, 284, 3, 1, 1); + tiff_set (&th->ntag, 296, 3, 1, 2); + tiff_set (&th->ntag, 305, 2, 32, TOFF(th->soft)); + tiff_set (&th->ntag, 306, 2, 20, TOFF(th->date)); + tiff_set (&th->ntag, 315, 2, 64, TOFF(th->artist)); + tiff_set (&th->ntag, 34665, 4, 1, TOFF(th->nexif)); + if (psize) tiff_set (&th->ntag, 34675, 7, psize, sizeof *th); + tiff_set (&th->nexif, 33434, 5, 1, TOFF(th->rat[4])); + tiff_set (&th->nexif, 33437, 5, 1, TOFF(th->rat[6])); + tiff_set (&th->nexif, 34855, 3, 1, iso_speed); + tiff_set (&th->nexif, 37386, 5, 1, TOFF(th->rat[8])); + if (gpsdata[1]) { + tiff_set (&th->ntag, 34853, 4, 1, TOFF(th->ngps)); + tiff_set (&th->ngps, 0, 1, 4, 0x202); + tiff_set (&th->ngps, 1, 2, 2, gpsdata[29]); + tiff_set (&th->ngps, 2, 5, 3, TOFF(th->gps[0])); + tiff_set (&th->ngps, 3, 2, 2, gpsdata[30]); + tiff_set (&th->ngps, 4, 5, 3, TOFF(th->gps[6])); + tiff_set (&th->ngps, 5, 1, 1, gpsdata[31]); + tiff_set (&th->ngps, 6, 5, 1, TOFF(th->gps[18])); + tiff_set (&th->ngps, 7, 5, 3, TOFF(th->gps[12])); + tiff_set (&th->ngps, 18, 2, 12, TOFF(th->gps[20])); + tiff_set (&th->ngps, 29, 2, 12, TOFF(th->gps[23])); + memcpy (th->gps, gpsdata, sizeof th->gps); + } + th->rat[0] = th->rat[2] = 300; + th->rat[1] = th->rat[3] = 1; + FORC(6) th->rat[4+c] = 1000000; + th->rat[4] *= shutter; + th->rat[6] *= aperture; + th->rat[8] *= focal_len; + strncpy (th->desc, desc, 512); + strncpy (th->make, make, 64); + strncpy (th->model, model, 64); + strcpy (th->soft, "dcraw v"VERSION); + t = gmtime (×tamp); + sprintf (th->date, "%04d:%02d:%02d %02d:%02d:%02d", + t->tm_year+1900,t->tm_mon+1,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec); + strncpy (th->artist, artist, 64); +} + +void CLASS jpeg_thumb() +{ + char *thumb; + ushort exif[5]; + struct tiff_hdr th; + + thumb = (char *) malloc (thumb_length); + merror (thumb, "jpeg_thumb()"); + fread (thumb, 1, thumb_length, ifp); + fputc (0xff, ofp); + fputc (0xd8, ofp); + if (strcmp (thumb+6, "Exif")) { + memcpy (exif, "\xff\xe1 Exif\0\0", 10); + exif[1] = htons (8 + sizeof th); + fwrite (exif, 1, sizeof exif, ofp); + tiff_head (&th, 0); + fwrite (&th, 1, sizeof th, ofp); + } + fwrite (thumb+2, 1, thumb_length-2, ofp); + free (thumb); +} + +void CLASS write_ppm_tiff() +{ + struct tiff_hdr th; + uchar *ppm; + ushort *ppm2; + int c, row, col, soff, rstep, cstep; + int perc, val, total, white=0x2000; + + perc = width * height * 0.01; /* 99th percentile white level */ + if (fuji_width) perc /= 2; + if (!((highlight & ~2) || no_auto_bright)) + for (white=c=0; c < colors; c++) { + for (val=0x2000, total=0; --val > 32; ) + if ((total += histogram[c][val]) > perc) break; + if (white < val) white = val; + } + gamma_curve (gamm[0], gamm[1], 2, (white << 3)/bright); + iheight = height; + iwidth = width; + if (flip & 4) SWAP(height,width); + ppm = (uchar *) calloc (width, colors*output_bps/8); + ppm2 = (ushort *) ppm; + merror (ppm, "write_ppm_tiff()"); + if (output_tiff) { + tiff_head (&th, 1); + fwrite (&th, sizeof th, 1, ofp); + if (oprof) + fwrite (oprof, ntohl(oprof[0]), 1, ofp); + } else if (colors > 3) + fprintf (ofp, + "P7\nWIDTH %d\nHEIGHT %d\nDEPTH %d\nMAXVAL %d\nTUPLTYPE %s\nENDHDR\n", + width, height, colors, (1 << output_bps)-1, cdesc); + else + fprintf (ofp, "P%d\n%d %d\n%d\n", + colors/2+5, width, height, (1 << output_bps)-1); + soff = flip_index (0, 0); + cstep = flip_index (0, 1) - soff; + rstep = flip_index (1, 0) - flip_index (0, width); + for (row=0; row < height; row++, soff += rstep) { + for (col=0; col < width; col++, soff += cstep) + if (output_bps == 8) + FORCC ppm [col*colors+c] = curve[image[soff][c]] >> 8; + else FORCC ppm2[col*colors+c] = curve[image[soff][c]]; + if (output_bps == 16 && !output_tiff && htons(0x55aa) != 0x55aa) + swab (ppm2, ppm2, width*colors*2); + fwrite (ppm, colors*output_bps/8, width, ofp); + } + free (ppm); +} + +int CLASS main (int argc, const char **argv) +{ + int arg, status=0; + int timestamp_only=0, thumbnail_only=0, identify_only=0; + int user_qual=-1, user_black=-1, user_sat=-1, user_flip=-1; + int use_fuji_rotate=1, write_to_stdout=0, quality, i, c; + const char *sp, *bpfile=0, *dark_frame=0, *write_ext; + char opm, opt, *ofname, *cp; + struct utimbuf ut; +#ifndef NO_LCMS + const char *cam_profile=0, *out_profile=0; +#endif + +#ifndef LOCALTIME + putenv ((char *) "TZ=UTC"); +#endif +#ifdef LOCALEDIR + setlocale (LC_CTYPE, ""); + setlocale (LC_MESSAGES, ""); + bindtextdomain ("dcraw", LOCALEDIR); + textdomain ("dcraw"); +#endif + + if (argc == 1) { + printf(_("\nRaw photo decoder \"dcraw\" v%s"), VERSION); + printf(_("\nby Dave Coffin, dcoffin a cybercom o net\n")); + printf(_("\nUsage: %s [OPTION]... [FILE]...\n\n"), argv[0]); + puts(_("-v Print verbose messages")); + puts(_("-c Write image data to standard output")); + puts(_("-e Extract embedded thumbnail image")); + puts(_("-i Identify files without decoding them")); + puts(_("-i -v Identify files and show metadata")); + puts(_("-z Change file dates to camera timestamp")); + puts(_("-w Use camera white balance, if possible")); + puts(_("-a Average the whole image for white balance")); + puts(_("-A Average a grey box for white balance")); + puts(_("-r Set custom white balance")); + puts(_("+M/-M Use/don't use an embedded color matrix")); + puts(_("-C Correct chromatic aberration")); + puts(_("-P Fix the dead pixels listed in this file")); + puts(_("-K Subtract dark frame (16-bit raw PGM)")); + puts(_("-k Set the darkness level")); + puts(_("-S Set the saturation level")); + puts(_("-n Set threshold for wavelet denoising")); + puts(_("-H [0-9] Highlight mode (0=clip, 1=unclip, 2=blend, 3+=rebuild)")); + puts(_("-t [0-7] Flip image (0=none, 3=180, 5=90CCW, 6=90CW)")); + puts(_("-o [0-5] Output colorspace (raw,sRGB,Adobe,Wide,ProPhoto,XYZ)")); +#ifndef NO_LCMS + puts(_("-o Apply output ICC profile from file")); + puts(_("-p Apply camera ICC profile from file or \"embed\"")); +#endif + puts(_("-d Document mode (no color, no interpolation)")); + puts(_("-D Document mode without scaling (totally raw)")); + puts(_("-j Don't stretch or rotate raw pixels")); + puts(_("-W Don't automatically brighten the image")); + puts(_("-b Adjust brightness (default = 1.0)")); + puts(_("-g

    Set custom gamma curve (default = 2.222 4.5)")); + puts(_("-q [0-3] Set the interpolation quality")); + puts(_("-h Half-size color image (twice as fast as \"-q 0\")")); + puts(_("-f Interpolate RGGB as four colors")); + puts(_("-m Apply a 3x3 median filter to R-G and B-G")); + puts(_("-s [0..N-1] Select one raw image or \"all\" from each file")); + puts(_("-6 Write 16-bit instead of 8-bit")); + puts(_("-4 Linear 16-bit, same as \"-6 -W -g 1 1\"")); + puts(_("-T Write TIFF instead of PPM")); + puts(""); + return 1; + } + argv[argc] = ""; + for (arg=1; (((opm = argv[arg][0]) - 2) | 2) == '+'; ) { + opt = argv[arg++][1]; + if ((cp = (char *) strchr (sp="nbrkStqmHACg", opt))) + for (i=0; i < "114111111422"[cp-sp]-'0'; i++) + if (!isdigit(argv[arg+i][0])) { + fprintf (stderr,_("Non-numeric argument to \"-%c\"\n"), opt); + return 1; + } + switch (opt) { + case 'n': threshold = atof(argv[arg++]); break; + case 'b': bright = atof(argv[arg++]); break; + case 'r': + FORC4 user_mul[c] = atof(argv[arg++]); break; + case 'C': aber[0] = 1 / atof(argv[arg++]); + aber[2] = 1 / atof(argv[arg++]); break; + case 'g': gamm[0] = atof(argv[arg++]); + gamm[1] = atof(argv[arg++]); + if (gamm[0]) gamm[0] = 1/gamm[0]; break; + case 'k': user_black = atoi(argv[arg++]); break; + case 'S': user_sat = atoi(argv[arg++]); break; + case 't': user_flip = atoi(argv[arg++]); break; + case 'q': user_qual = atoi(argv[arg++]); break; + case 'm': med_passes = atoi(argv[arg++]); break; + case 'H': highlight = atoi(argv[arg++]); break; + case 's': + shot_select = abs(atoi(argv[arg])); + multi_out = !strcmp(argv[arg++],"all"); + break; + case 'o': + if (isdigit(argv[arg][0]) && !argv[arg][1]) + output_color = atoi(argv[arg++]); +#ifndef NO_LCMS + else out_profile = argv[arg++]; + break; + case 'p': cam_profile = argv[arg++]; +#endif + break; + case 'P': bpfile = argv[arg++]; break; + case 'K': dark_frame = argv[arg++]; break; + case 'z': timestamp_only = 1; break; + case 'e': thumbnail_only = 1; break; + case 'i': identify_only = 1; break; + case 'c': write_to_stdout = 1; break; + case 'v': verbose = 1; break; + case 'h': half_size = 1; /* "-h" implies "-f" */ + case 'f': four_color_rgb = 1; break; + case 'A': FORC4 greybox[c] = atoi(argv[arg++]); + case 'a': use_auto_wb = 1; break; + case 'w': use_camera_wb = 1; break; + case 'M': use_camera_matrix = (opm == '+'); break; + case 'D': + case 'd': document_mode = 1 + (opt == 'D'); + case 'j': use_fuji_rotate = 0; break; + case 'W': no_auto_bright = 1; break; + case 'T': output_tiff = 1; break; + case '4': gamm[0] = gamm[1] = + no_auto_bright = 1; + case '6': output_bps = 16; break; + default: + fprintf (stderr,_("Unknown option \"-%c\".\n"), opt); + return 1; + } + } + if (use_camera_matrix < 0) + use_camera_matrix = use_camera_wb; + if (arg == argc) { + fprintf (stderr,_("No files to process.\n")); + return 1; + } + if (write_to_stdout) { + if (isatty(1)) { + fprintf (stderr,_("Will not write an image to the terminal!\n")); + return 1; + } +#if defined(WIN32) || defined(DJGPP) || defined(__CYGWIN__) + if (setmode(1,O_BINARY) < 0) { + perror ("setmode()"); + return 1; + } +#endif + } + for ( ; arg < argc; arg++) { + status = 1; + image = 0; + oprof = 0; + meta_data = ofname = 0; + ofp = stdout; + if (setjmp (failure)) { + if (fileno(ifp) > 2) fclose(ifp); + if (fileno(ofp) > 2) fclose(ofp); + status = 1; + goto cleanup; + } + ifname = argv[arg]; + if (!(ifp = fopen (ifname, "rb"))) { + perror (ifname); + continue; + } + status = (identify(),!is_raw); + if (user_flip >= 0) + flip = user_flip; + switch ((flip+3600) % 360) { + case 270: flip = 5; break; + case 180: flip = 3; break; + case 90: flip = 6; + } + if (timestamp_only) { + if ((status = !timestamp)) + fprintf (stderr,_("%s has no timestamp.\n"), ifname); + else if (identify_only) + printf ("%10ld%10d %s\n", (long) timestamp, shot_order, ifname); + else { + if (verbose) + fprintf (stderr,_("%s time set to %d.\n"), ifname, (int) timestamp); + ut.actime = ut.modtime = timestamp; + utime (ifname, &ut); + } + goto next; + } + write_fun = &CLASS write_ppm_tiff; + if (thumbnail_only) { + if ((status = !thumb_offset)) { + fprintf (stderr,_("%s has no thumbnail.\n"), ifname); + goto next; + } else if (thumb_load_raw) { + load_raw = thumb_load_raw; + data_offset = thumb_offset; + height = thumb_height; + width = thumb_width; + filters = 0; + } else { + fseek (ifp, thumb_offset, SEEK_SET); + write_fun = write_thumb; + goto thumbnail; + } + } + if (load_raw == &CLASS kodak_ycbcr_load_raw) { + height += height & 1; + width += width & 1; + } + if (identify_only && verbose && make[0]) { + printf (_("\nFilename: %s\n"), ifname); + printf (_("Timestamp: %s"), ctime(×tamp)); + printf (_("Camera: %s %s\n"), make, model); + if (artist[0]) + printf (_("Owner: %s\n"), artist); + if (dng_version) { + printf (_("DNG Version: ")); + for (i=24; i >= 0; i -= 8) + printf ("%d%c", dng_version >> i & 255, i ? '.':'\n'); + } + printf (_("ISO speed: %d\n"), (int) iso_speed); + printf (_("Shutter: ")); + if (shutter > 0 && shutter < 1) + shutter = (printf ("1/"), 1 / shutter); + printf (_("%0.1f sec\n"), shutter); + printf (_("Aperture: f/%0.1f\n"), aperture); + printf (_("Focal length: %0.1f mm\n"), focal_len); + printf (_("Embedded ICC profile: %s\n"), profile_length ? _("yes"):_("no")); + printf (_("Number of raw images: %d\n"), is_raw); + if (pixel_aspect != 1) + printf (_("Pixel Aspect Ratio: %0.6f\n"), pixel_aspect); + if (thumb_offset) + printf (_("Thumb size: %4d x %d\n"), thumb_width, thumb_height); + printf (_("Full size: %4d x %d\n"), raw_width, raw_height); + } else if (!is_raw) + fprintf (stderr,_("Cannot decode file %s\n"), ifname); + if (!is_raw) goto next; + shrink = filters && + (half_size || threshold || aber[0] != 1 || aber[2] != 1); + iheight = (height + shrink) >> shrink; + iwidth = (width + shrink) >> shrink; + if (identify_only) { + if (verbose) { + if (use_fuji_rotate) { + if (fuji_width) { + fuji_width = (fuji_width - 1 + shrink) >> shrink; + iwidth = fuji_width / sqrt(0.5); + iheight = (iheight - fuji_width) / sqrt(0.5); + } else { + if (pixel_aspect < 1) iheight = iheight / pixel_aspect + 0.5; + if (pixel_aspect > 1) iwidth = iwidth * pixel_aspect + 0.5; + } + } + if (flip & 4) + SWAP(iheight,iwidth); + printf (_("Image size: %4d x %d\n"), width, height); + printf (_("Output size: %4d x %d\n"), iwidth, iheight); + printf (_("Raw colors: %d"), colors); + if (filters) { + printf (_("\nFilter pattern: ")); + if (!cdesc[3]) cdesc[3] = 'G'; + for (i=0; i < 16; i++) + putchar (cdesc[fc(i >> 1,i & 1)]); + } + printf (_("\nDaylight multipliers:")); + FORCC printf (" %f", pre_mul[c]); + if (cam_mul[0] > 0) { + printf (_("\nCamera multipliers:")); + FORC4 printf (" %f", cam_mul[c]); + } + putchar ('\n'); + } else + printf (_("%s is a %s %s image.\n"), ifname, make, model); +next: + fclose(ifp); + continue; + } + if (use_camera_matrix && cmatrix[0][0] > 0.25) { + memcpy (rgb_cam, cmatrix, sizeof cmatrix); + raw_color = 0; + } + image = (ushort (*)[4]) calloc (iheight*iwidth, sizeof *image); + merror (image, "main()"); + if (meta_length) { + meta_data = (char *) malloc (meta_length); + merror (meta_data, "main()"); + } + if (verbose) + fprintf (stderr,_("Loading %s %s image from %s ...\n"), + make, model, ifname); + if (shot_select >= is_raw) + fprintf (stderr,_("%s: \"-s %d\" requests a nonexistent image!\n"), + ifname, shot_select); + fseeko (ifp, data_offset, SEEK_SET); + (*load_raw)(); + if (zero_is_bad) remove_zeroes(); + bad_pixels (bpfile); + if (dark_frame) subtract (dark_frame); + quality = 2 + !fuji_width; + if (user_qual >= 0) quality = user_qual; + if (user_black >= 0) black = user_black; + if (user_sat > 0) maximum = user_sat; +#ifdef COLORCHECK + colorcheck(); +#endif + if (is_foveon && !document_mode) foveon_interpolate(); + if (!is_foveon && document_mode < 2) scale_colors(); + pre_interpolate(); + if (filters && !document_mode) { + if (quality == 0) + lin_interpolate(); + else if (quality == 1 || colors > 3) + vng_interpolate(); + else if (quality == 2) + ppg_interpolate(); + else ahd_interpolate(); + } + if (mix_green) + for (colors=3, i=0; i < height*width; i++) + image[i][1] = (image[i][1] + image[i][3]) >> 1; + if (!is_foveon && colors == 3) median_filter(); + if (!is_foveon && highlight == 2) blend_highlights(); + if (!is_foveon && highlight > 2) recover_highlights(); + if (use_fuji_rotate) fuji_rotate(); +#ifndef NO_LCMS + if (cam_profile) apply_profile (cam_profile, out_profile); +#endif + convert_to_rgb(); + if (use_fuji_rotate) stretch(); +thumbnail: + if (write_fun == &CLASS jpeg_thumb) + write_ext = ".jpg"; + else if (output_tiff && write_fun == &CLASS write_ppm_tiff) + write_ext = ".tiff"; + else + write_ext = ".pgm\0.ppm\0.ppm\0.pam" + colors*5-5; + ofname = (char *) malloc (strlen(ifname) + 64); + merror (ofname, "main()"); + if (write_to_stdout) + strcpy (ofname,_("standard output")); + else { + strcpy (ofname, ifname); + if ((cp = strrchr (ofname, '.'))) *cp = 0; + if (multi_out) + sprintf (ofname+strlen(ofname), "_%0*d", + snprintf(0,0,"%d",is_raw-1), shot_select); + if (thumbnail_only) + strcat (ofname, ".thumb"); + strcat (ofname, write_ext); + ofp = fopen (ofname, "wb"); + if (!ofp) { + status = 1; + perror (ofname); + goto cleanup; + } + } + if (verbose) + fprintf (stderr,_("Writing data to %s ...\n"), ofname); + (*write_fun)(); + fclose(ifp); + if (ofp != stdout) fclose(ofp); +cleanup: + if (meta_data) free (meta_data); + if (ofname) free (ofname); + if (oprof) free (oprof); + if (image) free (image); + if (multi_out) { + if (++shot_select < is_raw) arg--; + else shot_select = 0; + } + } + return status; +} diff --git a/rtengine/dcraw.cc b/rtengine/dcraw.cc new file mode 100755 index 000000000..dc5777794 --- /dev/null +++ b/rtengine/dcraw.cc @@ -0,0 +1,9374 @@ +/* + * This file is part of RawTherapee. + * + * The functions defined after the original "main" are copyrighted + * by Gabor Horvath and protected by the GNU + * General Public License. + * The original copyright notice of Dave Coffin is valid for everything + * before that point (see below). + * + * 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 . + */ +/*RT*/#include +/*RT*/#include +/*RT*/int ciff_base, ciff_len, exif_base, pre_filters; +/*RT*/#undef MAX +/*RT*/#undef MIN +/*RT*/#define NO_LCMS +/*RT*/#define NO_JPEG +/*RT*/#define LOCALTIME +/*RT*/#define DJGPP +/*RT*/#include + +#include "myfile.h" + +/* + dcraw.c -- Dave Coffin's raw photo decoder + Copyright 1997-2009 by Dave Coffin, dcoffin a cybercom o net + + This is a command-line ANSI C program to convert raw photos from + any digital camera on any computer running any operating system. + + No license is required to download and use dcraw.c. However, + to lawfully redistribute dcraw, you must either (a) offer, at + no extra charge, full source code* for all executable files + containing RESTRICTED functions, (b) distribute this code under + the GPL Version 2 or later, (c) remove all RESTRICTED functions, + re-implement them, or copy them from an earlier, unrestricted + Revision of dcraw.c, or (d) purchase a license from the author. + + The functions that process Foveon images have been RESTRICTED + since Revision 1.237. All other code remains free for all uses. + + *If you have not modified dcraw.c in any way, a link to my + homepage qualifies as "full source code". + + $Revision: 1.432 $ + $Date: 2009/12/25 18:51:16 $ + */ + +#define VERSION "8.99" + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#define _USE_MATH_DEFINES +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* + NO_JPEG disables decoding of compressed Kodak DC120 files. + NO_LCMS disables the "-p" option. + */ +#ifndef NO_JPEG +/*RT*/extern "C" { +/*RT*/#include +/*RT*/} +#endif +#ifndef NO_LCMS +#include +#endif +#ifdef LOCALEDIR +#include +#define _(String) gettext(String) +#else +#define _(String) (String) +#endif +#ifdef DJGPP +#define fseeko fseek +#define ftello ftell +#else +#define fgetc getc_unlocked +#endif +#ifdef __CYGWIN__ +#include +#endif +#ifdef WIN32 +#include +#include +#pragma comment(lib, "ws2_32.lib") +#define snprintf _snprintf +#define strcasecmp stricmp +#define strncasecmp strnicmp +typedef __int64 INT64; +typedef unsigned __int64 UINT64; +#else +#include +#include +#include +typedef long long INT64; +typedef unsigned long long UINT64; +#endif + +#ifdef LJPEG_DECODE +#error Please compile dcraw.c by itself. +#error Do not link it with ljpeg_decode. +#endif + +#ifndef LONG_BIT +#define LONG_BIT (8 * sizeof (long)) +#endif + +#define ushort UshORt +typedef unsigned char uchar; +typedef unsigned short ushort; + +/* + All global variables are defined here, and all functions that + access them are prefixed with "CLASS". Note that a thread-safe + C++ class cannot have non-const static local variables. + */ +/*RT*/IMFILE *ifp; +FILE * ofp; +short order; +const char *ifname; +char *meta_data; +char cdesc[5], desc[512], make[64], model[64], model2[64], artist[64]; +float flash_used, canon_ev, iso_speed, shutter, aperture, focal_len; +time_t timestamp; +unsigned shot_order, kodak_cbpp, filters, exif_cfa, unique_id; +off_t strip_offset, data_offset; +off_t thumb_offset, meta_offset, profile_offset; +unsigned thumb_length, meta_length, profile_length; +unsigned thumb_misc, *oprof, fuji_layout, shot_select=0, multi_out=0; +unsigned tiff_nifds, tiff_samples, tiff_bps, tiff_compress; +unsigned black, maximum, mix_green, raw_color, zero_is_bad; +unsigned zero_after_ff, is_raw, dng_version, is_foveon, data_error; +unsigned tile_width, tile_length, gpsdata[32], load_flags; +ushort raw_height, raw_width, height, width, top_margin, left_margin; +ushort shrink, iheight, iwidth, fuji_width, thumb_width, thumb_height; +int flip, tiff_flip, colors; +double pixel_aspect, aber[4]={1,1,1,1}, gamm[6]={ 0.45,4.5,0,0,0,0 }; +ushort (*image)[4], white[8][8], curve[0x10000], cr2_slice[3], sraw_mul[4]; +float bright=1, user_mul[4]={0,0,0,0}, threshold=0; +int half_size=0, four_color_rgb=0, document_mode=0, highlight=0; +int verbose=0, use_auto_wb=0, use_camera_wb=0, use_camera_matrix=-1; +int output_color=1, output_bps=8, output_tiff=0, med_passes=0; +int no_auto_bright=0; +unsigned greybox[4] = { 0, 0, UINT_MAX, UINT_MAX }; +float cam_mul[4], pre_mul[4], cmatrix[3][4], rgb_cam[3][4]; +const double xyz_rgb[3][3] = { /* XYZ from RGB */ + { 0.412453, 0.357580, 0.180423 }, + { 0.212671, 0.715160, 0.072169 }, + { 0.019334, 0.119193, 0.950227 } }; +const float d65_white[3] = { 0.950456, 1, 1.088754 }; +int histogram[4][0x2000]; +void (*write_thumb)(), (*write_fun)(); +void (*load_raw)(), (*thumb_load_raw)(); +jmp_buf failure; + +struct decode { + struct decode *branch[2]; + int leaf; +} first_decode[2048], *second_decode, *free_decode; + +struct tiff_ifd { + int width, height, bps, comp, phint, offset, flip, samples, bytes; +} tiff_ifd[10]; + +struct ph1 { + int format, key_off, black, black_off, split_col, tag_21a; + float tag_210; +} ph1; + +#define CLASS + +#define FORC(cnt) for (c=0; c < cnt; c++) +#define FORC3 FORC(3) +#define FORC4 FORC(4) +#define FORCC FORC(colors) + +#define SQR(x) ((x)*(x)) +#define ABS(x) (((int)(x) ^ ((int)(x) >> 31)) - ((int)(x) >> 31)) +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#define LIM(x,min,max) MAX(min,MIN(x,max)) +#define ULIM(x,y,z) ((y) < (z) ? LIM(x,y,z) : LIM(x,z,y)) +#define CLIP(x) LIM(x,0,65535) +#define SWAP(a,b) { a ^= b; a ^= (b ^= a); } + +/* + In order to inline this calculation, I make the risky + assumption that all filter patterns can be described + by a repeating pattern of eight rows and two columns + + Do not use the FC or BAYER macros with the Leaf CatchLight, + because its pattern is 16x16, not 2x8. + + Return values are either 0/1/2/3 = G/M/C/Y or 0/1/2/3 = R/G1/B/G2 + + PowerShot 600 PowerShot A50 PowerShot Pro70 Pro90 & G1 + 0xe1e4e1e4: 0x1b4e4b1e: 0x1e4b4e1b: 0xb4b4b4b4: + + 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 + 0 G M G M G M 0 C Y C Y C Y 0 Y C Y C Y C 0 G M G M G M + 1 C Y C Y C Y 1 M G M G M G 1 M G M G M G 1 Y C Y C Y C + 2 M G M G M G 2 Y C Y C Y C 2 C Y C Y C Y + 3 C Y C Y C Y 3 G M G M G M 3 G M G M G M + 4 C Y C Y C Y 4 Y C Y C Y C + PowerShot A5 5 G M G M G M 5 G M G M G M + 0x1e4e1e4e: 6 Y C Y C Y C 6 C Y C Y C Y + 7 M G M G M G 7 M G M G M G + 0 1 2 3 4 5 + 0 C Y C Y C Y + 1 G M G M G M + 2 C Y C Y C Y + 3 M G M G M G + + All RGB cameras use one of these Bayer grids: + + 0x16161616: 0x61616161: 0x49494949: 0x94949494: + + 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 + 0 B G B G B G 0 G R G R G R 0 G B G B G B 0 R G R G R G + 1 G R G R G R 1 B G B G B G 1 R G R G R G 1 G B G B G B + 2 B G B G B G 2 G R G R G R 2 G B G B G B 2 R G R G R G + 3 G R G R G R 3 B G B G B G 3 R G R G R G 3 G B G B G B + */ + +#define FC(row,col) \ + (filters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3) + +#define BAYER(row,col) \ + image[((row) >> shrink)*iwidth + ((col) >> shrink)][FC(row,col)] + +#define BAYER2(row,col) \ + image[((row) >> shrink)*iwidth + ((col) >> shrink)][fc(row,col)] + +int CLASS fc (int row, int col) +{ + static const char filter[16][16] = + { { 2,1,1,3,2,3,2,0,3,2,3,0,1,2,1,0 }, + { 0,3,0,2,0,1,3,1,0,1,1,2,0,3,3,2 }, + { 2,3,3,2,3,1,1,3,3,1,2,1,2,0,0,3 }, + { 0,1,0,1,0,2,0,2,2,0,3,0,1,3,2,1 }, + { 3,1,1,2,0,1,0,2,1,3,1,3,0,1,3,0 }, + { 2,0,0,3,3,2,3,1,2,0,2,0,3,2,2,1 }, + { 2,3,3,1,2,1,2,1,2,1,1,2,3,0,0,1 }, + { 1,0,0,2,3,0,0,3,0,3,0,3,2,1,2,3 }, + { 2,3,3,1,1,2,1,0,3,2,3,0,2,3,1,3 }, + { 1,0,2,0,3,0,3,2,0,1,1,2,0,1,0,2 }, + { 0,1,1,3,3,2,2,1,1,3,3,0,2,1,3,2 }, + { 2,3,2,0,0,1,3,0,2,0,1,2,3,0,1,0 }, + { 1,3,1,2,3,2,3,2,0,2,0,1,1,0,3,0 }, + { 0,2,0,3,1,0,0,1,1,3,3,2,3,2,2,1 }, + { 2,1,3,2,3,1,2,1,0,3,0,2,0,2,0,2 }, + { 0,3,1,0,0,2,0,3,2,1,3,1,1,3,1,3 } }; + + if (filters != 1) return FC(row,col); + return filter[(row+top_margin) & 15][(col+left_margin) & 15]; +} + +#ifndef __GLIBC__ +char *my_memmem (char *haystack, size_t haystacklen, + char *needle, size_t needlelen) +{ + char *c; + for (c = haystack; c <= haystack + haystacklen - needlelen; c++) + if (!memcmp (c, needle, needlelen)) + return c; + return 0; +} +#define memmem my_memmem +#endif + +void CLASS merror (void *ptr, const char *where) +{ + if (ptr) return; + fprintf (stderr,_("%s: Out of memory in %s\n"), ifname, where); + longjmp (failure, 1); +} + +void CLASS derror() +{ + if (!data_error) { + fprintf (stderr, "%s: ", ifname); + if (feof(ifp)) + fprintf (stderr,_("Unexpected end of file\n")); + else + fprintf (stderr,_("Corrupt data near 0x%llx\n"), (INT64) ftello(ifp)); + } + data_error++; + /*RT*/ longjmp (failure, 1); +} + +ushort CLASS sget2 (uchar *s) +{ + if (order == 0x4949) /* "II" means little-endian */ + return s[0] | s[1] << 8; + else /* "MM" means big-endian */ + return s[0] << 8 | s[1]; +} + +ushort CLASS get2() +{ + uchar str[2] = { 0xff,0xff }; + fread (str, 1, 2, ifp); + return sget2(str); +} + +unsigned CLASS sget4 (uchar *s) +{ + if (order == 0x4949) + return s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24; + else + return s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]; +} +#define sget4(s) sget4((uchar *)s) + +unsigned CLASS get4() +{ + uchar str[4] = { 0xff,0xff,0xff,0xff }; + fread (str, 1, 4, ifp); + return sget4(str); +} + +unsigned CLASS getint (int type) +{ + return type == 3 ? get2() : get4(); +} + +float CLASS int_to_float (int i) +{ + union { int i; float f; } u; + u.i = i; + return u.f; +} + +double CLASS getreal (int type) +{ + union { char c[8]; double d; } u; + int i, rev; + + switch (type) { + case 3: return (unsigned short) get2(); + case 4: return (unsigned int) get4(); + case 5: u.d = (unsigned int) get4(); + return u.d / (unsigned int) get4(); + case 8: return (signed short) get2(); + case 9: return (signed int) get4(); + case 10: u.d = (signed int) get4(); + return u.d / (signed int) get4(); + case 11: return int_to_float (get4()); + case 12: + rev = 7 * ((order == 0x4949) == (ntohs(0x1234) == 0x1234)); + for (i=0; i < 8; i++) + u.c[i ^ rev] = fgetc(ifp); + return u.d; + default: return fgetc(ifp); + } +} + +void CLASS read_shorts (ushort *pixel, int count) +{ + if (fread (pixel, 2, count, ifp) < count) derror(); + if ((order == 0x4949) == (ntohs(0x1234) == 0x1234)) + swab ((char*)pixel, (char*)pixel, count*2); +} + +void CLASS canon_black (double dark[2], int nblack) +{ + int c, diff, row, col; + + if (!nblack) return; + FORC(2) dark[c] /= nblack >> 1; + if ((diff = dark[0] - dark[1])) + for (row=0; row < height; row++) + for (col=1; col < width; col+=2) + BAYER(row,col) += diff; + dark[1] += diff; + black = (dark[0] + dark[1] + 1) / 2; +} + +void CLASS canon_600_fixed_wb (int temp) +{ + static const short mul[4][5] = { + { 667, 358,397,565,452 }, + { 731, 390,367,499,517 }, + { 1119, 396,348,448,537 }, + { 1399, 485,431,508,688 } }; + int lo, hi, i; + float frac=0; + + for (lo=4; --lo; ) + if (*mul[lo] <= temp) break; + for (hi=0; hi < 3; hi++) + if (*mul[hi] >= temp) break; + if (lo != hi) + frac = (float) (temp - *mul[lo]) / (*mul[hi] - *mul[lo]); + for (i=1; i < 5; i++) + pre_mul[i-1] = 1 / (frac * mul[hi][i] + (1-frac) * mul[lo][i]); +} + +/* Return values: 0 = white 1 = near white 2 = not white */ +int CLASS canon_600_color (int ratio[2], int mar) +{ + int clipped=0, target, miss; + + if (flash_used) { + if (ratio[1] < -104) + { ratio[1] = -104; clipped = 1; } + if (ratio[1] > 12) + { ratio[1] = 12; clipped = 1; } + } else { + if (ratio[1] < -264 || ratio[1] > 461) return 2; + if (ratio[1] < -50) + { ratio[1] = -50; clipped = 1; } + if (ratio[1] > 307) + { ratio[1] = 307; clipped = 1; } + } + target = flash_used || ratio[1] < 197 + ? -38 - (398 * ratio[1] >> 10) + : -123 + (48 * ratio[1] >> 10); + if (target - mar <= ratio[0] && + target + 20 >= ratio[0] && !clipped) return 0; + miss = target - ratio[0]; + if (abs(miss) >= mar*4) return 2; + if (miss < -20) miss = -20; + if (miss > mar) miss = mar; + ratio[0] = target - miss; + return 1; +} + +void CLASS canon_600_auto_wb() +{ + int mar, row, col, i, j, st, count[] = { 0,0 }; + int test[8], total[2][8], ratio[2][2], stat[2]; + + memset (&total, 0, sizeof total); + i = canon_ev + 0.5; + if (i < 10) mar = 150; + else if (i > 12) mar = 20; + else mar = 280 - 20 * i; + if (flash_used) mar = 80; + for (row=14; row < height-14; row+=4) + for (col=10; col < width; col+=2) { + for (i=0; i < 8; i++) + test[(i & 4) + FC(row+(i >> 1),col+(i & 1))] = + BAYER(row+(i >> 1),col+(i & 1)); + for (i=0; i < 8; i++) + if (test[i] < 150 || test[i] > 1500) goto next; + for (i=0; i < 4; i++) + if (abs(test[i] - test[i+4]) > 50) goto next; + for (i=0; i < 2; i++) { + for (j=0; j < 4; j+=2) + ratio[i][j >> 1] = ((test[i*4+j+1]-test[i*4+j]) << 10) / test[i*4+j]; + stat[i] = canon_600_color (ratio[i], mar); + } + if ((st = stat[0] | stat[1]) > 1) goto next; + for (i=0; i < 2; i++) + if (stat[i]) + for (j=0; j < 2; j++) + test[i*4+j*2+1] = test[i*4+j*2] * (0x400 + ratio[i][j]) >> 10; + for (i=0; i < 8; i++) + total[st][i] += test[i]; + count[st]++; +next: ; + } + if (count[0] | count[1]) { + st = count[0]*200 < count[1]; + for (i=0; i < 4; i++) + pre_mul[i] = 1.0 / (total[st][i] + total[st][i+4]); + } +} + +void CLASS canon_600_coeff() +{ + static const short table[6][12] = { + { -190,702,-1878,2390, 1861,-1349,905,-393, -432,944,2617,-2105 }, + { -1203,1715,-1136,1648, 1388,-876,267,245, -1641,2153,3921,-3409 }, + { -615,1127,-1563,2075, 1437,-925,509,3, -756,1268,2519,-2007 }, + { -190,702,-1886,2398, 2153,-1641,763,-251, -452,964,3040,-2528 }, + { -190,702,-1878,2390, 1861,-1349,905,-393, -432,944,2617,-2105 }, + { -807,1319,-1785,2297, 1388,-876,769,-257, -230,742,2067,-1555 } }; + int t=0, i, c; + float mc, yc; + + mc = pre_mul[1] / pre_mul[2]; + yc = pre_mul[3] / pre_mul[2]; + if (mc > 1 && mc <= 1.28 && yc < 0.8789) t=1; + if (mc > 1.28 && mc <= 2) { + if (yc < 0.8789) t=3; + else if (yc <= 2) t=4; + } + if (flash_used) t=5; + for (raw_color = i=0; i < 3; i++) + FORCC rgb_cam[i][c] = table[t][i*4 + c] / 1024.0; +} + +void CLASS canon_600_load_raw() +{ + uchar data[1120], *dp; + ushort pixel[896], *pix; + int irow, row, col, val; + static const short mul[4][2] = + { { 1141,1145 }, { 1128,1109 }, { 1178,1149 }, { 1128,1109 } }; + + for (irow=row=0; irow < height; irow++) { + if (fread (data, 1, raw_width*5/4, ifp) < raw_width*5/4) derror(); + for (dp=data, pix=pixel; dp < data+1120; dp+=10, pix+=8) { + pix[0] = (dp[0] << 2) + (dp[1] >> 6 ); + pix[1] = (dp[2] << 2) + (dp[1] >> 4 & 3); + pix[2] = (dp[3] << 2) + (dp[1] >> 2 & 3); + pix[3] = (dp[4] << 2) + (dp[1] & 3); + pix[4] = (dp[5] << 2) + (dp[9] & 3); + pix[5] = (dp[6] << 2) + (dp[9] >> 2 & 3); + pix[6] = (dp[7] << 2) + (dp[9] >> 4 & 3); + pix[7] = (dp[8] << 2) + (dp[9] >> 6 ); + } + for (col=0; col < width; col++) + BAYER(row,col) = pixel[col]; + for (col=width; col < raw_width; col++) + black += pixel[col]; + if ((row+=2) > height) row = 1; + } + if (raw_width > width) + black = black / ((raw_width - width) * height) - 4; + for (row=0; row < height; row++) + for (col=0; col < width; col++) { + if ((val = BAYER(row,col) - black) < 0) val = 0; + val = val * mul[row & 3][col & 1] >> 9; + BAYER(row,col) = val; + } + canon_600_fixed_wb(1311); + canon_600_auto_wb(); + canon_600_coeff(); + maximum = (0x3ff - black) * 1109 >> 9; + black = 0; +} + +void CLASS remove_zeroes() +{ + unsigned row, col, tot, n, r, c; + + for (row=0; row < height; row++) + for (col=0; col < width; col++) + if (BAYER(row,col) == 0) { + tot = n = 0; + for (r = row-2; r <= row+2; r++) + for (c = col-2; c <= col+2; c++) + if (r < height && c < width && + FC(r,c) == FC(row,col) && BAYER(r,c)) + tot += (n++,BAYER(r,c)); + if (n) BAYER(row,col) = tot/n; + } +} + +int CLASS canon_s2is() +{ + unsigned row; + + for (row=0; row < 100; row++) { + fseek (ifp, row*3340 + 3284, SEEK_SET); + if (getc(ifp) > 15) return 1; + } + return 0; +} + +/* + getbits(-1) initializes the buffer + getbits(n) where 0 <= n <= 25 returns an n-bit integer + */ +unsigned CLASS getbithuff (int nbits, ushort *huff) +{ + static unsigned bitbuf=0; + static int vbits=0, reset=0; + unsigned c; + + if (nbits == -1) + return bitbuf = vbits = reset = 0; + if (nbits == 0 || vbits < 0) return 0; + while (!reset && vbits < nbits && (c = fgetc(ifp)) != EOF && + !(reset = zero_after_ff && c == 0xff && fgetc(ifp))) { + bitbuf = (bitbuf << 8) + (uchar) c; + vbits += 8; + } + c = bitbuf << (32-vbits) >> (32-nbits); + if (huff) { + vbits -= huff[c] >> 8; + c = (uchar) huff[c]; + } else + vbits -= nbits; + if (vbits < 0) derror(); + return c; +} + +#define getbits(n) getbithuff(n,0) +#define gethuff(h) getbithuff(*h,h+1) + +/* + Construct a decode tree according the specification in *source. + The first 16 bytes specify how many codes should be 1-bit, 2-bit + 3-bit, etc. Bytes after that are the leaf values. + + For example, if the source is + + { 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0, + 0x04,0x03,0x05,0x06,0x02,0x07,0x01,0x08,0x09,0x00,0x0a,0x0b,0xff }, + + then the code is + + 00 0x04 + 010 0x03 + 011 0x05 + 100 0x06 + 101 0x02 + 1100 0x07 + 1101 0x01 + 11100 0x08 + 11101 0x09 + 11110 0x00 + 111110 0x0a + 1111110 0x0b + 1111111 0xff + */ +ushort * CLASS make_decoder_ref (const uchar **source) +{ + int max, len, h, i, j; + const uchar *count; + ushort *huff; + + count = (*source += 16) - 17; + for (max=16; max && !count[max]; max--); + huff = (ushort *) calloc (1 + (1 << max), sizeof *huff); + merror (huff, "make_decoder()"); + huff[0] = max; + for (h=len=1; len <= max; len++) + for (i=0; i < count[len]; i++, ++*source) + for (j=0; j < 1 << (max-len); j++) + if (h <= 1 << max) + huff[h++] = len << 8 | **source; + return huff; +} + +ushort * CLASS make_decoder (const uchar *source) +{ + return make_decoder_ref (&source); +} + +void CLASS crw_init_tables (unsigned table, ushort *huff[2]) +{ + static const uchar first_tree[3][29] = { + { 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0, + 0x04,0x03,0x05,0x06,0x02,0x07,0x01,0x08,0x09,0x00,0x0a,0x0b,0xff }, + { 0,2,2,3,1,1,1,1,2,0,0,0,0,0,0,0, + 0x03,0x02,0x04,0x01,0x05,0x00,0x06,0x07,0x09,0x08,0x0a,0x0b,0xff }, + { 0,0,6,3,1,1,2,0,0,0,0,0,0,0,0,0, + 0x06,0x05,0x07,0x04,0x08,0x03,0x09,0x02,0x00,0x0a,0x01,0x0b,0xff }, + }; + static const uchar second_tree[3][180] = { + { 0,2,2,2,1,4,2,1,2,5,1,1,0,0,0,139, + 0x03,0x04,0x02,0x05,0x01,0x06,0x07,0x08, + 0x12,0x13,0x11,0x14,0x09,0x15,0x22,0x00,0x21,0x16,0x0a,0xf0, + 0x23,0x17,0x24,0x31,0x32,0x18,0x19,0x33,0x25,0x41,0x34,0x42, + 0x35,0x51,0x36,0x37,0x38,0x29,0x79,0x26,0x1a,0x39,0x56,0x57, + 0x28,0x27,0x52,0x55,0x58,0x43,0x76,0x59,0x77,0x54,0x61,0xf9, + 0x71,0x78,0x75,0x96,0x97,0x49,0xb7,0x53,0xd7,0x74,0xb6,0x98, + 0x47,0x48,0x95,0x69,0x99,0x91,0xfa,0xb8,0x68,0xb5,0xb9,0xd6, + 0xf7,0xd8,0x67,0x46,0x45,0x94,0x89,0xf8,0x81,0xd5,0xf6,0xb4, + 0x88,0xb1,0x2a,0x44,0x72,0xd9,0x87,0x66,0xd4,0xf5,0x3a,0xa7, + 0x73,0xa9,0xa8,0x86,0x62,0xc7,0x65,0xc8,0xc9,0xa1,0xf4,0xd1, + 0xe9,0x5a,0x92,0x85,0xa6,0xe7,0x93,0xe8,0xc1,0xc6,0x7a,0x64, + 0xe1,0x4a,0x6a,0xe6,0xb3,0xf1,0xd3,0xa5,0x8a,0xb2,0x9a,0xba, + 0x84,0xa4,0x63,0xe5,0xc5,0xf3,0xd2,0xc4,0x82,0xaa,0xda,0xe4, + 0xf2,0xca,0x83,0xa3,0xa2,0xc3,0xea,0xc2,0xe2,0xe3,0xff,0xff }, + { 0,2,2,1,4,1,4,1,3,3,1,0,0,0,0,140, + 0x02,0x03,0x01,0x04,0x05,0x12,0x11,0x06, + 0x13,0x07,0x08,0x14,0x22,0x09,0x21,0x00,0x23,0x15,0x31,0x32, + 0x0a,0x16,0xf0,0x24,0x33,0x41,0x42,0x19,0x17,0x25,0x18,0x51, + 0x34,0x43,0x52,0x29,0x35,0x61,0x39,0x71,0x62,0x36,0x53,0x26, + 0x38,0x1a,0x37,0x81,0x27,0x91,0x79,0x55,0x45,0x28,0x72,0x59, + 0xa1,0xb1,0x44,0x69,0x54,0x58,0xd1,0xfa,0x57,0xe1,0xf1,0xb9, + 0x49,0x47,0x63,0x6a,0xf9,0x56,0x46,0xa8,0x2a,0x4a,0x78,0x99, + 0x3a,0x75,0x74,0x86,0x65,0xc1,0x76,0xb6,0x96,0xd6,0x89,0x85, + 0xc9,0xf5,0x95,0xb4,0xc7,0xf7,0x8a,0x97,0xb8,0x73,0xb7,0xd8, + 0xd9,0x87,0xa7,0x7a,0x48,0x82,0x84,0xea,0xf4,0xa6,0xc5,0x5a, + 0x94,0xa4,0xc6,0x92,0xc3,0x68,0xb5,0xc8,0xe4,0xe5,0xe6,0xe9, + 0xa2,0xa3,0xe3,0xc2,0x66,0x67,0x93,0xaa,0xd4,0xd5,0xe7,0xf8, + 0x88,0x9a,0xd7,0x77,0xc4,0x64,0xe2,0x98,0xa5,0xca,0xda,0xe8, + 0xf3,0xf6,0xa9,0xb2,0xb3,0xf2,0xd2,0x83,0xba,0xd3,0xff,0xff }, + { 0,0,6,2,1,3,3,2,5,1,2,2,8,10,0,117, + 0x04,0x05,0x03,0x06,0x02,0x07,0x01,0x08, + 0x09,0x12,0x13,0x14,0x11,0x15,0x0a,0x16,0x17,0xf0,0x00,0x22, + 0x21,0x18,0x23,0x19,0x24,0x32,0x31,0x25,0x33,0x38,0x37,0x34, + 0x35,0x36,0x39,0x79,0x57,0x58,0x59,0x28,0x56,0x78,0x27,0x41, + 0x29,0x77,0x26,0x42,0x76,0x99,0x1a,0x55,0x98,0x97,0xf9,0x48, + 0x54,0x96,0x89,0x47,0xb7,0x49,0xfa,0x75,0x68,0xb6,0x67,0x69, + 0xb9,0xb8,0xd8,0x52,0xd7,0x88,0xb5,0x74,0x51,0x46,0xd9,0xf8, + 0x3a,0xd6,0x87,0x45,0x7a,0x95,0xd5,0xf6,0x86,0xb4,0xa9,0x94, + 0x53,0x2a,0xa8,0x43,0xf5,0xf7,0xd4,0x66,0xa7,0x5a,0x44,0x8a, + 0xc9,0xe8,0xc8,0xe7,0x9a,0x6a,0x73,0x4a,0x61,0xc7,0xf4,0xc6, + 0x65,0xe9,0x72,0xe6,0x71,0x91,0x93,0xa6,0xda,0x92,0x85,0x62, + 0xf3,0xc5,0xb2,0xa4,0x84,0xba,0x64,0xa5,0xb3,0xd2,0x81,0xe5, + 0xd3,0xaa,0xc4,0xca,0xf2,0xb1,0xe4,0xd1,0x83,0x63,0xea,0xc3, + 0xe2,0x82,0xf1,0xa3,0xc2,0xa1,0xc1,0xe3,0xa2,0xe1,0xff,0xff } + }; + if (table > 2) table = 2; + huff[0] = make_decoder ( first_tree[table]); + huff[1] = make_decoder (second_tree[table]); +} + +/* + Return 0 if the image starts with compressed data, + 1 if it starts with uncompressed low-order bits. + + In Canon compressed data, 0xff is always followed by 0x00. + */ +int CLASS canon_has_lowbits() +{ + uchar test[0x4000]; + int ret=1, i; + + fseek (ifp, 0, SEEK_SET); + fread (test, 1, sizeof test, ifp); + for (i=540; i < sizeof test - 1; i++) + if (test[i] == 0xff) { + if (test[i+1]) return 1; + ret=0; + } + return ret; +} + +void CLASS canon_compressed_load_raw() +{ + ushort *pixel, *prow, *huff[2]; + int nblocks, lowbits, i, c, row, r, col, save, val, nblack=0; + unsigned irow, icol; + int block, diffbuf[64], leaf, len, diff, carry=0, pnum=0, base[2]; + double dark[2] = { 0,0 }; + + crw_init_tables (tiff_compress, huff); + pixel = (ushort *) calloc (raw_width*8, sizeof *pixel); + merror (pixel, "canon_compressed_load_raw()"); + lowbits = canon_has_lowbits(); + if (!lowbits) maximum = 0x3ff; + fseek (ifp, 540 + lowbits*raw_height*raw_width/4, SEEK_SET); + zero_after_ff = 1; + getbits(-1); + for (row=0; row < raw_height; row+=8) { + nblocks = MIN (8, raw_height-row) * raw_width >> 6; + for (block=0; block < nblocks; block++) { + memset (diffbuf, 0, sizeof diffbuf); + for (i=0; i < 64; i++ ) { + leaf = gethuff(huff[i > 0]); + if (leaf == 0 && i) break; + if (leaf == 0xff) continue; + i += leaf >> 4; + len = leaf & 15; + if (len == 0) continue; + diff = getbits(len); + if ((diff & (1 << (len-1))) == 0) + diff -= (1 << len) - 1; + if (i < 64) diffbuf[i] = diff; + } + diffbuf[0] += carry; + carry = diffbuf[0]; + for (i=0; i < 64; i++ ) { + if (pnum++ % raw_width == 0) + base[0] = base[1] = 512; + if ((pixel[(block << 6) + i] = base[i & 1] += diffbuf[i]) >> 10) + derror(); + } + } + if (lowbits) { + save = ftell(ifp); + fseek (ifp, 26 + row*raw_width/4, SEEK_SET); + for (prow=pixel, i=0; i < raw_width*2; i++) { + c = fgetc(ifp); + for (r=0; r < 8; r+=2, prow++) { + val = (*prow << 2) + ((c >> r) & 3); + if (raw_width == 2672 && val < 512) val += 2; + *prow = val; + } + } + fseek (ifp, save, SEEK_SET); + } + for (r=0; r < 8; r++) { + irow = row - top_margin + r; + if (irow >= height) continue; + for (col=0; col < raw_width; col++) { + icol = col - left_margin; + if (icol < width) + BAYER(irow,icol) = pixel[r*raw_width+col]; + else if (col > 1 && (unsigned) (col-left_margin+2) > width+3) + dark[icol & 1] += (nblack++,pixel[r*raw_width+col]); + } + } + } + free (pixel); + FORC(2) free (huff[c]); + canon_black (dark, nblack); +} + +/* + Not a full implementation of Lossless JPEG, just + enough to decode Canon, Kodak and Adobe DNG images. + */ +struct jhead { + int bits, high, wide, clrs, sraw, psv, restart, vpred[6]; + ushort *huff[6], *free[4], *row; +}; + +int CLASS ljpeg_start (struct jhead *jh, int info_only) +{ + int c, tag, len; + uchar data[0x10000]; + const uchar *dp; + + memset (jh, 0, sizeof *jh); + jh->restart = INT_MAX; + fread (data, 2, 1, ifp); + if (data[1] != 0xd8) return 0; + do { + fread (data, 2, 2, ifp); + tag = data[0] << 8 | data[1]; + len = (data[2] << 8 | data[3]) - 2; + if (tag <= 0xff00) return 0; + fread (data, 1, len, ifp); + switch (tag) { + case 0xffc3: + jh->sraw = ((data[7] >> 4) * (data[7] & 15) - 1) & 3; + case 0xffc0: + jh->bits = data[0]; + jh->high = data[1] << 8 | data[2]; + jh->wide = data[3] << 8 | data[4]; + jh->clrs = data[5] + jh->sraw; + if (len == 9 && !dng_version) getc(ifp); + break; + case 0xffc4: + if (info_only) break; + for (dp = data; dp < data+len && (c = *dp++) < 4; ) + jh->free[c] = jh->huff[c] = make_decoder_ref (&dp); + break; + case 0xffda: + jh->psv = data[1+data[0]*2]; + jh->bits -= data[3+data[0]*2] & 15; + break; + case 0xffdd: + jh->restart = data[0] << 8 | data[1]; + } + } while (tag != 0xffda); + if (info_only) return 1; + FORC(5) if (!jh->huff[c+1]) jh->huff[c+1] = jh->huff[c]; + if (jh->sraw) { + FORC(4) jh->huff[2+c] = jh->huff[1]; + FORC(jh->sraw) jh->huff[1+c] = jh->huff[0]; + } + jh->row = (ushort *) calloc (jh->wide*jh->clrs, 4); + merror (jh->row, "ljpeg_start()"); + return zero_after_ff = 1; +} + +void CLASS ljpeg_end (struct jhead *jh) +{ + int c; + FORC4 if (jh->free[c]) free (jh->free[c]); + free (jh->row); +} + +int CLASS ljpeg_diff (ushort *huff) +{ + int len, diff; + + len = gethuff(huff); + if (len == 16 && (!dng_version || dng_version >= 0x1010000)) + return -32768; + diff = getbits(len); + if ((diff & (1 << (len-1))) == 0) + diff -= (1 << len) - 1; + return diff; +} + +ushort * CLASS ljpeg_row (int jrow, struct jhead *jh) +{ + int col, c, diff, pred, spred=0; + ushort mark=0, *row[3]; + + if (jrow * jh->wide % jh->restart == 0) { + FORC(6) jh->vpred[c] = 1 << (jh->bits-1); + if (jrow) { + fseek (ifp, -2, SEEK_CUR); + do mark = (mark << 8) + (c = fgetc(ifp)); + while (c != EOF && mark >> 4 != 0xffd); + } + getbits(-1); + } + FORC3 row[c] = jh->row + jh->wide*jh->clrs*((jrow+c) & 1); + for (col=0; col < jh->wide; col++) + FORC(jh->clrs) { + diff = ljpeg_diff (jh->huff[c]); + if (jh->sraw && c <= jh->sraw && (col | c)) + pred = spred; + else if (col) pred = row[0][-jh->clrs]; + else pred = (jh->vpred[c] += diff) - diff; + if (jrow && col) switch (jh->psv) { + case 1: break; + case 2: pred = row[1][0]; break; + case 3: pred = row[1][-jh->clrs]; break; + case 4: pred = pred + row[1][0] - row[1][-jh->clrs]; break; + case 5: pred = pred + ((row[1][0] - row[1][-jh->clrs]) >> 1); break; + case 6: pred = row[1][0] + ((pred - row[1][-jh->clrs]) >> 1); break; + case 7: pred = (pred + row[1][0]) >> 1; break; + default: pred = 0; + } + if ((**row = pred + diff) >> jh->bits) derror(); + if (c <= jh->sraw) spred = **row; + row[0]++; row[1]++; + } + return row[2]; +} + +void CLASS lossless_jpeg_load_raw() +{ + int jwide, jrow, jcol, val, jidx, i, j, row=0, col=0, nblack=0; + double dark[2] = { 0,0 }; + struct jhead jh; + int min=INT_MAX; + ushort *rp; + + if (!ljpeg_start (&jh, 0)) return; + jwide = jh.wide * jh.clrs; + + for (jrow=0; jrow < jh.high; jrow++) { + rp = ljpeg_row (jrow, &jh); + for (jcol=0; jcol < jwide; jcol++) { + val = *rp++; + if (jh.bits <= 12) + val = curve[val & 0xfff]; + if (cr2_slice[0]) { + jidx = jrow*jwide + jcol; + i = jidx / (cr2_slice[1]*jh.high); + if ((j = i >= cr2_slice[0])) + i = cr2_slice[0]; + jidx -= i * (cr2_slice[1]*jh.high); + row = jidx / cr2_slice[1+j]; + col = jidx % cr2_slice[1+j] + i*cr2_slice[1]; + } + if (raw_width == 3984 && (col -= 2) < 0) + col += (row--,raw_width); + if ((unsigned) (row-top_margin) < height) { + if ((unsigned) (col-left_margin) < width) { + BAYER(row-top_margin,col-left_margin) = val; + if (min > val) min = val; + } else if (col > 1 && (unsigned) (col-left_margin+2) > width+3) + dark[(col-left_margin) & 1] += (nblack++,val); + } + if (++col >= raw_width) + col = (row++,0); + } + } + ljpeg_end (&jh); + canon_black (dark, nblack); + if (!strcasecmp(make,"KODAK")) + black = min; +} + +void CLASS canon_sraw_load_raw() +{ + struct jhead jh; + short *rp=0, (*ip)[4]; + int jwide, slice, scol, ecol, row, col, jrow=0, jcol=0, pix[3], c; + int v[3]={0,0,0}, ver, hue; + char *cp; + + if (!ljpeg_start (&jh, 0)) return; + jwide = (jh.wide >>= 1) * jh.clrs; + + for (ecol=slice=0; slice <= cr2_slice[0]; slice++) { + scol = ecol; + ecol += cr2_slice[1] * 2 / jh.clrs; + if (!cr2_slice[0] || ecol > raw_width-1) ecol = raw_width & -2; + for (row=0; row < height; row += (jh.clrs >> 1) - 1) { + ip = (short (*)[4]) image + row*width; + for (col=scol; col < ecol; col+=2, jcol+=jh.clrs) { + if ((jcol %= jwide) == 0) + rp = (short *) ljpeg_row (jrow++, &jh); + if (col >= width) continue; + FORC (jh.clrs-2) + ip[col + (c >> 1)*width + (c & 1)][0] = rp[jcol+c]; + ip[col][1] = rp[jcol+jh.clrs-2] - 16384; + ip[col][2] = rp[jcol+jh.clrs-1] - 16384; + } + } + } + for (cp=model2; *cp && !isdigit(*cp); cp++); + sscanf (cp, "%d.%d.%d", v, v+1, v+2); + ver = (v[0]*1000 + v[1])*1000 + v[2]; + hue = (jh.sraw+1) << 2; + if (unique_id == 0x80000218 && ver > 1000006 && ver < 3000000) + hue = jh.sraw << 1; + ip = (short (*)[4]) image; + rp = ip[0]; + for (row=0; row < height; row++, ip+=width) { + if (row & (jh.sraw >> 1)) + for (col=0; col < width; col+=2) + for (c=1; c < 3; c++) + if (row == height-1) + ip[col][c] = ip[col-width][c]; + else ip[col][c] = (ip[col-width][c] + ip[col+width][c] + 1) >> 1; + for (col=1; col < width; col+=2) + for (c=1; c < 3; c++) + if (col == width-1) + ip[col][c] = ip[col-1][c]; + else ip[col][c] = (ip[col-1][c] + ip[col+1][c] + 1) >> 1; + } + for ( ; rp < ip[0]; rp+=4) { + if (unique_id < 0x80000218) { + pix[0] = rp[0] + rp[2] - 512; + pix[2] = rp[0] + rp[1] - 512; + pix[1] = rp[0] + ((-778*rp[1] - (rp[2] << 11)) >> 12) - 512; + } else { + rp[1] = (rp[1] << 2) + hue; + rp[2] = (rp[2] << 2) + hue; + pix[0] = rp[0] + (( 200*rp[1] + 22929*rp[2]) >> 14); + pix[1] = rp[0] + ((-5640*rp[1] - 11751*rp[2]) >> 14); + pix[2] = rp[0] + ((29040*rp[1] - 101*rp[2]) >> 14); + } + FORC3 rp[c] = CLIP(pix[c] * sraw_mul[c] >> 10); + } + ljpeg_end (&jh); + maximum = 0x3fff; +} + +void CLASS adobe_copy_pixel (int row, int col, ushort **rp) +{ + unsigned r, c; + + r = row -= top_margin; + c = col -= left_margin; + if (is_raw == 2 && shot_select) (*rp)++; + if (filters) { + if (fuji_width) { + r = row + fuji_width - 1 - (col >> 1); + c = row + ((col+1) >> 1); + } + if (r < height && c < width) + BAYER(r,c) = **rp < 0x1000 ? curve[**rp] : **rp; + *rp += is_raw; + } else { + if (r < height && c < width) + FORC(tiff_samples) + image[row*width+col][c] = (*rp)[c] < 0x1000 ? curve[(*rp)[c]]:(*rp)[c]; + *rp += tiff_samples; + } + if (is_raw == 2 && shot_select) (*rp)--; +} + +void CLASS adobe_dng_load_raw_lj() +{ + unsigned save, trow=0, tcol=0, jwide, jrow, jcol, row, col; + struct jhead jh; + ushort *rp; + + while (trow < raw_height) { + save = ftell(ifp); + if (tile_length < INT_MAX) + fseek (ifp, get4(), SEEK_SET); + if (!ljpeg_start (&jh, 0)) break; + jwide = jh.wide; + if (filters) jwide *= jh.clrs; + jwide /= is_raw; + for (row=col=jrow=0; jrow < jh.high; jrow++) { + rp = ljpeg_row (jrow, &jh); + for (jcol=0; jcol < jwide; jcol++) { + adobe_copy_pixel (trow+row, tcol+col, &rp); + if (++col >= tile_width || col >= raw_width) + row += 1 + (col = 0); + } + } + fseek (ifp, save+4, SEEK_SET); + if ((tcol += tile_width) >= raw_width) + trow += tile_length + (tcol = 0); + ljpeg_end (&jh); + } +} + +void CLASS adobe_dng_load_raw_nc() +{ + ushort *pixel, *rp; + int row, col; + + pixel = (ushort *) calloc (raw_width * tiff_samples, sizeof *pixel); + merror (pixel, "adobe_dng_load_raw_nc()"); + for (row=0; row < raw_height; row++) { + if (tiff_bps == 16) + read_shorts (pixel, raw_width * tiff_samples); + else { + getbits(-1); + for (col=0; col < raw_width * tiff_samples; col++) + pixel[col] = getbits(tiff_bps); + } + for (rp=pixel, col=0; col < raw_width; col++) + adobe_copy_pixel (row, col, &rp); + } + free (pixel); +} + +void CLASS pentax_load_raw() +{ + ushort bit[2][13], huff[4097]; + int row, col, diff, c, i; + ushort vpred[2][2] = {{0,0},{0,0}}, hpred[2]; + + fseek (ifp, meta_offset, SEEK_SET); + FORC(13) bit[0][c] = get2(); + FORC(13) bit[1][c] = fgetc(ifp); + FORC(13) + for (i=bit[0][c]; i <= ((bit[0][c]+(4096 >> bit[1][c])-1) & 4095); ) + huff[++i] = bit[1][c] << 8 | c; + huff[0] = 12; + fseek (ifp, data_offset, SEEK_SET); + getbits(-1); + for (row=0; row < raw_height; row++) + for (col=0; col < raw_width; col++) { + diff = ljpeg_diff (huff); + if (col < 2) hpred[col] = vpred[row & 1][col] += diff; + else hpred[col & 1] += diff; + if ((unsigned) (row-top_margin) < height && col < width) + BAYER(row-top_margin,col) = hpred[col & 1]; + if (hpred[col & 1] >> 12) derror(); + } +} + +void CLASS nikon_compressed_load_raw() +{ + static const uchar nikon_tree[][32] = { + { 0,1,5,1,1,1,1,1,1,2,0,0,0,0,0,0, /* 12-bit lossy */ + 5,4,3,6,2,7,1,0,8,9,11,10,12 }, + { 0,1,5,1,1,1,1,1,1,2,0,0,0,0,0,0, /* 12-bit lossy after split */ + 0x39,0x5a,0x38,0x27,0x16,5,4,3,2,1,0,11,12,12 }, + { 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0, /* 12-bit lossless */ + 5,4,6,3,7,2,8,1,9,0,10,11,12 }, + { 0,1,4,3,1,1,1,1,1,2,0,0,0,0,0,0, /* 14-bit lossy */ + 5,6,4,7,8,3,9,2,1,0,10,11,12,13,14 }, + { 0,1,5,1,1,1,1,1,1,1,2,0,0,0,0,0, /* 14-bit lossy after split */ + 8,0x5c,0x4b,0x3a,0x29,7,6,5,4,3,2,1,0,13,14 }, + { 0,1,4,2,2,3,1,2,0,0,0,0,0,0,0,0, /* 14-bit lossless */ + 7,6,8,5,9,4,10,3,11,12,2,0,1,13,14 } }; + ushort *huff, ver0, ver1, vpred[2][2], hpred[2], csize; + int i, min, max, step=0, tree=0, split=0, row, col, len, shl, diff; + + fseek (ifp, meta_offset, SEEK_SET); + ver0 = fgetc(ifp); + ver1 = fgetc(ifp); + if (ver0 == 0x49 || ver1 == 0x58) + fseek (ifp, 2110, SEEK_CUR); + if (ver0 == 0x46) tree = 2; + if (tiff_bps == 14) tree += 3; + read_shorts (vpred[0], 4); + max = 1 << tiff_bps & 0x7fff; + if ((csize = get2()) > 1) + step = max / (csize-1); + if (ver0 == 0x44 && ver1 == 0x20 && step > 0) { + for (i=0; i < csize; i++) + curve[i*step] = get2(); + for (i=0; i < max; i++) + curve[i] = ( curve[i-i%step]*(step-i%step) + + curve[i-i%step+step]*(i%step) ) / step; + fseek (ifp, meta_offset+562, SEEK_SET); + split = get2(); + } else if (ver0 != 0x46 && csize <= 0x4001) + read_shorts (curve, max=csize); + while (curve[max-2] == curve[max-1]) max--; + huff = make_decoder (nikon_tree[tree]); + fseek (ifp, data_offset, SEEK_SET); + getbits(-1); + for (min=row=0; row < height; row++) { + if (split && row == split) { + free (huff); + huff = make_decoder (nikon_tree[tree+1]); + max += (min = 16) << 1; + } + for (col=0; col < raw_width; col++) { + i = gethuff(huff); + len = i & 15; + shl = i >> 4; + diff = ((getbits(len-shl) << 1) + 1) << shl >> 1; + if ((diff & (1 << (len-1))) == 0) + diff -= (1 << len) - !shl; + if (col < 2) hpred[col] = vpred[row & 1][col] += diff; + else hpred[col & 1] += diff; + if ((ushort)(hpred[col & 1] + min) >= max) derror(); + if ((unsigned) (col-left_margin) < width) + BAYER(row,col-left_margin) = curve[LIM((short)hpred[col & 1],0,0x3fff)]; + } + } + free (huff); +} + +/* + Figure out if a NEF file is compressed. These fancy heuristics + are only needed for the D100, thanks to a bug in some cameras + that tags all images as "compressed". + */ +int CLASS nikon_is_compressed() +{ + uchar test[256]; + int i; + + fseek (ifp, data_offset, SEEK_SET); + fread (test, 1, 256, ifp); + for (i=15; i < 256; i+=16) + if (test[i]) return 1; + return 0; +} + +/* + Returns 1 for a Coolpix 995, 0 for anything else. + */ +int CLASS nikon_e995() +{ + int i, histo[256]; + const uchar often[] = { 0x00, 0x55, 0xaa, 0xff }; + + memset (histo, 0, sizeof histo); + fseek (ifp, -2000, SEEK_END); + for (i=0; i < 2000; i++) + histo[fgetc(ifp)]++; + for (i=0; i < 4; i++) + if (histo[often[i]] < 200) + return 0; + return 1; +} + +/* + Returns 1 for a Coolpix 2100, 0 for anything else. + */ +int CLASS nikon_e2100() +{ + uchar t[12]; + int i; + + fseek (ifp, 0, SEEK_SET); + for (i=0; i < 1024; i++) { + fread (t, 1, 12, ifp); + if (((t[2] & t[4] & t[7] & t[9]) >> 4 + & t[1] & t[6] & t[8] & t[11] & 3) != 3) + return 0; + } + return 1; +} + +void CLASS nikon_3700() +{ + int bits, i; + uchar dp[24]; + static const struct { + int bits; + char make[12], model[15]; + } table[] = { + { 0x00, "PENTAX", "Optio 33WR" }, + { 0x03, "NIKON", "E3200" }, + { 0x32, "NIKON", "E3700" }, + { 0x33, "OLYMPUS", "C740UZ" } }; + + fseek (ifp, 3072, SEEK_SET); + fread (dp, 1, 24, ifp); + bits = (dp[8] & 3) << 4 | (dp[20] & 3); + for (i=0; i < sizeof table / sizeof *table; i++) + if (bits == table[i].bits) { + strcpy (make, table[i].make ); + strcpy (model, table[i].model); + } +} + +/* + Separates a Minolta DiMAGE Z2 from a Nikon E4300. + */ +int CLASS minolta_z2() +{ + int i, nz; + char tail[424]; + + fseek (ifp, -sizeof tail, SEEK_END); + fread (tail, 1, sizeof tail, ifp); + for (nz=i=0; i < sizeof tail; i++) + if (tail[i]) nz++; + return nz > 20; +} + +/* + The Fuji Super CCD is just a Bayer grid rotated 45 degrees. + */ +void CLASS fuji_load_raw() +{ + ushort *pixel; + int wide, row, col, r, c; + + fseek (ifp, (top_margin*raw_width + left_margin) * 2, SEEK_CUR); + wide = fuji_width << !fuji_layout; + pixel = (ushort *) calloc (wide, sizeof *pixel); + merror (pixel, "fuji_load_raw()"); + for (row=0; row < raw_height; row++) { + read_shorts (pixel, wide); + fseek (ifp, 2*(raw_width - wide), SEEK_CUR); + for (col=0; col < wide; col++) { + if (fuji_layout) { + r = fuji_width - 1 - col + (row >> 1); + c = col + ((row+1) >> 1); + } else { + r = fuji_width - 1 + row - (col >> 1); + c = row + ((col+1) >> 1); + } + BAYER(r,c) = pixel[col]; + } + } + free (pixel); +} + +void CLASS jpeg_thumb(); + +void CLASS ppm_thumb() +{ + char *thumb; + thumb_length = thumb_width*thumb_height*3; + thumb = (char *) malloc (thumb_length); + merror (thumb, "ppm_thumb()"); + fprintf (ofp, "P6\n%d %d\n255\n", thumb_width, thumb_height); + fread (thumb, 1, thumb_length, ifp); + fwrite (thumb, 1, thumb_length, ofp); + free (thumb); +} + +void CLASS layer_thumb() +{ + int i, c; + char *thumb, map[][4] = { "012","102" }; + + colors = thumb_misc >> 5 & 7; + thumb_length = thumb_width*thumb_height; + thumb = (char *) calloc (colors, thumb_length); + merror (thumb, "layer_thumb()"); + fprintf (ofp, "P%d\n%d %d\n255\n", + 5 + (colors >> 1), thumb_width, thumb_height); + fread (thumb, thumb_length, colors, ifp); + for (i=0; i < thumb_length; i++) + FORCC putc (thumb[i+thumb_length*(map[thumb_misc >> 8][c]-'0')], ofp); + free (thumb); +} + +void CLASS rollei_thumb() +{ + unsigned i; + ushort *thumb; + + thumb_length = thumb_width * thumb_height; + thumb = (ushort *) calloc (thumb_length, 2); + merror (thumb, "rollei_thumb()"); + fprintf (ofp, "P6\n%d %d\n255\n", thumb_width, thumb_height); + read_shorts (thumb, thumb_length); + for (i=0; i < thumb_length; i++) { + putc (thumb[i] << 3, ofp); + putc (thumb[i] >> 5 << 2, ofp); + putc (thumb[i] >> 11 << 3, ofp); + } + free (thumb); +} + +void CLASS rollei_load_raw() +{ + uchar pixel[10]; + unsigned iten=0, isix, i, buffer=0, row, col, todo[16]; + + isix = raw_width * raw_height * 5 / 8; + while (fread (pixel, 1, 10, ifp) == 10) { + for (i=0; i < 10; i+=2) { + todo[i] = iten++; + todo[i+1] = pixel[i] << 8 | pixel[i+1]; + buffer = pixel[i] >> 2 | buffer << 6; + } + for ( ; i < 16; i+=2) { + todo[i] = isix++; + todo[i+1] = buffer >> (14-i)*5; + } + for (i=0; i < 16; i+=2) { + row = todo[i] / raw_width - top_margin; + col = todo[i] % raw_width - left_margin; + if (row < height && col < width) + BAYER(row,col) = (todo[i+1] & 0x3ff); + } + } + maximum = 0x3ff; +} + +int CLASS bayer (unsigned row, unsigned col) +{ + return (row < height && col < width) ? BAYER(row,col) : 0; +} + +void CLASS phase_one_flat_field (int is_float, int nc) +{ + ushort head[8]; + unsigned wide, y, x, c, rend, cend, row, col; + float *mrow, num, mult[4]; + + read_shorts (head, 8); + wide = head[2] / head[4]; + mrow = (float *) calloc (nc*wide, sizeof *mrow); + merror (mrow, "phase_one_flat_field()"); + for (y=0; y < head[3] / head[5]; y++) { + for (x=0; x < wide; x++) + for (c=0; c < nc; c+=2) { + num = is_float ? getreal(11) : get2()/32768.0; + if (y==0) mrow[c*wide+x] = num; + else mrow[(c+1)*wide+x] = (num - mrow[c*wide+x]) / head[5]; + } + if (y==0) continue; + rend = head[1]-top_margin + y*head[5]; + for (row = rend-head[5]; row < height && row < rend; row++) { + for (x=1; x < wide; x++) { + for (c=0; c < nc; c+=2) { + mult[c] = mrow[c*wide+x-1]; + mult[c+1] = (mrow[c*wide+x] - mult[c]) / head[4]; + } + cend = head[0]-left_margin + x*head[4]; + for (col = cend-head[4]; col < width && col < cend; col++) { + c = nc > 2 ? FC(row,col) : 0; + if (!(c & 1)) { + c = BAYER(row,col) * mult[c]; + BAYER(row,col) = LIM(c,0,65535); + } + for (c=0; c < nc; c+=2) + mult[c] += mult[c+1]; + } + } + for (x=0; x < wide; x++) + for (c=0; c < nc; c+=2) + mrow[c*wide+x] += mrow[(c+1)*wide+x]; + } + } + free (mrow); +} + +void CLASS phase_one_correct() +{ + unsigned entries, tag, data, save, col, row, type; + int len, i, j, k, cip, val[4], dev[4], sum, max; + int head[9], diff, mindiff=INT_MAX, off_412=0; + static const signed char dir[12][2] = + { {-1,-1}, {-1,1}, {1,-1}, {1,1}, {-2,0}, {0,-2}, {0,2}, {2,0}, + {-2,-2}, {-2,2}, {2,-2}, {2,2} }; + float poly[8], num, cfrac, frac, mult[2], *yval[2]; + ushort *xval[2]; + + if (half_size || !meta_length) return; + if (verbose) fprintf (stderr,_("Phase One correction...\n")); + fseek (ifp, meta_offset, SEEK_SET); + order = get2(); + fseek (ifp, 6, SEEK_CUR); + fseek (ifp, meta_offset+get4(), SEEK_SET); + entries = get4(); get4(); + while (entries--) { + tag = get4(); + len = get4(); + data = get4(); + save = ftell(ifp); + fseek (ifp, meta_offset+data, SEEK_SET); + if (tag == 0x419) { /* Polynomial curve */ + for (get4(), i=0; i < 8; i++) + poly[i] = getreal(11); + poly[3] += (ph1.tag_210 - poly[7]) * poly[6] + 1; + for (i=0; i < 0x10000; i++) { + num = (poly[5]*i + poly[3])*i + poly[1]; + curve[i] = LIM(num,0,65535); + } goto apply; /* apply to right half */ + } else if (tag == 0x41a) { /* Polynomial curve */ + for (i=0; i < 4; i++) + poly[i] = getreal(11); + for (i=0; i < 0x10000; i++) { + for (num=0, j=4; j--; ) + num = num * i + poly[j]; + curve[i] = LIM(num+i,0,65535); + } apply: /* apply to whole image */ + for (row=0; row < height; row++) + for (col = (tag & 1)*ph1.split_col; col < width; col++) + BAYER(row,col) = curve[BAYER(row,col)]; + } else if (tag == 0x400) { /* Sensor defects */ + while ((len -= 8) >= 0) { + col = get2() - left_margin; + row = get2() - top_margin; + type = get2(); get2(); + if (col >= width) continue; + if (type == 131) /* Bad column */ + for (row=0; row < height; row++) + if (FC(row,col) == 1) { + for (sum=i=0; i < 4; i++) + sum += val[i] = bayer (row+dir[i][0], col+dir[i][1]); + for (max=i=0; i < 4; i++) { + dev[i] = abs((val[i] << 2) - sum); + if (dev[max] < dev[i]) max = i; + } + BAYER(row,col) = (sum - val[max])/3.0 + 0.5; + } else { + for (sum=0, i=8; i < 12; i++) + sum += bayer (row+dir[i][0], col+dir[i][1]); + BAYER(row,col) = 0.5 + sum * 0.0732233 + + (bayer(row,col-2) + bayer(row,col+2)) * 0.3535534; + } + else if (type == 129) { /* Bad pixel */ + if (row >= height) continue; + j = (FC(row,col) != 1) * 4; + for (sum=0, i=j; i < j+8; i++) + sum += bayer (row+dir[i][0], col+dir[i][1]); + BAYER(row,col) = (sum + 4) >> 3; + } + } + } else if (tag == 0x401) { /* All-color flat fields */ + phase_one_flat_field (1, 2); + } else if (tag == 0x416 || tag == 0x410) { + phase_one_flat_field (0, 2); + } else if (tag == 0x40b) { /* Red+blue flat field */ + phase_one_flat_field (0, 4); + } else if (tag == 0x412) { + fseek (ifp, 36, SEEK_CUR); + diff = abs (get2() - ph1.tag_21a); + if (mindiff > diff) { + mindiff = diff; + off_412 = ftell(ifp) - 38; + } + } + fseek (ifp, save, SEEK_SET); + } + if (off_412) { + fseek (ifp, off_412, SEEK_SET); + for (i=0; i < 9; i++) head[i] = get4() & 0x7fff; + yval[0] = (float *) calloc (head[1]*head[3] + head[2]*head[4], 6); + merror (yval[0], "phase_one_correct()"); + yval[1] = (float *) (yval[0] + head[1]*head[3]); + xval[0] = (ushort *) (yval[1] + head[2]*head[4]); + xval[1] = (ushort *) (xval[0] + head[1]*head[3]); + get2(); + for (i=0; i < 2; i++) + for (j=0; j < head[i+1]*head[i+3]; j++) + yval[i][j] = getreal(11); + for (i=0; i < 2; i++) + for (j=0; j < head[i+1]*head[i+3]; j++) + xval[i][j] = get2(); + for (row=0; row < height; row++) + for (col=0; col < width; col++) { + cfrac = (float) col * head[3] / raw_width; + cfrac -= cip = cfrac; + num = BAYER(row,col) * 0.5; + for (i=cip; i < cip+2; i++) { + for (k=j=0; j < head[1]; j++) + if (num < xval[0][k = head[1]*i+j]) break; + frac = (j == 0 || j == head[1]) ? 0 : + (xval[0][k] - num) / (xval[0][k] - xval[0][k-1]); + mult[i-cip] = yval[0][k-1] * frac + yval[0][k] * (1-frac); + } + i = ((mult[0] * (1-cfrac) + mult[1] * cfrac) + * (row + top_margin) + num) * 2; + BAYER(row,col) = LIM(i,0,65535); + } + free (yval[0]); + } +} + +void CLASS phase_one_load_raw() +{ + int row, col, a, b; + ushort *pixel, akey, bkey, mask; + + fseek (ifp, ph1.key_off, SEEK_SET); + akey = get2(); + bkey = get2(); + mask = ph1.format == 1 ? 0x5555:0x1354; + fseek (ifp, data_offset + top_margin*raw_width*2, SEEK_SET); + pixel = (ushort *) calloc (raw_width, sizeof *pixel); + merror (pixel, "phase_one_load_raw()"); + for (row=0; row < height; row++) { + read_shorts (pixel, raw_width); + for (col=0; col < raw_width; col+=2) { + a = pixel[col+0] ^ akey; + b = pixel[col+1] ^ bkey; + pixel[col+0] = (a & mask) | (b & ~mask); + pixel[col+1] = (b & mask) | (a & ~mask); + } + for (col=0; col < width; col++) + BAYER(row,col) = pixel[col+left_margin]; + } + free (pixel); + phase_one_correct(); +} + +unsigned CLASS ph1_bithuff (int nbits, ushort *huff) +{ + static UINT64 bitbuf=0; + static int vbits=0; + unsigned c; + + if (nbits == -1) + return bitbuf = vbits = 0; + if (nbits == 0) return 0; + if (vbits < nbits) { + bitbuf = bitbuf << 32 | get4(); + vbits += 32; + } + c = bitbuf << (64-vbits) >> (64-nbits); + if (huff) { + vbits -= huff[c] >> 8; + return (uchar) huff[c]; + } + vbits -= nbits; + return c; +} +#define ph1_bits(n) ph1_bithuff(n,0) +#define ph1_huff(h) ph1_bithuff(*h,h+1) + +void CLASS phase_one_load_raw_c() +{ + static const int length[] = { 8,7,6,9,11,10,5,12,14,13 }; + int *offset, len[2], pred[2], row, col, i, j; + ushort *pixel; + short (*black)[2]; + + pixel = (ushort *) calloc (raw_width + raw_height*4, 2); + merror (pixel, "phase_one_load_raw_c()"); + offset = (int *) (pixel + raw_width); + fseek (ifp, strip_offset, SEEK_SET); + for (row=0; row < raw_height; row++) + offset[row] = get4(); + black = (short (*)[2]) offset + raw_height; + fseek (ifp, ph1.black_off, SEEK_SET); + if (ph1.black_off) + read_shorts ((ushort *) black[0], raw_height*2); + for (i=0; i < 256; i++) + curve[i] = i*i / 3.969 + 0.5; + for (row=0; row < raw_height; row++) { + fseek (ifp, data_offset + offset[row], SEEK_SET); + ph1_bits(-1); + pred[0] = pred[1] = 0; + for (col=0; col < raw_width; col++) { + if (col >= (raw_width & -8)) + len[0] = len[1] = 14; + else if ((col & 7) == 0) + for (i=0; i < 2; i++) { + for (j=0; j < 5 && !ph1_bits(1); j++); + if (j--) len[i] = length[j*2 + ph1_bits(1)]; + } + if ((i = len[col & 1]) == 14) + pixel[col] = pred[col & 1] = ph1_bits(16); + else + pixel[col] = pred[col & 1] += ph1_bits(i) + 1 - (1 << (i - 1)); + if (pred[col & 1] >> 16) derror(); + if (ph1.format == 5 && pixel[col] < 256) + pixel[col] = curve[pixel[col]]; + } + if ((unsigned) (row-top_margin) < height) + for (col=0; col < width; col++) { + i = (pixel[col+left_margin] << 2) + - ph1.black + black[row][col >= ph1.split_col]; + if (i > 0) BAYER(row-top_margin,col) = i; + } + } + free (pixel); + phase_one_correct(); + maximum = 0xfffc - ph1.black; +} + +void CLASS hasselblad_load_raw() +{ + struct jhead jh; + int row, col, pred[2], len[2], diff, c; + + if (!ljpeg_start (&jh, 0)) return; + order = 0x4949; + ph1_bits(-1); + for (row=-top_margin; row < height; row++) { + pred[0] = pred[1] = 0x8000; + for (col=-left_margin; col < raw_width-left_margin; col+=2) { + FORC(2) len[c] = ph1_huff(jh.huff[0]); + FORC(2) { + diff = ph1_bits(len[c]); + if ((diff & (1 << (len[c]-1))) == 0) + diff -= (1 << len[c]) - 1; + if (diff == 65535) diff = -32768; + pred[c] += diff; + if (row >= 0 && (unsigned)(col+c) < width) + BAYER(row,col+c) = pred[c]; + } + } + } + ljpeg_end (&jh); + maximum = 0xffff; +} + +void CLASS leaf_hdr_load_raw() +{ + ushort *pixel; + unsigned tile=0, r, c, row, col; + + pixel = (ushort *) calloc (raw_width, sizeof *pixel); + merror (pixel, "leaf_hdr_load_raw()"); + FORC(tiff_samples) + for (r=0; r < raw_height; r++) { + if (r % tile_length == 0) { + fseek (ifp, data_offset + 4*tile++, SEEK_SET); + fseek (ifp, get4() + 2*left_margin, SEEK_SET); + } + if (filters && c != shot_select) continue; + read_shorts (pixel, raw_width); + if ((row = r - top_margin) >= height) continue; + for (col=0; col < width; col++) + if (filters) BAYER(row,col) = pixel[col]; + else image[row*width+col][c] = pixel[col]; + } + free (pixel); + if (!filters) { + maximum = 0xffff; + raw_color = 1; + } +} + +void CLASS unpacked_load_raw(); + +void CLASS sinar_4shot_load_raw() +{ + ushort *pixel; + unsigned shot, row, col, r, c; + + if ((shot = shot_select) || half_size) { + if (shot) shot--; + if (shot > 3) shot = 3; + fseek (ifp, data_offset + shot*4, SEEK_SET); + fseek (ifp, get4(), SEEK_SET); + unpacked_load_raw(); + return; + } + free (image); + image = (ushort (*)[4]) + calloc ((iheight=height)*(iwidth=width), sizeof *image); + merror (image, "sinar_4shot_load_raw()"); + pixel = (ushort *) calloc (raw_width, sizeof *pixel); + merror (pixel, "sinar_4shot_load_raw()"); + for (shot=0; shot < 4; shot++) { + fseek (ifp, data_offset + shot*4, SEEK_SET); + fseek (ifp, get4(), SEEK_SET); + for (row=0; row < raw_height; row++) { + read_shorts (pixel, raw_width); + if ((r = row-top_margin - (shot >> 1 & 1)) >= height) continue; + for (col=0; col < raw_width; col++) { + if ((c = col-left_margin - (shot & 1)) >= width) continue; + image[r*width+c][FC(row,col)] = pixel[col]; + } + } + } + free (pixel); + shrink = filters = 0; +} + +void CLASS imacon_full_load_raw() +{ + int row, col; + + for (row=0; row < height; row++) + for (col=0; col < width; col++) + read_shorts (image[row*width+col], 3); +} + +void CLASS packed_load_raw() +{ + int vbits=0, bwide, pwide, rbits, bite, half, irow, row, col, val, i; + UINT64 bitbuf=0; + + if (raw_width * 8 >= width * tiff_bps) /* Is raw_width in bytes? */ + pwide = (bwide = raw_width) * 8 / tiff_bps; + else bwide = (pwide = raw_width) * tiff_bps / 8; + rbits = bwide * 8 - pwide * tiff_bps; + if (load_flags & 1) bwide = bwide * 16 / 15; + fseek (ifp, top_margin*bwide, SEEK_CUR); + bite = 8 + (load_flags & 24); + half = (height+1) >> 1; + for (irow=0; irow < height; irow++) { + row = irow; + if (load_flags & 2 && + (row = irow % half * 2 + irow / half) == 1 && + load_flags & 4) { + if (vbits=0, tiff_compress) + fseek (ifp, data_offset - (-half*bwide & -2048), SEEK_SET); + else { + fseek (ifp, 0, SEEK_END); + fseek (ifp, ftell(ifp) >> 3 << 2, SEEK_SET); + } + } + for (col=0; col < pwide; col++) { + for (vbits -= tiff_bps; vbits < 0; vbits += bite) { + bitbuf <<= bite; + for (i=0; i < bite; i+=8) + bitbuf |= (unsigned) (fgetc(ifp) << i); + } + val = bitbuf << (64-tiff_bps-vbits) >> (64-tiff_bps); + i = (col ^ (bite == 24)) - left_margin; + if ((unsigned) i < width) + BAYER(row,i) = val << (load_flags >> 6); + else if (load_flags & 32) + black += val; + if (load_flags & 1 && (col % 10) == 9 && + fgetc(ifp) && col < width+left_margin) derror(); + } + vbits -= rbits; + } + if (load_flags & 32 && pwide > width) + black /= (pwide - width) * height; +} + +void CLASS unpacked_load_raw() +{ + ushort *pixel; + int row, col, bits=0; + + while (1 << ++bits < maximum); + fseek (ifp, (top_margin*raw_width + left_margin) * 2, SEEK_CUR); + pixel = (ushort *) calloc (width, sizeof *pixel); + merror (pixel, "unpacked_load_raw()"); + for (row=0; row < height; row++) { + read_shorts (pixel, width); + fseek (ifp, 2*(raw_width - width), SEEK_CUR); + for (col=0; col < width; col++) + if ((BAYER2(row,col) = pixel[col]) >> bits) derror(); + } + free (pixel); +} + +void CLASS nokia_load_raw() +{ + uchar *data, *dp; + ushort *pixel, *pix; + int dwide, row, c; + + dwide = raw_width * 5 / 4; + data = (uchar *) malloc (dwide + raw_width*2); + merror (data, "nokia_load_raw()"); + pixel = (ushort *) (data + dwide); + for (row=0; row < raw_height; row++) { + if (fread (data, 1, dwide, ifp) < dwide) derror(); + for (dp=data, pix=pixel; pix < pixel+raw_width; dp+=5, pix+=4) + FORC4 pix[c] = (dp[c] << 2) | (dp[4] >> (c << 1) & 3); + if (row < top_margin) + FORC(width) black += pixel[c]; + else + FORC(width) BAYER(row-top_margin,c) = pixel[c]; + } + free (data); + if (top_margin) black /= top_margin * width; + maximum = 0x3ff; +} + +unsigned CLASS pana_bits (int nbits) +{ + static uchar buf[0x4000]; + static int vbits; + int byte; + + if (!nbits) return vbits=0; + if (!vbits) { + fread (buf+load_flags, 1, 0x4000-load_flags, ifp); + fread (buf, 1, load_flags, ifp); + } + vbits = (vbits - nbits) & 0x1ffff; + byte = vbits >> 3 ^ 0x3ff0; + return (buf[byte] | buf[byte+1] << 8) >> (vbits & 7) & ~(-1 << nbits); +} + +void CLASS panasonic_load_raw() +{ + int row, col, i, j, sh=0, pred[2], nonz[2]; + + pana_bits(0); + for (row=0; row < height; row++) + for (col=0; col < raw_width; col++) { + if ((i = col % 14) == 0) + pred[0] = pred[1] = nonz[0] = nonz[1] = 0; + if (i % 3 == 2) sh = 4 >> (3 - pana_bits(2)); + if (nonz[i & 1]) { + if ((j = pana_bits(8))) { + if ((pred[i & 1] -= 0x80 << sh) < 0 || sh == 4) + pred[i & 1] &= ~(-1 << sh); + pred[i & 1] += j << sh; + } + } else if ((nonz[i & 1] = pana_bits(8)) || i > 11) + pred[i & 1] = nonz[i & 1] << 4 | pana_bits(4); + if (col < width) + if ((BAYER(row,col) = pred[col & 1]) > 4098) derror(); + } +} + +void CLASS olympus_load_raw() +{ + ushort huff[4096]; + int row, col, nbits, sign, low, high, i, c, w, n, nw; + int acarry[2][3], *carry, pred, diff; + + huff[n=0] = 0xc0c; + for (i=12; i--; ) + FORC(2048 >> i) huff[++n] = (i+1) << 8 | i; + fseek (ifp, 7, SEEK_CUR); + getbits(-1); + for (row=0; row < height; row++) { + memset (acarry, 0, sizeof acarry); + for (col=0; col < raw_width; col++) { + carry = acarry[col & 1]; + i = 2 * (carry[2] < 3); + for (nbits=2+i; (ushort) carry[0] >> (nbits+i); nbits++); + low = (sign = getbits(3)) & 3; + sign = sign << 29 >> 31; + if ((high = getbithuff(12,huff)) == 12) + high = getbits(16-nbits) >> 1; + carry[0] = (high << nbits) | getbits(nbits); + diff = (carry[0] ^ sign) + carry[1]; + carry[1] = (diff*3 + carry[1]) >> 5; + carry[2] = carry[0] > 16 ? 0 : carry[2]+1; + if (col >= width) continue; + if (row < 2 && col < 2) pred = 0; + else if (row < 2) pred = BAYER(row,col-2); + else if (col < 2) pred = BAYER(row-2,col); + else { + w = BAYER(row,col-2); + n = BAYER(row-2,col); + nw = BAYER(row-2,col-2); + if ((w < nw && nw < n) || (n < nw && nw < w)) { + if (ABS(w-nw) > 32 || ABS(n-nw) > 32) + pred = w + n - nw; + else pred = (w + n) >> 1; + } else pred = ABS(w-nw) > ABS(n-nw) ? w : n; + } + if ((BAYER(row,col) = pred + ((diff << 2) | low)) >> 12) derror(); + } + } +} + +void CLASS minolta_rd175_load_raw() +{ + uchar pixel[768]; + unsigned irow, box, row, col; + + for (irow=0; irow < 1481; irow++) { + if (fread (pixel, 1, 768, ifp) < 768) derror(); + box = irow / 82; + row = irow % 82 * 12 + ((box < 12) ? box | 1 : (box-12)*2); + switch (irow) { + case 1477: case 1479: continue; + case 1476: row = 984; break; + case 1480: row = 985; break; + case 1478: row = 985; box = 1; + } + if ((box < 12) && (box & 1)) { + for (col=0; col < 1533; col++, row ^= 1) + if (col != 1) BAYER(row,col) = (col+1) & 2 ? + pixel[col/2-1] + pixel[col/2+1] : pixel[col/2] << 1; + BAYER(row,1) = pixel[1] << 1; + BAYER(row,1533) = pixel[765] << 1; + } else + for (col=row & 1; col < 1534; col+=2) + BAYER(row,col) = pixel[col/2] << 1; + } + maximum = 0xff << 1; +} + +void CLASS quicktake_100_load_raw() +{ + uchar pixel[484][644]; + static const short gstep[16] = + { -89,-60,-44,-32,-22,-15,-8,-2,2,8,15,22,32,44,60,89 }; + static const short rstep[6][4] = + { { -3,-1,1,3 }, { -5,-1,1,5 }, { -8,-2,2,8 }, + { -13,-3,3,13 }, { -19,-4,4,19 }, { -28,-6,6,28 } }; + static const short curve[256] = + { 0,1,2,3,4,5,6,7,8,9,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27, + 28,29,30,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,53, + 54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,74,75,76,77,78, + 79,80,81,82,83,84,86,88,90,92,94,97,99,101,103,105,107,110,112,114,116, + 118,120,123,125,127,129,131,134,136,138,140,142,144,147,149,151,153,155, + 158,160,162,164,166,168,171,173,175,177,179,181,184,186,188,190,192,195, + 197,199,201,203,205,208,210,212,214,216,218,221,223,226,230,235,239,244, + 248,252,257,261,265,270,274,278,283,287,291,296,300,305,309,313,318,322, + 326,331,335,339,344,348,352,357,361,365,370,374,379,383,387,392,396,400, + 405,409,413,418,422,426,431,435,440,444,448,453,457,461,466,470,474,479, + 483,487,492,496,500,508,519,531,542,553,564,575,587,598,609,620,631,643, + 654,665,676,687,698,710,721,732,743,754,766,777,788,799,810,822,833,844, + 855,866,878,889,900,911,922,933,945,956,967,978,989,1001,1012,1023 }; + int rb, row, col, sharp, val=0; + + getbits(-1); + memset (pixel, 0x80, sizeof pixel); + for (row=2; row < height+2; row++) { + for (col=2+(row & 1); col < width+2; col+=2) { + val = ((pixel[row-1][col-1] + 2*pixel[row-1][col+1] + + pixel[row][col-2]) >> 2) + gstep[getbits(4)]; + pixel[row][col] = val = LIM(val,0,255); + if (col < 4) + pixel[row][col-2] = pixel[row+1][~row & 1] = val; + if (row == 2) + pixel[row-1][col+1] = pixel[row-1][col+3] = val; + } + pixel[row][col] = val; + } + for (rb=0; rb < 2; rb++) + for (row=2+rb; row < height+2; row+=2) + for (col=3-(row & 1); col < width+2; col+=2) { + if (row < 4 || col < 4) sharp = 2; + else { + val = ABS(pixel[row-2][col] - pixel[row][col-2]) + + ABS(pixel[row-2][col] - pixel[row-2][col-2]) + + ABS(pixel[row][col-2] - pixel[row-2][col-2]); + sharp = val < 4 ? 0 : val < 8 ? 1 : val < 16 ? 2 : + val < 32 ? 3 : val < 48 ? 4 : 5; + } + val = ((pixel[row-2][col] + pixel[row][col-2]) >> 1) + + rstep[sharp][getbits(2)]; + pixel[row][col] = val = LIM(val,0,255); + if (row < 4) pixel[row-2][col+2] = val; + if (col < 4) pixel[row+2][col-2] = val; + } + for (row=2; row < height+2; row++) + for (col=3-(row & 1); col < width+2; col+=2) { + val = ((pixel[row][col-1] + (pixel[row][col] << 2) + + pixel[row][col+1]) >> 1) - 0x100; + pixel[row][col] = LIM(val,0,255); + } + for (row=0; row < height; row++) + for (col=0; col < width; col++) + BAYER(row,col) = curve[pixel[row+2][col+2]]; + maximum = 0x3ff; +} + +#define radc_token(tree) ((signed char) getbithuff(8,huff[tree])) + +#define FORYX for (y=1; y < 3; y++) for (x=col+1; x >= col; x--) + +#define PREDICTOR (c ? (buf[c][y-1][x] + buf[c][y][x+1]) / 2 \ +: (buf[c][y-1][x+1] + 2*buf[c][y-1][x] + buf[c][y][x+1]) / 4) + +void CLASS kodak_radc_load_raw() +{ + static const char src[] = { + 1,1, 2,3, 3,4, 4,2, 5,7, 6,5, 7,6, 7,8, + 1,0, 2,1, 3,3, 4,4, 5,2, 6,7, 7,6, 8,5, 8,8, + 2,1, 2,3, 3,0, 3,2, 3,4, 4,6, 5,5, 6,7, 6,8, + 2,0, 2,1, 2,3, 3,2, 4,4, 5,6, 6,7, 7,5, 7,8, + 2,1, 2,4, 3,0, 3,2, 3,3, 4,7, 5,5, 6,6, 6,8, + 2,3, 3,1, 3,2, 3,4, 3,5, 3,6, 4,7, 5,0, 5,8, + 2,3, 2,6, 3,0, 3,1, 4,4, 4,5, 4,7, 5,2, 5,8, + 2,4, 2,7, 3,3, 3,6, 4,1, 4,2, 4,5, 5,0, 5,8, + 2,6, 3,1, 3,3, 3,5, 3,7, 3,8, 4,0, 5,2, 5,4, + 2,0, 2,1, 3,2, 3,3, 4,4, 4,5, 5,6, 5,7, 4,8, + 1,0, 2,2, 2,-2, + 1,-3, 1,3, + 2,-17, 2,-5, 2,5, 2,17, + 2,-7, 2,2, 2,9, 2,18, + 2,-18, 2,-9, 2,-2, 2,7, + 2,-28, 2,28, 3,-49, 3,-9, 3,9, 4,49, 5,-79, 5,79, + 2,-1, 2,13, 2,26, 3,39, 4,-16, 5,55, 6,-37, 6,76, + 2,-26, 2,-13, 2,1, 3,-39, 4,16, 5,-55, 6,-76, 6,37 + }; + ushort huff[19][256]; + int row, col, tree, nreps, rep, step, i, c, s, r, x, y, val; + short last[3] = { 16,16,16 }, mul[3], buf[3][3][386]; + static const ushort pt[] = + { 0,0, 1280,1344, 2320,3616, 3328,8000, 4095,16383, 65535,16383 }; + + for (i=2; i < 12; i+=2) + for (c=pt[i-2]; c <= pt[i]; c++) + curve[c] = (float) + (c-pt[i-2]) / (pt[i]-pt[i-2]) * (pt[i+1]-pt[i-1]) + pt[i-1] + 0.5; + for (s=i=0; i < sizeof src; i+=2) + FORC(256 >> src[i]) + huff[0][s++] = src[i] << 8 | (uchar) src[i+1]; + s = kodak_cbpp == 243 ? 2 : 3; + FORC(256) huff[18][c] = (8-s) << 8 | c >> s << s | 1 << (s-1); + getbits(-1); + for (i=0; i < sizeof(buf)/sizeof(short); i++) + buf[0][0][i] = 2048; + for (row=0; row < height; row+=4) { + FORC3 mul[c] = getbits(6); + FORC3 { + val = ((0x1000000/last[c] + 0x7ff) >> 12) * mul[c]; + s = val > 65564 ? 10:12; + x = ~(-1 << (s-1)); + val <<= 12-s; + for (i=0; i < sizeof(buf[0])/sizeof(short); i++) + buf[c][0][i] = (buf[c][0][i] * val + x) >> s; + last[c] = mul[c]; + for (r=0; r <= !c; r++) { + buf[c][1][width/2] = buf[c][2][width/2] = mul[c] << 7; + for (tree=1, col=width/2; col > 0; ) { + if ((tree = radc_token(tree))) { + col -= 2; + if (tree == 8) + FORYX buf[c][y][x] = (uchar) radc_token(18) * mul[c]; + else + FORYX buf[c][y][x] = radc_token(tree+10) * 16 + PREDICTOR; + } else + do { + nreps = (col > 2) ? radc_token(9) + 1 : 1; + for (rep=0; rep < 8 && rep < nreps && col > 0; rep++) { + col -= 2; + FORYX buf[c][y][x] = PREDICTOR; + if (rep & 1) { + step = radc_token(10) << 4; + FORYX buf[c][y][x] += step; + } + } + } while (nreps == 9); + } + for (y=0; y < 2; y++) + for (x=0; x < width/2; x++) { + val = (buf[c][y+1][x] << 4) / mul[c]; + if (val < 0) val = 0; + if (c) BAYER(row+y*2+c-1,x*2+2-c) = val; + else BAYER(row+r*2+y,x*2+y) = val; + } + memcpy (buf[c][0]+!c, buf[c][2], sizeof buf[c][0]-2*!c); + } + } + for (y=row; y < row+4; y++) + for (x=0; x < width; x++) + if ((x+y) & 1) { + r = x ? x-1 : x+1; + s = x+1 < width ? x+1 : x-1; + val = (BAYER(y,x)-2048)*2 + (BAYER(y,r)+BAYER(y,s))/2; + if (val < 0) val = 0; + BAYER(y,x) = val; + } + } + for (i=0; i < iheight*iwidth*4; i++) + image[0][i] = curve[image[0][i]]; + maximum = 0x3fff; +} + +#undef FORYX +#undef PREDICTOR + +#ifdef NO_JPEG +void CLASS kodak_jpeg_load_raw() {} +#else + +METHODDEF(boolean) +fill_input_buffer (j_decompress_ptr cinfo) +{ + static uchar jpeg_buffer[4096]; + size_t nbytes; + + nbytes = fread (jpeg_buffer, 1, 4096, ifp); + swab ((char*)jpeg_buffer, (char*)jpeg_buffer, nbytes); + cinfo->src->next_input_byte = jpeg_buffer; + cinfo->src->bytes_in_buffer = nbytes; + return TRUE; +} + +void CLASS kodak_jpeg_load_raw() +{ + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + JSAMPARRAY buf; + JSAMPLE (*pixel)[3]; + int row, col; + + cinfo.err = jpeg_std_error (&jerr); + jpeg_create_decompress (&cinfo); + jpeg_stdio_src (&cinfo, ifp); + cinfo.src->fill_input_buffer = fill_input_buffer; + jpeg_read_header (&cinfo, TRUE); + jpeg_start_decompress (&cinfo); + if ((cinfo.output_width != width ) || + (cinfo.output_height*2 != height ) || + (cinfo.output_components != 3 )) { + fprintf (stderr,_("%s: incorrect JPEG dimensions\n"), ifname); + jpeg_destroy_decompress (&cinfo); + longjmp (failure, 3); + } + buf = (*cinfo.mem->alloc_sarray) + ((j_common_ptr) &cinfo, JPOOL_IMAGE, width*3, 1); + + while (cinfo.output_scanline < cinfo.output_height) { + row = cinfo.output_scanline * 2; + jpeg_read_scanlines (&cinfo, buf, 1); + pixel = (JSAMPLE (*)[3]) buf[0]; + for (col=0; col < width; col+=2) { + BAYER(row+0,col+0) = pixel[col+0][1] << 1; + BAYER(row+1,col+1) = pixel[col+1][1] << 1; + BAYER(row+0,col+1) = pixel[col][0] + pixel[col+1][0]; + BAYER(row+1,col+0) = pixel[col][2] + pixel[col+1][2]; + } + } + jpeg_finish_decompress (&cinfo); + jpeg_destroy_decompress (&cinfo); + maximum = 0xff << 1; +} +#endif + +void CLASS kodak_dc120_load_raw() +{ + static const int mul[4] = { 162, 192, 187, 92 }; + static const int add[4] = { 0, 636, 424, 212 }; + uchar pixel[848]; + int row, shift, col; + + for (row=0; row < height; row++) { + if (fread (pixel, 1, 848, ifp) < 848) derror(); + shift = row * mul[row & 3] + add[row & 3]; + for (col=0; col < width; col++) + BAYER(row,col) = (ushort) pixel[(col + shift) % 848]; + } + maximum = 0xff; +} + +void CLASS eight_bit_load_raw() +{ + uchar *pixel; + unsigned row, col, val, lblack=0; + + pixel = (uchar *) calloc (raw_width, sizeof *pixel); + merror (pixel, "eight_bit_load_raw()"); + fseek (ifp, top_margin*raw_width, SEEK_CUR); + for (row=0; row < height; row++) { + if (fread (pixel, 1, raw_width, ifp) < raw_width) derror(); + for (col=0; col < raw_width; col++) { + val = curve[pixel[col]]; + if ((unsigned) (col-left_margin) < width) + BAYER(row,col-left_margin) = val; + else lblack += val; + } + } + free (pixel); + if (raw_width > width+1) + black = lblack / ((raw_width - width) * height); + if (!strncmp(model,"DC2",3)) + black = 0; + maximum = curve[0xff]; +} + +void CLASS kodak_yrgb_load_raw() +{ + uchar *pixel; + int row, col, y, cb, cr, rgb[3], c; + + pixel = (uchar *) calloc (raw_width, 3*sizeof *pixel); + merror (pixel, "kodak_yrgb_load_raw()"); + for (row=0; row < height; row++) { + if (~row & 1) + if (fread (pixel, raw_width, 3, ifp) < 3) derror(); + for (col=0; col < raw_width; col++) { + y = pixel[width*2*(row & 1) + col]; + cb = pixel[width + (col & -2)] - 128; + cr = pixel[width + (col & -2)+1] - 128; + rgb[1] = y-((cb + cr + 2) >> 2); + rgb[2] = rgb[1] + cb; + rgb[0] = rgb[1] + cr; + FORC3 image[row*width+col][c] = curve[LIM(rgb[c],0,255)]; + } + } + free (pixel); + maximum = curve[0xff]; +} + +void CLASS kodak_262_load_raw() +{ + static const uchar kodak_tree[2][26] = + { { 0,1,5,1,1,2,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9 }, + { 0,3,1,1,1,1,1,2,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9 } }; + ushort *huff[2]; + uchar *pixel; + int *strip, ns, c, row, col, chess, pi=0, pi1, pi2, pred, val; + + FORC(2) huff[c] = make_decoder (kodak_tree[c]); + ns = (raw_height+63) >> 5; + pixel = (uchar *) malloc (raw_width*32 + ns*4); + merror (pixel, "kodak_262_load_raw()"); + strip = (int *) (pixel + raw_width*32); + order = 0x4d4d; + FORC(ns) strip[c] = get4(); + for (row=0; row < raw_height; row++) { + if ((row & 31) == 0) { + fseek (ifp, strip[row >> 5], SEEK_SET); + getbits(-1); + pi = 0; + } + for (col=0; col < raw_width; col++) { + chess = (row + col) & 1; + pi1 = chess ? pi-2 : pi-raw_width-1; + pi2 = chess ? pi-2*raw_width : pi-raw_width+1; + if (col <= chess) pi1 = -1; + if (pi1 < 0) pi1 = pi2; + if (pi2 < 0) pi2 = pi1; + if (pi1 < 0 && col > 1) pi1 = pi2 = pi-2; + pred = (pi1 < 0) ? 0 : (pixel[pi1] + pixel[pi2]) >> 1; + pixel[pi] = val = pred + ljpeg_diff (huff[chess]); + if (val >> 8) derror(); + val = curve[pixel[pi++]]; + if ((unsigned) (col-left_margin) < width) + BAYER(row,col-left_margin) = val; + else black += val; + } + } + free (pixel); + FORC(2) free (huff[c]); + if (raw_width > width) + black /= (raw_width - width) * height; +} + +int CLASS kodak_65000_decode (short *out, int bsize) +{ + uchar c, blen[768]; + ushort raw[6]; + INT64 bitbuf=0; + int save, bits=0, i, j, len, diff; + + save = ftell(ifp); + bsize = (bsize + 3) & -4; + for (i=0; i < bsize; i+=2) { + c = fgetc(ifp); + if ((blen[i ] = c & 15) > 12 || + (blen[i+1] = c >> 4) > 12 ) { + fseek (ifp, save, SEEK_SET); + for (i=0; i < bsize; i+=8) { + read_shorts (raw, 6); + out[i ] = raw[0] >> 12 << 8 | raw[2] >> 12 << 4 | raw[4] >> 12; + out[i+1] = raw[1] >> 12 << 8 | raw[3] >> 12 << 4 | raw[5] >> 12; + for (j=0; j < 6; j++) + out[i+2+j] = raw[j] & 0xfff; + } + return 1; + } + } + if ((bsize & 7) == 4) { + bitbuf = fgetc(ifp) << 8; + bitbuf += fgetc(ifp); + bits = 16; + } + for (i=0; i < bsize; i++) { + len = blen[i]; + if (bits < len) { + for (j=0; j < 32; j+=8) + bitbuf += (INT64) fgetc(ifp) << (bits+(j^8)); + bits += 32; + } + diff = bitbuf & (0xffff >> (16-len)); + bitbuf >>= len; + bits -= len; + if ((diff & (1 << (len-1))) == 0) + diff -= (1 << len) - 1; + out[i] = diff; + } + return 0; +} + +void CLASS kodak_65000_load_raw() +{ + short buf[256]; + int row, col, len, pred[2], ret, i; + + for (row=0; row < height; row++) + for (col=0; col < width; col+=256) { + pred[0] = pred[1] = 0; + len = MIN (256, width-col); + ret = kodak_65000_decode (buf, len); + for (i=0; i < len; i++) + if ((BAYER(row,col+i) = curve[ret ? buf[i] : + (pred[i & 1] += buf[i])]) >> 12) derror(); + } +} + +void CLASS kodak_ycbcr_load_raw() +{ + short buf[384], *bp; + int row, col, len, c, i, j, k, y[2][2], cb, cr, rgb[3]; + ushort *ip; + + for (row=0; row < height; row+=2) + for (col=0; col < width; col+=128) { + len = MIN (128, width-col); + kodak_65000_decode (buf, len*3); + y[0][1] = y[1][1] = cb = cr = 0; + for (bp=buf, i=0; i < len; i+=2, bp+=2) { + cb += bp[4]; + cr += bp[5]; + rgb[1] = -((cb + cr + 2) >> 2); + rgb[2] = rgb[1] + cb; + rgb[0] = rgb[1] + cr; + for (j=0; j < 2; j++) + for (k=0; k < 2; k++) { + if ((y[j][k] = y[j][k^1] + *bp++) >> 10) derror(); + ip = image[(row+j)*width + col+i+k]; + FORC3 ip[c] = curve[LIM(y[j][k]+rgb[c], 0, 0xfff)]; + } + } + } +} + +void CLASS kodak_rgb_load_raw() +{ + short buf[768], *bp; + int row, col, len, c, i, rgb[3]; + ushort *ip=image[0]; + + for (row=0; row < height; row++) + for (col=0; col < width; col+=256) { + len = MIN (256, width-col); + kodak_65000_decode (buf, len*3); + memset (rgb, 0, sizeof rgb); + for (bp=buf, i=0; i < len; i++, ip+=4) + FORC3 if ((ip[c] = rgb[c] += *bp++) >> 12) derror(); + } +} + +void CLASS kodak_thumb_load_raw() +{ + int row, col; + colors = thumb_misc >> 5; + for (row=0; row < height; row++) + for (col=0; col < width; col++) + read_shorts (image[row*width+col], colors); + maximum = (1 << (thumb_misc & 31)) - 1; +} + +void CLASS sony_decrypt (unsigned *data, int len, int start, int key) +{ + static unsigned pad[128], p; + + if (start) { + for (p=0; p < 4; p++) + pad[p] = key = key * 48828125 + 1; + pad[3] = pad[3] << 1 | (pad[0]^pad[2]) >> 31; + for (p=4; p < 127; p++) + pad[p] = (pad[p-4]^pad[p-2]) << 1 | (pad[p-3]^pad[p-1]) >> 31; + for (p=0; p < 127; p++) + pad[p] = htonl(pad[p]); + } + while (len--) + *data++ ^= pad[p++ & 127] = pad[(p+1) & 127] ^ pad[(p+65) & 127]; +} + +void CLASS sony_load_raw() +{ + uchar head[40]; + ushort *pixel; + unsigned i, key, row, col; + + fseek (ifp, 200896, SEEK_SET); + fseek (ifp, (unsigned) fgetc(ifp)*4 - 1, SEEK_CUR); + order = 0x4d4d; + key = get4(); + fseek (ifp, 164600, SEEK_SET); + fread (head, 1, 40, ifp); + sony_decrypt ((unsigned int *) head, 10, 1, key); + for (i=26; i-- > 22; ) + key = key << 8 | head[i]; + fseek (ifp, data_offset, SEEK_SET); + pixel = (ushort *) calloc (raw_width, sizeof *pixel); + merror (pixel, "sony_load_raw()"); + for (row=0; row < height; row++) { + if (fread (pixel, 2, raw_width, ifp) < raw_width) derror(); + sony_decrypt ((unsigned int *) pixel, raw_width/2, !row, key); + for (col=9; col < left_margin; col++) + black += ntohs(pixel[col]); + for (col=0; col < width; col++) + if ((BAYER(row,col) = ntohs(pixel[col+left_margin])) >> 14) + derror(); + } + free (pixel); + if (left_margin > 9) + black /= (left_margin-9) * height; + maximum = 0x3ff0; +} + +void CLASS sony_arw_load_raw() +{ + ushort huff[32768]; + static const ushort tab[18] = + { 0xf11,0xf10,0xe0f,0xd0e,0xc0d,0xb0c,0xa0b,0x90a,0x809, + 0x708,0x607,0x506,0x405,0x304,0x303,0x300,0x202,0x201 }; + int i, c, n, col, row, len, diff, sum=0; + + for (n=i=0; i < 18; i++) + FORC(32768 >> (tab[i] >> 8)) huff[n++] = tab[i]; + getbits(-1); + for (col = raw_width; col--; ) + for (row=0; row < raw_height+1; row+=2) { + if (row == raw_height) row = 1; + len = getbithuff(15,huff); + diff = getbits(len); + if ((diff & (1 << (len-1))) == 0) + diff -= (1 << len) - 1; + if ((sum += diff) >> 12) derror(); + if (row < height) BAYER(row,col) = sum; + } +} + +void CLASS sony_arw2_load_raw() +{ + uchar *data, *dp; + ushort pix[16]; + int row, col, val, max, min, imax, imin, sh, bit, i; + + data = (uchar *) malloc (raw_width); + merror (data, "sony_arw2_load_raw()"); + for (row=0; row < height; row++) { + fread (data, 1, raw_width, ifp); + for (dp=data, col=0; col < width-30; dp+=16) { + max = 0x7ff & (val = sget4(dp)); + min = 0x7ff & val >> 11; + imax = 0x0f & val >> 22; + imin = 0x0f & val >> 26; + for (sh=0; sh < 4 && 0x80 << sh <= max-min; sh++); + for (bit=30, i=0; i < 16; i++) + if (i == imax) pix[i] = max; + else if (i == imin) pix[i] = min; + else { + pix[i] = ((sget2(dp+(bit >> 3)) >> (bit & 7) & 0x7f) << sh) + min; + if (pix[i] > 0x7ff) pix[i] = 0x7ff; + bit += 7; + } + for (i=0; i < 16; i++, col+=2) + BAYER(row,col) = curve[pix[i] << 1] >> 1; + col -= col & 1 ? 1:31; + } + } + free (data); +} + +#define HOLE(row) ((holes >> (((row) - raw_height) & 7)) & 1) + +/* Kudos to Rich Taylor for figuring out SMaL's compression algorithm. */ +void CLASS smal_decode_segment (unsigned seg[2][2], int holes) +{ + uchar hist[3][13] = { + { 7, 7, 0, 0, 63, 55, 47, 39, 31, 23, 15, 7, 0 }, + { 7, 7, 0, 0, 63, 55, 47, 39, 31, 23, 15, 7, 0 }, + { 3, 3, 0, 0, 63, 47, 31, 15, 0 } }; + int low, high=0xff, carry=0, nbits=8; + int s, count, bin, next, i, sym[3]; + uchar diff, pred[]={0,0}; + ushort data=0, range=0; + unsigned pix, row, col; + + fseek (ifp, seg[0][1]+1, SEEK_SET); + getbits(-1); + for (pix=seg[0][0]; pix < seg[1][0]; pix++) { + for (s=0; s < 3; s++) { + data = data << nbits | getbits(nbits); + if (carry < 0) + carry = (nbits += carry+1) < 1 ? nbits-1 : 0; + while (--nbits >= 0) + if ((data >> nbits & 0xff) == 0xff) break; + if (nbits > 0) + data = ((data & ((1 << (nbits-1)) - 1)) << 1) | + ((data + (((data & (1 << (nbits-1)))) << 1)) & (-1 << nbits)); + if (nbits >= 0) { + data += getbits(1); + carry = nbits - 8; + } + count = ((((data-range+1) & 0xffff) << 2) - 1) / (high >> 4); + for (bin=0; hist[s][bin+5] > count; bin++); + low = hist[s][bin+5] * (high >> 4) >> 2; + if (bin) high = hist[s][bin+4] * (high >> 4) >> 2; + high -= low; + for (nbits=0; high << nbits < 128; nbits++); + range = (range+low) << nbits; + high <<= nbits; + next = hist[s][1]; + if (++hist[s][2] > hist[s][3]) { + next = (next+1) & hist[s][0]; + hist[s][3] = (hist[s][next+4] - hist[s][next+5]) >> 2; + hist[s][2] = 1; + } + if (hist[s][hist[s][1]+4] - hist[s][hist[s][1]+5] > 1) { + if (bin < hist[s][1]) + for (i=bin; i < hist[s][1]; i++) hist[s][i+5]--; + else if (next <= bin) + for (i=hist[s][1]; i < bin; i++) hist[s][i+5]++; + } + hist[s][1] = next; + sym[s] = bin; + } + diff = sym[2] << 5 | sym[1] << 2 | (sym[0] & 3); + if (sym[0] & 4) + diff = diff ? -diff : 0x80; + if (ftell(ifp) + 12 >= seg[1][1]) + diff = 0; + pred[pix & 1] += diff; + row = pix / raw_width - top_margin; + col = pix % raw_width - left_margin; + if (row < height && col < width) + BAYER(row,col) = pred[pix & 1]; + if (!(pix & 1) && HOLE(row)) pix += 2; + } + maximum = 0xff; +} + +void CLASS smal_v6_load_raw() +{ + unsigned seg[2][2]; + + fseek (ifp, 16, SEEK_SET); + seg[0][0] = 0; + seg[0][1] = get2(); + seg[1][0] = raw_width * raw_height; + seg[1][1] = INT_MAX; + smal_decode_segment (seg, 0); +} + +int CLASS median4 (int *p) +{ + int min, max, sum, i; + + min = max = sum = p[0]; + for (i=1; i < 4; i++) { + sum += p[i]; + if (min > p[i]) min = p[i]; + if (max < p[i]) max = p[i]; + } + return (sum - min - max) >> 1; +} + +void CLASS fill_holes (int holes) +{ + int row, col, val[4]; + + for (row=2; row < height-2; row++) { + if (!HOLE(row)) continue; + for (col=1; col < width-1; col+=4) { + val[0] = BAYER(row-1,col-1); + val[1] = BAYER(row-1,col+1); + val[2] = BAYER(row+1,col-1); + val[3] = BAYER(row+1,col+1); + BAYER(row,col) = median4(val); + } + for (col=2; col < width-2; col+=4) + if (HOLE(row-2) || HOLE(row+2)) + BAYER(row,col) = (BAYER(row,col-2) + BAYER(row,col+2)) >> 1; + else { + val[0] = BAYER(row,col-2); + val[1] = BAYER(row,col+2); + val[2] = BAYER(row-2,col); + val[3] = BAYER(row+2,col); + BAYER(row,col) = median4(val); + } + } +} + +void CLASS smal_v9_load_raw() +{ + unsigned seg[256][2], offset, nseg, holes, i; + + fseek (ifp, 67, SEEK_SET); + offset = get4(); + nseg = fgetc(ifp); + fseek (ifp, offset, SEEK_SET); + for (i=0; i < nseg*2; i++) + seg[0][i] = get4() + data_offset*(i & 1); + fseek (ifp, 78, SEEK_SET); + holes = fgetc(ifp); + fseek (ifp, 88, SEEK_SET); + seg[nseg][0] = raw_height * raw_width; + seg[nseg][1] = get4() + data_offset; + for (i=0; i < nseg; i++) + smal_decode_segment (seg+i, holes); + if (holes) fill_holes (holes); +} + +/* RESTRICTED code starts here */ + +void CLASS foveon_decoder (unsigned size, unsigned code) +{ + static unsigned huff[1024]; + struct decode *cur; + int i, len; + + if (!code) { + for (i=0; i < size; i++) + huff[i] = get4(); + memset (first_decode, 0, sizeof first_decode); + free_decode = first_decode; + } + cur = free_decode++; + if (free_decode > first_decode+2048) { + fprintf (stderr,_("%s: decoder table overflow\n"), ifname); + longjmp (failure, 2); + } + if (code) + for (i=0; i < size; i++) + if (huff[i] == code) { + cur->leaf = i; + return; + } + if ((len = code >> 27) > 26) return; + code = (len+1) << 27 | (code & 0x3ffffff) << 1; + + cur->branch[0] = free_decode; + foveon_decoder (size, code); + cur->branch[1] = free_decode; + foveon_decoder (size, code+1); +} + +void CLASS foveon_thumb() +{ + unsigned bwide, row, col, bitbuf=0, bit=1, c, i; + char *buf; + struct decode *dindex; + short pred[3]; + + bwide = get4(); + fprintf (ofp, "P6\n%d %d\n255\n", thumb_width, thumb_height); + if (bwide > 0) { + if (bwide < thumb_width*3) return; + buf = (char *) malloc (bwide); + merror (buf, "foveon_thumb()"); + for (row=0; row < thumb_height; row++) { + fread (buf, 1, bwide, ifp); + fwrite (buf, 3, thumb_width, ofp); + } + free (buf); + return; + } + foveon_decoder (256, 0); + + for (row=0; row < thumb_height; row++) { + memset (pred, 0, sizeof pred); + if (!bit) get4(); + for (bit=col=0; col < thumb_width; col++) + FORC3 { + for (dindex=first_decode; dindex->branch[0]; ) { + if ((bit = (bit-1) & 31) == 31) + for (i=0; i < 4; i++) + bitbuf = (bitbuf << 8) + fgetc(ifp); + dindex = dindex->branch[bitbuf >> bit & 1]; + } + pred[c] += dindex->leaf; + fputc (pred[c], ofp); + } + } +} + +void CLASS foveon_load_camf() +{ + unsigned key, i, val; + + fseek (ifp, meta_offset, SEEK_SET); + key = get4(); + fread (meta_data, 1, meta_length, ifp); + for (i=0; i < meta_length; i++) { + key = (key * 1597 + 51749) % 244944; + val = key * (INT64) 301593171 >> 24; + meta_data[i] ^= ((((key << 8) - val) >> 1) + val) >> 17; + } +} + +void CLASS foveon_load_raw() +{ + struct decode *dindex; + short diff[1024]; + unsigned bitbuf=0; + int pred[3], fixed, row, col, bit=-1, c, i; + + fixed = get4(); + read_shorts ((ushort *) diff, 1024); + if (!fixed) foveon_decoder (1024, 0); + + for (row=0; row < height; row++) { + memset (pred, 0, sizeof pred); + if (!bit && !fixed && atoi(model+2) < 14) get4(); + for (col=bit=0; col < width; col++) { + if (fixed) { + bitbuf = get4(); + FORC3 pred[2-c] += diff[bitbuf >> c*10 & 0x3ff]; + } + else FORC3 { + for (dindex=first_decode; dindex->branch[0]; ) { + if ((bit = (bit-1) & 31) == 31) + for (i=0; i < 4; i++) + bitbuf = (bitbuf << 8) + fgetc(ifp); + dindex = dindex->branch[bitbuf >> bit & 1]; + } + pred[c] += diff[dindex->leaf]; + if (pred[c] >> 16 && ~pred[c] >> 16) derror(); + } + FORC3 image[row*width+col][c] = pred[c]; + } + } + if (document_mode) + for (i=0; i < height*width*4; i++) + if ((short) image[0][i] < 0) image[0][i] = 0; + foveon_load_camf(); +} + +const char * CLASS foveon_camf_param (const char *block, const char *param) +{ + unsigned idx, num; + char *pos, *cp, *dp; + + for (idx=0; idx < meta_length; idx += sget4(pos+8)) { + pos = meta_data + idx; + if (strncmp (pos, "CMb", 3)) break; + if (pos[3] != 'P') continue; + if (strcmp (block, pos+sget4(pos+12))) continue; + cp = pos + sget4(pos+16); + num = sget4(cp); + dp = pos + sget4(cp+4); + while (num--) { + cp += 8; + if (!strcmp (param, dp+sget4(cp))) + return dp+sget4(cp+4); + } + } + return 0; +} + +void * CLASS foveon_camf_matrix (unsigned dim[3], const char *name) +{ + unsigned i, idx, type, ndim, size, *mat; + char *pos, *cp, *dp; + double dsize; + + for (idx=0; idx < meta_length; idx += sget4(pos+8)) { + pos = meta_data + idx; + if (strncmp (pos, "CMb", 3)) break; + if (pos[3] != 'M') continue; + if (strcmp (name, pos+sget4(pos+12))) continue; + dim[0] = dim[1] = dim[2] = 1; + cp = pos + sget4(pos+16); + type = sget4(cp); + if ((ndim = sget4(cp+4)) > 3) break; + dp = pos + sget4(cp+8); + for (i=ndim; i--; ) { + cp += 12; + dim[i] = sget4(cp); + } + if ((dsize = (double) dim[0]*dim[1]*dim[2]) > meta_length/4) break; + mat = (unsigned *) malloc ((size = dsize) * 4); + merror (mat, "foveon_camf_matrix()"); + for (i=0; i < size; i++) + if (type && type != 6) + mat[i] = sget4(dp + i*4); + else + mat[i] = sget4(dp + i*2) & 0xffff; + return mat; + } + fprintf (stderr,_("%s: \"%s\" matrix not found!\n"), ifname, name); + return 0; +} + +int CLASS foveon_fixed (void *ptr, int size, const char *name) +{ + void *dp; + unsigned dim[3]; + + dp = foveon_camf_matrix (dim, name); + if (!dp) return 0; + memcpy (ptr, dp, size*4); + free (dp); + return 1; +} + +float CLASS foveon_avg (short *pix, int range[2], float cfilt) +{ + int i; + float val, min=FLT_MAX, max=-FLT_MAX, sum=0; + + for (i=range[0]; i <= range[1]; i++) { + sum += val = pix[i*4] + (pix[i*4]-pix[(i-1)*4]) * cfilt; + if (min > val) min = val; + if (max < val) max = val; + } + if (range[1] - range[0] == 1) return sum/2; + return (sum - min - max) / (range[1] - range[0] - 1); +} + +short * CLASS foveon_make_curve (double max, double mul, double filt) +{ + short *curve; + unsigned i, size; + double x; + + if (!filt) filt = 0.8; + size = 4*M_PI*max / filt; + if (size == UINT_MAX) size--; + curve = (short *) calloc (size+1, sizeof *curve); + merror (curve, "foveon_make_curve()"); + curve[0] = size; + for (i=0; i < size; i++) { + x = i*filt/max/4; + curve[i+1] = (cos(x)+1)/2 * tanh(i*filt/mul) * mul + 0.5; + } + return curve; +} + +void CLASS foveon_make_curves + (short **curvep, float dq[3], float div[3], float filt) +{ + double mul[3], max=0; + int c; + + FORC3 mul[c] = dq[c]/div[c]; + FORC3 if (max < mul[c]) max = mul[c]; + FORC3 curvep[c] = foveon_make_curve (max, mul[c], filt); +} + +int CLASS foveon_apply_curve (short *curve, int i) +{ + if (abs(i) >= curve[0]) return 0; + return i < 0 ? -curve[1-i] : curve[1+i]; +} + +#define image ((short (*)[4]) image) + +void CLASS foveon_interpolate() +{ + static const short hood[] = { -1,-1, -1,0, -1,1, 0,-1, 0,1, 1,-1, 1,0, 1,1 }; + short *pix, prev[3], *curve[8], (*shrink)[3]; + float cfilt=0, ddft[3][3][2], ppm[3][3][3]; + float cam_xyz[3][3], correct[3][3], last[3][3], trans[3][3]; + float chroma_dq[3], color_dq[3], diag[3][3], div[3]; + float (*black)[3], (*sgain)[3], (*sgrow)[3]; + float fsum[3], val, frow, num; + int row, col, c, i, j, diff, sgx, irow, sum, min, max, limit; + int dscr[2][2], dstb[4], (*smrow[7])[3], total[4], ipix[3]; + int work[3][3], smlast, smred, smred_p=0, dev[3]; + int satlev[3], keep[4], active[4]; + unsigned dim[3], *badpix; + double dsum=0, trsum[3]; + char str[128]; + const char* cp; + + if (verbose) + fprintf (stderr,_("Foveon interpolation...\n")); + + foveon_fixed (dscr, 4, "DarkShieldColRange"); + foveon_fixed (ppm[0][0], 27, "PostPolyMatrix"); + foveon_fixed (satlev, 3, "SaturationLevel"); + foveon_fixed (keep, 4, "KeepImageArea"); + foveon_fixed (active, 4, "ActiveImageArea"); + foveon_fixed (chroma_dq, 3, "ChromaDQ"); + foveon_fixed (color_dq, 3, + foveon_camf_param ("IncludeBlocks", "ColorDQ") ? + "ColorDQ" : "ColorDQCamRGB"); + if (foveon_camf_param ("IncludeBlocks", "ColumnFilter")) + foveon_fixed (&cfilt, 1, "ColumnFilter"); + + memset (ddft, 0, sizeof ddft); + if (!foveon_camf_param ("IncludeBlocks", "DarkDrift") + || !foveon_fixed (ddft[1][0], 12, "DarkDrift")) + for (i=0; i < 2; i++) { + foveon_fixed (dstb, 4, i ? "DarkShieldBottom":"DarkShieldTop"); + for (row = dstb[1]; row <= dstb[3]; row++) + for (col = dstb[0]; col <= dstb[2]; col++) + FORC3 ddft[i+1][c][1] += (short) image[row*width+col][c]; + FORC3 ddft[i+1][c][1] /= (dstb[3]-dstb[1]+1) * (dstb[2]-dstb[0]+1); + } + + if (!(cp = foveon_camf_param ("WhiteBalanceIlluminants", model2))) + { fprintf (stderr,_("%s: Invalid white balance \"%s\"\n"), ifname, model2); + return; } + foveon_fixed (cam_xyz, 9, cp); + foveon_fixed (correct, 9, + foveon_camf_param ("WhiteBalanceCorrections", model2)); + memset (last, 0, sizeof last); + for (i=0; i < 3; i++) + for (j=0; j < 3; j++) + FORC3 last[i][j] += correct[i][c] * cam_xyz[c][j]; + + #define LAST(x,y) last[(i+x)%3][(c+y)%3] + for (i=0; i < 3; i++) + FORC3 diag[c][i] = LAST(1,1)*LAST(2,2) - LAST(1,2)*LAST(2,1); + #undef LAST + FORC3 div[c] = diag[c][0]*0.3127 + diag[c][1]*0.329 + diag[c][2]*0.3583; + sprintf (str, "%sRGBNeutral", model2); + if (foveon_camf_param ("IncludeBlocks", str)) + foveon_fixed (div, 3, str); + num = 0; + FORC3 if (num < div[c]) num = div[c]; + FORC3 div[c] /= num; + + memset (trans, 0, sizeof trans); + for (i=0; i < 3; i++) + for (j=0; j < 3; j++) + FORC3 trans[i][j] += rgb_cam[i][c] * last[c][j] * div[j]; + FORC3 trsum[c] = trans[c][0] + trans[c][1] + trans[c][2]; + dsum = (6*trsum[0] + 11*trsum[1] + 3*trsum[2]) / 20; + for (i=0; i < 3; i++) + FORC3 last[i][c] = trans[i][c] * dsum / trsum[i]; + memset (trans, 0, sizeof trans); + for (i=0; i < 3; i++) + for (j=0; j < 3; j++) + FORC3 trans[i][j] += (i==c ? 32 : -1) * last[c][j] / 30; + + foveon_make_curves (curve, color_dq, div, cfilt); + FORC3 chroma_dq[c] /= 3; + foveon_make_curves (curve+3, chroma_dq, div, cfilt); + FORC3 dsum += chroma_dq[c] / div[c]; + curve[6] = foveon_make_curve (dsum, dsum, cfilt); + curve[7] = foveon_make_curve (dsum*2, dsum*2, cfilt); + + sgain = (float (*)[3]) foveon_camf_matrix (dim, "SpatialGain"); + if (!sgain) return; + sgrow = (float (*)[3]) calloc (dim[1], sizeof *sgrow); + sgx = (width + dim[1]-2) / (dim[1]-1); + + black = (float (*)[3]) calloc (height, sizeof *black); + for (row=0; row < height; row++) { + for (i=0; i < 6; i++) + ddft[0][0][i] = ddft[1][0][i] + + row / (height-1.0) * (ddft[2][0][i] - ddft[1][0][i]); + FORC3 black[row][c] = + ( foveon_avg (image[row*width]+c, dscr[0], cfilt) + + foveon_avg (image[row*width]+c, dscr[1], cfilt) * 3 + - ddft[0][c][0] ) / 4 - ddft[0][c][1]; + } + memcpy (black, black+8, sizeof *black*8); + memcpy (black+height-11, black+height-22, 11*sizeof *black); + memcpy (last, black, sizeof last); + + for (row=1; row < height-1; row++) { + FORC3 if (last[1][c] > last[0][c]) { + if (last[1][c] > last[2][c]) + black[row][c] = (last[0][c] > last[2][c]) ? last[0][c]:last[2][c]; + } else + if (last[1][c] < last[2][c]) + black[row][c] = (last[0][c] < last[2][c]) ? last[0][c]:last[2][c]; + memmove (last, last+1, 2*sizeof last[0]); + memcpy (last[2], black[row+1], sizeof last[2]); + } + FORC3 black[row][c] = (last[0][c] + last[1][c])/2; + FORC3 black[0][c] = (black[1][c] + black[3][c])/2; + + val = 1 - exp(-1/24.0); + memcpy (fsum, black, sizeof fsum); + for (row=1; row < height; row++) + FORC3 fsum[c] += black[row][c] = + (black[row][c] - black[row-1][c])*val + black[row-1][c]; + memcpy (last[0], black[height-1], sizeof last[0]); + FORC3 fsum[c] /= height; + for (row = height; row--; ) + FORC3 last[0][c] = black[row][c] = + (black[row][c] - fsum[c] - last[0][c])*val + last[0][c]; + + memset (total, 0, sizeof total); + for (row=2; row < height; row+=4) + for (col=2; col < width; col+=4) { + FORC3 total[c] += (short) image[row*width+col][c]; + total[3]++; + } + for (row=0; row < height; row++) + FORC3 black[row][c] += fsum[c]/2 + total[c]/(total[3]*100.0); + + for (row=0; row < height; row++) { + for (i=0; i < 6; i++) + ddft[0][0][i] = ddft[1][0][i] + + row / (height-1.0) * (ddft[2][0][i] - ddft[1][0][i]); + pix = image[row*width]; + memcpy (prev, pix, sizeof prev); + frow = row / (height-1.0) * (dim[2]-1); + if ((irow = frow) == dim[2]-1) irow--; + frow -= irow; + for (i=0; i < dim[1]; i++) + FORC3 sgrow[i][c] = sgain[ irow *dim[1]+i][c] * (1-frow) + + sgain[(irow+1)*dim[1]+i][c] * frow; + for (col=0; col < width; col++) { + FORC3 { + diff = pix[c] - prev[c]; + prev[c] = pix[c]; + ipix[c] = pix[c] + floor ((diff + (diff*diff >> 14)) * cfilt + - ddft[0][c][1] - ddft[0][c][0] * ((float) col/width - 0.5) + - black[row][c] ); + } + FORC3 { + work[0][c] = ipix[c] * ipix[c] >> 14; + work[2][c] = ipix[c] * work[0][c] >> 14; + work[1][2-c] = ipix[(c+1) % 3] * ipix[(c+2) % 3] >> 14; + } + FORC3 { + for (val=i=0; i < 3; i++) + for ( j=0; j < 3; j++) + val += ppm[c][i][j] * work[i][j]; + ipix[c] = floor ((ipix[c] + floor(val)) * + ( sgrow[col/sgx ][c] * (sgx - col%sgx) + + sgrow[col/sgx+1][c] * (col%sgx) ) / sgx / div[c]); + if (ipix[c] > 32000) ipix[c] = 32000; + pix[c] = ipix[c]; + } + pix += 4; + } + } + free (black); + free (sgrow); + free (sgain); + + if ((badpix = (unsigned int *) foveon_camf_matrix (dim, "BadPixels"))) { + for (i=0; i < dim[0]; i++) { + col = (badpix[i] >> 8 & 0xfff) - keep[0]; + row = (badpix[i] >> 20 ) - keep[1]; + if ((unsigned)(row-1) > height-3 || (unsigned)(col-1) > width-3) + continue; + memset (fsum, 0, sizeof fsum); + for (sum=j=0; j < 8; j++) + if (badpix[i] & (1 << j)) { + FORC3 fsum[c] += (short) + image[(row+hood[j*2])*width+col+hood[j*2+1]][c]; + sum++; + } + if (sum) FORC3 image[row*width+col][c] = fsum[c]/sum; + } + free (badpix); + } + + /* Array for 5x5 Gaussian averaging of red values */ + smrow[6] = (int (*)[3]) calloc (width*5, sizeof **smrow); + merror (smrow[6], "foveon_interpolate()"); + for (i=0; i < 5; i++) + smrow[i] = smrow[6] + i*width; + + /* Sharpen the reds against these Gaussian averages */ + for (smlast=-1, row=2; row < height-2; row++) { + while (smlast < row+2) { + for (i=0; i < 6; i++) + smrow[(i+5) % 6] = smrow[i]; + pix = image[++smlast*width+2]; + for (col=2; col < width-2; col++) { + smrow[4][col][0] = + (pix[0]*6 + (pix[-4]+pix[4])*4 + pix[-8]+pix[8] + 8) >> 4; + pix += 4; + } + } + pix = image[row*width+2]; + for (col=2; col < width-2; col++) { + smred = ( 6 * smrow[2][col][0] + + 4 * (smrow[1][col][0] + smrow[3][col][0]) + + smrow[0][col][0] + smrow[4][col][0] + 8 ) >> 4; + if (col == 2) + smred_p = smred; + i = pix[0] + ((pix[0] - ((smred*7 + smred_p) >> 3)) >> 3); + if (i > 32000) i = 32000; + pix[0] = i; + smred_p = smred; + pix += 4; + } + } + + /* Adjust the brighter pixels for better linearity */ + min = 0xffff; + FORC3 { + i = satlev[c] / div[c]; + if (min > i) min = i; + } + limit = min * 9 >> 4; + for (pix=image[0]; pix < image[height*width]; pix+=4) { + if (pix[0] <= limit || pix[1] <= limit || pix[2] <= limit) + continue; + min = max = pix[0]; + for (c=1; c < 3; c++) { + if (min > pix[c]) min = pix[c]; + if (max < pix[c]) max = pix[c]; + } + if (min >= limit*2) { + pix[0] = pix[1] = pix[2] = max; + } else { + i = 0x4000 - ((min - limit) << 14) / limit; + i = 0x4000 - (i*i >> 14); + i = i*i >> 14; + FORC3 pix[c] += (max - pix[c]) * i >> 14; + } + } +/* + Because photons that miss one detector often hit another, + the sum R+G+B is much less noisy than the individual colors. + So smooth the hues without smoothing the total. + */ + for (smlast=-1, row=2; row < height-2; row++) { + while (smlast < row+2) { + for (i=0; i < 6; i++) + smrow[(i+5) % 6] = smrow[i]; + pix = image[++smlast*width+2]; + for (col=2; col < width-2; col++) { + FORC3 smrow[4][col][c] = (pix[c-4]+2*pix[c]+pix[c+4]+2) >> 2; + pix += 4; + } + } + pix = image[row*width+2]; + for (col=2; col < width-2; col++) { + FORC3 dev[c] = -foveon_apply_curve (curve[7], pix[c] - + ((smrow[1][col][c] + 2*smrow[2][col][c] + smrow[3][col][c]) >> 2)); + sum = (dev[0] + dev[1] + dev[2]) >> 3; + FORC3 pix[c] += dev[c] - sum; + pix += 4; + } + } + for (smlast=-1, row=2; row < height-2; row++) { + while (smlast < row+2) { + for (i=0; i < 6; i++) + smrow[(i+5) % 6] = smrow[i]; + pix = image[++smlast*width+2]; + for (col=2; col < width-2; col++) { + FORC3 smrow[4][col][c] = + (pix[c-8]+pix[c-4]+pix[c]+pix[c+4]+pix[c+8]+2) >> 2; + pix += 4; + } + } + pix = image[row*width+2]; + for (col=2; col < width-2; col++) { + for (total[3]=375, sum=60, c=0; c < 3; c++) { + for (total[c]=i=0; i < 5; i++) + total[c] += smrow[i][col][c]; + total[3] += total[c]; + sum += pix[c]; + } + if (sum < 0) sum = 0; + j = total[3] > 375 ? (sum << 16) / total[3] : sum * 174; + FORC3 pix[c] += foveon_apply_curve (curve[6], + ((j*total[c] + 0x8000) >> 16) - pix[c]); + pix += 4; + } + } + + /* Transform the image to a different colorspace */ + for (pix=image[0]; pix < image[height*width]; pix+=4) { + FORC3 pix[c] -= foveon_apply_curve (curve[c], pix[c]); + sum = (pix[0]+pix[1]+pix[1]+pix[2]) >> 2; + FORC3 pix[c] -= foveon_apply_curve (curve[c], pix[c]-sum); + FORC3 { + for (dsum=i=0; i < 3; i++) + dsum += trans[c][i] * pix[i]; + if (dsum < 0) dsum = 0; + if (dsum > 24000) dsum = 24000; + ipix[c] = dsum + 0.5; + } + FORC3 pix[c] = ipix[c]; + } + + /* Smooth the image bottom-to-top and save at 1/4 scale */ + shrink = (short (*)[3]) calloc ((width/4) * (height/4), sizeof *shrink); + merror (shrink, "foveon_interpolate()"); + for (row = height/4; row--; ) + for (col=0; col < width/4; col++) { + ipix[0] = ipix[1] = ipix[2] = 0; + for (i=0; i < 4; i++) + for (j=0; j < 4; j++) + FORC3 ipix[c] += image[(row*4+i)*width+col*4+j][c]; + FORC3 + if (row+2 > height/4) + shrink[row*(width/4)+col][c] = ipix[c] >> 4; + else + shrink[row*(width/4)+col][c] = + (shrink[(row+1)*(width/4)+col][c]*1840 + ipix[c]*141 + 2048) >> 12; + } + /* From the 1/4-scale image, smooth right-to-left */ + for (row=0; row < (height & ~3); row++) { + ipix[0] = ipix[1] = ipix[2] = 0; + if ((row & 3) == 0) + for (col = width & ~3 ; col--; ) + FORC3 smrow[0][col][c] = ipix[c] = + (shrink[(row/4)*(width/4)+col/4][c]*1485 + ipix[c]*6707 + 4096) >> 13; + + /* Then smooth left-to-right */ + ipix[0] = ipix[1] = ipix[2] = 0; + for (col=0; col < (width & ~3); col++) + FORC3 smrow[1][col][c] = ipix[c] = + (smrow[0][col][c]*1485 + ipix[c]*6707 + 4096) >> 13; + + /* Smooth top-to-bottom */ + if (row == 0) + memcpy (smrow[2], smrow[1], sizeof **smrow * width); + else + for (col=0; col < (width & ~3); col++) + FORC3 smrow[2][col][c] = + (smrow[2][col][c]*6707 + smrow[1][col][c]*1485 + 4096) >> 13; + + /* Adjust the chroma toward the smooth values */ + for (col=0; col < (width & ~3); col++) { + for (i=j=30, c=0; c < 3; c++) { + i += smrow[2][col][c]; + j += image[row*width+col][c]; + } + j = (j << 16) / i; + for (sum=c=0; c < 3; c++) { + ipix[c] = foveon_apply_curve (curve[c+3], + ((smrow[2][col][c] * j + 0x8000) >> 16) - image[row*width+col][c]); + sum += ipix[c]; + } + sum >>= 3; + FORC3 { + i = image[row*width+col][c] + ipix[c] - sum; + if (i < 0) i = 0; + image[row*width+col][c] = i; + } + } + } + free (shrink); + free (smrow[6]); + for (i=0; i < 8; i++) + free (curve[i]); + + /* Trim off the black border */ + active[1] -= keep[1]; + active[3] -= 2; + i = active[2] - active[0]; + for (row=0; row < active[3]-active[1]; row++) + memcpy (image[row*i], image[(row+active[1])*width+active[0]], + i * sizeof *image); + width = i; + height = row; +} +#undef image + +/* RESTRICTED code ends here */ + +/* + Seach from the current directory up to the root looking for + a ".badpixels" file, and fix those pixels now. + */ +void CLASS bad_pixels (const char *cfname) +{ + FILE *fp=0; + char *fname, *cp, line[128]; + int len, time, row, col, r, c, rad, tot, n, fixed=0; + + if (!filters) return; + if (cfname) + fp = fopen (cfname, "r"); + else { + for (len=32 ; ; len *= 2) { + fname = (char *) malloc (len); + if (!fname) return; + if (getcwd (fname, len-16)) break; + free (fname); + if (errno != ERANGE) return; + } +#if defined(WIN32) || defined(DJGPP) + if (fname[1] == ':') + memmove (fname, fname+2, len-2); + for (cp=fname; *cp; cp++) + if (*cp == '\\') *cp = '/'; +#endif + cp = fname + strlen(fname); + if (cp[-1] == '/') cp--; + while (*fname == '/') { + strcpy (cp, "/.badpixels"); + if ((fp = fopen (fname, "r"))) break; + if (cp == fname) break; + while (*--cp != '/'); + } + free (fname); + } + if (!fp) return; + while (fgets (line, 128, fp)) { + cp = strchr (line, '#'); + if (cp) *cp = 0; + if (sscanf (line, "%d %d %d", &col, &row, &time) != 3) continue; + if ((unsigned) col >= width || (unsigned) row >= height) continue; + if (time > timestamp) continue; + for (tot=n=0, rad=1; rad < 3 && n==0; rad++) + for (r = row-rad; r <= row+rad; r++) + for (c = col-rad; c <= col+rad; c++) + if ((unsigned) r < height && (unsigned) c < width && + (r != row || c != col) && fc(r,c) == fc(row,col)) { + tot += BAYER2(r,c); + n++; + } + BAYER2(row,col) = tot/n; + if (verbose) { + if (!fixed++) + fprintf (stderr,_("Fixed dead pixels at:")); + fprintf (stderr, " %d,%d", col, row); + } + } + if (fixed) fputc ('\n', stderr); + fclose (fp); +} + +void CLASS subtract (const char *fname) +{ + FILE *fp; + int dim[3]={0,0,0}, comment=0, number=0, error=0, nd=0, c, row, col; + ushort *pixel; + + if (!(fp = fopen (fname, "rb"))) { + perror (fname); return; + } + if (fgetc(fp) != 'P' || fgetc(fp) != '5') error = 1; + while (!error && nd < 3 && (c = fgetc(fp)) != EOF) { + if (c == '#') comment = 1; + if (c == '\n') comment = 0; + if (comment) continue; + if (isdigit(c)) number = 1; + if (number) { + if (isdigit(c)) dim[nd] = dim[nd]*10 + c -'0'; + else if (isspace(c)) { + number = 0; nd++; + } else error = 1; + } + } + if (error || nd < 3) { + fprintf (stderr,_("%s is not a valid PGM file!\n"), fname); + fclose (fp); return; + } else if (dim[0] != width || dim[1] != height || dim[2] != 65535) { + fprintf (stderr,_("%s has the wrong dimensions!\n"), fname); + fclose (fp); return; + } + pixel = (ushort *) calloc (width, sizeof *pixel); + merror (pixel, "subtract()"); + for (row=0; row < height; row++) { + fread (pixel, 2, width, fp); + for (col=0; col < width; col++) + BAYER(row,col) = MAX (BAYER(row,col) - ntohs(pixel[col]), 0); + } + free (pixel); + black = 0; +} + +void CLASS gamma_curve (double pwr, double ts, int mode, int imax) +{ + int i; + double g[6], bnd[2]={0,0}, r; + + g[0] = pwr; + g[1] = ts; + g[2] = g[3] = g[4] = 0; + bnd[g[1] >= 1] = 1; + if (g[1] && (g[1]-1)*(g[0]-1) <= 0) { + for (i=0; i < 48; i++) { + g[2] = (bnd[0] + bnd[1])/2; + if (g[0]) bnd[(pow(g[2]/g[1],-g[0]) - 1)/g[0] - 1/g[2] > -1] = g[2]; + else bnd[g[2]/exp(1-1/g[2]) < g[1]] = g[2]; + } + g[3] = g[2] / g[1]; + if (g[0]) g[4] = g[2] * (1/g[0] - 1); + } + if (g[0]) g[5] = 1 / (g[1]*SQR(g[3])/2 - g[4]*(1 - g[3]) + + (1 - pow(g[3],1+g[0]))*(1 + g[4])/(1 + g[0])) - 1; + else g[5] = 1 / (g[1]*SQR(g[3])/2 + 1 + - g[2] - g[3] - g[2]*g[3]*(log(g[3]) - 1)) - 1; + if (!mode--) { + memcpy (gamm, g, sizeof gamm); + return; + } + for (i=0; i < 0x10000; i++) { + curve[i] = 0xffff; + if ((r = (double) i / imax) < 1) + curve[i] = 0x10000 * ( mode + ? (r < g[3] ? r*g[1] : (g[0] ? pow( r,g[0])*(1+g[4])-g[4] : log(r)*g[2]+1)) + : (r < g[2] ? r/g[1] : (g[0] ? pow((r+g[4])/(1+g[4]),1/g[0]) : exp((r-1)/g[2])))); + } +} + +void CLASS pseudoinverse (double (*in)[3], double (*out)[3], int size) +{ + double work[3][6], num; + int i, j, k; + + for (i=0; i < 3; i++) { + for (j=0; j < 6; j++) + work[i][j] = j == i+3; + for (j=0; j < 3; j++) + for (k=0; k < size; k++) + work[i][j] += in[k][i] * in[k][j]; + } + for (i=0; i < 3; i++) { + num = work[i][i]; + for (j=0; j < 6; j++) + work[i][j] /= num; + for (k=0; k < 3; k++) { + if (k==i) continue; + num = work[k][i]; + for (j=0; j < 6; j++) + work[k][j] -= work[i][j] * num; + } + } + for (i=0; i < size; i++) + for (j=0; j < 3; j++) + for (out[i][j]=k=0; k < 3; k++) + out[i][j] += work[j][k+3] * in[i][k]; +} + +void CLASS cam_xyz_coeff (double cam_xyz[4][3]) +{ + double cam_rgb[4][3], inverse[4][3], num; + int i, j, k; + + for (i=0; i < colors; i++) /* Multiply out XYZ colorspace */ + for (j=0; j < 3; j++) + for (cam_rgb[i][j] = k=0; k < 3; k++) + cam_rgb[i][j] += cam_xyz[i][k] * xyz_rgb[k][j]; + + for (i=0; i < colors; i++) { /* Normalize cam_rgb so that */ + for (num=j=0; j < 3; j++) /* cam_rgb * (1,1,1) is (1,1,1,1) */ + num += cam_rgb[i][j]; + for (j=0; j < 3; j++) + cam_rgb[i][j] /= num; + pre_mul[i] = 1 / num; + } + pseudoinverse (cam_rgb, inverse, colors); + for (raw_color = i=0; i < 3; i++) + for (j=0; j < colors; j++) + rgb_cam[i][j] = inverse[j][i]; +} + +#ifdef COLORCHECK +void CLASS colorcheck() +{ +#define NSQ 24 +// Coordinates of the GretagMacbeth ColorChecker squares +// width, height, 1st_column, 1st_row + int cut[NSQ][4]; // you must set these +// ColorChecker Chart under 6500-kelvin illumination + static const double gmb_xyY[NSQ][3] = { + { 0.400, 0.350, 10.1 }, // Dark Skin + { 0.377, 0.345, 35.8 }, // Light Skin + { 0.247, 0.251, 19.3 }, // Blue Sky + { 0.337, 0.422, 13.3 }, // Foliage + { 0.265, 0.240, 24.3 }, // Blue Flower + { 0.261, 0.343, 43.1 }, // Bluish Green + { 0.506, 0.407, 30.1 }, // Orange + { 0.211, 0.175, 12.0 }, // Purplish Blue + { 0.453, 0.306, 19.8 }, // Moderate Red + { 0.285, 0.202, 6.6 }, // Purple + { 0.380, 0.489, 44.3 }, // Yellow Green + { 0.473, 0.438, 43.1 }, // Orange Yellow + { 0.187, 0.129, 6.1 }, // Blue + { 0.305, 0.478, 23.4 }, // Green + { 0.539, 0.313, 12.0 }, // Red + { 0.448, 0.470, 59.1 }, // Yellow + { 0.364, 0.233, 19.8 }, // Magenta + { 0.196, 0.252, 19.8 }, // Cyan + { 0.310, 0.316, 90.0 }, // White + { 0.310, 0.316, 59.1 }, // Neutral 8 + { 0.310, 0.316, 36.2 }, // Neutral 6.5 + { 0.310, 0.316, 19.8 }, // Neutral 5 + { 0.310, 0.316, 9.0 }, // Neutral 3.5 + { 0.310, 0.316, 3.1 } }; // Black + double gmb_cam[NSQ][4], gmb_xyz[NSQ][3]; + double inverse[NSQ][3], cam_xyz[4][3], num; + int c, i, j, k, sq, row, col, count[4]; + + memset (gmb_cam, 0, sizeof gmb_cam); + for (sq=0; sq < NSQ; sq++) { + FORCC count[c] = 0; + for (row=cut[sq][3]; row < cut[sq][3]+cut[sq][1]; row++) + for (col=cut[sq][2]; col < cut[sq][2]+cut[sq][0]; col++) { + c = FC(row,col); + if (c >= colors) c -= 2; + gmb_cam[sq][c] += BAYER(row,col); + count[c]++; + } + FORCC gmb_cam[sq][c] = gmb_cam[sq][c]/count[c] - black; + gmb_xyz[sq][0] = gmb_xyY[sq][2] * gmb_xyY[sq][0] / gmb_xyY[sq][1]; + gmb_xyz[sq][1] = gmb_xyY[sq][2]; + gmb_xyz[sq][2] = gmb_xyY[sq][2] * + (1 - gmb_xyY[sq][0] - gmb_xyY[sq][1]) / gmb_xyY[sq][1]; + } + pseudoinverse (gmb_xyz, inverse, NSQ); + for (i=0; i < colors; i++) + for (j=0; j < 3; j++) + for (cam_xyz[i][j] = k=0; k < NSQ; k++) + cam_xyz[i][j] += gmb_cam[k][i] * inverse[k][j]; + cam_xyz_coeff (cam_xyz); + if (verbose) { + printf (" { \"%s %s\", %d,\n\t{", make, model, black); + num = 10000 / (cam_xyz[1][0] + cam_xyz[1][1] + cam_xyz[1][2]); + FORCC for (j=0; j < 3; j++) + printf ("%c%d", (c | j) ? ',':' ', (int) (cam_xyz[c][j] * num + 0.5)); + puts (" } },"); + } +#undef NSQ +} +#endif + +void CLASS hat_transform (float *temp, float *base, int st, int size, int sc) +{ + int i; + for (i=0; i < sc; i++) + temp[i] = 2*base[st*i] + base[st*(sc-i)] + base[st*(i+sc)]; + for (; i+sc < size; i++) + temp[i] = 2*base[st*i] + base[st*(i-sc)] + base[st*(i+sc)]; + for (; i < size; i++) + temp[i] = 2*base[st*i] + base[st*(i-sc)] + base[st*(2*size-2-(i+sc))]; +} + +void CLASS wavelet_denoise() +{ + float *fimg=0, *temp, thold, mul[2], avg, diff; + int scale=1, size, lev, hpass, lpass, row, col, nc, c, i, wlast; + ushort *window[4]; + static const float noise[] = + { 0.8002,0.2735,0.1202,0.0585,0.0291,0.0152,0.0080,0.0044 }; + + if (verbose) fprintf (stderr,_("Wavelet denoising...\n")); + + while (maximum << scale < 0x10000) scale++; + maximum <<= --scale; + black <<= scale; + if ((size = iheight*iwidth) < 0x15550000) + fimg = (float *) malloc ((size*3 + iheight + iwidth) * sizeof *fimg); + merror (fimg, "wavelet_denoise()"); + temp = fimg + size*3; + if ((nc = colors) == 3 && filters) nc++; + FORC(nc) { /* denoise R,G1,B,G3 individually */ + for (i=0; i < size; i++) + fimg[i] = 256 * sqrt(image[i][c] << scale); + for (hpass=lev=0; lev < 5; lev++) { + lpass = size*((lev & 1)+1); + for (row=0; row < iheight; row++) { + hat_transform (temp, fimg+hpass+row*iwidth, 1, iwidth, 1 << lev); + for (col=0; col < iwidth; col++) + fimg[lpass + row*iwidth + col] = temp[col] * 0.25; + } + for (col=0; col < iwidth; col++) { + hat_transform (temp, fimg+lpass+col, iwidth, iheight, 1 << lev); + for (row=0; row < iheight; row++) + fimg[lpass + row*iwidth + col] = temp[row] * 0.25; + } + thold = threshold * noise[lev]; + for (i=0; i < size; i++) { + fimg[hpass+i] -= fimg[lpass+i]; + if (fimg[hpass+i] < -thold) fimg[hpass+i] += thold; + else if (fimg[hpass+i] > thold) fimg[hpass+i] -= thold; + else fimg[hpass+i] = 0; + if (hpass) fimg[i] += fimg[hpass+i]; + } + hpass = lpass; + } + for (i=0; i < size; i++) + image[i][c] = CLIP(SQR(fimg[i]+fimg[lpass+i])/0x10000); + } + if (filters && colors == 3) { /* pull G1 and G3 closer together */ + for (row=0; row < 2; row++) + mul[row] = 0.125 * pre_mul[FC(row+1,0) | 1] / pre_mul[FC(row,0) | 1]; + for (i=0; i < 4; i++) + window[i] = (ushort *) fimg + width*i; + for (wlast=-1, row=1; row < height-1; row++) { + while (wlast < row+1) { + for (wlast++, i=0; i < 4; i++) + window[(i+3) & 3] = window[i]; + for (col = FC(wlast,1) & 1; col < width; col+=2) + window[2][col] = BAYER(wlast,col); + } + thold = threshold/512; + for (col = (FC(row,0) & 1)+1; col < width-1; col+=2) { + avg = ( window[0][col-1] + window[0][col+1] + + window[2][col-1] + window[2][col+1] - black*4 ) + * mul[row & 1] + (window[1][col] - black) * 0.5 + black; + avg = avg < 0 ? 0 : sqrt(avg); + diff = sqrt(BAYER(row,col)) - avg; + if (diff < -thold) diff += thold; + else if (diff > thold) diff -= thold; + else diff = 0; + BAYER(row,col) = CLIP(SQR(avg+diff) + 0.5); + } + } + } + free (fimg); +} + +void CLASS scale_colors() +{ + unsigned bottom, right, size, row, col, ur, uc, i, x, y, c, sum[8]; + int val, dark, sat; + double dsum[8], dmin, dmax; + float scale_mul[4], fr, fc; + ushort *img=0, *pix; + + if (user_mul[0]) + memcpy (pre_mul, user_mul, sizeof pre_mul); + if (use_auto_wb || (use_camera_wb && cam_mul[0] == -1)) { + memset (dsum, 0, sizeof dsum); + bottom = MIN (greybox[1]+greybox[3], height); + right = MIN (greybox[0]+greybox[2], width); + for (row=greybox[1]; row < bottom; row += 8) + for (col=greybox[0]; col < right; col += 8) { + memset (sum, 0, sizeof sum); + for (y=row; y < row+8 && y < bottom; y++) + for (x=col; x < col+8 && x < right; x++) + FORC4 { + if (filters) { + c = FC(y,x); + val = BAYER(y,x); + } else + val = image[y*width+x][c]; + if (val > maximum-25) goto skip_block; + if ((val -= black) < 0) val = 0; + sum[c] += val; + sum[c+4]++; + if (filters) break; + } + FORC(8) dsum[c] += sum[c]; +skip_block: ; + } + FORC4 if (dsum[c]) pre_mul[c] = dsum[c+4] / dsum[c]; + } + if (use_camera_wb && cam_mul[0] != -1) { + memset (sum, 0, sizeof sum); + for (row=0; row < 8; row++) + for (col=0; col < 8; col++) { + c = FC(row,col); + if ((val = white[row][col] - black) > 0) + sum[c] += val; + sum[c+4]++; + } + if (sum[0] && sum[1] && sum[2] && sum[3]) + FORC4 pre_mul[c] = (float) sum[c+4] / sum[c]; + else if (cam_mul[0] && cam_mul[2]) + memcpy (pre_mul, cam_mul, sizeof pre_mul); + else + fprintf (stderr,_("%s: Cannot use camera white balance.\n"), ifname); + } + if (pre_mul[3] == 0) pre_mul[3] = colors < 4 ? pre_mul[1] : 1; + dark = black; + sat = maximum; + if (threshold) wavelet_denoise(); + maximum -= black; + for (dmin=DBL_MAX, dmax=c=0; c < 4; c++) { + if (dmin > pre_mul[c]) + dmin = pre_mul[c]; + if (dmax < pre_mul[c]) + dmax = pre_mul[c]; + } + if (!highlight) dmax = dmin; + FORC4 scale_mul[c] = (pre_mul[c] /= dmax) * 65535.0 / maximum; + if (verbose) { + fprintf (stderr, + _("Scaling with darkness %d, saturation %d, and\nmultipliers"), dark, sat); + FORC4 fprintf (stderr, " %f", pre_mul[c]); + fputc ('\n', stderr); + } + size = iheight*iwidth; + for (i=0; i < size*4; i++) { + val = image[0][i]; + if (!val) continue; + val -= black; + val *= scale_mul[i & 3]; + image[0][i] = CLIP(val); + } + if ((aber[0] != 1 || aber[2] != 1) && colors == 3) { + if (verbose) + fprintf (stderr,_("Correcting chromatic aberration...\n")); + for (c=0; c < 4; c+=2) { + if (aber[c] == 1) continue; + img = (ushort *) malloc (size * sizeof *img); + merror (img, "scale_colors()"); + for (i=0; i < size; i++) + img[i] = image[i][c]; + for (row=0; row < iheight; row++) { + ur = fr = (row - iheight*0.5) * aber[c] + iheight*0.5; + if (ur > iheight-2) continue; + fr -= ur; + for (col=0; col < iwidth; col++) { + uc = fc = (col - iwidth*0.5) * aber[c] + iwidth*0.5; + if (uc > iwidth-2) continue; + fc -= uc; + pix = img + ur*iwidth + uc; + image[row*iwidth+col][c] = + (pix[ 0]*(1-fc) + pix[ 1]*fc) * (1-fr) + + (pix[iwidth]*(1-fc) + pix[iwidth+1]*fc) * fr; + } + } + free(img); + } + } +} + +void CLASS pre_interpolate() +{ + ushort (*img)[4]; + int row, col, c; + + if (shrink) { + if (half_size) { + height = iheight; + width = iwidth; + } else { + img = (ushort (*)[4]) calloc (height*width, sizeof *img); + merror (img, "pre_interpolate()"); + for (row=0; row < height; row++) + for (col=0; col < width; col++) { + c = fc(row,col); + img[row*width+col][c] = image[(row >> 1)*iwidth+(col >> 1)][c]; + } + free (image); + image = img; + shrink = 0; + } + } + if (filters && colors == 3) { + if ((mix_green = four_color_rgb)) colors++; + else { + for (row = FC(1,0) >> 1; row < height; row+=2) + for (col = FC(row,1) & 1; col < width; col+=2) + image[row*width+col][1] = image[row*width+col][3]; +/*RT*/ pre_filters = filters; + filters &= ~((filters & 0x55555555) << 1); + } + } + if (half_size) filters = 0; +} + +void CLASS border_interpolate (int border) +{ + unsigned row, col, y, x, f, c, sum[8]; + + for (row=0; row < height; row++) + for (col=0; col < width; col++) { + if (col==border && row >= border && row < height-border) + col = width-border; + memset (sum, 0, sizeof sum); + for (y=row-1; y != row+2; y++) + for (x=col-1; x != col+2; x++) + if (y < height && x < width) { + f = fc(y,x); + sum[f] += image[y*width+x][f]; + sum[f+4]++; + } + f = fc(row,col); + FORCC if (c != f && sum[c+4]) + image[row*width+col][c] = sum[c] / sum[c+4]; + } +} + +void CLASS lin_interpolate() +{ + int code[16][16][32], *ip, sum[4]; + int c, i, x, y, row, col, shift, color; + ushort *pix; + + if (verbose) fprintf (stderr,_("Bilinear interpolation...\n")); + + border_interpolate(1); + for (row=0; row < 16; row++) + for (col=0; col < 16; col++) { + ip = code[row][col]; + memset (sum, 0, sizeof sum); + for (y=-1; y <= 1; y++) + for (x=-1; x <= 1; x++) { + shift = (y==0) + (x==0); + if (shift == 2) continue; + color = fc(row+y,col+x); + *ip++ = (width*y + x)*4 + color; + *ip++ = shift; + *ip++ = color; + sum[color] += 1 << shift; + } + FORCC + if (c != fc(row,col)) { + *ip++ = c; + *ip++ = 256 / sum[c]; + } + } + for (row=1; row < height-1; row++) + for (col=1; col < width-1; col++) { + pix = image[row*width+col]; + ip = code[row & 15][col & 15]; + memset (sum, 0, sizeof sum); + for (i=8; i--; ip+=3) + sum[ip[2]] += pix[ip[0]] << ip[1]; + for (i=colors; --i; ip+=2) + pix[ip[0]] = sum[ip[0]] * ip[1] >> 8; + } +} + +/* + This algorithm is officially called: + + "Interpolation using a Threshold-based variable number of gradients" + + described in http://scien.stanford.edu/class/psych221/projects/99/tingchen/algodep/vargra.html + + I've extended the basic idea to work with non-Bayer filter arrays. + Gradients are numbered clockwise from NW=0 to W=7. + */ +void CLASS vng_interpolate() +{ + static const signed char *cp, terms[] = { + -2,-2,+0,-1,0,0x01, -2,-2,+0,+0,1,0x01, -2,-1,-1,+0,0,0x01, + -2,-1,+0,-1,0,0x02, -2,-1,+0,+0,0,0x03, -2,-1,+0,+1,1,0x01, + -2,+0,+0,-1,0,0x06, -2,+0,+0,+0,1,0x02, -2,+0,+0,+1,0,0x03, + -2,+1,-1,+0,0,0x04, -2,+1,+0,-1,1,0x04, -2,+1,+0,+0,0,0x06, + -2,+1,+0,+1,0,0x02, -2,+2,+0,+0,1,0x04, -2,+2,+0,+1,0,0x04, + -1,-2,-1,+0,0,0x80, -1,-2,+0,-1,0,0x01, -1,-2,+1,-1,0,0x01, + -1,-2,+1,+0,1,0x01, -1,-1,-1,+1,0,0x88, -1,-1,+1,-2,0,0x40, + -1,-1,+1,-1,0,0x22, -1,-1,+1,+0,0,0x33, -1,-1,+1,+1,1,0x11, + -1,+0,-1,+2,0,0x08, -1,+0,+0,-1,0,0x44, -1,+0,+0,+1,0,0x11, + -1,+0,+1,-2,1,0x40, -1,+0,+1,-1,0,0x66, -1,+0,+1,+0,1,0x22, + -1,+0,+1,+1,0,0x33, -1,+0,+1,+2,1,0x10, -1,+1,+1,-1,1,0x44, + -1,+1,+1,+0,0,0x66, -1,+1,+1,+1,0,0x22, -1,+1,+1,+2,0,0x10, + -1,+2,+0,+1,0,0x04, -1,+2,+1,+0,1,0x04, -1,+2,+1,+1,0,0x04, + +0,-2,+0,+0,1,0x80, +0,-1,+0,+1,1,0x88, +0,-1,+1,-2,0,0x40, + +0,-1,+1,+0,0,0x11, +0,-1,+2,-2,0,0x40, +0,-1,+2,-1,0,0x20, + +0,-1,+2,+0,0,0x30, +0,-1,+2,+1,1,0x10, +0,+0,+0,+2,1,0x08, + +0,+0,+2,-2,1,0x40, +0,+0,+2,-1,0,0x60, +0,+0,+2,+0,1,0x20, + +0,+0,+2,+1,0,0x30, +0,+0,+2,+2,1,0x10, +0,+1,+1,+0,0,0x44, + +0,+1,+1,+2,0,0x10, +0,+1,+2,-1,1,0x40, +0,+1,+2,+0,0,0x60, + +0,+1,+2,+1,0,0x20, +0,+1,+2,+2,0,0x10, +1,-2,+1,+0,0,0x80, + +1,-1,+1,+1,0,0x88, +1,+0,+1,+2,0,0x08, +1,+0,+2,-1,0,0x40, + +1,+0,+2,+1,0,0x10 + }, chood[] = { -1,-1, -1,0, -1,+1, 0,+1, +1,+1, +1,0, +1,-1, 0,-1 }; + ushort (*brow[5])[4], *pix; + int prow=7, pcol=1, *ip, *code[16][16], gval[8], gmin, gmax, sum[4]; + int row, col, x, y, x1, x2, y1, y2, t, weight, grads, color, diag; + int g, diff, thold, num, c; + + lin_interpolate(); + if (verbose) fprintf (stderr,_("VNG interpolation...\n")); + + if (filters == 1) prow = pcol = 15; + ip = (int *) calloc ((prow+1)*(pcol+1), 1280); + merror (ip, "vng_interpolate()"); + for (row=0; row <= prow; row++) /* Precalculate for VNG */ + for (col=0; col <= pcol; col++) { + code[row][col] = ip; + for (cp=terms, t=0; t < 64; t++) { + y1 = *cp++; x1 = *cp++; + y2 = *cp++; x2 = *cp++; + weight = *cp++; + grads = *cp++; + color = fc(row+y1,col+x1); + if (fc(row+y2,col+x2) != color) continue; + diag = (fc(row,col+1) == color && fc(row+1,col) == color) ? 2:1; + if (abs(y1-y2) == diag && abs(x1-x2) == diag) continue; + *ip++ = (y1*width + x1)*4 + color; + *ip++ = (y2*width + x2)*4 + color; + *ip++ = weight; + for (g=0; g < 8; g++) + if (grads & 1< gval[g]) gmin = gval[g]; + if (gmax < gval[g]) gmax = gval[g]; + } + if (gmax == 0) { + memcpy (brow[2][col], pix, sizeof *image); + continue; + } + thold = gmin + (gmax >> 1); + memset (sum, 0, sizeof sum); + color = fc(row,col); + for (num=g=0; g < 8; g++,ip+=2) { /* Average the neighbors */ + if (gval[g] <= thold) { + FORCC + if (c == color && ip[1]) + sum[c] += (pix[c] + pix[ip[1]]) >> 1; + else + sum[c] += pix[ip[0] + c]; + num++; + } + } + FORCC { /* Save to buffer */ + t = pix[color]; + if (c != color) + t += (sum[c] - sum[color]) / num; + brow[2][col][c] = CLIP(t); + } + } + if (row > 3) /* Write buffer to image */ + memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image); + for (g=0; g < 4; g++) + brow[(g-1) & 3] = brow[g]; + } + memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image); + memcpy (image[(row-1)*width+2], brow[1]+2, (width-4)*sizeof *image); + free (brow[4]); + free (code[0][0]); +} + +/* + Patterned Pixel Grouping Interpolation by Alain Desbiolles +*/ +void CLASS ppg_interpolate() +{ + int dir[5] = { 1, width, -1, -width, 1 }; + int row, col, diff[2], guess[2], c, d, i; + ushort (*pix)[4]; + + border_interpolate(3); + if (verbose) fprintf (stderr,_("PPG interpolation...\n")); + +/* Fill in the green layer with gradients and pattern recognition: */ + for (row=3; row < height-3; row++) + for (col=3+(FC(row,3) & 1), c=FC(row,col); col < width-3; col+=2) { + pix = image + row*width+col; + for (i=0; (d=dir[i]) > 0; i++) { + guess[i] = (pix[-d][1] + pix[0][c] + pix[d][1]) * 2 + - pix[-2*d][c] - pix[2*d][c]; + diff[i] = ( ABS(pix[-2*d][c] - pix[ 0][c]) + + ABS(pix[ 2*d][c] - pix[ 0][c]) + + ABS(pix[ -d][1] - pix[ d][1]) ) * 3 + + ( ABS(pix[ 3*d][1] - pix[ d][1]) + + ABS(pix[-3*d][1] - pix[-d][1]) ) * 2; + } + d = dir[i = diff[0] > diff[1]]; + pix[0][1] = ULIM(guess[i] >> 2, pix[d][1], pix[-d][1]); + } +/* Calculate red and blue for each green pixel: */ + for (row=1; row < height-1; row++) + for (col=1+(FC(row,2) & 1), c=FC(row,col+1); col < width-1; col+=2) { + pix = image + row*width+col; + for (i=0; (d=dir[i]) > 0; c=2-c, i++) + pix[0][c] = CLIP((pix[-d][c] + pix[d][c] + 2*pix[0][1] + - pix[-d][1] - pix[d][1]) >> 1); + } +/* Calculate blue for red pixels and vice versa: */ + for (row=1; row < height-1; row++) + for (col=1+(FC(row,1) & 1), c=2-FC(row,col); col < width-1; col+=2) { + pix = image + row*width+col; + for (i=0; (d=dir[i]+dir[i+1]) > 0; i++) { + diff[i] = ABS(pix[-d][c] - pix[d][c]) + + ABS(pix[-d][1] - pix[0][1]) + + ABS(pix[ d][1] - pix[0][1]); + guess[i] = pix[-d][c] + pix[d][c] + 2*pix[0][1] + - pix[-d][1] - pix[d][1]; + } + if (diff[0] != diff[1]) + pix[0][c] = CLIP(guess[diff[0] > diff[1]] >> 1); + else + pix[0][c] = CLIP((guess[0]+guess[1]) >> 2); + } +} + +/* + Adaptive Homogeneity-Directed interpolation is based on + the work of Keigo Hirakawa, Thomas Parks, and Paul Lee. + */ +#define TS 256 /* Tile Size */ + +void CLASS ahd_interpolate() +{ + int i, j, k, top, left, row, col, tr, tc, c, d, val, hm[2]; + ushort (*pix)[4], (*rix)[3]; + static const int dir[4] = { -1, 1, -TS, TS }; + unsigned ldiff[2][4], abdiff[2][4], leps, abeps; + float r, cbrt[0x10000], xyz[3], xyz_cam[3][4]; + ushort (*rgb)[TS][TS][3]; + short (*lab)[TS][TS][3], (*lix)[3]; + char (*homo)[TS][TS], *buffer; + + if (verbose) fprintf (stderr,_("AHD interpolation...\n")); + + for (i=0; i < 0x10000; i++) { + r = i / 65535.0; + cbrt[i] = r > 0.008856 ? pow(r,1/3.0) : 7.787*r + 16/116.0; + } + for (i=0; i < 3; i++) + for (j=0; j < colors; j++) + for (xyz_cam[i][j] = k=0; k < 3; k++) + xyz_cam[i][j] += xyz_rgb[i][k] * rgb_cam[k][j] / d65_white[i]; + + border_interpolate(5); + buffer = (char *) malloc (26*TS*TS); /* 1664 kB */ + merror (buffer, "ahd_interpolate()"); + rgb = (ushort(*)[TS][TS][3]) buffer; + lab = (short (*)[TS][TS][3])(buffer + 12*TS*TS); + homo = (char (*)[TS][TS]) (buffer + 24*TS*TS); + + for (top=2; top < height-5; top += TS-6) + for (left=2; left < width-5; left += TS-6) { + +/* Interpolate green horizontally and vertically: */ + for (row = top; row < top+TS && row < height-2; row++) { + col = left + (FC(row,left) & 1); + for (c = FC(row,col); col < left+TS && col < width-2; col+=2) { + pix = image + row*width+col; + val = ((pix[-1][1] + pix[0][c] + pix[1][1]) * 2 + - pix[-2][c] - pix[2][c]) >> 2; + rgb[0][row-top][col-left][1] = ULIM(val,pix[-1][1],pix[1][1]); + val = ((pix[-width][1] + pix[0][c] + pix[width][1]) * 2 + - pix[-2*width][c] - pix[2*width][c]) >> 2; + rgb[1][row-top][col-left][1] = ULIM(val,pix[-width][1],pix[width][1]); + } + } +/* Interpolate red and blue, and convert to CIELab: */ + for (d=0; d < 2; d++) + for (row=top+1; row < top+TS-1 && row < height-3; row++) + for (col=left+1; col < left+TS-1 && col < width-3; col++) { + pix = image + row*width+col; + rix = &rgb[d][row-top][col-left]; + lix = &lab[d][row-top][col-left]; + if ((c = 2 - FC(row,col)) == 1) { + c = FC(row+1,col); + val = pix[0][1] + (( pix[-1][2-c] + pix[1][2-c] + - rix[-1][1] - rix[1][1] ) >> 1); + rix[0][2-c] = CLIP(val); + val = pix[0][1] + (( pix[-width][c] + pix[width][c] + - rix[-TS][1] - rix[TS][1] ) >> 1); + } else + val = rix[0][1] + (( pix[-width-1][c] + pix[-width+1][c] + + pix[+width-1][c] + pix[+width+1][c] + - rix[-TS-1][1] - rix[-TS+1][1] + - rix[+TS-1][1] - rix[+TS+1][1] + 1) >> 2); + rix[0][c] = CLIP(val); + c = FC(row,col); + rix[0][c] = pix[0][c]; + xyz[0] = xyz[1] = xyz[2] = 0.5; + FORCC { + xyz[0] += xyz_cam[0][c] * rix[0][c]; + xyz[1] += xyz_cam[1][c] * rix[0][c]; + xyz[2] += xyz_cam[2][c] * rix[0][c]; + } + xyz[0] = cbrt[CLIP((int) xyz[0])]; + xyz[1] = cbrt[CLIP((int) xyz[1])]; + xyz[2] = cbrt[CLIP((int) xyz[2])]; + lix[0][0] = 64 * (116 * xyz[1] - 16); + lix[0][1] = 64 * 500 * (xyz[0] - xyz[1]); + lix[0][2] = 64 * 200 * (xyz[1] - xyz[2]); + } +/* Build homogeneity maps from the CIELab images: */ + memset (homo, 0, 2*TS*TS); + for (row=top+2; row < top+TS-2 && row < height-4; row++) { + tr = row-top; + for (col=left+2; col < left+TS-2 && col < width-4; col++) { + tc = col-left; + for (d=0; d < 2; d++) { + lix = &lab[d][tr][tc]; + for (i=0; i < 4; i++) { + ldiff[d][i] = ABS(lix[0][0]-lix[dir[i]][0]); + abdiff[d][i] = SQR(lix[0][1]-lix[dir[i]][1]) + + SQR(lix[0][2]-lix[dir[i]][2]); + } + } + leps = MIN(MAX(ldiff[0][0],ldiff[0][1]), + MAX(ldiff[1][2],ldiff[1][3])); + abeps = MIN(MAX(abdiff[0][0],abdiff[0][1]), + MAX(abdiff[1][2],abdiff[1][3])); + for (d=0; d < 2; d++) + for (i=0; i < 4; i++) + if (ldiff[d][i] <= leps && abdiff[d][i] <= abeps) + homo[d][tr][tc]++; + } + } +/* Combine the most homogenous pixels for the final result: */ + for (row=top+3; row < top+TS-3 && row < height-5; row++) { + tr = row-top; + for (col=left+3; col < left+TS-3 && col < width-5; col++) { + tc = col-left; + for (d=0; d < 2; d++) + for (hm[d]=0, i=tr-1; i <= tr+1; i++) + for (j=tc-1; j <= tc+1; j++) + hm[d] += homo[d][i][j]; + if (hm[0] != hm[1]) + FORC3 image[row*width+col][c] = rgb[hm[1] > hm[0]][tr][tc][c]; + else + FORC3 image[row*width+col][c] = + (rgb[0][tr][tc][c] + rgb[1][tr][tc][c]) >> 1; + } + } + } + free (buffer); +} +#undef TS + +void CLASS median_filter() +{ + ushort (*pix)[4]; + int pass, c, i, j, k, med[9]; + static const uchar opt[] = /* Optimal 9-element median search */ + { 1,2, 4,5, 7,8, 0,1, 3,4, 6,7, 1,2, 4,5, 7,8, + 0,3, 5,8, 4,7, 3,6, 1,4, 2,5, 4,7, 4,2, 6,4, 4,2 }; + + for (pass=1; pass <= med_passes; pass++) { + if (verbose) + fprintf (stderr,_("Median filter pass %d...\n"), pass); + for (c=0; c < 3; c+=2) { + for (pix = image; pix < image+width*height; pix++) + pix[0][3] = pix[0][c]; + for (pix = image+width; pix < image+width*(height-1); pix++) { + if ((pix-image+1) % width < 2) continue; + for (k=0, i = -width; i <= width; i += width) + for (j = i-1; j <= i+1; j++) + med[k++] = pix[j][3] - pix[j][1]; + for (i=0; i < sizeof opt; i+=2) + if (med[opt[i]] > med[opt[i+1]]) + SWAP (med[opt[i]] , med[opt[i+1]]); + pix[0][c] = CLIP(med[4] + pix[0][1]); + } + } + } +} + +void CLASS blend_highlights() +{ + int clip=INT_MAX, row, col, c, i, j; + static const float trans[2][4][4] = + { { { 1,1,1 }, { 1.7320508,-1.7320508,0 }, { -1,-1,2 } }, + { { 1,1,1,1 }, { 1,-1,1,-1 }, { 1,1,-1,-1 }, { 1,-1,-1,1 } } }; + static const float itrans[2][4][4] = + { { { 1,0.8660254,-0.5 }, { 1,-0.8660254,-0.5 }, { 1,0,1 } }, + { { 1,1,1,1 }, { 1,-1,1,-1 }, { 1,1,-1,-1 }, { 1,-1,-1,1 } } }; + float cam[2][4], lab[2][4], sum[2], chratio; + + if ((unsigned) (colors-3) > 1) return; + if (verbose) fprintf (stderr,_("Blending highlights...\n")); + FORCC if (clip > (i = 65535*pre_mul[c])) clip = i; + for (row=0; row < height; row++) + for (col=0; col < width; col++) { + FORCC if (image[row*width+col][c] > clip) break; + if (c == colors) continue; + FORCC { + cam[0][c] = image[row*width+col][c]; + cam[1][c] = MIN(cam[0][c],clip); + } + for (i=0; i < 2; i++) { + FORCC for (lab[i][c]=j=0; j < colors; j++) + lab[i][c] += trans[colors-3][c][j] * cam[i][j]; + for (sum[i]=0,c=1; c < colors; c++) + sum[i] += SQR(lab[i][c]); + } + chratio = sqrt(sum[1]/sum[0]); + for (c=1; c < colors; c++) + lab[0][c] *= chratio; + FORCC for (cam[0][c]=j=0; j < colors; j++) + cam[0][c] += itrans[colors-3][c][j] * lab[0][j]; + FORCC image[row*width+col][c] = cam[0][c] / colors; + } +} + +#define SCALE (4 >> shrink) +void CLASS recover_highlights() +{ + float *map, sum, wgt, grow; + int hsat[4], count, spread, change, val, i; + unsigned high, wide, mrow, mcol, row, col, kc, c, d, y, x; + ushort *pixel; + static const signed char dir[8][2] = + { {-1,-1}, {-1,0}, {-1,1}, {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1} }; + + if (verbose) fprintf (stderr,_("Rebuilding highlights...\n")); + + grow = pow (2, 4-highlight); + FORCC hsat[c] = 32000 * pre_mul[c]; + for (kc=0, c=1; c < colors; c++) + if (pre_mul[kc] < pre_mul[c]) kc = c; + high = height / SCALE; + wide = width / SCALE; + map = (float *) calloc (high*wide, sizeof *map); + merror (map, "recover_highlights()"); + FORCC if (c != kc) { + memset (map, 0, high*wide*sizeof *map); + for (mrow=0; mrow < high; mrow++) + for (mcol=0; mcol < wide; mcol++) { + sum = wgt = count = 0; + for (row = mrow*SCALE; row < (mrow+1)*SCALE; row++) + for (col = mcol*SCALE; col < (mcol+1)*SCALE; col++) { + pixel = image[row*width+col]; + if (pixel[c] / hsat[c] == 1 && pixel[kc] > 24000) { + sum += pixel[c]; + wgt += pixel[kc]; + count++; + } + } + if (count == SCALE*SCALE) + map[mrow*wide+mcol] = sum / wgt; + } + for (spread = 32/grow; spread--; ) { + for (mrow=0; mrow < high; mrow++) + for (mcol=0; mcol < wide; mcol++) { + if (map[mrow*wide+mcol]) continue; + sum = count = 0; + for (d=0; d < 8; d++) { + y = mrow + dir[d][0]; + x = mcol + dir[d][1]; + if (y < high && x < wide && map[y*wide+x] > 0) { + sum += (1 + (d & 1)) * map[y*wide+x]; + count += 1 + (d & 1); + } + } + if (count > 3) + map[mrow*wide+mcol] = - (sum+grow) / (count+grow); + } + for (change=i=0; i < high*wide; i++) + if (map[i] < 0) { + map[i] = -map[i]; + change = 1; + } + if (!change) break; + } + for (i=0; i < high*wide; i++) + if (map[i] == 0) map[i] = 1; + for (mrow=0; mrow < high; mrow++) + for (mcol=0; mcol < wide; mcol++) { + for (row = mrow*SCALE; row < (mrow+1)*SCALE; row++) + for (col = mcol*SCALE; col < (mcol+1)*SCALE; col++) { + pixel = image[row*width+col]; + if (pixel[c] / hsat[c] > 1) { + val = pixel[kc] * map[mrow*wide+mcol]; + if (pixel[c] < val) pixel[c] = CLIP(val); + } + } + } + } + free (map); +} +#undef SCALE + +void CLASS tiff_get (unsigned base, + unsigned *tag, unsigned *type, unsigned *len, unsigned *save) +{ + *tag = get2(); + *type = get2(); + *len = get4(); + *save = ftell(ifp) + 4; + if (*len * ("11124811248488"[*type < 14 ? *type:0]-'0') > 4) + fseek (ifp, get4()+base, SEEK_SET); +} + +void CLASS parse_thumb_note (int base, unsigned toff, unsigned tlen) +{ + unsigned entries, tag, type, len, save; + + entries = get2(); + while (entries--) { + tiff_get (base, &tag, &type, &len, &save); + if (tag == toff) thumb_offset = get4()+base; + if (tag == tlen) thumb_length = get4(); + fseek (ifp, save, SEEK_SET); + } +} + +int CLASS parse_tiff_ifd (int base); + +void CLASS parse_makernote (int base, int uptag) +{ + static const uchar xlat[2][256] = { + { 0xc1,0xbf,0x6d,0x0d,0x59,0xc5,0x13,0x9d,0x83,0x61,0x6b,0x4f,0xc7,0x7f,0x3d,0x3d, + 0x53,0x59,0xe3,0xc7,0xe9,0x2f,0x95,0xa7,0x95,0x1f,0xdf,0x7f,0x2b,0x29,0xc7,0x0d, + 0xdf,0x07,0xef,0x71,0x89,0x3d,0x13,0x3d,0x3b,0x13,0xfb,0x0d,0x89,0xc1,0x65,0x1f, + 0xb3,0x0d,0x6b,0x29,0xe3,0xfb,0xef,0xa3,0x6b,0x47,0x7f,0x95,0x35,0xa7,0x47,0x4f, + 0xc7,0xf1,0x59,0x95,0x35,0x11,0x29,0x61,0xf1,0x3d,0xb3,0x2b,0x0d,0x43,0x89,0xc1, + 0x9d,0x9d,0x89,0x65,0xf1,0xe9,0xdf,0xbf,0x3d,0x7f,0x53,0x97,0xe5,0xe9,0x95,0x17, + 0x1d,0x3d,0x8b,0xfb,0xc7,0xe3,0x67,0xa7,0x07,0xf1,0x71,0xa7,0x53,0xb5,0x29,0x89, + 0xe5,0x2b,0xa7,0x17,0x29,0xe9,0x4f,0xc5,0x65,0x6d,0x6b,0xef,0x0d,0x89,0x49,0x2f, + 0xb3,0x43,0x53,0x65,0x1d,0x49,0xa3,0x13,0x89,0x59,0xef,0x6b,0xef,0x65,0x1d,0x0b, + 0x59,0x13,0xe3,0x4f,0x9d,0xb3,0x29,0x43,0x2b,0x07,0x1d,0x95,0x59,0x59,0x47,0xfb, + 0xe5,0xe9,0x61,0x47,0x2f,0x35,0x7f,0x17,0x7f,0xef,0x7f,0x95,0x95,0x71,0xd3,0xa3, + 0x0b,0x71,0xa3,0xad,0x0b,0x3b,0xb5,0xfb,0xa3,0xbf,0x4f,0x83,0x1d,0xad,0xe9,0x2f, + 0x71,0x65,0xa3,0xe5,0x07,0x35,0x3d,0x0d,0xb5,0xe9,0xe5,0x47,0x3b,0x9d,0xef,0x35, + 0xa3,0xbf,0xb3,0xdf,0x53,0xd3,0x97,0x53,0x49,0x71,0x07,0x35,0x61,0x71,0x2f,0x43, + 0x2f,0x11,0xdf,0x17,0x97,0xfb,0x95,0x3b,0x7f,0x6b,0xd3,0x25,0xbf,0xad,0xc7,0xc5, + 0xc5,0xb5,0x8b,0xef,0x2f,0xd3,0x07,0x6b,0x25,0x49,0x95,0x25,0x49,0x6d,0x71,0xc7 }, + { 0xa7,0xbc,0xc9,0xad,0x91,0xdf,0x85,0xe5,0xd4,0x78,0xd5,0x17,0x46,0x7c,0x29,0x4c, + 0x4d,0x03,0xe9,0x25,0x68,0x11,0x86,0xb3,0xbd,0xf7,0x6f,0x61,0x22,0xa2,0x26,0x34, + 0x2a,0xbe,0x1e,0x46,0x14,0x68,0x9d,0x44,0x18,0xc2,0x40,0xf4,0x7e,0x5f,0x1b,0xad, + 0x0b,0x94,0xb6,0x67,0xb4,0x0b,0xe1,0xea,0x95,0x9c,0x66,0xdc,0xe7,0x5d,0x6c,0x05, + 0xda,0xd5,0xdf,0x7a,0xef,0xf6,0xdb,0x1f,0x82,0x4c,0xc0,0x68,0x47,0xa1,0xbd,0xee, + 0x39,0x50,0x56,0x4a,0xdd,0xdf,0xa5,0xf8,0xc6,0xda,0xca,0x90,0xca,0x01,0x42,0x9d, + 0x8b,0x0c,0x73,0x43,0x75,0x05,0x94,0xde,0x24,0xb3,0x80,0x34,0xe5,0x2c,0xdc,0x9b, + 0x3f,0xca,0x33,0x45,0xd0,0xdb,0x5f,0xf5,0x52,0xc3,0x21,0xda,0xe2,0x22,0x72,0x6b, + 0x3e,0xd0,0x5b,0xa8,0x87,0x8c,0x06,0x5d,0x0f,0xdd,0x09,0x19,0x93,0xd0,0xb9,0xfc, + 0x8b,0x0f,0x84,0x60,0x33,0x1c,0x9b,0x45,0xf1,0xf0,0xa3,0x94,0x3a,0x12,0x77,0x33, + 0x4d,0x44,0x78,0x28,0x3c,0x9e,0xfd,0x65,0x57,0x16,0x94,0x6b,0xfb,0x59,0xd0,0xc8, + 0x22,0x36,0xdb,0xd2,0x63,0x98,0x43,0xa1,0x04,0x87,0x86,0xf7,0xa6,0x26,0xbb,0xd6, + 0x59,0x4d,0xbf,0x6a,0x2e,0xaa,0x2b,0xef,0xe6,0x78,0xb6,0x4e,0xe0,0x2f,0xdc,0x7c, + 0xbe,0x57,0x19,0x32,0x7e,0x2a,0xd0,0xb8,0xba,0x29,0x00,0x3c,0x52,0x7d,0xa8,0x49, + 0x3b,0x2d,0xeb,0x25,0x49,0xfa,0xa3,0xaa,0x39,0xa7,0xc5,0xa7,0x50,0x11,0x36,0xfb, + 0xc6,0x67,0x4a,0xf5,0xa5,0x12,0x65,0x7e,0xb0,0xdf,0xaf,0x4e,0xb3,0x61,0x7f,0x2f } }; + unsigned offset=0, entries, tag, type, len, save, c; + unsigned ver97=0, serial=0, i, wbi=0, wb[4]={0,0,0,0}; + uchar buf97[324], ci, cj, ck; + short sorder=order; + char buf[10]; +/* + The MakerNote might have its own TIFF header (possibly with + its own byte-order!), or it might just be a table. + */ + fread (buf, 1, 10, ifp); + if (!strncmp (buf,"KDK" ,3) || /* these aren't TIFF tables */ + !strncmp (buf,"VER" ,3) || + !strncmp (buf,"IIII",4) || + !strncmp (buf,"MMMM",4)) return; + if (!strncmp (buf,"KC" ,2) || /* Konica KD-400Z, KD-510Z */ + !strncmp (buf,"MLY" ,3)) { /* Minolta DiMAGE G series */ + order = 0x4d4d; + while ((i=ftell(ifp)) < data_offset && i < 16384) { + wb[0] = wb[2]; wb[2] = wb[1]; wb[1] = wb[3]; + wb[3] = get2(); + if (wb[1] == 256 && wb[3] == 256 && + wb[0] > 256 && wb[0] < 640 && wb[2] > 256 && wb[2] < 640) + FORC4 cam_mul[c] = wb[c]; + } + goto quit; + } + if (!strcmp (buf,"Nikon")) { + base = ftell(ifp); + order = get2(); + if (get2() != 42) goto quit; + offset = get4(); + fseek (ifp, offset-8, SEEK_CUR); + } else if (!strcmp (buf,"OLYMPUS")) { + base = ftell(ifp)-10; + fseek (ifp, -2, SEEK_CUR); + order = get2(); get2(); + } else if (!strncmp (buf,"FUJIFILM",8) || + !strncmp (buf,"SONY",4) || + !strcmp (buf,"Panasonic")) { + order = 0x4949; + fseek (ifp, 2, SEEK_CUR); + } else if (!strcmp (buf,"OLYMP") || + !strcmp (buf,"LEICA") || + !strcmp (buf,"Ricoh") || + !strcmp (buf,"EPSON")) + fseek (ifp, -2, SEEK_CUR); + else if (!strcmp (buf,"AOC") || + !strcmp (buf,"QVC")) + fseek (ifp, -4, SEEK_CUR); + else fseek (ifp, -10, SEEK_CUR); + + entries = get2(); + if (entries > 1000) return; + while (entries--) { + tiff_get (base, &tag, &type, &len, &save); + tag |= uptag << 16; + if (tag == 2 && strstr(make,"NIKON")) + iso_speed = (get2(),get2()); + if (tag == 4 && len > 26 && len < 35) { + if ((i=(get4(),get2())) != 0x7fff && !iso_speed) + iso_speed = 50 * pow (2, i/32.0 - 4); + if ((i=(get2(),get2())) != 0x7fff && !aperture) + aperture = pow (2, i/64.0); + if ((i=get2()) != 0xffff && !shutter) + shutter = pow (2, (short) i/-32.0); + wbi = (get2(),get2()); + shot_order = (get2(),get2()); + } + if ((tag == 4 || tag == 0x114) && !strncmp(make,"KONICA",6)) { + fseek (ifp, tag == 4 ? 140:160, SEEK_CUR); + switch (get2()) { + case 72: flip = 0; break; + case 76: flip = 6; break; + case 82: flip = 5; break; + } + } + if (tag == 7 && type == 2 && len > 20) + fgets (model2, 64, ifp); + if (tag == 8 && type == 4) + shot_order = get4(); + if (tag == 9 && !strcmp(make,"Canon")) + fread (artist, 64, 1, ifp); + if (tag == 0xc && len == 4) { + cam_mul[0] = getreal(type); + cam_mul[2] = getreal(type); + } + if (tag == 0x10 && type == 4) + unique_id = get4(); + if (tag == 0x11 && is_raw && !strncmp(make,"NIKON",5)) { + fseek (ifp, get4()+base, SEEK_SET); + parse_tiff_ifd (base); + } + if (tag == 0x14 && len == 2560 && type == 7) { + fseek (ifp, 1248, SEEK_CUR); + goto get2_256; + } + if (tag == 0x15 && type == 2 && is_raw) + fread (model, 64, 1, ifp); + if (strstr(make,"PENTAX")) { + if (tag == 0x1b) tag = 0x1018; + if (tag == 0x1c) tag = 0x1017; + } + if (tag == 0x1d) + while ((c = fgetc(ifp)) && c != EOF) + serial = serial*10 + (isdigit(c) ? c - '0' : c % 10); + if (tag == 0x81 && type == 4) { + data_offset = get4(); + fseek (ifp, data_offset + 41, SEEK_SET); + raw_height = get2() * 2; + raw_width = get2(); + filters = 0x61616161; + } + if (tag == 0x29 && type == 1) { + c = wbi < 18 ? "012347800000005896"[wbi]-'0' : 0; + fseek (ifp, 8 + c*32, SEEK_CUR); + FORC4 cam_mul[c ^ (c >> 1) ^ 1] = get4(); + } + if ((tag == 0x81 && type == 7) || + (tag == 0x100 && type == 7) || + (tag == 0x280 && type == 1)) { + thumb_offset = ftell(ifp); + thumb_length = len; + } + if (tag == 0x88 && type == 4 && (thumb_offset = get4())) + thumb_offset += base; + if (tag == 0x89 && type == 4) + thumb_length = get4(); + if (tag == 0x8c || tag == 0x96) + meta_offset = ftell(ifp); + if (tag == 0x97) { + for (i=0; i < 4; i++) + ver97 = ver97 * 10 + fgetc(ifp)-'0'; + switch (ver97) { + case 100: + fseek (ifp, 68, SEEK_CUR); + FORC4 cam_mul[(c >> 1) | ((c & 1) << 1)] = get2(); + break; + case 102: + fseek (ifp, 6, SEEK_CUR); + goto get2_rggb; + case 103: + fseek (ifp, 16, SEEK_CUR); + FORC4 cam_mul[c] = get2(); + } + if (ver97 >= 200) { + if (ver97 != 205) fseek (ifp, 280, SEEK_CUR); + fread (buf97, 324, 1, ifp); + } + } + if (tag == 0xa4 && type == 3) { + fseek (ifp, wbi*48, SEEK_CUR); + FORC3 cam_mul[c] = get2(); + } + if (tag == 0xa7 && (unsigned) (ver97-200) < 12 && !cam_mul[0]) { + ci = xlat[0][serial & 0xff]; + cj = xlat[1][fgetc(ifp)^fgetc(ifp)^fgetc(ifp)^fgetc(ifp)]; + ck = 0x60; + for (i=0; i < 324; i++) + buf97[i] ^= (cj += ci * ck++); + i = "66666>666;6A"[ver97-200] - '0'; + FORC4 cam_mul[c ^ (c >> 1) ^ (i & 1)] = + sget2 (buf97 + (i & -2) + c*2); + } + if (tag == 0x200 && len == 3) + shot_order = (get4(),get4()); + if (tag == 0x200 && len == 4) + black = (get2()+get2()+get2()+get2())/4; + if (tag == 0x201 && len == 4) + goto get2_rggb; + if (tag == 0x220 && len == 53) + meta_offset = ftell(ifp) + 14; + if (tag == 0x401 && type == 4 && len == 4) { + black = (get4()+get4()+get4()+get4())/4; + } + if (tag == 0xe01) { /* Nikon Capture Note */ + type = order; + order = 0x4949; + fseek (ifp, 22, SEEK_CUR); + for (offset=22; offset+22 < len; offset += 22+i) { + tag = get4(); + fseek (ifp, 14, SEEK_CUR); + i = get4()-4; + if (tag == 0x76a43207) flip = get2(); + else fseek (ifp, i, SEEK_CUR); + } + order = type; + } + if (tag == 0xe80 && len == 256 && type == 7) { + fseek (ifp, 48, SEEK_CUR); + cam_mul[0] = get2() * 508 * 1.078 / 0x10000; + cam_mul[2] = get2() * 382 * 1.173 / 0x10000; + } + if (tag == 0xf00 && type == 7) { + if (len == 614) + fseek (ifp, 176, SEEK_CUR); + else if (len == 734 || len == 1502) + fseek (ifp, 148, SEEK_CUR); + else goto next; + goto get2_256; + } + if ((tag == 0x1011 && len == 9) || tag == 0x20400200) + for (i=0; i < 3; i++) + FORC3 cmatrix[i][c] = ((short) get2()) / 256.0; + if ((tag == 0x1012 || tag == 0x20400600) && len == 4) + for (black = i=0; i < 4; i++) + black += get2() << 2; + if (tag == 0x1017 || tag == 0x20400100) + cam_mul[0] = get2() / 256.0; + if (tag == 0x1018 || tag == 0x20400100) + cam_mul[2] = get2() / 256.0; + if (tag == 0x2011 && len == 2) { +get2_256: + order = 0x4d4d; + cam_mul[0] = get2() / 256.0; + cam_mul[2] = get2() / 256.0; + } + if ((tag | 0x70) == 0x2070 && type == 4) + fseek (ifp, get4()+base, SEEK_SET); + if (tag == 0x2010 && type != 7) + load_raw = &CLASS olympus_load_raw; + if (tag == 0x2020) + parse_thumb_note (base, 257, 258); + if (tag == 0x2040) + parse_makernote (base, 0x2040); + if (tag == 0xb028) { + fseek (ifp, get4(), SEEK_SET); + parse_thumb_note (base, 136, 137); + } + if (tag == 0x4001 && len > 500) { + i = len == 582 ? 50 : len == 653 ? 68 : len == 5120 ? 142 : 126; + fseek (ifp, i, SEEK_CUR); +get2_rggb: + FORC4 cam_mul[c ^ (c >> 1)] = get2(); + fseek (ifp, 22, SEEK_CUR); + FORC4 sraw_mul[c ^ (c >> 1)] = get2(); + } +next: + fseek (ifp, save, SEEK_SET); + } +quit: + order = sorder; +} + +/* + Since the TIFF DateTime string has no timezone information, + assume that the camera's clock was set to Universal Time. + */ +void CLASS get_timestamp (int reversed) +{ + struct tm t; + char str[20]; + int i; + + str[19] = 0; + if (reversed) + for (i=19; i--; ) str[i] = fgetc(ifp); + else + fread (str, 19, 1, ifp); + memset (&t, 0, sizeof t); + if (sscanf (str, "%d:%d:%d %d:%d:%d", &t.tm_year, &t.tm_mon, + &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec) != 6) + return; + t.tm_year -= 1900; + t.tm_mon -= 1; + if (mktime(&t) > 0) + timestamp = mktime(&t); +} + +void CLASS parse_exif (int base) +{ + unsigned kodak, entries, tag, type, len, save, c; + double expo; + + kodak = !strncmp(make,"EASTMAN",7); + entries = get2(); + while (entries--) { + tiff_get (base, &tag, &type, &len, &save); + switch (tag) { + case 33434: shutter = getreal(type); break; + case 33437: aperture = getreal(type); break; + case 34855: iso_speed = get2(); break; + case 36867: + case 36868: get_timestamp(0); break; + case 37377: if ((expo = -getreal(type)) < 128) + shutter = pow (2, expo); break; + case 37378: aperture = pow (2, getreal(type)/2); break; + case 37386: focal_len = getreal(type); break; + case 37500: parse_makernote (base, 0); break; + case 40962: if (kodak) raw_width = get4(); break; + case 40963: if (kodak) raw_height = get4(); break; + case 41730: + if (get4() == 0x20002) + for (exif_cfa=c=0; c < 8; c+=2) + exif_cfa |= fgetc(ifp) * 0x01010101 << c; + } + fseek (ifp, save, SEEK_SET); + } +} + +void CLASS parse_gps (int base) +{ + unsigned entries, tag, type, len, save, c; + + entries = get2(); + while (entries--) { + tiff_get (base, &tag, &type, &len, &save); + switch (tag) { + case 1: case 3: case 5: + gpsdata[29+tag/2] = getc(ifp); break; + case 2: case 4: case 7: + FORC(6) gpsdata[tag/3*6+c] = get4(); break; + case 6: + FORC(2) gpsdata[18+c] = get4(); break; + case 18: case 29: + fgets ((char *) (gpsdata+14+tag/3), MIN(len,12), ifp); + } + fseek (ifp, save, SEEK_SET); + } +} + +void CLASS romm_coeff (float romm_cam[3][3]) +{ + static const float rgb_romm[3][3] = /* ROMM == Kodak ProPhoto */ + { { 2.034193, -0.727420, -0.306766 }, + { -0.228811, 1.231729, -0.002922 }, + { -0.008565, -0.153273, 1.161839 } }; + int i, j, k; + + for (i=0; i < 3; i++) + for (j=0; j < 3; j++) + for (cmatrix[i][j] = k=0; k < 3; k++) + cmatrix[i][j] += rgb_romm[i][k] * romm_cam[k][j]; +} + +void CLASS parse_mos (int offset) +{ + char data[40]; + int skip, from, i, c, neut[4], planes=0, frot=0; + static const char *mod[] = + { "","DCB2","Volare","Cantare","CMost","Valeo 6","Valeo 11","Valeo 22", + "Valeo 11p","Valeo 17","","Aptus 17","Aptus 22","Aptus 75","Aptus 65", + "Aptus 54S","Aptus 65S","Aptus 75S","AFi 5","AFi 6","AFi 7" }; + float romm_cam[3][3]; + + fseek (ifp, offset, SEEK_SET); + while (1) { + if (get4() != 0x504b5453) break; + get4(); + fread (data, 1, 40, ifp); + skip = get4(); + from = ftell(ifp); + if (!strcmp(data,"JPEG_preview_data")) { + thumb_offset = from; + thumb_length = skip; + } + if (!strcmp(data,"icc_camera_profile")) { + profile_offset = from; + profile_length = skip; + } + if (!strcmp(data,"ShootObj_back_type")) { + fscanf (ifp, "%d", &i); + if ((unsigned) i < sizeof mod / sizeof (*mod)) + strcpy (model, mod[i]); + } + if (!strcmp(data,"icc_camera_to_tone_matrix")) { + for (i=0; i < 9; i++) + romm_cam[0][i] = int_to_float(get4()); + romm_coeff (romm_cam); + } + if (!strcmp(data,"CaptProf_color_matrix")) { + for (i=0; i < 9; i++) + fscanf (ifp, "%f", &romm_cam[0][i]); + romm_coeff (romm_cam); + } + if (!strcmp(data,"CaptProf_number_of_planes")) + fscanf (ifp, "%d", &planes); + if (!strcmp(data,"CaptProf_raw_data_rotation")) + fscanf (ifp, "%d", &flip); + if (!strcmp(data,"CaptProf_mosaic_pattern")) + FORC4 { + fscanf (ifp, "%d", &i); + if (i == 1) frot = c ^ (c >> 1); + } + if (!strcmp(data,"ImgProf_rotation_angle")) { + fscanf (ifp, "%d", &i); + flip = i - flip; + } + if (!strcmp(data,"NeutObj_neutrals") && !cam_mul[0]) { + FORC4 fscanf (ifp, "%d", neut+c); + FORC3 cam_mul[c] = (float) neut[0] / neut[c+1]; + } + parse_mos (from); + fseek (ifp, skip+from, SEEK_SET); + } + if (planes) + filters = (planes == 1) * 0x01010101 * + (uchar) "\x94\x61\x16\x49"[(flip/90 + frot) & 3]; +} + +void CLASS linear_table (unsigned len) +{ + int i; + if (len > 0x1000) len = 0x1000; + read_shorts (curve, len); + for (i=len; i < 0x1000; i++) + curve[i] = curve[i-1]; + maximum = curve[0xfff]; +} + +void CLASS parse_kodak_ifd (int base) +{ + unsigned entries, tag, type, len, save; + int i, c, wbi=-2, wbtemp=6500; + float mul[3]={1,1,1}, num; + static const int wbtag[]={ 0xfa25,0xfa28,0xfa27,0xfa29,-1,-1,0xfa2a }; + + entries = get2(); + if (entries > 1024) return; + while (entries--) { + tiff_get (base, &tag, &type, &len, &save); + if (tag == 1020) wbi = getint(type); + if (tag == 1021 && len == 72) { /* WB set in software */ + fseek (ifp, 40, SEEK_CUR); + FORC3 cam_mul[c] = 2048.0 / get2(); + wbi = -2; + } + if (tag == 2118) wbtemp = getint(type); + if (tag == 2130 + wbi) + FORC3 mul[c] = getreal(type); + if (tag == 2140 + wbi && wbi >= 0) + FORC3 { + for (num=i=0; i < 4; i++) + num += getreal(type) * pow (wbtemp/100.0, i); + cam_mul[c] = 2048 / (num * mul[c]); + } + if (tag == 2317) linear_table (len); + if (tag == 6020) iso_speed = getint(type); + if (tag == 0xfa0d) wbi = fgetc(ifp); + if ((unsigned) wbi < 7 && tag == wbtag[wbi]) + FORC3 cam_mul[c] = get4(); + fseek (ifp, save, SEEK_SET); + } +} + +void CLASS parse_minolta (int base); + +int CLASS parse_tiff_ifd (int base) +{ + unsigned entries, tag, type, len, plen=16, save; + int ifd, use_cm=0, cfa, i, j, c, ima_len=0; + char software[64], *cbuf, *cp; + uchar cfa_pat[16], cfa_pc[] = { 0,1,2,3 }, tab[256]; + double dblack, cc[4][4], cm[4][3], cam_xyz[4][3], num; + double ab[]={ 1,1,1,1 }, asn[] = { 0,0,0,0 }, xyz[] = { 1,1,1 }; + unsigned sony_curve[] = { 0,0,0,0,0,4095 }; + unsigned *buf, sony_offset=0, sony_length=0, sony_key=0; + struct jhead jh; +/*RT*/ IMFILE *sfp; + + if (tiff_nifds >= sizeof tiff_ifd / sizeof tiff_ifd[0]) + return 1; + ifd = tiff_nifds++; + for (j=0; j < 4; j++) + for (i=0; i < 4; i++) + cc[j][i] = i == j; + entries = get2(); + if (entries > 512) return 1; + while (entries--) { + tiff_get (base, &tag, &type, &len, &save); + switch (tag) { + case 17: case 18: + if (type == 3 && len == 1) + cam_mul[(tag-17)*2] = get2() / 256.0; + break; + case 23: + if (type == 3) iso_speed = get2(); + break; + case 36: case 37: case 38: + cam_mul[tag-0x24] = get2(); + break; + case 39: + if (len < 50 || cam_mul[0]) break; + fseek (ifp, 12, SEEK_CUR); + FORC3 cam_mul[c] = get2(); + break; + case 46: + if (type != 7 || fgetc(ifp) != 0xff || fgetc(ifp) != 0xd8) break; + thumb_offset = ftell(ifp) - 2; + thumb_length = len; + break; + case 2: case 256: /* ImageWidth */ + tiff_ifd[ifd].width = getint(type); + break; + case 3: case 257: /* ImageHeight */ + tiff_ifd[ifd].height = getint(type); + break; + case 258: /* BitsPerSample */ + tiff_ifd[ifd].samples = len & 7; + tiff_ifd[ifd].bps = get2(); + break; + case 259: /* Compression */ + tiff_ifd[ifd].comp = get2(); + break; + case 262: /* PhotometricInterpretation */ + tiff_ifd[ifd].phint = get2(); + break; + case 270: /* ImageDescription */ + fread (desc, 512, 1, ifp); + break; + case 271: /* Make */ + fgets (make, 64, ifp); + break; + case 272: /* Model */ + fgets (model, 64, ifp); + break; + case 280: /* Panasonic RW2 offset */ + if (type != 4) break; + load_raw = &CLASS panasonic_load_raw; + load_flags = 0x2008; + case 273: /* StripOffset */ + case 513: + tiff_ifd[ifd].offset = get4()+base; + if (!tiff_ifd[ifd].bps) { + fseek (ifp, tiff_ifd[ifd].offset, SEEK_SET); + if (ljpeg_start (&jh, 1)) { + tiff_ifd[ifd].comp = 6; + tiff_ifd[ifd].width = jh.wide << (jh.clrs == 2); + tiff_ifd[ifd].height = jh.high; + tiff_ifd[ifd].bps = jh.bits; + tiff_ifd[ifd].samples = jh.clrs; + } + } + break; + case 274: /* Orientation */ + tiff_ifd[ifd].flip = "50132467"[get2() & 7]-'0'; + break; + case 277: /* SamplesPerPixel */ + tiff_ifd[ifd].samples = getint(type) & 7; + break; + case 279: /* StripByteCounts */ + case 514: + tiff_ifd[ifd].bytes = get4(); + break; + case 305: case 11: /* Software */ + fgets (software, 64, ifp); + if (!strncmp(software,"Adobe",5) || + !strncmp(software,"dcraw",5) || + !strncmp(software,"UFRaw",5) || + !strncmp(software,"Bibble",6) || + !strncmp(software,"Nikon Scan",10) || + !strcmp (software,"Digital Photo Professional")) + is_raw = 0; + break; + case 306: /* DateTime */ + get_timestamp(0); + break; + case 315: /* Artist */ + fread (artist, 64, 1, ifp); + break; + case 322: /* TileWidth */ + tile_width = getint(type); + break; + case 323: /* TileLength */ + tile_length = getint(type); + break; + case 324: /* TileOffsets */ + tiff_ifd[ifd].offset = len > 1 ? ftell(ifp) : get4(); + if (len == 4) { + load_raw = &CLASS sinar_4shot_load_raw; + is_raw = 5; + } + break; + case 330: /* SubIFDs */ + if (!strcmp(model,"DSLR-A100") && tiff_ifd[ifd].width == 3872) { + load_raw = &CLASS sony_arw_load_raw; + data_offset = get4()+base; + ifd++; break; + } + while (len--) { + i = ftell(ifp); + fseek (ifp, get4()+base, SEEK_SET); + if (parse_tiff_ifd (base)) break; + fseek (ifp, i+4, SEEK_SET); + } + break; + case 400: + strcpy (make, "Sarnoff"); + maximum = 0xfff; + break; + case 28688: + FORC4 sony_curve[c+1] = get2() >> 2 & 0xfff; + for (i=0; i < 5; i++) + for (j = sony_curve[i]+1; j <= sony_curve[i+1]; j++) + curve[j] = curve[j-1] + (1 << i); + break; + case 29184: sony_offset = get4(); break; + case 29185: sony_length = get4(); break; + case 29217: sony_key = get4(); break; + case 29264: + parse_minolta (ftell(ifp)); + raw_width = 0; + break; + case 29443: + FORC4 cam_mul[c ^ (c < 2)] = get2(); + break; + case 29459: + FORC4 cam_mul[c ^ (c >> 1)] = get2(); + break; + case 33405: /* Model2 */ + fgets (model2, 64, ifp); + break; + case 33422: /* CFAPattern */ + case 64777: /* Kodak P-series */ + if ((plen=len) > 16) plen = 16; + fread (cfa_pat, 1, plen, ifp); + for (colors=cfa=i=0; i < plen; i++) { + colors += !(cfa & (1 << cfa_pat[i])); + cfa |= 1 << cfa_pat[i]; + } + if (cfa == 070) memcpy (cfa_pc,"\003\004\005",3); /* CMY */ + if (cfa == 072) memcpy (cfa_pc,"\005\003\004\001",4); /* GMCY */ + goto guess_cfa_pc; + case 33424: + case 65024: + fseek (ifp, get4()+base, SEEK_SET); + parse_kodak_ifd (base); + break; + case 33434: /* ExposureTime */ + shutter = getreal(type); + break; + case 33437: /* FNumber */ + aperture = getreal(type); + break; + case 34306: /* Leaf white balance */ + FORC4 cam_mul[c ^ 1] = 4096.0 / get2(); + break; + case 34307: /* Leaf CatchLight color matrix */ + fread (software, 1, 7, ifp); + if (strncmp(software,"MATRIX",6)) break; + colors = 4; + for (raw_color = i=0; i < 3; i++) { + FORC4 fscanf (ifp, "%f", &rgb_cam[i][c^1]); + if (!use_camera_wb) continue; + num = 0; + FORC4 num += rgb_cam[i][c]; + FORC4 rgb_cam[i][c] /= num; + } + break; + case 34310: /* Leaf metadata */ + parse_mos (ftell(ifp)); + case 34303: + strcpy (make, "Leaf"); + break; + case 34665: /* EXIF tag */ + fseek (ifp, get4()+base, SEEK_SET); + parse_exif (base); + break; + case 34853: /* GPSInfo tag */ + fseek (ifp, get4()+base, SEEK_SET); + parse_gps (base); + break; + case 34675: /* InterColorProfile */ + case 50831: /* AsShotICCProfile */ + profile_offset = ftell(ifp); + profile_length = len; + break; + case 37122: /* CompressedBitsPerPixel */ + kodak_cbpp = get4(); + break; + case 37386: /* FocalLength */ + focal_len = getreal(type); + break; + case 37393: /* ImageNumber */ + shot_order = getint(type); + break; + case 37400: /* old Kodak KDC tag */ + for (raw_color = i=0; i < 3; i++) { + getreal(type); + FORC3 rgb_cam[i][c] = getreal(type); + } + break; + case 46275: /* Imacon tags */ + strcpy (make, "Imacon"); + data_offset = ftell(ifp); + ima_len = len; + break; + case 46279: + if (!ima_len) break; + fseek (ifp, 78, SEEK_CUR); + raw_width = get4(); + raw_height = get4(); + left_margin = get4() & 7; + width = raw_width - left_margin - (get4() & 7); + top_margin = get4() & 7; + height = raw_height - top_margin - (get4() & 7); + if (raw_width == 7262) { + height = 5444; + width = 7244; + left_margin = 7; + } + fseek (ifp, 52, SEEK_CUR); + FORC3 cam_mul[c] = getreal(11); + fseek (ifp, 114, SEEK_CUR); + flip = (get2() >> 7) * 90; + if (width * height * 6 == ima_len) { + if (flip % 180 == 90) SWAP(width,height); + filters = flip = 0; + } + sprintf (model, "Ixpress %d-Mp", height*width/1000000); + load_raw = &CLASS imacon_full_load_raw; + if (filters) { + if (left_margin & 1) filters = 0x61616161; + load_raw = &CLASS unpacked_load_raw; + } + maximum = 0xffff; + break; + case 50454: /* Sinar tag */ + case 50455: + if (!(cbuf = (char *) malloc(len))) break; + fread (cbuf, 1, len, ifp); + for (cp = cbuf-1; cp && cp < cbuf+len; cp = strchr(cp,'\n')) + if (!strncmp (++cp,"Neutral ",8)) + sscanf (cp+8, "%f %f %f", cam_mul, cam_mul+1, cam_mul+2); + free (cbuf); + break; + case 50458: + if (!make[0]) strcpy (make, "Hasselblad"); + break; + case 50459: /* Hasselblad tag */ + i = order; + j = ftell(ifp); + c = tiff_nifds; + order = get2(); + fseek (ifp, j+(get2(),get4()), SEEK_SET); + parse_tiff_ifd (j); + maximum = 0xffff; + tiff_nifds = c; + order = i; + break; + case 50706: /* DNGVersion */ + FORC4 dng_version = (dng_version << 8) + fgetc(ifp); + if (!make[0]) strcpy (make, "DNG"); + is_raw = 1; + break; + case 50710: /* CFAPlaneColor */ + if (len > 4) len = 4; + colors = len; + fread (cfa_pc, 1, colors, ifp); +guess_cfa_pc: + FORCC tab[cfa_pc[c]] = c; + cdesc[c] = 0; + for (i=16; i--; ) + filters = filters << 2 | tab[cfa_pat[i % plen]]; + break; + case 50711: /* CFALayout */ + if (get2() == 2) { + fuji_width = 1; + filters = 0x49494949; + } + break; + case 291: + case 50712: /* LinearizationTable */ + linear_table (len); + break; + case 50714: /* BlackLevel */ + case 50715: /* BlackLevelDeltaH */ + case 50716: /* BlackLevelDeltaV */ + for (dblack=i=0; i < len; i++) + dblack += getreal(type); + black += dblack/len + 0.5; + break; + case 50717: /* WhiteLevel */ + maximum = getint(type); + break; + case 50718: /* DefaultScale */ + pixel_aspect = getreal(type); + pixel_aspect /= getreal(type); + break; + case 50721: /* ColorMatrix1 */ + case 50722: /* ColorMatrix2 */ + FORCC for (j=0; j < 3; j++) + cm[c][j] = getreal(type); + use_cm = 1; + break; + case 50723: /* CameraCalibration1 */ + case 50724: /* CameraCalibration2 */ + for (i=0; i < colors; i++) + FORCC cc[i][c] = getreal(type); + break; + case 50727: /* AnalogBalance */ + FORCC ab[c] = getreal(type); + break; + case 50728: /* AsShotNeutral */ + FORCC asn[c] = getreal(type); + break; + case 50729: /* AsShotWhiteXY */ + xyz[0] = getreal(type); + xyz[1] = getreal(type); + xyz[2] = 1 - xyz[0] - xyz[1]; + FORC3 xyz[c] /= d65_white[c]; + break; + case 50740: /* DNGPrivateData */ + if (dng_version) break; + parse_minolta (j = get4()+base); + fseek (ifp, j, SEEK_SET); + parse_tiff_ifd (base); + break; + case 50752: + read_shorts (cr2_slice, 3); + break; + case 50829: /* ActiveArea */ + top_margin = getint(type); + left_margin = getint(type); + height = getint(type) - top_margin; + width = getint(type) - left_margin; + break; + case 64772: /* Kodak P-series */ + if (len < 13) break; + fseek (ifp, 16, SEEK_CUR); + data_offset = get4(); + fseek (ifp, 28, SEEK_CUR); + data_offset += get4(); + load_raw = &CLASS packed_load_raw; + break; + case 65026: + if (type == 2) fgets (model2, 64, ifp); + } + fseek (ifp, save, SEEK_SET); + } + if (sony_length && (buf = (unsigned *) malloc(sony_length))) { + fseek (ifp, sony_offset, SEEK_SET); + fread (buf, sony_length, 1, ifp); + sony_decrypt (buf, sony_length/4, 1, sony_key); + sfp = ifp; +/*RT*/ ifp = fopen (buf, sony_length); +// if ((ifp = tmpfile())) { +// fwrite (buf, sony_length, 1, ifp); +// fseek (ifp, 0, SEEK_SET); + parse_tiff_ifd (-sony_offset); +// fclose (ifp); +// } + ifp = sfp; + free (buf); + } + for (i=0; i < colors; i++) + FORCC cc[i][c] *= ab[i]; + if (use_cm) { + FORCC for (i=0; i < 3; i++) + for (cam_xyz[c][i]=j=0; j < colors; j++) + cam_xyz[c][i] += cc[c][j] * cm[j][i] * xyz[i]; + cam_xyz_coeff (cam_xyz); + } + if (asn[0]) { + cam_mul[3] = 0; + FORCC cam_mul[c] = 1 / asn[c]; + } + if (!use_cm) + FORCC pre_mul[c] /= cc[c][c]; + return 0; +} + +void CLASS parse_tiff (int base) +{ + int doff, max_samp=0, raw=-1, thm=-1, i; + struct jhead jh; + + /*RT*/ exif_base = base; + + fseek (ifp, base, SEEK_SET); + order = get2(); + if (order != 0x4949 && order != 0x4d4d) return; + get2(); + memset (tiff_ifd, 0, sizeof tiff_ifd); + tiff_nifds = 0; + while ((doff = get4())) { + fseek (ifp, doff+base, SEEK_SET); + if (parse_tiff_ifd (base)) break; + } + thumb_misc = 16; + if (thumb_offset) { + fseek (ifp, thumb_offset, SEEK_SET); + if (ljpeg_start (&jh, 1)) { + thumb_misc = jh.bits; + thumb_width = jh.wide; + thumb_height = jh.high; + } + } + for (i=0; i < tiff_nifds; i++) { + if (max_samp < tiff_ifd[i].samples) + max_samp = tiff_ifd[i].samples; + if (max_samp > 3) max_samp = 3; + if ((tiff_ifd[i].comp != 6 || tiff_ifd[i].samples != 3) && + (tiff_ifd[i].width | tiff_ifd[i].height) < 0x10000 && + tiff_ifd[i].width*tiff_ifd[i].height > raw_width*raw_height) { + raw_width = tiff_ifd[i].width; + raw_height = tiff_ifd[i].height; + tiff_bps = tiff_ifd[i].bps; + tiff_compress = tiff_ifd[i].comp; + data_offset = tiff_ifd[i].offset; + tiff_flip = tiff_ifd[i].flip; + tiff_samples = tiff_ifd[i].samples; + raw = i; + } + } + fuji_width *= (raw_width+1)/2; + if (tiff_ifd[0].flip) tiff_flip = tiff_ifd[0].flip; + if (raw >= 0 && !load_raw) + switch (tiff_compress) { + case 0: case 1: + switch (tiff_bps) { + case 8: load_raw = &CLASS eight_bit_load_raw; break; + case 12: load_raw = &CLASS packed_load_raw; + if (tiff_ifd[raw].phint == 2) + load_flags = 6; + if (strncmp(make,"PENTAX",6)) break; + case 14: + case 16: load_raw = &CLASS unpacked_load_raw; break; + } + if (tiff_ifd[raw].bytes*5 == raw_width*raw_height*8) { + tiff_bps = 12; + maximum = 0xffff; + load_raw = &CLASS packed_load_raw; + load_flags = 273; + } + break; + case 6: case 7: case 99: + load_raw = &CLASS lossless_jpeg_load_raw; break; + case 262: + load_raw = &CLASS kodak_262_load_raw; break; + case 32767: + if (tiff_ifd[raw].bytes == raw_width*raw_height) { + tiff_bps = 12; + load_raw = &CLASS sony_arw2_load_raw; break; + } + if (tiff_ifd[raw].bytes*8 != raw_width*raw_height*tiff_bps) { + raw_height += 8; + load_raw = &CLASS sony_arw_load_raw; break; + } + load_flags = 79; + case 32769: + load_flags++; + case 32773: + load_raw = &CLASS packed_load_raw; break; + case 34713: + load_raw = &CLASS nikon_compressed_load_raw; break; + case 65535: + load_raw = &CLASS pentax_load_raw; break; + case 65000: + switch (tiff_ifd[raw].phint) { + case 2: load_raw = &CLASS kodak_rgb_load_raw; filters = 0; break; + case 6: load_raw = &CLASS kodak_ycbcr_load_raw; filters = 0; break; + case 32803: load_raw = &CLASS kodak_65000_load_raw; + } + case 32867: break; + default: is_raw = 0; + } + if (!dng_version) + if ( (tiff_samples == 3 && tiff_ifd[raw].bytes && + tiff_bps != 14 && tiff_bps != 2048) + || (tiff_bps == 8 && !strstr(make,"KODAK") && !strstr(make,"Kodak") && + !strstr(model2,"DEBUG RAW"))) + is_raw = 0; + for (i=0; i < tiff_nifds; i++) + if (i != raw && tiff_ifd[i].samples == max_samp && + tiff_ifd[i].width * tiff_ifd[i].height / SQR(tiff_ifd[i].bps+1) > + thumb_width * thumb_height / SQR(thumb_misc+1)) { + thumb_width = tiff_ifd[i].width; + thumb_height = tiff_ifd[i].height; + thumb_offset = tiff_ifd[i].offset; + thumb_length = tiff_ifd[i].bytes; + thumb_misc = tiff_ifd[i].bps; + thm = i; + } + if (thm >= 0) { + thumb_misc |= tiff_ifd[thm].samples << 5; + switch (tiff_ifd[thm].comp) { + case 0: + write_thumb = &CLASS layer_thumb; + break; + case 1: + if (tiff_ifd[thm].bps > 8) + thumb_load_raw = &CLASS kodak_thumb_load_raw; + else + write_thumb = &CLASS ppm_thumb; + break; + case 65000: + thumb_load_raw = tiff_ifd[thm].phint == 6 ? + &CLASS kodak_ycbcr_load_raw : &CLASS kodak_rgb_load_raw; + } + } +} + +void CLASS parse_minolta (int base) +{ + int save, tag, len, offset, high=0, wide=0, i, c; + short sorder=order; + + fseek (ifp, base, SEEK_SET); + if (fgetc(ifp) || fgetc(ifp)-'M' || fgetc(ifp)-'R') return; + order = fgetc(ifp) * 0x101; + offset = base + get4() + 8; + while ((save=ftell(ifp)) < offset) { + for (tag=i=0; i < 4; i++) + tag = tag << 8 | fgetc(ifp); + len = get4(); + switch (tag) { + case 0x505244: /* PRD */ + fseek (ifp, 8, SEEK_CUR); + high = get2(); + wide = get2(); + break; + case 0x574247: /* WBG */ + get4(); + i = strcmp(model,"DiMAGE A200") ? 0:3; + FORC4 cam_mul[c ^ (c >> 1) ^ i] = get2(); + break; + case 0x545457: /* TTW */ + parse_tiff (ftell(ifp)); + data_offset = offset; + } + fseek (ifp, save+len+8, SEEK_SET); + } + raw_height = high; + raw_width = wide; + order = sorder; +} + +/* + Many cameras have a "debug mode" that writes JPEG and raw + at the same time. The raw file has no header, so try to + to open the matching JPEG file and read its metadata. + */ +void CLASS parse_external_jpeg() +{ + const char *file, *ext; + char *jname, *jfile, *jext; +/*RT*/ IMFILE *save=ifp; + + ext = strrchr (ifname, '.'); + file = strrchr (ifname, '/'); + if (!file) file = strrchr (ifname, '\\'); + if (!file) file = ifname-1; + file++; + if (!ext || strlen(ext) != 4 || ext-file != 8) return; + jname = (char *) malloc (strlen(ifname) + 1); + merror (jname, "parse_external_jpeg()"); + strcpy (jname, ifname); + jfile = file - ifname + jname; + jext = ext - ifname + jname; + if (strcasecmp (ext, ".jpg")) { + strcpy (jext, isupper(ext[1]) ? ".JPG":".jpg"); + if (isdigit(*file)) { + memcpy (jfile, file+4, 4); + memcpy (jfile+4, file, 4); + } + } else + while (isdigit(*--jext)) { + if (*jext != '9') { + (*jext)++; + break; + } + *jext = '0'; + } + if (strcmp (jname, ifname)) { +/*RT*/ if ((ifp = fopen (jname))) { +// if ((ifp = fopen (jname, "rb"))) { + if (verbose) + fprintf (stderr,_("Reading metadata from %s ...\n"), jname); + parse_tiff (12); + thumb_offset = 0; + is_raw = 1; + fclose (ifp); + } + } + if (!timestamp) + fprintf (stderr,_("Failed to read metadata from %s\n"), jname); + free (jname); + ifp = save; +} + +/* + CIFF block 0x1030 contains an 8x8 white sample. + Load this into white[][] for use in scale_colors(). + */ +void CLASS ciff_block_1030() +{ + static const ushort key[] = { 0x410, 0x45f3 }; + int i, bpp, row, col, vbits=0; + unsigned long bitbuf=0; + + if ((get2(),get4()) != 0x80008 || !get4()) return; + bpp = get2(); + if (bpp != 10 && bpp != 12) return; + for (i=row=0; row < 8; row++) + for (col=0; col < 8; col++) { + if (vbits < bpp) { + bitbuf = bitbuf << 16 | (get2() ^ key[i++ & 1]); + vbits += 16; + } + white[row][col] = + bitbuf << (LONG_BIT - vbits) >> (LONG_BIT - bpp); + vbits -= bpp; + } +} + +/* + Parse a CIFF file, better known as Canon CRW format. + */ +void CLASS parse_ciff (int offset, int length) +{ + int tboff, nrecs, c, type, len, save, wbi=-1; + ushort key[] = { 0x410, 0x45f3 }; + + fseek (ifp, offset+length-4, SEEK_SET); + tboff = get4() + offset; + fseek (ifp, tboff, SEEK_SET); + nrecs = get2(); + if (nrecs > 100) return; + while (nrecs--) { + type = get2(); + len = get4(); + save = ftell(ifp) + 4; + fseek (ifp, offset+get4(), SEEK_SET); + if ((((type >> 8) + 8) | 8) == 0x38) + parse_ciff (ftell(ifp), len); /* Parse a sub-table */ + + if (type == 0x0810) + fread (artist, 64, 1, ifp); + if (type == 0x080a) { + fread (make, 64, 1, ifp); + fseek (ifp, strlen(make) - 63, SEEK_CUR); + fread (model, 64, 1, ifp); + } + if (type == 0x1810) { + fseek (ifp, 12, SEEK_CUR); + flip = get4(); + } + if (type == 0x1835) /* Get the decoder table */ + tiff_compress = get4(); + if (type == 0x2007) { + thumb_offset = ftell(ifp); + thumb_length = len; + } + if (type == 0x1818) { + shutter = pow (2, -int_to_float((get4(),get4()))); + aperture = pow (2, int_to_float(get4())/2); + } + if (type == 0x102a) { + iso_speed = pow (2, (get4(),get2())/32.0 - 4) * 50; + aperture = pow (2, (get2(),(short)get2())/64.0); + shutter = pow (2,-((short)get2())/32.0); + wbi = (get2(),get2()); + if (wbi > 17) wbi = 0; + fseek (ifp, 32, SEEK_CUR); + if (shutter > 1e6) shutter = get2()/10.0; + } + if (type == 0x102c) { + if (get2() > 512) { /* Pro90, G1 */ + fseek (ifp, 118, SEEK_CUR); + FORC4 cam_mul[c ^ 2] = get2(); + } else { /* G2, S30, S40 */ + fseek (ifp, 98, SEEK_CUR); + FORC4 cam_mul[c ^ (c >> 1) ^ 1] = get2(); + } + } + if (type == 0x0032) { + if (len == 768) { /* EOS D30 */ + fseek (ifp, 72, SEEK_CUR); + FORC4 cam_mul[c ^ (c >> 1)] = 1024.0 / get2(); + if (!wbi) cam_mul[0] = -1; /* use my auto white balance */ + } else if (!cam_mul[0]) { + if (get2() == key[0]) /* Pro1, G6, S60, S70 */ + c = (strstr(model,"Pro1") ? + "012346000000000000":"01345:000000006008")[wbi]-'0'+ 2; + else { /* G3, G5, S45, S50 */ + c = "023457000000006000"[wbi]-'0'; + key[0] = key[1] = 0; + } + fseek (ifp, 78 + c*8, SEEK_CUR); + FORC4 cam_mul[c ^ (c >> 1) ^ 1] = get2() ^ key[c & 1]; + if (!wbi) cam_mul[0] = -1; + } + } + if (type == 0x10a9) { /* D60, 10D, 300D, and clones */ + if (len > 66) wbi = "0134567028"[wbi]-'0'; + fseek (ifp, 2 + wbi*8, SEEK_CUR); + FORC4 cam_mul[c ^ (c >> 1)] = get2(); + } + if (type == 0x1030 && (0x18040 >> wbi & 1)) + ciff_block_1030(); /* all that don't have 0x10a9 */ + if (type == 0x1031) { + raw_width = (get2(),get2()); + raw_height = get2(); + } + if (type == 0x5029) { + focal_len = len >> 16; + if ((len & 0xffff) == 2) focal_len /= 32; + } + if (type == 0x5813) flash_used = int_to_float(len); + if (type == 0x5814) canon_ev = int_to_float(len); + if (type == 0x5817) shot_order = len; + if (type == 0x5834) unique_id = len; + if (type == 0x580e) timestamp = len; + if (type == 0x180e) timestamp = get4(); +#ifdef LOCALTIME + if ((type | 0x4000) == 0x580e) + timestamp = mktime (gmtime (×tamp)); +#endif + fseek (ifp, save, SEEK_SET); + } +} + +void CLASS parse_rollei() +{ + char line[128], *val; + struct tm t; + + fseek (ifp, 0, SEEK_SET); + memset (&t, 0, sizeof t); + do { + fgets (line, 128, ifp); + if ((val = strchr(line,'='))) + *val++ = 0; + else + val = line + strlen(line); + if (!strcmp(line,"DAT")) + sscanf (val, "%d.%d.%d", &t.tm_mday, &t.tm_mon, &t.tm_year); + if (!strcmp(line,"TIM")) + sscanf (val, "%d:%d:%d", &t.tm_hour, &t.tm_min, &t.tm_sec); + if (!strcmp(line,"HDR")) + thumb_offset = atoi(val); + if (!strcmp(line,"X ")) + raw_width = atoi(val); + if (!strcmp(line,"Y ")) + raw_height = atoi(val); + if (!strcmp(line,"TX ")) + thumb_width = atoi(val); + if (!strcmp(line,"TY ")) + thumb_height = atoi(val); + } while (strncmp(line,"EOHD",4)); + data_offset = thumb_offset + thumb_width * thumb_height * 2; + t.tm_year -= 1900; + t.tm_mon -= 1; + if (mktime(&t) > 0) + timestamp = mktime(&t); + strcpy (make, "Rollei"); + strcpy (model,"d530flex"); + write_thumb = &CLASS rollei_thumb; +} + +void CLASS parse_sinar_ia() +{ + int entries, off; + char str[8], *cp; + + order = 0x4949; + fseek (ifp, 4, SEEK_SET); + entries = get4(); + fseek (ifp, get4(), SEEK_SET); + while (entries--) { + off = get4(); get4(); + fread (str, 8, 1, ifp); + if (!strcmp(str,"META")) meta_offset = off; + if (!strcmp(str,"THUMB")) thumb_offset = off; + if (!strcmp(str,"RAW0")) data_offset = off; + } + fseek (ifp, meta_offset+20, SEEK_SET); + fread (make, 64, 1, ifp); + make[63] = 0; + if ((cp = strchr(make,' '))) { + strcpy (model, cp+1); + *cp = 0; + } + raw_width = get2(); + raw_height = get2(); + load_raw = &CLASS unpacked_load_raw; + thumb_width = (get4(),get2()); + thumb_height = get2(); + write_thumb = &CLASS ppm_thumb; + maximum = 0x3fff; +} + +void CLASS parse_phase_one (int base) +{ + unsigned entries, tag, type, len, data, save, i, c; + float romm_cam[3][3]; + char *cp; + + memset (&ph1, 0, sizeof ph1); + fseek (ifp, base, SEEK_SET); + order = get4() & 0xffff; + if (get4() >> 8 != 0x526177) return; /* "Raw" */ + fseek (ifp, get4()+base, SEEK_SET); + entries = get4(); + get4(); + while (entries--) { + tag = get4(); + type = get4(); + len = get4(); + data = get4(); + save = ftell(ifp); + fseek (ifp, base+data, SEEK_SET); + switch (tag) { + case 0x100: flip = "0653"[data & 3]-'0'; break; + case 0x106: + for (i=0; i < 9; i++) + romm_cam[0][i] = getreal(11); + romm_coeff (romm_cam); + break; + case 0x107: + FORC3 cam_mul[c] = getreal(11); + break; + case 0x108: raw_width = data; break; + case 0x109: raw_height = data; break; + case 0x10a: left_margin = data; break; + case 0x10b: top_margin = data; break; + case 0x10c: width = data; break; + case 0x10d: height = data; break; + case 0x10e: ph1.format = data; break; + case 0x10f: data_offset = data+base; break; + case 0x110: meta_offset = data+base; + meta_length = len; break; + case 0x112: ph1.key_off = save - 4; break; + case 0x210: ph1.tag_210 = int_to_float(data); break; + case 0x21a: ph1.tag_21a = data; break; + case 0x21c: strip_offset = data+base; break; + case 0x21d: ph1.black = data; break; + case 0x222: ph1.split_col = data - left_margin; break; + case 0x223: ph1.black_off = data+base; break; + case 0x301: + model[63] = 0; + fread (model, 1, 63, ifp); + if ((cp = strstr(model," camera"))) *cp = 0; + } + fseek (ifp, save, SEEK_SET); + } + load_raw = ph1.format < 3 ? + &CLASS phase_one_load_raw : &CLASS phase_one_load_raw_c; + maximum = 0xffff; + strcpy (make, "Phase One"); + if (model[0]) return; + switch (raw_height) { + case 2060: strcpy (model,"LightPhase"); break; + case 2682: strcpy (model,"H 10"); break; + case 4128: strcpy (model,"H 20"); break; + case 5488: strcpy (model,"H 25"); break; + } +} + +void CLASS parse_fuji (int offset) +{ + unsigned entries, tag, len, save, c; + + fseek (ifp, offset, SEEK_SET); + entries = get4(); + if (entries > 255) return; + while (entries--) { + tag = get2(); + len = get2(); + save = ftell(ifp); + if (tag == 0x100) { + raw_height = get2(); + raw_width = get2(); + } else if (tag == 0x121) { + height = get2(); + if ((width = get2()) == 4284) width += 3; + } else if (tag == 0x130) { + fuji_layout = fgetc(ifp) >> 7; + load_raw = fgetc(ifp) & 8 ? + &CLASS unpacked_load_raw : &CLASS fuji_load_raw; + } + if (tag == 0x2ff0) + FORC4 cam_mul[c ^ 1] = get2(); + fseek (ifp, save+len, SEEK_SET); + } + height <<= fuji_layout; + width >>= fuji_layout; +} + +int CLASS parse_jpeg (int offset) +{ + int len, save, hlen, mark; + + fseek (ifp, offset, SEEK_SET); + if (fgetc(ifp) != 0xff || fgetc(ifp) != 0xd8) return 0; + + while (fgetc(ifp) == 0xff && (mark = fgetc(ifp)) != 0xda) { + order = 0x4d4d; + len = get2() - 2; + save = ftell(ifp); + if (mark == 0xc0 || mark == 0xc3) { + fgetc(ifp); + raw_height = get2(); + raw_width = get2(); + } + order = get2(); + hlen = get4(); + if (get4() == 0x48454150) /* "HEAP" */ +/*RT*/ { +/*RT*/ ciff_base = save+hlen; +/*RT*/ ciff_len = len-hlen; + parse_ciff (save+hlen, len-hlen); +/*RT*/ } + parse_tiff (save+6); + fseek (ifp, save+len, SEEK_SET); + } + return 1; +} + +void CLASS parse_riff() +{ + unsigned i, size, end; + char tag[4], date[64], month[64]; + static const char mon[12][4] = + { "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" }; + struct tm t; + + order = 0x4949; + fread (tag, 4, 1, ifp); + size = get4(); + end = ftell(ifp) + size; + if (!memcmp(tag,"RIFF",4) || !memcmp(tag,"LIST",4)) { + get4(); + while (ftell(ifp)+7 < end) + parse_riff(); + } else if (!memcmp(tag,"nctg",4)) { + while (ftell(ifp)+7 < end) { + i = get2(); + size = get2(); + if ((i+1) >> 1 == 10 && size == 20) + get_timestamp(0); + else fseek (ifp, size, SEEK_CUR); + } + } else if (!memcmp(tag,"IDIT",4) && size < 64) { + fread (date, 64, 1, ifp); + date[size] = 0; + memset (&t, 0, sizeof t); + if (sscanf (date, "%*s %s %d %d:%d:%d %d", month, &t.tm_mday, + &t.tm_hour, &t.tm_min, &t.tm_sec, &t.tm_year) == 6) { + for (i=0; i < 12 && strcasecmp(mon[i],month); i++); + t.tm_mon = i; + t.tm_year -= 1900; + if (mktime(&t) > 0) + timestamp = mktime(&t); + } + } else + fseek (ifp, size, SEEK_CUR); +} + +void CLASS parse_smal (int offset, int fsize) +{ + int ver; + + fseek (ifp, offset+2, SEEK_SET); + order = 0x4949; + ver = fgetc(ifp); + if (ver == 6) + fseek (ifp, 5, SEEK_CUR); + if (get4() != fsize) return; + if (ver > 6) data_offset = get4(); + raw_height = height = get2(); + raw_width = width = get2(); + strcpy (make, "SMaL"); + sprintf (model, "v%d %dx%d", ver, width, height); + if (ver == 6) load_raw = &CLASS smal_v6_load_raw; + if (ver == 9) load_raw = &CLASS smal_v9_load_raw; +} + +void CLASS parse_cine() +{ + unsigned off_head, off_setup, off_image, i; + + order = 0x4949; + fseek (ifp, 4, SEEK_SET); + is_raw = get2() == 2; + fseek (ifp, 14, SEEK_CUR); + is_raw *= get4(); + off_head = get4(); + off_setup = get4(); + off_image = get4(); + timestamp = get4(); + if ((i = get4())) timestamp = i; + fseek (ifp, off_head+4, SEEK_SET); + raw_width = get4(); + raw_height = get4(); + switch (get2(),get2()) { + case 8: load_raw = &CLASS eight_bit_load_raw; break; + case 16: load_raw = &CLASS unpacked_load_raw; + } + fseek (ifp, off_setup+792, SEEK_SET); + strcpy (make, "CINE"); + sprintf (model, "%d", get4()); + fseek (ifp, 12, SEEK_CUR); + switch ((i=get4()) & 0xffffff) { + case 3: filters = 0x94949494; break; + case 4: filters = 0x49494949; break; + default: is_raw = 0; + } + fseek (ifp, 72, SEEK_CUR); + switch ((get4()+3600) % 360) { + case 270: flip = 4; break; + case 180: flip = 1; break; + case 90: flip = 7; break; + case 0: flip = 2; + } + cam_mul[0] = getreal(11); + cam_mul[2] = getreal(11); + maximum = ~(-1 << get4()); + fseek (ifp, 668, SEEK_CUR); + shutter = get4()/1000000000.0; + fseek (ifp, off_image, SEEK_SET); + if (shot_select < is_raw) + fseek (ifp, shot_select*8, SEEK_CUR); + data_offset = (INT64) get4() + 8; + data_offset += (INT64) get4() << 32; +} + +char * CLASS foveon_gets (int offset, char *str, int len) +{ + int i; + fseek (ifp, offset, SEEK_SET); + for (i=0; i < len-1; i++) + if ((str[i] = get2()) == 0) break; + str[i] = 0; + return str; +} + +void CLASS parse_foveon() +{ + int entries, img=0, off, len, tag, save, i, wide, high, pent, poff[256][2]; + char name[64], value[64]; + + order = 0x4949; /* Little-endian */ + fseek (ifp, 36, SEEK_SET); + flip = get4(); + fseek (ifp, -4, SEEK_END); + fseek (ifp, get4(), SEEK_SET); + if (get4() != 0x64434553) return; /* SECd */ + entries = (get4(),get4()); + while (entries--) { + off = get4(); + len = get4(); + tag = get4(); + save = ftell(ifp); + fseek (ifp, off, SEEK_SET); + if (get4() != (0x20434553 | (tag << 24))) return; + switch (tag) { + case 0x47414d49: /* IMAG */ + case 0x32414d49: /* IMA2 */ + fseek (ifp, 12, SEEK_CUR); + wide = get4(); + high = get4(); + if (wide > raw_width && high > raw_height) { + raw_width = wide; + raw_height = high; + data_offset = off+24; + } + fseek (ifp, off+28, SEEK_SET); + if (fgetc(ifp) == 0xff && fgetc(ifp) == 0xd8 + && thumb_length < len-28) { + thumb_offset = off+28; + thumb_length = len-28; + write_thumb = &CLASS jpeg_thumb; + } + if (++img == 2 && !thumb_length) { + thumb_offset = off+24; + thumb_width = wide; + thumb_height = high; + write_thumb = &CLASS foveon_thumb; + } + break; + case 0x464d4143: /* CAMF */ + meta_offset = off+24; + meta_length = len-28; + if (meta_length > 0x20000) + meta_length = 0x20000; + break; + case 0x504f5250: /* PROP */ + pent = (get4(),get4()); + fseek (ifp, 12, SEEK_CUR); + off += pent*8 + 24; + if ((unsigned) pent > 256) pent=256; + for (i=0; i < pent*2; i++) + poff[0][i] = off + get4()*2; + for (i=0; i < pent; i++) { + foveon_gets (poff[i][0], name, 64); + foveon_gets (poff[i][1], value, 64); + if (!strcmp (name, "ISO")) + iso_speed = atoi(value); + if (!strcmp (name, "CAMMANUF")) + strcpy (make, value); + if (!strcmp (name, "CAMMODEL")) + strcpy (model, value); + if (!strcmp (name, "WB_DESC")) + strcpy (model2, value); + if (!strcmp (name, "TIME")) + timestamp = atoi(value); + if (!strcmp (name, "EXPTIME")) + shutter = atoi(value) / 1000000.0; + if (!strcmp (name, "APERTURE")) + aperture = atof(value); + if (!strcmp (name, "FLENGTH")) + focal_len = atof(value); + } +#ifdef LOCALTIME + timestamp = mktime (gmtime (×tamp)); +#endif + } + fseek (ifp, save, SEEK_SET); + } + is_foveon = 1; +} + +/* + All matrices are from Adobe DNG Converter unless otherwise noted. + */ +void CLASS adobe_coeff (const char *make, const char *model) +{ + static const struct { + const char *prefix; + short black, maximum, trans[12]; + } table[] = { + { "AGFAPHOTO DC-833m", 0, 0, /* DJC */ + { 11438,-3762,-1115,-2409,9914,2497,-1227,2295,5300 } }, + { "Apple QuickTake", 0, 0, /* DJC */ + { 21392,-5653,-3353,2406,8010,-415,7166,1427,2078 } }, + { "Canon EOS D2000", 0, 0, + { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } }, + { "Canon EOS D6000", 0, 0, + { 20482,-7172,-3125,-1033,10410,-285,2542,226,3136 } }, + { "Canon EOS D30", 0, 0, + { 9805,-2689,-1312,-5803,13064,3068,-2438,3075,8775 } }, + { "Canon EOS D60", 0, 0xfa0, + { 6188,-1341,-890,-7168,14489,2937,-2640,3228,8483 } }, + { "Canon EOS 5D Mark II", 0, 0x3cf0, + { 4716,603,-830,-7798,15474,2480,-1496,1937,6651 } }, + { "Canon EOS 5D", 0, 0xe6c, + { 6347,-479,-972,-8297,15954,2480,-1968,2131,7649 } }, + { "Canon EOS 7D", 0, 0x3510, + { 6844,-996,-856,-3876,11761,2396,-593,1772,6198 } }, + { "Canon EOS 10D", 0, 0xfa0, + { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } }, + { "Canon EOS 20Da", 0, 0, + { 14155,-5065,-1382,-6550,14633,2039,-1623,1824,6561 } }, + { "Canon EOS 20D", 0, 0xfff, + { 6599,-537,-891,-8071,15783,2424,-1983,2234,7462 } }, + { "Canon EOS 30D", 0, 0, + { 6257,-303,-1000,-7880,15621,2396,-1714,1904,7046 } }, + { "Canon EOS 40D", 0, 0x3f60, + { 6071,-747,-856,-7653,15365,2441,-2025,2553,7315 } }, + { "Canon EOS 50D", 0, 0x3d93, + { 4920,616,-593,-6493,13964,2784,-1774,3178,7005 } }, + { "Canon EOS 300D", 0, 0xfa0, + { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } }, + { "Canon EOS 350D", 0, 0xfff, + { 6018,-617,-965,-8645,15881,2975,-1530,1719,7642 } }, + { "Canon EOS 400D", 0, 0xe8e, + { 7054,-1501,-990,-8156,15544,2812,-1278,1414,7796 } }, + { "Canon EOS 450D", 0, 0x390d, + { 5784,-262,-821,-7539,15064,2672,-1982,2681,7427 } }, + { "Canon EOS 500D", 0, 0x3479, + { 4763,712,-646,-6821,14399,2640,-1921,3276,6561 } }, + { "Canon EOS 1000D", 0, 0xe43, + { 6771,-1139,-977,-7818,15123,2928,-1244,1437,7533 } }, + { "Canon EOS-1Ds Mark III", 0, 0x3bb0, + { 5859,-211,-930,-8255,16017,2353,-1732,1887,7448 } }, + { "Canon EOS-1Ds Mark II", 0, 0xe80, + { 6517,-602,-867,-8180,15926,2378,-1618,1771,7633 } }, + { "Canon EOS-1D Mark IV", 0, 0x3bb0, + { 6014,-220,-795,-4109,12014,2361,-561,1824,5787 } }, + { "Canon EOS-1D Mark III", 0, 0x3bb0, + { 6291,-540,-976,-8350,16145,2311,-1714,1858,7326 } }, + { "Canon EOS-1D Mark II N", 0, 0xe80, + { 6240,-466,-822,-8180,15825,2500,-1801,1938,8042 } }, + { "Canon EOS-1D Mark II", 0, 0xe80, + { 6264,-582,-724,-8312,15948,2504,-1744,1919,8664 } }, + { "Canon EOS-1DS", 0, 0xe20, + { 4374,3631,-1743,-7520,15212,2472,-2892,3632,8161 } }, + { "Canon EOS-1D", 0, 0xe20, + { 6806,-179,-1020,-8097,16415,1687,-3267,4236,7690 } }, + { "Canon EOS", 0, 0, + { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } }, + { "Canon PowerShot A530", 0, 0, + { 0 } }, /* don't want the A5 matrix */ + { "Canon PowerShot A50", 0, 0, + { -5300,9846,1776,3436,684,3939,-5540,9879,6200,-1404,11175,217 } }, + { "Canon PowerShot A5", 0, 0, + { -4801,9475,1952,2926,1611,4094,-5259,10164,5947,-1554,10883,547 } }, + { "Canon PowerShot G10", 0, 0, + { 11093,-3906,-1028,-5047,12492,2879,-1003,1750,5561 } }, + { "Canon PowerShot G11", 0, 0, + { 12177,-4817,-1069,-1612,9864,2049,-98,850,4471 } }, + { "Canon PowerShot G1", 0, 0, + { -4778,9467,2172,4743,-1141,4344,-5146,9908,6077,-1566,11051,557 } }, + { "Canon PowerShot G2", 0, 0, + { 9087,-2693,-1049,-6715,14382,2537,-2291,2819,7790 } }, + { "Canon PowerShot G3", 0, 0, + { 9212,-2781,-1073,-6573,14189,2605,-2300,2844,7664 } }, + { "Canon PowerShot G5", 0, 0, + { 9757,-2872,-933,-5972,13861,2301,-1622,2328,7212 } }, + { "Canon PowerShot G6", 0, 0, + { 9877,-3775,-871,-7613,14807,3072,-1448,1305,7485 } }, + { "Canon PowerShot G9", 0, 0, + { 7368,-2141,-598,-5621,13254,2625,-1418,1696,5743 } }, + { "Canon PowerShot Pro1", 0, 0, + { 10062,-3522,-999,-7643,15117,2730,-765,817,7323 } }, + { "Canon PowerShot Pro70", 34, 0, + { -4155,9818,1529,3939,-25,4522,-5521,9870,6610,-2238,10873,1342 } }, + { "Canon PowerShot Pro90", 0, 0, + { -4963,9896,2235,4642,-987,4294,-5162,10011,5859,-1770,11230,577 } }, + { "Canon PowerShot S30", 0, 0, + { 10566,-3652,-1129,-6552,14662,2006,-2197,2581,7670 } }, + { "Canon PowerShot S40", 0, 0, + { 8510,-2487,-940,-6869,14231,2900,-2318,2829,9013 } }, + { "Canon PowerShot S45", 0, 0, + { 8163,-2333,-955,-6682,14174,2751,-2077,2597,8041 } }, + { "Canon PowerShot S50", 0, 0, + { 8882,-2571,-863,-6348,14234,2288,-1516,2172,6569 } }, + { "Canon PowerShot S60", 0, 0, + { 8795,-2482,-797,-7804,15403,2573,-1422,1996,7082 } }, + { "Canon PowerShot S70", 0, 0, + { 9976,-3810,-832,-7115,14463,2906,-901,989,7889 } }, + { "Canon PowerShot S90", 0, 0, + { 12374,-5016,-1049,-1677,9902,2078,-83,852,4683 } }, + { "Canon PowerShot A470", 0, 0, /* DJC */ + { 12513,-4407,-1242,-2680,10276,2405,-878,2215,4734 } }, + { "Canon PowerShot A610", 0, 0, /* DJC */ + { 15591,-6402,-1592,-5365,13198,2168,-1300,1824,5075 } }, + { "Canon PowerShot A620", 0, 0, /* DJC */ + { 15265,-6193,-1558,-4125,12116,2010,-888,1639,5220 } }, + { "Canon PowerShot A630", 0, 0, /* DJC */ + { 14201,-5308,-1757,-6087,14472,1617,-2191,3105,5348 } }, + { "Canon PowerShot A640", 0, 0, /* DJC */ + { 13124,-5329,-1390,-3602,11658,1944,-1612,2863,4885 } }, + { "Canon PowerShot A650", 0, 0, /* DJC */ + { 9427,-3036,-959,-2581,10671,1911,-1039,1982,4430 } }, + { "Canon PowerShot A720", 0, 0, /* DJC */ + { 14573,-5482,-1546,-1266,9799,1468,-1040,1912,3810 } }, + { "Canon PowerShot S3 IS", 0, 0, /* DJC */ + { 14062,-5199,-1446,-4712,12470,2243,-1286,2028,4836 } }, + { "Canon PowerShot SX1 IS", 0, 0, + { 6578,-259,-502,-5974,13030,3309,-308,1058,4970 } }, + { "Canon PowerShot SX110 IS", 0, 0, /* DJC */ + { 14134,-5576,-1527,-1991,10719,1273,-1158,1929,3581 } }, + { "CASIO EX-S20", 0, 0, /* DJC */ + { 11634,-3924,-1128,-4968,12954,2015,-1588,2648,7206 } }, + { "CASIO EX-Z750", 0, 0, /* DJC */ + { 10819,-3873,-1099,-4903,13730,1175,-1755,3751,4632 } }, + { "CINE 650", 0, 0, + { 3390,480,-500,-800,3610,340,-550,2336,1192 } }, + { "CINE 660", 0, 0, + { 3390,480,-500,-800,3610,340,-550,2336,1192 } }, + { "CINE", 0, 0, + { 20183,-4295,-423,-3940,15330,3985,-280,4870,9800 } }, + { "Contax N Digital", 0, 0xf1e, + { 7777,1285,-1053,-9280,16543,2916,-3677,5679,7060 } }, + { "EPSON R-D1", 0, 0, + { 6827,-1878,-732,-8429,16012,2564,-704,592,7145 } }, + { "FUJIFILM FinePix E550", 0, 0, + { 11044,-3888,-1120,-7248,15168,2208,-1531,2277,8069 } }, + { "FUJIFILM FinePix E900", 0, 0, + { 9183,-2526,-1078,-7461,15071,2574,-2022,2440,8639 } }, + { "FUJIFILM FinePix F8", 0, 0, + { 11044,-3888,-1120,-7248,15168,2208,-1531,2277,8069 } }, + { "FUJIFILM FinePix F7", 0, 0, + { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } }, + { "FUJIFILM FinePix S100FS", 514, 0, + { 11521,-4355,-1065,-6524,13767,3058,-1466,1984,6045 } }, + { "FUJIFILM FinePix S20Pro", 0, 0, + { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } }, + { "FUJIFILM FinePix S2Pro", 128, 0, + { 12492,-4690,-1402,-7033,15423,1647,-1507,2111,7697 } }, + { "FUJIFILM FinePix S3Pro", 0, 0, + { 11807,-4612,-1294,-8927,16968,1988,-2120,2741,8006 } }, + { "FUJIFILM FinePix S5Pro", 0, 0, + { 12300,-5110,-1304,-9117,17143,1998,-1947,2448,8100 } }, + { "FUJIFILM FinePix S5000", 0, 0, + { 8754,-2732,-1019,-7204,15069,2276,-1702,2334,6982 } }, + { "FUJIFILM FinePix S5100", 0, 0x3e00, + { 11940,-4431,-1255,-6766,14428,2542,-993,1165,7421 } }, + { "FUJIFILM FinePix S5500", 0, 0x3e00, + { 11940,-4431,-1255,-6766,14428,2542,-993,1165,7421 } }, + { "FUJIFILM FinePix S5200", 0, 0, + { 9636,-2804,-988,-7442,15040,2589,-1803,2311,8621 } }, + { "FUJIFILM FinePix S5600", 0, 0, + { 9636,-2804,-988,-7442,15040,2589,-1803,2311,8621 } }, + { "FUJIFILM FinePix S6", 0, 0, + { 12628,-4887,-1401,-6861,14996,1962,-2198,2782,7091 } }, + { "FUJIFILM FinePix S7000", 0, 0, + { 10190,-3506,-1312,-7153,15051,2238,-2003,2399,7505 } }, + { "FUJIFILM FinePix S9000", 0, 0, + { 10491,-3423,-1145,-7385,15027,2538,-1809,2275,8692 } }, + { "FUJIFILM FinePix S9500", 0, 0, + { 10491,-3423,-1145,-7385,15027,2538,-1809,2275,8692 } }, + { "FUJIFILM FinePix S9100", 0, 0, + { 12343,-4515,-1285,-7165,14899,2435,-1895,2496,8800 } }, + { "FUJIFILM FinePix S9600", 0, 0, + { 12343,-4515,-1285,-7165,14899,2435,-1895,2496,8800 } }, + { "FUJIFILM IS-1", 0, 0, + { 21461,-10807,-1441,-2332,10599,1999,289,875,7703 } }, + { "FUJIFILM IS Pro", 0, 0, + { 12300,-5110,-1304,-9117,17143,1998,-1947,2448,8100 } }, + { "Imacon Ixpress", 0, 0, /* DJC */ + { 7025,-1415,-704,-5188,13765,1424,-1248,2742,6038 } }, + { "KODAK NC2000", 0, 0, + { 13891,-6055,-803,-465,9919,642,2121,82,1291 } }, + { "Kodak DCS315C", 8, 0, + { 17523,-4827,-2510,756,8546,-137,6113,1649,2250 } }, + { "Kodak DCS330C", 8, 0, + { 20620,-7572,-2801,-103,10073,-396,3551,-233,2220 } }, + { "KODAK DCS420", 0, 0, + { 10868,-1852,-644,-1537,11083,484,2343,628,2216 } }, + { "KODAK DCS460", 0, 0, + { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } }, + { "KODAK EOSDCS1", 0, 0, + { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } }, + { "KODAK EOSDCS3B", 0, 0, + { 9898,-2700,-940,-2478,12219,206,1985,634,1031 } }, + { "Kodak DCS520C", 180, 0, + { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } }, + { "Kodak DCS560C", 188, 0, + { 20482,-7172,-3125,-1033,10410,-285,2542,226,3136 } }, + { "Kodak DCS620C", 180, 0, + { 23617,-10175,-3149,-2054,11749,-272,2586,-489,3453 } }, + { "Kodak DCS620X", 185, 0, + { 13095,-6231,154,12221,-21,-2137,895,4602,2258 } }, + { "Kodak DCS660C", 214, 0, + { 18244,-6351,-2739,-791,11193,-521,3711,-129,2802 } }, + { "Kodak DCS720X", 0, 0, + { 11775,-5884,950,9556,1846,-1286,-1019,6221,2728 } }, + { "Kodak DCS760C", 0, 0, + { 16623,-6309,-1411,-4344,13923,323,2285,274,2926 } }, + { "Kodak DCS Pro SLR", 0, 0, + { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } }, + { "Kodak DCS Pro 14nx", 0, 0, + { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } }, + { "Kodak DCS Pro 14", 0, 0, + { 7791,3128,-776,-8588,16458,2039,-2455,4006,6198 } }, + { "Kodak ProBack645", 0, 0, + { 16414,-6060,-1470,-3555,13037,473,2545,122,4948 } }, + { "Kodak ProBack", 0, 0, + { 21179,-8316,-2918,-915,11019,-165,3477,-180,4210 } }, + { "KODAK P712", 0, 0, + { 9658,-3314,-823,-5163,12695,2768,-1342,1843,6044 } }, + { "KODAK P850", 0, 0xf7c, + { 10511,-3836,-1102,-6946,14587,2558,-1481,1792,6246 } }, + { "KODAK P880", 0, 0xfff, + { 12805,-4662,-1376,-7480,15267,2360,-1626,2194,7904 } }, + { "KODAK EasyShare Z980", 0, 0, + { 11313,-3559,-1101,-3893,11891,2257,-1214,2398,4908 } }, + { "KODAK EASYSHARE Z1015", 0, 0xef1, + { 11265,-4286,-992,-4694,12343,2647,-1090,1523,5447 } }, + { "Leaf CMost", 0, 0, + { 3952,2189,449,-6701,14585,2275,-4536,7349,6536 } }, + { "Leaf Valeo 6", 0, 0, + { 3952,2189,449,-6701,14585,2275,-4536,7349,6536 } }, + { "Leaf Aptus 54S", 0, 0, + { 8236,1746,-1314,-8251,15953,2428,-3673,5786,5771 } }, + { "Leaf Aptus 65", 0, 0, + { 7914,1414,-1190,-8777,16582,2280,-2811,4605,5562 } }, + { "Leaf Aptus 75", 0, 0, + { 7914,1414,-1190,-8777,16582,2280,-2811,4605,5562 } }, + { "Leaf", 0, 0, + { 8236,1746,-1314,-8251,15953,2428,-3673,5786,5771 } }, + { "Mamiya ZD", 0, 0, + { 7645,2579,-1363,-8689,16717,2015,-3712,5941,5961 } }, + { "Micron 2010", 110, 0, /* DJC */ + { 16695,-3761,-2151,155,9682,163,3433,951,4904 } }, + { "Minolta DiMAGE 5", 0, 0xf7d, + { 8983,-2942,-963,-6556,14476,2237,-2426,2887,8014 } }, + { "Minolta DiMAGE 7Hi", 0, 0xf7d, + { 11368,-3894,-1242,-6521,14358,2339,-2475,3056,7285 } }, + { "Minolta DiMAGE 7", 0, 0xf7d, + { 9144,-2777,-998,-6676,14556,2281,-2470,3019,7744 } }, + { "Minolta DiMAGE A1", 0, 0xf8b, + { 9274,-2547,-1167,-8220,16323,1943,-2273,2720,8340 } }, + { "MINOLTA DiMAGE A200", 0, 0, + { 8560,-2487,-986,-8112,15535,2771,-1209,1324,7743 } }, + { "Minolta DiMAGE A2", 0, 0xf8f, + { 9097,-2726,-1053,-8073,15506,2762,-966,981,7763 } }, + { "Minolta DiMAGE Z2", 0, 0, /* DJC */ + { 11280,-3564,-1370,-4655,12374,2282,-1423,2168,5396 } }, + { "MINOLTA DYNAX 5", 0, 0xffb, + { 10284,-3283,-1086,-7957,15762,2316,-829,882,6644 } }, + { "MINOLTA DYNAX 7", 0, 0xffb, + { 10239,-3104,-1099,-8037,15727,2451,-927,925,6871 } }, + { "MOTOROLA PIXL", 0, 0, /* DJC */ + { 8898,-989,-1033,-3292,11619,1674,-661,3178,5216 } }, + { "NIKON D100", 0, 0, + { 5902,-933,-782,-8983,16719,2354,-1402,1455,6464 } }, + { "NIKON D1H", 0, 0, + { 7577,-2166,-926,-7454,15592,1934,-2377,2808,8606 } }, + { "NIKON D1X", 0, 0, + { 7702,-2245,-975,-9114,17242,1875,-2679,3055,8521 } }, + { "NIKON D1", 0, 0, /* multiplied by 2.218750, 1.0, 1.148438 */ + { 16772,-4726,-2141,-7611,15713,1972,-2846,3494,9521 } }, + { "NIKON D200", 0, 0xfbc, + { 8367,-2248,-763,-8758,16447,2422,-1527,1550,8053 } }, + { "NIKON D2H", 0, 0, + { 5710,-901,-615,-8594,16617,2024,-2975,4120,6830 } }, + { "NIKON D2X", 0, 0, + { 10231,-2769,-1255,-8301,15900,2552,-797,680,7148 } }, + { "NIKON D3000", 0, 0, + { 8736,-2458,-935,-9075,16894,2251,-1354,1242,8263 } }, + { "NIKON D300", 0, 0, + { 9030,-1992,-715,-8465,16302,2255,-2689,3217,8069 } }, + { "NIKON D3X", 0, 0, + { 7171,-1986,-648,-8085,15555,2718,-2170,2512,7457 } }, + { "NIKON D3S", 0, 0, + { 8828,-2406,-694,-4874,12603,2541,-660,1509,7587 } }, + { "NIKON D3", 0, 0, + { 8139,-2171,-663,-8747,16541,2295,-1925,2008,8093 } }, + { "NIKON D40X", 0, 0, + { 8819,-2543,-911,-9025,16928,2151,-1329,1213,8449 } }, + { "NIKON D40", 0, 0, + { 6992,-1668,-806,-8138,15748,2543,-874,850,7897 } }, + { "NIKON D5000", 0, 0xf00, + { 7309,-1403,-519,-8474,16008,2622,-2433,2826,8064 } }, + { "NIKON D50", 0, 0, + { 7732,-2422,-789,-8238,15884,2498,-859,783,7330 } }, + { "NIKON D60", 0, 0, + { 8736,-2458,-935,-9075,16894,2251,-1354,1242,8263 } }, + { "NIKON D700", 0, 0, + { 8139,-2171,-663,-8747,16541,2295,-1925,2008,8093 } }, + { "NIKON D70", 0, 0, + { 7732,-2422,-789,-8238,15884,2498,-859,783,7330 } }, + { "NIKON D80", 0, 0, + { 8629,-2410,-883,-9055,16940,2171,-1490,1363,8520 } }, + { "NIKON D90", 0, 0xf00, + { 7309,-1403,-519,-8474,16008,2622,-2434,2826,8064 } }, + { "NIKON E950", 0, 0x3dd, /* DJC */ + { -3746,10611,1665,9621,-1734,2114,-2389,7082,3064,3406,6116,-244 } }, + { "NIKON E995", 0, 0, /* copied from E5000 */ + { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, + { "NIKON E2100", 0, 0, /* copied from Z2, new white balance */ + { 13142,-4152,-1596,-4655,12374,2282,-1769,2696,6711} }, + { "NIKON E2500", 0, 0, + { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, + { "NIKON E4300", 0, 0, /* copied from Minolta DiMAGE Z2 */ + { 11280,-3564,-1370,-4655,12374,2282,-1423,2168,5396 } }, + { "NIKON E4500", 0, 0, + { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, + { "NIKON E5000", 0, 0, + { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, + { "NIKON E5400", 0, 0, + { 9349,-2987,-1001,-7919,15766,2266,-2098,2680,6839 } }, + { "NIKON E5700", 0, 0, + { -5368,11478,2368,5537,-113,3148,-4969,10021,5782,778,9028,211 } }, + { "NIKON E8400", 0, 0, + { 7842,-2320,-992,-8154,15718,2599,-1098,1342,7560 } }, + { "NIKON E8700", 0, 0, + { 8489,-2583,-1036,-8051,15583,2643,-1307,1407,7354 } }, + { "NIKON E8800", 0, 0, + { 7971,-2314,-913,-8451,15762,2894,-1442,1520,7610 } }, + { "NIKON COOLPIX P6000", 0, 0, + { 9698,-3367,-914,-4706,12584,2368,-837,968,5801 } }, + { "OLYMPUS C5050", 0, 0, + { 10508,-3124,-1273,-6079,14294,1901,-1653,2306,6237 } }, + { "OLYMPUS C5060", 0, 0, + { 10445,-3362,-1307,-7662,15690,2058,-1135,1176,7602 } }, + { "OLYMPUS C7070", 0, 0, + { 10252,-3531,-1095,-7114,14850,2436,-1451,1723,6365 } }, + { "OLYMPUS C70", 0, 0, + { 10793,-3791,-1146,-7498,15177,2488,-1390,1577,7321 } }, + { "OLYMPUS C80", 0, 0, + { 8606,-2509,-1014,-8238,15714,2703,-942,979,7760 } }, + { "OLYMPUS E-10", 0, 0xffc0, + { 12745,-4500,-1416,-6062,14542,1580,-1934,2256,6603 } }, + { "OLYMPUS E-1", 0, 0xfff0, + { 11846,-4767,-945,-7027,15878,1089,-2699,4122,8311 } }, + { "OLYMPUS E-20", 0, 0xffc0, + { 13173,-4732,-1499,-5807,14036,1895,-2045,2452,7142 } }, + { "OLYMPUS E-300", 0, 0, + { 7828,-1761,-348,-5788,14071,1830,-2853,4518,6557 } }, + { "OLYMPUS E-330", 0, 0, + { 8961,-2473,-1084,-7979,15990,2067,-2319,3035,8249 } }, + { "OLYMPUS E-30", 0, 0xfbc, + { 8144,-1861,-1111,-7763,15894,1929,-1865,2542,7607 } }, + { "OLYMPUS E-3", 0, 0xf99, + { 9487,-2875,-1115,-7533,15606,2010,-1618,2100,7389 } }, + { "OLYMPUS E-400", 0, 0xfff0, + { 6169,-1483,-21,-7107,14761,2536,-2904,3580,8568 } }, + { "OLYMPUS E-410", 0, 0xf6a, + { 8856,-2582,-1026,-7761,15766,2082,-2009,2575,7469 } }, + { "OLYMPUS E-420", 0, 0xfd7, + { 8746,-2425,-1095,-7594,15612,2073,-1780,2309,7416 } }, + { "OLYMPUS E-450", 0, 0xfd2, + { 8745,-2425,-1095,-7594,15613,2073,-1780,2309,7416 } }, + { "OLYMPUS E-500", 0, 0xfff0, + { 8136,-1968,-299,-5481,13742,1871,-2556,4205,6630 } }, + { "OLYMPUS E-510", 0, 0xf6a, + { 8785,-2529,-1033,-7639,15624,2112,-1783,2300,7817 } }, + { "OLYMPUS E-520", 0, 0xfd2, + { 8344,-2322,-1020,-7596,15635,2048,-1748,2269,7287 } }, + { "OLYMPUS E-620", 0, 0xfb9, + { 8453,-2198,-1092,-7609,15681,2008,-1725,2337,7824 } }, + { "OLYMPUS E-P1", 0, 0xffd, + { 8343,-2050,-1021,-7715,15705,2103,-1831,2380,8235 } }, + { "OLYMPUS SP350", 0, 0, + { 12078,-4836,-1069,-6671,14306,2578,-786,939,7418 } }, + { "OLYMPUS SP3", 0, 0, + { 11766,-4445,-1067,-6901,14421,2707,-1029,1217,7572 } }, + { "OLYMPUS SP500UZ", 0, 0xfff, + { 9493,-3415,-666,-5211,12334,3260,-1548,2262,6482 } }, + { "OLYMPUS SP510UZ", 0, 0xffe, + { 10593,-3607,-1010,-5881,13127,3084,-1200,1805,6721 } }, + { "OLYMPUS SP550UZ", 0, 0xffe, + { 11597,-4006,-1049,-5432,12799,2957,-1029,1750,6516 } }, + { "OLYMPUS SP560UZ", 0, 0xff9, + { 10915,-3677,-982,-5587,12986,2911,-1168,1968,6223 } }, + { "OLYMPUS SP570UZ", 0, 0, + { 11522,-4044,-1146,-4736,12172,2904,-988,1829,6039 } }, + { "PENTAX *ist DL2", 0, 0, + { 10504,-2438,-1189,-8603,16207,2531,-1022,863,12242 } }, + { "PENTAX *ist DL", 0, 0, + { 10829,-2838,-1115,-8339,15817,2696,-837,680,11939 } }, + { "PENTAX *ist DS2", 0, 0, + { 10504,-2438,-1189,-8603,16207,2531,-1022,863,12242 } }, + { "PENTAX *ist DS", 0, 0, + { 10371,-2333,-1206,-8688,16231,2602,-1230,1116,11282 } }, + { "PENTAX *ist D", 0, 0, + { 9651,-2059,-1189,-8881,16512,2487,-1460,1345,10687 } }, + { "PENTAX K10D", 0, 0, + { 9566,-2863,-803,-7170,15172,2112,-818,803,9705 } }, + { "PENTAX K1", 0, 0, + { 11095,-3157,-1324,-8377,15834,2720,-1108,947,11688 } }, + { "PENTAX K20D", 0, 0, + { 9427,-2714,-868,-7493,16092,1373,-2199,3264,7180 } }, + { "PENTAX K200D", 0, 0, + { 9186,-2678,-907,-8693,16517,2260,-1129,1094,8524 } }, + { "PENTAX K2000", 0, 0, + { 11057,-3604,-1155,-5152,13046,2329,-282,375,8104 } }, + { "PENTAX K-m", 0, 0, + { 11057,-3604,-1155,-5152,13046,2329,-282,375,8104 } }, + { "PENTAX K-x", 0, 0, + { 8843,-2837,-625,-5025,12644,2668,-411,1234,7410 } }, + { "PENTAX K-7", 0, 0, + { 9142,-2947,-678,-8648,16967,1663,-2224,2898,8615 } }, + { "Panasonic DMC-FZ8", 0, 0xf7f0, + { 8986,-2755,-802,-6341,13575,3077,-1476,2144,6379 } }, + { "Panasonic DMC-FZ18", 0, 0, + { 9932,-3060,-935,-5809,13331,2753,-1267,2155,5575 } }, + { "Panasonic DMC-FZ28", 15, 0xfff, + { 10109,-3488,-993,-5412,12812,2916,-1305,2140,5543 } }, + { "Panasonic DMC-FZ30", 0, 0xf94c, + { 10976,-4029,-1141,-7918,15491,2600,-1670,2071,8246 } }, + { "Panasonic DMC-FZ35", 147, 0xfff, + { 9938,-2780,-890,-4604,12393,2480,-1117,2304,4620 } }, + { "Panasonic DMC-FZ50", 0, 0xfff0, /* aka "LEICA V-LUX1" */ + { 7906,-2709,-594,-6231,13351,3220,-1922,2631,6537 } }, + { "Panasonic DMC-L10", 15, 0xf96, + { 8025,-1942,-1050,-7920,15904,2100,-2456,3005,7039 } }, + { "Panasonic DMC-L1", 0, 0xf7fc, /* aka "LEICA DIGILUX 3" */ + { 8054,-1885,-1025,-8349,16367,2040,-2805,3542,7629 } }, + { "Panasonic DMC-LC1", 0, 0, /* aka "LEICA DIGILUX 2" */ + { 11340,-4069,-1275,-7555,15266,2448,-2960,3426,7685 } }, + { "Panasonic DMC-LX1", 0, 0xf7f0, /* aka "LEICA D-LUX2" */ + { 10704,-4187,-1230,-8314,15952,2501,-920,945,8927 } }, + { "Panasonic DMC-LX2", 0, 0, /* aka "LEICA D-LUX3" */ + { 8048,-2810,-623,-6450,13519,3272,-1700,2146,7049 } }, + { "Panasonic DMC-LX3", 15, 0xfff, /* aka "LEICA D-LUX4" */ + { 8128,-2668,-655,-6134,13307,3161,-1782,2568,6083 } }, + { "Panasonic DMC-FX150", 15, 0xfff, + { 9082,-2907,-925,-6119,13377,3058,-1797,2641,5609 } }, + { "Panasonic DMC-G1", 15, 0xfff, + { 8199,-2065,-1056,-8124,16156,2033,-2458,3022,7220 } }, + { "Panasonic DMC-GF1", 15, 0xf92, + { 7888,-1902,-1011,-8106,16085,2099,-2353,2866,7330 } }, + { "Panasonic DMC-GH1", 15, 0xf92, + { 6299,-1466,-532,-6535,13852,2969,-2331,3112,5984 } }, + { "Phase One H 20", 0, 0, /* DJC */ + { 1313,1855,-109,-6715,15908,808,-327,1840,6020 } }, + { "Phase One P 2", 0, 0, + { 2905,732,-237,-8134,16626,1476,-3038,4253,7517 } }, + { "Phase One P 30", 0, 0, + { 4516,-245,-37,-7020,14976,2173,-3206,4671,7087 } }, + { "Phase One P 45", 0, 0, + { 5053,-24,-117,-5684,14076,1702,-2619,4492,5849 } }, + { "Phase One P65", 0, 0, /* DJC */ + { 8522,1268,-1916,-7706,16350,1358,-2397,4344,4923 } }, + { "SAMSUNG GX-1", 0, 0, + { 10504,-2438,-1189,-8603,16207,2531,-1022,863,12242 } }, + { "SAMSUNG S85", 0, 0, /* DJC */ + { 11885,-3968,-1473,-4214,12299,1916,-835,1655,5549 } }, + { "Sinar", 0, 0, /* DJC */ + { 16442,-2956,-2422,-2877,12128,750,-1136,6066,4559 } }, + { "SONY DSC-F828", 491, 0, + { 7924,-1910,-777,-8226,15459,2998,-1517,2199,6818,-7242,11401,3481 } }, + { "SONY DSC-R1", 512, 0, + { 8512,-2641,-694,-8042,15670,2526,-1821,2117,7414 } }, + { "SONY DSC-V3", 0, 0, + { 7511,-2571,-692,-7894,15088,3060,-948,1111,8128 } }, + { "SONY DSLR-A100", 0, 0xfeb, + { 9437,-2811,-774,-8405,16215,2290,-710,596,7181 } }, + { "SONY DSLR-A200", 0, 0, + { 9847,-3091,-928,-8485,16345,2225,-715,595,7103 } }, + { "SONY DSLR-A230", 0, 0, /* copied */ + { 9847,-3091,-928,-8485,16345,2225,-715,595,7103 } }, + { "SONY DSLR-A300", 0, 0, + { 9847,-3091,-928,-8485,16345,2225,-715,595,7103 } }, + { "SONY DSLR-A330", 0, 0, + { 9847,-3091,-929,-8485,16346,2225,-714,595,7103 } }, + { "SONY DSLR-A350", 0, 0xffc, + { 6038,-1484,-578,-9146,16746,2513,-875,746,7217 } }, + { "SONY DSLR-A380", 0, 0, + { 6038,-1484,-579,-9145,16746,2512,-875,746,7218 } }, + { "SONY DSLR-A5", 254, 0x1ffe, + { 4950,-580,-103,-5228,12542,3029,-709,1435,7371 } }, + { "SONY DSLR-A700", 254, 0x1ffe, + { 5775,-805,-359,-8574,16295,2391,-1943,2341,7249 } }, + { "SONY DSLR-A850", 256, 0x1ffe, + { 5413,-1162,-365,-5665,13098,2866,-608,1179,8440 } }, + { "SONY DSLR-A900", 254, 0x1ffe, + { 5209,-1072,-397,-8845,16120,2919,-1618,1803,8654 } } + }; + double cam_xyz[4][3]; + char name[130]; + int i, j; + + sprintf (name, "%s %s", make, model); + for (i=0; i < sizeof table / sizeof *table; i++) + if (!strncmp (name, table[i].prefix, strlen(table[i].prefix))) { + if (table[i].black) black = (ushort) table[i].black; + if (table[i].maximum) maximum = (ushort) table[i].maximum; + if (table[i].trans[0]) { + for (j=0; j < 12; j++) + cam_xyz[0][j] = table[i].trans[j] / 10000.0; + cam_xyz_coeff (cam_xyz); + } + break; + } +} + +void CLASS simple_coeff (int index) +{ + static const float table[][12] = { + /* index 0 -- all Foveon cameras */ + { 1.4032,-0.2231,-0.1016,-0.5263,1.4816,0.017,-0.0112,0.0183,0.9113 }, + /* index 1 -- Kodak DC20 and DC25 */ + { 2.25,0.75,-1.75,-0.25,-0.25,0.75,0.75,-0.25,-0.25,-1.75,0.75,2.25 }, + /* index 2 -- Logitech Fotoman Pixtura */ + { 1.893,-0.418,-0.476,-0.495,1.773,-0.278,-1.017,-0.655,2.672 }, + /* index 3 -- Nikon E880, E900, and E990 */ + { -1.936280, 1.800443, -1.448486, 2.584324, + 1.405365, -0.524955, -0.289090, 0.408680, + -1.204965, 1.082304, 2.941367, -1.818705 } + }; + int i, c; + + for (raw_color = i=0; i < 3; i++) + FORCC rgb_cam[i][c] = table[index][i*colors+c]; +} + +short CLASS guess_byte_order (int words) +{ + uchar test[4][2]; + int t=2, msb; + double diff, sum[2] = {0,0}; + + fread (test[0], 2, 2, ifp); + for (words-=2; words--; ) { + fread (test[t], 2, 1, ifp); + for (msb=0; msb < 2; msb++) { + diff = (test[t^2][msb] << 8 | test[t^2][!msb]) + - (test[t ][msb] << 8 | test[t ][!msb]); + sum[msb] += diff*diff; + } + t = (t+1) & 3; + } + return sum[0] < sum[1] ? 0x4d4d : 0x4949; +} + +float CLASS find_green (int bps, int bite, int off0, int off1) +{ + UINT64 bitbuf=0; + int vbits, col, i, c; + ushort img[2][2064]; + double sum[]={0,0}; + + FORC(2) { + fseek (ifp, c ? off1:off0, SEEK_SET); + for (vbits=col=0; col < width; col++) { + for (vbits -= bps; vbits < 0; vbits += bite) { + bitbuf <<= bite; + for (i=0; i < bite; i+=8) + bitbuf |= (unsigned) (fgetc(ifp) << i); + } + img[c][col] = bitbuf << (64-bps-vbits) >> (64-bps); + } + } + FORC(width-1) { + sum[ c & 1] += ABS(img[0][c]-img[1][c+1]); + sum[~c & 1] += ABS(img[1][c]-img[0][c+1]); + } + return 100 * log(sum[0]/sum[1]); +} + +/* + Identify which camera created this file, and set global variables + accordingly. + */ +void CLASS identify() +{ + char head[32], *cp; + int hlen, fsize, i, c, is_canon; + struct jhead jh; + static const struct { + int fsize; + char make[12], model[19], withjpeg; + } table[] = { + { 62464, "Kodak", "DC20" ,0 }, + { 124928, "Kodak", "DC20" ,0 }, + { 1652736, "Kodak", "DCS200" ,0 }, + { 4159302, "Kodak", "C330" ,0 }, + { 4162462, "Kodak", "C330" ,0 }, + { 460800, "Kodak", "C603v" ,0 }, + { 614400, "Kodak", "C603v" ,0 }, + { 6163328, "Kodak", "C603" ,0 }, + { 6166488, "Kodak", "C603" ,0 }, + { 9116448, "Kodak", "C603y" ,0 }, + { 311696, "ST Micro", "STV680 VGA" ,0 }, /* SPYz */ + { 787456, "Creative", "PC-CAM 600" ,0 }, + { 1138688, "Minolta", "RD175" ,0 }, + { 3840000, "Foculus", "531C" ,0 }, + { 786432, "AVT", "F-080C" ,0 }, + { 1447680, "AVT", "F-145C" ,0 }, + { 1920000, "AVT", "F-201C" ,0 }, + { 5067304, "AVT", "F-510C" ,0 }, + { 10134608, "AVT", "F-510C" ,0 }, + { 16157136, "AVT", "F-810C" ,0 }, + { 1409024, "Sony", "XCD-SX910CR" ,0 }, + { 2818048, "Sony", "XCD-SX910CR" ,0 }, + { 3884928, "Micron", "2010" ,0 }, + { 6624000, "Pixelink", "A782" ,0 }, + { 13248000, "Pixelink", "A782" ,0 }, + { 6291456, "RoverShot","3320AF" ,0 }, + { 6553440, "Canon", "PowerShot A460" ,0 }, + { 6653280, "Canon", "PowerShot A530" ,0 }, + { 6573120, "Canon", "PowerShot A610" ,0 }, + { 9219600, "Canon", "PowerShot A620" ,0 }, + { 9243240, "Canon", "PowerShot A470" ,0 }, + { 10341600, "Canon", "PowerShot A720" ,0 }, + { 10383120, "Canon", "PowerShot A630" ,0 }, + { 12945240, "Canon", "PowerShot A640" ,0 }, + { 15636240, "Canon", "PowerShot A650" ,0 }, + { 5298000, "Canon", "PowerShot SD300" ,0 }, + { 7710960, "Canon", "PowerShot S3 IS" ,0 }, + { 15467760, "Canon", "PowerShot SX110 IS",0 }, + { 5939200, "OLYMPUS", "C770UZ" ,0 }, + { 1581060, "NIKON", "E900" ,1 }, /* or E900s,E910 */ + { 2465792, "NIKON", "E950" ,1 }, /* or E800,E700 */ + { 2940928, "NIKON", "E2100" ,1 }, /* or E2500 */ + { 4771840, "NIKON", "E990" ,1 }, /* or E995, Oly C3030Z */ + { 4775936, "NIKON", "E3700" ,1 }, /* or Optio 33WR */ + { 5869568, "NIKON", "E4300" ,1 }, /* or DiMAGE Z2 */ + { 5865472, "NIKON", "E4500" ,1 }, + { 7438336, "NIKON", "E5000" ,1 }, /* or E5700 */ + { 8998912, "NIKON", "COOLPIX S6" ,1 }, + { 1976352, "CASIO", "QV-2000UX" ,1 }, + { 3217760, "CASIO", "QV-3*00EX" ,1 }, + { 6218368, "CASIO", "QV-5700" ,1 }, + { 6054400, "CASIO", "QV-R41" ,1 }, + { 7530816, "CASIO", "QV-R51" ,1 }, + { 7684000, "CASIO", "QV-4000" ,1 }, + { 2937856, "CASIO", "EX-S20" ,1 }, + { 4948608, "CASIO", "EX-S100" ,1 }, + { 7542528, "CASIO", "EX-Z50" ,1 }, + { 7753344, "CASIO", "EX-Z55" ,1 }, + { 7816704, "CASIO", "EX-Z60" ,1 }, + { 10843712, "CASIO", "EX-Z75" ,1 }, + { 10834368, "CASIO", "EX-Z750" ,1 }, + { 12310144, "CASIO", "EX-Z850" ,1 }, + { 7426656, "CASIO", "EX-P505" ,1 }, + { 9313536, "CASIO", "EX-P600" ,1 }, + { 10979200, "CASIO", "EX-P700" ,1 }, + { 3178560, "PENTAX", "Optio S" ,1 }, + { 4841984, "PENTAX", "Optio S" ,1 }, + { 6114240, "PENTAX", "Optio S4" ,1 }, /* or S4i, CASIO EX-Z4 */ + { 10702848, "PENTAX", "Optio 750Z" ,1 }, + { 15980544, "AGFAPHOTO","DC-833m" ,1 }, + { 16098048, "SAMSUNG", "S85" ,1 }, + { 16215552, "SAMSUNG", "S85" ,1 }, + { 12582980, "Sinar", "" ,0 }, + { 33292868, "Sinar", "" ,0 }, + { 44390468, "Sinar", "" ,0 } }; + static const char *corp[] = + { "Canon", "NIKON", "EPSON", "KODAK", "Kodak", "OLYMPUS", "PENTAX", + "MINOLTA", "Minolta", "Konica", "CASIO", "Sinar", "Phase One", + "SAMSUNG", "Mamiya", "MOTOROLA" }; + + tiff_flip = flip = filters = -1; /* 0 is valid, so -1 is unknown */ + raw_height = raw_width = fuji_width = fuji_layout = cr2_slice[0] = 0; + maximum = height = width = top_margin = left_margin = 0; + cdesc[0] = desc[0] = artist[0] = make[0] = model[0] = model2[0] = 0; + iso_speed = shutter = aperture = focal_len = unique_id = 0; + memset (gpsdata, 0, sizeof gpsdata); + memset (white, 0, sizeof white); + thumb_offset = thumb_length = thumb_width = thumb_height = 0; + load_raw = thumb_load_raw = 0; + write_thumb = &CLASS jpeg_thumb; + data_offset = meta_length = tiff_bps = tiff_compress = 0; + kodak_cbpp = zero_after_ff = dng_version = load_flags = 0; + timestamp = shot_order = tiff_samples = black = is_foveon = 0; + mix_green = profile_length = data_error = zero_is_bad = 0; + pixel_aspect = is_raw = raw_color = 1; + tile_width = tile_length = INT_MAX; + for (i=0; i < 4; i++) { + cam_mul[i] = i == 1; + pre_mul[i] = i < 3; + FORC3 cmatrix[c][i] = 0; + FORC3 rgb_cam[c][i] = c == i; + } + colors = 3; + for (i=0; i < 0x4000; i++) curve[i] = i; + + order = get2(); + hlen = get4(); + fseek (ifp, 0, SEEK_SET); + fread (head, 1, 32, ifp); + fseek (ifp, 0, SEEK_END); + fsize = ftell(ifp); + + /*RT*/ if (fsize<100000) { + is_raw = 0; + return; + } + + if ((cp = (char *) memmem (head, 32, "MMMM", 4)) || + (cp = (char *) memmem (head, 32, "IIII", 4))) { + parse_phase_one (cp-head); + if (cp-head) parse_tiff(0); + } else if (order == 0x4949 || order == 0x4d4d) { + if (!memcmp (head+6,"HEAPCCDR",8)) { + data_offset = hlen; +/*RT*/ ciff_base = hlen; +/*RT*/ ciff_len = fsize - hlen; + parse_ciff (hlen, fsize - hlen); + } else { + parse_tiff(0); + } + } else if (!memcmp (head,"\xff\xd8\xff\xe1",4) && + !memcmp (head+6,"Exif",4)) { + fseek (ifp, 4, SEEK_SET); + data_offset = 4 + get2(); + fseek (ifp, data_offset, SEEK_SET); + if (fgetc(ifp) != 0xff) + parse_tiff(12); + thumb_offset = 0; + } else if (!memcmp (head+25,"ARECOYK",7)) { + strcpy (make, "Contax"); + strcpy (model,"N Digital"); + fseek (ifp, 33, SEEK_SET); + get_timestamp(1); + fseek (ifp, 60, SEEK_SET); + FORC4 cam_mul[c ^ (c >> 1)] = get4(); + } else if (!strcmp (head, "PXN")) { + strcpy (make, "Logitech"); + strcpy (model,"Fotoman Pixtura"); + } else if (!strcmp (head, "qktk")) { + strcpy (make, "Apple"); + strcpy (model,"QuickTake 100"); + } else if (!strcmp (head, "qktn")) { + strcpy (make, "Apple"); + strcpy (model,"QuickTake 150"); + } else if (!memcmp (head,"FUJIFILM",8)) { + fseek (ifp, 84, SEEK_SET); + thumb_offset = get4(); + thumb_length = get4(); + fseek (ifp, 92, SEEK_SET); + parse_fuji (get4()); + if (thumb_offset > 120) { + fseek (ifp, 120, SEEK_SET); + is_raw += (i = get4()) && 1; + if (is_raw == 2 && shot_select) + parse_fuji (i); + } + fseek (ifp, 100, SEEK_SET); + data_offset = get4(); + parse_tiff (thumb_offset+12); + } else if (!memcmp (head,"RIFF",4)) { + fseek (ifp, 0, SEEK_SET); + parse_riff(); + } else if (!memcmp (head,"\0\001\0\001\0@",6)) { + fseek (ifp, 6, SEEK_SET); + fread (make, 1, 8, ifp); + fread (model, 1, 8, ifp); + fread (model2, 1, 16, ifp); + data_offset = get2(); + get2(); + raw_width = get2(); + raw_height = get2(); + load_raw = &CLASS nokia_load_raw; + filters = 0x61616161; + } else if (!memcmp (head,"DSC-Image",9)) + parse_rollei(); + else if (!memcmp (head,"PWAD",4)) + parse_sinar_ia(); + else if (!memcmp (head,"\0MRM",4)) + parse_minolta(0); + else if (!memcmp (head,"FOVb",4)) + parse_foveon(); + else if (!memcmp (head,"CI",2)) + parse_cine(); + else + for (i=0; i < sizeof table / sizeof *table; i++) + if (fsize == table[i].fsize) { + strcpy (make, table[i].make ); + strcpy (model, table[i].model); + if (table[i].withjpeg) + parse_external_jpeg(); + } + if (make[0] == 0) parse_smal (0, fsize); + if (make[0] == 0) parse_jpeg (is_raw = 0); + + for (i=0; i < sizeof corp / sizeof *corp; i++) + if (strstr (make, corp[i])) /* Simplify company names */ + strcpy (make, corp[i]); + if (!strncmp (make,"KODAK",5) && + ((cp = strstr(model," DIGITAL CAMERA")) || + (cp = strstr(model," Digital Camera")) || + (cp = strstr(model,"FILE VERSION")))) + *cp = 0; + cp = make + strlen(make); /* Remove trailing spaces */ + while (*--cp == ' ') *cp = 0; + cp = model + strlen(model); + while (*--cp == ' ') *cp = 0; + i = strlen(make); /* Remove make from model */ + if (!strncasecmp (model, make, i) && model[i++] == ' ') + memmove (model, model+i, 64-i); + if (!strncmp (model,"Digital Camera ",15)) + strcpy (model, model+15); + desc[511] = artist[63] = make[63] = model[63] = model2[63] = 0; + if (!is_raw) goto notraw; + + if (!height) height = raw_height; + if (!width) width = raw_width; + if (fuji_width) { + width = height + fuji_width; + height = width - 1; + pixel_aspect = 1; + } + if (height == 2624 && width == 3936) /* Pentax K10D and Samsung GX10 */ + { height = 2616; width = 3896; } + if (height == 3136 && width == 4864) /* Pentax K20D */ + { height = 3124; width = 4688; } + if (height == 3136 && width == 4736) /* Pentax K-7 */ + { height = 3122; width = 4684; + top_margin = 2; filters = 0x16161616; } + if (height == 3014 && width == 4096) /* Ricoh GX200 */ + width = 4014; + if (dng_version) { + if (filters == UINT_MAX) filters = 0; + if (filters) is_raw = tiff_samples; + else colors = tiff_samples; + if (tiff_compress == 1) + load_raw = &CLASS adobe_dng_load_raw_nc; + if (tiff_compress == 7) + load_raw = &CLASS adobe_dng_load_raw_lj; + goto dng_skip; + } + if ((is_canon = !strcmp(make,"Canon"))) + load_raw = memcmp (head+6,"HEAPCCDR",8) ? + &CLASS lossless_jpeg_load_raw : &CLASS canon_compressed_load_raw; + if (!strcmp(make,"NIKON")) { + if (!load_raw) + load_raw = &CLASS packed_load_raw; + if (model[0] == 'E') + load_flags |= !data_offset << 2 | 2; + } + if (!strcmp(make,"CASIO")) { + load_raw = &CLASS packed_load_raw; + maximum = 0xf7f; + } + +/* Set parameters based on camera name (for non-DNG files). */ + + if (is_foveon) { + if (height*2 < width) pixel_aspect = 0.5; + if (height > width) pixel_aspect = 2; + filters = 0; + load_raw = &CLASS foveon_load_raw; + simple_coeff(0); + } else if (is_canon && tiff_bps == 15) { + switch (width) { + case 3344: width -= 66; + case 3872: width -= 6; + } + filters = 0; + load_raw = &CLASS canon_sraw_load_raw; + } else if (!strcmp(model,"PowerShot 600")) { + height = 613; + width = 854; + raw_width = 896; + pixel_aspect = 607/628.0; + colors = 4; + filters = 0xe1e4e1e4; + load_raw = &CLASS canon_600_load_raw; + } else if (!strcmp(model,"PowerShot A5") || + !strcmp(model,"PowerShot A5 Zoom")) { + height = 773; + width = 960; + raw_width = 992; + pixel_aspect = 256/235.0; + colors = 4; + filters = 0x1e4e1e4e; + goto canon_a5; + } else if (!strcmp(model,"PowerShot A50")) { + height = 968; + width = 1290; + raw_width = 1320; + colors = 4; + filters = 0x1b4e4b1e; + goto canon_a5; + } else if (!strcmp(model,"PowerShot Pro70")) { + height = 1024; + width = 1552; + colors = 4; + filters = 0x1e4b4e1b; + goto canon_a5; + } else if (!strcmp(model,"PowerShot SD300")) { + height = 1752; + width = 2344; + raw_height = 1766; + raw_width = 2400; + top_margin = 12; + left_margin = 12; + goto canon_a5; + } else if (!strcmp(model,"PowerShot A460")) { + height = 1960; + width = 2616; + raw_height = 1968; + raw_width = 2664; + top_margin = 4; + left_margin = 4; + goto canon_a5; + } else if (!strcmp(model,"PowerShot A530")) { + height = 1984; + width = 2620; + raw_height = 1992; + raw_width = 2672; + top_margin = 6; + left_margin = 10; + goto canon_a5; + } else if (!strcmp(model,"PowerShot A610")) { + if (canon_s2is()) strcpy (model+10, "S2 IS"); + height = 1960; + width = 2616; + raw_height = 1968; + raw_width = 2672; + top_margin = 8; + left_margin = 12; + goto canon_a5; + } else if (!strcmp(model,"PowerShot A620")) { + height = 2328; + width = 3112; + raw_height = 2340; + raw_width = 3152; + top_margin = 12; + left_margin = 36; + goto canon_a5; + } else if (!strcmp(model,"PowerShot A470")) { + height = 2328; + width = 3096; + raw_height = 2346; + raw_width = 3152; + top_margin = 6; + left_margin = 12; + goto canon_a5; + } else if (!strcmp(model,"PowerShot A720")) { + height = 2472; + width = 3298; + raw_height = 2480; + raw_width = 3336; + top_margin = 5; + left_margin = 6; + goto canon_a5; + } else if (!strcmp(model,"PowerShot A630")) { + height = 2472; + width = 3288; + raw_height = 2484; + raw_width = 3344; + top_margin = 6; + left_margin = 12; + goto canon_a5; + } else if (!strcmp(model,"PowerShot A640")) { + height = 2760; + width = 3672; + raw_height = 2772; + raw_width = 3736; + top_margin = 6; + left_margin = 12; + goto canon_a5; + } else if (!strcmp(model,"PowerShot A650")) { + height = 3024; + width = 4032; + raw_height = 3048; + raw_width = 4104; + top_margin = 12; + left_margin = 48; + goto canon_a5; + } else if (!strcmp(model,"PowerShot S3 IS")) { + height = 2128; + width = 2840; + raw_height = 2136; + raw_width = 2888; + top_margin = 8; + left_margin = 44; +canon_a5: + tiff_bps = 10; + load_raw = &CLASS packed_load_raw; + load_flags = 40; + if (raw_width > 1600) zero_is_bad = 1; + } else if (!strcmp(model,"PowerShot SX110 IS")) { + height = 2760; + width = 3684; + raw_height = 2772; + raw_width = 3720; + top_margin = 12; + left_margin = 6; + load_raw = &CLASS packed_load_raw; + load_flags = 40; + zero_is_bad = 1; + } else if (!strcmp(model,"PowerShot Pro90 IS")) { + width = 1896; + colors = 4; + filters = 0xb4b4b4b4; + } else if (is_canon && raw_width == 2144) { + height = 1550; + width = 2088; + top_margin = 8; + left_margin = 4; + if (!strcmp(model,"PowerShot G1")) { + colors = 4; + filters = 0xb4b4b4b4; + } + } else if (is_canon && raw_width == 2224) { + height = 1448; + width = 2176; + top_margin = 6; + left_margin = 48; + } else if (is_canon && raw_width == 2376) { + height = 1720; + width = 2312; + top_margin = 6; + left_margin = 12; + } else if (is_canon && raw_width == 2672) { + height = 1960; + width = 2616; + top_margin = 6; + left_margin = 12; + } else if (is_canon && raw_width == 3152) { + height = 2056; + width = 3088; + top_margin = 12; + left_margin = 64; + if (unique_id == 0x80000170) + adobe_coeff ("Canon","EOS 300D"); + } else if (is_canon && raw_width == 3160) { + height = 2328; + width = 3112; + top_margin = 12; + left_margin = 44; + } else if (is_canon && raw_width == 3344) { + height = 2472; + width = 3288; + top_margin = 6; + left_margin = 4; + } else if (!strcmp(model,"EOS D2000C")) { + filters = 0x61616161; + black = curve[200]; + } else if (is_canon && raw_width == 3516) { + top_margin = 14; + left_margin = 42; + if (unique_id == 0x80000189) + adobe_coeff ("Canon","EOS 350D"); + goto canon_cr2; + } else if (is_canon && raw_width == 3596) { + top_margin = 12; + left_margin = 74; + goto canon_cr2; + } else if (is_canon && raw_width == 3744) { + height = 2760; + width = 3684; + top_margin = 16; + left_margin = 8; + } else if (is_canon && raw_width == 3944) { + height = 2602; + width = 3908; + top_margin = 18; + left_margin = 30; + } else if (is_canon && raw_width == 3948) { + top_margin = 18; + left_margin = 42; + height -= 2; + if (unique_id == 0x80000236) + adobe_coeff ("Canon","EOS 400D"); + if (unique_id == 0x80000254) + adobe_coeff ("Canon","EOS 1000D"); + goto canon_cr2; + } else if (is_canon && raw_width == 3984) { + top_margin = 20; + left_margin = 76; + height -= 2; + goto canon_cr2; + } else if (is_canon && raw_width == 4104) { + height = 3024; + width = 4032; + top_margin = 12; + left_margin = 48; + } else if (is_canon && raw_width == 4152) { + top_margin = 12; + left_margin = 192; + goto canon_cr2; + } else if (is_canon && raw_width == 4312) { + top_margin = 18; + left_margin = 22; + height -= 2; + if (unique_id == 0x80000176) + adobe_coeff ("Canon","EOS 450D"); + goto canon_cr2; + } else if (is_canon && raw_width == 4476) { + top_margin = 34; + left_margin = 90; + goto canon_cr2; + } else if (is_canon && raw_width == 4480) { + height = 3326; + width = 4432; + top_margin = 10; + left_margin = 12; + filters = 0x49494949; + } else if (is_canon && raw_width == 1208) { + top_margin = unique_id == 0x80000261 ? 51:26; + left_margin = 62; + raw_width = width *= 4; + if (unique_id == 0x80000252) + adobe_coeff ("Canon","EOS 500D"); + goto canon_cr2; + } else if (is_canon && raw_width == 1280) { + height -= top_margin = 45; + left_margin = 142; + raw_width *= 4; + width = 4916; + } else if (is_canon && raw_width == 1340) { + top_margin = 51; + left_margin = 158; + raw_width = width *= 4; + goto canon_cr2; + } else if (is_canon && raw_width == 1448) { + top_margin = 51; + left_margin = 158; + raw_width = width *= 4; + goto canon_cr2; + } else if (is_canon && raw_width == 5108) { + top_margin = 13; + left_margin = 98; +canon_cr2: + height -= top_margin; + width -= left_margin; + } else if (is_canon && raw_width == 5712) { + height = 3752; + width = 5640; + top_margin = 20; + left_margin = 62; + } else if (!strcmp(model,"D1")) { + cam_mul[0] *= 256/527.0; + cam_mul[2] *= 256/317.0; + } else if (!strcmp(model,"D1X")) { + width -= 4; + pixel_aspect = 0.5; + } else if (!strcmp(model,"D40X") || + !strcmp(model,"D60") || + !strcmp(model,"D80") || + !strcmp(model,"D3000")) { + height -= 3; + width -= 4; + } else if (!strcmp(model,"D3") || + !strcmp(model,"D3S") || + !strcmp(model,"D700")) { + width -= 4; + left_margin = 2; + } else if (!strcmp(model,"D5000")) { + width -= 42; + } else if (!strncmp(model,"D40",3) || + !strncmp(model,"D50",3) || + !strncmp(model,"D70",3)) { + width--; + } else if (!strcmp(model,"D90")) { + width -= 42; + } else if (!strcmp(model,"D100")) { + if (tiff_compress == 34713 && !nikon_is_compressed()) { + load_raw = &CLASS packed_load_raw; + load_flags |= 1; + raw_width = (width += 3) + 3; + } + } else if (!strcmp(model,"D200")) { + left_margin = 1; + width -= 4; + filters = 0x94949494; + } else if (!strncmp(model,"D2H",3)) { + left_margin = 6; + width -= 14; + } else if (!strncmp(model,"D2X",3)) { + if (width == 3264) width -= 32; + else width -= 8; + } else if (!strncmp(model,"D300",4)) { + width -= 32; + } else if (!strcmp(model,"COOLPIX P6000")) { + load_flags = 24; + filters = 0x94949494; + } else if (fsize == 1581060) { + height = 963; + width = 1287; + raw_width = 1632; + maximum = 0x3f4; + colors = 4; + filters = 0x1e1e1e1e; + simple_coeff(3); + pre_mul[0] = 1.2085; + pre_mul[1] = 1.0943; + pre_mul[3] = 1.1103; + goto e900; + } else if (fsize == 2465792) { + height = 1203; + width = 1616; + raw_width = 2048; + colors = 4; + filters = 0x4b4b4b4b; + adobe_coeff ("NIKON","E950"); +e900: + tiff_bps = 10; + load_raw = &CLASS packed_load_raw; + load_flags = 6; + } else if (fsize == 4771840) { + height = 1540; + width = 2064; + colors = 4; + filters = 0xe1e1e1e1; + load_raw = &CLASS packed_load_raw; + load_flags = 6; + if (!timestamp && nikon_e995()) + strcpy (model, "E995"); + if (strcmp(model,"E995")) { + filters = 0xb4b4b4b4; + simple_coeff(3); + pre_mul[0] = 1.196; + pre_mul[1] = 1.246; + pre_mul[2] = 1.018; + } + } else if (!strcmp(model,"E2100")) { + if (!timestamp && !nikon_e2100()) goto cp_e2500; + height = 1206; + width = 1616; + load_flags = 30; + } else if (!strcmp(model,"E2500")) { +cp_e2500: + strcpy (model, "E2500"); + height = 1204; + width = 1616; + colors = 4; + filters = 0x4b4b4b4b; + } else if (fsize == 4775936) { + height = 1542; + width = 2064; + load_raw = &CLASS packed_load_raw; + load_flags = 30; + if (!timestamp) nikon_3700(); + if (model[0] == 'E' && atoi(model+1) < 3700) + filters = 0x49494949; + if (!strcmp(model,"Optio 33WR")) { + flip = 1; + filters = 0x16161616; + } + if (make[0] == 'O') { + i = find_green (12, 32, 0, fsize/2); + c = find_green (12, 32, 0, 3096); + if (abs(i) < abs(c)) { + SWAP(i,c); + load_flags = 24; + } + if (i < 0) filters = 0x61616161; + } + } else if (fsize == 5869568) { + height = 1710; + width = 2288; + filters = 0x16161616; + if (!timestamp && minolta_z2()) { + strcpy (make, "Minolta"); + strcpy (model,"DiMAGE Z2"); + } + load_raw = &CLASS packed_load_raw; + load_flags = 6 + 24*(make[0] == 'M'); + } else if (!strcmp(model,"E4500")) { + height = 1708; + width = 2288; + colors = 4; + filters = 0xb4b4b4b4; + } else if (fsize == 7438336) { + height = 1924; + width = 2576; + colors = 4; + filters = 0xb4b4b4b4; + } else if (fsize == 8998912) { + height = 2118; + width = 2832; + maximum = 0xf83; + load_raw = &CLASS packed_load_raw; + load_flags = 30; + } else if (!strcmp(make,"FUJIFILM")) { + if (!strcmp(model+7,"S2Pro")) { + strcpy (model+7," S2Pro"); + height = 2144; + width = 2880; + flip = 6; + } else + maximum = 0x3e00; + if (is_raw == 2 && shot_select) + maximum = 0x2f00; + top_margin = (raw_height - height)/2; + left_margin = (raw_width - width )/2; + if (is_raw == 2) + data_offset += (shot_select > 0) * ( fuji_layout ? + (raw_width *= 2) : raw_height*raw_width*2 ); + if (load_raw == &CLASS fuji_load_raw) { + fuji_width = width >> !fuji_layout; + width = (height >> fuji_layout) + fuji_width; + raw_height = height; + height = width - 1; + if (~fuji_width & 1) filters = 0x49494949; + } + } else if (!strcmp(model,"RD175")) { + height = 986; + width = 1534; + data_offset = 513; + filters = 0x61616161; + load_raw = &CLASS minolta_rd175_load_raw; + } else if (!strcmp(model,"KD-400Z")) { + height = 1712; + width = 2312; + raw_width = 2336; + goto konica_400z; + } else if (!strcmp(model,"KD-510Z")) { + goto konica_510z; + } else if (!strcasecmp(make,"MINOLTA")) { + load_raw = &CLASS unpacked_load_raw; + maximum = 0xfff; + if (!strncmp(model,"DiMAGE A",8)) { + if (!strcmp(model,"DiMAGE A200")) + filters = 0x49494949; + tiff_bps = 12; + load_raw = &CLASS packed_load_raw; + } else if (!strncmp(model,"ALPHA",5) || + !strncmp(model,"DYNAX",5) || + !strncmp(model,"MAXXUM",6)) { + sprintf (model+20, "DYNAX %-10s", model+6+(model[0]=='M')); + adobe_coeff (make, model+20); + load_raw = &CLASS packed_load_raw; + } else if (!strncmp(model,"DiMAGE G",8)) { + if (model[8] == '4') { + height = 1716; + width = 2304; + } else if (model[8] == '5') { +konica_510z: + height = 1956; + width = 2607; + raw_width = 2624; + } else if (model[8] == '6') { + height = 2136; + width = 2848; + } + data_offset += 14; + filters = 0x61616161; +konica_400z: + load_raw = &CLASS unpacked_load_raw; + maximum = 0x3df; + order = 0x4d4d; + } + } else if (!strcmp(model,"*ist D")) { + data_error = -1; + } else if (!strcmp(model,"*ist DS")) { + height -= 2; + } else if (!strcmp(model,"K20D")) { + filters = 0x16161616; + } else if (!strcmp(model,"K-x")) { + width = 4309; + filters = 0x16161616; + } else if (!strcmp(model,"Optio S")) { + if (fsize == 3178560) { + height = 1540; + width = 2064; + load_raw = &CLASS eight_bit_load_raw; + cam_mul[0] *= 4; + cam_mul[2] *= 4; + } else { + height = 1544; + width = 2068; + raw_width = 3136; + load_raw = &CLASS packed_load_raw; + maximum = 0xf7c; + } + } else if (fsize == 6114240) { + height = 1737; + width = 2324; + raw_width = 3520; + load_raw = &CLASS packed_load_raw; + maximum = 0xf7a; + } else if (!strcmp(model,"Optio 750Z")) { + height = 2302; + width = 3072; + load_raw = &CLASS packed_load_raw; + load_flags = 30; + } else if (!strcmp(model,"DC-833m")) { + height = 2448; + width = 3264; + order = 0x4949; + filters = 0x61616161; + load_raw = &CLASS unpacked_load_raw; + maximum = 0xfc00; + } else if (!strncmp(model,"S85",3)) { + height = 2448; + width = 3264; + raw_width = fsize/height/2; + order = 0x4d4d; + load_raw = &CLASS unpacked_load_raw; + maximum = 0xffff; + } else if (!strcmp(model,"STV680 VGA")) { + height = 484; + width = 644; + load_raw = &CLASS eight_bit_load_raw; + flip = 2; + filters = 0x16161616; + black = 16; + } else if (!strcmp(model,"N95")) { + height = raw_height - (top_margin = 2); + } else if (!strcmp(model,"531C")) { + height = 1200; + width = 1600; + load_raw = &CLASS unpacked_load_raw; + filters = 0x49494949; + } else if (!strcmp(model,"F-080C")) { + height = 768; + width = 1024; + load_raw = &CLASS eight_bit_load_raw; + } else if (!strcmp(model,"F-145C")) { + height = 1040; + width = 1392; + load_raw = &CLASS eight_bit_load_raw; + } else if (!strcmp(model,"F-201C")) { + height = 1200; + width = 1600; + load_raw = &CLASS eight_bit_load_raw; + } else if (!strcmp(model,"F-510C")) { + height = 1958; + width = 2588; + load_raw = fsize < 7500000 ? + &CLASS eight_bit_load_raw : &CLASS unpacked_load_raw; + maximum = 0xfff0; + } else if (!strcmp(model,"F-810C")) { + height = 2469; + width = 3272; + load_raw = &CLASS unpacked_load_raw; + maximum = 0xfff0; + } else if (!strcmp(model,"XCD-SX910CR")) { + height = 1024; + width = 1375; + raw_width = 1376; + filters = 0x49494949; + maximum = 0x3ff; + load_raw = fsize < 2000000 ? + &CLASS eight_bit_load_raw : &CLASS unpacked_load_raw; + } else if (!strcmp(model,"2010")) { + height = 1207; + width = 1608; + order = 0x4949; + filters = 0x16161616; + data_offset = 3212; + maximum = 0x3ff; + load_raw = &CLASS unpacked_load_raw; + } else if (!strcmp(model,"A782")) { + height = 3000; + width = 2208; + filters = 0x61616161; + load_raw = fsize < 10000000 ? + &CLASS eight_bit_load_raw : &CLASS unpacked_load_raw; + maximum = 0xffc0; + } else if (!strcmp(model,"3320AF")) { + height = 1536; + raw_width = width = 2048; + filters = 0x61616161; + load_raw = &CLASS unpacked_load_raw; + maximum = 0x3ff; + fseek (ifp, 0x300000, SEEK_SET); + if ((order = guess_byte_order(0x10000)) == 0x4d4d) { + height -= (top_margin = 16); + width -= (left_margin = 28); + maximum = 0xf5c0; + strcpy (make, "ISG"); + model[0] = 0; + } + } else if (!strcmp(make,"Hasselblad")) { + if (load_raw == &CLASS lossless_jpeg_load_raw) + load_raw = &CLASS hasselblad_load_raw; + if (raw_width == 7262) { + height = 5444; + width = 7248; + top_margin = 4; + left_margin = 7; + filters = 0x61616161; + } else if (raw_width == 4090) { + strcpy (model, "V96C"); + height -= (top_margin = 6); + width -= (left_margin = 3) + 7; + filters = 0x61616161; + } + } else if (!strcmp(make,"Sinar")) { + if (!memcmp(head,"8BPS",4)) { + fseek (ifp, 14, SEEK_SET); + height = get4(); + width = get4(); + filters = 0x61616161; + data_offset = 68; + } + if (!load_raw) load_raw = &CLASS unpacked_load_raw; + maximum = 0x3fff; + } else if (!strcmp(make,"Leaf")) { + maximum = 0x3fff; + fseek (ifp, data_offset, SEEK_SET); + if (ljpeg_start (&jh, 1) && jh.bits == 15) + maximum = 0x1fff; + if (tiff_samples > 1) filters = 0; + if (tiff_samples > 1 || tile_length < raw_height) + load_raw = &CLASS leaf_hdr_load_raw; + if ((width | height) == 2048) { + if (tiff_samples == 1) { + filters = 1; + strcpy (cdesc, "RBTG"); + strcpy (model, "CatchLight"); + top_margin = 8; left_margin = 18; height = 2032; width = 2016; + } else { + strcpy (model, "DCB2"); + top_margin = 10; left_margin = 16; height = 2028; width = 2022; + } + } else if (width+height == 3144+2060) { + if (!model[0]) strcpy (model, "Cantare"); + if (width > height) { + top_margin = 6; left_margin = 32; height = 2048; width = 3072; + filters = 0x61616161; + } else { + left_margin = 6; top_margin = 32; width = 2048; height = 3072; + filters = 0x16161616; + } + if (!cam_mul[0] || model[0] == 'V') filters = 0; + else is_raw = tiff_samples; + } else if (width == 2116) { + strcpy (model, "Valeo 6"); + height -= 2 * (top_margin = 30); + width -= 2 * (left_margin = 55); + filters = 0x49494949; + } else if (width == 3171) { + strcpy (model, "Valeo 6"); + height -= 2 * (top_margin = 24); + width -= 2 * (left_margin = 24); + filters = 0x16161616; + } + } else if (!strcmp(make,"LEICA") || !strcmp(make,"Panasonic")) { + maximum = 0xfff0; + if ((fsize-data_offset) / (width*8/7) == height) + load_raw = &CLASS panasonic_load_raw; + if (!load_raw) load_raw = &CLASS unpacked_load_raw; + switch (width) { + case 2568: + adobe_coeff ("Panasonic","DMC-LC1"); break; + case 3130: + left_margin = -14; + case 3170: + left_margin += 18; + width = 3096; + if (height > 2326) { + height = 2326; + top_margin = 13; + filters = 0x49494949; + } + zero_is_bad = 1; + adobe_coeff ("Panasonic","DMC-FZ8"); break; + case 3213: + width -= 27; + case 3177: + width -= 10; + filters = 0x49494949; + zero_is_bad = 1; + adobe_coeff ("Panasonic","DMC-L1"); break; + case 3304: + width -= 17; + zero_is_bad = 1; + adobe_coeff ("Panasonic","DMC-FZ30"); break; + case 3330: + width += 43; + left_margin = -6; + maximum = 0xf7f0; + case 3370: + width -= 82; + left_margin += 15; + if (height > 2480) + height = 2480 - (top_margin = 10); + filters = 0x49494949; + zero_is_bad = 1; + adobe_coeff ("Panasonic","DMC-FZ18"); break; + case 3690: + height -= 2; + left_margin = -14; + maximum = 0xf7f0; + case 3770: + width = 3672; + if (--height == 2798 && (height = 2760)) + top_margin = 15; + else filters = 0x49494949; + left_margin += 17; + zero_is_bad = 1; + adobe_coeff ("Panasonic","DMC-FZ50"); break; + case 3710: + width = 3682; + filters = 0x49494949; + adobe_coeff ("Panasonic","DMC-L10"); break; + case 3724: + width -= 14; + if (height == 2450) height -= 2; + case 3836: + width -= 42; +lx3: filters = 0x16161616; + if (make[0] != 'P') + adobe_coeff ("Panasonic","DMC-LX3"); + break; + case 3880: + width -= 22; + left_margin = 6; + zero_is_bad = 1; + adobe_coeff ("Panasonic","DMC-LX1"); break; + case 4060: + width = 3982; + if (height == 2250) goto lx3; + width = 4018; + filters = 0x16161616; + if (!strncmp(model,"DMC-FZ3",7)) { + height -= 2; + adobe_coeff ("Panasonic","DMC-FZ35"); break; + } + filters = 0x49494949; + if (!strcmp(model,"DMC-GH1")) break; + zero_is_bad = 1; + adobe_coeff ("Panasonic","DMC-G1"); break; + case 4172: + case 4396: + width -= 28; + filters = 0x49494949; + adobe_coeff ("Panasonic","DMC-GH1"); break; + case 4290: + height += 38; + left_margin = -14; + filters = 0x49494949; + case 4330: + width = 4248; + if ((height -= 39) == 2400) + top_margin = 15; + left_margin += 17; + adobe_coeff ("Panasonic","DMC-LX2"); break; + case 4508: + height -= 6; + width = 4429; + filters = 0x16161616; + adobe_coeff ("Panasonic","DMC-FX150"); break; + } + } else if (!strcmp(model,"C770UZ")) { + height = 1718; + width = 2304; + filters = 0x16161616; + load_raw = &CLASS packed_load_raw; + load_flags = 30; + } else if (!strcmp(make,"OLYMPUS")) { + height += height & 1; + filters = exif_cfa; + if (width == 4100) width -= 4; + if (load_raw == &CLASS olympus_load_raw) { + tiff_bps = 12; + black >>= 4; + } else if (!strcmp(model,"E-10") || + !strncmp(model,"E-20",4)) { + black <<= 2; + } else if (!strcmp(model,"E-300") || + !strcmp(model,"E-500")) { + width -= 20; + if (load_raw == &CLASS unpacked_load_raw) { + maximum = 0xfc30; + black = 0; + } + } else if (!strcmp(model,"E-330")) { + width -= 30; + if (load_raw == &CLASS unpacked_load_raw) + maximum = 0xf790; + } else if (!strcmp(model,"SP550UZ")) { + thumb_length = fsize - (thumb_offset = 0xa39800); + thumb_height = 480; + thumb_width = 640; + } + } else if (!strcmp(model,"N Digital")) { + height = 2047; + width = 3072; + filters = 0x61616161; + data_offset = 0x1a00; + load_raw = &CLASS packed_load_raw; + } else if (!strcmp(model,"DSC-F828")) { + width = 3288; + left_margin = 5; + data_offset = 862144; + load_raw = &CLASS sony_load_raw; + filters = 0x9c9c9c9c; + colors = 4; + strcpy (cdesc, "RGBE"); + } else if (!strcmp(model,"DSC-V3")) { + width = 3109; + left_margin = 59; + data_offset = 787392; + load_raw = &CLASS sony_load_raw; + } else if (!strcmp(make,"SONY") && raw_width == 3984) { + adobe_coeff ("SONY","DSC-R1"); + width = 3925; + order = 0x4d4d; + } else if (!strcmp(model,"DSLR-A100")) { + height--; + width = ++raw_width; + filters = 0x61616161; + } else if (!strcmp(model,"DSLR-A350")) { + height -= 4; + } else if (!strcmp(model,"PIXL")) { + height -= top_margin = 4; + width -= left_margin = 32; + gamma_curve (0, 7, 1, 255); + } else if (!strcmp(model,"C603v")) { + height = 480; + width = 640; + if (fsize < 614400 || find_green (16, 16, 3840, 5120) < 25) goto c603v; + strcpy (model,"KAI-0340"); + height -= 3; + data_offset = 3840; + order = 0x4949; + load_raw = &CLASS unpacked_load_raw; + } else if (!strcmp(model,"C603y")) { + height = 2134; + width = 2848; +c603v: + filters = 0; + load_raw = &CLASS kodak_yrgb_load_raw; + gamma_curve (0, 3.875, 1, 255); + } else if (!strcmp(model,"C603")) { + raw_height = height = 2152; + raw_width = width = 2864; + goto c603; + } else if (!strcmp(model,"C330")) { + height = 1744; + width = 2336; + raw_height = 1779; + raw_width = 2338; + top_margin = 33; + left_margin = 1; +c603: + order = 0x4949; + if ((data_offset = fsize - raw_height*raw_width)) { + fseek (ifp, 168, SEEK_SET); + read_shorts (curve, 256); + } else gamma_curve (0, 3.875, 1, 255); + load_raw = &CLASS eight_bit_load_raw; + } else if (!strcmp(model,"EASYSHARE Z1015 IS")) { + height = 2742; + width = 3664; + goto ezshare; + } else if (!strcmp(model,"EasyShare Z980")) { + height = 3006; + width = 4016; +ezshare: + data_offset = 0x15000; + load_raw = &CLASS packed_load_raw; + } else if (!strcasecmp(make,"KODAK")) { + if (filters == UINT_MAX) filters = 0x61616161; + if (!strncmp(model,"NC2000",6)) { + width -= 4; + left_margin = 2; + } else if (!strcmp(model,"EOSDCS3B")) { + width -= 4; + left_margin = 2; + } else if (!strcmp(model,"EOSDCS1")) { + width -= 4; + left_margin = 2; + } else if (!strcmp(model,"DCS420")) { + width -= 4; + left_margin = 2; + } else if (!strncmp(model,"DCS460 ",7)) { + model[6] = 0; + width -= 4; + left_margin = 2; + } else if (!strcmp(model,"DCS460A")) { + width -= 4; + left_margin = 2; + colors = 1; + filters = 0; + } else if (!strcmp(model,"DCS660M")) { + black = 214; + colors = 1; + filters = 0; + } else if (!strcmp(model,"DCS760M")) { + colors = 1; + filters = 0; + } + if (!strcmp(model+4,"20X")) + strcpy (cdesc, "MYCY"); + if (strstr(model,"DC25")) { + strcpy (model, "DC25"); + data_offset = 15424; + } + if (!strncmp(model,"DC2",3)) { + height = 242; + if (fsize < 100000) { + raw_width = 256; width = 249; + pixel_aspect = (4.0*height) / (3.0*width); + } else { + raw_width = 512; width = 501; + pixel_aspect = (493.0*height) / (373.0*width); + } + data_offset += raw_width + 1; + colors = 4; + filters = 0x8d8d8d8d; + simple_coeff(1); + pre_mul[1] = 1.179; + pre_mul[2] = 1.209; + pre_mul[3] = 1.036; + load_raw = &CLASS eight_bit_load_raw; + } else if (!strcmp(model,"40")) { + strcpy (model, "DC40"); + height = 512; + width = 768; + data_offset = 1152; + load_raw = &CLASS kodak_radc_load_raw; + } else if (strstr(model,"DC50")) { + strcpy (model, "DC50"); + height = 512; + width = 768; + data_offset = 19712; + load_raw = &CLASS kodak_radc_load_raw; + } else if (strstr(model,"DC120")) { + strcpy (model, "DC120"); + height = 976; + width = 848; + pixel_aspect = height/0.75/width; + load_raw = tiff_compress == 7 ? + &CLASS kodak_jpeg_load_raw : &CLASS kodak_dc120_load_raw; + } else if (!strcmp(model,"DCS200")) { + thumb_height = 128; + thumb_width = 192; + thumb_offset = 6144; + thumb_misc = 360; + write_thumb = &CLASS layer_thumb; + height = 1024; + width = 1536; + data_offset = 79872; + load_raw = &CLASS eight_bit_load_raw; + black = 17; + } + } else if (!strcmp(model,"Fotoman Pixtura")) { + height = 512; + width = 768; + data_offset = 3632; + load_raw = &CLASS kodak_radc_load_raw; + filters = 0x61616161; + simple_coeff(2); + } else if (!strcmp(model,"QuickTake 100")) { + fseek (ifp, 544, SEEK_SET); + height = get2(); + width = get2(); + data_offset = (get4(),get2()) == 30 ? 738:736; + if (height > width) { + SWAP(height,width); + fseek (ifp, data_offset-6, SEEK_SET); + flip = ~get2() & 3 ? 5:6; + } + load_raw = &CLASS quicktake_100_load_raw; + filters = 0x61616161; + } else if (!strcmp(model,"QuickTake 150")) { + data_offset = 738 - head[5]; + if (head[5]) strcpy (model+10, "200"); + load_raw = &CLASS kodak_radc_load_raw; + height = 480; + width = 640; + filters = 0x61616161; + } else if (!strcmp(make,"Rollei") && !load_raw) { + switch (raw_width) { + case 1316: + height = 1030; + width = 1300; + top_margin = 1; + left_margin = 6; + break; + case 2568: + height = 1960; + width = 2560; + top_margin = 2; + left_margin = 8; + } + filters = 0x16161616; + load_raw = &CLASS rollei_load_raw; + } else if (!strcmp(model,"PC-CAM 600")) { + height = 768; + data_offset = width = 1024; + filters = 0x49494949; + load_raw = &CLASS eight_bit_load_raw; + } else if (!strcmp(model,"QV-2000UX")) { + height = 1208; + width = 1632; + data_offset = width * 2; + load_raw = &CLASS eight_bit_load_raw; + } else if (fsize == 3217760) { + height = 1546; + width = 2070; + raw_width = 2080; + load_raw = &CLASS eight_bit_load_raw; + } else if (!strcmp(model,"QV-4000")) { + height = 1700; + width = 2260; + load_raw = &CLASS unpacked_load_raw; + maximum = 0xffff; + } else if (!strcmp(model,"QV-5700")) { + height = 1924; + width = 2576; + raw_width = 3232; + tiff_bps = 10; + } else if (!strcmp(model,"QV-R41")) { + height = 1720; + width = 2312; + raw_width = 3520; + left_margin = 2; + } else if (!strcmp(model,"QV-R51")) { + height = 1926; + width = 2580; + raw_width = 3904; + } else if (!strcmp(model,"EX-S20")) { + height = 1208; + width = 1620; + raw_width = 2432; + flip = 3; + } else if (!strcmp(model,"EX-S100")) { + height = 1544; + width = 2058; + raw_width = 3136; + } else if (!strcmp(model,"EX-Z50")) { + height = 1931; + width = 2570; + raw_width = 3904; + } else if (!strcmp(model,"EX-Z55")) { + height = 1960; + width = 2570; + raw_width = 3904; + } else if (!strcmp(model,"EX-Z60")) { + height = 2145; + width = 2833; + raw_width = 3584; + filters = 0x16161616; + tiff_bps = 10; + } else if (!strcmp(model,"EX-Z75")) { + height = 2321; + width = 3089; + raw_width = 4672; + maximum = 0xfff; + } else if (!strcmp(model,"EX-Z750")) { + height = 2319; + width = 3087; + raw_width = 4672; + maximum = 0xfff; + } else if (!strcmp(model,"EX-Z850")) { + height = 2468; + width = 3279; + raw_width = 4928; + maximum = 0xfff; + } else if (!strcmp(model,"EX-P505")) { + height = 1928; + width = 2568; + raw_width = 3852; + maximum = 0xfff; + } else if (fsize == 9313536) { /* EX-P600 or QV-R61 */ + height = 2142; + width = 2844; + raw_width = 4288; + } else if (!strcmp(model,"EX-P700")) { + height = 2318; + width = 3082; + raw_width = 4672; + } + if (!model[0]) + sprintf (model, "%dx%d", width, height); + if (filters == UINT_MAX) filters = 0x94949494; + if (raw_color) adobe_coeff (make, model); + if (load_raw == &CLASS kodak_radc_load_raw) + if (raw_color) adobe_coeff ("Apple","Quicktake"); + if (thumb_offset && !thumb_height) { + fseek (ifp, thumb_offset, SEEK_SET); + if (ljpeg_start (&jh, 1)) { + thumb_width = jh.wide; + thumb_height = jh.high; + } + } +dng_skip: + if (!tiff_bps) tiff_bps = 12; + if (!maximum) maximum = (1 << tiff_bps) - 1; + if (!load_raw || height < 22) is_raw = 0; +#ifdef NO_JPEG + if (load_raw == &CLASS kodak_jpeg_load_raw) { + fprintf (stderr,_("%s: You must link dcraw with libjpeg!!\n"), ifname); + is_raw = 0; + } +#endif + if (!cdesc[0]) + strcpy (cdesc, colors == 3 ? "RGB":"GMCY"); + if (!raw_height) raw_height = height; + if (!raw_width ) raw_width = width; + if (filters && colors == 3) + for (i=0; i < 32; i+=4) { + if ((filters >> i & 15) == 9) + filters |= 2 << i; + if ((filters >> i & 15) == 6) + filters |= 8 << i; + } +notraw: + if (flip == -1) flip = tiff_flip; + if (flip == -1) flip = 0; +} + +#ifndef NO_LCMS +void CLASS apply_profile (const char *input, const char *output) +{ + char *prof; + cmsHPROFILE hInProfile=0, hOutProfile=0; + cmsHTRANSFORM hTransform; + FILE *fp; + unsigned size; + + cmsErrorAction (LCMS_ERROR_SHOW); + if (strcmp (input, "embed")) + hInProfile = cmsOpenProfileFromFile (input, "r"); + else if (profile_length) { + prof = (char *) malloc (profile_length); + merror (prof, "apply_profile()"); + fseek (ifp, profile_offset, SEEK_SET); + fread (prof, 1, profile_length, ifp); + hInProfile = cmsOpenProfileFromMem (prof, profile_length); + free (prof); + } else + fprintf (stderr,_("%s has no embedded profile.\n"), ifname); + if (!hInProfile) return; + if (!output) + hOutProfile = cmsCreate_sRGBProfile(); + else if ((fp = fopen (output, "rb"))) { + fread (&size, 4, 1, fp); + fseek (fp, 0, SEEK_SET); + oprof = (unsigned *) malloc (size = ntohl(size)); + merror (oprof, "apply_profile()"); + fread (oprof, 1, size, fp); + fclose (fp); + if (!(hOutProfile = cmsOpenProfileFromMem (oprof, size))) { + free (oprof); + oprof = 0; + } + } else + fprintf (stderr,_("Cannot open file %s!\n"), output); + if (!hOutProfile) goto quit; + if (verbose) + fprintf (stderr,_("Applying color profile...\n")); + hTransform = cmsCreateTransform (hInProfile, TYPE_RGBA_16, + hOutProfile, TYPE_RGBA_16, INTENT_PERCEPTUAL, 0); + cmsDoTransform (hTransform, image, image, width*height); + raw_color = 1; /* Don't use rgb_cam with a profile */ + cmsDeleteTransform (hTransform); + cmsCloseProfile (hOutProfile); +quit: + cmsCloseProfile (hInProfile); +} +#endif + +void CLASS convert_to_rgb() +{ + int row, col, c, i, j, k; + ushort *img; + float out[3], out_cam[3][4]; + double num, inverse[3][3]; + static const double xyzd50_srgb[3][3] = + { { 0.436083, 0.385083, 0.143055 }, + { 0.222507, 0.716888, 0.060608 }, + { 0.013930, 0.097097, 0.714022 } }; + static const double rgb_rgb[3][3] = + { { 1,0,0 }, { 0,1,0 }, { 0,0,1 } }; + static const double adobe_rgb[3][3] = + { { 0.715146, 0.284856, 0.000000 }, + { 0.000000, 1.000000, 0.000000 }, + { 0.000000, 0.041166, 0.958839 } }; + static const double wide_rgb[3][3] = + { { 0.593087, 0.404710, 0.002206 }, + { 0.095413, 0.843149, 0.061439 }, + { 0.011621, 0.069091, 0.919288 } }; + static const double prophoto_rgb[3][3] = + { { 0.529317, 0.330092, 0.140588 }, + { 0.098368, 0.873465, 0.028169 }, + { 0.016879, 0.117663, 0.865457 } }; + static const double (*out_rgb[])[3] = + { rgb_rgb, adobe_rgb, wide_rgb, prophoto_rgb, xyz_rgb }; + static const char *name[] = + { "sRGB", "Adobe RGB (1998)", "WideGamut D65", "ProPhoto D65", "XYZ" }; + static const unsigned phead[] = + { 1024, 0, 0x2100000, 0x6d6e7472, 0x52474220, 0x58595a20, 0, 0, 0, + 0x61637370, 0, 0, 0x6e6f6e65, 0, 0, 0, 0, 0xf6d6, 0x10000, 0xd32d }; + unsigned pbody[] = + { 10, 0x63707274, 0, 36, /* cprt */ + 0x64657363, 0, 40, /* desc */ + 0x77747074, 0, 20, /* wtpt */ + 0x626b7074, 0, 20, /* bkpt */ + 0x72545243, 0, 14, /* rTRC */ + 0x67545243, 0, 14, /* gTRC */ + 0x62545243, 0, 14, /* bTRC */ + 0x7258595a, 0, 20, /* rXYZ */ + 0x6758595a, 0, 20, /* gXYZ */ + 0x6258595a, 0, 20 }; /* bXYZ */ + static const unsigned pwhite[] = { 0xf351, 0x10000, 0x116cc }; + unsigned pcurve[] = { 0x63757276, 0, 1, 0x1000000 }; + + gamma_curve (gamm[0], gamm[1], 0, 0); + memcpy (out_cam, rgb_cam, sizeof out_cam); + raw_color |= colors == 1 || document_mode || + output_color < 1 || output_color > 5; + if (!raw_color) { + oprof = (unsigned *) calloc (phead[0], 1); + merror (oprof, "convert_to_rgb()"); + memcpy (oprof, phead, sizeof phead); + if (output_color == 5) oprof[4] = oprof[5]; + oprof[0] = 132 + 12*pbody[0]; + for (i=0; i < pbody[0]; i++) { + oprof[oprof[0]/4] = i ? (i > 1 ? 0x58595a20 : 0x64657363) : 0x74657874; + pbody[i*3+2] = oprof[0]; + oprof[0] += (pbody[i*3+3] + 3) & -4; + } + memcpy (oprof+32, pbody, sizeof pbody); + oprof[pbody[5]/4+2] = strlen(name[output_color-1]) + 1; + memcpy ((char *)oprof+pbody[8]+8, pwhite, sizeof pwhite); + pcurve[3] = (short)(256/gamm[5]+0.5) << 16; + for (i=4; i < 7; i++) + memcpy ((char *)oprof+pbody[i*3+2], pcurve, sizeof pcurve); + pseudoinverse ((double (*)[3]) out_rgb[output_color-1], inverse, 3); + for (i=0; i < 3; i++) + for (j=0; j < 3; j++) { + for (num = k=0; k < 3; k++) + num += xyzd50_srgb[i][k] * inverse[j][k]; + oprof[pbody[j*3+23]/4+i+2] = num * 0x10000 + 0.5; + } + for (i=0; i < phead[0]/4; i++) + oprof[i] = htonl(oprof[i]); + strcpy ((char *)oprof+pbody[2]+8, "auto-generated by dcraw"); + strcpy ((char *)oprof+pbody[5]+12, name[output_color-1]); + for (i=0; i < 3; i++) + for (j=0; j < colors; j++) + for (out_cam[i][j] = k=0; k < 3; k++) + out_cam[i][j] += out_rgb[output_color-1][i][k] * rgb_cam[k][j]; + } + if (verbose) + fprintf (stderr, raw_color ? _("Building histograms...\n") : + _("Converting to %s colorspace...\n"), name[output_color-1]); + + memset (histogram, 0, sizeof histogram); + for (img=image[0], row=0; row < height; row++) + for (col=0; col < width; col++, img+=4) { + if (!raw_color) { + out[0] = out[1] = out[2] = 0; + FORCC { + out[0] += out_cam[0][c] * img[c]; + out[1] += out_cam[1][c] * img[c]; + out[2] += out_cam[2][c] * img[c]; + } + FORC3 img[c] = CLIP((int) out[c]); + } + else if (document_mode) + img[0] = img[FC(row,col)]; + FORCC histogram[c][img[c] >> 3]++; + } + if (colors == 4 && output_color) colors = 3; + if (document_mode && filters) colors = 1; +} + +void CLASS fuji_rotate() +{ + int i, row, col; + double step; + float r, c, fr, fc; + unsigned ur, uc; + ushort wide, high, (*img)[4], (*pix)[4]; + + if (!fuji_width) return; + if (verbose) + fprintf (stderr,_("Rotating image 45 degrees...\n")); + fuji_width = (fuji_width - 1 + shrink) >> shrink; + step = sqrt(0.5); + wide = fuji_width / step; + high = (height - fuji_width) / step; + img = (ushort (*)[4]) calloc (wide*high, sizeof *img); + merror (img, "fuji_rotate()"); + + for (row=0; row < high; row++) + for (col=0; col < wide; col++) { + ur = r = fuji_width + (row-col)*step; + uc = c = (row+col)*step; + if (ur > height-2 || uc > width-2) continue; + fr = r - ur; + fc = c - uc; + pix = image + ur*width + uc; + for (i=0; i < colors; i++) + img[row*wide+col][i] = + (pix[ 0][i]*(1-fc) + pix[ 1][i]*fc) * (1-fr) + + (pix[width][i]*(1-fc) + pix[width+1][i]*fc) * fr; + } + free (image); + width = wide; + height = high; + image = img; + fuji_width = 0; +} + +void CLASS stretch() +{ + ushort newdim, (*img)[4], *pix0, *pix1; + int row, col, c; + double rc, frac; + + if (pixel_aspect == 1) return; + if (verbose) fprintf (stderr,_("Stretching the image...\n")); + if (pixel_aspect < 1) { + newdim = height / pixel_aspect + 0.5; + img = (ushort (*)[4]) calloc (width*newdim, sizeof *img); + merror (img, "stretch()"); + for (rc=row=0; row < newdim; row++, rc+=pixel_aspect) { + frac = rc - (c = rc); + pix0 = pix1 = image[c*width]; + if (c+1 < height) pix1 += width*4; + for (col=0; col < width; col++, pix0+=4, pix1+=4) + FORCC img[row*width+col][c] = pix0[c]*(1-frac) + pix1[c]*frac + 0.5; + } + height = newdim; + } else { + newdim = width * pixel_aspect + 0.5; + img = (ushort (*)[4]) calloc (height*newdim, sizeof *img); + merror (img, "stretch()"); + for (rc=col=0; col < newdim; col++, rc+=1/pixel_aspect) { + frac = rc - (c = rc); + pix0 = pix1 = image[c]; + if (c+1 < width) pix1 += 4; + for (row=0; row < height; row++, pix0+=width*4, pix1+=width*4) + FORCC img[row*newdim+col][c] = pix0[c]*(1-frac) + pix1[c]*frac + 0.5; + } + width = newdim; + } + free (image); + image = img; +} + +int CLASS flip_index (int row, int col) +{ + if (flip & 4) SWAP(row,col); + if (flip & 2) row = iheight - 1 - row; + if (flip & 1) col = iwidth - 1 - col; + return row * iwidth + col; +} + +struct tiff_tag { + ushort tag, type; + int count; + union { char c[4]; short s[2]; int i; } val; +}; + +struct tiff_hdr { + ushort order, magic; + int ifd; + ushort pad, ntag; + struct tiff_tag tag[23]; + int nextifd; + ushort pad2, nexif; + struct tiff_tag exif[4]; + ushort pad3, ngps; + struct tiff_tag gpst[10]; + short bps[4]; + int rat[10]; + unsigned gps[26]; + char desc[512], make[64], model[64], soft[32], date[20], artist[64]; +}; + +void CLASS tiff_set (ushort *ntag, + ushort tag, ushort type, int count, int val) +{ + struct tiff_tag *tt; + int c; + + tt = (struct tiff_tag *)(ntag+1) + (*ntag)++; + tt->tag = tag; + tt->type = type; + tt->count = count; + if (type < 3 && count <= 4) + FORC(4) tt->val.c[c] = val >> (c << 3); + else if (type == 3 && count <= 2) + FORC(2) tt->val.s[c] = val >> (c << 4); + else tt->val.i = val; +} + +#define TOFF(ptr) ((char *)(&(ptr)) - (char *)th) + +void CLASS tiff_head (struct tiff_hdr *th, int full) +{ + int c, psize=0; + struct tm *t; + + memset (th, 0, sizeof *th); + th->order = htonl(0x4d4d4949) >> 16; + th->magic = 42; + th->ifd = 10; + if (full) { + tiff_set (&th->ntag, 254, 4, 1, 0); + tiff_set (&th->ntag, 256, 4, 1, width); + tiff_set (&th->ntag, 257, 4, 1, height); + tiff_set (&th->ntag, 258, 3, colors, output_bps); + if (colors > 2) + th->tag[th->ntag-1].val.i = TOFF(th->bps); + FORC4 th->bps[c] = output_bps; + tiff_set (&th->ntag, 259, 3, 1, 1); + tiff_set (&th->ntag, 262, 3, 1, 1 + (colors > 1)); + } + tiff_set (&th->ntag, 270, 2, 512, TOFF(th->desc)); + tiff_set (&th->ntag, 271, 2, 64, TOFF(th->make)); + tiff_set (&th->ntag, 272, 2, 64, TOFF(th->model)); + if (full) { + if (oprof) psize = ntohl(oprof[0]); + tiff_set (&th->ntag, 273, 4, 1, sizeof *th + psize); + tiff_set (&th->ntag, 277, 3, 1, colors); + tiff_set (&th->ntag, 278, 4, 1, height); + tiff_set (&th->ntag, 279, 4, 1, height*width*colors*output_bps/8); + } else + tiff_set (&th->ntag, 274, 3, 1, "12435867"[flip]-'0'); + tiff_set (&th->ntag, 282, 5, 1, TOFF(th->rat[0])); + tiff_set (&th->ntag, 283, 5, 1, TOFF(th->rat[2])); + tiff_set (&th->ntag, 284, 3, 1, 1); + tiff_set (&th->ntag, 296, 3, 1, 2); + tiff_set (&th->ntag, 305, 2, 32, TOFF(th->soft)); + tiff_set (&th->ntag, 306, 2, 20, TOFF(th->date)); + tiff_set (&th->ntag, 315, 2, 64, TOFF(th->artist)); + tiff_set (&th->ntag, 34665, 4, 1, TOFF(th->nexif)); + if (psize) tiff_set (&th->ntag, 34675, 7, psize, sizeof *th); + tiff_set (&th->nexif, 33434, 5, 1, TOFF(th->rat[4])); + tiff_set (&th->nexif, 33437, 5, 1, TOFF(th->rat[6])); + tiff_set (&th->nexif, 34855, 3, 1, iso_speed); + tiff_set (&th->nexif, 37386, 5, 1, TOFF(th->rat[8])); + if (gpsdata[1]) { + tiff_set (&th->ntag, 34853, 4, 1, TOFF(th->ngps)); + tiff_set (&th->ngps, 0, 1, 4, 0x202); + tiff_set (&th->ngps, 1, 2, 2, gpsdata[29]); + tiff_set (&th->ngps, 2, 5, 3, TOFF(th->gps[0])); + tiff_set (&th->ngps, 3, 2, 2, gpsdata[30]); + tiff_set (&th->ngps, 4, 5, 3, TOFF(th->gps[6])); + tiff_set (&th->ngps, 5, 1, 1, gpsdata[31]); + tiff_set (&th->ngps, 6, 5, 1, TOFF(th->gps[18])); + tiff_set (&th->ngps, 7, 5, 3, TOFF(th->gps[12])); + tiff_set (&th->ngps, 18, 2, 12, TOFF(th->gps[20])); + tiff_set (&th->ngps, 29, 2, 12, TOFF(th->gps[23])); + memcpy (th->gps, gpsdata, sizeof th->gps); + } + th->rat[0] = th->rat[2] = 300; + th->rat[1] = th->rat[3] = 1; + FORC(6) th->rat[4+c] = 1000000; + th->rat[4] *= shutter; + th->rat[6] *= aperture; + th->rat[8] *= focal_len; + strncpy (th->desc, desc, 512); + strncpy (th->make, make, 64); + strncpy (th->model, model, 64); + strcpy (th->soft, "dcraw v"VERSION); + t = gmtime (×tamp); + sprintf (th->date, "%04d:%02d:%02d %02d:%02d:%02d", + t->tm_year+1900,t->tm_mon+1,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec); + strncpy (th->artist, artist, 64); +} + +void CLASS jpeg_thumb() +{ + char *thumb; + ushort exif[5]; + struct tiff_hdr th; + + thumb = (char *) malloc (thumb_length); + merror (thumb, "jpeg_thumb()"); + fread (thumb, 1, thumb_length, ifp); + fputc (0xff, ofp); + fputc (0xd8, ofp); + if (strcmp (thumb+6, "Exif")) { + memcpy (exif, "\xff\xe1 Exif\0\0", 10); + exif[1] = htons (8 + sizeof th); + fwrite (exif, 1, sizeof exif, ofp); + tiff_head (&th, 0); + fwrite (&th, 1, sizeof th, ofp); + } + fwrite (thumb+2, 1, thumb_length-2, ofp); + free (thumb); +} + +void CLASS write_ppm_tiff() +{ + struct tiff_hdr th; + uchar *ppm; + ushort *ppm2; + int c, row, col, soff, rstep, cstep; + int perc, val, total, white=0x2000; + + perc = width * height * 0.01; /* 99th percentile white level */ + if (fuji_width) perc /= 2; + if (!((highlight & ~2) || no_auto_bright)) + for (white=c=0; c < colors; c++) { + for (val=0x2000, total=0; --val > 32; ) + if ((total += histogram[c][val]) > perc) break; + if (white < val) white = val; + } + gamma_curve (gamm[0], gamm[1], 2, (white << 3)/bright); + iheight = height; + iwidth = width; + if (flip & 4) SWAP(height,width); + ppm = (uchar *) calloc (width, colors*output_bps/8); + ppm2 = (ushort *) ppm; + merror (ppm, "write_ppm_tiff()"); + if (output_tiff) { + tiff_head (&th, 1); + fwrite (&th, sizeof th, 1, ofp); + if (oprof) + fwrite (oprof, ntohl(oprof[0]), 1, ofp); + } else if (colors > 3) + fprintf (ofp, + "P7\nWIDTH %d\nHEIGHT %d\nDEPTH %d\nMAXVAL %d\nTUPLTYPE %s\nENDHDR\n", + width, height, colors, (1 << output_bps)-1, cdesc); + else + fprintf (ofp, "P%d\n%d %d\n%d\n", + colors/2+5, width, height, (1 << output_bps)-1); + soff = flip_index (0, 0); + cstep = flip_index (0, 1) - soff; + rstep = flip_index (1, 0) - flip_index (0, width); + for (row=0; row < height; row++, soff += rstep) { + for (col=0; col < width; col++, soff += cstep) + if (output_bps == 8) + FORCC ppm [col*colors+c] = curve[image[soff][c]] >> 8; + else FORCC ppm2[col*colors+c] = curve[image[soff][c]]; + if (output_bps == 16 && !output_tiff && htons(0x55aa) != 0x55aa) + swab ((char*)ppm2, (char*)ppm2, width*colors*2); + fwrite (ppm, colors*output_bps/8, width, ofp); + } + free (ppm); +} + +/*int CLASS main (int argc, const char **argv) +{ + int arg, status=0; + int timestamp_only=0, thumbnail_only=0, identify_only=0; + int user_qual=-1, user_black=-1, user_sat=-1, user_flip=-1; + int use_fuji_rotate=1, write_to_stdout=0, quality, i, c; + const char *sp, *bpfile=0, *dark_frame=0, *write_ext; + char opm, opt, *ofname, *cp; + struct utimbuf ut; +#ifndef NO_LCMS + const char *cam_profile=0, *out_profile=0; +#endif + +#ifndef LOCALTIME + putenv ((char *) "TZ=UTC"); +#endif +#ifdef LOCALEDIR + setlocale (LC_CTYPE, ""); + setlocale (LC_MESSAGES, ""); + bindtextdomain ("dcraw", LOCALEDIR); + textdomain ("dcraw"); +#endif + + if (argc == 1) { + printf(_("\nRaw photo decoder \"dcraw\" v%s"), VERSION); + printf(_("\nby Dave Coffin, dcoffin a cybercom o net\n")); + printf(_("\nUsage: %s [OPTION]... [FILE]...\n\n"), argv[0]); + puts(_("-v Print verbose messages")); + puts(_("-c Write image data to standard output")); + puts(_("-e Extract embedded thumbnail image")); + puts(_("-i Identify files without decoding them")); + puts(_("-i -v Identify files and show metadata")); + puts(_("-z Change file dates to camera timestamp")); + puts(_("-w Use camera white balance, if possible")); + puts(_("-a Average the whole image for white balance")); + puts(_("-A Average a grey box for white balance")); + puts(_("-r Set custom white balance")); + puts(_("+M/-M Use/don't use an embedded color matrix")); + puts(_("-C Correct chromatic aberration")); + puts(_("-P Fix the dead pixels listed in this file")); + puts(_("-K Subtract dark frame (16-bit raw PGM)")); + puts(_("-k Set the darkness level")); + puts(_("-S Set the saturation level")); + puts(_("-n Set threshold for wavelet denoising")); + puts(_("-H [0-9] Highlight mode (0=clip, 1=unclip, 2=blend, 3+=rebuild)")); + puts(_("-t [0-7] Flip image (0=none, 3=180, 5=90CCW, 6=90CW)")); + puts(_("-o [0-5] Output colorspace (raw,sRGB,Adobe,Wide,ProPhoto,XYZ)")); +#ifndef NO_LCMS + puts(_("-o Apply output ICC profile from file")); + puts(_("-p Apply camera ICC profile from file or \"embed\"")); +#endif + puts(_("-d Document mode (no color, no interpolation)")); + puts(_("-D Document mode without scaling (totally raw)")); + puts(_("-j Don't stretch or rotate raw pixels")); + puts(_("-W Don't automatically brighten the image")); + puts(_("-b Adjust brightness (default = 1.0)")); + puts(_("-g

    Set custom gamma curve (default = 2.222 4.5)")); + puts(_("-q [0-3] Set the interpolation quality")); + puts(_("-h Half-size color image (twice as fast as \"-q 0\")")); + puts(_("-f Interpolate RGGB as four colors")); + puts(_("-m Apply a 3x3 median filter to R-G and B-G")); + puts(_("-s [0..N-1] Select one raw image or \"all\" from each file")); + puts(_("-6 Write 16-bit instead of 8-bit")); + puts(_("-4 Linear 16-bit, same as \"-6 -W -g 1 1\"")); + puts(_("-T Write TIFF instead of PPM")); + puts(""); + return 1; + } + argv[argc] = ""; + for (arg=1; (((opm = argv[arg][0]) - 2) | 2) == '+'; ) { + opt = argv[arg++][1]; + if ((cp = (char *) strchr (sp="nbrkStqmHACg", opt))) + for (i=0; i < "114111111422"[cp-sp]-'0'; i++) + if (!isdigit(argv[arg+i][0])) { + fprintf (stderr,_("Non-numeric argument to \"-%c\"\n"), opt); + return 1; + } + switch (opt) { + case 'n': threshold = atof(argv[arg++]); break; + case 'b': bright = atof(argv[arg++]); break; + case 'r': + FORC4 user_mul[c] = atof(argv[arg++]); break; + case 'C': aber[0] = 1 / atof(argv[arg++]); + aber[2] = 1 / atof(argv[arg++]); break; + case 'g': gamm[0] = atof(argv[arg++]); + gamm[1] = atof(argv[arg++]); + if (gamm[0]) gamm[0] = 1/gamm[0]; break; + case 'k': user_black = atoi(argv[arg++]); break; + case 'S': user_sat = atoi(argv[arg++]); break; + case 't': user_flip = atoi(argv[arg++]); break; + case 'q': user_qual = atoi(argv[arg++]); break; + case 'm': med_passes = atoi(argv[arg++]); break; + case 'H': highlight = atoi(argv[arg++]); break; + case 's': + shot_select = abs(atoi(argv[arg])); + multi_out = !strcmp(argv[arg++],"all"); + break; + case 'o': + if (isdigit(argv[arg][0]) && !argv[arg][1]) + output_color = atoi(argv[arg++]); +#ifndef NO_LCMS + else out_profile = argv[arg++]; + break; + case 'p': cam_profile = argv[arg++]; +#endif + break; + case 'P': bpfile = argv[arg++]; break; + case 'K': dark_frame = argv[arg++]; break; + case 'z': timestamp_only = 1; break; + case 'e': thumbnail_only = 1; break; + case 'i': identify_only = 1; break; + case 'c': write_to_stdout = 1; break; + case 'v': verbose = 1; break; + case 'h': half_size = 1; /* "-h" implies "-f" *//* + case 'f': four_color_rgb = 1; break; + case 'A': FORC4 greybox[c] = atoi(argv[arg++]); + case 'a': use_auto_wb = 1; break; + case 'w': use_camera_wb = 1; break; + case 'M': use_camera_matrix = (opm == '+'); break; + case 'D': + case 'd': document_mode = 1 + (opt == 'D'); + case 'j': use_fuji_rotate = 0; break; + case 'W': no_auto_bright = 1; break; + case 'T': output_tiff = 1; break; + case '4': gamm[0] = gamm[1] = + no_auto_bright = 1; + case '6': output_bps = 16; break; + default: + fprintf (stderr,_("Unknown option \"-%c\".\n"), opt); + return 1; + } + } + if (use_camera_matrix < 0) + use_camera_matrix = use_camera_wb; + if (arg == argc) { + fprintf (stderr,_("No files to process.\n")); + return 1; + } + if (write_to_stdout) { + if (isatty(1)) { + fprintf (stderr,_("Will not write an image to the terminal!\n")); + return 1; + } +#if defined(WIN32) || defined(DJGPP) || defined(__CYGWIN__) + if (setmode(1,O_BINARY) < 0) { + perror ("setmode()"); + return 1; + } +#endif + } + for ( ; arg < argc; arg++) { + status = 1; + image = 0; + oprof = 0; + meta_data = ofname = 0; + ofp = stdout; + if (setjmp (failure)) { + if (fileno(ifp) > 2) fclose(ifp); + if (fileno(ofp) > 2) fclose(ofp); + status = 1; + goto cleanup; + } + ifname = argv[arg]; + if (!(ifp = fopen (ifname, "rb"))) { + perror (ifname); + continue; + } + status = (identify(),!is_raw); + if (user_flip >= 0) + flip = user_flip; + switch ((flip+3600) % 360) { + case 270: flip = 5; break; + case 180: flip = 3; break; + case 90: flip = 6; + } + if (timestamp_only) { + if ((status = !timestamp)) + fprintf (stderr,_("%s has no timestamp.\n"), ifname); + else if (identify_only) + printf ("%10ld%10d %s\n", (long) timestamp, shot_order, ifname); + else { + if (verbose) + fprintf (stderr,_("%s time set to %d.\n"), ifname, (int) timestamp); + ut.actime = ut.modtime = timestamp; + utime (ifname, &ut); + } + goto next; + } + write_fun = &CLASS write_ppm_tiff; + if (thumbnail_only) { + if ((status = !thumb_offset)) { + fprintf (stderr,_("%s has no thumbnail.\n"), ifname); + goto next; + } else if (thumb_load_raw) { + load_raw = thumb_load_raw; + data_offset = thumb_offset; + height = thumb_height; + width = thumb_width; + filters = 0; + } else { + fseek (ifp, thumb_offset, SEEK_SET); + write_fun = write_thumb; + goto thumbnail; + } + } + if (load_raw == &CLASS kodak_ycbcr_load_raw) { + height += height & 1; + width += width & 1; + } + if (identify_only && verbose && make[0]) { + printf (_("\nFilename: %s\n"), ifname); + printf (_("Timestamp: %s"), ctime(×tamp)); + printf (_("Camera: %s %s\n"), make, model); + if (artist[0]) + printf (_("Owner: %s\n"), artist); + if (dng_version) { + printf (_("DNG Version: ")); + for (i=24; i >= 0; i -= 8) + printf ("%d%c", dng_version >> i & 255, i ? '.':'\n'); + } + printf (_("ISO speed: %d\n"), (int) iso_speed); + printf (_("Shutter: ")); + if (shutter > 0 && shutter < 1) + shutter = (printf ("1/"), 1 / shutter); + printf (_("%0.1f sec\n"), shutter); + printf (_("Aperture: f/%0.1f\n"), aperture); + printf (_("Focal length: %0.1f mm\n"), focal_len); + printf (_("Embedded ICC profile: %s\n"), profile_length ? _("yes"):_("no")); + printf (_("Number of raw images: %d\n"), is_raw); + if (pixel_aspect != 1) + printf (_("Pixel Aspect Ratio: %0.6f\n"), pixel_aspect); + if (thumb_offset) + printf (_("Thumb size: %4d x %d\n"), thumb_width, thumb_height); + printf (_("Full size: %4d x %d\n"), raw_width, raw_height); + } else if (!is_raw) + fprintf (stderr,_("Cannot decode file %s\n"), ifname); + if (!is_raw) goto next; + shrink = filters && + (half_size || threshold || aber[0] != 1 || aber[2] != 1); + iheight = (height + shrink) >> shrink; + iwidth = (width + shrink) >> shrink; + if (identify_only) { + if (verbose) { + if (use_fuji_rotate) { + if (fuji_width) { + fuji_width = (fuji_width - 1 + shrink) >> shrink; + iwidth = fuji_width / sqrt(0.5); + iheight = (iheight - fuji_width) / sqrt(0.5); + } else { + if (pixel_aspect < 1) iheight = iheight / pixel_aspect + 0.5; + if (pixel_aspect > 1) iwidth = iwidth * pixel_aspect + 0.5; + } + } + if (flip & 4) + SWAP(iheight,iwidth); + printf (_("Image size: %4d x %d\n"), width, height); + printf (_("Output size: %4d x %d\n"), iwidth, iheight); + printf (_("Raw colors: %d"), colors); + if (filters) { + printf (_("\nFilter pattern: ")); + if (!cdesc[3]) cdesc[3] = 'G'; + for (i=0; i < 16; i++) + putchar (cdesc[fc(i >> 1,i & 1)]); + } + printf (_("\nDaylight multipliers:")); + FORCC printf (" %f", pre_mul[c]); + if (cam_mul[0] > 0) { + printf (_("\nCamera multipliers:")); + FORC4 printf (" %f", cam_mul[c]); + } + putchar ('\n'); + } else + printf (_("%s is a %s %s image.\n"), ifname, make, model); +next: + fclose(ifp); + continue; + } + if (use_camera_matrix && cmatrix[0][0] > 0.25) { + memcpy (rgb_cam, cmatrix, sizeof cmatrix); + raw_color = 0; + } + image = (ushort (*)[4]) calloc (iheight*iwidth, sizeof *image); + merror (image, "main()"); + if (meta_length) { + meta_data = (char *) malloc (meta_length); + merror (meta_data, "main()"); + } + if (verbose) + fprintf (stderr,_("Loading %s %s image from %s ...\n"), + make, model, ifname); + if (shot_select >= is_raw) + fprintf (stderr,_("%s: \"-s %d\" requests a nonexistent image!\n"), + ifname, shot_select); + fseeko (ifp, data_offset, SEEK_SET); + (*load_raw)(); + if (zero_is_bad) remove_zeroes(); + bad_pixels (bpfile); + if (dark_frame) subtract (dark_frame); + quality = 2 + !fuji_width; + if (user_qual >= 0) quality = user_qual; + if (user_black >= 0) black = user_black; + if (user_sat > 0) maximum = user_sat; +#ifdef COLORCHECK + colorcheck(); +#endif + if (is_foveon && !document_mode) foveon_interpolate(); + if (!is_foveon && document_mode < 2) scale_colors(); + pre_interpolate(); + if (filters && !document_mode) { + if (quality == 0) + lin_interpolate(); + else if (quality == 1 || colors > 3) + vng_interpolate(); + else if (quality == 2) + ppg_interpolate(); + else ahd_interpolate(); + } + if (mix_green) + for (colors=3, i=0; i < height*width; i++) + image[i][1] = (image[i][1] + image[i][3]) >> 1; + if (!is_foveon && colors == 3) median_filter(); + if (!is_foveon && highlight == 2) blend_highlights(); + if (!is_foveon && highlight > 2) recover_highlights(); + if (use_fuji_rotate) fuji_rotate(); +#ifndef NO_LCMS + if (cam_profile) apply_profile (cam_profile, out_profile); +#endif + convert_to_rgb(); + if (use_fuji_rotate) stretch(); +thumbnail: + if (write_fun == &CLASS jpeg_thumb) + write_ext = ".jpg"; + else if (output_tiff && write_fun == &CLASS write_ppm_tiff) + write_ext = ".tiff"; + else + write_ext = ".pgm\0.ppm\0.ppm\0.pam" + colors*5-5; + ofname = (char *) malloc (strlen(ifname) + 64); + merror (ofname, "main()"); + if (write_to_stdout) + strcpy (ofname,_("standard output")); + else { + strcpy (ofname, ifname); + if ((cp = strrchr (ofname, '.'))) *cp = 0; + if (multi_out) + sprintf (ofname+strlen(ofname), "_%0*d", + snprintf(0,0,"%d",is_raw-1), shot_select); + if (thumbnail_only) + strcat (ofname, ".thumb"); + strcat (ofname, write_ext); + ofp = fopen (ofname, "wb"); + if (!ofp) { + status = 1; + perror (ofname); + goto cleanup; + } + } + if (verbose) + fprintf (stderr,_("Writing data to %s ...\n"), ofname); + (*write_fun)(); + fclose(ifp); + if (ofp != stdout) fclose(ofp); +cleanup: + if (meta_data) free (meta_data); + if (ofname) free (ofname); + if (oprof) free (oprof); + if (image) free (image); + if (multi_out) { + if (++shot_select < is_raw) arg--; + else shot_select = 0; + } + } + return status; +} +*/ + +#include +#include +#include +#include +#include +#include + +namespace rtengine { + +extern Settings* settings; + +Glib::Mutex* dcrMutex=NULL; + +int loadRaw (const char* fname, struct RawImage *ri) { + + static const double xyzd50_srgb[3][3] = + { { 0.436083, 0.385083, 0.143055 }, + { 0.222507, 0.716888, 0.060608 }, + { 0.013930, 0.097097, 0.714022 } }; + +dcrMutex->lock (); + + ifname = fname;//strdup (fname); + image = NULL; + + exif_base = -1; + ciff_base = -1; + ciff_len = -1; + verbose = settings->verbose; + oprof = NULL; + ri->data = NULL; + ri->allocation = NULL; + ri->profile_data = NULL; + ifp = gfopen (fname); + if (!ifp) { + dcrMutex->unlock (); + return 3; + } + + use_camera_wb = 0; + highlight = 1; + half_size = 0; + + identify (); + use_camera_wb = 1; + if (!is_raw) { + fclose(ifp); + dcrMutex->unlock (); + return 2; + } + + shrink = 0; + + if (settings->verbose) printf ("Loading %s %s image from %s...\n", make, model, fname); + iheight = height; + iwidth = width; + + image = (UshORt (*)[4])calloc (height*width*sizeof *image + meta_length, 1); + meta_data = (char *) (image + height*width); + + if (setjmp (failure)) { + if (image) + free (image); + if (ri->data) + free(ri->data); + fclose (ifp); + dcrMutex->unlock (); + return 100; + } + + fseek (ifp, data_offset, SEEK_SET); + (*load_raw)(); + + ri->profile_len = 0; + ri->profile_data = NULL; + if (profile_length) { + ri->profile_len = profile_length; + ri->profile_data = (char *) malloc (profile_length); + fseek (ifp, profile_offset, SEEK_SET); + fread (ri->profile_data, 1, profile_length, ifp); + } + + fclose(ifp); + if (zero_is_bad) remove_zeroes(); + + ri->red_multiplier = pre_mul[0]; + ri->green_multiplier = pre_mul[1]; + ri->blue_multiplier = pre_mul[2]; + + scale_colors(); + pre_interpolate (); + + ri->width = width; + ri->height = height; + ri->filters = filters; + + if (filters) { + ri->allocation = (short unsigned int*)calloc(height*width, sizeof(unsigned short)); + ri->data = (unsigned short**)calloc(height, sizeof(unsigned short*)); + for (int i=0; idata[i] = ri->allocation + i*width; + for (int row = 0; row < height; row++) + for (int col = 0; col < width; col++) + if (ISGREEN(ri,row,col)) + ri->data[row][col] = image[row*width+col][1]; + else if (ISRED(ri,row,col)) + ri->data[row][col] = image[row*width+col][0]; + else + ri->data[row][col] = image[row*width+col][2]; + } + else { + ri->allocation = (short unsigned int*)calloc(3*height*width, sizeof(unsigned short)); + ri->data = (unsigned short**)calloc(height, sizeof(unsigned short*)); + for (int i=0; idata[i] = ri->allocation + 3*i*width; + for (int row = 0; row < height; row++) + for (int col = 0; col < width; col++) { + ri->data[row][3*col+0] = image[row*width+col][0]; + ri->data[row][3*col+1] = image[row*width+col][1]; + ri->data[row][3*col+2] = image[row*width+col][2]; + } + } + + if (flip==5) + ri->rotate_deg = 270; + else if (flip==3) + ri->rotate_deg = 180; + else if (flip==6) + ri->rotate_deg = 90; + else + ri->rotate_deg = 0; + + ri->make = strdup (make); + ri->model = strdup (model); + + ri->exifbase = exif_base; + ri->prefilters = pre_filters; + ri->ciff_base = ciff_base; + ri->ciff_len = ciff_len; + + ri->camwb_red = ri->red_multiplier / pre_mul[0]; + ri->camwb_green = ri->green_multiplier / pre_mul[1]; + ri->camwb_blue = ri->blue_multiplier / pre_mul[2]; + + ri->defgain = 1.0 / MIN(MIN(pre_mul[0],pre_mul[1]),pre_mul[2]); + + ri->fuji_width = fuji_width; + + for (int a=0; a < 3; a++) + for (int b=0; b < 3; b++) + ri->coeff[a][b] = rgb_cam[a][b]; + + free (image); +dcrMutex->unlock (); + return 0; +} + +int getRawFileBasicInfo (const Glib::ustring& fname, rtengine::RawMetaDataLocation& rml, int& rotation, int& thumbWidth, int& thumbHeight, int& thumbOffset, int& thumbType) { + + int status=0; + +dcrMutex->lock (); + + exif_base = -1; + ciff_base = -1; + ciff_len = -1; + + half_size = 1; + bright = 1.0; + verbose = settings->verbose; + use_camera_wb = 1; + + thumb_length = 0; + thumb_offset = 0; + thumb_load_raw = 0; + status = 1; + + ifname = fname.c_str(); + if (!(ifp = gfopen (ifname))) { + status = 2; + dcrMutex->unlock (); + return status; + } + identify (); + if (!is_raw || colors>3) { + status = 3; + fclose (ifp); + dcrMutex->unlock (); + return status; + } + + thumbOffset = thumb_offset; + + if (flip==5) + rotation = 270; + else if (flip==3) + rotation = 180; + else if (flip==6) + rotation = 90; + else + rotation = 0; + + thumbWidth = thumb_width; + thumbHeight = thumb_height; + if (!thumb_load_raw && thumb_offset && write_thumb == jpeg_thumb) + thumbType = 1; + else if (!thumb_load_raw && thumb_offset && write_thumb == ppm_thumb) + thumbType = 2; + else { + thumbType = 0; + thumbWidth = width; + thumbHeight = height; + } + + rml.exifBase = exif_base; + rml.ciffBase = ciff_base; + rml.ciffLength = ciff_len; + + fclose (ifp); +dcrMutex->unlock (); + return !is_raw; +} + +#include + +rtengine::Thumbnail* rtengine::Thumbnail::loadFromRaw (const Glib::ustring& fname, rtengine::RawMetaDataLocation& rml, int &w, int &h, int fixwh) { + +dcrMutex->lock (); +MyTime t0, t1, t2, t3, t4, t5, t6; +t0.set (); + + image = NULL; + ifname = fname.c_str(); + exif_base = -1; + ciff_base = -1; + ciff_len = -1; + verbose = settings->verbose; + oprof = NULL; + ifp = gfopen (fname.c_str()); + if (!ifp) { + dcrMutex->unlock (); + return NULL; + } + +t1.set (); + + if (setjmp (failure)) { + if (image) + free (image); + fclose (ifp); + dcrMutex->unlock (); + return NULL; + } + + use_camera_wb = 0; + highlight = 1; + half_size = 0; + shrink = 0; + identify (); + use_camera_wb = 1; + if (!is_raw || colors>3) { + fclose(ifp); + dcrMutex->unlock (); + return NULL; + } + +t2.set(); + + iheight = ::height; + iwidth = ::width; + + image = (UshORt (*)[4])calloc (::height*::width*sizeof *image + meta_length, 1); + meta_data = (char *) (image + ::height*::width); + + if (settings->verbose) printf ("Loading %s %s image from %s...\n", make, model, fname.c_str()); + fseek (ifp, data_offset, SEEK_SET); + (*load_raw)(); + if (zero_is_bad) remove_zeroes(); + + rtengine::Thumbnail* tpp = new rtengine::Thumbnail; + + tpp->isRaw = true; + tpp->embProfileLength = 0; + if (profile_length) { + tpp->embProfileLength = profile_length; + tpp->embProfileData = new unsigned char[profile_length]; + fseek (ifp, profile_offset, SEEK_SET); + fread (tpp->embProfileData, 1, profile_length, ifp); + tpp->embProfile = cmsOpenProfileFromMem (tpp->embProfileData, tpp->embProfileLength); + } + else { + tpp->embProfile = NULL; + tpp->embProfileData = NULL; + } + + fclose(ifp); + tpp->redMultiplier = pre_mul[0]; + tpp->greenMultiplier = pre_mul[1]; + tpp->blueMultiplier = pre_mul[2]; + +t3.set (); + + scale_colors(); + pre_interpolate (); + + unsigned filter = filters; + int firstgreen = 1; + // locate first green location in the first row + while (!FISGREEN(filter,1,firstgreen)) + firstgreen++; + + int skip = 1; + if (fixwh==1) // fix height, scale width + skip = (::height-firstgreen-1) / h; + else + skip = (::width-firstgreen-1) / w; + if (skip%2) + skip--; + if (skip<1) + skip = 1; + + int hskip = skip, vskip = skip; + if (!strcmp (model, "D1X")) + hskip *=2; + + rml.exifBase = exif_base; + rml.ciffBase = ciff_base; + rml.ciffLength = ciff_len; + tpp->camwbRed = tpp->redMultiplier / pre_mul[0]; + tpp->camwbGreen = tpp->greenMultiplier / pre_mul[1]; + tpp->camwbBlue = tpp->blueMultiplier / pre_mul[2]; + + tpp->defGain = 1.0 / MIN(MIN(pre_mul[0],pre_mul[1]),pre_mul[2]); + tpp->gammaCorrected = true; + + int ix = 0; + int rofs = 0; + int tmpw = (::width-2)/hskip; + int tmph = (::height-2)/vskip; + Image16* tmpImg = new Image16 (tmpw, tmph); + if (filter) { + for (int row=1, y=0; row< ::height-1 && y> 1; + b = (image[ofs+::width][2] + image[ofs-::width][2]) >> 1; + } + else { + b = (image[ofs+1][2] + image[ofs-1][2]) >> 1; + r = (image[ofs+::width][0] + image[ofs-::width][0]) >> 1; + } + tmpImg->r[y][x] = r; + tmpImg->g[y][x] = g; + tmpImg->b[y][x] = b; + } + } + } + else { + for (int row=1, y=0; row< ::height-1 && yr[y][x] = image[ofs][0]; + tmpImg->g[y][x] = image[ofs][1]; + tmpImg->b[y][x] = image[ofs][2]; + } + } + } + + if (fuji_width) { + int fw = fuji_width / hskip; + double step = sqrt(0.5); + int wide = fw / step; + int high = (tmph - fw) / step; + Image16* fImg = new Image16 (wide, high); + float r, c; + + for (int row=0; row < high; row++) + for (int col=0; col < wide; col++) { + unsigned ur = r = fw + (row-col)*step; + unsigned uc = c = (row+col)*step; + if (ur > tmph-2 || uc > tmpw-2) + continue; + double fr = r - ur; + double fc = c - uc; + int oofs = (ur*tmpw + uc)*3; + int fofs = (row*wide+col)*3; + fImg->r[row][col] = (tmpImg->r[ur][uc] * (1-fc) + tmpImg->r[ur][uc+1] * fc) * (1-fr) + (tmpImg->r[ur+1][uc] * (1-fc) + tmpImg->r[ur+1][uc+1] * fc) * fr; + fImg->g[row][col] = (tmpImg->g[ur][uc] * (1-fc) + tmpImg->g[ur][uc+1] * fc) * (1-fr) + (tmpImg->g[ur+1][uc] * (1-fc) + tmpImg->g[ur+1][uc+1] * fc) * fr; + fImg->b[row][col] = (tmpImg->b[ur][uc] * (1-fc) + tmpImg->b[ur][uc+1] * fc) * (1-fr) + (tmpImg->b[ur+1][uc] * (1-fc) + tmpImg->b[ur+1][uc+1] * fc) * fr; + } + delete tmpImg; + tmpImg = fImg; + } + + + if (fixwh==1) // fix height, scale width + w = tmpw * h / tmph; + else + h = tmph * w / tmpw; + + tpp->thumbImg = tmpImg->resize (w, h, TI_Bilinear); + delete tmpImg; + + if (fuji_width) + tpp->scale = (double)(::height - fuji_width) / sqrt(0.5) / h; + else + tpp->scale = (double)::height / h; + +t4.set (); + + // generate histogram for auto exposure + tpp->aeHistCompression = 3; + tpp->aeHistogram = new int[65536>>tpp->aeHistCompression]; + memset (tpp->aeHistogram, 0, (65536>>tpp->aeHistCompression)*sizeof(int)); + int radd = 4; + int gadd = 2; + int badd = 4; + if (!filter) + radd = gadd = badd = 1; + for (int i=8; i< ::height-8; i++) { + int start, end; + if (fuji_width) { + int fw = fuji_width; + start = ABS(fw-i) + 8; + end = MIN( ::height+ ::width-fw-i, fw+i) - 8; + } + else { + start = 8; + end = ::width-8; + } + for (int j=start; jaeHistogram[image[i* ::width+j][1]>>tpp->aeHistCompression]+=gadd; + else if (FISRED(filter,i,j)) + tpp->aeHistogram[image[i* ::width+j][0]>>tpp->aeHistCompression]+=radd; + else if (FISBLUE(filter,i,j)) + tpp->aeHistogram[image[i* ::width+j][2]>>tpp->aeHistCompression]+=badd; + } + +t5.set (); + + // generate autoWB + double avg_r = 0; + double avg_g = 0; + double avg_b = 0; + int rn = 0, gn = 0, bn = 0; + + for (int i=32; i< ::height-32; i++) { + int start, end; + if (fuji_width) { + int fw = fuji_width; + start = ABS(fw-i) + 32; + end = MIN( ::height+ ::width-fw-i, fw+i) - 32; + } + else { + start = 32; + end = ::width-32; + } + for (int j=start; jdefGain * image[i* ::width+j][1]; + if (d>64000) + continue; + avg_g += d*d*d*d*d*d; + gn++; + } + if (FISRED(filter,i,j)) { + double d = tpp->defGain * image[i* ::width+j][0]; + if (d>64000) + continue; + avg_r += d*d*d*d*d*d; + rn++; + } + if (FISBLUE(filter,i,j)) { + double d = tpp->defGain * image[i* ::width+j][2]; + if (d>64000) + continue; + avg_b += d*d*d*d*d*d; + bn++; + } + } + } + + double reds = pow (avg_r/rn, 1.0/6.0) * tpp->camwbRed; + double greens = pow (avg_g/gn, 1.0/6.0) * tpp->camwbGreen; + double blues = pow (avg_b/bn, 1.0/6.0) * tpp->camwbBlue; + + double rm = rgb_cam[0][0]*reds + rgb_cam[0][1]*greens + rgb_cam[0][2]*blues; + double gm = rgb_cam[1][0]*reds + rgb_cam[1][1]*greens + rgb_cam[1][2]*blues; + double bm = rgb_cam[2][0]*reds + rgb_cam[2][1]*greens + rgb_cam[2][2]*blues; + + ColorTemp::mul2temp (rm, gm, bm, tpp->autowbTemp, tpp->autowbGreen); + +t6.set (); + +if (settings->verbose) printf ("0: %d, 1: %d, 2: %d, 3: %d, 4: %d, 5: %d All: %d\n", t1.etime(t0), t2.etime(t1), t3.etime(t2), t4.etime(t3), t5.etime(t4), t6.etime(t5), t6.etime(t0)); + + int deg = 0; + if (flip==5) + deg = 270; + else if (flip==3) + deg = 180; + else if (flip==6) + deg = 90; + + if (deg>0) { + Image16* rot = tpp->thumbImg->rotate (deg); + delete tpp->thumbImg; + tpp->thumbImg = rot; + } + + for (int a=0; a < 3; a++) + for (int b=0; b < 3; b++) + tpp->colorMatrix[a][b] = rgb_cam[a][b]; + + tpp->init (); + + free (image); + +dcrMutex->unlock (); + + return tpp; +} + + +} + diff --git a/rtengine/dcraw.patch b/rtengine/dcraw.patch new file mode 100755 index 000000000..9b520da4d --- /dev/null +++ b/rtengine/dcraw.patch @@ -0,0 +1,727 @@ +--- dcraw.c 2009-08-31 17:24:29.000000000 +0200 ++++ dcraw.cc 2009-10-09 08:55:28.000000000 +0200 +@@ -1,3 +1,16 @@ ++/*RT*/#include ++/*RT*/#include ++/*RT*/int ciff_base, ciff_len, exif_base, pre_filters; ++/*RT*/#undef MAX ++/*RT*/#undef MIN ++/*RT*/#define NO_LCMS ++/*RT*/#define NO_JPEG ++/*RT*/#define LOCALTIME ++/*RT*/#define DJGPP ++/*RT*/#include ++ ++#include "myfile.h" ++ + /* + dcraw.c -- Dave Coffin's raw photo decoder + Copyright 1997-2009 by Dave Coffin, dcoffin a cybercom o net +@@ -46,7 +59,9 @@ + NO_LCMS disables the "-p" option. + */ + #ifndef NO_JPEG +-#include ++/*RT*/extern "C" { ++/*RT*/#include ++/*RT*/} + #endif + #ifndef NO_LCMS + #include +@@ -101,7 +116,8 @@ + access them are prefixed with "CLASS". Note that a thread-safe + C++ class cannot have non-const static local variables. + */ +-FILE *ifp, *ofp; ++/*RT*/IMFILE *ifp; ++FILE * ofp; + short order; + const char *ifname; + char *meta_data; +@@ -271,6 +287,7 @@ + fprintf (stderr,_("Corrupt data near 0x%llx\n"), (INT64) ftello(ifp)); + } + data_error = 1; ++ /*RT*/ longjmp (failure, 1); + } + + ushort CLASS sget2 (uchar *s) +@@ -344,7 +361,7 @@ + { + if (fread (pixel, 2, count, ifp) < count) derror(); + if ((order == 0x4949) == (ntohs(0x1234) == 0x1234)) +- swab (pixel, pixel, count*2); ++ swab ((char*)pixel, (char*)pixel, count*2); + } + + void CLASS canon_black (double dark[2], int nblack) +@@ -2131,7 +2148,7 @@ + size_t nbytes; + + nbytes = fread (jpeg_buffer, 1, 4096, ifp); +- swab (jpeg_buffer, jpeg_buffer, nbytes); ++ swab ((char*)jpeg_buffer, (char*)jpeg_buffer, nbytes); + cinfo->src->next_input_byte = jpeg_buffer; + cinfo->src->bytes_in_buffer = nbytes; + return TRUE; +@@ -3773,6 +3790,7 @@ + for (row = FC(1,0) >> 1; row < height; row+=2) + for (col = FC(row,1) & 1; col < width; col+=2) + image[row*width+col][1] = image[row*width+col][3]; ++/*RT*/ pre_filters = filters; + filters &= ~((filters & 0x55555555) << 1); + } + } +@@ -4824,7 +4842,7 @@ + unsigned sony_curve[] = { 0,0,0,0,0,4095 }; + unsigned *buf, sony_offset=0, sony_length=0, sony_key=0; + struct jhead jh; +- FILE *sfp; ++/*RT*/ IMFILE *sfp; + + if (tiff_nifds >= sizeof tiff_ifd / sizeof tiff_ifd[0]) + return 1; +@@ -5200,12 +5218,13 @@ + fread (buf, sony_length, 1, ifp); + sony_decrypt (buf, sony_length/4, 1, sony_key); + sfp = ifp; +- if ((ifp = tmpfile())) { +- fwrite (buf, sony_length, 1, ifp); +- fseek (ifp, 0, SEEK_SET); ++/*RT*/ ifp = fopen (buf, sony_length); ++// if ((ifp = tmpfile())) { ++// fwrite (buf, sony_length, 1, ifp); ++// fseek (ifp, 0, SEEK_SET); + parse_tiff_ifd (-sony_offset); +- fclose (ifp); +- } ++// fclose (ifp); ++// } + ifp = sfp; + free (buf); + } +@@ -5231,6 +5250,8 @@ + int doff, max_samp=0, raw=-1, thm=-1, i; + struct jhead jh; + ++ /*RT*/ exif_base = base; ++ + fseek (ifp, base, SEEK_SET); + order = get2(); + if (order != 0x4949 && order != 0x4d4d) return; +@@ -5399,7 +5420,7 @@ + { + const char *file, *ext; + char *jname, *jfile, *jext; +- FILE *save=ifp; ++/*RT*/ IMFILE *save=ifp; + + ext = strrchr (ifname, '.'); + file = strrchr (ifname, '/'); +@@ -5427,7 +5448,8 @@ + *jext = '0'; + } + if (strcmp (jname, ifname)) { +- if ((ifp = fopen (jname, "rb"))) { ++/*RT*/ if ((ifp = fopen (jname))) { ++// if ((ifp = fopen (jname, "rb"))) { + if (verbose) + fprintf (stderr,_("Reading metadata from %s ...\n"), jname); + parse_tiff (12); +@@ -5757,7 +5779,11 @@ + order = get2(); + hlen = get4(); + if (get4() == 0x48454150) /* "HEAP" */ ++/*RT*/ { ++/*RT*/ ciff_base = save+hlen; ++/*RT*/ ciff_len = len-hlen; + parse_ciff (save+hlen, len-hlen); ++/*RT*/ } + parse_tiff (save+6); + fseek (ifp, save+len, SEEK_SET); + } +@@ -6656,6 +6682,12 @@ + fread (head, 1, 32, ifp); + fseek (ifp, 0, SEEK_END); + fsize = ftell(ifp); ++ ++ /*RT*/ if (fsize<100000) { ++ is_raw = 0; ++ return; ++ } ++ + if ((cp = (char *) memmem (head, 32, "MMMM", 4)) || + (cp = (char *) memmem (head, 32, "IIII", 4))) { + parse_phase_one (cp-head); +@@ -6663,6 +6695,8 @@ + } else if (order == 0x4949 || order == 0x4d4d) { + if (!memcmp (head+6,"HEAPCCDR",8)) { + data_offset = hlen; ++/*RT*/ ciff_base = hlen; ++/*RT*/ ciff_len = fsize - hlen; + parse_ciff (hlen, fsize - hlen); + } else { + parse_tiff(0); +@@ -8354,13 +8388,13 @@ + FORCC ppm [col*colors+c] = curve[image[soff][c]] >> 8; + else FORCC ppm2[col*colors+c] = curve[image[soff][c]]; + if (output_bps == 16 && !output_tiff && htons(0x55aa) != 0x55aa) +- swab (ppm2, ppm2, width*colors*2); ++ swab ((char*)ppm2, (char*)ppm2, width*colors*2); + fwrite (ppm, colors*output_bps/8, width, ofp); + } + free (ppm); + } + +-int CLASS main (int argc, const char **argv) ++/*int CLASS main (int argc, const char **argv) + { + int arg, status=0; + int timestamp_only=0, thumbnail_only=0, identify_only=0; +@@ -8473,7 +8507,7 @@ + case 'i': identify_only = 1; break; + case 'c': write_to_stdout = 1; break; + case 'v': verbose = 1; break; +- case 'h': half_size = 1; /* "-h" implies "-f" */ ++ case 'h': half_size = 1; /* "-h" implies "-f" *//* + case 'f': four_color_rgb = 1; break; + case 'A': FORC4 greybox[c] = atoi(argv[arg++]); + case 'a': use_auto_wb = 1; break; +@@ -8733,3 +8767,537 @@ + } + return status; + } ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++namespace rtengine { ++ ++extern Settings* settings; ++ ++Glib::Mutex* dcrMutex=NULL; ++ ++int loadRaw (const char* fname, struct RawImage *ri) { ++ ++ static const double xyzd50_srgb[3][3] = ++ { { 0.436083, 0.385083, 0.143055 }, ++ { 0.222507, 0.716888, 0.060608 }, ++ { 0.013930, 0.097097, 0.714022 } }; ++ ++dcrMutex->lock (); ++ ++ ifname = fname;//strdup (fname); ++ image = NULL; ++ ++ exif_base = -1; ++ ciff_base = -1; ++ ciff_len = -1; ++ verbose = settings->verbose; ++ oprof = NULL; ++ ri->data = NULL; ++ ri->allocation = NULL; ++ ri->profile_data = NULL; ++ ifp = gfopen (fname); ++ if (!ifp) { ++ dcrMutex->unlock (); ++ return 3; ++ } ++ ++ use_camera_wb = 0; ++ highlight = 1; ++ half_size = 0; ++ ++ identify (); ++ use_camera_wb = 1; ++ if (!is_raw) { ++ fclose(ifp); ++ dcrMutex->unlock (); ++ return 2; ++ } ++ ++ shrink = 0; ++ ++ if (settings->verbose) printf ("Loading %s %s image from %s...\n", make, model, fname); ++ iheight = height; ++ iwidth = width; ++ ++ image = (UshORt (*)[4])calloc (height*width*sizeof *image + meta_length, 1); ++ meta_data = (char *) (image + height*width); ++ ++ if (setjmp (failure)) { ++ if (image) ++ free (image); ++ if (ri->data) ++ free(ri->data); ++ fclose (ifp); ++ dcrMutex->unlock (); ++ return 100; ++ } ++ ++ fseek (ifp, data_offset, SEEK_SET); ++ (*load_raw)(); ++ ++ ri->profile_len = 0; ++ ri->profile_data = NULL; ++ if (profile_length) { ++ ri->profile_len = profile_length; ++ ri->profile_data = (char *) malloc (profile_length); ++ fseek (ifp, profile_offset, SEEK_SET); ++ fread (ri->profile_data, 1, profile_length, ifp); ++ } ++ ++ fclose(ifp); ++ if (zero_is_bad) remove_zeroes(); ++ ++ ri->red_multiplier = pre_mul[0]; ++ ri->green_multiplier = pre_mul[1]; ++ ri->blue_multiplier = pre_mul[2]; ++ ++ scale_colors(); ++ pre_interpolate (); ++ ++ ri->width = width; ++ ri->height = height; ++ ri->filters = filters; ++ ++ if (filters) { ++ ri->allocation = (short unsigned int*)calloc(height*width, sizeof(unsigned short)); ++ ri->data = (unsigned short**)calloc(height, sizeof(unsigned short*)); ++ for (int i=0; idata[i] = ri->allocation + i*width; ++ for (int row = 0; row < height; row++) ++ for (int col = 0; col < width; col++) ++ if (ISGREEN(ri,row,col)) ++ ri->data[row][col] = image[row*width+col][1]; ++ else if (ISRED(ri,row,col)) ++ ri->data[row][col] = image[row*width+col][0]; ++ else ++ ri->data[row][col] = image[row*width+col][2]; ++ } ++ else { ++ ri->allocation = (short unsigned int*)calloc(3*height*width, sizeof(unsigned short)); ++ ri->data = (unsigned short**)calloc(height, sizeof(unsigned short*)); ++ for (int i=0; idata[i] = ri->allocation + 3*i*width; ++ for (int row = 0; row < height; row++) ++ for (int col = 0; col < width; col++) { ++ ri->data[row][3*col+0] = image[row*width+col][0]; ++ ri->data[row][3*col+1] = image[row*width+col][1]; ++ ri->data[row][3*col+2] = image[row*width+col][2]; ++ } ++ } ++ ++ if (flip==5) ++ ri->rotate_deg = 270; ++ else if (flip==3) ++ ri->rotate_deg = 180; ++ else if (flip==6) ++ ri->rotate_deg = 90; ++ else ++ ri->rotate_deg = 0; ++ ++ ri->make = strdup (make); ++ ri->model = strdup (model); ++ ++ ri->exifbase = exif_base; ++ ri->prefilters = pre_filters; ++ ri->ciff_base = ciff_base; ++ ri->ciff_len = ciff_len; ++ ++ ri->camwb_red = ri->red_multiplier / pre_mul[0]; ++ ri->camwb_green = ri->green_multiplier / pre_mul[1]; ++ ri->camwb_blue = ri->blue_multiplier / pre_mul[2]; ++ ++ ri->defgain = 1.0 / MIN(MIN(pre_mul[0],pre_mul[1]),pre_mul[2]); ++ ++ ri->fuji_width = fuji_width; ++ ++ for (int a=0; a < 3; a++) ++ for (int b=0; b < 3; b++) ++ ri->coeff[a][b] = rgb_cam[a][b]; ++ ++ free (image); ++dcrMutex->unlock (); ++ return 0; ++} ++ ++int getRawFileBasicInfo (const Glib::ustring& fname, rtengine::RawMetaDataLocation& rml, int& rotation, int& thumbWidth, int& thumbHeight, int& thumbOffset, int& thumbType) { ++ ++ int status=0; ++ ++dcrMutex->lock (); ++ ++ exif_base = -1; ++ ciff_base = -1; ++ ciff_len = -1; ++ ++ half_size = 1; ++ bright = 1.0; ++ verbose = settings->verbose; ++ use_camera_wb = 1; ++ ++ thumb_length = 0; ++ thumb_offset = 0; ++ thumb_load_raw = 0; ++ status = 1; ++ ++ ifname = fname.c_str(); ++ if (!(ifp = gfopen (ifname))) { ++ status = 2; ++ dcrMutex->unlock (); ++ return status; ++ } ++ identify (); ++ if (!is_raw || colors>3) { ++ status = 3; ++ fclose (ifp); ++ dcrMutex->unlock (); ++ return status; ++ } ++ ++ thumbOffset = thumb_offset; ++ ++ if (flip==5) ++ rotation = 270; ++ else if (flip==3) ++ rotation = 180; ++ else if (flip==6) ++ rotation = 90; ++ else ++ rotation = 0; ++ ++ thumbWidth = thumb_width; ++ thumbHeight = thumb_height; ++ if (!thumb_load_raw && thumb_offset && write_thumb == jpeg_thumb) ++ thumbType = 1; ++ else if (!thumb_load_raw && thumb_offset && write_thumb == ppm_thumb) ++ thumbType = 2; ++ else { ++ thumbType = 0; ++ thumbWidth = width; ++ thumbHeight = height; ++ } ++ ++ rml.exifBase = exif_base; ++ rml.ciffBase = ciff_base; ++ rml.ciffLength = ciff_len; ++ ++ fclose (ifp); ++dcrMutex->unlock (); ++ return !is_raw; ++} ++ ++#include ++ ++rtengine::Thumbnail* rtengine::Thumbnail::loadFromRaw (const Glib::ustring& fname, rtengine::RawMetaDataLocation& rml, int &w, int &h, int fixwh) { ++ ++dcrMutex->lock (); ++MyTime t0, t1, t2, t3, t4, t5, t6; ++t0.set (); ++ ++ image = NULL; ++ ifname = fname.c_str(); ++ exif_base = -1; ++ ciff_base = -1; ++ ciff_len = -1; ++ verbose = settings->verbose; ++ oprof = NULL; ++ ifp = gfopen (fname.c_str()); ++ if (!ifp) { ++ dcrMutex->unlock (); ++ return NULL; ++ } ++ ++t1.set (); ++ ++ if (setjmp (failure)) { ++ if (image) ++ free (image); ++ fclose (ifp); ++ dcrMutex->unlock (); ++ return NULL; ++ } ++ ++ use_camera_wb = 0; ++ highlight = 1; ++ half_size = 0; ++ shrink = 0; ++ identify (); ++ use_camera_wb = 1; ++ if (!is_raw || colors>3) { ++ fclose(ifp); ++ dcrMutex->unlock (); ++ return NULL; ++ } ++ ++t2.set(); ++ ++ iheight = ::height; ++ iwidth = ::width; ++ ++ image = (UshORt (*)[4])calloc (::height*::width*sizeof *image + meta_length, 1); ++ meta_data = (char *) (image + ::height*::width); ++ ++ if (settings->verbose) printf ("Loading %s %s image from %s...\n", make, model, fname.c_str()); ++ fseek (ifp, data_offset, SEEK_SET); ++ (*load_raw)(); ++ if (zero_is_bad) remove_zeroes(); ++ ++ rtengine::Thumbnail* tpp = new rtengine::Thumbnail; ++ ++ tpp->isRaw = true; ++ tpp->embProfileLength = 0; ++ if (profile_length) { ++ tpp->embProfileLength = profile_length; ++ tpp->embProfileData = new unsigned char[profile_length]; ++ fseek (ifp, profile_offset, SEEK_SET); ++ fread (tpp->embProfileData, 1, profile_length, ifp); ++ tpp->embProfile = cmsOpenProfileFromMem (tpp->embProfileData, tpp->embProfileLength); ++ } ++ else { ++ tpp->embProfile = NULL; ++ tpp->embProfileData = NULL; ++ } ++ ++ fclose(ifp); ++ tpp->redMultiplier = pre_mul[0]; ++ tpp->greenMultiplier = pre_mul[1]; ++ tpp->blueMultiplier = pre_mul[2]; ++ ++t3.set (); ++ ++ scale_colors(); ++ pre_interpolate (); ++ ++ unsigned filter = filters; ++ int firstgreen = 1; ++ // locate first green location in the first row ++ while (!FISGREEN(filter,1,firstgreen)) ++ firstgreen++; ++ ++ int skip = 1; ++ if (fixwh==1) // fix height, scale width ++ skip = (::height-firstgreen-1) / h; ++ else ++ skip = (::width-firstgreen-1) / w; ++ if (skip%2) ++ skip--; ++ if (skip<1) ++ skip = 1; ++ ++ int hskip = skip, vskip = skip; ++ if (!strcmp (model, "D1X")) ++ hskip *=2; ++ ++ rml.exifBase = exif_base; ++ rml.ciffBase = ciff_base; ++ rml.ciffLength = ciff_len; ++ tpp->camwbRed = tpp->redMultiplier / pre_mul[0]; ++ tpp->camwbGreen = tpp->greenMultiplier / pre_mul[1]; ++ tpp->camwbBlue = tpp->blueMultiplier / pre_mul[2]; ++ ++ tpp->defGain = 1.0 / MIN(MIN(pre_mul[0],pre_mul[1]),pre_mul[2]); ++ tpp->gammaCorrected = true; ++ ++ int ix = 0; ++ int rofs = 0; ++ int tmpw = (::width-2)/hskip; ++ int tmph = (::height-2)/vskip; ++ Image16* tmpImg = new Image16 (tmpw, tmph); ++ if (filter) { ++ for (int row=1, y=0; row< ::height-1 && y> 1; ++ b = (image[ofs+::width][2] + image[ofs-::width][2]) >> 1; ++ } ++ else { ++ b = (image[ofs+1][2] + image[ofs-1][2]) >> 1; ++ r = (image[ofs+::width][0] + image[ofs-::width][0]) >> 1; ++ } ++ tmpImg->r[y][x] = r; ++ tmpImg->g[y][x] = g; ++ tmpImg->b[y][x] = b; ++ } ++ } ++ } ++ else { ++ for (int row=1, y=0; row< ::height-1 && yr[y][x] = image[ofs][0]; ++ tmpImg->g[y][x] = image[ofs][1]; ++ tmpImg->b[y][x] = image[ofs][2]; ++ } ++ } ++ } ++ ++ if (fuji_width) { ++ int fw = fuji_width / hskip; ++ double step = sqrt(0.5); ++ int wide = fw / step; ++ int high = (tmph - fw) / step; ++ Image16* fImg = new Image16 (wide, high); ++ float r, c; ++ ++ for (int row=0; row < high; row++) ++ for (int col=0; col < wide; col++) { ++ unsigned ur = r = fw + (row-col)*step; ++ unsigned uc = c = (row+col)*step; ++ if (ur > tmph-2 || uc > tmpw-2) ++ continue; ++ double fr = r - ur; ++ double fc = c - uc; ++ int oofs = (ur*tmpw + uc)*3; ++ int fofs = (row*wide+col)*3; ++ fImg->r[row][col] = (tmpImg->r[ur][uc] * (1-fc) + tmpImg->r[ur][uc+1] * fc) * (1-fr) + (tmpImg->r[ur+1][uc] * (1-fc) + tmpImg->r[ur+1][uc+1] * fc) * fr; ++ fImg->g[row][col] = (tmpImg->g[ur][uc] * (1-fc) + tmpImg->g[ur][uc+1] * fc) * (1-fr) + (tmpImg->g[ur+1][uc] * (1-fc) + tmpImg->g[ur+1][uc+1] * fc) * fr; ++ fImg->b[row][col] = (tmpImg->b[ur][uc] * (1-fc) + tmpImg->b[ur][uc+1] * fc) * (1-fr) + (tmpImg->b[ur+1][uc] * (1-fc) + tmpImg->b[ur+1][uc+1] * fc) * fr; ++ } ++ delete tmpImg; ++ tmpImg = fImg; ++ } ++ ++ ++ if (fixwh==1) // fix height, scale width ++ w = tmpw * h / tmph; ++ else ++ h = tmph * w / tmpw; ++ ++ tpp->thumbImg = tmpImg->resize (w, h, TI_Bilinear); ++ delete tmpImg; ++ ++ if (fuji_width) ++ tpp->scale = (double)(::height - fuji_width) / sqrt(0.5) / h; ++ else ++ tpp->scale = (double)::height / h; ++ ++t4.set (); ++ ++ // generate histogram for auto exposure ++ tpp->aeHistCompression = 3; ++ tpp->aeHistogram = new int[65536>>tpp->aeHistCompression]; ++ memset (tpp->aeHistogram, 0, (65536>>tpp->aeHistCompression)*sizeof(int)); ++ int radd = 4; ++ int gadd = 2; ++ int badd = 4; ++ if (!filter) ++ radd = gadd = badd = 1; ++ for (int i=8; i< ::height-8; i++) { ++ int start, end; ++ if (fuji_width) { ++ int fw = fuji_width; ++ start = ABS(fw-i) + 8; ++ end = MIN( ::height+ ::width-fw-i, fw+i) - 8; ++ } ++ else { ++ start = 8; ++ end = ::width-8; ++ } ++ for (int j=start; jaeHistogram[image[i* ::width+j][1]>>tpp->aeHistCompression]+=gadd; ++ else if (FISRED(filter,i,j)) ++ tpp->aeHistogram[image[i* ::width+j][0]>>tpp->aeHistCompression]+=radd; ++ else if (FISBLUE(filter,i,j)) ++ tpp->aeHistogram[image[i* ::width+j][2]>>tpp->aeHistCompression]+=badd; ++ } ++ ++t5.set (); ++ ++ // generate autoWB ++ double avg_r = 0; ++ double avg_g = 0; ++ double avg_b = 0; ++ int rn = 0, gn = 0, bn = 0; ++ ++ for (int i=32; i< ::height-32; i++) { ++ int start, end; ++ if (fuji_width) { ++ int fw = fuji_width; ++ start = ABS(fw-i) + 32; ++ end = MIN( ::height+ ::width-fw-i, fw+i) - 32; ++ } ++ else { ++ start = 32; ++ end = ::width-32; ++ } ++ for (int j=start; jdefGain * image[i* ::width+j][1]; ++ if (d>64000) ++ continue; ++ avg_g += d*d*d*d*d*d; ++ gn++; ++ } ++ if (FISRED(filter,i,j)) { ++ double d = tpp->defGain * image[i* ::width+j][0]; ++ if (d>64000) ++ continue; ++ avg_r += d*d*d*d*d*d; ++ rn++; ++ } ++ if (FISBLUE(filter,i,j)) { ++ double d = tpp->defGain * image[i* ::width+j][2]; ++ if (d>64000) ++ continue; ++ avg_b += d*d*d*d*d*d; ++ bn++; ++ } ++ } ++ } ++ ++ double reds = pow (avg_r/rn, 1.0/6.0) * tpp->camwbRed; ++ double greens = pow (avg_g/gn, 1.0/6.0) * tpp->camwbGreen; ++ double blues = pow (avg_b/bn, 1.0/6.0) * tpp->camwbBlue; ++ ++ double rm = rgb_cam[0][0]*reds + rgb_cam[0][1]*greens + rgb_cam[0][2]*blues; ++ double gm = rgb_cam[1][0]*reds + rgb_cam[1][1]*greens + rgb_cam[1][2]*blues; ++ double bm = rgb_cam[2][0]*reds + rgb_cam[2][1]*greens + rgb_cam[2][2]*blues; ++ ++ ColorTemp::mul2temp (rm, gm, bm, tpp->autowbTemp, tpp->autowbGreen); ++ ++t6.set (); ++ ++if (settings->verbose) printf ("0: %d, 1: %d, 2: %d, 3: %d, 4: %d, 5: %d All: %d\n", t1.etime(t0), t2.etime(t1), t3.etime(t2), t4.etime(t3), t5.etime(t4), t6.etime(t5), t6.etime(t0)); ++ ++ int deg = 0; ++ if (flip==5) ++ deg = 270; ++ else if (flip==3) ++ deg = 180; ++ else if (flip==6) ++ deg = 90; ++ ++ if (deg>0) { ++ Image16* rot = tpp->thumbImg->rotate (deg); ++ delete tpp->thumbImg; ++ tpp->thumbImg = rot; ++ } ++ ++ for (int a=0; a < 3; a++) ++ for (int b=0; b < 3; b++) ++ tpp->colorMatrix[a][b] = rgb_cam[a][b]; ++ ++ tpp->init (); ++ ++ free (image); ++ ++dcrMutex->unlock (); ++ ++ return tpp; ++} ++ ++ ++} ++ diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc new file mode 100755 index 000000000..10546fbe7 --- /dev/null +++ b/rtengine/dcrop.cc @@ -0,0 +1,386 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include +#define CLIPTO(a,b,c) ((a)>b?((a) 0)) + +namespace rtengine { + +extern Settings* settings; + +Crop::Crop (ImProcCoordinator* parent) + : parent(parent), cropAllocated(false), + cropw(-1), croph(-1), trafw(-1), trafh(-1), + cropImageListener(NULL), updating(false), + resizeCrop(NULL), transCrop(NULL), borderRequested(32) +{ + parent->crops.push_back (this); +} + +Crop::~Crop () { + + cropMutex.lock (); + parent->mProcessing.lock (); + std::vector::iterator i = std::find (parent->crops.begin(), parent->crops.end(), this); + if (i!=parent->crops.end ()) + parent->crops.erase (i); + + freeAll (); + parent->mProcessing.unlock (); + cropMutex.unlock (); +} + +void Crop::setListener (DetailedCropListener* il) { + + parent->mProcessing.lock(); + cropImageListener = il; + parent->mProcessing.unlock(); +} + +void Crop::update (int todo, bool internal) { + + if (!internal) + parent->mProcessing.lock (); + + ProcParams& params = parent->params; + cropMutex.lock (); + + if (!params.resize.enabled) + params.resize.scale = 1.0; + else if (params.resize.dataspec==1) + params.resize.scale = (double)params.resize.width / (params.coarse.rotate==90 || params.coarse.rotate==270 ? parent->fh : parent->fw); + else if (params.resize.dataspec==2) + params.resize.scale = (double)params.resize.height / (params.coarse.rotate==90 || params.coarse.rotate==270 ? parent->fw : parent->fh); + + MyTime t1,t2,t3,t4,t5,t6,t7,t8,t9; + + t1.set (); + // give possibility to the listener to modify crop window (as the full image dimensions are already known at this point) + int wx, wy, ww, wh, ws; + bool overrideWindow = false; + if (cropImageListener) + overrideWindow = cropImageListener->getWindow (wx, wy, ww, wh, ws); + // re-allocate sub-images and arrays if their dimensions changed + bool needsinitupdate = false; + if (!overrideWindow) + needsinitupdate = setCropSizes (rqcropx, rqcropy, rqcropw, rqcroph, skip, true); + else + needsinitupdate = setCropSizes (wx, wy, ww, wh, ws, true); + // it something has been reallocated, all processing steps have to be performed + if (needsinitupdate) + todo = ALL; + + if (resizeCrop) + baseCrop = resizeCrop; + else + baseCrop = origCrop; + bool needstransform = fabs(params.rotate.degree)>1e-15 || fabs(params.distortion.amount)>1e-15 || fabs(params.cacorrection.red)>1e-15 || fabs(params.cacorrection.blue)>1e-15; + + if (todo & M_INIT) { + parent->minit.lock (); + int tr = TR_NONE; + if (params.coarse.rotate==90) tr |= TR_R90; + if (params.coarse.rotate==180) tr |= TR_R180; + if (params.coarse.rotate==270) tr |= TR_R270; + if (params.coarse.hflip) tr |= TR_HFLIP; + if (params.coarse.vflip) tr |= TR_VFLIP; + + if (!needsinitupdate) + setCropSizes (rqcropx, rqcropy, rqcropw, rqcroph, skip, true); + PreviewProps pp (trafx, trafy, trafw*skip, trafh*skip, skip); + parent->imgsrc->getImage (parent->currWB, tr, origCrop, pp, params.hlrecovery, params.icm); + + if (fabs(params.resize.scale-1.0)<1e-7) { + if (resizeCrop) { + delete resizeCrop; + resizeCrop = NULL; + } + baseCrop = origCrop; + } + else { + int rcw = trafw*params.resize.scale; + int rch = trafh*params.resize.scale; + if (!needstransform) { + rcw = cropw; + rch = croph; + } + if (resizeCrop && (resizeCrop->width!=rcw || resizeCrop->height!=rch)) { + delete resizeCrop; + resizeCrop = NULL; + } + if (!resizeCrop) + resizeCrop = new Image16 (rcw, rch); + parent->ipf.resize (origCrop, resizeCrop, params.resize); + baseCrop = resizeCrop; + } + parent->minit.unlock (); + } + + t2.set (); + if (settings->verbose) printf ("C-INIT: %d\n", t2.etime(t1)); + + bool needsvignetting = params.vignetting.amount!=0; + + if ((!needstransform && !needsvignetting && transCrop) || (transCrop && (transCrop->width!=cropw || transCrop->height!=croph))) { + delete transCrop; + transCrop = NULL; + } + // check if the transformation has been switched on: + else if ((needstransform || needsvignetting) && !transCrop) + transCrop = new Image16 (cropw, croph); + if ((todo & M_TRANSFORM) && !needstransform && needsvignetting) + parent->ipf.vignetting (baseCrop, transCrop, ¶ms, cropx/skip, cropy/skip, SKIPS(parent->fw,skip), SKIPS(parent->fh,skip)); + else if ((todo & M_TRANSFORM) && needstransform) { + if (skip==1) + parent->ipf.transform (baseCrop, transCrop, ¶ms, cropx/skip, cropy/skip, trafx*params.resize.scale/skip, trafy*params.resize.scale/skip, SKIPS(parent->fw,skip), SKIPS(parent->fh,skip)); + else + parent->ipf.simpltransform (baseCrop, transCrop, ¶ms, cropx/skip, cropy/skip, trafx*params.resize.scale/skip, trafy*params.resize.scale/skip, SKIPS(parent->fw,skip), SKIPS(parent->fh,skip)); + } + if (transCrop) + baseCrop = transCrop; + + t3.set (); + if (settings->verbose) printf ("C-TRANSFORM: %d\n", t3.etime(t2)); + + if ((todo & M_BLURMAP) && params.sh.enabled) { + double radius = sqrt (SKIPS(parent->fw,skip)*SKIPS(parent->fw,skip)+SKIPS(parent->fh,skip)*SKIPS(parent->fh,skip)) / 2.0; + double shradius = radius / 1800.0 * params.sh.radius; + cshmap->update (baseCrop, (unsigned short**)cbuffer, shradius, parent->ipf.lumimul, params.sh.hq); + cshmap->forceStat (parent->shmap->max, parent->shmap->min, parent->shmap->avg); + } + + t4.set (); + if (settings->verbose) printf ("C-BLURMAP: %d\n", t4.etime(t3)); + + if (todo & M_RGBCURVE) { + parent->ipf.rgbProc (baseCrop, laboCrop, ¶ms, parent->tonecurve, cshmap); + } + + t5.set (); + if (settings->verbose) printf ("C-RGB: %d\n", t5.etime(t4)); + + if (todo & M_LUMINANCE) { + parent->ipf.luminanceCurve (laboCrop, labnCrop, parent->lumacurve, 0, croph); + if (skip==1) { + parent->ipf.lumadenoise (labnCrop, ¶ms, 1, cbuffer); + parent->ipf.sharpening (labnCrop, ¶ms, 1, (unsigned short**)cbuffer); + } + } + + t6.set (); + if (settings->verbose) printf ("C-LUMINANCE: %d\n", t6.etime(t5)); + + if (todo & M_COLOR) { + parent->ipf.colorCurve (laboCrop, labnCrop, ¶ms); + if (skip==1) + parent->ipf.colordenoise (labnCrop, ¶ms, 1, cbuffer); + } + + t7.set (); + if (settings->verbose) printf ("C-COLOR: %d\n", t7.etime(t6)); + + parent->ipf.lab2rgb (labnCrop, cropImg); + + t8.set (); + if (settings->verbose) printf ("C-RGBCONVERT: %d\n", t8.etime(t7)); + if (cropImageListener) { + int finalW = rqcropw; + if (cropImg->getWidth()-leftBorder < finalW) + finalW = cropImg->getWidth()-leftBorder; + int finalH = rqcroph; + if (cropImg->getHeight()-upperBorder < finalH) + finalH = cropImg->getHeight()-upperBorder; + + Image8* final = new Image8 (finalW, finalH); + for (int i=0; idata + 3*i*finalW, cropImg->data + 3*(i+upperBorder)*cropw + 3*leftBorder, 3*finalW); + cropImageListener->setDetailedCrop (final, params.crop, rqcropx, rqcropy, rqcropw, rqcroph, skip); + delete final; + } + + t9.set (); + if (settings->verbose) printf ("Total crop processing time: %d\n", t9.etime(t1)); + + cropMutex.unlock (); + + if (!internal) + parent->mProcessing.unlock (); +} + +void Crop::freeAll () { + + if (settings->verbose) printf ("freeallcrop starts %d\n", (int)cropAllocated); + + if (cropAllocated) { + delete origCrop; + if (transCrop) + delete transCrop; + transCrop = NULL; + if (resizeCrop) + delete resizeCrop; + resizeCrop = NULL; + delete laboCrop; + delete labnCrop; + delete cropImg; + delete cshmap; + for (int i=0; iverbose) printf ("setcropsizes before lock\n"); + + if (!internal) + cropMutex.lock (); + + bool changed = false; + + rqcropx = rcx; + rqcropy = rcy; + rqcropw = rcw; + rqcroph = rch; + + // store and set requested crop size + int rqx1 = CLIPTO(rqcropx,0,parent->fullw-1); + int rqy1 = CLIPTO(rqcropy,0,parent->fullh-1); + int rqx2 = rqx1 + rqcropw - 1; + int rqy2 = rqy1 + rqcroph - 1; + rqx2 = CLIPTO(rqx2,0,parent->fullw-1); + rqy2 = CLIPTO(rqy2,0,parent->fullh-1); + + this->skip = skip; + + // add border, if possible + int bx1 = rqx1 - skip*borderRequested; + int by1 = rqy1 - skip*borderRequested; + int bx2 = rqx2 + skip*borderRequested; + int by2 = rqy2 + skip*borderRequested; + // clip it to fit into image area + bx1 = CLIPTO(bx1,0,parent->fullw-1); + by1 = CLIPTO(by1,0,parent->fullh-1); + bx2 = CLIPTO(bx2,0,parent->fullw-1); + by2 = CLIPTO(by2,0,parent->fullh-1); + int bw = bx2 - bx1 + 1; + int bh = by2 - by1 + 1; + + // determine which part of the source image is required to compute the crop rectangle + int orx, ory, orw, orh; + ProcParams& params = parent->params; + parent->ipf.transCoord (¶ms, parent->fw, parent->fh, bx1, by1, bw, bh, orx, ory, orw, orh); + + int tr = TR_NONE; + if (params.coarse.rotate==90) tr |= TR_R90; + if (params.coarse.rotate==180) tr |= TR_R180; + if (params.coarse.rotate==270) tr |= TR_R270; + if (params.coarse.hflip) tr |= TR_HFLIP; + if (params.coarse.vflip) tr |= TR_VFLIP; + + PreviewProps cp (orx, ory, orw, orh, skip); + int orW, orH; + parent->imgsrc->getSize (tr, cp, orW, orH); + + int cw = SKIPS(bw,skip); + int ch = SKIPS(bh,skip); + + leftBorder = SKIPS(rqx1-bx1,skip); + upperBorder = SKIPS(rqy1-by1,skip); + + if (settings->verbose) printf ("setsizes starts (%d, %d, %d, %d)\n", orW, orH, trafw, trafh); + + if (cw!=cropw || ch!=croph || orW!=trafw || orH!=trafh) { + + freeAll (); + + cropw = cw; + croph = ch; + trafw = orW; + trafh = orH; + + origCrop = new Image16 (trafw, trafh); + laboCrop = new LabImage (cropw, croph); + labnCrop = new LabImage (cropw, croph); + cropImg = new Image8 (cropw, croph); + cshmap = new SHMap (cropw, croph); + + cbuffer = new int*[croph]; + for (int i=0; iverbose) printf ("setsizes ends\n"); + + if (!internal) + cropMutex.unlock (); + + return changed; +} + +void Crop::fullUpdate () { + + if (updating) { + needsNext = true; + return; + } + + updating = true; + + parent->updaterThreadStart.lock (); + if (parent->updaterRunning && parent->thread) { + parent->changeSinceLast = 0; + parent->thread->join (); + } + + if (parent->plistener) + parent->plistener->setProgressState (1); + + needsNext = true; + while (needsNext) { + needsNext = false; + update (ALL, true); + } + updating = false; + + if (parent->plistener) + parent->plistener->setProgressState (0); + + parent->updaterThreadStart.unlock (); +} + +} + diff --git a/rtengine/dcrop.h b/rtengine/dcrop.h new file mode 100755 index 000000000..71ca82654 --- /dev/null +++ b/rtengine/dcrop.h @@ -0,0 +1,74 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _CROP_H_ +#define _CROP_H_ + +#include +#include +#include +#include +#include +#include +#include + +namespace rtengine { + +using namespace procparams; + +class ImProcCoordinator; + +class Crop : public DetailedCrop { + + protected: + Image16* origCrop, *resizeCrop, *transCrop, *baseCrop; + LabImage *laboCrop, *labnCrop; + Image8 *cropImg; + + int** cbuffer; + SHMap* cshmap; + + bool updating, needsNext; + int skip; + int cropx, cropy, cropw, croph; // size of the detail crop image ('skip' taken into account), with border + int trafx, trafy, trafw, trafh; // the size and position to get from the imagesource that is transformed to the requested crop area + int rqcropx, rqcropy, rqcropw, rqcroph; // size of the requested detail crop image (the image might be smaller) (without border) + int borderRequested, upperBorder, leftBorder; + + + bool cropAllocated; + DetailedCropListener* cropImageListener; + Glib::Mutex cropMutex; + ImProcCoordinator* parent; + + bool setCropSizes (int cx, int cy, int cw, int ch, int skip, bool internal); + void freeAll (); + + public: + Crop (ImProcCoordinator* parent); + ~Crop (); + + bool hasListener () { return cropImageListener; } + void update (int todo, bool internal=false); + void setWindow (int cx, int cy, int cw, int ch, int skip) { setCropSizes (cx, cy, cw, ch, skip, false); } + void fullUpdate (); + void setListener (DetailedCropListener* il); + void destroy () { delete this; } +}; +} +#endif diff --git a/rtengine/ex1simple.cc b/rtengine/ex1simple.cc new file mode 100755 index 000000000..5295df92a --- /dev/null +++ b/rtengine/ex1simple.cc @@ -0,0 +1,83 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +//#include +#include + +class PListener : public rtengine::ProgressListener { + + public: + void setProgressStr (Glib::ustring str) { + std::cout << str << std::endl; + } + void setProgress (double p) { + std::cout << p << std::endl; + } +}; + +int main (int argc, char* argv[]) { + + if (argc<4) { + std::cout << "Usage: rtcmd " << std::endl; + exit(1); + } + + Glib::thread_init (); + + // create and fill settings + rtengine::Settings* s = rtengine::Settings::create (); + s->dualThreadEnabled = true; + s->demosaicMethod = "hphd"; + s->colorCorrectionSteps = 2; + s->iccDirectory = ""; + s->colorimetricIntent = 1; + s->monitorProfile = ""; + // init rtengine + rtengine::init (s); + // the settings can be modified later through the "s" pointer without calling any api function + + // Create a listener object. Any class is appropriate that inherits from rtengine::ProgressListener + PListener pl; + + // Load the image given in the first command line parameter + rtengine::InitialImage* ii; + int errorCode; + ii = rtengine::InitialImage::load (argv[1], true, errorCode, &pl); + if (!ii) + ii = rtengine::InitialImage::load (argv[1], false, errorCode, &pl); + if (!ii) { + std::cout << "Input file not supported." << std::endl; + exit(2); + } + + // create an instance of ProcParams structure that holds the image processing settings. You find the memory map in a separate file and the non-basic types like strings and vectors can be manipulated through helper functions + rtengine::procparams::ProcParams params; + params.load (argv[2]); + +/* First, simplest scenario. Develope image and save it in a file */ + // create a processing job with the loaded image and the current processing parameters + rtengine::ProcessingJob* job = ProcessingJob::create (i, params); + // process image. The error is given back in errorcode. + rtengine::IImage16* res = rtengine::processImage (job, errorCode, &pl); + // save image to disk + res->saveToFile (argv[3]); + // through "res" you can access width/height and pixel data, too +} + diff --git a/rtengine/ex2simple.cc b/rtengine/ex2simple.cc new file mode 100755 index 000000000..941e5787f --- /dev/null +++ b/rtengine/ex2simple.cc @@ -0,0 +1,140 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +//#include +#include + +class PListener : public rtengine::ProgressListener { + + public: + void setProgressStr (Glib::ustring str) { + std::cout << str << std::endl; + } + void setProgress (double p) { + std::cout << p << std::endl; + } +}; + +clas MyPrevImgListener : public rtengine::PreviewImageListener { + + IImage8* i; + + public: + // this method is called when the staged image processor creates a new image to store the resulting preview image (this does not happen too often) + // usually you just have to store it + void setImage (IImage8* img, double scale, procparams::CropParams cp) { + i = img; + } + // if the staged image processor wants to delete the image that stores the preview image, it calls this method. You have to destroy the image. + void delImage (IImage8* img) { + if (img) { + // make sure we dont use this image in an other thread + IImage8* temp = i; + i->getMutex().lock (); + i = NULL; + temp->getMutex().unlock (); + // free it + img->free (); + } + } + // if the preview image changes, this method is called + void imageReady (procparams::CropParams cp) { + // initiate a redraw in the background and return as fast as possible + } + // a possible redraw function: + //void redraw () { + // if (i) { + // i->lock (); + // int w = i->getWidth (); + // int h = i->getHeigt (); + // const char* data = i->getData (); + // ... draw it ... + // i->unlock (); + // } + // } +}; + +int main (int argc, char* argv[]) { + + if (argc<4) { + std::cout << "Usage: rtcmd " << std::endl; + exit(1); + } + + Glib::thread_init (); + + // create and fill settings + rtengine::Settings* s = rtengine::Settings::create (); + s->dualThreadEnabled = true; + s->demosaicMethod = "hphd"; + s->colorCorrectionSteps = 2; + s->iccDirectory = ""; + s->colorimetricIntent = 1; + s->monitorProfile = ""; + // init rtengine + rtengine::init (s); + // the settings can be modified later through the "s" pointer without calling any api function + + // Create a listener object. Any class is appropriate that inherits from rtengine::ProgressListener + PListener pl; + + // Load the image given in the first command line parameter + rtengine::InitialImage* ii; + int errorCode; + ii = rtengine::InitialImage::load (argv[1], true, errorCode, &pl); + if (!ii) + ii = rtengine::InitialImage::load (argv[1], false, errorCode, &pl); + if (!ii) { + std::cout << "Input file not supported." << std::endl; + exit(2); + } + +/* Second scenario. Create a stagedimageprocessor with a preview scale of 1:5 and change few things */ + MyPrevImgListener myPrevImgListener; + + StagedImageProcessor* ipc = StagedImageProcessor::create (ii); + ipc->setProgressListener (&pl); + ipc->setPreviewImageListener (&myPrevImgListener); + ipc->setPreviewScale (5); // preview scale = 1:5 + // you can add a histogram listener, too, that is notified when the histogram changes + // ipc->setHistogramListener (...); + // you can add autoexplistener that is notified about the exposure settings when the auto exp algorithm finishes + // ipc->setAutoExpListener (curve); + // you can add sizelistener if you want to be notified when the size of the final image changes (due to rotation/resize/etc) + // ipc->setSizeListener (crop); + + // if you want to change the settings you have to ask for the procparams structure of the staged image processor + // you have to tell it what has changed. At the first time tell it EvPhotoLoaded so a full processing will be performed + rtengine::procparams::ProcParams* params = ipc->getParamsForUpdate (rtengine::EvPhotoLoaded); + // change this and that... + params->toneCurve.brightness = 1.0; + // you can load it, too, from a file: params->load (argv[2]); + // finally you have to call this non-blocking method, and the image processing starts in the background. When finished, the preview image listener will be notified + ipc->paramsUpdateReady (); + // you can go on with changing of the settings, following the gui actions + // now we know that only the brightness has changed compared to the previous settings, to only a part of the processing has to be repeated + params = ipc->getParamsForUpdate (rtengine::EvBrightness); + params->toneCurve.brightness = 1.2; + ipc->paramsUpdateReady (); + + // ... and so on. If you dont need it any more, you can destroy it (make sure that no processing is happening when you destroy it!) + StagedImageProcessor::destroy (ipc); +} + diff --git a/rtengine/gauss.cc b/rtengine/gauss.cc new file mode 100755 index 000000000..1b208dc9d --- /dev/null +++ b/rtengine/gauss.cc @@ -0,0 +1,49 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +void gaussHorizontal_unsigned (unsigned short** src, unsigned short** dst, AlignedBuffer* buffer, int W, int row_from, int row_to, double sigma) { + + gaussHorizontal (src, dst, buffer, W, row_from, row_to, sigma); +} + +void gaussVertical_unsigned (unsigned short** src, unsigned short** dst, AlignedBuffer* buffer, int H, int col_from, int col_to, double sigma) { + + gaussVertical (src, dst, buffer, H, col_from, col_to, sigma); +} + +void gaussHorizontal_signed (short** src, short** dst, AlignedBuffer* buffer, int W, int row_from, int row_to, double sigma) { + + gaussHorizontal (src, dst, buffer, W, row_from, row_to, sigma); +} + +void gaussVertical_signed (short** src, short** dst, AlignedBuffer* buffer, int H, int col_from, int col_to, double sigma) { + + gaussVertical (src, dst, buffer, H, col_from, col_to, sigma); +} + +void gaussHorizontal_float (float** src, float** dst, AlignedBuffer* buffer, int W, int row_from, int row_to, double sigma) { + + gaussHorizontal (src, dst, buffer, W, row_from, row_to, sigma); +} + +void gaussVertical_float (float** src, float** dst, AlignedBuffer* buffer, int H, int col_from, int col_to, double sigma) { + + gaussVertical (src, dst, buffer, H, col_from, col_to, sigma); +} diff --git a/rtengine/gauss.h b/rtengine/gauss.h new file mode 100755 index 000000000..6f708b40f --- /dev/null +++ b/rtengine/gauss.h @@ -0,0 +1,624 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _GAUSS_H_ +#define _GAUSS_H_ + +#include +#include +#include +#include + +#define NOSSE 1 + +#ifndef NOSSE +#include +template void gaussHorizontal3 (T** src, T** dst, T* buffer, int W, int row_from, int row_to, const float c0, const float c1) { + + typedef float pfloat[4]; + pfloat* temp = (pfloat*)buffer + 1; + pfloat* tmp = (pfloat*)buffer; + + __m128 xmm1; xmm1 = _mm_load1_ps (&c0); + __m128 xmm2; xmm2 = _mm_load1_ps (&c1); + __m128 xmm3; __m128 xmm4; __m128 xmm5; __m128 xmm6; + __m128 xmm0; + + int i; + for (i = row_from; i void gaussHorizontal3 (T** src, T** dst, T* buffer, int W, int row_from, int row_to, const int c0, const int c1) { + + time_t t1 = clock (); + + const int csum = c0 + 2 * c1; + for (int i = row_from; i void gaussVertical3 (T** src, T** dst, T* buffer, int H, int col_from, int col_to, const float c0, const float c1) { + + typedef float pfloat[4]; + pfloat* temp = (pfloat*)buffer + 1; + pfloat* tmp = (pfloat*)buffer; + + __m128 xmm1; xmm1 = _mm_load1_ps (&c0); + __m128 xmm2; xmm2 = _mm_load1_ps (&c1); + __m128 xmm3; __m128 xmm4; __m128 xmm5; __m128 xmm6; + __m128 xmm0; + + int i; + for (i = col_from; i void gaussVertical3 (T** src, T** dst, T* buffer, int H, int col_from, int col_to, const float c0, const float c1) { + + time_t t1 = clock (); + + int stride = dst[1] - dst[0]; + for (int j=col_from; j void gaussHorizontal (T** src, T** dst, AlignedBuffer* buffer, int W, int row_from, int row_to, double sigma) { + + if (sigma<0.25) { + // dont perform filtering + if (src!=dst) + for (int i = row_from; i (src, dst, (T*)(buffer->data), W, row_from, row_to, (int) round(c0), 2); + double c1 = exp (-1.0 / (2.0 * sigma * sigma)); + double csum = 2.0 * c1 + 1.0; + c1 /= csum; + double c0 = 1.0 / csum; + gaussHorizontal3 (src, dst, (T*)(buffer->data), W, row_from, row_to, c0, c1); + return; + } + + // horizontal + float q = 0.98711 * sigma - 0.96330; + if (sigma<2.5) + q = 3.97156 - 4.14554 * sqrt (1.0 - 0.26891 * sigma); + float b0 = 1.57825 + 2.44413*q + 1.4281*q*q + 0.422205*q*q*q; + float b1 = 2.44413*q + 2.85619*q*q + 1.26661*q*q*q; + float b2 = -1.4281*q*q - 1.26661*q*q*q; + float b3 = 0.422205*q*q*q; + float B = 1.0 - (b1+b2+b3) / b0; + + b1 /= b0; + b2 /= b0; + b3 /= b0; + + // SSE optimized version: + __m128 xmm1; xmm1 = _mm_load1_ps (&B); + __m128 xmm2; xmm2 = _mm_load1_ps (&b1); + __m128 xmm3; xmm3 = _mm_load1_ps (&b2); + __m128 xmm4; xmm4 = _mm_load1_ps (&b3); + __m128 xmm5; + __m128 xmm6; + + typedef float pfloat[4]; + pfloat* temp = (pfloat*)buffer->data + 1; + pfloat* tmp = (pfloat*)buffer->data; + + memset (temp, 0, W*sizeof(pfloat)); + + int i; + for (i=row_from; i=0; j--) { + xmm5 = _mm_load_ps ((float*)&temp[j]); + xmm5 =_mm_mul_ps (xmm1, xmm5); + xmm6 = _mm_load_ps ((float*)&temp[j+1]); + xmm6 = _mm_mul_ps (xmm2, xmm6); + xmm5 = _mm_add_ps (xmm6, xmm5); + xmm6 = _mm_load_ps ((float*)&temp[j+2]); + xmm6 = _mm_mul_ps (xmm6, xmm3); + xmm5 = _mm_add_ps (xmm5, xmm6); + xmm6 = _mm_load_ps ((float*)&temp[j+3]); + xmm6 = _mm_mul_ps (xmm6, xmm4); + xmm5 = _mm_add_ps (xmm5, xmm6); + _mm_store_ps ((float*)&temp[j], xmm5); + } + for (int j=0; jdata; + for (; i=0; j--) + temp2[j] = B * temp2[j] + b1*temp2[j+1] + b2*temp2[j+2] + b3*temp2[j+3]; + for (int j=0; j void gaussVertical (T** src, T** dst, AlignedBuffer* buffer, int H, int col_from, int col_to, double sigma) { + + if (sigma<0.25) { + // dont perform filtering + if (src!=dst) + for (int i = 0; i (src, dst, (T*)(buffer->data), H, col_from, col_to, c0, c1); +// double c0 = 2.0 / exp (-1.0 / (2.0 * sigma * sigma)); +// gaussVertical3 (src, dst, (T*)(buffer->data), H, col_from, col_to, (int) round(c0), 2); + return; + } + + // vertical + float q = 0.98711 * sigma - 0.96330; + if (sigma<2.5) + q = 3.97156 - 4.14554 * sqrt (1.0 - 0.26891 * sigma); + float b0 = 1.57825 + 2.44413*q + 1.4281*q*q + 0.422205*q*q*q; + float b1 = 2.44413*q + 2.85619*q*q + 1.26661*q*q*q; + float b2 = -1.4281*q*q - 1.26661*q*q*q; + float b3 = 0.422205*q*q*q; + float B = 1.0 - (b1+b2+b3) / b0; + + b1 /= b0; + b2 /= b0; + b3 /= b0; + + // SSE optimized version: + __m128 xmm1; xmm1 = _mm_load1_ps (&B); + __m128 xmm2; xmm2 = _mm_load1_ps (&b1); + __m128 xmm3; xmm3 = _mm_load1_ps (&b2); + __m128 xmm4; xmm4 = _mm_load1_ps (&b3); + __m128 xmm5; + __m128 xmm6; + + typedef float pfloat[4]; + pfloat* temp = (pfloat*)buffer->data + 1; + pfloat* tmp = (pfloat*)buffer->data; + + memset (temp, 0, H*sizeof(pfloat)); + + int i; + for (i=col_from; i=0; j--) { + xmm5 = _mm_load_ps ((float*)&temp[j]); + xmm5 =_mm_mul_ps (xmm1, xmm5); + xmm6 = _mm_load_ps ((float*)&temp[j+1]); + xmm6 = _mm_mul_ps (xmm2, xmm6); + xmm5 = _mm_add_ps (xmm6, xmm5); + xmm6 = _mm_load_ps ((float*)&temp[j+2]); + xmm6 = _mm_mul_ps (xmm6, xmm3); + xmm5 = _mm_add_ps (xmm5, xmm6); + xmm6 = _mm_load_ps ((float*)&temp[j+3]); + xmm6 = _mm_mul_ps (xmm6, xmm4); + xmm5 = _mm_add_ps (xmm5, xmm6); + _mm_store_ps ((float*)&temp[j], xmm5); + } + for (int j=0; jdata; + for (; i=0; j--) + temp2[j] = B * temp2[j] + b1*temp2[j+1] + b2*temp2[j+2] + b3*temp2[j+3]; + for (int j=0; j void gaussHorizontal3 (T** src, T** dst, T* buffer, int W, int row_from, int row_to, const float c0, const float c1) { + + for (int i=row_from; i void gaussVertical3 (T** src, T** dst, T* buffer, int H, int col_from, int col_to, const float c0, const float c1) { + + for (int i=col_from; i void gaussHorizontal (T** src, T** dst, AlignedBuffer* buffer, int W, int row_from, int row_to, double sigma) { + + if (sigma<0.25) { + // dont perform filtering + if (src!=dst) + for (int i = row_from; i (src, dst, (T*)(buffer->data), W, row_from, row_to, c0, c1); + return; + } + + // horizontal + double q = 0.98711 * sigma - 0.96330; + if (sigma<2.5) + q = 3.97156 - 4.14554 * sqrt (1.0 - 0.26891 * sigma); + double b0 = 1.57825 + 2.44413*q + 1.4281*q*q + 0.422205*q*q*q; + double b1 = 2.44413*q + 2.85619*q*q + 1.26661*q*q*q; + double b2 = -1.4281*q*q - 1.26661*q*q*q; + double b3 = 0.422205*q*q*q; + double B = 1.0 - (b1+b2+b3) / b0; + + b1 /= b0; + b2 /= b0; + b3 /= b0; + + // From: Bill Triggs, Michael Sdika: Boundary Conditions for Young-van Vliet Recursive Filtering + double M[3][3]; + M[0][0] = -b3*b1+1.0-b3*b3-b2; + M[0][1] = (b3+b1)*(b2+b3*b1); + M[0][2] = b3*(b1+b3*b2); + M[1][0] = b1+b3*b2; + M[1][1] = -(b2-1.0)*(b2+b3*b1); + M[1][2] = -(b3*b1+b3*b3+b2-1.0)*b3; + M[2][0] = b3*b1+b2+b1*b1-b2*b2; + M[2][1] = b1*b2+b3*b2*b2-b1*b3*b3-b3*b3*b3-b3*b2+b3; + M[2][2] = b3*(b1+b3*b2); + for (int i=0; i<3; i++) + for (int j=0; j<3; j++) + M[i][j] /= (1.0+b1-b2+b3)*(1.0+b2+(b1-b3)*b3); + + double* temp2 = (double*)buffer->data; + for (int i=row_from; i=0; j--) + temp2[j] = B * temp2[j] + b1*temp2[j+1] + b2*temp2[j+2] + b3*temp2[j+3]; + for (int j=0; j void gaussVertical (T** src, T** dst, AlignedBuffer* buffer, int H, int col_from, int col_to, double sigma) { + + if (sigma<0.25) { + // dont perform filtering + if (src!=dst) + for (int i = 0; i (src, dst, (T*)(buffer->data), H, col_from, col_to, c0, c1); + return; + } + + // vertical + double q = 0.98711 * sigma - 0.96330; + if (sigma<2.5) + q = 3.97156 - 4.14554 * sqrt (1.0 - 0.26891 * sigma); + double b0 = 1.57825 + 2.44413*q + 1.4281*q*q + 0.422205*q*q*q; + double b1 = 2.44413*q + 2.85619*q*q + 1.26661*q*q*q; + double b2 = -1.4281*q*q - 1.26661*q*q*q; + double b3 = 0.422205*q*q*q; + double B = 1.0 - (b1+b2+b3) / b0; + + b1 /= b0; + b2 /= b0; + b3 /= b0; + + // From: Bill Triggs, Michael Sdika: Boundary Conditions for Young-van Vliet Recursive Filtering + double M[3][3]; + M[0][0] = -b3*b1+1.0-b3*b3-b2; + M[0][1] = (b3+b1)*(b2+b3*b1); + M[0][2] = b3*(b1+b3*b2); + M[1][0] = b1+b3*b2; + M[1][1] = -(b2-1.0)*(b2+b3*b1); + M[1][2] = -(b3*b1+b3*b3+b2-1.0)*b3; + M[2][0] = b3*b1+b2+b1*b1-b2*b2; + M[2][1] = b1*b2+b3*b2*b2-b1*b3*b3-b3*b3*b3-b3*b2+b3; + M[2][2] = b3*(b1+b3*b2); + for (int i=0; i<3; i++) + for (int j=0; j<3; j++) + M[i][j] /= (1.0+b1-b2+b3)*(1.0+b2+(b1-b3)*b3); + + double* temp2 = (double*)buffer->data; + for (int i=col_from; i=0; j--) + temp2[j] = B * temp2[j] + b1*temp2[j+1] + b2*temp2[j+2] + b3*temp2[j+3]; + + for (int j=0; j* buffer, int W, int row_from, int row_to, double sigma); +void gaussVertical_unsigned (unsigned short** src, unsigned short** dst, AlignedBuffer* buffer, int H, int col_from, int col_to, double sigma); +void gaussHorizontal_signed (short** src, short** dst, AlignedBuffer* buffer, int W, int row_from, int row_to, double sigma); +void gaussVertical_signed (short** src, short** dst, AlignedBuffer* buffer, int H, int col_from, int col_to, double sigma); +void gaussHorizontal_float (float** src, float** dst, AlignedBuffer* buffer, int W, int row_from, int row_to, double sigma); +void gaussVertical_float (float** src, float** dst, AlignedBuffer* buffer, int H, int col_from, int col_to, double sigma); + +#endif diff --git a/rtengine/helpers.cc b/rtengine/helpers.cc new file mode 100755 index 000000000..63a242d58 --- /dev/null +++ b/rtengine/helpers.cc @@ -0,0 +1,67 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +using namespace rtengine; +using namespace rtengine::procparams; + +std::string* create_stdstring (char* txt) { return new std::string (txt); } +Glib::ustring* create_gustring (char* txt) { return new Glib::ustring (txt); } +void set_stdstring (std::string& s, char* txt) { s = txt; } +void set_gustring (Glib::ustring& s, char* txt) { s = txt; } +char* get_stdstring (std::string& s) { return strdup (s.c_str()); } +char* get_gustring (Glib::ustring& s) { return strdup (s.c_str()); } + +void clear_double_vector (std::vector& d) { d.clear(); } +void append_double_vector (std::vector& d, double dd) { d.push_back(dd); } +void resize_double_vector (std::vector& d, int size) { d.resize (size); } +double get_double_vector (std::vector& d, int i) { return d[i]; } +void set_double_vector (std::vector& d, int i, double x) { d[i] = x; } +int size_double_vector (std::vector& d) { return d.size(); } + +void clear_gustring_vector (std::vector& d) { d.clear(); } +void append_gustring_vector (std::vector& d, const Glib::ustring& dd) { d.push_back(dd); } +void resize_gustring_vector (std::vector& d, int size) { d.resize (size); } +Glib::ustring& get_gustring_vector (std::vector& d, int i) { return d[i]; } +void set_gustring_vector (std::vector& d, int i, const Glib::ustring& x) { d[i] = x; } +int size_gustring_vector (std::vector& d) { return d.size(); } + +void clear_exifpair_vector (std::vector& d) { d.clear(); } +void append_exifpair_vector (std::vector& d, const ExifPair& dd) { d.push_back(dd); } +void resize_exifpair_vector (std::vector& d, int size) { d.resize (size); } +ExifPair& get_exifpair_vector (std::vector& d, int i) { return d[i]; } +void set_exifpair_vector (std::vector& d, int i, const ExifPair& x) { d[i] = x; } +int size_exifpair_vector (std::vector& d) { return d.size(); } + +void clear_iptcpair_vector (std::vector& d) { d.clear(); } +void append_iptcpair_vector (std::vector& d, const IPTCPair& dd) { d.push_back(dd); } +void resize_iptcpair_vector (std::vector& d, int size) { d.resize (size); } +IPTCPair& get_iptcpair_vector (std::vector& d, int i) { return d[i]; } +void set_iptcpair_vector (std::vector& d, int i, const IPTCPair& x) { d[i] = x; } +int size_iptcpair_vector (std::vector& d) { return d.size(); } + +int sizeof_stdstring () { return sizeof(std::string); } +int sizeof_gustring () { return sizeof(Glib::ustring); } +int sizeof_double_vector () { return sizeof(std::vector); } +int sizeof_gustring_vector () { return sizeof(std::vector); } +int sizeof_exifpair_vector () { return sizeof(std::vector); } +int sizeof_iptcpair_vector () { return sizeof(std::vector); } + + diff --git a/rtengine/helpers.h b/rtengine/helpers.h new file mode 100755 index 000000000..e6e454c32 --- /dev/null +++ b/rtengine/helpers.h @@ -0,0 +1,67 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include + +using namespace rtengine; +using namespace rtengine::procparams; + +std::string* create_stdstring (char* txt); +Glib::ustring* create_gustring (char* txt); +void set_stdstring (std::string& s, char* txt); +void set_gustring (Glib::ustring& s, char* txt); +char* get_stdstring (std::string& s); +char* get_gustring (Glib::ustring& s); + +void clear_double_vector (std::vector& d); +void append_double_vector (std::vector& d, double dd); +void resize_double_vector (std::vector& d, int size); +double get_double_vector (std::vector& d, int i); +void set_double_vector (std::vector& d, int i, double x); +int size_double_vector (std::vector& d); + +void clear_gustring_vector (std::vector& d); +void append_gustring_vector (std::vector& d, const Glib::ustring& dd); +void resize_gustring_vector (std::vector& d, int size); +Glib::ustring& get_gustring_vector (std::vector& d, int i); +void set_gustring_vector (std::vector& d, int i, const Glib::ustring& x); +int size_gustring_vector (std::vector& d); + +void clear_exifpair_vector (std::vector& d); +void append_exifpair_vector (std::vector& d, const ExifPair& dd); +void resize_exifpair_vector (std::vector& d, int size); +ExifPair& get_exifpair_vector (std::vector& d, int i); +void set_exifpair_vector (std::vector& d, int i, const ExifPair& x); +int size_exifpair_vector (std::vector& d); + +void clear_iptcpair_vector (std::vector& d); +void append_iptcpair_vector (std::vector& d, const IPTCPair& dd); +void resize_iptcpair_vector (std::vector& d, int size); +IPTCPair& get_iptcpair_vector (std::vector& d, int i); +void set_iptcpair_vector (std::vector& d, int i, const IPTCPair& x); +int size_iptcpair_vector (std::vector& d); + +int sizeof_stdstring (); +int sizeof_gustring (); +int sizeof_double_vector (); +int sizeof_gustring_vector (); +int sizeof_exifpair_vector (); +int sizeof_iptcpair_vector (); + diff --git a/rtengine/hlmultipliers.cc b/rtengine/hlmultipliers.cc new file mode 100755 index 000000000..ea44742ba --- /dev/null +++ b/rtengine/hlmultipliers.cc @@ -0,0 +1,352 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include + +#define MAX(a,b) ((a)<(b)?(b):(a)) + +#define MAXVAL 0xffff +#define CLIP(a) ((a)>0?((a)0)// && phase!=4) +// continue; + if (phase==-1 || phase==0 || phase==2) { + if (rec[0][i][j] == INT_MAX && rec[1][i][j] != INT_MAX && rec[1][i][j] >=0 && rec[2][i][j] != INT_MAX && rec[2][i][j] >=0) { + co = 0; + c1 = 1; + c2 = 2; + } + else if (rec[1][i][j] == INT_MAX && rec[0][i][j] != INT_MAX && rec[0][i][j] >=0 && rec[2][i][j] != INT_MAX && rec[2][i][j] >=0) { + co = 1; + c1 = 0; + c2 = 2; + } + else if (rec[2][i][j] == INT_MAX && rec[1][i][j] != INT_MAX && rec[1][i][j] >=0 && rec[0][i][j] != INT_MAX && rec[0][i][j] >=0) { + co = 2; + c1 = 1; + c2 = 0; + } + else + continue; + + double ratio[2] = {0.0, 0.0}; + int count = 0; + double rato = (double)rec[c1][i][j] / rec[c2][i][j]; + double arato = 0.0; + if (phase==2) { + for (int x=-1; x<=1; x++) + for (int y=-1; y<=1; y++) { + // average m/c color ratios in the surrounding pixels + if (rec[co][i+x][j+y]>=0 && rec[co][i+x][j+y]!=INT_MAX && rec[c1][i+x][j+y]>=0 && rec[c1][i+x][j+y]!=INT_MAX && rec[c2][i+x][j+y]>0 && rec[c2][i+x][j+y]!=INT_MAX) { + double ratt = (double)rec[c1][i+x][j+y] / rec[c2][i+x][j+y]; + if (ratt > rato*1.2 || ratt < rato / 1.2 || rec[co][i+x][j+y]=0 && rec[co][i+x][j+y]!=INT_MAX && rec[c1][i+x][j+y]>=0 && rec[c1][i+x][j+y]!=INT_MAX && rec[c2][i+x][j+y]>0 && rec[c2][i+x][j+y]!=INT_MAX) { + double ratt = (double)rec[c1][i+x][j+y] / rec[c2][i+x][j+y]; + if (ratt > rato*1.05 || ratt < rato / 1.05 || rec[co][i+x][j+y]=0 && rec[co][i+x][j+y]!=INT_MAX && rec[c1][i+x][j+y]>=0 && rec[c1][i+x][j+y]!=INT_MAX && rec[c2][i+x][j+y]>0 && rec[c2][i+x][j+y]!=INT_MAX) { + double ratt = (double)rec[c1][i+x][j+y] / rec[c2][i+x][j+y]; + if (ratt > rato*1.1 || ratt < rato / 1.1 || rec[co][i+x][j+y]1) { //(phase==0 && count>1) || (phase==2 && count>1)) { + rec[co][i][j] = -(int)((rec[c1][i][j] / ratio[0] * count + rec[c2][i][j] / ratio[1] * count) / 2); + changed++; + } + } + else if (phase==1 || phase==3) { + if (rec[0][i][j] == INT_MAX && rec[1][i][j] == INT_MAX && rec[2][i][j] != INT_MAX && rec[2][i][j] >=0) { + co = 2; + c1 = 0; + c2 = 1; + } + else if (rec[0][i][j] == INT_MAX && rec[2][i][j] == INT_MAX && rec[1][i][j] != INT_MAX && rec[1][i][j] >=0) { + co = 1; + c1 = 0; + c2 = 2; + } + else if (rec[1][i][j] == INT_MAX && rec[2][i][j] == INT_MAX && rec[0][i][j] != INT_MAX && rec[0][i][j] >=0) { + co = 0; + c1 = 1; + c2 = 2; + } + else + continue; + + double ratio[2] = {0.0, 0.0}; + int count[2] = {0, 0}; + int ix = 0; + for (int x=-1; x<=1; x++) + for (int y=-1; y<=1; y++) { + // average m/c color ratios in the surrounding pixels + if (rec[co][i+x][j+y]>=0 && rec[co][i+x][j+y]!=INT_MAX && rec[c1][i+x][j+y]>0 && rec[c1][i+x][j+y]!=INT_MAX) { + if ((phase==1 && rec[c1][i+x][j+y]=0 && rec[co][i+x][j+y]!=INT_MAX && rec[c2][i+x][j+y]>0 && rec[c2][i+x][j+y]!=INT_MAX) { + if ((phase==1 && rec[c2][i+x][j+y]2) || (phase==3 && count[0]>1)) { + rec[c1][i][j] = - (int) ((double)rec[co][i][j] / ratio[0] * count[0]); + changed++; + } + if ((phase==1 && count[1]>2) || (phase==3 && count[1]>1)) { + rec[c2][i][j] = - (int) ((double)rec[co][i][j] / ratio[1] * count[1]); + changed++; + } + } + else { + int val = 0; + int num = 0; + for (int c=0; c<3; c++) + if (rec[c][i][j]!=INT_MAX) { + val += rec[c][i][j]; + num++; + } + if (num<3 && num>0) { + for (int c=0; c<3; c++) + rec[c][i][j] = val / num; + } + } + } + + + bool change = false; + for (int i=1; i=H/HR_SCALE-2) + return; + double mr1 = 1.0 - ((double)((i+HR_SCALE/2) % HR_SCALE) / HR_SCALE + 0.5 / HR_SCALE); + int jx = 0; + int maxcol = W/HR_SCALE-2; + for (int j=sx1, jx=0; jx=maxcol) + continue; + double mc1 = 1.0 - ((double)((j+HR_SCALE/2) % HR_SCALE) / HR_SCALE + 0.5 / HR_SCALE); + double mulr = mr1*mc1 * hrmap[0][blr][blc] + mr1*(1.0-mc1) * hrmap[0][blr][blc+1] + (1.0-mr1)*mc1 * hrmap[0][blr+1][blc] + (1.0-mr1)*(1.0-mc1) * hrmap[0][blr+1][blc+1]; + double mulg = mr1*mc1 * hrmap[1][blr][blc] + mr1*(1.0-mc1) * hrmap[1][blr][blc+1] + (1.0-mr1)*mc1 * hrmap[1][blr+1][blc] + (1.0-mr1)*(1.0-mc1) * hrmap[1][blr+1][blc+1]; + double mulb = mr1*mc1 * hrmap[2][blr][blc] + mr1*(1.0-mc1) * hrmap[2][blr][blc+1] + (1.0-mr1)*mc1 * hrmap[2][blr+1][blc] + (1.0-mr1)*(1.0-mc1) * hrmap[2][blr+1][blc+1]; + red[jx] = CLIP(red[jx] * mulr); + green[jx] = CLIP(green[jx] * mulg); + blue[jx] = CLIP(blue[jx] * mulb); + } + } +} + +void RawImageSource::updateHLRecoveryMap_ColorPropagation () { + + // detect maximal pixel values + unsigned short* red = new unsigned short[W]; + unsigned short* blue = new unsigned short[W]; + int maxr = 0, maxg = 0, maxb = 0; + for (int i=32; ifilters) && red[j] > maxr) maxr = red[j]; + if ((ISGREEN(ri,i,j) || !ri->filters) && green[i][j] > maxg) maxg = green[i][j]; + if ((ISBLUE(ri,i,j) || !ri->filters) && blue[j] > maxb) maxb = blue[j]; + } + } + delete [] red; + delete [] blue; + + maxr = maxr * 19 / 20; + maxg = maxg * 19 / 20; + maxb = maxb * 19 / 20; + max[0] = maxr; + max[1] = maxg; + max[2] = maxb; + + // downscale image + int dw = W/HR_SCALE; + int dh = H/HR_SCALE; + Image16* ds = new Image16 (dw, dh); + + // overburnt areas + int** rec[3]; + for (int i=0; i<3; i++) + rec[i] = allocArray (dw, dh); + + unsigned short* reds[HR_SCALE]; + unsigned short* blues[HR_SCALE]; + for (int i=0; i(needhr, H); + needhr = allocArray (W, H); + + for (int i=0; i=max[0] || green[HR_SCALE*i+j][k]>=max[1] || blues[j][k]>=max[2]) + needhr[HR_SCALE*i+j][k] = 1; + else + needhr[HR_SCALE*i+j][k] = 0; + } + for (int j=0; jr[i][j] = sumr / HR_SCALE/HR_SCALE; + ds->g[i][j] = sumg / HR_SCALE/HR_SCALE; + ds->b[i][j] = sumb / HR_SCALE/HR_SCALE; + } + } + for (int i=0; i (hrmap[0], dh); + freeArray (hrmap[1], dh); + freeArray (hrmap[2], dh); + } + + hrmap[0] = allocArray (dw, dh); + hrmap[1] = allocArray (dw, dh); + hrmap[2] = allocArray (dw, dh); + + for (int i=0; ir[i][j]>0 ? (double)rec[0][i][j] / ds->r[i][j] : 1.0; + hrmap[1][i][j] = ds->g[i][j]>0 ? (double)rec[1][i][j] / ds->g[i][j] : 1.0; + hrmap[2][i][j] = ds->b[i][j]>0 ? (double)rec[2][i][j] / ds->b[i][j] : 1.0; + } + + delete ds; + + freeArray (rec[0], dh); + freeArray (rec[1], dh); + freeArray (rec[2], dh); +} + +} + diff --git a/rtengine/hlrecovery.cc b/rtengine/hlrecovery.cc new file mode 100755 index 000000000..d19769f92 --- /dev/null +++ b/rtengine/hlrecovery.cc @@ -0,0 +1,287 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ + +namespace rtengine { + +template T** allocArray (int W, int H) { + + T** t = new T*[H]; + for (int i=0; i maxr) maxr = red[j]; + if (green[i][j] > maxg) maxg = green[i][j]; + if (blue[j] > maxb) maxb = blue[j]; + } + } + delete [] red; + delete [] blue; + + maxr = maxr * 19 / 20; + maxg = maxg * 19 / 20; + maxb = maxb * 19 / 20; + int max[3]; + max[0] = maxr; + max[1] = maxg; + max[2] = maxb; + + printf ("Maximum: R: %d, G: %d, B: %d\n", maxr, maxg, maxb); + + // downscale image + int dw = W/SCALE; + int dh = H/SCALE; + Image16* ds = new Image16 (dw, dh); + + // overburnt areas + int** rec[3]; + for (int i=0; i<3; i++) + rec[i] = allocArray (dw, dh); + + unsigned short* reds[SCALE]; + unsigned short* blues[SCALE]; + for (int i=0; ir[i][j] = sumr / SCALE/SCALE; + ds->g[i][j] = sumg / SCALE/SCALE; + ds->b[i][j] = sumb / SCALE/SCALE; + } + } + for (int i=0; i200) + phase2 = true; + for (int i=1; i=0) { + for (int x=-1; x<=1; x++) + for (int y=-1; y<=1; y++) + // average m/c color ratios in the surrounding pixels + if (rec[m][i+x][j+y]>=0 && rec[m][i+x][j+y]!=INT_MAX && rec[c][i+x][j+y]>0 && rec[c][i+x][j+y]!=INT_MAX) { + double ww = 1.0; + if (!phase2 && (/*(double)(rec[m][i+x][j+y] - rec[m][i][j])/max[m]*(rec[m][i+x][j+y] - rec[m][i][j])/max[m] > 1.0/2 || */rec[c][i+x][j+y]200) + phase2 = true; + for (int i=1; i0 && rec[0][i+x][j+y]!=INT_MAX && rec[1][i+x][j+y]>0 && rec[1][i+x][j+y]!=INT_MAX && rec[2][i+x][j+y]>0 && rec[2][i+x][j+y]!=INT_MAX) { + // convert to yiq + double Y = 0.299 * rec[0][i+x][j+y] + 0.587 * rec[1][i+x][j+y] + 0.114 * rec[2][i+x][j+y]; + double I = 0.596 * rec[0][i+x][j+y] - 0.275 * rec[1][i+x][j+y] - 0.321 * rec[2][i+x][j+y]; + double Q = 0.212 * rec[0][i+x][j+y] - 0.523 * rec[1][i+x][j+y] + 0.311 * rec[2][i+x][j+y]; + if (Y > maxY*7/10) { + double w = 1.0;// / (I*I+Q*Q); + yavg += Y*w; + iavg += I*w; + qavg += Q*w; + weight += w; + count++; + } + } + if ((!phase2 && count>5) || (phase2 && count>3)) { + double Y = yavg / weight; + double I = iavg / weight; + double Q = qavg / weight; + rec[0][i][j] = - (Y + 0.956*I + 0.621*Q); + rec[1][i][j] = - (Y - 0.272*I - 0.647*Q); + rec[2][i][j] = - (Y - 1.105*I + 1.702*Q); + } + } + + } + bool change = false; + for (int i=0; imaxval) + maxval = rec[c][i][j]; + + for (int i=0; i (hrmap[0], dh); + freeArray (hrmap[1], dh); + freeArray (hrmap[2], dh); + } + hrmap[0] = allocArray (dw, dh); + hrmap[1] = allocArray (dw, dh); + hrmap[2] = allocArray (dw, dh); + + this->full = full; + + for (int i=0; ir[i][j]; + hrmap[1][i][j] = (double)rec[1][i][j] / ds->g[i][j]; + hrmap[2][i][j] = (double)rec[2][i][j] / ds->b[i][j]; + } + +/* for (int i=0; ir[i][j] = CLIP (rec[0][i][j]); + ds->g[i][j] = CLIP (rec[1][i][j]); + ds->b[i][j] = CLIP (rec[2][i][j]); + } + ds->save ("test.png"); +*/ + delete ds; + freeArray (rec[0], dh); + freeArray (rec[1], dh); + freeArray (rec[2], dh); + + printf ("HLMap vege\n"); +} + +void RawImageSource::hlRecovery (unsigned short* red, unsigned short* green, unsigned short* blue, int i, int sx1, int sx2, int skip) { + + int blr = (i+SCALE/2) / SCALE - 1; + if (blr<0 || blr>=H/SCALE-1) + return; + double mr1 = 1.0 - ((double)((i+SCALE/2) % SCALE) / SCALE + 0.5 / SCALE); + int jx = 0; + int maxcol = W/SCALE; + for (int j=sx1, jx=0; j=maxcol-1) + continue; + double mc1 = 1.0 - ((double)((j+SCALE/2) % SCALE) / SCALE + 0.5 / SCALE); + double mulr = mr1*mc1 * hrmap[0][blr][blc] + mr1*(1.0-mc1) * hrmap[0][blr][blc+1] + (1.0-mr1)*mc1 * hrmap[0][blr+1][blc] + (1.0-mr1)*(1.0-mc1) * hrmap[0][blr+1][blc+1]; + double mulg = mr1*mc1 * hrmap[1][blr][blc] + mr1*(1.0-mc1) * hrmap[1][blr][blc+1] + (1.0-mr1)*mc1 * hrmap[1][blr+1][blc] + (1.0-mr1)*(1.0-mc1) * hrmap[1][blr+1][blc+1]; + double mulb = mr1*mc1 * hrmap[2][blr][blc] + mr1*(1.0-mc1) * hrmap[2][blr][blc+1] + (1.0-mr1)*mc1 * hrmap[2][blr+1][blc] + (1.0-mr1)*(1.0-mc1) * hrmap[2][blr+1][blc+1]; + red[jx] = CLIP(red[jx] * mulr); + green[jx] = CLIP(green[jx] * mulg); + blue[jx] = CLIP(blue[jx] * mulb); + } +} +} + diff --git a/rtengine/iccjpeg.c b/rtengine/iccjpeg.c new file mode 100755 index 000000000..392259373 --- /dev/null +++ b/rtengine/iccjpeg.c @@ -0,0 +1,256 @@ +/* + * iccprofile.c + * + * This file provides code to read and write International Color Consortium + * (ICC) device profiles embedded in JFIF JPEG image files. The ICC has + * defined a standard format for including such data in JPEG "APP2" markers. + * The code given here does not know anything about the internal structure + * of the ICC profile data; it just knows how to put the profile data into + * a JPEG file being written, or get it back out when reading. + * + * This code depends on new features added to the IJG JPEG library as of + * IJG release 6b; it will not compile or work with older IJG versions. + * + * NOTE: this code would need surgery to work on 16-bit-int machines + * with ICC profiles exceeding 64K bytes in size. If you need to do that, + * change all the "unsigned int" variables to "INT32". You'll also need + * to find a malloc() replacement that can allocate more than 64K. + */ + +#include "iccjpeg.h" +#include /* define malloc() */ + + +/* + * Since an ICC profile can be larger than the maximum size of a JPEG marker + * (64K), we need provisions to split it into multiple markers. The format + * defined by the ICC specifies one or more APP2 markers containing the + * following data: + * Identifying string ASCII "ICC_PROFILE\0" (12 bytes) + * Marker sequence number 1 for first APP2, 2 for next, etc (1 byte) + * Number of markers Total number of APP2's used (1 byte) + * Profile data (remainder of APP2 data) + * Decoders should use the marker sequence numbers to reassemble the profile, + * rather than assuming that the APP2 markers appear in the correct sequence. + */ + +#define ICC_MARKER (JPEG_APP0 + 2) /* JPEG marker code for ICC */ +#define ICC_OVERHEAD_LEN 14 /* size of non-profile data in APP2 */ +#define MAX_BYTES_IN_MARKER 65533 /* maximum data len of a JPEG marker */ +#define MAX_DATA_BYTES_IN_MARKER (MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN) + + +/* + * This routine writes the given ICC profile data into a JPEG file. + * It *must* be called AFTER calling jpeg_start_compress() and BEFORE + * the first call to jpeg_write_scanlines(). + * (This ordering ensures that the APP2 marker(s) will appear after the + * SOI and JFIF or Adobe markers, but before all else.) + */ + +void +write_icc_profile (j_compress_ptr cinfo, + const JOCTET *icc_data_ptr, + unsigned int icc_data_len) +{ + unsigned int num_markers; /* total number of markers we'll write */ + int cur_marker = 1; /* per spec, counting starts at 1 */ + unsigned int length; /* number of bytes to write in this marker */ + + /* Calculate the number of markers we'll need, rounding up of course */ + num_markers = icc_data_len / MAX_DATA_BYTES_IN_MARKER; + if (num_markers * MAX_DATA_BYTES_IN_MARKER != icc_data_len) + num_markers++; + + while (icc_data_len > 0) { + /* length of profile to put in this marker */ + length = icc_data_len; + if (length > MAX_DATA_BYTES_IN_MARKER) + length = MAX_DATA_BYTES_IN_MARKER; + icc_data_len -= length; + + /* Write the JPEG marker header (APP2 code and marker length) */ + jpeg_write_m_header(cinfo, ICC_MARKER, + (unsigned int) (length + ICC_OVERHEAD_LEN)); + + /* Write the marker identifying string "ICC_PROFILE" (null-terminated). + * We code it in this less-than-transparent way so that the code works + * even if the local character set is not ASCII. + */ + jpeg_write_m_byte(cinfo, 0x49); + jpeg_write_m_byte(cinfo, 0x43); + jpeg_write_m_byte(cinfo, 0x43); + jpeg_write_m_byte(cinfo, 0x5F); + jpeg_write_m_byte(cinfo, 0x50); + jpeg_write_m_byte(cinfo, 0x52); + jpeg_write_m_byte(cinfo, 0x4F); + jpeg_write_m_byte(cinfo, 0x46); + jpeg_write_m_byte(cinfo, 0x49); + jpeg_write_m_byte(cinfo, 0x4C); + jpeg_write_m_byte(cinfo, 0x45); + jpeg_write_m_byte(cinfo, 0x0); + + /* Add the sequencing info */ + jpeg_write_m_byte(cinfo, cur_marker); + jpeg_write_m_byte(cinfo, (int) num_markers); + + /* Add the profile data */ + while (length--) { + jpeg_write_m_byte(cinfo, *icc_data_ptr); + icc_data_ptr++; + } + cur_marker++; + } +} + + +/* + * Prepare for reading an ICC profile + */ + +void +setup_read_icc_profile (j_decompress_ptr cinfo) +{ + /* Tell the library to keep any APP2 data it may find */ + jpeg_save_markers(cinfo, ICC_MARKER, 0xFFFF); +} + + +/* + * Handy subroutine to test whether a saved marker is an ICC profile marker. + */ +#ifdef WIN32 +static jboolean +#else +static boolean +#endif +marker_is_icc (jpeg_saved_marker_ptr marker) +{ + return + marker->marker == ICC_MARKER && + marker->data_length >= ICC_OVERHEAD_LEN && + /* verify the identifying string */ + GETJOCTET(marker->data[0]) == 0x49 && + GETJOCTET(marker->data[1]) == 0x43 && + GETJOCTET(marker->data[2]) == 0x43 && + GETJOCTET(marker->data[3]) == 0x5F && + GETJOCTET(marker->data[4]) == 0x50 && + GETJOCTET(marker->data[5]) == 0x52 && + GETJOCTET(marker->data[6]) == 0x4F && + GETJOCTET(marker->data[7]) == 0x46 && + GETJOCTET(marker->data[8]) == 0x49 && + GETJOCTET(marker->data[9]) == 0x4C && + GETJOCTET(marker->data[10]) == 0x45 && + GETJOCTET(marker->data[11]) == 0x0; +} + + +/* + * See if there was an ICC profile in the JPEG file being read; + * if so, reassemble and return the profile data. + * + * TRUE is returned if an ICC profile was found, FALSE if not. + * If TRUE is returned, *icc_data_ptr is set to point to the + * returned data, and *icc_data_len is set to its length. + * + * IMPORTANT: the data at **icc_data_ptr has been allocated with malloc() + * and must be freed by the caller with free() when the caller no longer + * needs it. (Alternatively, we could write this routine to use the + * IJG library's memory allocator, so that the data would be freed implicitly + * at jpeg_finish_decompress() time. But it seems likely that many apps + * will prefer to have the data stick around after decompression finishes.) + * + * NOTE: if the file contains invalid ICC APP2 markers, we just silently + * return FALSE. You might want to issue an error message instead. + */ + +#ifdef WIN32 +jboolean +#else +boolean +#endif +read_icc_profile (j_decompress_ptr cinfo, + JOCTET **icc_data_ptr, + unsigned int *icc_data_len) +{ + jpeg_saved_marker_ptr marker; + int num_markers = 0; + int seq_no; + JOCTET *icc_data; + unsigned int total_length; +#define MAX_SEQ_NO 255 /* sufficient since marker numbers are bytes */ + char marker_present[MAX_SEQ_NO+1]; /* 1 if marker found */ + unsigned int data_length[MAX_SEQ_NO+1]; /* size of profile data in marker */ + unsigned int data_offset[MAX_SEQ_NO+1]; /* offset for data in marker */ + + *icc_data_ptr = NULL; /* avoid confusion if FALSE return */ + *icc_data_len = 0; + + /* This first pass over the saved markers discovers whether there are + * any ICC markers and verifies the consistency of the marker numbering. + */ + + for (seq_no = 1; seq_no <= MAX_SEQ_NO; seq_no++) + marker_present[seq_no] = 0; + + for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) { + if (marker_is_icc(marker)) { + if (num_markers == 0) + num_markers = GETJOCTET(marker->data[13]); + else if (num_markers != GETJOCTET(marker->data[13])) + return FALSE; /* inconsistent num_markers fields */ + seq_no = GETJOCTET(marker->data[12]); + if (seq_no <= 0 || seq_no > num_markers) + return FALSE; /* bogus sequence number */ + if (marker_present[seq_no]) + return FALSE; /* duplicate sequence numbers */ + marker_present[seq_no] = 1; + data_length[seq_no] = marker->data_length - ICC_OVERHEAD_LEN; + } + } + + if (num_markers == 0) + return FALSE; + + /* Check for missing markers, count total space needed, + * compute offset of each marker's part of the data. + */ + + total_length = 0; + for (seq_no = 1; seq_no <= num_markers; seq_no++) { + if (marker_present[seq_no] == 0) + return FALSE; /* missing sequence number */ + data_offset[seq_no] = total_length; + total_length += data_length[seq_no]; + } + + if (total_length <= 0) + return FALSE; /* found only empty markers? */ + + /* Allocate space for assembled data */ + icc_data = (JOCTET *) malloc(total_length * sizeof(JOCTET)); + if (icc_data == NULL) + return FALSE; /* oops, out of memory */ + + /* and fill it in */ + for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) { + if (marker_is_icc(marker)) { + JOCTET FAR *src_ptr; + JOCTET *dst_ptr; + unsigned int length; + seq_no = GETJOCTET(marker->data[12]); + dst_ptr = icc_data + data_offset[seq_no]; + src_ptr = marker->data + ICC_OVERHEAD_LEN; + length = data_length[seq_no]; + while (length--) { + *dst_ptr++ = *src_ptr++; + } + } + } + + *icc_data_ptr = icc_data; + *icc_data_len = total_length; + + return TRUE; +} + diff --git a/rtengine/iccjpeg.h b/rtengine/iccjpeg.h new file mode 100755 index 000000000..494c646f7 --- /dev/null +++ b/rtengine/iccjpeg.h @@ -0,0 +1,80 @@ +/* + * iccprofile.h + * + * This file provides code to read and write International Color Consortium + * (ICC) device profiles embedded in JFIF JPEG image files. The ICC has + * defined a standard format for including such data in JPEG "APP2" markers. + * The code given here does not know anything about the internal structure + * of the ICC profile data; it just knows how to put the profile data into + * a JPEG file being written, or get it back out when reading. + * + * This code depends on new features added to the IJG JPEG library as of + * IJG release 6b; it will not compile or work with older IJG versions. + * + * NOTE: this code would need surgery to work on 16-bit-int machines + * with ICC profiles exceeding 64K bytes in size. See iccprofile.c + * for details. + */ + +#include /* needed to define "FILE", "NULL" */ +#include "jpeglib.h" + + +/* + * This routine writes the given ICC profile data into a JPEG file. + * It *must* be called AFTER calling jpeg_start_compress() and BEFORE + * the first call to jpeg_write_scanlines(). + * (This ordering ensures that the APP2 marker(s) will appear after the + * SOI and JFIF or Adobe markers, but before all else.) + */ + +extern void write_icc_profile JPP((j_compress_ptr cinfo, + const JOCTET *icc_data_ptr, + unsigned int icc_data_len)); + + +/* + * Reading a JPEG file that may contain an ICC profile requires two steps: + * + * 1. After jpeg_create_decompress() but before jpeg_read_header(), + * call setup_read_icc_profile(). This routine tells the IJG library + * to save in memory any APP2 markers it may find in the file. + * + * 2. After jpeg_read_header(), call read_icc_profile() to find out + * whether there was a profile and obtain it if so. + */ + + +/* + * Prepare for reading an ICC profile + */ + +extern void setup_read_icc_profile JPP((j_decompress_ptr cinfo)); + + +/* + * See if there was an ICC profile in the JPEG file being read; + * if so, reassemble and return the profile data. + * + * TRUE is returned if an ICC profile was found, FALSE if not. + * If TRUE is returned, *icc_data_ptr is set to point to the + * returned data, and *icc_data_len is set to its length. + * + * IMPORTANT: the data at **icc_data_ptr has been allocated with malloc() + * and must be freed by the caller with free() when the caller no longer + * needs it. (Alternatively, we could write this routine to use the + * IJG library's memory allocator, so that the data would be freed implicitly + * at jpeg_finish_decompress() time. But it seems likely that many apps + * will prefer to have the data stick around after decompression finishes.) + */ + +#ifdef WIN32 +extern jboolean read_icc_profile JPP((j_decompress_ptr cinfo, + JOCTET **icc_data_ptr, + unsigned int *icc_data_len)); +#else +extern boolean read_icc_profile JPP((j_decompress_ptr cinfo, + JOCTET **icc_data_ptr, + unsigned int *icc_data_len)); +#endif + diff --git a/rtengine/iccmatrices.h b/rtengine/iccmatrices.h new file mode 100755 index 000000000..66d25cb6d --- /dev/null +++ b/rtengine/iccmatrices.h @@ -0,0 +1,74 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _ICCMATRICES_ +#define _ICCMATRICES_ + +const double sRGB_d50[3][3] = {{0.435859, 0.222385, 0.0139162}, + {0.385336, 0.717021, 0.0971389}, + {0.143023, 0.0605936, 0.713817}}; + +const double d50_sRGB[3][3] = {{3.13593293538656, -0.978702373022194, 0.0720490013929888}, + {-1.61878246026431, 1.91609508555177, -0.22919049060526}, + {-0.490913888760734, 0.0334453372795315, 1.40593851447263}}; + +/*const double sRGB_d50[3][3] = {{0.4360520246092, 0.2224915978656, 0.0139291219896}, + {0.38508159282, 0.716886060114, 0.09709700166}, + {0.1430874138552, 0.0606214863936, 0.714185469944}}; + +const double d50_sRGB[3][3] = {{3.13405134405167,-0.978762729953942, 0.0719425766617001}, + {-1.61702771153574,1.91614222810656, -0.228971178679309}, + {-0.49065220876631,0.0334496273068589, 1.40521830559074}};*/ + +const double adobe_d50[3][3] = {{0.6097395054954, 0.3111142944042, 0.0194773131652}, + {0.2052518325737, 0.6256618480686, 0.0608872306106}, + {0.1492308013399, 0.0632241329247, 0.744846530711}}; +const double d50_adobe[3][3] = {{1.9624959949628, -0.978762712052774, 0.0286904764959749}, + {-0.610587687828765,1.91614073756734, -0.140667763143042}, + {-0.34136021627766, 0.0334501217627688, 1.34875045144924}}; +const double prophoto_d50[3][3] = {{0.797675, 0.288040, 0.000000}, + {0.135192, 0.711874, 0.000000}, + {0.0313534,0.000086, 0.825210}}; +const double d50_prophoto[3][3] = {{1.34594335079331, -0.544598514291158, 0}, + {-0.255608118122657, 1.50816768465213, 0}, + {-0.0511117387775285, 0.0205345459181255, 1.21181275069376}}; +const double widegamut_d50[3][3] = {{0.716105, 0.258187, 0.000000}, + {0.100930, 0.724938, 0.0517813}, + {0.147186, 0.0168748, 0.773429}}; +const double d50_widegamut[3][3] = {{1.46280597103052, -0.521792197260068, 0.0349341417298585}, + {-0.184062984909417, 1.44723786022891, -0.0968930022172314}, + {-0.27436071519732, 0.0677226440980744,1.28840945122198}}; +const double bruce_d50[3][3] = {{0.4941607255908, 0.2521412970174, 0.0157852934504}, + {0.3204990468435, 0.684494580042, 0.062927176507}, + {0.1495612990809, 0.0633643619597, 0.746498914581}}; +const double d50_bruce[3][3] = {{2.65042308164152, -0.978762745761462, 0.0264609493245811}, + {-1.20155941925411, 1.9161402914007, -0.136115844662896}, + {-0.42902228923717, 0.0334495071197919, 1.34583900936772}}; +const double beta_d50[3][3] = {{0.671254, 0.303273, 0.000000}, + {0.174583, 0.663786, 0.040701}, + {0.118383, 0.0329413, 0.784509}}; +const double d50_beta[3][3] = {{1.68322591962771, -0.771023599950842, 0.0400013658754702}, + {-0.428235060337656, 1.70655704781303, -0.0885376438040078}, + {-0.236018598193503, 0.0446902191738489,1.27236406897742}}; +const double best_d50[3][3] = {{0.632670, 0.228457, 0.000000}, + {0.204556, 0.737352, 0.00951424}, + {0.126995, 0.0341908, 0.815696}}; +const double d50_best[3][3] = {{1.75525923340349, -0.544133953997468, 0.00634675299435191}, + {-0.483679025800866, 1.50687975713407, -0.017576175021718}, + {-0.253000840399762, 0.0215532098817316,1.22569552576991}}; +#endif diff --git a/rtengine/iccstore.cc b/rtengine/iccstore.cc new file mode 100755 index 000000000..dccf950a5 --- /dev/null +++ b/rtengine/iccstore.cc @@ -0,0 +1,314 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#ifdef WIN32 +#include +#else +#include +#endif +#include +#include + +namespace rtengine { + +ICCStore iccStore; + +const double (*wprofiles[])[3] = {sRGB_d50, adobe_d50, prophoto_d50, widegamut_d50, bruce_d50, beta_d50, best_d50}; +const double (*iwprofiles[])[3] = {d50_sRGB, d50_adobe, d50_prophoto, d50_widegamut, d50_bruce, d50_beta, d50_best}; +const char* wpnames[] = {"sRGB", "Adobe RGB", "ProPhoto", "WideGamut", "BruceRGB", "Beta RGB", "BestRGB"}; + +std::vector getWorkingProfiles () { + + std::vector res; + for (int i=0; i getOutputProfiles () { + + return iccStore.getOutputProfiles (); +} + +std::vector ICCStore::getOutputProfiles () { + + std::vector res; + for (std::map::iterator i=fileProfiles.begin(); i!=fileProfiles.end(); i++) + res.push_back (i->first); + return res; +} + + +ICCStore::ICCStore () { + + cmsErrorAction (LCMS_ERROR_SHOW); + + int N = sizeof(wpnames)/sizeof(wpnames[0]); + for (int i=0; i::iterator r = wMatrices.find (name); + if (r!=wMatrices.end()) + return r->second; + else + return wMatrices["sRGB"]; +} + +TMatrix ICCStore::workingSpaceInverseMatrix (Glib::ustring name) { + + std::map::iterator r = iwMatrices.find (name); + if (r!=iwMatrices.end()) + return r->second; + else + return iwMatrices["sRGB"]; +} + +cmsHPROFILE ICCStore::workingSpace (Glib::ustring name) { + + std::map::iterator r = wProfiles.find (name); + if (r!=wProfiles.end()) + return r->second; + else + return wProfiles["sRGB"]; +} + +cmsHPROFILE ICCStore::workingSpaceGamma (Glib::ustring name) { + + std::map::iterator r = wProfilesGamma.find (name); + if (r!=wProfilesGamma.end()) + return r->second; + else + return wProfilesGamma["sRGB"]; +} + +cmsHPROFILE ICCStore::getProfile (Glib::ustring name) { + + + std::map::iterator r = fileProfiles.find (name); + if (r!=fileProfiles.end()) + return r->second; + else { + if (!name.compare (0, 5, "file:") && Glib::file_test (name.substr(5), Glib::FILE_TEST_EXISTS) && !Glib::file_test (name.substr(5), Glib::FILE_TEST_IS_DIR)) { + ProfileContent pc (name.substr(5)); + if (pc.data) { + cmsHPROFILE profile = pc.toProfile (); + if (profile) { + fileProfiles[name] = profile; + fileProfileContents[name] = pc; + return profile; + } + } + } + } + return NULL; +} + +ProfileContent ICCStore::getContent (Glib::ustring name) { + + return fileProfileContents[name]; +} + +std::vector ICCStore::parseDir (Glib::ustring pdir) { + + fileProfiles.clear (); + fileProfileContents.clear (); + std::vector result; + if (pdir!="") { + // process directory + Glib::ustring dirname = pdir; + Glib::Dir* dir = NULL; + try { + if (!Glib::file_test (dirname, Glib::FILE_TEST_IS_DIR)) + return result; + dir = new Glib::Dir (dirname); + } + catch (Glib::Exception& fe) { + return result; + } + dirname = dirname + "/"; + for (Glib::DirIterator i = dir->begin(); i!=dir->end(); ++i) { + Glib::ustring fname = dirname + *i; + Glib::ustring sname = *i; + // ignore directories + if (!Glib::file_test (fname, Glib::FILE_TEST_IS_DIR)) { + int lastdot = sname.find_last_of ('.'); + if (lastdot!=Glib::ustring::npos && lastdot<=sname.size()-4 && (!sname.casefold().compare (lastdot, 4, ".icm") || !sname.casefold().compare (lastdot, 4, ".icc"))) { +// printf ("processing file %s...\n", fname.c_str()); + Glib::ustring name = sname.substr(0,lastdot); + ProfileContent pc (fname); + if (pc.data) { + cmsHPROFILE profile = pc.toProfile (); + if (profile) { + fileProfiles[name] = profile; + fileProfileContents[name] = pc; + result.push_back (name); + } + } + } + } + } + delete dir; + } + return result; +} + +ProfileContent::ProfileContent (Glib::ustring fileName) { + + data = NULL; + FILE* f = g_fopen (fileName.c_str(), "rb"); + if (!f) + return; + fseek (f, 0, SEEK_END); + length = ftell (f); + fseek (f, 0, SEEK_SET); + data = new char[length+1]; + fread (data, length, 1, f); + data[length] = 0; + fclose (f); +} + +ProfileContent::ProfileContent (const ProfileContent& other) { + + length = other.length; + if (other.data) { + data = new char[length+1]; + memcpy (data, other.data, length+1); + } + else + data = NULL; +} + +ProfileContent& ProfileContent::operator= (const ProfileContent other) { + + length = other.length; + if (data) + delete [] data; + if (other.data) { + data = new char[length+1]; + memcpy (data, other.data, length+1); + } + else + data = NULL; + return *this; +} + +ProfileContent::~ProfileContent () { + + if (data) + delete [] data; +} + +cmsHPROFILE ProfileContent::toProfile () { + + if (data) + return cmsOpenProfileFromMem (data, length); + else + return NULL; +} + +cmsHPROFILE ICCStore::createFromMatrix (const double matrix[3][3], bool gamma, Glib::ustring name) { + + static const unsigned phead[] = + { 1024, 0, 0x2100000, 0x6d6e7472, 0x52474220, 0x58595a20, 0, 0, 0, + 0x61637370, 0, 0, 0, 0, 0, 0, 0, 0xf6d6, 0x10000, 0xd32d }; + unsigned pbody[] = + { 10, 0x63707274, 0, 36, /* cprt */ + 0x64657363, 0, 40, /* desc */ + 0x77747074, 0, 20, /* wtpt */ + 0x626b7074, 0, 20, /* bkpt */ + 0x72545243, 0, 14, /* rTRC */ + 0x67545243, 0, 14, /* gTRC */ + 0x62545243, 0, 14, /* bTRC */ + 0x7258595a, 0, 20, /* rXYZ */ + 0x6758595a, 0, 20, /* gXYZ */ + 0x6258595a, 0, 20 }; /* bXYZ */ + static const unsigned pwhite[] = { 0xf351, 0x10000, 0x116cc }; + // 0x63757276 : curveType, 0 : reserved, 1 : entries (1=gamma, 0=identity), 0x1000000=1.0 + unsigned pcurve[] = { 0x63757276, 0, 0, 0x1000000 }; +// unsigned pcurve[] = { 0x63757276, 0, 1, 0x1000000 }; + + if (gamma) { + pcurve[2] = 1; + pcurve[3] = 0x1f00000; + } + + // constructing profile header + unsigned* oprof = new unsigned [phead[0]/sizeof(unsigned)]; + memset (oprof, 0, phead[0]); + memcpy (oprof, phead, sizeof(phead)); + + oprof[0] = 132 + 12*pbody[0]; + + // constructing tag directory (pointers inside the file), and types + // 0x74657874 : text + // 0x64657363 : description tag + for (int i=0; i < pbody[0]; i++) { + oprof[oprof[0]/4] = i ? (i > 1 ? 0x58595a20 : 0x64657363) : 0x74657874; + pbody[i*3+2] = oprof[0]; + oprof[0] += (pbody[i*3+3] + 3) & -4; + } + memcpy (oprof+32, pbody, sizeof(pbody)); + + // wtpt + memcpy ((char *)oprof+pbody[8]+8, pwhite, sizeof(pwhite)); + + // r/g/b TRC + for (int i=4; i < 7; i++) + memcpy ((char *)oprof+pbody[i*3+2], pcurve, sizeof(pcurve)); + + // r/g/b XYZ +// pseudoinverse ((double (*)[3]) out_rgb[output_color-1], inverse, 3); + for (int i=0; i < 3; i++) + for (int j=0; j < 3; j++) { + oprof[pbody[j*3+23]/4+i+2] = matrix[j][i] * 0x10000 + 0.5; +// for (num = k=0; k < 3; k++) +// num += xyzd50_srgb[i][k] * inverse[j][k]; + } + + // convert to network byte order + for (int i=0; i < phead[0]/4; i++) + oprof[i] = htonl(oprof[i]); + + // cprt + strcpy ((char *)oprof+pbody[2]+8, "--rawtherapee profile--"); + + // desc + oprof[pbody[5]/4+2] = name.size() + 1; + strcpy ((char *)oprof+pbody[5]+12, name.c_str()); + + + return cmsOpenProfileFromMem (oprof, ntohl(oprof[0])); +} +} diff --git a/rtengine/iccstore.h b/rtengine/iccstore.h new file mode 100755 index 000000000..a7434bec6 --- /dev/null +++ b/rtengine/iccstore.h @@ -0,0 +1,82 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef __ICCSTORE__ +#define __ICCSTORE__ + +#include +#include +#include +#include + +namespace rtengine { + +typedef const double (*TMatrix)[3]; + +class ProfileContent { + + public: + char* data; + int length; + + ProfileContent (): data(NULL), length(0) {} + ProfileContent (Glib::ustring fileName); + ProfileContent (const ProfileContent& other); + ~ProfileContent (); + ProfileContent& operator= (const ProfileContent other); + cmsHPROFILE toProfile (); +}; + +class ICCStore { + + std::map wProfiles; + std::map wProfilesGamma; + std::map wMatrices; + std::map iwMatrices; + + std::map fileProfiles; + std::map fileProfileContents; + + cmsHPROFILE xyz; + cmsHPROFILE srgb; + + public: + ICCStore (); + + int numOfWProfiles (); + cmsHPROFILE createFromMatrix (const double matrix[3][3], bool gamma=false, Glib::ustring name=""); + cmsHPROFILE workingSpace (Glib::ustring name); + cmsHPROFILE workingSpaceGamma (Glib::ustring name); + TMatrix workingSpaceMatrix (Glib::ustring name); + TMatrix workingSpaceInverseMatrix (Glib::ustring name); + + cmsHPROFILE getProfile (Glib::ustring name); + std::vector parseDir (Glib::ustring pdir); + ProfileContent getContent (Glib::ustring name); + + cmsHPROFILE getXYZProfile () { return xyz; } + cmsHPROFILE getsRGBProfile () { return srgb; } + std::vector getOutputProfiles (); +}; + +extern ICCStore iccStore; + +//extern const char* wpnames[]; +} +#endif + diff --git a/rtengine/iimage.h b/rtengine/iimage.h new file mode 100755 index 000000000..54a8e2014 --- /dev/null +++ b/rtengine/iimage.h @@ -0,0 +1,96 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _IIMAGE_ +#define _IIMAGE_ + +#include +#include + +namespace rtengine { + + class ProgressListener; + + /** This class represents an image (the result of the image processing) */ + class IImage { + public: + /** Returns a mutex that can is useful in many situations. No image operations shuold be performed without locking this mutex. + * @return The mutex */ + virtual Glib::Mutex& getMutex (); + virtual cmsHPROFILE getProfile (); + /** Returns the width of the image. + * @return The width of the image */ + virtual int getWidth (); + /** Returns the height of the image. + * @return The height of the image */ + virtual int getHeight (); + /** Returns the bits per pixel of the image. + * @return The bits per pixel of the image */ + virtual int getBitsPerPixel (); + /** Saves the image to file. It autodetects the format (jpg, tif, png are supported). + * @param fname is the name of the file + @return the error code, 0 if none */ + virtual int saveToFile (Glib::ustring fname); + /** Saves the image to file in a png format. + * @param fname is the name of the file + * @param compression is the amount of compression (0-6), -1 corresponds to the default + * @param bps can be 8 or 16 depending on the bits per pixels the output file will have + @return the error code, 0 if none */ + virtual int saveAsPNG (Glib::ustring fname, int compression = -1, int bps = -1); + /** Saves the image to file in a jpg format. + * @param fname is the name of the file + * @param quality is the quality of the jpeg (0...100), set it to -1 to use default + @return the error code, 0 if none */ + virtual int saveAsJPEG (Glib::ustring fname, int quality = 100); + /** Saves the image to file in a tif format. + * @param fname is the name of the file + * @param bps can be 8 or 16 depending on the bits per pixels the output file will have + @return the error code, 0 if none */ + virtual int saveAsTIFF (Glib::ustring fname, int bps = -1); + /** Sets the progress listener if you want to follow the progress of the image saving operations (optional). + * @param pl is the pointer to the class implementing the ProgressListener interface */ + virtual void setSaveProgressListener (ProgressListener* pl); + /** Free the image */ + virtual void free (); + }; + + /** This class represents an image having a classical 8 bits/pixel representation */ + class IImage8 : public IImage { + public: + /** Returns the pixel data, in r/g/b order from top left to bottom right continously. + * @return a pointer to the pixel data */ + virtual const unsigned char* getData (); + }; + + /** This class represents an image having a 16 bits/pixel planar representation. + The planes are stored as two dimensional arrays. All the rows have a 8-byte alignment. */ + class IImage16 : public IImage { + public: + /** Returns the "red" plane data. + * @return the two dimensional array of the red plane */ + virtual unsigned short** getRPlane (); + /** Returns the "green" plane data. + * @return the two dimensional array of the green plane */ + virtual unsigned short** getGPlane (); + /** Returns the "blue" plane data. + * @return the two dimensional array of the blue plane */ + virtual unsigned short** getBPlane (); + }; +} + +#endif diff --git a/rtengine/image16.cc b/rtengine/image16.cc new file mode 100755 index 000000000..4fe4994a4 --- /dev/null +++ b/rtengine/image16.cc @@ -0,0 +1,244 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include + +using namespace rtengine; + +unsigned short** IImage16::getRPlane () {} +unsigned short** IImage16::getGPlane () {} +unsigned short** IImage16::getBPlane () {} + +Image16::Image16 () + : r (NULL), g (NULL), b (NULL), data (NULL), unaligned (NULL) { +} + +Image16::Image16 (int w, int h) + : width(w), height (h), r (NULL), g (NULL), b (NULL), data (NULL), unaligned (NULL) { + + allocate (w, h); +} + +Image16::~Image16 () { + + if (data!=NULL) { + delete [] unaligned; + delete [] r; + delete [] g; + delete [] b; + } +} + +void Image16::allocate (int width, int height) { + + if (data!=NULL) { + delete [] unaligned; + delete [] r; + delete [] g; + delete [] b; + } + + int lsize = width + 8 - width % 8; + unaligned = new unsigned char[16 + 3 * lsize * sizeof(short) * height]; + + unsigned long poin = (unsigned long)unaligned + 16 - (unsigned long)unaligned % 16; + data = (unsigned short*) (poin); + + rowstride = lsize * sizeof(unsigned short); + planestride = rowstride * height; + + unsigned long redstart = poin + 0*planestride; + unsigned long greenstart = poin + 1*planestride; + unsigned long bluestart = poin + 2*planestride; + + r = new unsigned short*[height]; + g = new unsigned short*[height]; + b = new unsigned short*[height]; + for (int i=0; iwidth = width; + this->height = height; +} + +void Image16::getScanline (int row, unsigned char* buffer, int bps) { + + if (data==NULL) + return; + + if (bps==16) { + int ix = 0; + unsigned short* sbuffer = (unsigned short*) buffer; + for (int i=0; i> 8; + buffer[ix++] = g[row][i] >> 8; + buffer[ix++] = b[row][i] >> 8; + } + } +} + +void Image16::setScanline (int row, unsigned char* buffer, int bps) { + + if (data==NULL) + return; + + if (bps==8) { + int ix = 0; + for (int i=0; ir[i], r[i], width*sizeof(unsigned short)); + memcpy (cp->g[i], g[i], width*sizeof(unsigned short)); + memcpy (cp->b[i], b[i], width*sizeof(unsigned short)); + } + + return cp; +} + +Image16* Image16::rotate (int deg) { + + if (deg==90) { + Image16* result = new Image16 (height, width); + for (int i=0; ir[i][j] = r[height-1-j][i]; + result->g[i][j] = g[height-1-j][i]; + result->b[i][j] = b[height-1-j][i]; + } + return result; + } + else if (deg==270) { + Image16* result = new Image16 (height, width); + for (int i=0; ir[i][j] = r[j][width-1-i]; + result->g[i][j] = g[j][width-1-i]; + result->b[i][j] = b[j][width-1-i]; + } + return result; + } + else if (deg==180) { + Image16* result = new Image16 (width, height); + for (int i=0; ir[i][j] = r[height-1-i][width-1-j]; + result->g[i][j] = g[height-1-i][width-1-j]; + result->b[i][j] = b[height-1-i][width-1-j]; + } + return result; + } + else + return NULL; +} + +Image16* Image16::hflip () { + + Image16* result = new Image16 (width, height); + for (int i=0; ir[i][j] = r[i][width-1-j]; + result->g[i][j] = g[i][width-1-j]; + result->b[i][j] = b[i][width-1-j]; + } + return result; + +} + +Image16* Image16::vflip () { + + Image16* result = new Image16 (width, height); + for (int i=0; ir[i][j] = r[height-1-i][j]; + result->g[i][j] = g[height-1-i][j]; + result->b[i][j] = b[height-1-i][j]; + } + return result; + +} + +Image16* Image16::resize (int nw, int nh, TypeInterpolation interp) { + + if (interp == TI_Nearest) { + Image16* res = new Image16 (nw, nh); + for (int i=0; ir[i][j] = r[ri][ci]; + res->g[i][j] = g[ri][ci]; + res->b[i][j] = b[ri][ci]; + } + } + return res; + } + else if (interp == TI_Bilinear) { + Image16* res = new Image16 (nw, nh); + for (int i=0; i=height) sy = height-1; + double dy = (double)i*height/nh - sy; + int ny = sy+1; + if (ny>=height) ny = sy; + for (int j=0; j=width) sx = width; + double dx = (double)j*width/nw - sx; + int nx = sx+1; + if (nx>=width) nx = sx; + res->r[i][j] = r[sy][sx]*(1-dx)*(1-dy) + r[sy][nx]*dx*(1-dy) + r[ny][sx]*(1-dx)*dy + r[ny][nx]*dx*dy; + res->g[i][j] = g[sy][sx]*(1-dx)*(1-dy) + g[sy][nx]*dx*(1-dy) + g[ny][sx]*(1-dx)*dy + g[ny][nx]*dx*dy; + res->b[i][j] = b[sy][sx]*(1-dx)*(1-dy) + b[sy][nx]*dx*(1-dy) + b[ny][sx]*(1-dx)*dy + b[ny][nx]*dx*dy; + } + } + return res; + } + return NULL; +} diff --git a/rtengine/image16.h b/rtengine/image16.h new file mode 100755 index 000000000..256c8b8eb --- /dev/null +++ b/rtengine/image16.h @@ -0,0 +1,86 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +// +// A class representing a 16 bit rgb image with separate planes and 16 byte aligned data +// +#ifndef _IMAGE16_ +#define _IMAGE16_ + +#include +#include + +namespace rtengine { + +enum TypeInterpolation { TI_Nearest, TI_Bilinear }; + +class Image16 : public ImageIO, public IImage16 { + + private: + unsigned char* unaligned; + + public: + int rowstride; + int planestride; + + int width; + int height; + + unsigned short* data; + + unsigned short** r; + unsigned short** g; + unsigned short** b; + + + Image16 (); + Image16 (int width, int height); + ~Image16 (); + + Image16* copy (); + + Image16* rotate (int deg); + Image16* hflip (); + Image16* vflip (); + Image16* resize (int nw, int nh, TypeInterpolation interp); + + virtual int getW () { return width; } + virtual int getH () { return height; } + virtual void allocate (int width, int height); + virtual int getBPS () { return 16; } + virtual void getScanline (int row, unsigned char* buffer, int bps); + virtual void setScanline (int row, unsigned char* buffer, int bps); + + // functions inherited from IImage16: + virtual Glib::Mutex& getMutex () { return mutex (); } + virtual cmsHPROFILE getProfile () { return getEmbeddedProfile (); } + virtual int getWidth () { return width; } + virtual int getHeight () { return height; } + virtual int getBitsPerPixel () { return 16; } + virtual int saveToFile (Glib::ustring fname) { return save (fname); } + virtual int saveAsPNG (Glib::ustring fname, int compression = -1, int bps = -1) { return savePNG (fname, compression, bps); } + virtual int saveAsJPEG (Glib::ustring fname, int quality = 100) { return saveJPEG (fname, quality); } + virtual int saveAsTIFF (Glib::ustring fname, int bps = -1) { return saveTIFF (fname, bps); } + virtual void setSaveProgressListener (ProgressListener* pl) { return setProgressListener (pl); } + virtual void free () { delete this; } + virtual unsigned short** getRPlane () { return r; } + virtual unsigned short** getGPlane () { return g; } + virtual unsigned short** getBPlane () { return b; } +}; +}; +#endif diff --git a/rtengine/image8.cc b/rtengine/image8.cc new file mode 100755 index 000000000..34d1e4973 --- /dev/null +++ b/rtengine/image8.cc @@ -0,0 +1,109 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +using namespace rtengine; + +const unsigned char* IImage8::getData () {} + +Image8::Image8 () + : width(-1), height(-1), data(NULL) { +} + +Image8::Image8 (int w, int h) + : width(w), height (h), data(NULL) { + + allocate (w, h); +} + +void Image8::allocate (int width, int height) { + + if (data!=NULL) + delete [] data; + + data = new unsigned char [width * height * 3]; + this->width = width; + this->height = height; +} + +Image8::~Image8 () { + + if (data!=NULL) + delete [] data; +} + +void Image8::getScanline (int row, unsigned char* buffer, int bps) { + + if (data==NULL) + return; + + if (bps==8) + memcpy (buffer, data + row*width*3, width*3); + else if (bps==16) { + unsigned short* sbuffer = (unsigned short*) buffer; + for (int i=0, ix = row*width*3; i> 8; + } +} + +unsigned char Image8::r (int row, int col) { + + return data[3*(row*width+col)]; +} + +unsigned char Image8::g (int row, int col) { + + return data[3*(row*width+col)+1]; +} + +unsigned char Image8::b (int row, int col) { + + return data[3*(row*width+col)+2]; +} + +void Image8::r (int row, int col, unsigned char val) { + + data[3*(row*width+col)] = val; +} + +void Image8::g (int row, int col, unsigned char val) { + + data[3*(row*width+col)+1] = val; +} + +void Image8::b (int row, int col, unsigned char val) { + + data[3*(row*width+col)+2] = val; +} + diff --git a/rtengine/image8.h b/rtengine/image8.h new file mode 100755 index 000000000..289b82009 --- /dev/null +++ b/rtengine/image8.h @@ -0,0 +1,71 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +// +// A class representing a 8 bit rgb image without alpha channel +// +#ifndef _IMAGE8_ +#define _IMAGE8_ + +#include +#include + +namespace rtengine { + +class Image8 : public ImageIO, public IImage8 { + + public: + unsigned char* data; + int width; + int height; + + Image8 (); + Image8 (int width, int height); + ~Image8 (); + + unsigned char r (int row, int col); + unsigned char g (int row, int col); + unsigned char b (int row, int col); + void r (int row, int col, unsigned char val); + void g (int row, int col, unsigned char val); + void b (int row, int col, unsigned char val); + + virtual int getW () { return width; } + virtual int getH () { return height; } + virtual void allocate (int width, int height); + virtual int getBPS () { return 8; } + virtual void getScanline (int row, unsigned char* buffer, int bps); + virtual void setScanline (int row, unsigned char* buffer, int bps); + + // functions inherited from IImage*: + virtual Glib::Mutex& getMutex () { return mutex (); } + virtual cmsHPROFILE getProfile () { return getEmbeddedProfile (); } + virtual int getWidth () { return width; } + virtual int getHeight () { return height; } + virtual int getBitsPerPixel () { return 16; } + virtual int saveToFile (Glib::ustring fname) { return save (fname); } + virtual int saveAsPNG (Glib::ustring fname, int compression = -1, int bps = -1) { return savePNG (fname, compression, bps); } + virtual int saveAsJPEG (Glib::ustring fname, int quality = 100) { return saveJPEG (fname, quality); } + virtual int saveAsTIFF (Glib::ustring fname, int bps = -1) { return saveTIFF (fname, bps); } + virtual void setSaveProgressListener (ProgressListener* pl) { setProgressListener (pl); } + virtual void free () { delete this; } + virtual const unsigned char* getData () { return data; } + +}; +}; +#endif diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc new file mode 100755 index 000000000..dd5055a65 --- /dev/null +++ b/rtengine/imagedata.cc @@ -0,0 +1,418 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include + +using namespace rtengine; + +extern "C" IptcData *iptc_data_new_from_jpeg_file (FILE* infile); + +ImageMetaData* ImageMetaData::fromFile (const Glib::ustring& fname, RawMetaDataLocation* rml) { + + return new ImageData (fname, rml); +} + +ImageData::ImageData (Glib::ustring fname, RawMetaDataLocation* ri) { + + int dotpos = fname.find_last_of ('.'); + root = NULL; + iptc = NULL; +#ifdef RAWZOR_SUPPORT + // RAWZOR support begin + if (dotposexifBase>=0 || ri->ciffBase>=0)) { + FILE* f = g_fopen (fname.c_str (), "rb"); + if (f) { + fseek (f, 0, SEEK_END); + int rzwSize = ftell (f); + char* rzwData = new char [rzwSize]; + fseek (f, 0, SEEK_SET); + fread (rzwData, 1, rzwSize, f); + fclose(f); + int rawSize; + if (!m_rwz_check (rzwData, rzwSize, &rawSize)) { + char* rawData = new char [rawSize]; + if (!m_rwz_get_meta_only (rzwData, rzwSize, rawData, rawSize)) { + std::string tfname; + int fd = Glib::file_open_tmp (tfname, ""); + FILE* tf = fdopen (fd, "w+b"); + fwrite (rawData, 1, rawSize, tf); + if (ri->exifBase>=0) + root = rtexif::ExifManager::parse (tf, ri->exifBase); + else if (ri->ciffBase>=0) + root = rtexif::ExifManager::parseCIFF (tf, ri->ciffBase, ri->ciffLength); + fclose (tf); + ::g_remove (tfname.c_str()); + extractInfo (); + } + delete [] rawData; + + } + delete [] rzwData; + } + } + // RAWZOR support end + else +#endif + if (ri && (ri->exifBase>=0 || ri->ciffBase>=0)) { + FILE* f = g_fopen (fname.c_str(), "rb"); + if (f) { + if (ri->exifBase>=0) { + root = rtexif::ExifManager::parse (f, ri->exifBase); + if (root) { + rtexif::Tag* t = root->getTag (0x83BB); + if (t) + iptc = iptc_data_new_from_data ((unsigned char*)t->getValue (), (unsigned)t->getValueSize ()); + } + } + else if (ri->ciffBase>=0) + root = rtexif::ExifManager::parseCIFF (f, ri->ciffBase, ri->ciffLength); + fclose (f); + extractInfo (); + } + } + else if (dotposgetTag (0x83BB); + if (t) + iptc = iptc_data_new_from_data ((unsigned char*)t->getValue (), (unsigned)t->getValueSize ()); + } + } + } + else { + root = new rtexif::TagDirectory (); + shutter = 0; + aperture = 0; + iso_speed = 0; + lens = "Unknown"; + make = "Unknown"; + model = "Unknown"; + focal_len = 0; + memset (&time, 0, sizeof(time)); + } +} + +void ImageData::extractInfo () { + + if (!root) + return; + + char buffer[256]; + + make = ""; + model = ""; + shutter = 0; + aperture = 0; + focal_len = 0; + iso_speed = 0; + memset (&time, 0, sizeof(time)); + + if (root->getTag ("Make")) + make = root->getTag ("Make")->valueToString (); + if (root->getTag ("Model")) + model = root->getTag ("Model")->valueToString (); + + rtexif::TagDirectory* exif = NULL; + if (root->getTag ("Exif")) + exif = root->getTag ("Exif")->getDirectory (); + + if (exif) { + + // standard exif tags + if (exif->getTag ("ShutterSpeedValue")) + shutter = exif->getTag ("ShutterSpeedValue")->toDouble (); + if (exif->getTag ("ExposureTime")) + shutter = exif->getTag ("ExposureTime")->toDouble (); + if (exif->getTag ("ApertureValue")) + aperture = exif->getTag ("ApertureValue")->toDouble (); + if (exif->getTag ("FNumber")) + aperture = exif->getTag ("FNumber")->toDouble (); + if (exif->getTag ("FocalLength")) + focal_len = exif->getTag ("FocalLength")->toDouble (); + if (exif->getTag ("ISOSpeedRatings")) + iso_speed = exif->getTag ("ISOSpeedRatings")->toDouble (); + if (exif->getTag ("DateTimeOriginal")) { + if (sscanf ((const char*)exif->getTag("DateTimeOriginal")->getValue(), "%d:%d:%d %d:%d:%d", &time.tm_year, &time.tm_mon, &time.tm_mday, &time.tm_hour, &time.tm_min, &time.tm_sec) == 6) { + time.tm_year -= 1900; + time.tm_mon -= 1; + } + } + // guess lens... + lens = "Unknown"; + + if (exif->getTag ("MakerNote")) { + rtexif::TagDirectory* mnote = exif->getTag ("MakerNote")->getDirectory(); + if (mnote && !make.compare (0, 5, "NIKON")) { + bool lensOk = false; + if (mnote->getTag ("LensData")) { + std::string ldata = mnote->getTag ("LensData")->valueToString (); + int pos; + if (ldata.size()>10 && (pos=ldata.find ("Lens = "))!=Glib::ustring::npos) { + lens = ldata.substr (pos + 7); + if (lens.compare (0, 7, "Unknown")) + lensOk = true; + } + } + if (!lensOk && mnote->getTag ("Lens")) { + std::string ldata = mnote->getTag ("Lens")->valueToString (); + int i=0, j=0; + double n[4]; + for (int m=0; m<4; m++) { + while (igetTag ("LensType")) { + std::string ldata = mnote->getTag ("LensType")->valueToString (); + if (ldata.size()>1) { + lens = ldata; + lensOk = true; + } + } + if (!lensOk && mnote->getTag ("CanonCameraSettings")) { + std::string ccs = mnote->getTag ("CanonCameraSettings")->valueToString (); + int i = ccs.find ("LongFocal = "); + double a = 0; + if (i!=ccs.npos) { + i += 12; + int j = i; + while (j!=ccs.npos && ccs[j]!='\n' && ccs[j]!=' ') j++; + a = atof (ccs.substr (i, j-i).c_str()); + } + i = ccs.find ("ShortFocal = "); + double b = 0; + if (i!=ccs.npos) { + i += 13; + int j = i; + while (j!=ccs.npos && ccs[j]!='\n' && ccs[j]!=' ') j++; + b = atof (ccs.substr (i, j-i).c_str()); + } + if (a>0 && b>0) { + std::ostringstream str; + if (a==b) + str << "Unknown " << a << "mm"; + else + str << "Unknown " << b << "-" << a << "mm"; + lens = str.str(); + } + } + } + else if (mnote && !make.compare (0, 6, "PENTAX")) { + if (mnote->getTag ("LensType")) + lens = mnote->getTag ("LensType")->valueToString (); + } + else if (mnote && (!make.compare (0, 4, "SONY") || !make.compare (0, 6, "KONICA"))) { + if (mnote->getTag ("LensID")) + lens = mnote->getTag ("LensID")->valueToString (); + } + else if (mnote && !make.compare (0, 7, "OLYMPUS")) { + if (mnote->getTag ("Equipment")) { + rtexif::TagDirectory* eq = mnote->getTag ("Equipment")->getDirectory (); + if (eq->getTag ("LensType")) + lens = eq->getTag ("LensType")->valueToString (); + } + } + } + } +} + +ImageData::~ImageData () { + + delete root; + if (iptc) + iptc_data_free (iptc); +} + +const std::vector ImageData::getIPTCData () const { + + std::vector iptcc; + if (!iptc) + return iptcc; + + unsigned char buffer[2100]; + for (int i=0; i<16; i++) { + IptcDataSet* ds = iptc_data_get_next_dataset (iptc, NULL, IPTC_RECORD_APP_2, strTags[i].tag); + if (ds) { + iptc_dataset_get_data (ds, buffer, 2100); + procparams::IPTCPair ic; + ic.field = strTags[i].field; + try { + ic.values.push_back (Glib::locale_to_utf8((char*)buffer)); + } + catch (const Glib::ConvertError& e) { + ic.values.push_back (Glib::convert_with_fallback((char*)buffer, "UTF8", "LATIN1","?")); + } + iptcc.push_back (ic); + iptc_dataset_unref (ds); + } + } + IptcDataSet* ds = NULL; + procparams::IPTCPair ickw; + ickw.field = "Keywords"; + while (ds=iptc_data_get_next_dataset (iptc, ds, IPTC_RECORD_APP_2, IPTC_TAG_KEYWORDS)) { + iptc_dataset_get_data (ds, buffer, 2100); + try { + ickw.values.push_back (Glib::locale_to_utf8((char*)buffer)); + } + catch (const Glib::ConvertError& e) { + ickw.values.push_back (Glib::convert_with_fallback((char*)buffer, "UTF8", "LATIN1","?")); + } + } + iptcc.push_back (ickw); + ds = NULL; + procparams::IPTCPair icsc; + icsc.field = "SupplementalCategories"; + while (ds=iptc_data_get_next_dataset (iptc, ds, IPTC_RECORD_APP_2, IPTC_TAG_SUPPL_CATEGORY)) { + iptc_dataset_get_data (ds, buffer, 2100); + try { + icsc.values.push_back (Glib::locale_to_utf8((char*)buffer)); + } + catch (const Glib::ConvertError& e) { + icsc.values.push_back (Glib::convert_with_fallback((char*)buffer, "UTF8", "LATIN1","?")); + } + iptc_dataset_unref (ds); + } + iptcc.push_back (icsc); +} + +//------inherited functions--------------// + + +std::string ImageMetaData::apertureToString (double aperture) { + + char buffer[256]; + sprintf (buffer, "%0.1f", aperture); + return buffer; +} + +std::string ImageMetaData::shutterToString (double shutter) { + + char buffer[256]; + if (shutter > 0.0 && shutter < 0.9) + sprintf (buffer, "1/%0.0f", 1.0 / shutter); + else + sprintf (buffer, "%0.1f", shutter); + return buffer; +} + +double ImageMetaData::shutterFromString (std::string s) { + + int i = s.find_first_of ('/'); + if (i==std::string::npos) + return atof (s.c_str()); + else + return atof (s.substr(0,i).c_str()) / atof (s.substr(i+1).c_str()); +} + +double ImageMetaData::apertureFromString (std::string s) { + + return atof (s.c_str()); +} + +extern "C" { + +#include +#include + +struct _IptcDataPrivate +{ + unsigned int ref_count; + + IptcLog *log; + IptcMem *mem; +}; + +IptcData * +iptc_data_new_from_jpeg_file (FILE *infile) +{ + IptcData *d; + unsigned char * buf; + int buf_len = 256*256; + int len, offset; + unsigned int iptc_len; + + if (!infile) + return NULL; + + d = iptc_data_new (); + if (!d) + return NULL; + + buf = (unsigned char*)iptc_mem_alloc (d->priv->mem, buf_len); + if (!buf) { + iptc_data_unref (d); + return NULL; + } + + len = iptc_jpeg_read_ps3 (infile, buf, buf_len); + + if (len <= 0) { + goto failure; + } + + offset = iptc_jpeg_ps3_find_iptc (buf, len, &iptc_len); + if (offset <= 0) { + goto failure; + } + + iptc_data_load (d, buf + offset, iptc_len); + + iptc_mem_free (d->priv->mem, buf); + return d; + +failure: + iptc_mem_free (d->priv->mem, buf); + iptc_data_unref (d); + return NULL; +} + +} diff --git a/rtengine/imagedata.h b/rtengine/imagedata.h new file mode 100755 index 000000000..553b43ebd --- /dev/null +++ b/rtengine/imagedata.h @@ -0,0 +1,70 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef __IMAGEDATA_H__ +#define __IMAGEDATA_H__ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace rtengine { + +class ImageData : public ImageMetaData { + + protected: + rtexif::TagDirectory* root; + IptcData* iptc; + + struct tm time; + int iso_speed; + double aperture; + double focal_len; + double shutter; + std::string make, model; + std::string lens; + + void extractInfo (); + + public: + + ImageData (Glib::ustring fname, RawMetaDataLocation* rml=NULL); + ~ImageData (); + + const rtexif::TagDirectory* getExifData () const { return root; } + const std::vector getIPTCData () const; + + bool hasExif () const { return root && root->getCount(); } + bool hasIPTC () const { return iptc; } + + struct tm getDateTime () const { return time; } + int getISOSpeed () const { return iso_speed; } + double getFNumber () const { return aperture; } + double getFocalLen () const { return focal_len; } + double getShutterSpeed () const { return shutter; } + std::string getMake () const { return make; } + std::string getModel () const { return model; } + std::string getLens () const { return lens; } +}; +}; +#endif diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc new file mode 100755 index 000000000..30d1365f3 --- /dev/null +++ b/rtengine/imageio.cc @@ -0,0 +1,759 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include +#include +#include +#include +extern "C" { +#include "jdatasrc.c" +#include +#include +} +#ifdef WIN32 +#include +#else +#include +#endif +#include +#include + +using namespace rtengine; +using namespace rtengine::procparams; + +Glib::Mutex& IImage::getMutex () {} +cmsHPROFILE IImage::getProfile () {} +int IImage::getWidth () {} +int IImage::getHeight () {} +int IImage::getBitsPerPixel () {} +int IImage::saveToFile (Glib::ustring fname) {} +int IImage::saveAsPNG (Glib::ustring fname, int compression, int bps) { } +int IImage::saveAsJPEG (Glib::ustring fname, int quality) {} +int IImage::saveAsTIFF (Glib::ustring fname, int bps) {} +void IImage::setSaveProgressListener (ProgressListener* pl) {} +void IImage::free () {} + +Glib::ustring ImageIO::errorMsg[6] = {"Success", "Cannot read file.", "Invalid header.","Error while reading header.","File reading error", "Image format not supported."}; + +void ImageIO::setMetadata (const rtexif::TagDirectory* eroot, const std::vector& exif, const std::vector& iptcc) { + + // store exif info + exifChange.resize (exif.size()); + for (int i=0; iclone (NULL); + + if (iptc) + iptc_data_free (iptc); + iptc = NULL; + + // build iptc structures for libiptcdata + if (iptcc.size()==0) + return; + + iptc = iptc_data_new (); + for (int i=0; i0) { + for (int j=0; j0) { + for (int j=0; j0) { + IptcDataSet * ds = iptc_dataset_new (); + iptc_dataset_set_tag (ds, IPTC_RECORD_APP_2, strTags[j].tag); + std::string loc = Glib::locale_from_utf8(iptcc[i].values[0]); + iptc_dataset_set_data (ds, (unsigned char*)loc.c_str(), MIN(strTags[j].size,loc.size()), IPTC_DONT_VALIDATE); + iptc_data_add_dataset (iptc, ds); + iptc_dataset_unref (ds); + } + } + iptc_data_sort (iptc); +} + +void ImageIO::setOutputProfile (char* pdata, int plen) { + + delete [] profileData; + if (pdata) { + profileData = new char [plen]; + memcpy (profileData, pdata, plen); + } + else + profileData = NULL; + profileLength = plen; +} + +ImageIO::~ImageIO () { + + if (embProfile) + cmsCloseProfile(embProfile); + delete loadedProfileData; + delete exifRoot; + delete profileData; +} + +void png_read_data(png_struct_def *png_ptr, unsigned char *data, size_t length); +void png_write_data(png_struct_def *png_ptr, unsigned char *data, size_t length); +void png_flush(png_struct_def *png_ptr); + +int ImageIO::loadPNG (Glib::ustring fname) { + + FILE *file = g_fopen (fname.c_str(),"rb"); + if (!file) + return IMIO_CANNOTREADFILE; + + if (pl) { + pl->setProgressStr ("Loading PNG file..."); + pl->setProgress (0.0); + } + + //reading PNG header + unsigned char header[8]; + fread (header, 1, 8, file); + if (!png_check_sig (header, 8)) { + fclose(file); + return IMIO_HEADERERROR; + } + //initializing main structures + png_structp png = png_create_read_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0); + if (!png) { + fclose (file); + return IMIO_HEADERERROR; + } + png_infop info = png_create_info_struct (png); + png_infop end_info = png_create_info_struct (png); + if (!end_info || !info) { + png_destroy_read_struct (&png, &info, &end_info); + fclose (file); + return IMIO_HEADERERROR; + } + + if (setjmp (png_jmpbuf(png))) { + png_destroy_read_struct (&png, &info, &end_info); + fclose (file); + return IMIO_READERROR; + } + + //set up png read + png_set_read_fn (png, file, png_read_data); + png_set_sig_bytes (png,8); + + png_read_info(png,info); + + embProfile = NULL; + + //retrieving image information + unsigned long width,height; + int bit_depth,color_type,interlace_type,compression_type,filter_method; + png_get_IHDR(png,info,&width,&height,&bit_depth,&color_type,&interlace_type, + &compression_type, &filter_method); + + //converting to 32bpp format + if (color_type==PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png); + + if (color_type==PNG_COLOR_TYPE_GRAY || color_type==PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(png); + + if (png_get_valid(png,info,PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png); + + if (interlace_type!=PNG_INTERLACE_NONE) { + png_destroy_read_struct (&png, &info, &end_info); + fclose (file); + return IMIO_VARIANTNOTSUPPORTED; + } + + if (color_type & PNG_COLOR_MASK_ALPHA) + png_set_strip_alpha(png); + + //setting gamma + double gamma; + if (png_get_gAMA(png,info,&gamma)) + png_set_gamma(png, 2.0, gamma); + else + png_set_gamma(png,2.0, 0.45455); + + int bps = getBPS (); + + +// if (bps==8 && bit_depth==16) png_set_strip_16(png); + + //updating png info struct + png_read_update_info(png,info); + png_get_IHDR(png,info,&width,&height,&bit_depth,&color_type,&interlace_type, + &compression_type, &filter_method); + + if (color_type & PNG_COLOR_MASK_ALPHA) + png_set_strip_alpha(png); + + png_read_update_info(png,info); + png_get_IHDR(png,info,&width,&height,&bit_depth,&color_type,&interlace_type, + &compression_type, &filter_method); + + allocate (width, height); + + int rowlen = width*3*bit_depth/8; + unsigned char *row = new unsigned char [rowlen]; + + for (unsigned int i=0;isetProgress ((double)(i+1)/height); + } + + png_read_end (png, 0); + png_destroy_read_struct (&png, &info, &end_info); + + delete [] row; + fclose(file); + if (pl) { + pl->setProgressStr ("Ready."); + pl->setProgress (1.0); + } + return IMIO_SUCCESS; +} + +extern jmp_buf jpeg_jmp_buf; + +int ImageIO::loadJPEG (Glib::ustring fname) { + + FILE *file=g_fopen(fname.c_str(),"rb"); + if (!file) + return IMIO_CANNOTREADFILE; + + jpeg_decompress_struct cinfo; + jpeg_error_mgr jerr; + cinfo.err = my_jpeg_std_error(&jerr); + jpeg_create_decompress(&cinfo); + my_jpeg_stdio_src (&cinfo,file); + + if (pl) { + pl->setProgressStr ("Loading JPEG file..."); + pl->setProgress (0.0); + + } + + setup_read_icc_profile (&cinfo); + + if (!setjmp(jpeg_jmp_buf)) { + jpeg_stdio_src(&cinfo,file); + jpeg_read_header(&cinfo, TRUE); + + unsigned int proflen; + delete loadedProfileData; + loadedProfileData = NULL; + bool hasprofile = read_icc_profile (&cinfo, (JOCTET**)&loadedProfileData, (unsigned int*)&loadedProfileLength); + if (hasprofile) + embProfile = cmsOpenProfileFromMem (loadedProfileData, loadedProfileLength); + else + embProfile = NULL; + + jpeg_start_decompress(&cinfo); + + int width = cinfo.output_width; + int height = cinfo.output_height; + + allocate (width, height); + + unsigned char *row=new unsigned char[width*3]; + while (cinfo.output_scanline < height) { + if (jpeg_read_scanlines(&cinfo,&row,1) < 1) { + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + delete [] row; + return IMIO_READERROR; + } + setScanline (cinfo.output_scanline-1, row, 8); + + if (pl && !(cinfo.output_scanline%100)) + pl->setProgress ((double)(cinfo.output_scanline)/cinfo.output_height); + } + delete [] row; + + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + fclose(file); + if (pl) { + pl->setProgressStr ("Ready."); + pl->setProgress (1.0); + } + return IMIO_SUCCESS; + } + else { + jpeg_destroy_decompress(&cinfo); + return IMIO_READERROR; + } +} + +int ImageIO::loadTIFF (Glib::ustring fname) { + +#ifdef WIN32 + wchar_t *wfilename = (wchar_t*)g_utf8_to_utf16 (fname.c_str(), -1, NULL, NULL, NULL); + TIFF* in = TIFFOpenW (wfilename, "r"); + g_free (wfilename); +#else + TIFF* in = TIFFOpen(fname.c_str(), "r"); +#endif + if (in == NULL) + return IMIO_CANNOTREADFILE; + + if (pl) { + pl->setProgressStr ("Loading TIFF file..."); + pl->setProgress (0.0); + } + + int width, height; + TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &width); + TIFFGetField(in, TIFFTAG_IMAGELENGTH, &height); + + uint16 bitspersample, samplesperpixel; + TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &bitspersample); + TIFFGetField(in, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel); + uint16 photometric; + if (!TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &photometric) || + photometric != PHOTOMETRIC_RGB || samplesperpixel < 3) { + TIFFClose(in); + return IMIO_VARIANTNOTSUPPORTED; + } + + uint16 config; + TIFFGetField(in, TIFFTAG_PLANARCONFIG, &config); + if (config != PLANARCONFIG_CONTIG) { + TIFFClose(in); + return IMIO_VARIANTNOTSUPPORTED; + } + + char* profdata; + delete loadedProfileData; + loadedProfileData = NULL; + if (TIFFGetField(in, TIFFTAG_ICCPROFILE, &loadedProfileLength, &profdata)) { + embProfile = cmsOpenProfileFromMem (profdata, loadedProfileLength); + loadedProfileData = new char [loadedProfileLength]; + memcpy (loadedProfileData, profdata, loadedProfileLength); + } + else + embProfile = NULL; + + + allocate (width, height); + + unsigned char* linebuffer = new unsigned char[TIFFScanlineSize(in)]; + for (int row = 0; row < height; row++) { + if (TIFFReadScanline(in, linebuffer, row, 0) <0) { + TIFFClose(in); + delete [] linebuffer; + return IMIO_READERROR; + } + if (samplesperpixel>3) + for (int i=0; isetProgress ((double)(row+1)/height); + } + TIFFClose(in); + delete [] linebuffer; + + if (pl) { + pl->setProgressStr ("Ready."); + pl->setProgress (1.0); + } + + return IMIO_SUCCESS; +} + + +int ImageIO::savePNG (Glib::ustring fname, int compression, int bps) { + + FILE* file=g_fopen(fname.c_str (),"wb"); + + if (!file) + return IMIO_CANNOTREADFILE; + + if (pl) { + pl->setProgressStr ("Saving PNG file..."); + pl->setProgress (0.0); + } + + png_structp png = png_create_write_struct (PNG_LIBPNG_VER_STRING,0,0,0); + if (!png) { + fclose (file); + return IMIO_HEADERERROR; + } + png_infop info = png_create_info_struct(png); + if (!info) { + png_destroy_write_struct (&png,0); + fclose (file); + return IMIO_HEADERERROR; + } + + if (setjmp(png_jmpbuf(png))) { + png_destroy_write_struct (&png,&info); + fclose(file); + return IMIO_READERROR; + } + + png_set_write_fn (png, file, png_write_data, png_flush); + + png_set_compression_level(png,compression); + + int width = getW (); + int height = getH (); + if (bps<0) + bps = getBPS (); + + png_set_IHDR(png, info, width, height, bps, PNG_COLOR_TYPE_RGB, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_BASE); + + + int rowlen = width*3*bps/8; + unsigned char *row = new unsigned char [rowlen]; + + png_write_info(png,info); + for (unsigned int i=0;isetProgress ((double)(i+1)/height); + } + + png_write_end(png,info); + png_destroy_write_struct(&png,&info); + + delete [] row; + fclose (file); + + if (pl) { + pl->setProgressStr ("Ready."); + pl->setProgress (1.0); + } + + return IMIO_SUCCESS; +} + + +int ImageIO::saveJPEG (Glib::ustring fname, int quality) { + + jpeg_compress_struct cinfo; + jpeg_error_mgr jerr; + + cinfo.err = jpeg_std_error (&jerr); + jpeg_create_compress (&cinfo); + + FILE *file = g_fopen (fname.c_str (), "wb"); + + if (!file) + return IMIO_CANNOTREADFILE; + + if (pl) { + pl->setProgressStr ("Saving JPEG file..."); + pl->setProgress (0.0); + } + + jpeg_stdio_dest (&cinfo, file); + + int width = getW (); + int height = getH (); + + cinfo.image_width = width; + cinfo.image_height = height; + cinfo.in_color_space = JCS_RGB; + cinfo.input_components = 3; + jpeg_set_defaults (&cinfo); + cinfo.write_JFIF_header = FALSE; + + + if (quality>=0 && quality<=100) + jpeg_set_quality (&cinfo, quality, true); + + jpeg_start_compress(&cinfo, TRUE); + + // buffer for exif and iptc markers + unsigned char buffer[165535]; + unsigned int size; + // assemble and write exif marker + if (exifRoot) { + int size = rtexif::ExifManager::createJPEGMarker (exifRoot, exifChange, cinfo.image_width, cinfo.image_height, buffer); + if (size>0 && size<65530) + jpeg_write_marker(&cinfo, JPEG_APP0+1, buffer, size); + } + // assemble and write iptc marker + if (iptc) { + unsigned char* iptcdata; + bool error = false; + if (iptc_data_save (iptc, &iptcdata, &size)) { + if (iptcdata) + iptc_data_free_buf (iptc, iptcdata); + error = true; + } + int bytes = 0; + if (!error && (bytes = iptc_jpeg_ps3_save_iptc (NULL, 0, iptcdata, size, buffer, 65532)) < 0) { + if (iptcdata) + iptc_data_free_buf (iptc, iptcdata); + error = true; + } + if (!error) + jpeg_write_marker(&cinfo, JPEG_APP0+13, buffer, bytes); + } + // write icc profile to the output + if (profileData) + write_icc_profile (&cinfo, (JOCTET*)profileData, profileLength); + + // write image data + int rowlen = width*3; + unsigned char *row = new unsigned char [rowlen]; + + while (cinfo.next_scanline < cinfo.image_height) { + + getScanline (cinfo.next_scanline, row, 8); + + if (jpeg_write_scanlines (&cinfo, &row, 1) < 1) { + jpeg_finish_compress (&cinfo); + jpeg_destroy_compress (&cinfo); + fclose (file); + return IMIO_READERROR; + } + + if (pl && !(cinfo.next_scanline%100)) + pl->setProgress ((double)(cinfo.next_scanline)/cinfo.image_height); + } + + jpeg_finish_compress (&cinfo); + jpeg_destroy_compress (&cinfo); + + delete [] row; + fclose (file); + + if (pl) { + pl->setProgressStr ("Ready."); + pl->setProgress (1.0); + } + + return IMIO_SUCCESS; +} + +int ImageIO::saveTIFF (Glib::ustring fname, int bps) { + + int width = getW (); + int height = getH (); + + if (bps<0) + bps = getBPS (); + + int lineWidth = width*3*bps/8; + unsigned char* linebuffer = new unsigned char[lineWidth]; + + if (exifRoot) { + FILE *file = g_fopen (fname.c_str (), "wb"); + + if (!file) + return IMIO_CANNOTREADFILE; + + if (pl) { + pl->setProgressStr ("Saving TIFF file..."); + pl->setProgress (0.0); + } + + // buffer for the exif and iptc + unsigned char buffer[165535]; + unsigned char* iptcdata = NULL; + unsigned int iptclen = 0; + if (iptc && iptc_data_save (iptc, &iptcdata, &iptclen) && iptcdata) { + iptc_data_free_buf (iptc, iptcdata); + iptcdata = NULL; + } + int size = rtexif::ExifManager::createTIFFHeader (exifRoot, exifChange, width, height, bps, profileData, profileLength, (char*)iptcdata, iptclen, buffer); + if (iptcdata) + iptc_data_free_buf (iptc, iptcdata); + if (size>0 && size<165530) + fwrite (buffer, size, 1, file); + + bool needsReverse = bps==16 && exifRoot->getOrder()==rtexif::MOTOROLA; + + for (int i=0; isetProgress ((double)(i+1)/height); + } + + fclose (file); + } + else { + #ifdef WIN32 + wchar_t *wfilename = (wchar_t*)g_utf8_to_utf16 (fname.c_str(), -1, NULL, NULL, NULL); + TIFF* out = TIFFOpenW (wfilename, "w"); + g_free (wfilename); + #else + TIFF* out = TIFFOpen(fname.c_str(), "w"); + #endif + if (!out) + return IMIO_CANNOTREADFILE; + + if (pl) { + pl->setProgressStr ("Saving TIFF file..."); + pl->setProgress (0.0); + } + + TIFFSetField (out, TIFFTAG_IMAGEWIDTH, width); + TIFFSetField (out, TIFFTAG_IMAGELENGTH, height); + TIFFSetField (out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); + TIFFSetField (out, TIFFTAG_SAMPLESPERPIXEL, 3); + TIFFSetField (out, TIFFTAG_BITSPERSAMPLE, bps); + TIFFSetField (out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField (out, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); + TIFFSetField (out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); + TIFFSetField (out, TIFFTAG_COMPRESSION, COMPRESSION_NONE); + + if (profileData) + TIFFSetField (out, TIFFTAG_ICCPROFILE, profileLength, profileData); + + for (int row = 0; row < height; row++) { + getScanline (row, linebuffer, bps); + + if (TIFFWriteScanline (out, linebuffer, row, 0) < 0) { + TIFFClose (out); + delete [] linebuffer; + return IMIO_READERROR; + } + if (pl && !(row%100)) + pl->setProgress ((double)(row+1)/height); + } + TIFFClose (out); + } + + delete [] linebuffer; + if (pl) { + pl->setProgressStr ("Ready."); + pl->setProgress (1.0); + } + + return IMIO_SUCCESS; +} + +// PNG read and write routines: + +void png_read_data(png_structp png_ptr, png_bytep data, png_size_t length) { + png_size_t check; + + /* fread() returns 0 on error, so it is OK to store this in a png_size_t + * instead of an int, which is what fread() actually returns. + */ + check = (png_size_t)fread(data, (png_size_t)1, length, (FILE *)png_ptr->io_ptr); + + if (check != length) + { + png_error(png_ptr, "Read Error"); + } +} + +void png_write_data(png_structp png_ptr, png_bytep data, png_size_t length) { + png_uint_32 check; + + check = fwrite(data, 1, length, (FILE *)(png_ptr->io_ptr)); + if (check != length) + { + png_error(png_ptr, "Write Error"); + } +} + +void png_flush(png_structp png_ptr) { + FILE *io_ptr; + io_ptr = (FILE *)CVT_PTR((png_ptr->io_ptr)); + if (io_ptr != NULL) + fflush(io_ptr); +} + +int ImageIO::load (Glib::ustring fname) { + + int lastdot = fname.find_last_of ('.'); + + if (!fname.casefold().compare (lastdot, 4, ".png")) + return loadPNG (fname); + else if (!fname.casefold().compare (lastdot, 4, ".jpg")) + return loadJPEG (fname); + else if (!fname.casefold().compare (lastdot, 4, ".tif")) + return loadTIFF (fname); +} + +int ImageIO::save (Glib::ustring fname) { + + int lastdot = fname.find_last_of ('.'); + + if (!fname.casefold().compare (lastdot, 4, ".png")) + return savePNG (fname); + else if (!fname.casefold().compare (lastdot, 4, ".jpg")) + return saveJPEG (fname); + else if (!fname.casefold().compare (lastdot, 4, ".tif")) + return saveTIFF (fname); +} + diff --git a/rtengine/imageio.h b/rtengine/imageio.h new file mode 100755 index 000000000..8880fcf64 --- /dev/null +++ b/rtengine/imageio.h @@ -0,0 +1,87 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _IMAGEIO_ +#define _IMAGEIO_ + +#define IMIO_SUCCESS 0 +#define IMIO_CANNOTREADFILE 1 +#define IMIO_INVALIDHEADER 2 +#define IMIO_HEADERERROR 3 +#define IMIO_READERROR 4 +#define IMIO_VARIANTNOTSUPPORTED 5 + +#include +#include +#include +#include +#include + +namespace rtengine { + +class ImageIO { + + protected: + ProgressListener* pl; + cmsHPROFILE embProfile; + char* profileData; + int profileLength; + char* loadedProfileData; + int loadedProfileLength; + std::vector > exifChange; + IptcData* iptc; + const rtexif::TagDirectory* exifRoot; + Glib::Mutex imutex; + + public: + static Glib::ustring errorMsg[6]; + + ImageIO () : pl (NULL), embProfile(NULL), profileData(NULL), exifRoot (NULL), iptc(NULL), loadedProfileData(NULL), loadedProfileLength(0) {} + + virtual ~ImageIO (); + + void setProgressListener (ProgressListener* l) { pl = l; } + + virtual int getW () {} + virtual int getH () {} + virtual void allocate (int width, int height) {} + virtual int getBPS () {} + virtual void getScanline (int row, unsigned char* buffer, int bps) {} + virtual void setScanline (int row, unsigned char* buffer, int bps) {} + + int load (Glib::ustring fname); + int save (Glib::ustring fname); + + int loadPNG (Glib::ustring fname); + int loadJPEG (Glib::ustring fname); + int loadTIFF (Glib::ustring fname); + + int savePNG (Glib::ustring fname, int compression = -1, int bps = -1); + int saveJPEG (Glib::ustring fname, int quality = 100); + int saveTIFF (Glib::ustring fname, int bps = -1); + + cmsHPROFILE getEmbeddedProfile () { return embProfile; } + void getEmbeddedProfileData (int& length, unsigned char*& pdata) { length = loadedProfileLength; pdata = (unsigned char*)loadedProfileData; } + + void setMetadata (const rtexif::TagDirectory* eroot, const std::vector& exif, const std::vector& iptcc); + void setOutputProfile (char* pdata, int plen); + Glib::Mutex& mutex () { return imutex; } +}; + +}; +#endif diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h new file mode 100755 index 000000000..98d75f02c --- /dev/null +++ b/rtengine/imagesource.h @@ -0,0 +1,95 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _IMAGESOURCE_ +#define _IMAGESOURCE_ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace rtengine { + +using namespace procparams; + +#define TR_NONE 0 +#define TR_R90 1 +#define TR_R180 2 +#define TR_R270 3 +#define TR_VFLIP 4 +#define TR_HFLIP 8 +#define TR_ROT 3 + +class PreviewProps { + + public: + + int x, y, w, h, skip; + + PreviewProps (int _x, int _y, int _w, int _h, int _skip) + : x(_x), y(_y), w(_w), h(_h), skip(_skip) {} + +}; + +class ImageSource : public InitialImage { + + private: + int references; + + protected: + cmsHPROFILE embProfile; + Glib::ustring fileName; + ImageData* idata; + + public: + ImageSource () : references (1), embProfile(NULL), idata(NULL) {} + + virtual ~ImageSource () {} + virtual int load (Glib::ustring fname) {} + virtual void getImage (ColorTemp ctemp, int tran, Image16* image, PreviewProps pp, HRecParams hlp, ColorManagementParams cmp) {} + virtual ColorTemp getWB () {} + virtual ColorTemp getAutoWB () {} + virtual ColorTemp getSpotWB (std::vector red, std::vector green, std::vector& blue, int tran) {} + + virtual double getDefGain () { return 1.0; } + + virtual double getGamma () { return 0.0; } + + virtual void getFullSize (int& w, int& h, int tr = TR_NONE) {} + virtual void getSize (int tran, PreviewProps pp, int& w, int& h) {} + + virtual ImageData* getImageData () {} + virtual void setProgressListener (ProgressListener* pl) {} + + void increaseRef () { references++; } + void decreaseRef () { references--; if (!references) delete this; } + virtual int getAEHistogram (int* histogram, int& histcompr) {return 0;} + + // functions inherited from the InitialImage interface + virtual Glib::ustring getFileName () { return fileName; } + virtual cmsHPROFILE getEmbeddedProfile () { return embProfile; } + virtual const ImageMetaData* getMetaData () { return idata; } + virtual ImageSource* getImageSource () { return this; } +}; +}; +#endif diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc new file mode 100755 index 000000000..cecddac21 --- /dev/null +++ b/rtengine/improccoordinator.cc @@ -0,0 +1,577 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include +#define CLIPTO(a,b,c) ((a)>b?((a)imgsrc = imgsrc; +} + +ImProcCoordinator::~ImProcCoordinator () { + + destroying = true; + updaterThreadStart.lock (); + if (updaterRunning && thread) + thread->join (); + mProcessing.lock(); + mProcessing.unlock(); + freeAll (); + + std::vector toDel = crops; + for (int i=0; idecreaseRef (); + ipf.release (); + updaterThreadStart.unlock (); +} + +DetailedCrop* ImProcCoordinator::createCrop () { + + return new Crop (this); +} + +void ImProcCoordinator::updatePreviewImage (int todo) { + + mProcessing.lock (); + MyTime t1,t2,t3,t4,t5,t6,t7,t8,t9; + t1.set (); + + int numofphases = 10; + int readyphase = 0; + + if (!params.resize.enabled) + params.resize.scale = 1.0; + else if (params.resize.dataspec==1) + params.resize.scale = (double)params.resize.width / (params.coarse.rotate==90 || params.coarse.rotate==270 ? fh : fw); + else if (params.resize.dataspec==2) + params.resize.scale = (double)params.resize.height / (params.coarse.rotate==90 || params.coarse.rotate==270 ? fw : fh); + + progress ("Applying white balance, color correction & sRBG conversion...",100*readyphase/numofphases); + if (todo & M_INIT) { + minit.lock (); + if (settings->verbose) printf ("Applying white balance, color correction & sRBG conversion...\n"); + currWB = ColorTemp (params.wb.temperature, params.wb.green); + if (params.wb.method=="Camera") + currWB = imgsrc->getWB (); + else if (params.wb.method=="Auto") { + if (!awbComputed) { + autoWB = imgsrc->getAutoWB (); + awbComputed = true; + } + currWB = autoWB; + } + params.wb.temperature = currWB.getTemp (); + params.wb.green = currWB.getGreen (); + + int tr = TR_NONE; + if (params.coarse.rotate==90) tr |= TR_R90; + if (params.coarse.rotate==180) tr |= TR_R180; + if (params.coarse.rotate==270) tr |= TR_R270; + if (params.coarse.hflip) tr |= TR_HFLIP; + if (params.coarse.vflip) tr |= TR_VFLIP; + + imgsrc->getFullSize (fw, fh, tr); + PreviewProps pp (0, 0, fw, fh, scale); + setScale (scale, true); + imgsrc->getImage (currWB, tr, orig_prev, pp, params.hlrecovery, params.icm); + ipf.firstAnalysis (orig_prev, ¶ms, vhist16, imgsrc->getGamma()); + minit.unlock (); + } + + t2.set (); + if (settings->verbose) printf ("INIT: %d\n", t2.etime(t1)); + readyphase++; + + progress ("Rotate / Distortion...",100*readyphase/numofphases); +// printf ("ROTSTAT: %g, %g, %d, %d\n", params.rotate.degree, params.distortion.amount, (int)orig_prev, (int)oprevi); + // check if the transformation has been switched off: + bool needstransform = fabs(params.rotate.degree)>1e-15 || fabs(params.distortion.amount)>1e-15 || fabs(params.cacorrection.red)>1e-15 || fabs(params.cacorrection.blue)>1e-15; + bool needsvignetting = params.vignetting.amount!=0; + if (!needstransform && !needsvignetting && orig_prev!=oprevi) { + delete oprevi; + oprevi = orig_prev; + } + // check if the transformation has been switched on: + else if ((needstransform || needsvignetting) && orig_prev==oprevi) { + oprevi = new Image16 (pW, pH); + } + if ((todo & M_TRANSFORM) && !needstransform && needsvignetting) + ipf.vignetting (orig_prev, oprevi, ¶ms, 0, 0, pW, pH); + else if ((todo & M_TRANSFORM) && needstransform) + if (scale==1) + ipf.transform (orig_prev, oprevi, ¶ms, 0, 0, 0, 0, pW, pH); + else + ipf.simpltransform (orig_prev, oprevi, ¶ms, 0, 0, 0, 0, pW, pH); + + t3.set (); + if (settings->verbose) printf ("TRANSFORM: %d\n", t3.etime(t2)); + readyphase++; + + + progress ("Preparing shadow/highlight map...",100*readyphase/numofphases); + if ((todo & M_BLURMAP) && params.sh.enabled) { + double radius = sqrt (pW*pW+pH*pH) / 2.0; + double shradius = radius / 1800.0 * params.sh.radius; + shmap->update (oprevi, (unsigned short**)buffer, shradius, ipf.lumimul, params.sh.hq); + } + + t4.set (); + if (settings->verbose) printf ("BLURMAP: %d\n", t4.etime(t3)); + readyphase++; + + if (todo & M_AUTOEXP) { + if (params.toneCurve.autoexp) { + int aehist[65536]; int aehistcompr; + imgsrc->getAEHistogram (aehist, aehistcompr); + ipf.getAutoExp (aehist, aehistcompr, imgsrc->getDefGain(), params.toneCurve.clip, params.toneCurve.expcomp, params.toneCurve.black); + if (aeListener) + aeListener->autoExpChanged (params.toneCurve.expcomp, params.toneCurve.black); + } + } + progress ("Exposure curve & CIELAB conversion...",100*readyphase/numofphases); + if (todo & M_RGBCURVE) { + CurveFactory::updateCurve3 (tonecurve, vhist16, params.toneCurve.curve, imgsrc->getDefGain(), params.toneCurve.expcomp, params.toneCurve.black, params.toneCurve.hlcompr, params.toneCurve.shcompr, params.toneCurve.brightness, params.toneCurve.contrast, imgsrc->getGamma(), true); + ipf.rgbProc (oprevi, oprevl, ¶ms, tonecurve, shmap); + + // recompute luminance histogram + memset (lhist16, 0, 65536*sizeof(int)); + for (int i=0; iL[i][j]]++; + } + t5.set (); + if (settings->verbose) printf ("RGB: %d\n", t5.etime(t4)); + readyphase++; + + if (todo & M_LUMACURVE) { + CurveFactory::updateCurve2 (lumacurve, lhist16, params.lumaCurve.curve, 0, params.lumaCurve.brightness, params.lumaCurve.black, params.lumaCurve.hlcompr, params.lumaCurve.shcompr, params.lumaCurve.contrast, 0.0, false); + } + + if (todo & M_LUMINANCE) { + progress ("Applying Luminance Curve...",100*readyphase/numofphases); + ipf.luminanceCurve (oprevl, nprevl, lumacurve, 0, pH); + readyphase++; + if (scale==1) { + progress ("Denoising luminance...",100*readyphase/numofphases); + ipf.lumadenoise (nprevl, ¶ms, scale*params.resize.scale, buffer); + } + readyphase++; + if (scale==1) { + progress ("Sharpening...",100*readyphase/numofphases); + ipf.sharpening (nprevl, ¶ms, scale*params.resize.scale, (unsigned short**)buffer); + } + readyphase++; + } + + t6.set (); + if (settings->verbose) printf ("LUMINANCE: %d\n", t6.etime(t5)); + + if (todo & M_COLOR) { + progress ("Applying Color Boost...",100*readyphase/numofphases); + ipf.colorCurve (oprevl, nprevl, ¶ms); + readyphase++; + if (scale==1) { + progress ("Denoising color...",100*readyphase/numofphases); + ipf.colordenoise (nprevl, ¶ms, scale*params.resize.scale, buffer); + } + readyphase++; + } + + t7.set (); + if (settings->verbose) printf ("COLOR: %d\n", t7.etime(t6)); + + // process crop, if needed + for (int i=0; ihasListener ()) + crops[i]->update (todo, true); + + progress ("Conversion to RGB...",100*readyphase/numofphases); + if (todo!=CROP) { + previmg->getMutex().lock(); + ipf.lab2rgb (nprevl, previmg); + previmg->getMutex().unlock(); + } + if (!resultValid) { + resultValid = true; + if (imageListener) + imageListener->setImage (previmg, scale*params.resize.scale, params.crop); + } + if (imageListener) + imageListener->imageReady (params.crop); + + readyphase++; + + t8.set (); + if (settings->verbose) printf ("RGBCONVERT: %d\n", t8.etime(t7)); + + if (hListener) { + int hx1 = 0, hx2 = pW, hy1 = 0, hy2 = pH; + if (params.crop.enabled) { + hx1 = MIN(pW-1,MAX(0,params.crop.x / scale)); + hy1 = MIN(pH-1,MAX(0,params.crop.y / scale)); + hx2 = MIN(pW,MAX(0,(params.crop.x+params.crop.w) / scale)); + hy2 = MIN(pH,MAX(0,(params.crop.y+params.crop.h) / scale)); + } + updateHistograms (hx1, hy1, hx2, hy2); + hListener->histogramChanged (rhist, ghist, bhist, Lhist); + } + + t9.set (); + if (settings->verbose) printf ("Total processing time: %d\n", t9.etime(t1)); + progress ("Ready",100*readyphase/numofphases); + + mProcessing.unlock (); +} + + +void ImProcCoordinator::freeAll () { + + if (settings->verbose) printf ("freeall starts %d\n", (int)allocated); + + if (allocated) { + if (orig_prev!=oprevi) + delete oprevi; + delete orig_prev; + delete oprevl; + delete nprevl; + if (imageListener) { + imageListener->delImage (previmg); + } + else + delete previmg; + delete shmap; + for (int i=0; iverbose) printf ("setscale before lock\n"); + + if (!internal) + mProcessing.lock (); + + tr = TR_NONE; + if (params.coarse.rotate==90) tr |= TR_R90; + if (params.coarse.rotate==180) tr |= TR_R180; + if (params.coarse.rotate==270) tr |= TR_R270; + if (params.coarse.hflip) tr |= TR_HFLIP; + if (params.coarse.vflip) tr |= TR_VFLIP; + + int nW, nH; + imgsrc->getFullSize (fw, fh, tr); + + PreviewProps pp (0, 0, fw, fh, prevscale); + imgsrc->getSize (tr, pp, nW, nH); + + if (settings->verbose) printf ("setscale starts (%d, %d)\n", nW, nH); + + if (nW!=pW || nH!=pH) { + + freeAll (); + + pW = nW; + pH = nH; + + orig_prev = new Image16 (pW, pH); + oprevi = orig_prev; + oprevl = new LabImage (pW, pH); + nprevl = new LabImage (pW, pH); + previmg = new Image8 (pW, pH); + shmap = new SHMap (pW, pH); + + buffer = new int*[pH]; + for (int i=0; iverbose) printf ("setscale ends\n"); + if (sizeListeners.size()>0) + for (int i=0; isizeChanged (fullw, fullh, fw, fh); + if (settings->verbose) printf ("setscale ends2\n"); + + if (!internal) + mProcessing.unlock (); +} + + +void ImProcCoordinator::updateHistograms (int x1, int y1, int x2, int y2) { + + memset (rhist, 0, 256*sizeof(int)); + memset (ghist, 0, 256*sizeof(int)); + memset (bhist, 0, 256*sizeof(int)); + + for (int i=y1; idata[ofs++]]++; + ghist[previmg->data[ofs++]]++; + bhist[previmg->data[ofs++]]++; + } + } + + memset (Lhist, 0, 256*sizeof(int)); + for (int i=y1; iL[i][j]/256]++; +} + +void ImProcCoordinator::progress (Glib::ustring str, int pr) { + +/* if (plistener) { + plistener->setProgressStr (str); + plistener->setProgress ((double)pr / 100.0); + }*/ +} + +void ImProcCoordinator::getAutoWB (double& temp, double& green) { + + if (imgsrc) { + if (!awbComputed) { + minit.lock (); + autoWB = imgsrc->getAutoWB (); + minit.unlock (); + awbComputed = true; + } + temp = autoWB.getTemp (); + green = autoWB.getGreen (); + } +} + +void ImProcCoordinator::getCamWB (double& temp, double& green) { + + if (imgsrc) { + temp = imgsrc->getWB().getTemp (); + green = imgsrc->getWB().getGreen (); + } +} + +void ImProcCoordinator::getSpotWB (int x, int y, int rect, double& temp, double& tgreen) { + + mProcessing.lock (); + std::vector points, red, green, blue; + for (int i=y-rect; i<=y+rect; i++) + for (int j=x-rect; j<=x+rect; j++) + points.push_back (Coord2D (j, i)); + + ipf.transCoord (¶ms, fw, fh, points, red, green, blue); + int tr = TR_NONE; + if (params.coarse.rotate==90) tr |= TR_R90; + if (params.coarse.rotate==180) tr |= TR_R180; + if (params.coarse.rotate==270) tr |= TR_R270; + if (params.coarse.hflip) tr |= TR_HFLIP; + if (params.coarse.vflip) tr |= TR_VFLIP; + + ColorTemp ret = imgsrc->getSpotWB (red, green, blue, tr); + mProcessing.unlock (); + temp = ret.getTemp (); + tgreen = ret.getGreen (); +} + +void ImProcCoordinator::getAutoCrop (double ratio, int &x, int &y, int &w, int &h) { + + mProcessing.lock (); + w = fullw; + bool clipped = true; + while (clipped && w>16) { + if (ratio>0) + h = w / ratio; + else + h = w * fullh / fullw; + x = (fullw - w) / 2; + y = (fullh - h) / 2; + int orx, ory, orw, orh; + clipped = ipf.transCoord (¶ms, fw, fh, x, y, w, h, orx, ory, orw, orh); + w -= 4; + } + if (ratio>0) + h = w / ratio; + else + h = w * fullh / fullw; + x = (fullw - w) / 2; + y = (fullh - h) / 2; + mProcessing.unlock (); +} + +void ImProcCoordinator::fullUpdatePreviewImage () { + + if (destroying) + return; + + updaterThreadStart.lock (); + if (updaterRunning && thread) { + changeSinceLast = 0; + thread->join (); + } + + if (plistener) + plistener->setProgressState (1); + + updatePreviewImage (ALL); + + if (plistener) + plistener->setProgressState (0); + + updaterThreadStart.unlock (); +} + +void ImProcCoordinator::fullUpdateDetailedCrops () { + + if (destroying) + return; + + updaterThreadStart.lock (); + if (updaterRunning && thread) { + changeSinceLast = 0; + thread->join (); + } + + if (plistener) + plistener->setProgressState (1); + + for (int i=0; iupdate (ALL, true); + + if (plistener) + plistener->setProgressState (0); + + updaterThreadStart.unlock (); +} + + +void ImProcCoordinator::saveInputICCReference (const Glib::ustring& fname) { + + mProcessing.lock (); + + int fW, fH; + imgsrc->getFullSize (fW, fH, 0); + PreviewProps pp (0, 0, fW, fH, 1); + ProcParams ppar = params; + ppar.hlrecovery.enabled = false; + ppar.icm.input = "(none)"; + Image16* im = new Image16 (fW, fH); + imgsrc->getImage (imgsrc->getWB(), 0, im, pp, ppar.hlrecovery, ppar.icm); + im->saveJPEG (fname, 85); + mProcessing.unlock (); +} + +void ImProcCoordinator::stopProcessing () { + + updaterThreadStart.lock (); + if (updaterRunning && thread) { + changeSinceLast = 0; + thread->join (); + } + updaterThreadStart.unlock (); +} + +void ImProcCoordinator::startProcessing () { + + #undef THREAD_PRIORITY_NORMAL + + if (!destroying) { + updaterThreadStart.lock (); + if (!updaterRunning) { + thread = NULL; + updaterRunning = true; + updaterThreadStart.unlock (); + thread = Glib::Thread::create(sigc::mem_fun(*this, &ImProcCoordinator::process), 0, false, true, Glib::THREAD_PRIORITY_NORMAL); + } + else + updaterThreadStart.unlock (); + } +} + +void ImProcCoordinator::process () { + + if (plistener) + plistener->setProgressState (1); + + paramsUpdateMutex.lock (); + while (changeSinceLast) { + params = nextParams; + int ch = changeSinceLast; + changeSinceLast = 0; + paramsUpdateMutex.unlock (); + if (ch&32767) + updatePreviewImage (ch); + paramsUpdateMutex.lock (); + } + paramsUpdateMutex.unlock (); + updaterRunning = false; + + if (plistener) + plistener->setProgressState (0); +} + +ProcParams* ImProcCoordinator::getParamsForUpdate (ProcEvent change) { + + paramsUpdateMutex.lock (); + changeSinceLast |= refreshmap[(int)change]; + return &nextParams; +} + +void ImProcCoordinator::paramsUpdateReady () { + + paramsUpdateMutex.unlock (); + startProcessing (); +} + + +} diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h new file mode 100755 index 000000000..8f2c85dd7 --- /dev/null +++ b/rtengine/improccoordinator.h @@ -0,0 +1,152 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _IMPROCCOORDINATOR_H_ +#define _IMPROCCOORDINATOR_H_ + +#include +#include +#include +#include +#include +#include +#include + +namespace rtengine { + +using namespace procparams; + +class Crop; + +class ImProcCoordinator : public StagedImageProcessor { + + friend class Crop; + + protected: + Image16 *orig_prev; + Image16 *oprevi; + LabImage *oprevl; + LabImage *nprevl; + Image8 *previmg; + ImageSource* imgsrc; + + int** buffer; + + SHMap* shmap; + + ColorTemp currWB; + ColorTemp autoWB; + + bool awbComputed; + + ImProcFunctions ipf; + + int scale; + bool allocated; + + void freeAll (); + + int tonecurve [65536]; + int lumacurve [65536]; + + int vhist16[65536]; + int lhist16[65536]; + + unsigned int rhist[256], ghist[256], bhist[256], Lhist[256]; + + int fw, fh, tr, fullw, fullh; + int pW, pH; + + ProgressListener* plistener; + PreviewImageListener* imageListener; + AutoExpListener* aeListener; + HistogramListener* hListener; + std::vector sizeListeners; + + std::vector crops; + + bool resultValid; + + Glib::Mutex minit; + + void progress (Glib::ustring str, int pr); + void reallocAll (); + void updateHistograms (int x1, int y1, int x2, int y2); + void setScale (int prevscale, bool internal=false); + void updatePreviewImage (int todo); + + Glib::Mutex mProcessing; + ProcParams params; + + // members of the updater: + Glib::Thread* thread; + Glib::Mutex updaterThreadStart; + Glib::Mutex paramsUpdateMutex; + int changeSinceLast; + bool updaterRunning; + ProcParams nextParams; + bool destroying; + + void startProcessing (); + void process (); + + public: + + ImProcCoordinator (); + ~ImProcCoordinator (); + void assign (ImageSource* imgsrc); + + void getParams (procparams::ProcParams* dst) { *dst = params; } + + ProcParams* getParamsForUpdate (ProcEvent change); + void paramsUpdateReady (); + void stopProcessing (); + + + void setPreviewScale (int scale) { setScale (scale); } + int getPreviewScale () { return scale; } + + void fullUpdatePreviewImage (); + void fullUpdateDetailedCrops (); + + int getFullWidth () { return fullw; } + int getFullHeight () { return fullh; } + + int getPreviewWidth () { return pW; } + int getPreviewHeight () { return pH; } + + DetailedCrop* createCrop (); + + void getAutoWB (double& temp, double& green); + void getCamWB (double& temp, double& green); + void getSpotWB (int x, int y, int rectSize, double& temp, double& green); + void getAutoCrop (double ratio, int &x, int &y, int &w, int &h); + + void setProgressListener (ProgressListener* pl) { plistener = pl; } + void setPreviewImageListener (PreviewImageListener* il) {imageListener = il; } + void setSizeListener (SizeListener* il) {sizeListeners.push_back (il); } + void delSizeListener (SizeListener* il) {std::vector::iterator it = std::find (sizeListeners.begin(), sizeListeners.end(), il); if (it!=sizeListeners.end()) sizeListeners.erase (it); } + void setAutoExpListener (AutoExpListener* ael) {aeListener = ael; } + void setHistogramListener(HistogramListener *h) {hListener = h; } + + void saveInputICCReference (const Glib::ustring& fname); + + InitialImage* getInitialImage () { return imgsrc; } +}; +} +#endif diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc new file mode 100755 index 000000000..902763076 --- /dev/null +++ b/rtengine/improcfun.cc @@ -0,0 +1,2085 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace rtengine { + +using namespace procparams; + +#undef MAX +#undef MIN +#undef MAXVAL +#undef CLIP +#undef CLIPS +#undef CLIPC +#undef CLIPTO +#undef CLIPTOC +#undef THREAD_PRIORITY_NORMAL + +#define MAXVAL 0xffff +#define CLIP(a) ((a)>0?((a)-32768?((a)<32767?(a):32767):-32768) +#define CLIPC(a) ((a)>-32000?((a)<32000?(a):32000):-32000) +#define MAX(a,b) ((a)<(b)?(b):(a)) +#define MIN(a,b) ((a)>(b)?(b):(a)) +#define CLIPTO(a,b,c) ((a)>(b)?((a)<(c)?(a):(c)):(b)) +#define CLIPTOC(a,b,c,d) ((a)>=(b)?((a)<=(c)?(a):((c),d=true)):((b),d=true)) + +extern const Settings* settings; + +// +// STRUCTURES FOR THE SHADOW MAP AND LAB SPACE IMAGE +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +LabImage::LabImage (int w, int h) : W(w), H(h), fromImage(false) { + + L = new unsigned short*[H]; + for (int i=0; iwidth; + H = im->height; + L = im->r; + a = (short**) im->g; + b = (short**) im->b; + fromImage = true; +} + +LabImage::~LabImage () { + + if (!fromImage) { + for (int i=0; i0?((a)(c)?(c):(a))) + +#define MAX(a,b) ((a)<(b)?(b):(a)) +#define MIN(a,b) ((a)>(b)?(b):(a)) + +#define MAXL 65535 +#define ABS(a) ((a)<0?-(a):(a)) + + +int* ImProcFunctions::cacheL; +int* ImProcFunctions::cachea; +int* ImProcFunctions::cacheb; +int* ImProcFunctions::xcache; +int* ImProcFunctions::ycache; +int* ImProcFunctions::zcache; +unsigned short ImProcFunctions::gamma2curve[65536]; + +/*const int c00 = (int) (32768.0 * 0.412453 / 0.950456); +const int c01 = (int) (32768.0 * 0.357580 / 0.950456); +const int c02 = (int) (32768.0 * 0.180423 / 0.950456); +const int c10 = (int) (32768.0 * 0.212671); +const int c11 = (int) (32768.0 * 0.715160); +const int c12 = (int) (32768.0 * 0.072169); +const int c20 = (int) (32768.0 * 0.019334 / 1.088754); +const int c21 = (int) (32768.0 * 0.119193 / 1.088754); +const int c22 = (int) (32768.0 * 0.950227 / 1.088754); +*/ + +void ImProcFunctions::initCache () { + + int maxindex = 2*65536; + cacheL = new int[maxindex]; + cachea = new int[maxindex]; + cacheb = new int[maxindex]; + + int threshold = (int)(0.008856*CMAXVAL); + for (int i=0; ithreshold) { + cacheL[i] = (int)round(655.35 * (116.0 * exp(1.0/3.0 * log((double)i / CMAXVAL)) - 16.0)); + cachea[i] = (int)round(32768.0 * 500.0 * exp(1.0/3.0 * log((double)i / CMAXVAL))); + cacheb[i] = (int)round(32768.0 * 200.0 * exp(1.0/3.0 * log((double)i / CMAXVAL))); + } + else { + cacheL[i] = (int)round(9033.0 * (double)i / 1000.0); // assuming CMAXVAL = 65535 + cachea[i] = (int)round(32768.0 * 500.0 * (7.787*i/CMAXVAL+16.0/116.0)); + cacheb[i] = (int)round(32768.0 * 200.0 * (7.787*i/CMAXVAL+16.0/116.0)); + } + + double fY; + ycache = new int[0x10000]; + for (int i=0; i<0x10000; i++) + ycache[i] = (int)round(65536.0 * ((fY=((double)i/655.35+16)/116) > 2.0689655172413793e-1 ? fY*fY*fY : 1.107056459879453852e-3*(double)i/655.35)); + for (int i=0; i<0x10000; i++) + ycache[i] = CLIP(ycache[i]); + xcache = new int[369621]; + for (int i=-141556; i<228064; i++) + xcache[i+141556] = (int)round(65536.0 * (i > 15728 ? ((double)i/76021)*((double)i/76021)*((double)i/76021)*0.96422 : (1.2841854934601665e-1*(double)i/76021-1.7712903358071262e-2)*0.96422)); + for (int i=0; i<369620; i++) + xcache[i] = CLIP(xcache[i]); + zcache = new int[825747]; + for (int i=-369619; i<456127; i++) + zcache[i+369619] = (int)round(65536.0 * (i > 15728 ? ((double)i/76021)*((double)i/76021)*((double)i/76021)*0.82521 : (1.2841854934601665e-1*(double)i/76021-1.7712903358071262e-2)*0.82521)); + for (int i=0; i<825747; i++) + zcache[i] = CLIP(zcache[i]); + + for (int i=0; i<65536; i++) { + int g = (int)(CurveFactory::gamma2(i/65535.0) * 65535.0); + gamma2curve[i] = CLIP(g); + } +} + +void ImProcFunctions::release () { + + if (monitorTransform!=NULL) + cmsDeleteTransform (monitorTransform); + monitorTransform = NULL; +} + +void ImProcFunctions::firstAnalysis_ (Image16* original, Glib::ustring wprofile, int* histogram, int* chroma_radius, int row_from, int row_to) { + + TMatrix wprof = iccStore.workingSpaceMatrix (wprofile); + int toxyz[3][3]; + toxyz[0][0] = round(32768.0 * wprof[0][0] / 0.96422); + toxyz[1][0] = round(32768.0 * wprof[1][0] / 0.96422); + toxyz[2][0] = round(32768.0 * wprof[2][0] / 0.96422); + toxyz[0][1] = round(32768.0 * wprof[0][1]); + toxyz[1][1] = round(32768.0 * wprof[1][1]); + toxyz[2][1] = round(32768.0 * wprof[2][1]); + toxyz[0][2] = round(32768.0 * wprof[0][2] / 0.82521); + toxyz[1][2] = round(32768.0 * wprof[1][2] / 0.82521); + toxyz[2][2] = round(32768.0 * wprof[2][2] / 0.82521); + + lumimul[0] = wprof[0][1]; + lumimul[1] = wprof[1][1]; + lumimul[2] = wprof[2][1]; + + int W = original->width; + int cradius = 1; + for (int i=row_from; ir[i][j]; + int g = original->g[i][j]; + int b = original->b[i][j]; + + int x = (toxyz[0][0] * r + toxyz[1][0] * g + toxyz[2][0] * b) >> 15; + int y = (toxyz[0][1] * r + toxyz[1][1] * g + toxyz[2][1] * b) >> 15; + int z = (toxyz[0][2] * r + toxyz[1][2] * g + toxyz[2][2] * b) >> 15; + + x = CLIPTO(x,0,2*65536-1); + y = CLIPTO(y,0,2*65536-1); + z = CLIPTO(z,0,2*65536-1); + + int oa = cachea[x] - cachea[y]; + int ob = cacheb[y] - cacheb[z]; + + if (oa<0) oa = -oa; + if (ob<0) ob = -ob; + + if (oa > cradius) + cradius = oa; + if (ob > cradius) + cradius = ob; + + if (histogram) { + int hval = CLIP(y); //(306 * original->r[i][j] + 601 * original->g[i][j] + 117 * original->b[i][j]) >> 10; + histogram[hval]++; + } + } + } + *chroma_radius = cradius; +} + +void ImProcFunctions::firstAnalysis (Image16* original, const ProcParams* params, int* histogram, double gamma) { + + int cr1, cr2; + int* hist1 = new int[65536]; memset (hist1, 0, 65536*sizeof(int)); + int* hist2 = new int[65536]; memset (hist2, 0, 65536*sizeof(int)); + + int H = original->height; + + Glib::ustring wprofile = params->icm.working; + if (monitorTransform) + cmsDeleteTransform (monitorTransform); + monitorTransform = NULL; + cmsHPROFILE monitor = iccStore.getProfile ("file:"+settings->monitorProfile); + if (monitor) { + cmsHPROFILE iprof = iccStore.getXYZProfile (); + cmsHPROFILE oprof = iccStore.getProfile (params->icm.output); + if (!oprof) + oprof = iccStore.getsRGBProfile (); + lcmsMutex->lock (); + monitorTransform = cmsCreateTransform (iprof, TYPE_RGB_16, monitor, TYPE_RGB_8, settings->colorimetricIntent, 0); + lcmsMutex->unlock (); + } + + if (settings->dualThreadEnabled) { + Glib::Thread *thread1 = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &ImProcFunctions::firstAnalysis_), original, wprofile, hist1, &cr1, 0, H/2), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + Glib::Thread *thread2 = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &ImProcFunctions::firstAnalysis_), original, wprofile, hist2, &cr2, H/2, H), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread1->join (); + thread2->join (); + } + else { + firstAnalysis_ (original, wprofile, hist1, &cr1, 0, H/2); + firstAnalysis_ (original, wprofile, hist2, &cr2, H/2, H); + } + + if (cr1dualThreadEnabled) { + + Glib::Thread *thread1 = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &ImProcFunctions::rgbProc_), working, lab, params, tonecurve, shmap, 0, working->height/2), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + Glib::Thread *thread2 = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &ImProcFunctions::rgbProc_), working, lab, params, tonecurve, shmap, working->height/2, working->height), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread1->join (); + thread2->join (); + } + else + rgbProc_ (working, lab, params, tonecurve, shmap, 0, working->height); +} + +void ImProcFunctions::rgbProc_ (Image16* working, LabImage* lab, const ProcParams* params, int* tonecurve, SHMap* shmap, int row_from, int row_to) { + + int r, g, b; + + int h_th, s_th; + if (shmap) { + h_th = shmap->max - params->sh.htonalwidth * (shmap->max - shmap->avg) / 100; + s_th = params->sh.stonalwidth * (shmap->avg - shmap->min) / 100; + } + + bool processSH = params->sh.enabled && shmap!=NULL && (params->sh.highlights>0 || params->sh.shadows>0); + bool processLCE = params->sh.enabled && shmap!=NULL && params->sh.localcontrast>0; + double lceamount = params->sh.localcontrast / 200.0; + + TMatrix wprof = iccStore.workingSpaceMatrix (params->icm.working); + int toxyz[3][3] = { + floor(32768.0 * wprof[0][0] / 0.96422), + floor(32768.0 * wprof[0][1]), + floor(32768.0 * wprof[0][2] / 0.82521), + floor(32768.0 * wprof[1][0] / 0.96422), + floor(32768.0 * wprof[1][1]), + floor(32768.0 * wprof[1][2] / 0.82521), + floor(32768.0 * wprof[2][0] / 0.96422), + floor(32768.0 * wprof[2][1]), + floor(32768.0 * wprof[2][2] / 0.82521)}; + + bool mixchannels = params->chmixer.red[0]!=100 || params->chmixer.red[1]!=0 || params->chmixer.red[2]!=0 || params->chmixer.green[0]!=0 || params->chmixer.green[1]!=100 || params->chmixer.green[2]!=0 || params->chmixer.blue[0]!=0 || params->chmixer.blue[1]!=0 || params->chmixer.blue[2]!=100; + + int mapval; + double factor; + int tW = working->width; + for (int i=row_from; ir[i][j]; + g = working->g[i][j]; + b = working->b[i][j]; + + if (mixchannels) { + int newr = (r*params->chmixer.red[0] + g*params->chmixer.red[1] + b*params->chmixer.red[2]) / 100; + int newg = (r*params->chmixer.green[0] + g*params->chmixer.green[1] + b*params->chmixer.green[2]) / 100; + int newb = (r*params->chmixer.blue[0] + g*params->chmixer.blue[1] + b*params->chmixer.blue[2]) / 100; + r = CLIP(newr); + g = CLIP(newg); + b = CLIP(newb); + } + + if (processSH || processLCE) { + mapval = shmap->map[i][j]; + factor = 1.0; + + if (processSH) { + if (mapval > h_th) + factor = (h_th + (100.0 - params->sh.highlights) * (mapval - h_th) / 100.0) / mapval; + else if (mapval < s_th) + factor = (s_th - (100.0 - params->sh.shadows) * (s_th - mapval) / 100.0) / mapval; + } + if (processLCE) { + double sub = lceamount*(mapval-factor*(r*lumimul[0] + g*lumimul[1] + b*lumimul[2])); + r = CLIP((int)(factor*r-sub)); + g = CLIP((int)(factor*g-sub)); + b = CLIP((int)(factor*b-sub)); + } + else { + if (i==100 && j==3500) + printf ("r=%d, %d, fact=%g, mapval=%d, %d\n", r, (int)(factor*r), factor, mapval, shmap->map[i][j]); + r = CLIP((int)(factor*r)); + g = CLIP((int)(factor*g)); + b = CLIP((int)(factor*b)); + } + } + r = tonecurve[r]; + g = tonecurve[g]; + b = tonecurve[b]; + +// int x = (14219 * r + 12328 * g + 6220 * b) >> 15; +// int y = ( 6968 * r + 23434 * g + 2365 * b) >> 15; +// int z = ( 582 * r + 3587 * g + 28598 * b) >> 15; + int x = (toxyz[0][0] * r + toxyz[1][0] * g + toxyz[2][0] * b) >> 15; + int y = (toxyz[0][1] * r + toxyz[1][1] * g + toxyz[2][1] * b) >> 15; + int z = (toxyz[0][2] * r + toxyz[1][2] * g + toxyz[2][2] * b) >> 15; + + x = CLIPTO(x,0,2*65536-1); + y = CLIPTO(y,0,2*65536-1); + z = CLIPTO(z,0,2*65536-1); + + int L = cacheL[y]; + lab->L[i][j] = L; + lab->a[i][j] = CLIPC(((cachea[x] - cachea[y]) * chroma_scale) >> 15); + lab->b[i][j] = CLIPC(((cacheb[y] - cacheb[z]) * chroma_scale) >> 15); + } + } + } + +void ImProcFunctions::luminanceCurve (LabImage* lold, LabImage* lnew, int* curve, int row_from, int row_to) { + + int W = lold->W; + int H = lold->H; + for (int i=row_from; iL[i][j] = curve[lold->L[i][j]]; +} + +#include "cubic.cc" + +void ImProcFunctions::colorCurve (LabImage* lold, LabImage* lnew, const ProcParams* params) { + + double* cmultiplier = new double [181021]; + + double boost_a = (params->colorBoost.amount + 100.0) / 100.0; + double boost_b = (params->colorBoost.amount + 100.0) / 100.0; + + double c, amul = 1.0, bmul = 1.0; + if (boost_a > boost_b) { + c = boost_a; + if (boost_a > 0) + bmul = boost_b / boost_a; + } + else { + c = boost_b; + if (boost_b > 0) + amul = boost_a / boost_b; + } + + if (params->colorBoost.enable_saturationlimiter && c>1) { + // re-generate color multiplier lookup table + double d = params->colorBoost.saturationlimit * chroma_scale / 3.0; + double alpha = 0.5; + double threshold1 = alpha * d; + double threshold2 = c*d*(alpha+1.0) - d; + for (int i=0; i<=181020; i++) { // lookup table stores multipliers with a 0.25 chrominance resolution + double chrominance = (double)i/4; + if (chrominance < threshold1) + cmultiplier[i] = c; + else if (chrominance < d) + cmultiplier[i] = (c / (2.0*d*(alpha-1.0)) * (chrominance-d)*(chrominance-d) + c*d/2.0 * (alpha+1.0) ) / chrominance; + else if (chrominance < threshold2) + cmultiplier[i] = (1.0 / (2.0*d*(c*(alpha+1.0)-2.0)) * (chrominance-d)*(chrominance-d) + c*d/2.0 * (alpha+1.0) ) / chrominance; + else + cmultiplier[i] = 1.0; + } + } + + if (settings->dualThreadEnabled) { + + Glib::Thread *thread1 = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &ImProcFunctions::colorCurve_), lold, lnew, params, 0, lnew->H/2, cmultiplier), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + Glib::Thread *thread2 = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &ImProcFunctions::colorCurve_), lold, lnew, params, lnew->H/2, lnew->H, cmultiplier), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread1->join (); + thread2->join (); + } + else + colorCurve_ (lold, lnew, params, 0, lnew->H, cmultiplier); + + delete [] cmultiplier; +} + +void ImProcFunctions::colorCurve_ (LabImage* lold, LabImage* lnew, const ProcParams* params, int row_from, int row_to, double* cmultiplier) { + + double boost_a = (params->colorBoost.amount + 100.0) / 100.0; + double boost_b = (params->colorBoost.amount + 100.0) / 100.0; + + double c, amul = 1.0, bmul = 1.0; + if (boost_a > boost_b) { + c = boost_a; + if (boost_a > 0) + bmul = boost_b / boost_a; + } + else { + c = boost_b; + if (boost_b > 0) + amul = boost_a / boost_b; + } + + int nna, nnb; + double shift_a = params->colorShift.a * chroma_scale, shift_b = params->colorShift.b * chroma_scale; + + short** oa = lold->a; + short** ob = lold->b; + + for (int i=row_from; iW; j++) { + + double wanted_c = c; + if (params->colorBoost.enable_saturationlimiter && c>1) { + int chroma = (int)(4.0 * sqrt((oa[i][j]+shift_a)*(oa[i][j]+shift_a) + (ob[i][j]+shift_b)*(ob[i][j]+shift_b))); + wanted_c = cmultiplier [MIN(chroma,181020)]; + } + + double real_c = wanted_c; + if (wanted_c >= 1.0 && params->colorBoost.avoidclip) { + double cclip = 100000; + double cr = tightestroot ((double)lnew->L[i][j]/655.35, (double)(oa[i][j]+shift_a)/chroma_scale*amul, (double)(ob[i][j]+shift_b)/chroma_scale*bmul, 3.079935, -1.5371515, -0.54278342); + double cg = tightestroot ((double)lnew->L[i][j]/655.35, (double)(oa[i][j]+shift_a)/chroma_scale*amul, (double)(ob[i][j]+shift_b)/chroma_scale*bmul, -0.92123418, 1.87599, 0.04524418); + double cb = tightestroot ((double)lnew->L[i][j]/655.35, (double)(oa[i][j]+shift_a)/chroma_scale*amul, (double)(ob[i][j]+shift_b)/chroma_scale*bmul, 0.052889682, -0.20404134, 1.15115166); + if (cr>1.0 && cr1.0 && cg1.0 && cba[i][j] = CLIPV(nna,-32000,32000); + lnew->b[i][j] = CLIPV(nnb,-32000,32000); + } +} + +void blur (float** src, float** dst, int W, int H, int r) { + + float** tmpI = new float*[H]; + for (int i=0; i=H-r) + tmpI[i][j] = src[i][j]; + else { + int num = 0; + float sum = 0.0; + for (int x=-r; x<=r; x++) + for (int y=-r; y<=r; y++) + if (x*x+y*y<=r*r) { + sum += src[i+x][j+y]; + num++; + } + tmpI[i][j] = sum / num; + } + } + for (int i=0; isharpening.enabled==false || params->sharpening.deconvamount<1) + return; + + int W = lab->W, H = lab->H; + + float** tmpI = new float*[H]; + for (int i=0; iL[i][j]; + } + + float** tmp = (float**)b2; + + AlignedBuffer* buffer1 = new AlignedBuffer (MAX(W,H)*5); + AlignedBuffer* buffer2 = new AlignedBuffer (MAX(W,H)*5); + + float damping = params->sharpening.deconvdamping / 5.0; + bool needdamp = params->sharpening.deconvdamping > 0; + for (int k=0; ksharpening.deconviter; k++) { + +// gaussHorizontal (tmpI, tmp, buffer1, W, 0, H, params->sharpening.deconvradius / scale); +// gaussVertical (tmp, tmp, buffer1, H, 0, W, params->sharpening.deconvradius / scale); + // apply blur function (gaussian blur) + if (settings->dualThreadEnabled) { + Glib::Thread *thread1 = Glib::Thread::create(sigc::bind(sigc::ptr_fun(gaussHorizontal_float), tmpI, tmp, buffer1, W, 0, H/2, params->sharpening.deconvradius / scale), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + Glib::Thread *thread2 = Glib::Thread::create(sigc::bind(sigc::ptr_fun(gaussHorizontal_float), tmpI, tmp, buffer2, W, H/2, H, params->sharpening.deconvradius / scale), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread1->join (); + thread2->join (); + } + else + gaussHorizontal_float (tmpI, tmp, buffer1, W, 0, H, params->sharpening.deconvradius / scale); + if (settings->dualThreadEnabled) { + Glib::Thread *thread1 = Glib::Thread::create(sigc::bind(sigc::ptr_fun(gaussVertical_float), tmp, tmp, buffer1, H, 0, W/2, params->sharpening.deconvradius / scale), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + Glib::Thread *thread2 = Glib::Thread::create(sigc::bind(sigc::ptr_fun(gaussVertical_float), tmp, tmp, buffer2, H, W/2, W, params->sharpening.deconvradius / scale), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread1->join (); + thread2->join (); + } + else + gaussVertical_float (tmp, tmp, buffer1, H, 0, W, params->sharpening.deconvradius / scale); + +// blur (tmpI, tmp, W, H, params->sharpening.radius / scale); + if (!needdamp) { + for (int i=0; i0) + tmp[i][j] = (float)lab->L[i][j] / tmp[i][j]; + } + else { + if (settings->dualThreadEnabled) { + Glib::Thread *thread1 = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &ImProcFunctions::damping_), tmp, lab->L, damping, W, 0, H/2), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + Glib::Thread *thread2 = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &ImProcFunctions::damping_), tmp, lab->L, damping, W, H/2, H), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread1->join (); + thread2->join (); + } + else + damping_ (tmp, lab->L, damping, W, 0, H); + } +// gaussHorizontal (tmp, tmp, buffer1, W, 0, H, params->sharpening.deconvradius / scale); +// gaussVertical (tmp, tmp, buffer1, H, 0, W, params->sharpening.deconvradius / scale); + // apply blur function (gaussian blur) + if (settings->dualThreadEnabled) { + Glib::Thread *thread1 = Glib::Thread::create(sigc::bind(sigc::ptr_fun(gaussHorizontal_float), tmp, tmp, buffer1, W, 0, H/2, params->sharpening.deconvradius / scale), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + Glib::Thread *thread2 = Glib::Thread::create(sigc::bind(sigc::ptr_fun(gaussHorizontal_float), tmp, tmp, buffer2, W, H/2, H, params->sharpening.deconvradius / scale), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread1->join (); + thread2->join (); + } + else + gaussHorizontal_float (tmp, tmp, buffer1, W, 0, H, params->sharpening.deconvradius / scale); + if (settings->dualThreadEnabled) { + Glib::Thread *thread1 = Glib::Thread::create(sigc::bind(sigc::ptr_fun(gaussVertical_float), tmp, tmp, buffer1, H, 0, W/2, params->sharpening.deconvradius / scale), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + Glib::Thread *thread2 = Glib::Thread::create(sigc::bind(sigc::ptr_fun(gaussVertical_float), tmp, tmp, buffer2, H, W/2, W, params->sharpening.deconvradius / scale), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread1->join (); + thread2->join (); + } + else + gaussVertical_float (tmp, tmp, buffer1, H, 0, W, params->sharpening.deconvradius / scale); + +// blur (tmp, tmp, W, H, params->sharpening.radius / scale); + + for (int i=0; iL[i][j] = lab->L[i][j]*(100-params->sharpening.deconvamount) / 100 + (int)CLIP(tmpI[i][j])*params->sharpening.deconvamount / 100; + + for (int i=0; isharpening.method=="rld") { + deconvsharpening (lab, params, scale, b2); + return; + } + + if (params->sharpening.enabled==false || params->sharpening.amount<1 || lab->W<8 || lab->H<8) + return; + + int W = lab->W, H = lab->H; + unsigned short** b3; + if (params->sharpening.edgesonly==false) { + + AlignedBuffer* buffer1 = new AlignedBuffer (MAX(W,H)*5); + AlignedBuffer* buffer2 = new AlignedBuffer (MAX(W,H)*5); + + MyTime t1, t2, t3; + t1.set (); + if (settings->dualThreadEnabled) { + Glib::Thread *thread1 = Glib::Thread::create(sigc::bind(sigc::ptr_fun(gaussHorizontal_unsigned), lab->L, b2, buffer1, W, 0, H/2, params->sharpening.radius / scale), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + Glib::Thread *thread2 = Glib::Thread::create(sigc::bind(sigc::ptr_fun(gaussHorizontal_unsigned), lab->L, b2, buffer2, W, H/2, H, params->sharpening.radius / scale), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread1->join (); + thread2->join (); + } + else + gaussHorizontal_unsigned (lab->L, b2, buffer1, W, 0, H, params->sharpening.radius / scale); + + t2.set (); +// printf ("Horizontal: %d\n", t2.etime (t1)); + + if (settings->dualThreadEnabled) { + Glib::Thread *thread1 = Glib::Thread::create(sigc::bind(sigc::ptr_fun(gaussVertical_unsigned), b2, b2, buffer1, H, 0, W/2, params->sharpening.radius / scale), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + Glib::Thread *thread2 = Glib::Thread::create(sigc::bind(sigc::ptr_fun(gaussVertical_unsigned), b2, b2, buffer2, H, W/2, W, params->sharpening.radius / scale), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread1->join (); + thread2->join (); + } + else + gaussVertical_unsigned (b2, b2, buffer1, H, 0, W, params->sharpening.radius / scale); + + t3.set (); +// printf ("Vertical: %d\n", t3.etime (t2)); + + delete buffer1; + delete buffer2; + } + else { + b3 = new unsigned short*[H]; + for (int i=0; i* buffer1 = new AlignedBuffer (MAX(W,H)*5); + AlignedBuffer* buffer2 = new AlignedBuffer (MAX(W,H)*5); + + if (settings->dualThreadEnabled) { + Glib::Thread *thread1 = Glib::Thread::create(sigc::bind(sigc::ptr_fun(bilateral_unsigned), lab->L, b3, b2, dim1, params->sharpening.edges_radius / scale, params->sharpening.edges_tolerance), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + Glib::Thread *thread2 = Glib::Thread::create(sigc::bind(sigc::ptr_fun(bilateral_unsigned), lab->L, b3, b2, dim2, params->sharpening.edges_radius / scale, params->sharpening.edges_tolerance), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread1->join (); + thread2->join (); + thread1 = Glib::Thread::create(sigc::bind(sigc::ptr_fun(gaussHorizontal_unsigned), b3, b2, buffer1, W, 0, H/2, params->sharpening.radius / scale), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread2 = Glib::Thread::create(sigc::bind(sigc::ptr_fun(gaussHorizontal_unsigned), b3, b2, buffer2, W, H/2, H, params->sharpening.radius / scale), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread1->join (); + thread2->join (); + thread1 = Glib::Thread::create(sigc::bind(sigc::ptr_fun(gaussVertical_unsigned), b2, b2, buffer1, H, 0, W/2, params->sharpening.radius / scale), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread2 = Glib::Thread::create(sigc::bind(sigc::ptr_fun(gaussVertical_unsigned), b2, b2, buffer2, H, W/2, W, params->sharpening.radius / scale), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread1->join (); + thread2->join (); + } + else { + bilateral_unsigned (lab->L, (unsigned short**)b2, b3, dim1, params->sharpening.edges_radius / scale, params->sharpening.edges_tolerance); + bilateral_unsigned (lab->L, (unsigned short**)b2, b3, dim2, params->sharpening.edges_radius / scale, params->sharpening.edges_tolerance); + gaussHorizontal_unsigned (b2, b2, buffer1, W, 0, H, params->sharpening.radius / scale); + gaussVertical_unsigned (b2, b2, buffer1, H, 0, W, params->sharpening.radius / scale); + } + + delete buffer1; + delete buffer2; + } + unsigned short** base = lab->L; + if (params->sharpening.edgesonly) + base = b3; + + if (params->sharpening.halocontrol==false) { + for (int i=0; iparams->sharpening.threshold) { + int val = lab->L[i][j] + params->sharpening.amount * diff / 100; + lab->L[i][j] = CLIP(val); + } + } + } + else { + if (settings->dualThreadEnabled) { + Glib::Thread *thread1 = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &ImProcFunctions::sharpenHaloCtrl), lab, params, b2, base, W, 2, H/2), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + Glib::Thread *thread2 = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &ImProcFunctions::sharpenHaloCtrl), lab, params, b2, base, W, H/2, H-2), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread1->join (); + thread2->join (); + } + else + sharpenHaloCtrl (lab, params, b2, base, W, 2, H-2); + } + + if (params->sharpening.edgesonly) { + for (int i=0; isharpening.halocontrol_amount); + unsigned short** nL = base; + for (int i=row_from; i params->sharpening.threshold) { + // compute maximum/minimum in a delta environment + np1 = 2*(nL[i-2][j] + nL[i-2][j+1] + nL[i-2][j+2] + nL[i-1][j] + nL[i-1][j+1] + nL[i-1][j+2] + nL[i][j] + nL[i][j+1] + nL[i][j+2]) / 27 + nL[i-1][j+1] / 3; + np2 = 2*(nL[i-1][j] + nL[i-1][j+1] + nL[i-1][j+2] + nL[i][j] + nL[i][j+1] + nL[i][j+2] + nL[i+1][j] + nL[i+1][j+1] + nL[i+1][j+2]) / 27 + nL[i][j+1] / 3; + np3 = 2*(nL[i][j] + nL[i][j+1] + nL[i][j+2] + nL[i+1][j] + nL[i+1][j+1] + nL[i+1][j+2] + nL[i+2][j] + nL[i+2][j+1] + nL[i+2][j+2]) / 27 + nL[i+1][j+1] / 3; + MINMAX3(np1,np2,np3,maxn,minn); + MAX3(max1,max2,maxn,max); + MIN3(min1,min2,minn,min); + max1 = max2; max2 = maxn; + min1 = min2; min2 = minn; + if (max < lab->L[i][j]) + max = lab->L[i][j]; + if (min > lab->L[i][j]) + min = lab->L[i][j]; + int val = lab->L[i][j] + params->sharpening.amount * diff / 100; + int newL = CLIP(val); + // applying halo control + if (newL > max) + newL = max + (newL-max) * scale / 10000; + else if (newLL[i][j] = newL; + } + } + } +} + +void ImProcFunctions::lumadenoise (LabImage* lab, const ProcParams* params, double scale, int** b2) { + +// MyTime t1, t2; +// t1.set (); + + if (params->lumaDenoise.enabled && lab->W>=8 && lab->H>=8) { + + Dim dim1 (lab->W, lab->H, 0, lab->H/2); + Dim dim2 (lab->W, lab->H, lab->H/2, lab->H); + + if (settings->dualThreadEnabled) { + Glib::Thread *thread1 = Glib::Thread::create(sigc::bind(sigc::ptr_fun(bilateral_unsigned), lab->L, lab->L, (unsigned short**)b2, dim1, params->lumaDenoise.radius / scale, params->lumaDenoise.edgetolerance), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + Glib::Thread *thread2 = Glib::Thread::create(sigc::bind(sigc::ptr_fun(bilateral_unsigned), lab->L, lab->L, (unsigned short**)b2, dim2, params->lumaDenoise.radius / scale, params->lumaDenoise.edgetolerance), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread1->join (); + thread2->join (); + } + else { + bilateral_unsigned (lab->L, lab->L, (unsigned short**)b2, dim1, params->lumaDenoise.radius / scale, params->lumaDenoise.edgetolerance); + bilateral_unsigned (lab->L, lab->L, (unsigned short**)b2, dim2, params->lumaDenoise.radius / scale, params->lumaDenoise.edgetolerance); + } + } +// t2.set (); +// printf ("Luminance denoising time = %d\n", t2.etime (t1)); +} + +void ImProcFunctions::colordenoise (LabImage* lab, const ProcParams* params, double scale, int** b2) { + + if (params->colorDenoise.enabled && lab->W>=8 && lab->H>=8) { + +/* if (params->colorDenoise.edgesensitive) { + + short** buffer1 = (short**)b2; + short** buffer2 = new short*[lab->H]; + for (int i=0; iH; i++) + buffer2[i] = buffer1[i]+lab->W; + Dim dim (lab->W, lab->H, 0, lab->H); + if (settings->dualThreadEnabled) { + Glib::Thread *thread1 = Glib::Thread::create(sigc::bind(sigc::ptr_fun(bilateral_signed), lab->a, lab->a, buffer1, dim, params->colorDenoise.radius / scale, params->colorDenoise.edgetolerance), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + Glib::Thread *thread2 = Glib::Thread::create(sigc::bind(sigc::ptr_fun(bilateral_signed), lab->b, lab->b, buffer2, dim, params->colorDenoise.radius / scale, params->colorDenoise.edgetolerance), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread1->join (); + thread2->join (); + } + else { + bilateral_signed (lab->a, lab->a, buffer1, dim, params->colorDenoise.radius / scale, params->colorDenoise.edgetolerance); + bilateral_signed (lab->b, lab->b, buffer1, dim, params->colorDenoise.radius / scale, params->colorDenoise.edgetolerance); + } + delete [] buffer2; + } + else { +*/ + AlignedBuffer* buffer1 = new AlignedBuffer (MAX(lab->W,lab->H)*5); + AlignedBuffer* buffer2 = new AlignedBuffer (MAX(lab->W,lab->H)*5); + + if (settings->dualThreadEnabled) { + Glib::Thread *thread1 = Glib::Thread::create(sigc::bind(sigc::ptr_fun(gaussHorizontal_signed), lab->a, lab->a, buffer1, lab->W, 0, lab->H, params->colorDenoise.amount / 10.0 / scale), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + Glib::Thread *thread2 = Glib::Thread::create(sigc::bind(sigc::ptr_fun(gaussHorizontal_signed), lab->b, lab->b, buffer2, lab->W, 0, lab->H, params->colorDenoise.amount / 10.0 / scale), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread1->join (); + thread2->join (); + thread1 = Glib::Thread::create(sigc::bind(sigc::ptr_fun(gaussVertical_signed), lab->a, lab->a, buffer1, lab->H, 0, lab->W, params->colorDenoise.amount / 10.0 / scale), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread2 = Glib::Thread::create(sigc::bind(sigc::ptr_fun(gaussVertical_signed), lab->b, lab->b, buffer2, lab->H, 0, lab->W, params->colorDenoise.amount / 10.0 / scale), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread1->join (); + thread2->join (); + } + else { + gaussHorizontal_signed (lab->a, lab->a, buffer1, lab->W, 0, lab->H, params->colorDenoise.amount / 10.0 / scale); + gaussHorizontal_signed (lab->b, lab->b, buffer1, lab->W, 0, lab->H, params->colorDenoise.amount / 10.0 / scale); + gaussVertical_signed (lab->a, lab->a, buffer1, lab->H, 0, lab->W, params->colorDenoise.amount / 10.0 / scale); + gaussVertical_signed (lab->b, lab->b, buffer1, lab->H, 0, lab->W, params->colorDenoise.amount / 10.0 / scale); + } + delete buffer1; + delete buffer2; +// } + } +} + +void ImProcFunctions::vignetting_ (Image16* original, Image16* transformed, const ProcParams* params, STemp sizes, int row_from, int row_to) { + + int oW = sizes.oW; + int oH = sizes.oH; + int cx = sizes.cx; + int cy = sizes.cy; + + double w2 = (double) oW / 2.0 - 0.5; + double h2 = (double) oH / 2.0 - 0.5; + + double maxRadius = sqrt( (double)( oW*oW + oH*oH ) ) / 2; + + double v = 1.0 - params->vignetting.amount * 3.0 / 400.0; + double b = 1.0 + params->vignetting.radius * 7.0 / 100.0; + + double mul = (1.0-v) / tanh(b); + + int val; + for (int y=row_from; ywidth; x++) { + double x_d = (double) (x + cx) - w2 ; + double r = sqrt(x_d*x_d + y_d*y_d); + double vign = v + mul * tanh (b*(maxRadius-r) / maxRadius); + val = original->r[y][x] / vign; + transformed->r[y][x] = CLIP(val); + val = original->g[y][x] / vign; + transformed->g[y][x] = CLIP(val); + val = original->b[y][x] / vign; + transformed->b[y][x] = CLIP(val); + } + } +} + +void ImProcFunctions::vignetting (Image16* original, Image16* transformed, const ProcParams* params, int cx, int cy, int oW, int oH) { + + STemp sizes; + sizes.cx = cx; + sizes.cy = cy; + sizes.oW = oW; + sizes.oH = oH; + + if (settings->dualThreadEnabled) { + Glib::Thread *thread1 = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &ImProcFunctions::vignetting_), original, transformed, params, sizes, 0, transformed->height/2), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + Glib::Thread *thread2 = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &ImProcFunctions::vignetting_), original, transformed, params, sizes, transformed->height/2, transformed->height), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread1->join (); + thread2->join (); + } + else + vignetting_ (original, transformed, params, sizes, 0, transformed->height); +} + +#include "cubint.cc" +void ImProcFunctions::transform_ (Image16* original, Image16* transformed, const ProcParams* params, STemp sizes, int row_from, int row_to) { + + int oW = sizes.oW; + int oH = sizes.oH; + int cx = sizes.cx; + int cy = sizes.cy; + int sx = sizes.sx; + int sy = sizes.sy; + + double w2 = (double) oW / 2.0 - 0.5; + double h2 = (double) oH / 2.0 - 0.5; + + double cost = cos(params->rotate.degree * 3.14/180.0); + double sint = sin(params->rotate.degree * 3.14/180.0); + + double max_x = (double) (sx + original->width - 1); + double max_y = (double) (sy + original->height - 1); + double min_x = (double) sx; + double min_y = (double) sy; + + const int n2 = 2; + const int n = 4; + + int mix = original->width - 1; // maximum x-index src + int miy = original->height - 1;// maximum y-index src + int mix2 = mix +1 - n; + int miy2 = miy +1 - n; + + double scale = (oW>oH) ? (double)oW / 2.0 : (double)oH / 2.0 ; + double radius = sqrt( (double)( oW*oW + oH*oH ) ); + radius /= (oWdistortion.amount; + + double d = 1.0 - a; + + // magnify image to keep size + double rotmagn = 1.0; + if (params->rotate.fill) { + double beta = atan((double)MIN(oH,oW)/MAX(oW,oH)); + rotmagn = sin(beta) / sin(fabs(params->rotate.degree) * 3.14/180.0 + beta); + } + // 1. check upper and lower border + double d1 = rotmagn - a*h2/scale; + double d2 = rotmagn - a*w2/scale; + double d3 = rotmagn - a*sqrt(h2*h2+w2*w2) / scale; + d = MIN(d,MIN(d1,MIN(d2,d3))); + + // auxilary variables for vignetting + double maxRadius = sqrt( (double)( oW*oW + oH*oH ) ) / 2 / scale; + + double v = 1.0 - params->vignetting.amount * 3.0 / 400.0; + double b = 1.0 + params->vignetting.radius * 7.0 / 100.0; + + double mul = (1.0-v) / tanh(b); + + // main cycle + double eps = 1e-10; + for (int y=row_from; ywidth; x++) { + double x_d = (double) (x + cx) - w2 ; + + double r = (sqrt(x_d*x_d + y_d*y_d)) / scale; + double s = 10000.0; + if (r= max_x) || (Dy >= max_y) || (Dx < min_x) || (Dy < min_y)); + + // Convert only valid pixels + if (valid) { + // Extract integer and fractions of source screen coordinates + int xc = (int) (Dx); Dx -= (double)xc; + int yc = (int) (Dy); Dy -= (double)yc; + int ys = yc +1 - n2 - sy; // smallest y-index used for interpolation + int xs = xc +1 - n2 - sx; // smallest x-index used for interpolation + + double vignmul = 1.0 / (v + mul * tanh (b*(maxRadius-s*r) / maxRadius)); + + if (ys >= 0 && ys <= miy2 && xs >= 0 && xs <= mix2) // all interpolation pixels inside image + cubint (original, xs, ys, Dx, Dy, &(transformed->r[y][x]), &(transformed->g[y][x]), &(transformed->b[y][x]), vignmul); + else { // edge pixels + int y1 = (yc>0) ? yc : 0; + if (y1>miy) y1 = miy; + int y2 = (yc0) ? xc : 0; + if (x1>mix) x1 = mix; + int x2 = (xcr[y1][x1]*(1.0-Dx)*(1.0-Dy) + original->r[y1][x2]*Dx*(1.0-Dy) + original->r[y2][x1]*(1.0-Dx)*Dy + original->r[y2][x2]*Dx*Dy); + int g = vignmul*(original->g[y1][x1]*(1.0-Dx)*(1.0-Dy) + original->g[y1][x2]*Dx*(1.0-Dy) + original->g[y2][x1]*(1.0-Dx)*Dy + original->g[y2][x2]*Dx*Dy); + int b = vignmul*(original->b[y1][x1]*(1.0-Dx)*(1.0-Dy) + original->b[y1][x2]*Dx*(1.0-Dy) + original->b[y2][x1]*(1.0-Dx)*Dy + original->b[y2][x2]*Dx*Dy); + transformed->r[y][x] = CLIP(r); + transformed->g[y][x] = CLIP(g); + transformed->b[y][x] = CLIP(b); + } + } + else { + // not valid (source pixel x,y not inside source image, etc.) + transformed->r[y][x] = 0; + transformed->g[y][x] = 0; + transformed->b[y][x] = 0; + } + } + } +} + +void ImProcFunctions::simpltransform_ (Image16* original, Image16* transformed, const ProcParams* params, STemp sizes, int row_from, int row_to) { + + int oW = sizes.oW; + int oH = sizes.oH; + int cx = sizes.cx; + int cy = sizes.cy; + int sx = sizes.sx; + int sy = sizes.sy; + + double w2 = (double) oW / 2.0 - 0.5; + double h2 = (double) oH / 2.0 - 0.5; + + double cost = cos(params->rotate.degree * 3.14/180.0); + double sint = sin(params->rotate.degree * 3.14/180.0); + + double max_x = (double) (sx + original->width - 1); + double max_y = (double) (sy + original->height - 1); + double min_x = (double) sx; + double min_y = (double) sy; + + const int n2 = 2; + const int n = 2; + + int mix = original->width - 1; // maximum x-index src + int miy = original->height - 1;// maximum y-index src + int mix2 = mix +1 - n; + int miy2 = miy +1 - n; + + double scale = (oW>oH) ? (double)oW / 2.0 : (double)oH / 2.0 ; + double radius = sqrt( (double)( oW*oW + oH*oH ) ); + radius /= (oWdistortion.amount; + + double d = 1.0 - a; + + // magnify image to keep size + double rotmagn = 1.0; + if (params->rotate.fill) { + double beta = atan((double)MIN(oH,oW)/MAX(oW,oH)); + rotmagn = sin(beta) / sin(fabs(params->rotate.degree) * 3.14/180.0 + beta); + } + // 1. check upper and lower border + double d1r = rotmagn - a*h2/scale - params->cacorrection.red; + double d2r = rotmagn - a*w2/scale - params->cacorrection.red; + double d3r = rotmagn - a*sqrt(h2*h2+w2*w2) / scale - params->cacorrection.red; + double dr = MIN(d,MIN(d1r,MIN(d2r,d3r))); + double d1b = rotmagn - a*h2/scale - params->cacorrection.blue; + double d2b = rotmagn - a*w2/scale - params->cacorrection.blue; + double d3b = rotmagn - a*sqrt(h2*h2+w2*w2) / scale - params->cacorrection.blue; + double db = MIN(d,MIN(d1b,MIN(d2b,d3b))); + double d1g = rotmagn - a*h2/scale; + double d2g = rotmagn - a*w2/scale; + double d3g = rotmagn - a*sqrt(h2*h2+w2*w2) / scale; + double dg = MIN(d,MIN(d1g,MIN(d2g,d3g))); + + d = MIN(dg,MIN(dr,db)); + + // auxilary variables for vignetting + double maxRadius = sqrt( (double)( oW*oW + oH*oH ) ) / 2 / scale; + + double v = 1.0 - params->vignetting.amount * 3.0 / 400.0; + double b = 1.0 + params->vignetting.radius * 7.0 / 100.0; + + double mul = (1.0-v) / tanh(b); + + // main cycle + double eps = 1e-10; + for (int y=row_from; ywidth; x++) { + double x_d = (double) (x + cx) - w2 ; + + double r = (sqrt(x_d*x_d + y_d*y_d)) / scale; + double s = 10000.0; + if (r= max_x) || (Dy >= max_y) || (Dx < min_x) || (Dy < min_y)); + + // Convert only valid pixels + if (valid) { + // Extract integer and fractions of source screen coordinates + int xc = (int) (Dx); Dx -= (double)xc; + int yc = (int) (Dy); Dy -= (double)yc; + int ys = yc +1 - n2 - sy; // smallest y-index used for interpolation + int xs = xc +1 - n2 - sx; // smallest x-index used for interpolation + + double vignmul = 1.0 / (v + mul * tanh (b*(maxRadius-s*r) / maxRadius)); + + if (ys >= 0 && ys <= miy2 && xs >= 0 && xs <= mix2) { // all interpolation pixels inside image + + int r = vignmul*(original->r[yc][xc]*(1.0-Dx)*(1.0-Dy) + original->r[yc][xc+1]*Dx*(1.0-Dy) + original->r[yc+1][xc]*(1.0-Dx)*Dy + original->r[yc+1][xc+1]*Dx*Dy); + int g = vignmul*(original->g[yc][xc]*(1.0-Dx)*(1.0-Dy) + original->g[yc][xc+1]*Dx*(1.0-Dy) + original->g[yc+1][xc]*(1.0-Dx)*Dy + original->g[yc+1][xc+1]*Dx*Dy); + int b = vignmul*(original->b[yc][xc]*(1.0-Dx)*(1.0-Dy) + original->b[yc][xc+1]*Dx*(1.0-Dy) + original->b[yc+1][xc]*(1.0-Dx)*Dy + original->b[yc+1][xc+1]*Dx*Dy); + transformed->r[y][x] = CLIP(r); + transformed->g[y][x] = CLIP(g); + transformed->b[y][x] = CLIP(b); + } + else { // edge pixels + int y1 = (yc>0) ? yc : 0; + if (y1>miy) y1 = miy; + int y2 = (yc0) ? xc : 0; + if (x1>mix) x1 = mix; + int x2 = (xcr[y1][x1]*(1.0-Dx)*(1.0-Dy) + original->r[y1][x2]*Dx*(1.0-Dy) + original->r[y2][x1]*(1.0-Dx)*Dy + original->r[y2][x2]*Dx*Dy); + int g = vignmul*(original->g[y1][x1]*(1.0-Dx)*(1.0-Dy) + original->g[y1][x2]*Dx*(1.0-Dy) + original->g[y2][x1]*(1.0-Dx)*Dy + original->g[y2][x2]*Dx*Dy); + int b = vignmul*(original->b[y1][x1]*(1.0-Dx)*(1.0-Dy) + original->b[y1][x2]*Dx*(1.0-Dy) + original->b[y2][x1]*(1.0-Dx)*Dy + original->b[y2][x2]*Dx*Dy); + transformed->r[y][x] = CLIP(r); + transformed->g[y][x] = CLIP(g); + transformed->b[y][x] = CLIP(b); + } + } + else { + // not valid (source pixel x,y not inside source image, etc.) + transformed->r[y][x] = 0; + transformed->g[y][x] = 0; + transformed->b[y][x] = 0; + } + } + } +} + + +#include "cubintch.cc" +void ImProcFunctions::transform_sep_ (Image16* original, Image16* transformed, const ProcParams* params, STemp sizes, int row_from, int row_to) { + + int oW = sizes.oW; + int oH = sizes.oH; + int cx = sizes.cx; + int cy = sizes.cy; + int sx = sizes.sx; + int sy = sizes.sy; + + double w2 = (double) oW / 2.0 - 0.5; + double h2 = (double) oH / 2.0 - 0.5; + + double cost = cos(params->rotate.degree * 3.14/180.0); + double sint = sin(params->rotate.degree * 3.14/180.0); + + double max_x = (double) (sx + original->width - 1); + double max_y = (double) (sy + original->height - 1); + double min_x = (double) sx; + double min_y = (double) sy; + + const int n2 = 2; + const int n = 4; + + int mix = original->width - 1; // maximum x-index src + int miy = original->height - 1;// maximum y-index src + int mix2 = mix +1 - n; + int miy2 = miy +1 - n; + + double scale = (oW>oH) ? (double)oW / 2.0 : (double)oH / 2.0 ; + double radius = sqrt( (double)( oW*oW + oH*oH ) ); + radius /= (oWdistortion.amount; + double d = 1.0 - a; + + double cdist[3]; + cdist[0] = params->cacorrection.red; + cdist[1] = 0.0; + cdist[2] = params->cacorrection.blue; + + // magnify image to keep size + double rotmagn = 1.0; + if (params->rotate.fill) { + double beta = atan((double)MIN(oH,oW)/MAX(oW,oH)); + rotmagn = sin(beta) / sin(fabs(params->rotate.degree) * 3.14/180.0 + beta); + } + // 1. check upper and lower border + double d1r = rotmagn - a*h2/scale - params->cacorrection.red; + double d2r = rotmagn - a*w2/scale - params->cacorrection.red; + double d3r = rotmagn - a*sqrt(h2*h2+w2*w2) / scale - params->cacorrection.red; + double dr = MIN(d,MIN(d1r,MIN(d2r,d3r))); + double d1b = rotmagn - a*h2/scale - params->cacorrection.blue; + double d2b = rotmagn - a*w2/scale - params->cacorrection.blue; + double d3b = rotmagn - a*sqrt(h2*h2+w2*w2) / scale - params->cacorrection.blue; + double db = MIN(d,MIN(d1b,MIN(d2b,d3b))); + double d1g = rotmagn - a*h2/scale; + double d2g = rotmagn - a*w2/scale; + double d3g = rotmagn - a*sqrt(h2*h2+w2*w2) / scale; + double dg = MIN(d,MIN(d1g,MIN(d2g,d3g))); + + d = MIN(dg,MIN(dr,db)); + + unsigned short** chorig[3]; + chorig[0] = original->r; + chorig[1] = original->g; + chorig[2] = original->b; + + unsigned short** chtrans[3]; + chtrans[0] = transformed->r; + chtrans[1] = transformed->g; + chtrans[2] = transformed->b; + + + // auxilary variables for vignetting + double maxRadius = sqrt( (double)( oW*oW + oH*oH ) ) / 2 / scale; + + double v = 1.0 - params->vignetting.amount * 3.0 / 400.0; + double b = 1.0 + params->vignetting.radius * 7.0 / 100.0; + + double mul = (1.0-v) / tanh(b); + + // main cycle + double eps = 1e-10; + for (int y=row_from; ywidth; x++) { + double x_d = (double) (x + cx) - w2 ; + + double r = (sqrt(x_d*x_d + y_d*y_d)) / scale; + double s = 10000.0; + if (r= max_x) || (Dy >= max_y) || (Dx < min_x) || (Dy < min_y)); + + // Convert only valid pixels + if (valid) { + // Extract integer and fractions of source screen coordinates + int xc = (int) (Dx); Dx -= (double)xc; + int yc = (int) (Dy); Dy -= (double)yc; + int ys = yc +1 - n2 - sy; // smallest y-index used for interpolation + int xs = xc +1 - n2 - sx; // smallest x-index used for interpolation + + if (ys >= 0 && ys <= miy2 && xs >= 0 && xs <= mix2) // all interpolation pixels inside image + cubintch (chorig[c], xs, ys, Dx, Dy, &(chtrans[c][y][x]), vignmul); + else {// edge pixels, linear interpolation + int y1 = (yc>0) ? yc : 0; + if (y1>miy) y1 = miy; + int y2 = (yc0) ? xc : 0; + if (x1>mix) x1 = mix; + int x2 = (xc &src, std::vector &red, std::vector &green, std::vector &blue) { + + bool clipresize = true; + bool clipped = false; + + red.clear (); + green.clear (); + blue.clear (); + bool needstransform = fabs(params->rotate.degree)>1e-15 || fabs(params->distortion.amount)>1e-15 || fabs(params->cacorrection.red)>1e-15 || fabs(params->cacorrection.blue)>1e-15; + if (!needstransform) { + if (clipresize) { + // Apply resizing + if (fabs(params->resize.scale-1.0)>=1e-7) { + for (int i=0; iresize.scale, src[i].y / params->resize.scale)); + green.push_back (Coord2D (src[i].x / params->resize.scale, src[i].y / params->resize.scale)); + blue.push_back (Coord2D (src[i].x / params->resize.scale, src[i].y / params->resize.scale)); + } + for (int i=0; iresize.scale; + double rH = H*params->resize.scale; + double w2 = (double) rW / 2.0 - 0.5; + double h2 = (double) rH / 2.0 - 0.5; + double cost = cos(params->rotate.degree * 3.14/180.0); + double sint = sin(params->rotate.degree * 3.14/180.0); + + double scale = (rW>rH) ? rW / 2.0 : rH / 2.0 ; + double radius = sqrt ((double)(rW*rW + rH*rH )); + radius /= (rWdistortion.amount; + double d = 1.0 - a; + + // magnify image to keep size + double rotmagn = 1.0; + if (params->rotate.fill) { + double beta = atan(MIN(rH,rW)/MAX(rW,rH)); + rotmagn = sin(beta) / sin(fabs(params->rotate.degree) * 3.14/180.0 + beta); + } + if (params->cacorrection.red==0 && params->cacorrection.blue==0) { + // 1. check upper and lower border + double d1 = rotmagn - a*h2/scale; + double d2 = rotmagn - a*w2/scale; + double d3 = rotmagn - a*sqrt(h2*h2+w2*w2) / scale; + d = MIN(d,MIN(d1,MIN(d2,d3))); + + for (int i=0; icacorrection.red; + cdist[1] = 0.0; + cdist[2] = params->cacorrection.blue; + + // 1. check upper and lower border + double d1r = rotmagn - a*h2/scale - params->cacorrection.red; + double d2r = rotmagn - a*w2/scale - params->cacorrection.red; + double d3r = rotmagn - a*sqrt(h2*h2+w2*w2) / scale - params->cacorrection.red; + double dr = MIN(d,MIN(d1r,MIN(d2r,d3r))); + double d1b = rotmagn - a*h2/scale - params->cacorrection.blue; + double d2b = rotmagn - a*w2/scale - params->cacorrection.blue; + double d3b = rotmagn - a*sqrt(h2*h2+w2*w2) / scale - params->cacorrection.blue; + double db = MIN(d,MIN(d1b,MIN(d2b,d3b))); + double d1g = rotmagn - a*h2/scale; + double d2g = rotmagn - a*w2/scale; + double d3g = rotmagn - a*sqrt(h2*h2+w2*w2) / scale; + double dg = MIN(d,MIN(d1g,MIN(d2g,d3g))); + + d = MIN(dg,MIN(dr,db)); + + for (int i=0; iresize.scale-1.0)>=1e-7) { + for (int i=0; iresize.scale; + red[i].y /= params->resize.scale; + green[i].x /= params->resize.scale; + green[i].y /= params->resize.scale; + blue[i].x /= params->resize.scale; + blue[i].y /= params->resize.scale; + } + } + for (int i=0; i corners (8); + corners[0].set (x1, y1); + corners[1].set (x1, y2); + corners[2].set (x2, y2); + corners[3].set (x2, y1); + corners[4].set ((x1+x2)/2, y1); + corners[5].set ((x1+x2)/2, y2); + corners[6].set (x1, (y1+y2)/2); + corners[7].set (x2, (y1+y2)/2); + + std::vector r, g, b; + + bool result = transCoord (params, W, H, corners, r, g, b); + + std::vector transCorners; + transCorners.insert (transCorners.end(), r.begin(), r.end()); + transCorners.insert (transCorners.end(), g.begin(), g.end()); + transCorners.insert (transCorners.end(), b.begin(), b.end()); + + double x1d = transCorners[0].x; + for (int i=1; ix2d) + x2d = transCorners[i].x; + int x2v = (int)ceil(x2d); + + double y2d = transCorners[0].y; + for (int i=1; iy2d) + y2d = transCorners[i].y; + int y2v = (int)ceil(y2d); + + xv = x1v; + yv = y1v; + wv = x2v - x1v + 1; + hv = y2v - y1v + 1; + + return result; +} + +void ImProcFunctions::transform (Image16* original, Image16* transformed, const ProcParams* params, int cx, int cy, int sx, int sy, int oW, int oH) { + + STemp sizes; + sizes.cx = cx; + sizes.cy = cy; + sizes.oW = oW; + sizes.oH = oH; + sizes.sx = sx; + sizes.sy = sy; + + if (params->cacorrection.red==0 && params->cacorrection.blue==0) { + if (settings->dualThreadEnabled) { + Glib::Thread *thread1 = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &ImProcFunctions::transform_), original, transformed, params, sizes, 0, transformed->height/2), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + Glib::Thread *thread2 = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &ImProcFunctions::transform_), original, transformed, params, sizes, transformed->height/2, transformed->height), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread1->join (); + thread2->join (); + } + else + transform_ (original, transformed, params, sizes, 0, transformed->height); + } + else { + if (settings->dualThreadEnabled) { + Glib::Thread *thread1 = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &ImProcFunctions::transform_sep_), original, transformed, params, sizes, 0, transformed->height/2), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + Glib::Thread *thread2 = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &ImProcFunctions::transform_sep_), original, transformed, params, sizes, transformed->height/2, transformed->height), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread1->join (); + thread2->join (); + } + else + transform_sep_ (original, transformed, params, sizes, 0, transformed->height); + } +} + +void ImProcFunctions::simpltransform (Image16* original, Image16* transformed, const ProcParams* params, int cx, int cy, int sx, int sy, int oW, int oH) { + + STemp sizes; + sizes.cx = cx; + sizes.cy = cy; + sizes.oW = oW; + sizes.oH = oH; + sizes.sx = sx; + sizes.sy = sy; + + if (settings->dualThreadEnabled) { + Glib::Thread *thread1 = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &ImProcFunctions::simpltransform_), original, transformed, params, sizes, 0, transformed->height/2), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + Glib::Thread *thread2 = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &ImProcFunctions::simpltransform_), original, transformed, params, sizes, transformed->height/2, transformed->height), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread1->join (); + thread2->join (); + } + else + simpltransform_ (original, transformed, params, sizes, 0, transformed->height); +} +/*void ImProcFunctions::transform (Image16* original, Image16* transformed, const ProcParams* params, int ox, int oy) { + + if (!transformed) + return; + + int oW = W, oH = H, tW = W, tH = H; + + double w2 = (double) tW / 2.0 - 0.5; + double h2 = (double) tH / 2.0 - 0.5; + double sw2 = (double) oW / 2.0 - 0.5; + double sh2 = (double) oH / 2.0 - 0.5; + + double cost = cos(params->rotate_fine * 3.14/180.0); + double sint = sin(params->rotate_fine * 3.14/180.0); + + double max_x = (double) oW; + double max_y = (double) oH; + double min_x = 0.0; + double min_y = 0.0; + + const int n2 = 2; + const int n = 4; + + int mix = oW - 1; // maximum x-index src + int miy = oH - 1;// maximum y-index src + int mix2 = mix +1 - n; + int miy2 = miy +1 - n; + + double scale = (tW>tH) ? (double)tW / 2.0 : (double)tH / 2.0 ; + double radius = sqrt( (double)( tW*tW + tH*tH ) ); + radius /= (tWlens_distortion; + + for (int y=0; yheight; y++) { + double y_d = (double) y + oy - h2 ; + + for (int x=0; xwidth; x++) { + double x_d = (double) x + ox - w2 ; + + double r = (sqrt(x_d*x_d + y_d*y_d)) / scale; + double s = 10000.0; + if (r= max_x) || (Dy >= max_y) || (Dx < min_x) || (Dy < min_y)); + + // Convert only valid pixels + if (valid) { + // Extract integer and fractions of source screen coordinates + int xc = (int) floor (Dx) ; Dx -= (double)xc; + int yc = (int) floor (Dy) ; Dy -= (double)yc; + int ys = yc +1 - n2 ; // smallest y-index used for interpolation + int xs = xc +1 - n2 ; // smallest x-index used for interpolation + + unsigned short sr[2][2], sg[2][2], sb[2][2]; + + if (ys >= 0 && ys <= miy2 && xs >= 0 && xs <= mix2) // all interpolation pixels inside image + cubint (original, xs, ys, Dx, Dy, &(transformed->r[y][x]), &(transformed->g[y][x]), &(transformed->b[y][x])); + else { // edge pixels + transformed->r[y][x] = 0; + transformed->g[y][x] = 0; + transformed->b[y][x] = 0; + } + } + else { + // not valid (source pixel x,y not inside source image, etc.) + transformed->r[y][x] = 0; + transformed->g[y][x] = 0; + transformed->b[y][x] = 0; + } + } + } +}*/ + +void ImProcFunctions::lab2rgb (LabImage* lab, Image8* image) { + + if (settings->dualThreadEnabled) { + + Glib::Thread *thread1 = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &ImProcFunctions::lab2rgb_), lab, image, 0, lab->H/2), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + Glib::Thread *thread2 = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &ImProcFunctions::lab2rgb_), lab, image, lab->H/2, lab->H), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread1->join (); + thread2->join (); + } + else + lab2rgb_ (lab, image, 0, lab->H); +} + +void ImProcFunctions::lab2rgb_ (LabImage* lab, Image8* image, int row_from, int row_to) { + + int X, Y, Z; + unsigned short** nL = lab->L; + short** na = lab->a; + short** nb = lab->b; + int tW = lab->W; + int ix = row_from*tW*3; + + if (monitorTransform) { + short* buffer = new short [3*tW]; + for (int i=row_from; idata + ix, tW); + ix += 3*tW; + } + delete [] buffer; + } + else { + for (int i=row_from; i> 13; + int G = (-8017*X+15697*Y+274*Z) >> 13; + int B = (590*X-1877*Y+11517*Z) >> 13; + + /* copy RGB */ + image->data[ix++] = gamma2curve[CLIP(R)] >> 8; + image->data[ix++] = gamma2curve[CLIP(G)] >> 8; + image->data[ix++] = gamma2curve[CLIP(B)] >> 8; + } + } + } +} + +Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile) { + + int tW = lab->W; + int tH = lab->H; + + if (cx<0) cx = 0; + if (cy<0) cy = 0; + if (cx+cw>tW) cw = tW-cx; + if (cy+ch>tH) ch = tH-cy; + + Image8* image = new Image8 (cw, ch); + + int X, Y, Z; + int ix = 0; + unsigned short** nL = lab->L; + short** na = lab->a; + short** nb = lab->b; + + cmsHPROFILE oprof = iccStore.getProfile (profile); + + if (oprof) { + cmsHPROFILE iprof = iccStore.getXYZProfile (); + lcmsMutex->lock (); + cmsHTRANSFORM hTransform = cmsCreateTransform (iprof, TYPE_RGB_16, oprof, TYPE_RGB_8, settings->colorimetricIntent, 0); + lcmsMutex->unlock (); + short* buffer = new short [3*cw]; + for (int i=cy; idata + ix, cw); + ix += 3*cw; + } + delete [] buffer; + cmsDeleteTransform(hTransform); + } + else { + for (int i=cy; i> 13; + int G = (-8017*X+15697*Y+274*Z) >> 13; + int B = (590*X-1877*Y+11517*Z) >> 13; + + image->data[ix++] = gamma2curve[CLIP(R)] >> 8; + image->data[ix++] = gamma2curve[CLIP(G)] >> 8; + image->data[ix++] = gamma2curve[CLIP(B)] >> 8; + } + } + } + return image; +} + +Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile) { + + int tW = lab->W; + int tH = lab->H; + + if (cx<0) cx = 0; + if (cy<0) cy = 0; + if (cx+cw>tW) cw = tW-cx; + if (cy+ch>tH) ch = tH-cy; + + Image16* image = new Image16 (cw, ch); + + int X, Y, Z; + int ix = 0; + unsigned short** nL = lab->L; + short** na = lab->a; + short** nb = lab->b; + + cmsHPROFILE oprof = iccStore.getProfile (profile); + + if (oprof) { + for (int i=cy; ir[i-cy]; + short* ya = (short*)image->g[i-cy]; + short* za = (short*)image->b[i-cy]; + for (register int j=cx; jlock (); + cmsHTRANSFORM hTransform = cmsCreateTransform (iprof, TYPE_RGB_16_PLANAR, oprof, TYPE_RGB_16_PLANAR, settings->colorimetricIntent, 0); + lcmsMutex->unlock (); + cmsDoTransform (hTransform, image->data, image->data, image->planestride/2); + cmsDeleteTransform(hTransform); + } + else { + for (int i=cy; i> 13; + int G = (-8017*X+15697*Y+274*Z) >> 13; + int B = (590*X-1877*Y+11517*Z) >> 13; + + image->r[i-cy][j-cx] = gamma2curve[CLIP(R)]; + image->g[i-cy][j-cx] = gamma2curve[CLIP(G)]; + image->b[i-cy][j-cx] = gamma2curve[CLIP(B)]; + } + } + } + return image; +} + +void ImProcFunctions::resize (Image16* src, Image16* dst, ResizeParams params) { + + if (settings->dualThreadEnabled) { + + Glib::Thread *thread1 = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &ImProcFunctions::resize_), src, dst, params, 0, dst->height/2), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + Glib::Thread *thread2 = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &ImProcFunctions::resize_), src, dst, params, dst->height/2, dst->height), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread1->join (); + thread2->join (); + } + else + resize_ (src, dst, params, 0, dst->height); +} + +void ImProcFunctions::resize_ (Image16* src, Image16* dst, ResizeParams params, int row_from, int row_to) { + + if (params.method.substr(0,7)=="Bicubic") { + double Av = -0.5; + if (params.method=="Bicubic (Sharper)") + Av = -0.75; + else if (params.method=="Bicubic (Softer)") + Av = -0.25; + double wx[4], wy[4]; + for (int i=row_from; iwidth; j++) { + double Dx = j / params.scale; + int xc = (int) Dx; Dx -= (double)xc; + int xs = xc - 1; // smallest x-index used for interpolation + if (ys >= 0 && ys height-3 && xs >= 0 && xs <= src->width-3) { + // compute horizontal weights + double t1 = -Av*(Dx-1.0)*Dx; + double t2 = (3.0-2.0*Dx)*Dx*Dx; + wx[3] = t1*Dx; + wx[2] = t1*(Dx-1.0) + t2; + wx[1] = -t1*Dx + 1.0 - t2; + wx[0] = -t1*(Dx-1.0); + // compute weighted sum + int r = 0; + int g = 0; + int b = 0; +/* r = wx[0]*wy[0]*src->r[ys+0][xs+0] + wx[0]*wy[1]*src->r[ys+1][xs+0] + wx[0]*wy[2]*src->r[ys+2][xs+0] + wx[0]*wy[3]*src->r[ys+3][xs+0] + + wx[1]*wy[0]*src->r[ys+0][xs+1] + wx[1]*wy[1]*src->r[ys+1][xs+1] + wx[1]*wy[2]*src->r[ys+2][xs+1] + wx[1]*wy[3]*src->r[ys+3][xs+1] + + wx[2]*wy[0]*src->r[ys+0][xs+2] + wx[2]*wy[1]*src->r[ys+1][xs+1] + wx[2]*wy[2]*src->r[ys+2][xs+2] + wx[2]*wy[3]*src->r[ys+3][xs+2] + + wx[3]*wy[0]*src->r[ys+0][xs+3] + wx[3]*wy[1]*src->r[ys+1][xs+1] + wx[3]*wy[2]*src->r[ys+2][xs+3] + wx[3]*wy[3]*src->r[ys+3][xs+3]; + g = wx[0]*wy[0]*src->g[ys+0][xs+0] + wx[0]*wy[1]*src->g[ys+1][xs+0] + wx[0]*wy[2]*src->g[ys+2][xs+0] + wx[0]*wy[3]*src->g[ys+3][xs+0] + + wx[1]*wy[0]*src->g[ys+0][xs+1] + wx[1]*wy[1]*src->g[ys+1][xs+1] + wx[1]*wy[2]*src->g[ys+2][xs+1] + wx[1]*wy[3]*src->g[ys+3][xs+1] + + wx[2]*wy[0]*src->g[ys+0][xs+2] + wx[2]*wy[1]*src->g[ys+1][xs+1] + wx[2]*wy[2]*src->g[ys+2][xs+2] + wx[2]*wy[3]*src->g[ys+3][xs+2] + + wx[3]*wy[0]*src->g[ys+0][xs+3] + wx[3]*wy[1]*src->g[ys+1][xs+1] + wx[3]*wy[2]*src->g[ys+2][xs+3] + wx[3]*wy[3]*src->g[ys+3][xs+3]; + b = wx[0]*wy[0]*src->b[ys+0][xs+0] + wx[0]*wy[1]*src->b[ys+1][xs+0] + wx[0]*wy[2]*src->b[ys+2][xs+0] + wx[0]*wy[3]*src->b[ys+3][xs+0] + + wx[1]*wy[0]*src->b[ys+0][xs+1] + wx[1]*wy[1]*src->b[ys+1][xs+1] + wx[1]*wy[2]*src->b[ys+2][xs+1] + wx[1]*wy[3]*src->b[ys+3][xs+1] + + wx[2]*wy[0]*src->b[ys+0][xs+2] + wx[2]*wy[1]*src->b[ys+1][xs+1] + wx[2]*wy[2]*src->b[ys+2][xs+2] + wx[2]*wy[3]*src->b[ys+3][xs+2] + + wx[3]*wy[0]*src->b[ys+0][xs+3] + wx[3]*wy[1]*src->b[ys+1][xs+1] + wx[3]*wy[2]*src->b[ys+2][xs+3] + wx[3]*wy[3]*src->b[ys+3][xs+3];*/ + for (int x=0; x<4; x++) + for (int y=0; y<4; y++) { + double w = wx[x]*wy[y]; + r += w*src->r[ys+y][xs+x]; + g += w*src->g[ys+y][xs+x]; + b += w*src->b[ys+y][xs+x]; + } + dst->r[i][j] = CLIP(r); + dst->g[i][j] = CLIP(g); + dst->b[i][j] = CLIP(b); + } + else { + xc = CLIPTO(xc, 0, src->width-1); + yc = CLIPTO(yc, 0, src->height-1); + int nx = xc + 1; + if (nx>=src->width) + nx = xc; + int ny = yc + 1; + if (ny>=src->height) + ny = yc; + dst->r[i][j] = (1-Dx)*(1-Dy)*src->r[yc][xc] + (1-Dx)*Dy*src->r[ny][xc] + Dx*(1-Dy)*src->r[yc][nx] + Dx*Dy*src->r[ny][nx]; + dst->g[i][j] = (1-Dx)*(1-Dy)*src->g[yc][xc] + (1-Dx)*Dy*src->g[ny][xc] + Dx*(1-Dy)*src->g[yc][nx] + Dx*Dy*src->g[ny][nx]; + dst->b[i][j] = (1-Dx)*(1-Dy)*src->b[yc][xc] + (1-Dx)*Dy*src->b[ny][xc] + Dx*(1-Dy)*src->b[yc][nx] + Dx*Dy*src->b[ny][nx]; + } + } + } + } + else if (params.method=="Bilinear") { + for (int i=row_from; iheight-1); + double dy = i/params.scale - sy; + int ny = sy+1; + if (ny>=src->height) + ny = sy; + for (int j=0; jwidth; j++) { + int sx = j/params.scale; + sx = CLIPTO(sx, 0, src->width-1); + double dx = j/params.scale - sx; + int nx = sx+1; + if (nx>=src->width) + nx = sx; + dst->r[i][j] = (1-dx)*(1-dy)*src->r[sy][sx] + (1-dx)*dy*src->r[ny][sx] + dx*(1-dy)*src->r[sy][nx] + dx*dy*src->r[ny][nx]; + dst->g[i][j] = (1-dx)*(1-dy)*src->g[sy][sx] + (1-dx)*dy*src->g[ny][sx] + dx*(1-dy)*src->g[sy][nx] + dx*dy*src->g[ny][nx]; + dst->b[i][j] = (1-dx)*(1-dy)*src->b[sy][sx] + (1-dx)*dy*src->b[ny][sx] + dx*(1-dy)*src->b[sy][nx] + dx*dy*src->b[ny][nx]; + } + } + } + else { + for (int i=row_from; iheight-1); + for (int j=0; jwidth; j++) { + int sx = j/params.scale; + sx = CLIPTO(sx, 0, src->width-1); + dst->r[i][j] = src->r[sy][sx]; + dst->g[i][j] = src->g[sy][sx]; + dst->b[i][j] = src->b[sy][sx]; + } + } + } +} + +void ImProcFunctions::getAutoExp (int* histogram, int histcompr, double expcomp, double clip, double& br, int& bl) { + + double sum = 0; + for (int i=0; i<65536>>histcompr; i++) + sum += histogram[i]; + + // compute clipping points based on the original histograms (linear, without exp comp.) + int clippable = (int)(sum * clip); + int clipped = 0; + int aw = (65536>>histcompr) - 1; + while (aw>1 && histogram[aw]+clipped <= clippable) { + clipped += histogram[aw]; + aw--; + } + + clipped = 0; + int shc = 0; + while (shc>histcompr; i++) + gavg += histogram[i] * CurveFactory::gamma2((int)(corr*(i< + * + * 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 . + */ +#ifndef _IMPROCFUN_H_ +#define _IMPROCFUN_H_ + +#include +#include +#include +#include +#include + +namespace rtengine { + +using namespace procparams; + +class LabImage { + private: + bool fromImage; + + public: + int W, H; + unsigned short** L; + short** a; + short** b; + + LabImage (int w, int h); + LabImage (Image16* im); + ~LabImage (); +}; + +class ImProcFunctions { + + protected: + struct STemp { + int cx, cy, sx, sy, oW, oH; + }; + cmsHTRANSFORM monitorTransform; + + void transform_ (Image16* original, Image16* transformed, const ProcParams* params, STemp sizes, int row_from, int row_to); + void simpltransform_ (Image16* original, Image16* transformed, const ProcParams* params, STemp sizes, int row_from, int row_to); + void vignetting_ (Image16* original, Image16* transformed, const ProcParams* params, STemp sizes, int row_from, int row_to); + void transform_sep_ (Image16* original, Image16* transformed, const ProcParams* params, STemp sizes, int row_from, int row_to); + void rgbProc_ (Image16* working, LabImage* lab, const ProcParams* params, int* tonecurve, SHMap* shmap, int row_from, int row_to); + void lab2rgb_ (LabImage* lab, Image8* image, int row_from, int row_to); + void colorCurve_ (LabImage* lold, LabImage* lnew, const ProcParams* params, int row_from, int row_to, double* cmultiplier); + void sharpenHaloCtrl (LabImage* lab, const ProcParams* params, unsigned short** blurmap, unsigned short** base, int W, int row_from, int row_to); + void firstAnalysis_ (Image16* original, Glib::ustring wprofile, int* histogram, int* chroma_radius, int row_from, int row_to); + void resize_ (Image16* src, Image16* dst, ResizeParams params, int row_from, int row_to); + void damping_ (float** aI, unsigned short** aO, float damping, int W, int rowfrom, int rowto); + + public: + + static int* cacheL; + static int* cachea; + static int* cacheb; + static int* xcache; + static int* ycache; + static int* zcache; + + int chroma_scale; + int chroma_radius; + + double lumimul[3]; + static unsigned short gamma2curve[65536]; + + + static void initCache (); + + ImProcFunctions () : monitorTransform(NULL) {} + void release (); + + + void firstAnalysis (Image16* working, const ProcParams* params, int* vhist16, double gamma); + + void rgbProc (Image16* working, LabImage* lab, const ProcParams* params, int* tonecurve, SHMap* shmap); + void luminanceCurve (LabImage* lold, LabImage* lnew, int* curve, int row_from, int row_to); + void colorCurve (LabImage* lold, LabImage* lnew, const ProcParams* params); + void sharpening (LabImage* lab, const ProcParams* params, double scale, unsigned short** buffer); + void lumadenoise (LabImage* lab, const ProcParams* params, double scale, int** buffer); + void colordenoise (LabImage* lab, const ProcParams* params, double scale, int** buffer); + void transform (Image16* original, Image16* transformed, const ProcParams* params, int cx, int cy, int sx, int sy, int oW, int oH); + void simpltransform (Image16* original, Image16* transformed, const ProcParams* params, int cx, int cy, int sx, int sy, int oW, int oH); + void vignetting (Image16* original, Image16* transformed, const ProcParams* params, int cx, int cy, int oW, int oH); + void lab2rgb (LabImage* lab, Image8* image); + void resize (Image16* src, Image16* dst, ResizeParams params); + + bool transCoord (const ProcParams* params, int W, int H, int x, int y, int w, int h, int& xv, int& yv, int& wv, int& hv); + bool transCoord (const ProcParams* params, int W, int H, std::vector &src, std::vector &red, std::vector &green, std::vector &blue); + void deconvsharpening(LabImage* lab, const ProcParams* params, double scale, unsigned short** buffer); + + Image8* lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile); + Image16* lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile); + + static void getAutoExp (int* histogram, int histcompr, double expcomp, double clip, double& br, int& bl); +}; +}; +#endif diff --git a/rtengine/init.cc b/rtengine/init.cc new file mode 100755 index 000000000..02111b00f --- /dev/null +++ b/rtengine/init.cc @@ -0,0 +1,68 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include +#include + +namespace rtengine { + +const Settings* settings; + +extern Glib::Mutex* dcrMutex; +Glib::Mutex* lcmsMutex = NULL; + +int init (const Settings* s) { + + settings = s; + iccStore.parseDir (s->iccDirectory); + CurveFactory::loadCurves (""); + ImProcFunctions::initCache (); + delete dcrMutex; + dcrMutex = new Glib::Mutex; + delete lcmsMutex; + lcmsMutex = new Glib::Mutex; +} + +StagedImageProcessor* StagedImageProcessor::create (InitialImage* initialImage) { + + ImProcCoordinator* ipc = new ImProcCoordinator (); + ipc->assign (initialImage->getImageSource ()); + return ipc; +} + +void StagedImageProcessor::destroy (StagedImageProcessor* sip) { + + delete sip; +} + +Settings* Settings::create () { + + return new Settings; +} + +void Settings::destroy (Settings* s) { + + delete s; +} + + +} + diff --git a/rtengine/iptcpairs.h b/rtengine/iptcpairs.h new file mode 100755 index 000000000..f4f0c0b07 --- /dev/null +++ b/rtengine/iptcpairs.h @@ -0,0 +1,47 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _IPTCPAIRS_ +#define _IPTCPAIRS_ + + +struct IptcPair { + IptcTag tag; + int size; + Glib::ustring field; +}; + +const IptcPair strTags[] = {IPTC_TAG_CAPTION, 2000, "Caption", + IPTC_TAG_WRITER_EDITOR, 32, "CaptionWriter", + IPTC_TAG_HEADLINE, 256, "Headline", + IPTC_TAG_SPECIAL_INSTRUCTIONS, 256, "Instructions", + IPTC_TAG_CATEGORY, 3, "Category", + IPTC_TAG_BYLINE, 32, "Author", + IPTC_TAG_BYLINE_TITLE, 32, "AuthorsPosition", + IPTC_TAG_CREDIT, 32, "Credit", + IPTC_TAG_SOURCE, 32, "Source", + IPTC_TAG_COPYRIGHT_NOTICE, 128, "Copyright", + IPTC_TAG_CITY, 32, "City", + IPTC_TAG_STATE, 32, "Province", + IPTC_TAG_COUNTRY_NAME, 64, "Country", + IPTC_TAG_OBJECT_NAME, 64, "Title", + IPTC_TAG_ORIG_TRANS_REF, 32, "TransReference", + IPTC_TAG_DATE_CREATED, 8, "DateCreated"}; + +#endif + diff --git a/rtengine/jdatasrc.c b/rtengine/jdatasrc.c new file mode 100755 index 000000000..0b77f26b1 --- /dev/null +++ b/rtengine/jdatasrc.c @@ -0,0 +1,413 @@ +#ifndef WIN32 +#define jboolean boolean +#endif +#include + +/* + * jdatasrc.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains decompression data source routines for the case of + * reading JPEG data from a file (or any stdio stream). While these routines + * are sufficient for most applications, some will want to use a different + * source manager. + * IMPORTANT: we assume that fread() will correctly transcribe an array of + * JOCTETs from 8-bit-wide elements on external storage. If char is wider + * than 8 bits on your machine, you may need to do some tweaking. + */ + +/* this is not a core library module, so it doesn't define JPEG_INTERNALS */ +//#include "jinclude.h" +#include +#include +#include + +#define JFREAD(file,buf,sizeofbuf) \ + ((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) +#define JFWRITE(file,buf,sizeofbuf) \ + ((size_t) fwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) + + + + +/* Expanded data source object for stdio input */ + +typedef struct { + struct jpeg_source_mgr pub; /* public fields */ + + FILE * infile; /* source stream */ + JOCTET * buffer; /* start of buffer */ + jboolean start_of_file; /* have we gotten any data yet? */ +} my_source_mgr; + +typedef my_source_mgr * my_src_ptr; + +#define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */ + + +/* + * Initialize source --- called by jpeg_read_header + * before any data is actually read. + */ + +METHODDEF(void) +my_init_source (j_decompress_ptr cinfo) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + /* We reset the empty-input-file flag for each image, + * but we don't clear the input buffer. + * This is correct behavior for reading a series of images from one source. + */ + src->start_of_file = TRUE; +} + + +/* + * Fill the input buffer --- called whenever buffer is emptied. + * + * In typical applications, this should read fresh data into the buffer + * (ignoring the current state of next_input_byte & bytes_in_buffer), + * reset the pointer & count to the start of the buffer, and return TRUE + * indicating that the buffer has been reloaded. It is not necessary to + * fill the buffer entirely, only to obtain at least one more byte. + * + * There is no such thing as an EOF return. If the end of the file has been + * reached, the routine has a choice of ERREXIT() or inserting fake data into + * the buffer. In most cases, generating a warning message and inserting a + * fake EOI marker is the best course of action --- this will allow the + * decompressor to output however much of the image is there. However, + * the resulting error message is misleading if the real problem is an empty + * input file, so we handle that case specially. + * + * In applications that need to be able to suspend compression due to input + * not being available yet, a FALSE return indicates that no more data can be + * obtained right now, but more may be forthcoming later. In this situation, + * the decompressor will return to its caller (with an indication of the + * number of scanlines it has read, if any). The application should resume + * decompression after it has loaded more data into the input buffer. Note + * that there are substantial restrictions on the use of suspension --- see + * the documentation. + * + * When suspending, the decompressor will back up to a convenient restart point + * (typically the start of the current MCU). next_input_byte & bytes_in_buffer + * indicate where the restart point will be if the current call returns FALSE. + * Data beyond this point must be rescanned after resumption, so move it to + * the front of the buffer rather than discarding it. + */ + +METHODDEF(jboolean) +my_fill_input_buffer (j_decompress_ptr cinfo) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + size_t nbytes; + + nbytes = JFREAD(src->infile, src->buffer, INPUT_BUF_SIZE); + + if (nbytes <= 0) { + if (src->start_of_file) /* Treat empty input file as fatal error */ + ERREXIT(cinfo, JERR_INPUT_EMPTY); + WARNMS(cinfo, JWRN_JPEG_EOF); + /* Insert a fake EOI marker */ + src->buffer[0] = (JOCTET) 0xFF; + src->buffer[1] = (JOCTET) JPEG_EOI; + nbytes = 2; + } + + if (src->start_of_file) + src->buffer[0] = (JOCTET) 0xFF; + + src->pub.next_input_byte = src->buffer; + src->pub.bytes_in_buffer = nbytes; + src->start_of_file = FALSE; + + return TRUE; +} + + +/* + * Skip data --- used to skip over a potentially large amount of + * uninteresting data (such as an APPn marker). + * + * Writers of suspendable-input applications must note that skip_input_data + * is not granted the right to give a suspension return. If the skip extends + * beyond the data currently in the buffer, the buffer can be marked empty so + * that the next read will cause a fill_input_buffer call that can suspend. + * Arranging for additional bytes to be discarded before reloading the input + * buffer is the application writer's problem. + */ + +METHODDEF(void) +my_skip_input_data (j_decompress_ptr cinfo, long num_bytes) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + /* Just a dumb implementation for now. Could use fseek() except + * it doesn't work on pipes. Not clear that being smart is worth + * any trouble anyway --- large skips are infrequent. + */ + if (num_bytes > 0) { + while (num_bytes > (long) src->pub.bytes_in_buffer) { + num_bytes -= (long) src->pub.bytes_in_buffer; + (void) my_fill_input_buffer(cinfo); + /* note we assume that fill_input_buffer will never return FALSE, + * so suspension need not be handled. + */ + } + src->pub.next_input_byte += (size_t) num_bytes; + src->pub.bytes_in_buffer -= (size_t) num_bytes; + } +} + + +/* + * An additional method that can be provided by data source modules is the + * resync_to_restart method for error recovery in the presence of RST markers. + * For the moment, this source module just uses the default resync method + * provided by the JPEG library. That method assumes that no backtracking + * is possible. + */ + + +/* + * Terminate source --- called by jpeg_finish_decompress + * after all data has been read. Often a no-op. + * + * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding + * application must deal with any cleanup that should happen even + * for error exit. + */ + +METHODDEF(void) +my_term_source (j_decompress_ptr cinfo) +{ + /* no work necessary here */ +} + + +/* + * Prepare for input from a stdio stream. + * The caller must have already opened the stream, and is responsible + * for closing it after finishing decompression. + */ + +GLOBAL(void) +my_jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile) +{ + my_src_ptr src; + + /* The source object and input buffer are made permanent so that a series + * of JPEG images can be read from the same file by calling jpeg_stdio_src + * only before the first one. (If we discarded the buffer at the end of + * one image, we'd likely lose the start of the next one.) + * This makes it unsafe to use this manager and a different source + * manager serially with the same JPEG object. Caveat programmer. + */ + if (cinfo->src == NULL) { /* first time for this JPEG object? */ + cinfo->src = (struct jpeg_source_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + sizeof(my_source_mgr)); + src = (my_src_ptr) cinfo->src; + src->buffer = (JOCTET *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + INPUT_BUF_SIZE * sizeof(JOCTET)); + } + + src = (my_src_ptr) cinfo->src; + src->pub.init_source = my_init_source; + src->pub.fill_input_buffer = my_fill_input_buffer; + src->pub.skip_input_data = my_skip_input_data; + src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ + src->pub.term_source = my_term_source; + src->infile = infile; + src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ + src->pub.next_input_byte = NULL; /* until buffer loaded */ +} + +jmp_buf jpeg_jmp_buf; + +METHODDEF(void) +my_error_exit (j_common_ptr cinfo) +{ + /* Always display the message */ + (*cinfo->err->output_message) (cinfo); + + /* Let the memory manager delete any temp files before we die */ + jpeg_destroy(cinfo); + + longjmp (jpeg_jmp_buf, 1); +} + + +//const char * const jpeg_std_message_table[] = { +//#include "jerror.h" +// NULL +//}; +extern const char * const jpeg_std_message_table[]; + + +/* + * Actual output of an error or trace message. + * Applications may override this method to send JPEG messages somewhere + * other than stderr. + * + * On Windows, printing to stderr is generally completely useless, + * so we provide optional code to produce an error-dialog popup. + * Most Windows applications will still prefer to override this routine, + * but if they don't, it'll do something at least marginally useful. + * + * NOTE: to use the library in an environment that doesn't support the + * C stdio library, you may have to delete the call to fprintf() entirely, + * not just not use this routine. + */ + +METHODDEF(void) +output_message (j_common_ptr cinfo) +{ + char buffer[JMSG_LENGTH_MAX]; + + /* Create the message */ + (*cinfo->err->format_message) (cinfo, buffer); + +#ifdef USE_WINDOWS_MESSAGEBOX + /* Display it in a message dialog box */ + MessageBox(GetActiveWindow(), buffer, "JPEG Library Error", + MB_OK | MB_ICONERROR); +#else + /* Send it to stderr, adding a newline */ + fprintf(stderr, "%s\n", buffer); +#endif +} + + +/* + * Decide whether to emit a trace or warning message. + * msg_level is one of: + * -1: recoverable corrupt-data warning, may want to abort. + * 0: important advisory messages (always display to user). + * 1: first level of tracing detail. + * 2,3,...: successively more detailed tracing messages. + * An application might override this method if it wanted to abort on warnings + * or change the policy about which messages to display. + */ + +METHODDEF(void) +emit_message (j_common_ptr cinfo, int msg_level) +{ + struct jpeg_error_mgr * err = cinfo->err; + + if (msg_level < 0) { + /* It's a warning message. Since corrupt files may generate many warnings, + * the policy implemented here is to show only the first warning, + * unless trace_level >= 3. + */ + if (err->num_warnings == 0 || err->trace_level >= 3) + (*err->output_message) (cinfo); + /* Always count warnings in num_warnings. */ + err->num_warnings++; + } else { + /* It's a trace message. Show it if trace_level >= msg_level. */ + if (err->trace_level >= msg_level) + (*err->output_message) (cinfo); + } +} + + +/* + * Format a message string for the most recent JPEG error or message. + * The message is stored into buffer, which should be at least JMSG_LENGTH_MAX + * characters. Note that no '\n' character is added to the string. + * Few applications should need to override this method. + */ + +METHODDEF(void) +format_message (j_common_ptr cinfo, char * buffer) +{ + struct jpeg_error_mgr * err = cinfo->err; + int msg_code = err->msg_code; + const char * msgtext = NULL; + const char * msgptr; + char ch; + jboolean isstring; + + /* Look up message string in proper table */ + if (msg_code > 0 && msg_code <= err->last_jpeg_message) { + msgtext = err->jpeg_message_table[msg_code]; + } else if (err->addon_message_table != NULL && + msg_code >= err->first_addon_message && + msg_code <= err->last_addon_message) { + msgtext = err->addon_message_table[msg_code - err->first_addon_message]; + } + + /* Defend against bogus message number */ + if (msgtext == NULL) { + err->msg_parm.i[0] = msg_code; + msgtext = err->jpeg_message_table[0]; + } + + /* Check for string parameter, as indicated by %s in the message text */ + isstring = FALSE; + msgptr = msgtext; + while ((ch = *msgptr++) != '\0') { + if (ch == '%') { + if (*msgptr == 's') isstring = TRUE; + break; + } + } + + /* Format the message into the passed buffer */ + if (isstring) + sprintf(buffer, msgtext, err->msg_parm.s); + else + sprintf(buffer, msgtext, + err->msg_parm.i[0], err->msg_parm.i[1], + err->msg_parm.i[2], err->msg_parm.i[3], + err->msg_parm.i[4], err->msg_parm.i[5], + err->msg_parm.i[6], err->msg_parm.i[7]); +} + + +/* + * Reset error state variables at start of a new image. + * This is called during compression startup to reset trace/error + * processing to default state, without losing any application-specific + * method pointers. An application might possibly want to override + * this method if it has additional error processing state. + */ + +METHODDEF(void) +reset_error_mgr (j_common_ptr cinfo) +{ + cinfo->err->num_warnings = 0; + /* trace_level is not reset since it is an application-supplied parameter */ + cinfo->err->msg_code = 0; /* may be useful as a flag for "no error" */ +} + + +GLOBAL(struct jpeg_error_mgr *) +my_jpeg_std_error (struct jpeg_error_mgr * err) +{ + + err->error_exit = my_error_exit; + err->emit_message = emit_message; + err->output_message = output_message; + err->format_message = format_message; + err->reset_error_mgr = reset_error_mgr; + + err->trace_level = 0; /* default = no tracing */ + err->num_warnings = 0; /* no warnings emitted yet */ + err->msg_code = 0; /* may be useful as a flag for "no error" */ + + /* Initialize message table pointers */ + err->jpeg_message_table = jpeg_std_message_table; + err->last_jpeg_message = (int) JMSG_LASTMSGCODE - 1; + + err->addon_message_table = NULL; + err->first_addon_message = 0; /* for safety */ + err->last_addon_message = 0; + + return err; +} diff --git a/rtengine/loadinitial.cc b/rtengine/loadinitial.cc new file mode 100755 index 000000000..515d703fd --- /dev/null +++ b/rtengine/loadinitial.cc @@ -0,0 +1,43 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include + +namespace rtengine { + +InitialImage* InitialImage::load (const Glib::ustring& fname, bool isRaw, int* errorCode, ProgressListener* pl) { + + ImageSource* isrc; + + if (!isRaw) + isrc = new StdImageSource (); + else + isrc = new RawImageSource (); + + isrc->setProgressListener (pl); + *errorCode = isrc->load (fname); + if (*errorCode) { + delete isrc; + return NULL; + } + return isrc; +} +} + diff --git a/rtengine/median.h b/rtengine/median.h new file mode 100755 index 000000000..e963d484b --- /dev/null +++ b/rtengine/median.h @@ -0,0 +1,222 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#define SORT3(a1,a2,a3,b1,b2,b3) \ + { \ + if ((a1)<(a2)) { \ + if ((a2)<(a3)) { \ + (b1) = (a1); (b2) = (a2); (b3) = (a3); \ + } \ + else if ((a1)<(a3)) { \ + (b1) = (a1); (b2) = (a3); (b3) = (a2); \ + } \ + else { \ + (b1) = (a3); (b2) = (a1); (b3) = (a2); \ + } \ + } \ + else { \ + if ((a3)<(a2)) { \ + (b1) = (a3); (b2) = (a2); (b3) = (a1); \ + } \ + else if ((a3)<(a1)) { \ + (b1) = (a2); (b2) = (a3); (b3) = (a1); \ + } \ + else { \ + (b1) = (a2); (b2) = (a1); (b3) = (a3); \ + } \ + } \ + } + +#define MERGESORT(a1,a2,a3,b1,b2,b3,c1,c2,c3,c4,c5,c6) \ + {\ + if (a1 + * + * 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 . + */ +#define MINMAX3(a,b,c,min,max) \ +{ \ +if ((a)<(b)) { \ + if ((b)<(c)) { \ + (min) = (a); \ + (max) = (c); \ + } \ + else { \ + (max) = (b); \ + if ((a)<(c)) \ + (min) = (a); \ + else \ + (min) = (c); \ + } \ +} else { \ + if ((b)>(c)) { \ + (min) = (c); \ + (max) = (a); \ + } \ + else { \ + (min) = (b); \ + if ((a)>(c)) \ + (max) = (a); \ + else \ + (max) = (c); \ + } \ +} \ +} + +#define MIN3(a,b,c,min) \ +{ \ +if ((a)<(b)) { \ + if ((a)<(c)) \ + (min) = (a); \ + else \ + (min) = (c); \ +} else { \ + if ((b)>(c)) \ + (min) = (c); \ + else \ + (min) = (b); \ +} \ +} + +#define MAX3(a,b,c,min) \ +{ \ +if ((a)>(b)) { \ + if ((a)>(c)) \ + (max) = (a); \ + else \ + (max) = (c); \ +} else { \ + if ((b)<(c)) \ + (max) = (c); \ + else \ + (max) = (b); \ +} \ +} diff --git a/rtengine/myfile.cc b/rtengine/myfile.cc new file mode 100755 index 000000000..e1d2ac79d --- /dev/null +++ b/rtengine/myfile.cc @@ -0,0 +1,133 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include + +IMFILE* fopen (const char* fname) { + + IMFILE* mf = new IMFILE; + FILE* f = fopen (fname, "rb"); + if (!f) + return NULL; + fseek (f, 0, SEEK_END); + mf->size = ftell (f); + mf->data = new char [mf->size]; + fseek (f, 0, SEEK_SET); + fread (mf->data, 1, mf->size, f); + fclose (f); + mf->pos = 0; + mf->eof = false; +#ifdef RAWZOR_SUPPORT + // RAWZOR support begin + bool rawzor = false; + Glib::ustring bname = Glib::path_get_basename(fname); + int lastdot = bname.find_last_of ('.'); + if (lastdot!=bname.npos) + rawzor = bname.substr (lastdot).casefold() == Glib::ustring(".rwz").casefold(); + + if (rawzor) { + int realSize = 0; + if (!m_rwz_check (mf->data, mf->size, &realSize)) { + char* realData = new char [realSize]; + m_rwz_decompress (mf->data, mf->size, realData, realSize); + delete [] mf->data; + mf->data = realData; + mf->size = realSize; + } + } + // RAWZOR support end +#endif + + return mf; +} + +IMFILE* gfopen (const char* fname) { + + IMFILE* mf = new IMFILE; + FILE* f = g_fopen (fname, "rb"); + if (!f) + return NULL; + fseek (f, 0, SEEK_END); + mf->size = ftell (f); + mf->data = new char [mf->size]; + fseek (f, 0, SEEK_SET); + fread (mf->data, 1, mf->size, f); + fclose (f); + mf->pos = 0; + mf->eof = false; + +#ifdef RAWZOR_SUPPORT + // RAWZOR support begin + bool rawzor = false; + Glib::ustring bname = Glib::path_get_basename(fname); + int lastdot = bname.find_last_of ('.'); + if (lastdot!=bname.npos) + rawzor = bname.substr (lastdot).casefold() == Glib::ustring(".rwz").casefold(); + + if (rawzor) { + int realSize = 0; + if (!m_rwz_check (mf->data, mf->size, &realSize)) { + char* realData = new char [realSize]; + m_rwz_decompress (mf->data, mf->size, realData, realSize); + delete [] mf->data; + mf->data = realData; + mf->size = realSize; + } + } + // RAWZOR support end +#endif + return mf; +} + +IMFILE* fopen (unsigned* buf, int size) { + + IMFILE* mf = new IMFILE; + mf->size = size; + mf->data = new char [mf->size]; + memcpy (mf->data, buf, size); + mf->pos = 0; + mf->eof = false; + return mf; +} + +void fclose (IMFILE* f) { + + delete [] f->data; + delete f; +} + +int fscanf (IMFILE* f, const char* s ...) { + + va_list ap; + return sscanf (f->data, s, ap); +} + +char* fgets (char* s, int n, IMFILE* f) { + + if (f->pos>=f->size) { + f->eof = true; + return NULL; + } + int i = 0; + do s[i++] = f->data[f->pos++]; + while (ipossize); + return s; +} diff --git a/rtengine/myfile.h b/rtengine/myfile.h new file mode 100755 index 000000000..c81d2eaac --- /dev/null +++ b/rtengine/myfile.h @@ -0,0 +1,92 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _MYFILE_ +#define _MYFILE_ + +#include +#include +#include +struct IMFILE { + + int pos; + int size; + char* data; + bool eof; +}; + +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) { + + return f->pos; +} + +inline int feof (IMFILE* f) { + + return f->eof; +} + +inline void fseek (IMFILE* f, int p, int how) { + + if (how==SEEK_SET) + f->pos = p; + else if (how==SEEK_CUR) + f->pos += p; + else if (how==SEEK_END) + f->pos = f->size-p; +} + +inline int fgetc (IMFILE* f) { + + if (f->possize) + return (unsigned char)f->data[f->pos++]; + f->eof = true; + return EOF; +} + +inline int getc (IMFILE* f) { + + if (f->possize) + return (unsigned char)f->data[f->pos++]; + f->eof = true; + return EOF; +} + +inline int fread (void* dst, int es, int count, IMFILE* f) { + + int s = es*count; + int avail = f->size - f->pos; + if (s<=avail) { + memcpy (dst, f->data+f->pos, s); + f->pos += s; + return count; + } + else { + memcpy (dst, f->data+f->pos, avail); + f->pos += avail; + f->eof = true; + return avail/es; + } +} + +int fscanf (IMFILE* f, const char* s ...); +char* fgets (char* s, int n, IMFILE* f); +#endif + diff --git a/rtengine/mytime.h b/rtengine/mytime.h new file mode 100755 index 000000000..b4e2c0879 --- /dev/null +++ b/rtengine/mytime.h @@ -0,0 +1,55 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _MYTIME_ +#define _MYTIME_ + +#ifndef WIN32 +#include +#else +#include +#endif + +class MyTime { + + public: +#ifndef WIN32 + timespec t; +#else + DWORD t; +#endif + + void set () { +#ifndef WIN32 + clock_gettime (CLOCK_REALTIME, &t); +#else + t = GetTickCount (); +#endif + } + + int etime (MyTime a) { +#ifndef WIN32 + return (t.tv_sec-a.t.tv_sec)*1000000 + (t.tv_nsec-a.t.tv_nsec)/1000; +#else + return (t - a.t)*1000; +#endif + } +}; + + +#endif diff --git a/rtengine/pparamsmap.cc b/rtengine/pparamsmap.cc new file mode 100755 index 000000000..03310844b --- /dev/null +++ b/rtengine/pparamsmap.cc @@ -0,0 +1,166 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +int main () { + + printf ("Member offsets in 'ProcParams':\n"); + + rtengine::procparams::ProcParams p; + + int d = (int) &p; + + printf ("%d\n", (int)&p.toneCurve.curve - d); + printf ("%d\n", (int)&p.toneCurve.brightness - d); + printf ("%d\n", (int)&p.toneCurve.black - d); + printf ("%d\n", (int)&p.toneCurve.contrast - d); + printf ("%d\n", (int)&p.toneCurve.shcompr - d); + printf ("%d\n", (int)&p.toneCurve.hlcompr - d); + printf ("%d\n", (int)&p.toneCurve.autoexp - d); + printf ("%d\n", (int)&p.toneCurve.clip - d); + printf ("%d\n", (int)&p.toneCurve.expcomp - d); + printf ("---------\n"); + printf ("%d\n", (int)&p.lumaCurve.curve - d); + printf ("%d\n", (int)&p.lumaCurve.brightness - d); + printf ("%d\n", (int)&p.lumaCurve.black - d); + printf ("%d\n", (int)&p.lumaCurve.contrast - d); + printf ("%d\n", (int)&p.lumaCurve.shcompr - d); + printf ("%d\n", (int)&p.lumaCurve.hlcompr - d); + printf ("---------\n"); + printf ("%d\n", (int)&p.sharpening.enabled - d); + printf ("%d\n", (int)&p.sharpening.radius - d); + printf ("%d\n", (int)&p.sharpening.amount - d); + printf ("%d\n", (int)&p.sharpening.threshold - d); + printf ("%d\n", (int)&p.sharpening.edgesonly - d); + printf ("%d\n", (int)&p.sharpening.edges_radius - d); + printf ("%d\n", (int)&p.sharpening.edges_tolerance - d); + printf ("%d\n", (int)&p.sharpening.halocontrol - d); + printf ("%d\n", (int)&p.sharpening.halocontrol_amount - d); + printf ("%d\n", (int)&p.sharpening.method - d); + printf ("%d\n", (int)&p.sharpening.deconvamount - d); + printf ("%d\n", (int)&p.sharpening.deconvradius - d); + printf ("%d\n", (int)&p.sharpening.deconviter - d); + printf ("%d\n", (int)&p.sharpening.deconvdamping - d); + printf ("---------\n"); + printf ("%d\n", (int)&p.colorBoost.a - d); + printf ("%d\n", (int)&p.colorBoost.b - d); + printf ("%d\n", (int)&p.colorBoost.avoidclip - d); + printf ("%d\n", (int)&p.colorBoost.enable_saturationlimiter - d); + printf ("%d\n", (int)&p.colorBoost.saturationlimit - d); + printf ("---------\n"); + printf ("%d\n", (int)&p.wb.method - d); + printf ("%d\n", (int)&p.wb.temperature - d); + printf ("%d\n", (int)&p.wb.green - d); + printf ("---------\n"); + printf ("%d\n", (int)&p.colorShift.a - d); + printf ("%d\n", (int)&p.colorShift.b - d); + printf ("---------\n"); + printf ("%d\n", (int)&p.lumaDenoise.enabled - d); + printf ("%d\n", (int)&p.lumaDenoise.radius - d); + printf ("%d\n", (int)&p.lumaDenoise.edgetolerance - d); + printf ("---------\n"); + printf ("%d\n", (int)&p.colorDenoise.enabled - d); + printf ("%d\n", (int)&p.colorDenoise.radius - d); + printf ("%d\n", (int)&p.colorDenoise.edgetolerance - d); + printf ("%d\n", (int)&p.colorDenoise.edgesensitive - d); + printf ("---------\n"); + printf ("%d\n", (int)&p.sh.enabled - d); + printf ("%d\n", (int)&p.sh.highlights - d); + printf ("%d\n", (int)&p.sh.htonalwidth - d); + printf ("%d\n", (int)&p.sh.shadows - d); + printf ("%d\n", (int)&p.sh.stonalwidth - d); + printf ("%d\n", (int)&p.sh.localcontrast - d); + printf ("%d\n", (int)&p.sh.radius - d); + printf ("---------\n"); + printf ("%d\n", (int)&p.crop.enabled - d); + printf ("%d\n", (int)&p.crop.x - d); + printf ("%d\n", (int)&p.crop.y - d); + printf ("%d\n", (int)&p.crop.w - d); + printf ("%d\n", (int)&p.crop.h - d); + printf ("%d\n", (int)&p.crop.fixratio - d); + printf ("%d\n", (int)&p.crop.ratio - d); + printf ("%d\n", (int)&p.crop.orientation - d); + printf ("%d\n", (int)&p.crop.guide - d); + printf ("---------\n"); + printf ("%d\n", (int)&p.coarse.rotate - d); + printf ("%d\n", (int)&p.coarse.hflip - d); + printf ("%d\n", (int)&p.coarse.vflip - d); + printf ("---------\n"); + printf ("%d\n", (int)&p.rotate.degree - d); + printf ("%d\n", (int)&p.rotate.fill - d); + printf ("---------\n"); + printf ("%d\n", (int)&p.distortion.amount - d); + printf ("---------\n"); + printf ("%d\n", (int)&p.cacorrection.red - d); + printf ("%d\n", (int)&p.cacorrection.blue - d); + printf ("---------\n"); + printf ("%d\n", (int)&p.vignetting.amount - d); + printf ("%d\n", (int)&p.vignetting.radius - d); + printf ("---------\n"); + printf ("%d\n", (int)&p.chmixer.red[0] - d); + printf ("%d\n", (int)&p.chmixer.green[0] - d); + printf ("%d\n", (int)&p.chmixer.blue[0] - d); + printf ("---------\n"); + printf ("%d\n", (int)&p.hlrecovery.enabled - d); + printf ("%d\n", (int)&p.hlrecovery.method - d); + printf ("---------\n"); + printf ("%d\n", (int)&p.resize.scale - d); + printf ("%d\n", (int)&p.resize.method - d); + printf ("---------\n"); + printf ("%d\n", (int)&p.icm.input - d); + printf ("%d\n", (int)&p.icm.gammaOnInput - d); + printf ("%d\n", (int)&p.icm.working - d); + printf ("%d\n", (int)&p.icm.output - d); + printf ("---------\n"); + printf ("%d\n", (int)&p.exif - d); + printf ("---------\n"); + printf ("%d\n", (int)&p.iptc - d); + printf ("---------\n"); + printf ("%d\n", (int)&p.version - d); + printf ("---------\n"); + printf ("sizeof 'ProcParams' = %d\n", sizeof(rtengine::procparams::ProcParams)); + + printf ("Member offsets in 'Settings':\n"); + rtengine::Settings s; + + d = (int) &s; + + printf ("%d\n", (int)&s.dualThreadEnabled - d); + printf ("%d\n", (int)&s.demosaicMethod - d); + printf ("%d\n", (int)&s.colorCorrectionSteps - d); + printf ("%d\n", (int)&s.iccDirectory - d); + printf ("%d\n", (int)&s.colorimetricIntent - d); + printf ("%d\n", (int)&s.monitorProfile - d); + printf ("---------\n"); + printf ("sizeof 'Settings' = %d\n", sizeof(rtengine::Settings)); + + printf ("Member offsets in 'RawMetaDataLocation':\n"); + rtengine::RawMetaDataLocation r; + + d = (int) &r; + + printf ("%d\n", (int)&r.exifBase - d); + printf ("%d\n", (int)&r.ciffBase - d); + printf ("%d\n", (int)&r.ciffLength - d); + printf ("---------\n"); + printf ("sizeof 'RawMetaDataLocation' = %d\n", sizeof(rtengine::RawMetaDataLocation)); + + +} + diff --git a/rtengine/processingjob.cc b/rtengine/processingjob.cc new file mode 100755 index 000000000..4c0b1ddcb --- /dev/null +++ b/rtengine/processingjob.cc @@ -0,0 +1,39 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +namespace rtengine { + +ProcessingJob* ProcessingJob::create (const Glib::ustring& fname, bool isRaw, const procparams::ProcParams& pparams) { + + return new ProcessingJobImpl (fname, isRaw, pparams); +} + +ProcessingJob* ProcessingJob::create (InitialImage* initialImage, const procparams::ProcParams& pparams) { + + return new ProcessingJobImpl (initialImage, pparams); +} + +void ProcessingJob::destroy (ProcessingJob* job) { + + delete (ProcessingJobImpl*) job; +} + +} + diff --git a/rtengine/processingjob.h b/rtengine/processingjob.h new file mode 100755 index 000000000..050bde66a --- /dev/null +++ b/rtengine/processingjob.h @@ -0,0 +1,45 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _PROCESSINGJOB_ +#define _PROCESSINGJOB_ + +#include + +namespace rtengine { + +class ProcessingJobImpl : public ProcessingJob { + + public: + Glib::ustring fname; + bool isRaw; + InitialImage* initialImage; + procparams::ProcParams pparams; + + ProcessingJobImpl (const Glib::ustring& fn, bool iR, const procparams::ProcParams& pp) + : fname(fn), isRaw(iR), initialImage(NULL) { pparams = pp; } + + ProcessingJobImpl (InitialImage* iImage, const procparams::ProcParams& pp) + : fname(""), initialImage(iImage) { pparams = pp; iImage->increaseRef(); } + + ~ProcessingJobImpl () { if (initialImage) initialImage->decreaseRef(); } +}; + +}; + +#endif diff --git a/rtengine/procevents.h b/rtengine/procevents.h new file mode 100755 index 000000000..9e0452b8d --- /dev/null +++ b/rtengine/procevents.h @@ -0,0 +1,114 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef __PROCEVENT__ +#define __PROCEVENT__ + +#include + +#define NUMOFEVENTS 83 + +namespace rtengine { + +enum ProcEvent { + EvPhotoLoaded=0, + EvProfileLoaded=1, + EvProfileChanged=2, + EvHistoryBrowsed=3, + EvBrightness=4, + EvContrast=5, + EvBlack=6, + EvExpComp=7, + EvHLCompr=8, + EvSHCompr=9, + EvToneCurve=10, + EvAutoExp=11, + EvClip=12, + EvLBrightness=13, + EvLContrast=14, + EvLBlack=15, + EvLHLCompr=16, + EvLSHCompr=17, + EvLCurve=18, + EvShrEnabled=19, + EvShrRadius=20, + EvShrAmount=21, + EvShrThresh=22, + EvShrEdgeOnly=23, + EvShrEdgeRadius=24, + EvShrEdgeTolerance=25, + EvShrHaloControl=26, + EvShrHaloAmount=27, + EvShrMethod=28, + EvShrDRadius=29, + EvShrDAmount=30, + EvShrDDamping=31, + EvShrDIterations=32, + EvCBAvoidClip=33, + EvCBSatLimiter=34, + EvCBSatLimit=35, + EvCBBoost=36, + EvWBMethod=37, + EvWBTemp=38, + EvWBGreen=39, + EvCShiftA=40, + EvCShiftB=41, + EvLDNEnabled=42, + EvLDNRadius=43, + EvLDNEdgeTolerance=44, + EvCDNEnabled=45, + EvCDNRadius=46, + EvCDNEdgeTolerance=47, + EvCDNEdgeSensitive=48, + EvSHEnabled=49, + EvSHHighlights=50, + EvSHShadows=51, + EvSHHLTonalW=52, + EvSHSHTonalW=53, + EvSHLContrast=54, + EvSHRadius=55, + EvCTRotate=56, + EvCTHFlip=57, + EvCTVFlip=58, + EvROTDegree=59, + EvROTFill=60, + EvDISTAmount=61, + EvBookmarkSelected=62, + EvCrop=63, + EvCACorr=64, + EvHREnabled=65, + EvHRAmount=66, + EvHRMethod=67, + EvWProfile=68, + EvOProfile=69, + EvIProfile=70, + EvVignetting=71, + EvChMixer=72, + EvResizeScale=73, + EvResizeMethod=74, + EvExif=75, + EvIPTC=76, + EvResizeSpec=77, + EvResizeWidth=78, + EvResizeHeight=79, + EvResizeEnabled=80, + EvProfileChangeNotification=81, + EvSHHighQuality=82 + }; +} +#endif diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc new file mode 100755 index 000000000..30bdebb21 --- /dev/null +++ b/rtengine/procparams.cc @@ -0,0 +1,657 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include +#include + +namespace rtengine { +namespace procparams { + +ProcParams::ProcParams () { + + setDefaults (); + +} + +ProcParams* ProcParams::create () { + + return new ProcParams(); +} + +void ProcParams::destroy (ProcParams* pp) { + + delete pp; +} + +void ProcParams::setDefaults () { + + toneCurve.autoexp = false; + toneCurve.clip = 0.002; + toneCurve.expcomp = 0; + toneCurve.brightness = 0; + toneCurve.contrast = 0; + toneCurve.black = 0; + toneCurve.hlcompr = 85; + toneCurve.shcompr = 85; + toneCurve.curve.clear (); + + lumaCurve.brightness = 0; + lumaCurve.contrast = 0; + lumaCurve.black = 0; + lumaCurve.hlcompr = 0; + lumaCurve.shcompr = 0; + lumaCurve.curve.clear (); + + sharpening.enabled = true; + sharpening.radius = 1.0; + sharpening.amount = 90; + sharpening.threshold = 768; + sharpening.edgesonly = false; + sharpening.edges_radius = 3; + sharpening.edges_tolerance = 1000; + sharpening.halocontrol = false; + sharpening.halocontrol_amount = 85; + sharpening.method = "usm"; + sharpening.deconvradius = 0.75; + sharpening.deconviter = 30; + sharpening.deconvdamping = 20; + sharpening.deconvamount = 75; + + colorBoost.amount = 0; + colorBoost.avoidclip = false; + colorBoost.enable_saturationlimiter = false; + colorBoost.saturationlimit = 50; + + wb.method = "Camera"; + wb.temperature = 6504; + wb.green = 1.00102; + + colorShift.a = 0; + colorShift.b = 0; + + lumaDenoise.enabled = false; + lumaDenoise.radius = 1.9; + lumaDenoise.edgetolerance = 2000; + + colorDenoise.enabled = false; + colorDenoise.edgesensitive = false; + colorDenoise.radius = 1.9; + colorDenoise.edgetolerance = 2000; + + sh.enabled = false; + sh.hq = false; + sh.highlights = 10; + sh.htonalwidth = 80; + sh.shadows = 10; + sh.stonalwidth = 80; + sh.localcontrast = 15; + sh.radius = 40; + + crop.enabled = false; + crop.x = -1; + crop.y = -1; + crop.w = 15000; + crop.h = 15000; + crop.fixratio = false; + crop.ratio = "3:2"; + crop.orientation= "Landscape"; + crop.guide = "None"; + + coarse.rotate = 0; + coarse.hflip = false; + coarse.vflip = false; + + rotate.degree = 0; + rotate.fill = true; + distortion.amount = 0; + + cacorrection.red = 0; + cacorrection.blue = 0; + + hlrecovery.enabled = false; + hlrecovery.method = "Luminance"; + + vignetting.amount = 0; + vignetting.radius = 50; + + chmixer.red[0] = 100; + chmixer.red[1] = 0; + chmixer.red[2] = 0; + chmixer.green[0] = 0; + chmixer.green[1] = 100; + chmixer.green[2] = 0; + chmixer.blue[0] = 0; + chmixer.blue[1] = 0; + chmixer.blue[2] = 100; + + resize.enabled = false; + resize.scale = 1.0; + resize.method = "Bicubic"; + resize.dataspec = 0; + resize.width = 800; + resize.height = 600; + + icm.input = ""; + icm.gammaOnInput = false; + icm.working = "sRGB"; + icm.output = "sRGB"; + + exif.clear (); + iptc.clear (); + + version = 249; +} + +int ProcParams::save (Glib::ustring fname) const { + + Glib::KeyFile keyFile; + + keyFile.set_integer ("Version", "Version", 231); + + // save tonecurve: + keyFile.set_boolean ("Exposure", "Auto", toneCurve.autoexp); + keyFile.set_double ("Exposure", "Clip", toneCurve.clip); + keyFile.set_double ("Exposure", "Compensation", toneCurve.expcomp); + keyFile.set_double ("Exposure", "Brightness", toneCurve.brightness); + keyFile.set_integer ("Exposure", "Contrast", toneCurve.contrast); + keyFile.set_integer ("Exposure", "Black", toneCurve.black); + keyFile.set_integer ("Exposure", "HighlightCompr", toneCurve.hlcompr); + keyFile.set_integer ("Exposure", "ShadowCompr", toneCurve.shcompr); + Glib::ArrayHandle tcurve = toneCurve.curve; + keyFile.set_double_list("Exposure", "Curve", tcurve); + + // save channel mixer + Glib::ArrayHandle rmix (chmixer.red, 3, Glib::OWNERSHIP_NONE); + Glib::ArrayHandle gmix (chmixer.green, 3, Glib::OWNERSHIP_NONE); + Glib::ArrayHandle bmix (chmixer.blue, 3, Glib::OWNERSHIP_NONE); + keyFile.set_integer_list("Channel Mixer", "Red", rmix); + keyFile.set_integer_list("Channel Mixer", "Green", gmix); + keyFile.set_integer_list("Channel Mixer", "Blue", bmix); + + // save luma curve + keyFile.set_double ("Luminance Curve", "Brightness", lumaCurve.brightness); + keyFile.set_integer ("Luminance Curve", "Contrast", lumaCurve.contrast); + keyFile.set_integer ("Luminance Curve", "Black", lumaCurve.black); + keyFile.set_integer ("Luminance Curve", "HighlightCompr", lumaCurve.hlcompr); + keyFile.set_integer ("Luminance Curve", "ShadowCompr", lumaCurve.shcompr); + Glib::ArrayHandle lcurve = lumaCurve.curve; + keyFile.set_double_list("Luminance Curve", "Curve", lcurve); + + // save sharpening + keyFile.set_boolean ("Sharpening", "Enabled", sharpening.enabled); + keyFile.set_string ("Sharpening", "Method", sharpening.method); + keyFile.set_double ("Sharpening", "Radius", sharpening.radius); + keyFile.set_integer ("Sharpening", "Amount", sharpening.amount); + keyFile.set_integer ("Sharpening", "Threshold", sharpening.threshold); + keyFile.set_boolean ("Sharpening", "OnlyEdges", sharpening.edgesonly); + keyFile.set_double ("Sharpening", "EdgedetectionRadius", sharpening.edges_radius); + keyFile.set_integer ("Sharpening", "EdgeTolerance", sharpening.edges_tolerance); + keyFile.set_boolean ("Sharpening", "HalocontrolEnabled", sharpening.halocontrol); + keyFile.set_integer ("Sharpening", "HalocontrolAmount", sharpening.halocontrol_amount); + keyFile.set_double ("Sharpening", "DeconvRadius", sharpening.deconvradius); + keyFile.set_integer ("Sharpening", "DeconvAmount", sharpening.deconvamount); + keyFile.set_integer ("Sharpening", "DeconvDamping", sharpening.deconvdamping); + keyFile.set_integer ("Sharpening", "DeconvIterations", sharpening.deconviter); + + // save colorBoost + keyFile.set_integer ("Color Boost", "Amount", colorBoost.amount); + keyFile.set_boolean ("Color Boost", "AvoidColorClipping", colorBoost.avoidclip); + keyFile.set_boolean ("Color Boost", "SaturationLimiter", colorBoost.enable_saturationlimiter); + keyFile.set_double ("Color Boost", "SaturationLimit", colorBoost.saturationlimit); + + // save wb + if (wb.method=="Camera") + keyFile.set_string ("White Balance", "Setting", "Camera"); + else + keyFile.set_string ("White Balance", "Setting", "Custom"); + keyFile.set_integer ("White Balance", "Temperature", wb.temperature); + keyFile.set_double ("White Balance", "Green", wb.green); + + // save colorShift + keyFile.set_double ("Color Shift", "ChannelA", colorShift.a); + keyFile.set_double ("Color Shift", "ChannelB", colorShift.b); + + // save lumaDenoise + keyFile.set_boolean ("Luminance Denoising", "Enabled", lumaDenoise.enabled); + keyFile.set_double ("Luminance Denoising", "Radius", lumaDenoise.radius); + keyFile.set_integer ("Luminance Denoising", "EdgeTolerance", lumaDenoise.edgetolerance); + + // save colorDenoise + keyFile.set_boolean ("Chrominance Denoising", "Enabled", colorDenoise.enabled); + keyFile.set_integer ("Chrominance Denoising", "Amount", colorDenoise.amount); + + // save sh + keyFile.set_boolean ("Shadows & Highlights", "Enabled", sh.enabled); + keyFile.set_boolean ("Shadows & Highlights", "HighQuality", sh.hq); + keyFile.set_integer ("Shadows & Highlights", "Highlights", sh.highlights); + keyFile.set_integer ("Shadows & Highlights", "HighlightTonalWidth", sh.htonalwidth); + keyFile.set_integer ("Shadows & Highlights", "Shadows", sh.shadows); + keyFile.set_integer ("Shadows & Highlights", "ShadowTonalWidth", sh.stonalwidth); + keyFile.set_integer ("Shadows & Highlights", "LocalContrast", sh.localcontrast); + keyFile.set_integer ("Shadows & Highlights", "Radius", sh.radius); + + // save crop + keyFile.set_boolean ("Crop", "Enabled", crop.enabled); + keyFile.set_integer ("Crop", "X", crop.x); + keyFile.set_integer ("Crop", "Y", crop.y); + keyFile.set_integer ("Crop", "W", crop.w); + keyFile.set_integer ("Crop", "H", crop.h); + keyFile.set_boolean ("Crop", "FixedRatio", crop.fixratio); + keyFile.set_string ("Crop", "Ratio", crop.ratio); + keyFile.set_string ("Crop", "Orientation", crop.orientation); + keyFile.set_string ("Crop", "Guide", crop.guide); + + // save coarse + keyFile.set_integer ("Coarse Transformation", "Rotate", coarse.rotate); + keyFile.set_boolean ("Coarse Transformation", "HorizontalFlip", coarse.hflip); + keyFile.set_boolean ("Coarse Transformation", "VerticalFlip", coarse.vflip); + + // save rotate + keyFile.set_double ("Rotation", "Degree", rotate.degree); + keyFile.set_double ("Rotation", "Fill", rotate.fill); + + // save distortion + keyFile.set_double ("Distortion", "Amount", distortion.amount); + + // save C/A correction + keyFile.set_double ("CACorrection", "Red", cacorrection.red); + keyFile.set_double ("CACorrection", "Blue", cacorrection.blue); + + // save vignetting correction + keyFile.set_integer ("Vignetting Correction", "Amount", vignetting.amount); + keyFile.set_integer ("Vignetting Correction", "Radius", vignetting.radius); + + // save highlight recovery settings + keyFile.set_boolean ("HLRecovery", "Enabled", hlrecovery.enabled); + keyFile.set_string ("HLRecovery", "Method", hlrecovery.method); + + keyFile.set_boolean ("Resize", "Enabled",resize.enabled); + keyFile.set_double ("Resize", "Scale", resize.scale); + keyFile.set_string ("Resize", "Method", resize.method); + keyFile.set_integer ("Resize", "DataSpecified", resize.dataspec); + keyFile.set_integer ("Resize", "Width", resize.width); + keyFile.set_integer ("Resize", "Height", resize.height); + + // save color management settings + keyFile.set_string ("Color Management", "InputProfile", icm.input); + keyFile.set_boolean ("Color Management", "ApplyGammaBeforeInputProfile", icm.gammaOnInput); + keyFile.set_string ("Color Management", "WorkingProfile", icm.working); + keyFile.set_string ("Color Management", "OutputProfile", icm.output); + + // save exif change list + for (int i=0; i values = iptc[i].values; + keyFile.set_string_list ("IPTC", iptc[i].field, values); + } + + FILE *f = g_fopen (fname.c_str(), "wt"); + + if (f==NULL) + return 1; + else { + fprintf (f, "%s", keyFile.to_data().c_str()); + fclose (f); + return 0; + } +} + +int ProcParams::load (Glib::ustring fname) { + + Glib::KeyFile keyFile; + try { + setDefaults (); + + FILE* f = g_fopen (fname.c_str(), "rt"); + if (!f) + return 1; + char* buffer = new char[1024]; + std::ostringstream ostr; + while (fgets (buffer, 1024, f)) + ostr << buffer << "\n"; + delete [] buffer; + if (!keyFile.load_from_data (ostr.str())) + return 1; + fclose (f); + + // load tonecurve: + +version = 200; +if (keyFile.has_group ("Version")) { + if (keyFile.has_key ("Version", "Version")) version = keyFile.get_integer ("Version", "Version"); +} + +if (keyFile.has_group ("Exposure")) { + if (keyFile.has_key ("Exposure", "Auto")) toneCurve.autoexp = keyFile.get_boolean ("Exposure", "Auto"); + if (keyFile.has_key ("Exposure", "Clip")) toneCurve.clip = keyFile.get_double ("Exposure", "Clip"); + if (keyFile.has_key ("Exposure", "Compensation")) toneCurve.expcomp = keyFile.get_double ("Exposure", "Compensation"); + if (keyFile.has_key ("Exposure", "Brightness")) toneCurve.brightness = keyFile.get_double ("Exposure", "Brightness"); + if (keyFile.has_key ("Exposure", "Contrast")) toneCurve.contrast = keyFile.get_integer ("Exposure", "Contrast"); + if (keyFile.has_key ("Exposure", "Black")) toneCurve.black = keyFile.get_integer ("Exposure", "Black"); + if (keyFile.has_key ("Exposure", "HighlightCompr")) toneCurve.hlcompr = keyFile.get_integer ("Exposure", "HighlightCompr"); + if (keyFile.has_key ("Exposure", "ShadowCompr")) toneCurve.shcompr = keyFile.get_integer ("Exposure", "ShadowCompr"); + if (version>200) + if (keyFile.has_key ("Exposure", "Curve")) toneCurve.curve = keyFile.get_double_list ("Exposure", "Curve"); +} + + // load channel mixer curve +if (keyFile.has_group ("Channel Mixer")) { + if (keyFile.has_key ("Channel Mixer", "Red") && keyFile.has_key ("Channel Mixer", "Green") && keyFile.has_key ("Channel Mixer", "Blue")) { + Glib::ArrayHandle rmix = keyFile.get_integer_list ("Channel Mixer", "Red"); + Glib::ArrayHandle gmix = keyFile.get_integer_list ("Channel Mixer", "Green"); + Glib::ArrayHandle bmix = keyFile.get_integer_list ("Channel Mixer", "Blue"); + memcpy (chmixer.red, rmix.data(), 3*sizeof(int)); + memcpy (chmixer.green, gmix.data(), 3*sizeof(int)); + memcpy (chmixer.blue, bmix.data(), 3*sizeof(int)); + } +} + + // load luma curve +if (keyFile.has_group ("Luminance Curve")) { + if (keyFile.has_key ("Luminance Curve", "Brightness")) lumaCurve.brightness = keyFile.get_double ("Luminance Curve", "Brightness"); + if (keyFile.has_key ("Luminance Curve", "Contrast")) lumaCurve.contrast = keyFile.get_integer ("Luminance Curve", "Contrast"); + if (keyFile.has_key ("Luminance Curve", "Black")) lumaCurve.black = keyFile.get_integer ("Luminance Curve", "Black"); + if (keyFile.has_key ("Luminance Curve", "HighlightCompr")) lumaCurve.hlcompr = keyFile.get_integer ("Luminance Curve", "HighlightCompr"); + if (keyFile.has_key ("Luminance Curve", "ShadowCompr")) lumaCurve.shcompr = keyFile.get_integer ("Luminance Curve", "ShadowCompr"); + if (version>200) + if (keyFile.has_key ("Luminance Curve", "Curve")) lumaCurve.curve = keyFile.get_double_list ("Luminance Curve", "Curve"); +} + + // load sharpening +if (keyFile.has_group ("Sharpening")) { + if (keyFile.has_key ("Sharpening", "Enabled")) sharpening.enabled = keyFile.get_boolean ("Sharpening", "Enabled"); + if (keyFile.has_key ("Sharpening", "Radius")) sharpening.radius = keyFile.get_double ("Sharpening", "Radius"); + if (keyFile.has_key ("Sharpening", "Amount")) sharpening.amount = keyFile.get_integer ("Sharpening", "Amount"); + if (keyFile.has_key ("Sharpening", "Threshold")) sharpening.threshold = keyFile.get_integer ("Sharpening", "Threshold"); + if (keyFile.has_key ("Sharpening", "OnlyEdges")) sharpening.edgesonly = keyFile.get_boolean ("Sharpening", "OnlyEdges"); + if (keyFile.has_key ("Sharpening", "EdgedetectionRadius")) sharpening.edges_radius = keyFile.get_double ("Sharpening", "EdgedetectionRadius"); + if (keyFile.has_key ("Sharpening", "EdgeTolerance")) sharpening.edges_tolerance = keyFile.get_integer ("Sharpening", "EdgeTolerance"); + if (keyFile.has_key ("Sharpening", "HalocontrolEnabled")) sharpening.halocontrol = keyFile.get_boolean ("Sharpening", "HalocontrolEnabled"); + if (keyFile.has_key ("Sharpening", "HalocontrolAmount")) sharpening.halocontrol_amount = keyFile.get_integer ("Sharpening", "HalocontrolAmount"); + if (keyFile.has_key ("Sharpening", "Method")) sharpening.method = keyFile.get_string ("Sharpening", "Method"); + if (keyFile.has_key ("Sharpening", "DeconvRadius")) sharpening.deconvradius = keyFile.get_double ("Sharpening", "DeconvRadius"); + if (keyFile.has_key ("Sharpening", "DeconvAmount")) sharpening.deconvamount = keyFile.get_integer ("Sharpening", "DeconvAmount"); + if (keyFile.has_key ("Sharpening", "DeconvDamping")) sharpening.deconvdamping = keyFile.get_integer ("Sharpening", "DeconvDamping"); + if (keyFile.has_key ("Sharpening", "DeconvIterations")) sharpening.deconviter = keyFile.get_integer ("Sharpening", "DeconvIterations"); +} + + // load colorBoost +if (keyFile.has_group ("Color Boost")) { + if (keyFile.has_key ("Color Boost", "Amount")) colorBoost.amount = keyFile.get_integer ("Color Boost", "Amount"); + else { + int a=0, b=0; + if (keyFile.has_key ("Color Boost", "ChannelA")) a = keyFile.get_integer ("Color Boost", "ChannelA"); + if (keyFile.has_key ("Color Boost", "ChannelB")) b = keyFile.get_integer ("Color Boost", "ChannelB"); + colorBoost.amount = (a+b) / 2; + } + if (keyFile.has_key ("Color Boost", "AvoidColorClipping")) colorBoost.avoidclip = keyFile.get_boolean ("Color Boost", "AvoidColorClipping"); + if (keyFile.has_key ("Color Boost", "SaturationLimiter")) colorBoost.enable_saturationlimiter= keyFile.get_boolean ("Color Boost", "SaturationLimiter"); + if (keyFile.has_key ("Color Boost", "SaturationLimit")) colorBoost.saturationlimit = keyFile.get_double ("Color Boost", "SaturationLimit"); +} + + // load wb +if (keyFile.has_group ("White Balance")) { + if (keyFile.has_key ("White Balance", "Setting")) wb.method = keyFile.get_string ("White Balance", "Setting"); + if (keyFile.has_key ("White Balance", "Temperature")) wb.temperature = keyFile.get_integer ("White Balance", "Temperature"); + if (keyFile.has_key ("White Balance", "Green")) wb.green = keyFile.get_double ("White Balance", "Green"); +} + + // load colorShift +if (keyFile.has_group ("Color Shift")) { + if (keyFile.has_key ("Color Shift", "ChannelA")) colorShift.a = keyFile.get_double ("Color Shift", "ChannelA"); + if (keyFile.has_key ("Color Shift", "ChannelB")) colorShift.b = keyFile.get_double ("Color Shift", "ChannelB"); +} + + // load lumaDenoise +if (keyFile.has_group ("Luminance Denoising")) { + if (keyFile.has_key ("Luminance Denoising", "Enabled")) lumaDenoise.enabled = keyFile.get_boolean ("Luminance Denoising", "Enabled"); + if (keyFile.has_key ("Luminance Denoising", "Radius")) lumaDenoise.radius = keyFile.get_double ("Luminance Denoising", "Radius"); + if (keyFile.has_key ("Luminance Denoising", "EdgeTolerance")) lumaDenoise.edgetolerance = keyFile.get_integer ("Luminance Denoising", "EdgeTolerance"); +} + + // load colorDenoise +if (keyFile.has_group ("Chrominance Denoising")) { + if (keyFile.has_key ("Chrominance Denoising", "Enabled")) colorDenoise.enabled = keyFile.get_boolean ("Chrominance Denoising", "Enabled"); + if (keyFile.has_key ("Chrominance Denoising", "Radius")) colorDenoise.amount = 10*keyFile.get_double ("Chrominance Denoising", "Radius"); + else if (keyFile.has_key ("Chrominance Denoising", "Amount")) colorDenoise.amount = keyFile.get_integer ("Chrominance Denoising", "Amount"); +} + + // load sh +if (keyFile.has_group ("Shadows & Highlights")) { + if (keyFile.has_key ("Shadows & Highlights", "Enabled")) sh.enabled = keyFile.get_boolean ("Shadows & Highlights", "Enabled"); + if (keyFile.has_key ("Shadows & Highlights", "HighQuality")) sh.hq = keyFile.get_boolean ("Shadows & Highlights", "HighQuality"); + if (keyFile.has_key ("Shadows & Highlights", "Highlights")) sh.highlights = keyFile.get_integer ("Shadows & Highlights", "Highlights"); + if (keyFile.has_key ("Shadows & Highlights", "HighlightTonalWidth")) sh.htonalwidth = keyFile.get_integer ("Shadows & Highlights", "HighlightTonalWidth"); + if (keyFile.has_key ("Shadows & Highlights", "Shadows")) sh.shadows = keyFile.get_integer ("Shadows & Highlights", "Shadows"); + if (keyFile.has_key ("Shadows & Highlights", "ShadowTonalWidth")) sh.stonalwidth = keyFile.get_integer ("Shadows & Highlights", "ShadowTonalWidth"); + if (keyFile.has_key ("Shadows & Highlights", "LocalContrast")) sh.localcontrast = keyFile.get_integer ("Shadows & Highlights", "LocalContrast"); + if (keyFile.has_key ("Shadows & Highlights", "Radius")) sh.radius = keyFile.get_integer ("Shadows & Highlights", "Radius"); +} + + // load crop +if (keyFile.has_group ("Crop")) { + if (keyFile.has_key ("Crop", "Enabled")) crop.enabled = keyFile.get_boolean ("Crop", "Enabled"); + if (keyFile.has_key ("Crop", "X")) crop.x = keyFile.get_integer ("Crop", "X"); + if (keyFile.has_key ("Crop", "Y")) crop.y = keyFile.get_integer ("Crop", "Y"); + if (keyFile.has_key ("Crop", "W")) crop.w = keyFile.get_integer ("Crop", "W"); + if (keyFile.has_key ("Crop", "H")) crop.h = keyFile.get_integer ("Crop", "H"); + if (keyFile.has_key ("Crop", "FixedRatio")) crop.fixratio = keyFile.get_boolean ("Crop", "FixedRatio"); + if (keyFile.has_key ("Crop", "Ratio")) crop.ratio = keyFile.get_string ("Crop", "Ratio"); + if (keyFile.has_key ("Crop", "Orientation"))crop.orientation= keyFile.get_string ("Crop", "Orientation"); + if (keyFile.has_key ("Crop", "Guide")) crop.guide = keyFile.get_string ("Crop", "Guide"); +} + + // load coarse +if (keyFile.has_group ("Coarse Transformation")) { + if (keyFile.has_key ("Coarse Transformation", "Rotate")) coarse.rotate = keyFile.get_integer ("Coarse Transformation", "Rotate"); + if (keyFile.has_key ("Coarse Transformation", "HorizontalFlip")) coarse.hflip = keyFile.get_boolean ("Coarse Transformation", "HorizontalFlip"); + if (keyFile.has_key ("Coarse Transformation", "VerticalFlip")) coarse.vflip = keyFile.get_boolean ("Coarse Transformation", "VerticalFlip"); +} + + // load rotate +if (keyFile.has_group ("Rotation")) { + if (keyFile.has_key ("Rotation", "Degree")) rotate.degree = keyFile.get_double ("Rotation", "Degree"); + if (keyFile.has_key ("Rotation", "Fill")) rotate.fill = keyFile.get_double ("Rotation", "Fill"); +} + + // load distortion +if (keyFile.has_group ("Distortion")) { + if (keyFile.has_key ("Distortion", "Amount")) distortion.amount = keyFile.get_double ("Distortion", "Amount"); +} + + // load c/a correction +if (keyFile.has_group ("CACorrection")) { + if (keyFile.has_key ("CACorrection", "Red")) cacorrection.red = keyFile.get_double ("CACorrection", "Red"); + if (keyFile.has_key ("CACorrection", "Blue")) cacorrection.blue = keyFile.get_double ("CACorrection", "Blue"); +} + + // load vignetting correction +if (keyFile.has_group ("Vignetting Correction")) { + if (keyFile.has_key ("Vignetting Correction", "Amount")) vignetting.amount = keyFile.get_integer ("Vignetting Correction", "Amount"); + if (keyFile.has_key ("Vignetting Correction", "Radius")) vignetting.radius = keyFile.get_integer ("Vignetting Correction", "Radius"); +} + + // load highlight recovery settings +if (keyFile.has_group ("HLRecovery")) { + if (keyFile.has_key ("HLRecovery", "Enabled")) hlrecovery.enabled = keyFile.get_boolean ("HLRecovery", "Enabled"); + if (keyFile.has_key ("HLRecovery", "Method")) hlrecovery.method = keyFile.get_string ("HLRecovery", "Method"); +} + // load resize settings +if (keyFile.has_group ("Resize")) { + if (keyFile.has_key ("Resize", "Enabled")) resize.enabled = keyFile.get_boolean ("Resize", "Enabled"); + if (keyFile.has_key ("Resize", "Scale")) resize.scale = keyFile.get_double ("Resize", "Scale"); + if (keyFile.has_key ("Resize", "Method")) resize.method = keyFile.get_string ("Resize", "Method"); + if (keyFile.has_key ("Resize", "DataSpecified")) resize.dataspec = keyFile.get_integer ("Resize", "DataSpecified"); + if (keyFile.has_key ("Resize", "Width")) resize.width = keyFile.get_integer ("Resize", "Width"); + if (keyFile.has_key ("Resize", "Height")) resize.height = keyFile.get_integer ("Resize", "Height"); +} + + // load color management settings +if (keyFile.has_group ("Color Management")) { + if (keyFile.has_key ("Color Management", "InputProfile")) icm.input = keyFile.get_string ("Color Management", "InputProfile"); + if (keyFile.has_key ("Color Management", "ApplyGammaBeforeInputProfile")) icm.gammaOnInput = keyFile.get_boolean ("Color Management", "ApplyGammaBeforeInputProfile"); + if (keyFile.has_key ("Color Management", "WorkingProfile")) icm.working = keyFile.get_string ("Color Management", "WorkingProfile"); + if (keyFile.has_key ("Color Management", "OutputProfile")) icm.output = keyFile.get_string ("Color Management", "OutputProfile"); +} + + // load exif change settings +if (keyFile.has_group ("Exif")) { + std::vector keys = keyFile.get_keys ("Exif"); + exif.resize (keys.size()); + for (int i=0; i keys = keyFile.get_keys ("IPTC"); + iptc.resize (keys.size()); + for (int i=0; i%s\n", e.what().c_str()); + } + catch (...) { + printf ("-->ismeretlen exception!\n"); + return 1; + } +} + +bool operator==(const ExifPair& a, const ExifPair& b) { + + return a.field == b.field && a.value == b.value; +} + bool operator==(const IPTCPair& a, const IPTCPair& b) { + + return a.field == b.field && a.values == b.values; +} +bool ProcParams::operator== (const ProcParams& other) { + + return + toneCurve.curve == other.toneCurve.curve + && toneCurve.brightness == other.toneCurve.brightness + && toneCurve.black == other.toneCurve.black + && toneCurve.contrast == other.toneCurve.contrast + && toneCurve.shcompr == other.toneCurve.shcompr + && toneCurve.hlcompr == other.toneCurve.hlcompr + && toneCurve.autoexp == other.toneCurve.autoexp + && toneCurve.clip == other.toneCurve.clip + && toneCurve.expcomp == other.toneCurve.expcomp + && lumaCurve.curve == other.lumaCurve.curve + && lumaCurve.brightness == other.lumaCurve.brightness + && lumaCurve.black == other.lumaCurve.black + && lumaCurve.contrast == other.lumaCurve.contrast + && lumaCurve.shcompr == other.lumaCurve.shcompr + && lumaCurve.hlcompr == other.lumaCurve.hlcompr + && sharpening.enabled == other.sharpening.enabled + && sharpening.radius == other.sharpening.radius + && sharpening.amount == other.sharpening.amount + && sharpening.threshold == other.sharpening.threshold + && sharpening.edgesonly == other.sharpening.edgesonly + && sharpening.edges_radius == other.sharpening.edges_radius + && sharpening.edges_tolerance == other.sharpening.edges_tolerance + && sharpening.halocontrol == other.sharpening.halocontrol + && sharpening.halocontrol_amount== other.sharpening.halocontrol_amount + && sharpening.method == other.sharpening.method + && sharpening.deconvamount == other.sharpening.deconvamount + && sharpening.deconvradius == other.sharpening.deconvradius + && sharpening.deconviter == other.sharpening.deconviter + && sharpening.deconvdamping == other.sharpening.deconvdamping + && colorBoost.amount == other.colorBoost.amount + && colorBoost.avoidclip == other.colorBoost.avoidclip + && colorBoost.enable_saturationlimiter == other.colorBoost.enable_saturationlimiter + && colorBoost.saturationlimit == other.colorBoost.saturationlimit + && wb.method == other.wb.method + && wb.green == other.wb.green + && wb.temperature == other.wb.temperature + && colorShift.a == other.colorShift.a + && colorShift.b == other.colorShift.b + && lumaDenoise.enabled == other.lumaDenoise.enabled + && lumaDenoise.radius == other.lumaDenoise.radius + && lumaDenoise.edgetolerance == other.lumaDenoise.edgetolerance + && colorDenoise.enabled == other.colorDenoise.enabled + && colorDenoise.radius == other.colorDenoise.radius + && colorDenoise.edgetolerance == other.colorDenoise.edgetolerance + && colorDenoise.edgesensitive == other.colorDenoise.edgesensitive + && sh.enabled == other.sh.enabled + && sh.hq == other.sh.hq + && sh.highlights == other.sh.highlights + && sh.htonalwidth == other.sh.htonalwidth + && sh.shadows == other.sh.shadows + && sh.stonalwidth == other.sh.stonalwidth + && sh.localcontrast == other.sh.localcontrast + && sh.radius == other.sh.radius + && crop.enabled == other.crop.enabled + && crop.x == other.crop.x + && crop.y == other.crop.y + && crop.w == other.crop.w + && crop.h == other.crop.h + && crop.fixratio == other.crop.fixratio + && crop.ratio == other.crop.ratio + && crop.orientation == other.crop.orientation + && crop.guide == other.crop.guide + && coarse.rotate == other.coarse.rotate + && coarse.hflip == other.coarse.hflip + && coarse.vflip == other.coarse.vflip + && rotate.degree == other.rotate.degree + && rotate.fill == other.rotate.fill + && distortion.amount == other.distortion.amount + && cacorrection.red == other.cacorrection.red + && cacorrection.blue == other.cacorrection.blue + && vignetting.amount == other.vignetting.amount + && vignetting.radius == other.vignetting.radius + && !memcmp (&chmixer.red, &other.chmixer.red, 3*sizeof(int)) + && !memcmp (&chmixer.green, &other.chmixer.green, 3*sizeof(int)) + && !memcmp (&chmixer.blue, &other.chmixer.blue, 3*sizeof(int)) + && hlrecovery.enabled == other.hlrecovery.enabled + && hlrecovery.method == other.hlrecovery.method + && resize.scale == other.resize.scale + && resize.method == other.resize.method + && resize.dataspec == other.resize.dataspec + && resize.width == other.resize.width + && resize.height == other.resize.height + && icm.input == other.icm.input + && icm.gammaOnInput == other.icm.gammaOnInput + && icm.working == other.icm.working + && icm.output == other.icm.output + && exif==other.exif + && iptc==other.iptc; +} + +bool ProcParams::operator!= (const ProcParams& other) { + + return !(*this==other); +} +} +} + diff --git a/rtengine/procparams.h b/rtengine/procparams.h new file mode 100755 index 000000000..307865eb9 --- /dev/null +++ b/rtengine/procparams.h @@ -0,0 +1,346 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _PROCPARAMS_H_ +#define _PROCPARAMS_H_ + +#include +#include + +namespace rtengine { +namespace procparams { + +/** + * Common parameters of the tone curve and the luminance curve + */ +class CurveParams { + + public: + std::vector curve; + double brightness; + int black; + int contrast; + int shcompr; + int hlcompr; +}; + +/** + * Additional parameters of the tone curve (auto exposure related parameters) + */ +class ToneCurveParams : public CurveParams { + + public: + bool autoexp; + double clip; + double expcomp; +}; + +/** + * Parameters of the sharpening + */ +class SharpeningParams { + + public: + bool enabled; + double radius; + int amount; + int threshold; + bool edgesonly; + double edges_radius; + int edges_tolerance; + bool halocontrol; + int halocontrol_amount; + + Glib::ustring method; + int deconvamount; + double deconvradius; + int deconviter; + int deconvdamping; +}; + +/** + * Parameters of the color boost + */ +class ColorBoostParams { + + public: + int amount; + bool avoidclip; + bool enable_saturationlimiter; + double saturationlimit; +}; + +/** + * Parameters of the white balance adjustments + */ +class WBParams { + + public: + Glib::ustring method; + int temperature; + double green; +}; + +/** + * Parameters of the color shift + */ +class ColorShiftParams { + + public: + double a; + double b; +}; + +/** + * Parameters of the luminance denoising + */ +class LumaDenoiseParams { + + public: + bool enabled; + double radius; + int edgetolerance; +}; + +/** + * Parameters of the color denoising + */ +class ColorDenoiseParams { + + public: + bool enabled; + double radius; + int edgetolerance; + bool edgesensitive; + int amount; +}; + +/** + * Parameters of the shadow/highlight enhancement + */ +class SHParams { + + public: + bool enabled; + bool hq; + int highlights; + int htonalwidth; + int shadows; + int stonalwidth; + int localcontrast; + int radius; +}; + +/** + * Parameters of the cropping + */ +class CropParams { + + public: + bool enabled; + int x; + int y; + int w; + int h; + bool fixratio; + Glib::ustring ratio; + Glib::ustring orientation; + Glib::ustring guide; +}; + +/** + * Parameters of the coarse transformations like 90 deg rotations and h/v flipping + */ +class CoarseTransformParams { + + public: + int rotate; + bool hflip; + bool vflip; +}; + +/** + * Parameters of the rotation + */ +class RotateParams { + + public: + double degree; + bool fill; +}; + +/** + * Parameters of the distortion correction + */ +class DistortionParams { + + public: + double amount; +}; + +/** + * Parameters of the vignetting correction + */ +class VignettingParams { + + public: + int amount; + int radius; +}; + +/** + * Parameters of the color mixer + */ +class ChannelMixerParams { + + public: + int red[3]; + int green[3]; + int blue[3]; +}; + +/** + * Parameters of the c/a correction + */ +class CACorrParams { + + public: + double red; + double blue; +}; + +/** + * Parameters of the highlight recovery + */ +class HRecParams { + + public: + bool enabled; + Glib::ustring method; +}; + +/** + * Parameters of the resizing + */ +class ResizeParams { + + public: + bool enabled; + double scale; + Glib::ustring method; + int dataspec; + int width; + int height; +}; + +/** + * Parameters of the color spaces used during the processing + */ +class ColorManagementParams { + + public: + Glib::ustring input; + bool gammaOnInput; + Glib::ustring working; + Glib::ustring output; +}; + +/** + * A class representing a key/value for the exif metadata information + */ +class ExifPair { + + public: + Glib::ustring field; + Glib::ustring value; +}; + +/** + * The IPTC key/value pairs + */ +class IPTCPair { + + public: + Glib::ustring field; + std::vector values; +}; + +/** + * This class holds all the processing parameters applied on the images + */ +class ProcParams { + + public: + ToneCurveParams toneCurve; ///< Tone curve parameters + CurveParams lumaCurve; ///< CIELAB luminance curve parameters + SharpeningParams sharpening; ///< Sharpening parameters + ColorBoostParams colorBoost; ///< Color boost parameters + WBParams wb; ///< White balance parameters + ColorShiftParams colorShift; ///< Color shift parameters + LumaDenoiseParams lumaDenoise; ///< Luminance denoising parameters + ColorDenoiseParams colorDenoise; ///< Color denoising parameters + SHParams sh; ///< Shadow/highlight enhancement parameters + CropParams crop; ///< Crop parameters + CoarseTransformParams coarse; ///< Coarse transformation (90, 180, 270 deg rotation, h/v flipping) parameters + RotateParams rotate; ///< Rotation parameters + DistortionParams distortion; ///< Lens distortion correction parameters + CACorrParams cacorrection; ///< Lens c/a correction parameters + VignettingParams vignetting; ///< Lens vignetting correction parameters + ChannelMixerParams chmixer; ///< Channel mixer parameters + HRecParams hlrecovery; ///< Highlight recovery parameters + ResizeParams resize; ///< Resize parameters + ColorManagementParams icm; ///< profiles/color spaces used during the image processing + std::vector exif; ///< List of modifications appplied on the exif tags of the input image + std::vector iptc; ///< The IPTC tags and values to be saved to the output image + int version; ///< Version of the file from which the parameters have been read + + /** + * The constructor only sets the hand-wired defaults. + */ + ProcParams (); + /** + * Sets the hand-wired defaults parameters. + */ + void setDefaults (); + /** + * Saves the parameters to a file. + * @param fname the name of the file + * @return Error code (=0 if no error) + */ + int save (Glib::ustring fname) const; + /** + * Loads the parameters from a file. + * @param fname the name of the file + * @return Error code (=0 if no error) + */ + int load (Glib::ustring fname); + + /** Creates a new instance of ProcParams. + * @return a pointer to the new ProcParams instance. */ + static ProcParams* create (); + + /** Destroys an instance of ProcParams. + * @param pp a pointer to the ProcParams instance to destroy. */ + static void destroy (ProcParams* pp); + + bool operator== (const ProcParams& other); + bool operator!= (const ProcParams& other); +}; +} +} +#endif diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc new file mode 100755 index 000000000..2c6929401 --- /dev/null +++ b/rtengine/rawimagesource.cc @@ -0,0 +1,2377 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include +#include +#include +#include +#include +#include + +namespace rtengine { + +int loadRaw (const char* fname, struct RawImage* ri); + +extern const Settings* settings; + +#undef ABS +#undef MAX +#undef MIN +#undef DIST +#undef MAXVAL +#undef CLIP +#undef THREAD_PRIORITY_NORMAL + +#define ABS(a) ((a)<0?-(a):(a)) +#define MAX(a,b) ((a)<(b)?(b):(a)) +#define MIN(a,b) ((a)>(b)?(b):(a)) +#define DIST(a,b) (ABS(a-b)) +#define MAXVAL 0xffff +#define CLIP(a) ((a)>0?((a)allocation) + free (ri->allocation); + if (ri->data) + free (ri->data); + if (ri->profile_data) + free (ri->profile_data); + delete ri; + } + if (green) + freeArray(green, H); + delete [] cache; + if (hrmap[0]!=NULL) { + int dh = H/HR_SCALE; + freeArray(hrmap[0], dh); + freeArray(hrmap[1], dh); + freeArray(hrmap[2], dh); + } + if (needhr) + freeArray(needhr, H); + if (hpmap) + freeArray(hpmap, H); + if (camProfile) + cmsCloseProfile (camProfile); + if (embProfile) + cmsCloseProfile (embProfile); +} + +void RawImageSource::transformRect (PreviewProps pp, int tran, int &ssx1, int &ssy1, int &width, int &height, int &fw) { + + pp.x += border; + pp.y += border; + + if (d1x) { + if ((tran & TR_ROT) == TR_R90 || (tran & TR_ROT) == TR_R270) { + pp.x /= 2; + pp.w = pp.w/2+1; + } + else { + pp.y /= 2; + pp.h = pp.h/2+1; + } + } + + int w = W, h = H; + if (fuji) { + w = ri->fuji_width * 2 + 1; + h = (H - ri->fuji_width)*2 + 1; + } + + int sw = w, sh = h; + if ((tran & TR_ROT) == TR_R90 || (tran & TR_ROT) == TR_R270) { + sw = h; + sh = w; + } + int ppx = pp.x, ppy = pp.y; + if (tran & TR_HFLIP) + ppx = sw - pp.x - pp.w; + if (tran & TR_VFLIP) + ppy = sh - pp.y - pp.h; + + int sx1 = ppx; + int sy1 = ppy; + int sx2 = ppx + pp.w; + int sy2 = ppy + pp.h; + + if ((tran & TR_ROT) == TR_R180) { + sx1 = w - ppx - pp.w; + sy1 = h - ppy - pp.h; + sx2 = sx1 + pp.w; + sy2 = sy1 + pp.h; + } + else if ((tran & TR_ROT) == TR_R90) { + sx1 = ppy; + sy1 = h - ppx - pp.w; + sx2 = sx1 + pp.h; + sy2 = sy1 + pp.w; + } + else if ((tran & TR_ROT) == TR_R270) { + sx1 = w - ppy - pp.h; + sy1 = ppx; + sx2 = sx1 + pp.h; + sy2 = sy1 + pp.w; + } + + if (fuji) { + // atszamoljuk a koordinatakat fuji-ra: + ssx1 = (sx1+sy1) / 2; + ssy1 = (sy1 - sx2 ) / 2 + ri->fuji_width; + int ssx2 = (sx2+sy2) / 2 + 1; + int ssy2 = (sy2 - sx1) / 2 + ri->fuji_width; + fw = (sx2 - sx1) / 2 / pp.skip; + width = (ssx2 - ssx1) / pp.skip + ((ssx2 - ssx1) % pp.skip > 0); + height = (ssy2 - ssy1) / pp.skip + ((ssy2 - ssy1) % pp.skip > 0); + } + else { + ssx1 = sx1; + ssy1 = sy1; + width = (sx2 - sx1) / pp.skip + ((sx2 - sx1) % pp.skip > 0); + height = (sy2 - sy1) / pp.skip + ((sy2 - sy1) % pp.skip > 0); + } +} + +void RawImageSource::getImage (ColorTemp ctemp, int tran, Image16* image, PreviewProps pp, HRecParams hrp, ColorManagementParams cmp) { + + isrcMutex.lock (); + + tran = defTransform (tran); + + // compute channel multipliers + double r, g, b, rm, gm, bm; + ctemp.getMultipliers (r, g, b); + rm = icoeff[0][0]*r + icoeff[0][1]*g + icoeff[0][2]*b; + gm = icoeff[1][0]*r + icoeff[1][1]*g + icoeff[1][2]*b; + bm = icoeff[2][0]*r + icoeff[2][1]*g + icoeff[2][2]*b; + rm = ri->camwb_red / rm; + gm = ri->camwb_green / gm; + bm = ri->camwb_blue / bm; + double mul_lum = 0.299*rm + 0.587*gm + 0.114*bm; + rm /= mul_lum; + gm /= mul_lum; + bm /= mul_lum; + + if (hrp.enabled) + defGain = log(ri->defgain) / log(2.0); + else { + defGain = 0.0; + rm *= ri->defgain; + gm *= ri->defgain; + bm *= ri->defgain; + } + + if (hrp.enabled==true && hrp.method=="Color" && hrmap[0]==NULL) + updateHLRecoveryMap_ColorPropagation (); + + // compute image area to render in order to provide the requested part of the image + int sx1, sy1, imwidth, imheight, fw; + transformRect (pp, tran, sx1, sy1, imwidth, imheight, fw); + + // check possible overflows + int maximwidth, maximheight; + if ((tran & TR_ROT) == TR_R90 || (tran & TR_ROT) == TR_R270) { + maximwidth = image->height; + maximheight = image->width; + } + else { + maximwidth = image->width; + maximheight = image->height; + } + if (d1x) + maximheight /= 2; + + // correct if overflow (very rare), but not fuji because it is corrected in transline + if (!fuji && imwidth>maximwidth) + imwidth = maximwidth; + if (!fuji && imheight>maximheight) + imheight = maximheight; + + // render the requested image part + unsigned short* red = new unsigned short[imwidth]; + unsigned short* grn = new unsigned short[imwidth]; + unsigned short* blue = new unsigned short[imwidth]; + + for (int i=sy1,ix=0; ixfilters) { + if (i==0) + interpolate_row_rb_mul_pp (red, blue, NULL, green[i], green[i+1], i, rm, gm, bm, sx1, imwidth, pp.skip); + else if (i==H-1) + interpolate_row_rb_mul_pp (red, blue, green[i-1], green[i], NULL, i, rm, gm, bm, sx1, imwidth, pp.skip); + else + interpolate_row_rb_mul_pp (red, blue, green[i-1], green[i], green[i+1], i, rm, gm, bm, sx1, imwidth, pp.skip); + + for (int j=0,jx=sx1; jdata[i][jx*3+0]); + grn[j] = CLIP(gm*ri->data[i][jx*3+1]); + blue[j] = CLIP(bm*ri->data[i][jx*3+2]); + } + } + + if (hrp.enabled) + hlRecovery (hrp.method, red, grn, blue, i, sx1, imwidth, pp.skip); + + transLine (red, grn, blue, ix, image, tran, imwidth, imheight, fw); + } + + delete [] red; + delete [] grn; + delete [] blue; + + if (fuji) { + int a = ((tran & TR_ROT) == TR_R90 && image->width%2==0) || ((tran & TR_ROT) == TR_R180 && image->height%2+image->width%2==1) || ((tran & TR_ROT) == TR_R270 && image->height%2==0); + // first row + for (int j=1+a; jwidth-1; j+=2) { + image->r[0][j] = (image->r[1][j] + image->r[0][j+1] + image->r[0][j-1]) / 3; + image->g[0][j] = (image->g[1][j] + image->g[0][j+1] + image->g[0][j-1]) / 3; + image->b[0][j] = (image->b[1][j] + image->b[0][j+1] + image->b[0][j-1]) / 3; + } + // other rows + for (int i=1; iheight-1; i++) { + for (int j=2-(a+i+1)%2; jwidth-1; j+=2) { + // edge-adaptive interpolation + double dh = (ABS(image->r[i][j+1] - image->r[i][j-1]) + ABS(image->g[i][j+1] - image->g[i][j-1]) + ABS(image->b[i][j+1] - image->b[i][j-1])) / 1.0; + double dv = (ABS(image->r[i+1][j] - image->r[i-1][j]) + ABS(image->g[i+1][j] - image->g[i-1][j]) + ABS(image->b[i+1][j] - image->b[i-1][j])) / 1.0; + double eh = 1.0 / (1.0 + dh); + double ev = 1.0 / (1.0 + dv); + image->r[i][j] = (eh * (image->r[i][j+1] + image->r[i][j-1]) + ev * (image->r[i+1][j] + image->r[i-1][j])) / (2.0 * (eh + ev)); + image->g[i][j] = (eh * (image->g[i][j+1] + image->g[i][j-1]) + ev * (image->g[i+1][j] + image->g[i-1][j])) / (2.0 * (eh + ev)); + image->b[i][j] = (eh * (image->b[i][j+1] + image->b[i][j-1]) + ev * (image->b[i+1][j] + image->b[i-1][j])) / (2.0 * (eh + ev)); + } + // first pixel + if (2-(a+i+1)%2==2) { + image->r[i][0] = (image->r[i+1][0] + image->r[i-1][0] + image->r[i][1]) / 3; + image->g[i][0] = (image->g[i+1][0] + image->g[i-1][0] + image->g[i][1]) / 3; + image->b[i][0] = (image->b[i+1][0] + image->b[i-1][0] + image->b[i][1]) / 3; + } + // last pixel + if (2-(a+i+image->width)%2==2) { + image->r[i][image->width-1] = (image->r[i+1][image->width-1] + image->r[i-1][image->width-1] + image->r[i][image->width-2]) / 3; + image->g[i][image->width-1] = (image->g[i+1][image->width-1] + image->g[i-1][image->width-1] + image->g[i][image->width-2]) / 3; + image->b[i][image->width-1] = (image->b[i+1][image->width-1] + image->b[i-1][image->width-1] + image->b[i][image->width-2]) / 3; + } + } + // last row + int b = (a==1 && image->height%2) || (a==0 && image->height%2==0); + for (int j=1+b; jwidth-1; j+=2) { + image->r[image->height-1][j] = (image->r[image->height-2][j] + image->r[image->height-1][j+1] + image->r[image->height-1][j-1]) / 3; + image->g[image->height-1][j] = (image->g[image->height-2][j] + image->g[image->height-1][j+1] + image->g[image->height-1][j-1]) / 3; + image->b[image->height-1][j] = (image->b[image->height-2][j] + image->b[image->height-1][j+1] + image->b[image->height-1][j-1]) / 3; + } + } + + // Flip if needed + if (tran & TR_HFLIP) + hflip (image); + if (tran & TR_VFLIP) + vflip (image); + + // Color correction + if (ri->filters && pp.skip==1) + correction_YIQ_LQ (image, settings->colorCorrectionSteps); + + // Applying postmul + colorSpaceConversion (image, cmp, embProfile, camProfile, cam, defGain); + + isrcMutex.unlock (); +} + +void RawImageSource::rotateLine (unsigned short* line, unsigned short** channel, int tran, int i, int w, int h) { + + if ((tran & TR_ROT) == TR_R180) + for (int j=0; j=0 && yheight && y>=0 && xwidth) { + image->r[image->height-1-y][image->width-1-x] = red[j]; + image->g[image->height-1-y][image->width-1-x] = green[j]; + image->b[image->height-1-y][image->width-1-x] = blue[j]; + } + } + } + else if ((tran & TR_ROT) == TR_R270) { + int end = MIN(h+fw-i, w-fw+i); + for (int j=start; j=0 && xheight && y>=0 && ywidth) { + image->r[image->height-1-x][y] = red[j]; + image->g[image->height-1-x][y] = green[j]; + image->b[image->height-1-x][y] = blue[j]; + } + } + } + else if ((tran & TR_ROT) == TR_R90) { + int end = MIN(h+fw-i, w-fw+i); + for (int j=start; j=0 && ywidth && y>=0 && xheight) { + image->r[x][image->width-1-y] = red[j]; + image->g[x][image->width-1-y] = green[j]; + image->b[x][image->width-1-y] = blue[j]; + } + } + } + else { + int end = MIN(h+fw-i, w-fw+i); + for (int j=start; j=0 && yheight && y>=0 && xwidth) { + image->r[y][x] = red[j]; + image->g[y][x] = green[j]; + image->b[y][x] = blue[j]; + } + } + } + } + // Nikon D1X vertical interpolation + coarse rotation + else if (d1x) { + // copy new pixels + if ((tran & TR_ROT) == TR_R180) { + for (int j=0; jr[2*imheight-2-2*i][imwidth-1-j] = red[j]; + image->g[2*imheight-2-2*i][imwidth-1-j] = green[j]; + image->b[2*imheight-2-2*i][imwidth-1-j] = blue[j]; + } + + if (i==1 || i==2) { // linear interpolation + int row = 2*imheight-1-2*i; + for (int j=0; jr[row][col] = (red[j] + image->r[row+1][col]) >> 1; + image->g[row][col] = (green[j] + image->g[row+1][col]) >> 1; + image->b[row][col] = (blue[j] + image->b[row+1][col]) >> 1; + } + } + else if (i==imheight-1) { + int row = 2*imheight-1-2*i; + for (int j=0; jr[row][col] = (red[j] + image->r[row+1][col]) >> 1; + image->g[row][col] = (green[j] + image->g[row+1][col]) >> 1; + image->b[row][col] = (blue[j] + image->b[row+1][col]) >> 1; + } + row = 2*imheight-1-2*i+2; + for (int j=0; jr[row][col] = (red[j] + image->r[row+1][col]) >> 1; + image->g[row][col] = (green[j] + image->g[row+1][col]) >> 1; + image->b[row][col] = (blue[j] + image->b[row+1][col]) >> 1; + } + } + else if (i>2 && ir[row][col] = CLIP((int)(-0.0625*red[j] + 0.5625*image->r[row-1][col] + 0.5625*image->r[row+1][col] - 0.0625*image->r[row+3][col])); + image->g[row][col] = CLIP((int)(-0.0625*green[j] + 0.5625*image->g[row-1][col] + 0.5625*image->g[row+1][col] - 0.0625*image->g[row+3][col])); + image->b[row][col] = CLIP((int)(-0.0625*blue[j] + 0.5625*image->b[row-1][col] + 0.5625*image->b[row+1][col] - 0.0625*image->b[row+3][col])); + } + } + } + else if ((tran & TR_ROT) == TR_R90) { + for (int j=0; jr[j][2*imheight-2-2*i] = red[j]; + image->g[j][2*imheight-2-2*i] = green[j]; + image->b[j][2*imheight-2-2*i] = blue[j]; + } + if (i==1 || i==2) { // linear interpolation + int col = 2*imheight-1-2*i; + for (int j=0; jr[j][col] = (red[j] + image->r[j][col+1]) >> 1; + image->g[j][col] = (green[j] + image->g[j][col+1]) >> 1; + image->b[j][col] = (blue[j] + image->b[j][col+1]) >> 1; + } + } + else if (i==imheight-1) { + int col = 2*imheight-1-2*i; + for (int j=0; jr[j][col] = (red[j] + image->r[j][col+1]) >> 1; + image->g[j][col] = (green[j] + image->g[j][col+1]) >> 1; + image->b[j][col] = (blue[j] + image->b[j][col+1]) >> 1; + } + col = 2*imheight-1-2*i+2; + for (int j=0; jr[j][col] = (red[j] + image->r[j][col+1]) >> 1; + image->g[j][col] = (green[j] + image->g[j][col+1]) >> 1; + image->b[j][col] = (blue[j] + image->b[j][col+1]) >> 1; + } + } + else if (i>2 && ir[j][col] = CLIP((int)(-0.0625*red[j] + 0.5625*image->r[j][col-1] + 0.5625*image->r[j][col+1] - 0.0625*image->r[j][col+3])); + image->g[j][col] = CLIP((int)(-0.0625*green[j] + 0.5625*image->g[j][col-1] + 0.5625*image->g[j][col+1] - 0.0625*image->g[j][col+3])); + image->b[j][col] = CLIP((int)(-0.0625*blue[j] + 0.5625*image->b[j][col-1] + 0.5625*image->b[j][col+1] - 0.0625*image->b[j][col+3])); + } + } + } + else if ((tran & TR_ROT) == TR_R270) { + for (int j=0; jr[imwidth-1-j][2*i] = red[j]; + image->g[imwidth-1-j][2*i] = green[j]; + image->b[imwidth-1-j][2*i] = blue[j]; + } + if (i==1 || i==2) { // linear interpolation + for (int j=0; jr[row][2*i-1] = (red[j] + image->r[row][2*i-2]) >> 1; + image->g[row][2*i-1] = (green[j] + image->g[row][2*i-2]) >> 1; + image->b[row][2*i-1] = (blue[j] + image->b[row][2*i-2]) >> 1; + } + } + else if (i==imheight-1) { + for (int j=0; jr[row][2*i-1] = (red[j] + image->r[row][2*i-2]) >> 1; + image->g[row][2*i-1] = (green[j] + image->g[row][2*i-2]) >> 1; + image->b[row][2*i-1] = (blue[j] + image->b[row][2*i-2]) >> 1; + image->r[row][2*i-3] = (image->r[row][2*i-2] + image->r[row][2*i-4]) >> 1; + image->g[row][2*i-3] = (image->g[row][2*i-2] + image->g[row][2*i-4]) >> 1; + image->b[row][2*i-3] = (image->b[row][2*i-2] + image->b[row][2*i-4]) >> 1; + } + } + else if (i>0 && ir[row][2*i-3] = CLIP((int)(-0.0625*red[j] + 0.5625*image->r[row][2*i-2] + 0.5625*image->r[row][2*i-4] - 0.0625*image->r[row][2*i-6])); + image->g[row][2*i-3] = CLIP((int)(-0.0625*green[j] + 0.5625*image->g[row][2*i-2] + 0.5625*image->g[row][2*i-4] - 0.0625*image->g[row][2*i-6])); + image->b[row][2*i-3] = CLIP((int)(-0.0625*blue[j] + 0.5625*image->b[row][2*i-2] + 0.5625*image->b[row][2*i-4] - 0.0625*image->b[row][2*i-6])); + } + } + } + else { + rotateLine (red, image->r, tran, 2*i, imwidth, imheight); + rotateLine (green, image->g, tran, 2*i, imwidth, imheight); + rotateLine (blue, image->b, tran, 2*i, imwidth, imheight); + + if (i==1 || i==2) { // linear interpolation + for (int j=0; jr[2*i-1][j] = (red[j] + image->r[2*i-2][j]) >> 1; + image->g[2*i-1][j] = (green[j] + image->g[2*i-2][j]) >> 1; + image->b[2*i-1][j] = (blue[j] + image->b[2*i-2][j]) >> 1; + } + } + else if (i==imheight-1) { + for (int j=0; jr[2*i-3][j] = (image->r[2*i-4][j] + image->r[2*i-2][j]) >> 1; + image->g[2*i-3][j] = (image->g[2*i-4][j] + image->g[2*i-2][j]) >> 1; + image->b[2*i-3][j] = (image->b[2*i-4][j] + image->b[2*i-2][j]) >> 1; + image->r[2*i-1][j] = (red[j] + image->r[2*i-2][j]) >> 1; + image->g[2*i-1][j] = (green[j] + image->g[2*i-2][j]) >> 1; + image->b[2*i-1][j] = (blue[j] + image->b[2*i-2][j]) >> 1; + } + } + else if (i>2 && ir[2*i-3][j] = CLIP((int)(-0.0625*red[j] + 0.5625*image->r[2*i-2][j] + 0.5625*image->r[2*i-4][j] - 0.0625*image->r[2*i-6][j])); + image->g[2*i-3][j] = CLIP((int)(-0.0625*green[j] + 0.5625*image->g[2*i-2][j] + 0.5625*image->g[2*i-4][j] - 0.0625*image->g[2*i-6][j])); + image->b[2*i-3][j] = CLIP((int)(-0.0625*blue[j] + 0.5625*image->b[2*i-2][j] + 0.5625*image->b[2*i-4][j] - 0.0625*image->b[2*i-6][j])); + } + } + } + } + // other (conventional) CCD coarse rotation + else { + rotateLine (red, image->r, tran, i, imwidth, imheight); + rotateLine (green, image->g, tran, i, imwidth, imheight); + rotateLine (blue, image->b, tran, i, imwidth, imheight); + } +} + +void RawImageSource::getFullSize (int& w, int& h, int tr) { + + tr = defTransform (tr); + + if (fuji) { + w = ri->fuji_width * 2 + 1; + h = (H - ri->fuji_width)*2 + 1; + } + else if (d1x) { + w = W; + h = 2*H-1; + } + else { + w = W; + h = H; + } + + if ((tr & TR_ROT) == TR_R90 || (tr & TR_ROT) == TR_R270) { + int tmp = w; + w = h; + h = tmp; + } + w -= 2 * border; + h -= 2 * border; +} + +void RawImageSource::getSize (int tran, PreviewProps pp, int& w, int& h) { + + tran = defTransform (tran); + +// if (fuji) { +// return; +// } +// else if (d1x) { +// return; +// } +// else { + w = pp.w / pp.skip + (pp.w % pp.skip > 0); + h = pp.h / pp.skip + (pp.h % pp.skip > 0); +// } +} + +void RawImageSource::hflip (Image16* image) { + int width = image->width; + int height = image->height; + + unsigned short* rowr = new unsigned short[width]; + unsigned short* rowg = new unsigned short[width]; + unsigned short* rowb = new unsigned short[width]; + for (int i=0; ir[i][width-1-j]; + rowg[j] = image->g[i][width-1-j]; + rowb[j] = image->b[i][width-1-j]; + } + memcpy (image->r[i], rowr, width*sizeof(unsigned short)); + memcpy (image->g[i], rowg, width*sizeof(unsigned short)); + memcpy (image->b[i], rowb, width*sizeof(unsigned short)); + } + delete [] rowr; + delete [] rowg; + delete [] rowb; +} + +void RawImageSource::vflip (Image16* image) { + int width = image->width; + int height = image->height; + + register unsigned short tmp; + for (int i=0; ir[i][j]; + image->r[i][j] = image->r[height-1-i][j]; + image->r[height-1-i][j] = tmp; + tmp = image->g[i][j]; + image->g[i][j] = image->g[height-1-i][j]; + image->g[height-1-i][j] = tmp; + tmp = image->b[i][j]; + image->b[i][j] = image->b[height-1-i][j]; + image->b[height-1-i][j] = tmp; + } +} + +void RawImageSource::inverse33 (double (*coeff)[3], double (*icoeff)[3]) { + double nom = coeff[0][2]*coeff[1][1]*coeff[2][0] - coeff[0][1]*coeff[1][2]*coeff[2][0] - coeff[0][2]*coeff[1][0]*coeff[2][1] + coeff[0][0]*coeff[1][2]*coeff[2][1] + coeff[0][1]*coeff[1][0]*coeff[2][2] - coeff[0][0]*coeff[1][1]*coeff[2][2]; + icoeff[0][0] = (coeff[1][2]*coeff[2][1]-coeff[1][1]*coeff[2][2]) / nom; + icoeff[0][1] = -(coeff[0][2]*coeff[2][1]-coeff[0][1]*coeff[2][2]) / nom; + icoeff[0][2] = (coeff[0][2]*coeff[1][1]-coeff[0][1]*coeff[1][2]) / nom; + icoeff[1][0] = -(coeff[1][2]*coeff[2][0]-coeff[1][0]*coeff[2][2]) / nom; + icoeff[1][1] = (coeff[0][2]*coeff[2][0]-coeff[0][0]*coeff[2][2]) / nom; + icoeff[1][2] = -(coeff[0][2]*coeff[1][0]-coeff[0][0]*coeff[1][2]) / nom; + icoeff[2][0] = (coeff[1][1]*coeff[2][0]-coeff[1][0]*coeff[2][1]) / nom; + icoeff[2][1] = -(coeff[0][1]*coeff[2][0]-coeff[0][0]*coeff[2][1]) / nom; + icoeff[2][2] = (coeff[0][1]*coeff[1][0]-coeff[0][0]*coeff[1][1]) / nom; +} + +int RawImageSource::load (Glib::ustring fname) { + + fileName = fname; + + if (plistener) { + plistener->setProgressStr ("Decoding..."); + plistener->setProgress (0.0); + } + + ri = new RawImage; + int res = loadRaw (fname.c_str(), ri); + if (res) + return res; + + W = ri->width; + H = ri->height; + + d1x = !strcmp(ri->model, "D1X"); + fuji = ri->fuji_width; + if (d1x) + border = 8; + + for (int i=0; i<3; i++) + for (int j=0; j<3; j++) + coeff[i][j] = ri->coeff[i][j]; + + // compute inverse of the color transformation matrix + inverse33 (coeff, icoeff); + + double cam_r = coeff[0][0]*ri->camwb_red + coeff[0][1]*ri->camwb_green + coeff[0][2]*ri->camwb_blue; + double cam_g = coeff[1][0]*ri->camwb_red + coeff[1][1]*ri->camwb_green + coeff[1][2]*ri->camwb_blue; + double cam_b = coeff[2][0]*ri->camwb_red + coeff[2][1]*ri->camwb_green + coeff[2][2]*ri->camwb_blue; + + wb = ColorTemp (cam_r, cam_g, cam_b); + + double tr = icoeff[0][0] * cam_r + icoeff[0][1] * cam_g + icoeff[0][2] * cam_b; + double tg = icoeff[1][0] * cam_r + icoeff[1][1] * cam_g + icoeff[1][2] * cam_b; + double tb = icoeff[2][0] * cam_r + icoeff[2][1] * cam_g + icoeff[2][2] * cam_b; + + // create profile + memset (cam, 0, sizeof(cam)); + for (int i=0; i<3; i++) + for (int j=0; j<3; j++) + for (int k=0; k<3; k++) + cam[i][j] += coeff[k][i] * sRGB_d50[k][j]; + camProfile = iccStore.createFromMatrix (cam, false, "Camera"); + inverse33 (cam, icam); + + if (ri->profile_data) + embProfile = cmsOpenProfileFromMem (ri->profile_data, ri->profile_len); + + defGain = log(ri->defgain) / log(2.0); + + RawMetaDataLocation rml; + rml.exifBase = ri->exifbase; + rml.ciffBase = ri->ciff_base; + rml.ciffLength = ri->ciff_len; + + idata = new ImageData (fname, &rml); + + // check if it is an olympus E camera, if yes, compute G channel pre-compensation factors + if (((idata->getMake().size()>=7 && idata->getMake().substr(0,7)=="OLYMPUS" && idata->getModel()[0]=='E') || (idata->getMake().size()>=9 && idata->getMake().substr(0,7)=="Panasonic")) && settings->demosaicMethod!="vng4" && ri->filters) { + // global correction + int ng1=0, ng2=0; + double avgg1=0, avgg2=0; + for (int i=border; idata[i][j]; + ng1++; + } + else { + avgg2 += ri->data[i][j]; + ng2++; + } + } + double corrg1 = ((double)avgg1/ng1 + (double)avgg2/ng2) / 2.0 / ((double)avgg1/ng1); + double corrg2 = ((double)avgg1/ng1 + (double)avgg2/ng2) / 2.0 / ((double)avgg2/ng2); + for (int i=border; idata[i][j] = CLIP(ri->data[i][j] * (i%2 ? corrg2 : corrg1)); + + // local correction in a 9x9 box +/* unsigned short* corr_alloc = new unsigned short[W*H]; + unsigned short** corr_data = new unsigned short* [H]; + for (int i=0; iallocation, W*H*sizeof(unsigned short)); + for (int i=border; idata[i-4][j-4] + ri->data[i-4][j-2] + ri->data[i-4][j] + ri->data[i-4][j+2] + + ri->data[i-2][j-4] + ri->data[i-2][j-2] + ri->data[i-2][j] + ri->data[i-2][j+2] + + ri->data[i][j-4] + ri->data[i][j-2] + ri->data[i][j] + ri->data[i][j+2] + + ri->data[i+2][j-4] + ri->data[i+2][j-2] + ri->data[i+2][j] + ri->data[i+2][j+2]; + unsigned int ag2 = ri->data[i-3][j-3] + ri->data[i-3][j-1] + ri->data[i-3][j+1] + ri->data[i-3][j+1] + + ri->data[i-1][j-3] + ri->data[i-1][j-1] + ri->data[i-1][j+1] + ri->data[i-1][j+1] + + ri->data[i+1][j-3] + ri->data[i+1][j-1] + ri->data[i+1][j+1] + ri->data[i+1][j+1] + + ri->data[i+3][j-3] + ri->data[i+3][j-1] + ri->data[i+3][j+1] + ri->data[i+3][j+1]; + unsigned int val = (ri->data[i][j] + ri->data[i][j] * ag2 / ag1) / 2; + corr_data[i][j] = CLIP (val); + } + memcpy (ri->allocation, corr_alloc, W*H*sizeof(unsigned short)); + delete corr_alloc; + delete corr_data; +*/ + } + + if (ri->filters) { + // demosaic + if (settings->demosaicMethod=="hphd") + hphd_demosaic (); + else if (settings->demosaicMethod=="vng4") + vng4_demosaic (); + else + eahd_demosaic (); + } + + + if (plistener) { + plistener->setProgressStr ("Ready."); + plistener->setProgress (1.0); + } + + return 0; +} + +int RawImageSource::defTransform (int tran) { + + int deg = ri->rotate_deg; + if ((tran & TR_ROT) == TR_R180) + deg += 180; + else if ((tran & TR_ROT) == TR_R90) + deg += 90; + else if ((tran & TR_ROT) == TR_R270) + deg += 270; + deg %= 360; + + int ret = 0; + if (deg==90) + ret |= TR_R90; + else if (deg==180) + ret |= TR_R180; + else if (deg==270) + ret |= TR_R270; + if (tran & TR_HFLIP) + ret |= TR_HFLIP; + if (tran & TR_VFLIP) + ret |= TR_VFLIP; + return ret; +} + +void RawImageSource::correction_YIQ_LQ_ (Image16* im, int row_from, int row_to) { + + int W = im->width; + + int** rbconv_Y = new int*[3]; + int** rbconv_I = new int*[3]; + int** rbconv_Q = new int*[3]; + int** rbout_I = new int*[3]; + int** rbout_Q = new int*[3]; + for (int i=0; i<3; i++) { + rbconv_Y[i] = new int[W]; + rbconv_I[i] = new int[W]; + rbconv_Q[i] = new int[W]; + rbout_I[i] = new int[W]; + rbout_Q[i] = new int[W]; + } + + int* row_I = new int[W]; + int* row_Q = new int[W]; + + int* pre1_I = new int[3]; + int* pre2_I = new int[3]; + int* post1_I = new int[3]; + int* post2_I = new int[3]; + int middle_I[6]; + int* pre1_Q = new int[3]; + int* pre2_Q = new int[3]; + int* post1_Q = new int[3]; + int* post2_Q = new int[3]; + int middle_Q[6]; + int* tmp; + + int ppx=0, px=(row_from-1)%3, cx=row_from%3, nx=0; + + convert_row_to_YIQ (im->r[row_from-1], im->g[row_from-1], im->b[row_from-1], rbconv_Y[px], rbconv_I[px], rbconv_Q[px], W); + convert_row_to_YIQ (im->r[row_from], im->g[row_from], im->b[row_from], rbconv_Y[cx], rbconv_I[cx], rbconv_Q[cx], W); + + for (int j=0; jr[i+1], im->g[i+1], im->b[i+1], rbconv_Y[nx], rbconv_I[nx], rbconv_Q[nx], W); + + SORT3(rbconv_I[px][0],rbconv_I[cx][0],rbconv_I[nx][0],pre1_I[0],pre1_I[1],pre1_I[2]); + SORT3(rbconv_I[px][1],rbconv_I[cx][1],rbconv_I[nx][1],pre2_I[0],pre2_I[1],pre2_I[2]); + SORT3(rbconv_Q[px][0],rbconv_Q[cx][0],rbconv_Q[nx][0],pre1_Q[0],pre1_Q[1],pre1_Q[2]); + SORT3(rbconv_Q[px][1],rbconv_Q[cx][1],rbconv_Q[nx][1],pre2_Q[0],pre2_Q[1],pre2_Q[2]); + + // median I channel + for (int j=1; jrow_from) { + for (int j=1; jr[i-1], im->g[i-1], im->b[i-1], rbconv_Y[px], row_I, row_Q, W); + } + } + // blur last 3 row and finalize H-1th row + for (int j=1; jr[row_to-1], im->g[row_to-1], im->b[row_to-1], rbconv_Y[cx], row_I, row_Q, W); + + freeArray(rbconv_Y, 3); + freeArray(rbconv_I, 3); + freeArray(rbconv_Q, 3); + freeArray(rbout_I, 3); + freeArray(rbout_Q, 3); + delete [] row_I; + delete [] row_Q; + delete [] pre1_I; + delete [] pre2_I; + delete [] post1_I; + delete [] post2_I; + delete [] pre1_Q; + delete [] pre2_Q; + delete [] post1_Q; + delete [] post2_Q; +} + + +void RawImageSource::correction_YIQ_LQ (Image16* im, int times) { + + if (im->height<4) + return; + + MyTime t1, t2; + + t1.set (); + for (int t=0; tdualThreadEnabled) { + Glib::Thread *thread1 = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &RawImageSource::correction_YIQ_LQ_), im, 1, im->height/2), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + Glib::Thread *thread2 = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &RawImageSource::correction_YIQ_LQ_), im, im->height/2, im->height-1), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread1->join (); + thread2->join (); + } + else + correction_YIQ_LQ_ (im, 1, im->height-1); + } + t2.set (); +// printf ("Corrected. (%d)\n", t2.etime(t1)); +} + + + +void RawImageSource::convert_row_to_YIQ (unsigned short* r, unsigned short* g, unsigned short* b, int* Y, int* I, int* Q, int W) { + for (int j=0; j +void RawImageSource::convert_to_cielab_row (unsigned short* ar, unsigned short* ag, unsigned short* ab, short* oL, short* oa, short* ob) { + + for (int j=0; jthreshold) + oL[j] = 300.0*cache[(int)y]; + else + oL[j] = 300.0 * 903.3 * y / CMAXVAL; + + oa[j] = 32.0 * 500.0 * ((x>threshold ? cache[(int)x] : 7.787*x/CMAXVAL+16.0/116.0) - (y>threshold ? cache[(int)y] : 7.787*y/CMAXVAL+16.0/116.0)); + ob[j] = 32.0 * 200.0 * ((y>threshold ? cache[(int)y] : 7.787*y/CMAXVAL+16.0/116.0) - (z>threshold ? cache[(int)z] : 7.787*z/CMAXVAL+16.0/116.0)); + } +} + +void RawImageSource::interpolate_row_g (unsigned short* agh, unsigned short* agv, int i) { + + for (int j=0; jdata[i][j]; + agv[j] = ri->data[i][j]; + } + else { + int gh=0; + int gv=0; + if (j>1 && jdata[i][j-2] + 2*ri->data[i][j-1] + 2*ri->data[i][j] + 2*ri->data[i][j+1] -ri->data[i][j+2]) / 4; + int maxgh = MAX(ri->data[i][j-1], ri->data[i][j+1]); + int mingh = MIN(ri->data[i][j-1], ri->data[i][j+1]); + if (gh>maxgh) + gh = maxgh; + else if (ghdata[i][1]; + else if (j==1) + gh = (ri->data[i][0] + ri->data[i][2]) / 2; + else if (j==W-1) + gh = ri->data[i][W-2]; + else if (j==W-2) + gh = (ri->data[i][W-1] + ri->data[i][W-3]) / 2; + + if (i>1 && idata[i-2][j] + 2*ri->data[i-1][j] + 2*ri->data[i][j] + 2*ri->data[i+1][j] - ri->data[i+2][j]) / 4; + int maxgv = MAX(ri->data[i-1][j], ri->data[i+1][j]); + int mingv = MIN(ri->data[i-1][j], ri->data[i+1][j]); + if (gv>maxgv) + gv = maxgv; + else if (gvdata[1][j]; + else if (i==1) + gv = (ri->data[0][j] + ri->data[2][j]) / 2; + else if (i==H-1) + gv = ri->data[H-2][j]; + else if (i==H-2) + gv = (ri->data[H-1][j] + ri->data[H-3][j]) / 2; + + agh[j] = CLIP(gh); + agv[j] = CLIP(gv); + } + } +} + +void RawImageSource::interpolate_row_rb (unsigned short* ar, unsigned short* ab, unsigned short* pg, unsigned short* cg, unsigned short* ng, int i) { + if (ISRED(ri,i,0) || ISRED(ri,i,1)) { + // RGRGR or GRGRGR line + for (int j=0; jdata[i][j]; + // blue: cross interpolation + int b = 0; + int n = 0; + if (i>0 && j>0) { + b += ri->data[i-1][j-1] - pg[j-1]; + n++; + } + if (i>0 && jdata[i-1][j+1] - pg[j+1]; + n++; + } + if (i0) { + b += ri->data[i+1][j-1] - ng[j-1]; + n++; + } + if (idata[i+1][j+1] - ng[j+1]; + n++; + } + b = cg[j] + b / n; + ab[j] = CLIP(b); + } + else { + // linear R-G interp. horizontally + int r; + if (j==0) + r = cg[0] + ri->data[i][1] - cg[1]; + else if (j==W-1) + r = cg[W-1] + ri->data[i][W-2] - cg[W-2]; + else + r = cg[j] + (ri->data[i][j-1] - cg[j-1] + ri->data[i][j+1] - cg[j+1]) / 2; + ar[j] = CLIP(r); + // linear B-G interp. vertically + int b; + if (i==0) + b = ng[j] + ri->data[1][j] - cg[j]; + else if (i==H-1) + b = pg[j] + ri->data[H-2][j] - cg[j]; + else + b = cg[j] + (ri->data[i-1][j] - pg[j] + ri->data[i+1][j] - ng[j]) / 2; + ab[j] = CLIP(b); + } + } + } + else { + // BGBGB or GBGBGB line + for (int j=0; jdata[i][j]; + // blue: cross interpolation + int r = 0; + int n = 0; + if (i>0 && j>0) { + r += ri->data[i-1][j-1] - pg[j-1]; + n++; + } + if (i>0 && jdata[i-1][j+1] - pg[j+1]; + n++; + } + if (i0) { + r += ri->data[i+1][j-1] - ng[j-1]; + n++; + } + if (idata[i+1][j+1] - ng[j+1]; + n++; + } + r = cg[j] + r / n; + + ar[j] = CLIP(r); + } + else { + // linear B-G interp. horizontally + int b; + if (j==0) + b = cg[0] + ri->data[i][1] - cg[1]; + else if (j==W-1) + b = cg[W-1] + ri->data[i][W-2] - cg[W-2]; + else + b = cg[j] + (ri->data[i][j-1] - cg[j-1] + ri->data[i][j+1] - cg[j+1]) / 2; + ab[j] = CLIP(b); + // linear R-G interp. vertically + int r; + if (i==0) + r = ng[j] + ri->data[1][j] - cg[j]; + else if (i==H-1) + r = pg[j] + ri->data[H-2][j] - cg[j]; + else + r = cg[j] + (ri->data[i-1][j] - pg[j] + ri->data[i+1][j] - ng[j]) / 2; + ar[j] = CLIP(r); + } + } + } +} + +void RawImageSource::interpolate_row_rb_mul_pp (unsigned short* ar, unsigned short* ab, unsigned short* pg, unsigned short* cg, unsigned short* ng, int i, double r_mul, double g_mul, double b_mul, int x1, int width, int skip) { + + if (ISRED(ri,i,0) || ISRED(ri,i,1)) { + // RGRGR or GRGRGR line + for (int j=x1, jx=0; jxdata[i][j]); + // blue: cross interpolation + int b = 0; + int n = 0; + if (i>0 && j>0) { + b += b_mul*ri->data[i-1][j-1] - g_mul*pg[j-1]; + n++; + } + if (i>0 && jdata[i-1][j+1] - g_mul*pg[j+1]; + n++; + } + if (i0) { + b += b_mul*ri->data[i+1][j-1] - g_mul*ng[j-1]; + n++; + } + if (idata[i+1][j+1] - g_mul*ng[j+1]; + n++; + } + b = g_mul*cg[j] + b / n; + ab[jx] = CLIP(b); + } + else { + // linear R-G interp. horizontally + int r; + if (j==0) + r = g_mul*cg[0] + r_mul*ri->data[i][1] - g_mul*cg[1]; + else if (j==W-1) + r = g_mul*cg[W-1] + r_mul*ri->data[i][W-2] - g_mul*cg[W-2]; + else + r = g_mul*cg[j] + (r_mul*ri->data[i][j-1] - g_mul*cg[j-1] + r_mul*ri->data[i][j+1] - g_mul*cg[j+1]) / 2; + ar[jx] = CLIP(r); + // linear B-G interp. vertically + int b; + if (i==0) + b = g_mul*ng[j] + b_mul*ri->data[1][j] - g_mul*cg[j]; + else if (i==H-1) + b = g_mul*pg[j] + b_mul*ri->data[H-2][j] - g_mul*cg[j]; + else + b = g_mul*cg[j] + (b_mul*ri->data[i-1][j] - g_mul*pg[j] + b_mul*ri->data[i+1][j] - g_mul*ng[j]) / 2; + ab[jx] = CLIP(b); + } + } + } + else { + // BGBGB or GBGBGB line + for (int j=x1, jx=0; jxdata[i][j]); + // blue: cross interpolation + int r = 0; + int n = 0; + if (i>0 && j>0) { + r += r_mul*ri->data[i-1][j-1] - g_mul*pg[j-1]; + n++; + } + if (i>0 && jdata[i-1][j+1] - g_mul*pg[j+1]; + n++; + } + if (i0) { + r += r_mul*ri->data[i+1][j-1] - g_mul*ng[j-1]; + n++; + } + if (idata[i+1][j+1] - g_mul*ng[j+1]; + n++; + } + r = g_mul*cg[j] + r / n; + + ar[jx] = CLIP(r); + } + else { + // linear B-G interp. horizontally + int b; + if (j==0) + b = g_mul*cg[0] + b_mul*ri->data[i][1] - g_mul*cg[1]; + else if (j==W-1) + b = g_mul*cg[W-1] + b_mul*ri->data[i][W-2] - g_mul*cg[W-2]; + else + b = g_mul*cg[j] + (b_mul*ri->data[i][j-1] - g_mul*cg[j-1] + b_mul*ri->data[i][j+1] - g_mul*cg[j+1]) / 2; + ab[jx] = CLIP(b); + // linear R-G interp. vertically + int r; + if (i==0) + r = g_mul*ng[j] + r_mul*ri->data[1][j] - g_mul*cg[j]; + else if (i==H-1) + r = g_mul*pg[j] + r_mul*ri->data[H-2][j] - g_mul*cg[j]; + else + r = g_mul*cg[j] + (r_mul*ri->data[i-1][j] - g_mul*pg[j] + r_mul*ri->data[i+1][j] - g_mul*ng[j]) / 2; + ar[jx] = CLIP(r); + } + } + } +} + + +void RawImageSource::colorSpaceConversion (Image16* im, ColorManagementParams cmp, cmsHPROFILE embedded, cmsHPROFILE camprofile, double camMatrix[3][3], double& defgain) { + + if (cmp.input == "(none)") + return; + + MyTime t1, t2, t3; + + t1.set (); + + cmsHPROFILE in; + cmsHPROFILE out; + + Glib::ustring inProfile = cmp.input; + + if (inProfile=="(embedded)") { + if (embedded) + in = embedded; + else + in = camprofile; + } + else if (inProfile=="(camera)" || inProfile=="") + in = camprofile; + else { + in = iccStore.getProfile (inProfile); + if (in==NULL) + inProfile = "(camera)"; + } + + + if (inProfile=="(camera)" || inProfile=="" || (inProfile=="(embedded)" && !embedded)) { + // in this case we avoid using the slllllooooooowwww lcms + +// out = iccStore.workingSpace (wProfile); +// hTransform = cmsCreateTransform (in, TYPE_RGB_16_PLANAR, out, TYPE_RGB_16_PLANAR, settings->colorimetricIntent, cmsFLAGS_MATRIXINPUT | cmsFLAGS_MATRIXOUTPUT);//cmsFLAGS_MATRIXINPUT | cmsFLAGS_MATRIXOUTPUT); +// cmsDoTransform (hTransform, im->data, im->data, im->planestride/2); +// cmsDeleteTransform(hTransform); + TMatrix work = iccStore.workingSpaceInverseMatrix (cmp.working); + double mat[3][3] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; + for (int i=0; i<3; i++) + for (int j=0; j<3; j++) + for (int k=0; k<3; k++) + mat[i][j] += camMatrix[i][k] * work[k][j]; + + for (int i=0; iheight; i++) + for (int j=0; jwidth; j++) { + + int newr = mat[0][0]*im->r[i][j] + mat[1][0]*im->g[i][j] + mat[2][0]*im->b[i][j]; + int newg = mat[0][1]*im->r[i][j] + mat[1][1]*im->g[i][j] + mat[2][1]*im->b[i][j]; + int newb = mat[0][2]*im->r[i][j] + mat[1][2]*im->g[i][j] + mat[2][2]*im->b[i][j]; + + im->r[i][j] = CLIP(newr); + im->g[i][j] = CLIP(newg); + im->b[i][j] = CLIP(newb); + } + } + else { + out = iccStore.workingSpace (cmp.working); +// out = iccStore.workingSpaceGamma (wProfile); + lcmsMutex->lock (); + cmsHTRANSFORM hTransform = cmsCreateTransform (in, TYPE_RGB_16_PLANAR, out, TYPE_RGB_16_PLANAR, settings->colorimetricIntent, 0); + lcmsMutex->unlock (); + if (hTransform) { + if (cmp.gammaOnInput) { + double gd = pow (2.0, defgain); + defgain = 0.0; + for (int i=0; iheight; i++) + for (int j=0; jwidth; j++) { + im->r[i][j] = CurveFactory::gamma (CLIP(defgain*im->r[i][j])); + im->g[i][j] = CurveFactory::gamma (CLIP(defgain*im->g[i][j])); + im->b[i][j] = CurveFactory::gamma (CLIP(defgain*im->b[i][j])); + } + } + cmsDoTransform (hTransform, im->data, im->data, im->planestride/2); + } + else { + lcmsMutex->lock (); + hTransform = cmsCreateTransform (camprofile, TYPE_RGB_16_PLANAR, out, TYPE_RGB_16_PLANAR, settings->colorimetricIntent, 0); + lcmsMutex->unlock (); + cmsDoTransform (hTransform, im->data, im->data, im->planestride/2); + } + cmsDeleteTransform(hTransform); + } + t3.set (); +// printf ("ICM TIME: %d\n", t3.etime(t1)); +} + +void RawImageSource::eahd_demosaic () { + + if (plistener) { + plistener->setProgressStr ("Demosaicing..."); + plistener->setProgress (0.0); + } + + // prepare chache and constants for cielab conversion + lc00 = (0.412453 * coeff[0][0] + 0.357580 * coeff[1][0] + 0.180423 * coeff[2][0]) / 0.950456; + lc01 = (0.412453 * coeff[0][1] + 0.357580 * coeff[1][1] + 0.180423 * coeff[2][1]) / 0.950456; + lc02 = (0.412453 * coeff[0][2] + 0.357580 * coeff[1][2] + 0.180423 * coeff[2][2]) / 0.950456; + + lc10 = 0.212671 * coeff[0][0] + 0.715160 * coeff[1][0] + 0.072169 * coeff[2][0]; + lc11 = 0.212671 * coeff[0][1] + 0.715160 * coeff[1][1] + 0.072169 * coeff[2][1]; + lc12 = 0.212671 * coeff[0][2] + 0.715160 * coeff[1][2] + 0.072169 * coeff[2][2]; + + lc20 = (0.019334 * coeff[0][0] + 0.119193 * coeff[1][0] + 0.950227 * coeff[2][0]) / 1.088754; + lc21 = (0.019334 * coeff[0][1] + 0.119193 * coeff[1][1] + 0.950227 * coeff[2][1]) / 1.088754; + lc22 = (0.019334 * coeff[0][2] + 0.119193 * coeff[1][2] + 0.950227 * coeff[2][2]) / 1.088754; + + int maxindex = 2*65536; + cache = new double[maxindex]; + threshold = (int)(0.008856*CMAXVAL); + for (int i=0; isv) { // fixate horizontal pixel + dLmaph[dmi] = DIST(lLh[ix][j], lLh[idx][j+y]); + dCamaph[dmi] = DIST(lah[ix][j], lah[idx][j+y]); + dCbmaph[dmi] = DIST(lbh[ix][j], lbh[idx][j+y]); + dLmapv[dmi] = DIST(lLv[ix][j], lLh[idx][j+y]); + dCamapv[dmi] = DIST(lav[ix][j], lah[idx][j+y]); + dCbmapv[dmi] = DIST(lbv[ix][j], lbh[idx][j+y]); + } + else if (shdata[i-1][j]; + else { + hc = homh[imx][j]; + vc = homv[imx][j]; + if (hc > vc) + green[i-1][j] = gh[(i-1)%4][j]; + else if (hc < vc) + green[i-1][j] = gv[(i-1)%4][j]; + else + green[i-1][j] = (gh[(i-1)%4][j] + gv[(i-1)%4][j]) / 2; + } + } + + if (!(i%20) && plistener) + plistener->setProgress ((double)i / (H-2)); + } + // finish H-2th and H-1th row, homogenity value is still valailable + int hc, vc; + for (int i=H-1; i vc) + green[i-1][j] = gh[(i-1)%4][j]; + else if (hc < vc) + green[i-1][j] = gv[(i-1)%4][j]; + else + green[i-1][j] = (gh[(i-1)%4][j] + gv[(i-1)%4][j]) / 2; + } + + freeArray2(rh, 3); + freeArray2(gh, 4); + freeArray2(bh, 3); + freeArray2(rv, 3); + freeArray2(gv, 4); + freeArray2(bv, 3); + freeArray2(lLh, 3); + freeArray2(lah, 3); + freeArray2(lbh, 3); + freeArray2(homh, 3); + freeArray2(lLv, 3); + freeArray2(lav, 3); + freeArray2(lbv, 3); + freeArray2(homv, 3); +} + +void RawImageSource::hphd_vertical (float** hpmap, int col_from, int col_to) { + + float* temp = new float[MAX(W,H)]; + float* avg = new float[MAX(W,H)]; + float* dev = new float[MAX(W,H)]; + + memset (temp, 0, MAX(W,H)*sizeof(float)); + memset (avg, 0, MAX(W,H)*sizeof(float)); + memset (dev, 0, MAX(W,H)*sizeof(float)); + + for (int k=col_from; kdata[i-5][k] - 8*ri->data[i-4][k] + 27*ri->data[i-3][k] - 48*ri->data[i-2][k] + 42*ri->data[i-1][k] - + (ri->data[i+5][k] - 8*ri->data[i+4][k] + 27*ri->data[i+3][k] - 48*ri->data[i+2][k] + 42*ri->data[i+1][k])) / 100.0; + temp[i] = ABS(temp[i]); + } + for (int j=4; jdata[i][j-5] - 8*ri->data[i][j-4] + 27*ri->data[i][j-3] - 48*ri->data[i][j-2] + 42*ri->data[i][j-1] - + (ri->data[i][j+5] - 8*ri->data[i][j+4] + 27*ri->data[i][j+3] - 48*ri->data[i][j+2] + 42*ri->data[i][j+1])) / 100; + temp[j] = ABS(temp[j]); + } + for (int j=4; jhpmap[i][j] = 2; + else if (hpv < 0.8*hpmap[i][j]) + this->hpmap[i][j] = 1; + else + this->hpmap[i][j] = 0; + } + } + delete [] temp; + delete [] avg; + delete [] dev; +} + +void RawImageSource::hphd_green (int row_from, int row_to) { + + for (int i=row_from; idata[i][j]; + else { + if (this->hpmap[i][j]==1) { + int g2 = ri->data[i][j+1] + ((ri->data[i][j] - ri->data[i][j+2]) >> 1); + int g4 = ri->data[i][j-1] + ((ri->data[i][j] - ri->data[i][j-2]) >> 1); + + int dx = ri->data[i][j+1] - ri->data[i][j-1]; + int d1 = ri->data[i][j+3] - ri->data[i][j+1]; + int d2 = ri->data[i][j+2] - ri->data[i][j]; + int d3 = (ri->data[i-1][j+2] - ri->data[i-1][j]) >> 1; + int d4 = (ri->data[i+1][j+2] - ri->data[i+1][j]) >> 1; + + double e2 = 1.0 / (1.0 + ABS(dx) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4)); + + d1 = ri->data[i][j-3] - ri->data[i][j-1]; + d2 = ri->data[i][j-2] - ri->data[i][j]; + d3 = (ri->data[i-1][j-2] - ri->data[i-1][j]) >> 1; + d4 = (ri->data[i+1][j-2] - ri->data[i+1][j]) >> 1; + + double e4 = 1.0 / (1.0 + ABS(dx) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4)); + + green[i][j] = CLIP((e2 * g2 + e4 * g4) / (e2 + e4)); + } + else if (this->hpmap[i][j]==2) { + int g1 = ri->data[i-1][j] + ((ri->data[i][j] - ri->data[i-2][j]) >> 1); + int g3 = ri->data[i+1][j] + ((ri->data[i][j] - ri->data[i+2][j]) >> 1); + + int dy = ri->data[i+1][j] - ri->data[i-1][j]; + int d1 = ri->data[i-1][j] - ri->data[i-3][j]; + int d2 = ri->data[i][j] - ri->data[i-2][j]; + int d3 = (ri->data[i][j-1] - ri->data[i-2][j-1]) >> 1; + int d4 = (ri->data[i][j+1] - ri->data[i-2][j+1]) >> 1; + + double e1 = 1.0 / (1.0 + ABS(dy) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4)); + + d1 = ri->data[i+1][j] - ri->data[i+3][j]; + d2 = ri->data[i][j] - ri->data[i+2][j]; + d3 = (ri->data[i][j-1] - ri->data[i+2][j-1]) >> 1; + d4 = (ri->data[i][j+1] - ri->data[i+2][j+1]) >> 1; + + double e3 = 1.0 / (1.0 + ABS(dy) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4)); + + green[i][j] = CLIP((e1 * g1 + e3 * g3) / (e1 + e3)); + } + else { + int g1 = ri->data[i-1][j] + ((ri->data[i][j] - ri->data[i-2][j]) >> 1); + int g2 = ri->data[i][j+1] + ((ri->data[i][j] - ri->data[i][j+2]) >> 1); + int g3 = ri->data[i+1][j] + ((ri->data[i][j] - ri->data[i+2][j]) >> 1); + int g4 = ri->data[i][j-1] + ((ri->data[i][j] - ri->data[i][j-2]) >> 1); + + int dx = ri->data[i][j+1] - ri->data[i][j-1]; + int dy = ri->data[i+1][j] - ri->data[i-1][j]; + + int d1 = ri->data[i-1][j] - ri->data[i-3][j]; + int d2 = ri->data[i][j] - ri->data[i-2][j]; + int d3 = (ri->data[i][j-1] - ri->data[i-2][j-1]) >> 1; + int d4 = (ri->data[i][j+1] - ri->data[i-2][j+1]) >> 1; + + double e1 = 1.0 / (1.0 + ABS(dy) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4)); + + d1 = ri->data[i][j+3] - ri->data[i][j+1]; + d2 = ri->data[i][j+2] - ri->data[i][j]; + d3 = (ri->data[i-1][j+2] - ri->data[i-1][j]) >> 1; + d4 = (ri->data[i+1][j+2] - ri->data[i+1][j]) >> 1; + + double e2 = 1.0 / (1.0 + ABS(dx) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4)); + + d1 = ri->data[i+1][j] - ri->data[i+3][j]; + d2 = ri->data[i][j] - ri->data[i+2][j]; + d3 = (ri->data[i][j-1] - ri->data[i+2][j-1]) >> 1; + d4 = (ri->data[i][j+1] - ri->data[i+2][j+1]) >> 1; + + double e3 = 1.0 / (1.0 + ABS(dy) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4)); + + d1 = ri->data[i][j-3] - ri->data[i][j-1]; + d2 = ri->data[i][j-2] - ri->data[i][j]; + d3 = (ri->data[i-1][j-2] - ri->data[i-1][j]) >> 1; + d4 = (ri->data[i+1][j-2] - ri->data[i+1][j]) >> 1; + + double e4 = 1.0 / (1.0 + ABS(dx) + ABS(d1) + ABS(d2) + ABS(d3) + ABS(d4)); + + green[i][j] = CLIP((e1*g1 + e2*g2 + e3*g3 + e4*g4) / (e1 + e2 + e3 + e4)); + } + } + } + } +} + +void RawImageSource::hphd_demosaic () { + + if (plistener) { + plistener->setProgressStr ("Demosaicing..."); + plistener->setProgress (0.0); + } + + float** hpmap = new float*[H]; + for (int i=0; idualThreadEnabled) { + Glib::Thread *thread1 = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &RawImageSource::hphd_vertical), hpmap, 0, W/2), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + Glib::Thread *thread2 = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &RawImageSource::hphd_vertical), hpmap, W/2, W), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread1->join (); + thread2->join (); + } + else + hphd_vertical (hpmap, 0, W); + + if (plistener) + plistener->setProgress (0.33); + + // horizontal + this->hpmap = allocArray(W, H); + for (int i=0; ihpmap[i], 0, W*sizeof(char)); + + if (settings->dualThreadEnabled) { + Glib::Thread *thread1 = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &RawImageSource::hphd_horizontal), hpmap, 0, H/2), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + Glib::Thread *thread2 = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &RawImageSource::hphd_horizontal), hpmap, H/2, H), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread1->join (); + thread2->join (); + } + else + hphd_horizontal (hpmap, 0, H); + + freeArray(hpmap, H); + + if (plistener) + plistener->setProgress (0.66); + +// reconstruct G + green = new unsigned short*[H]; + for (int i=0; idualThreadEnabled) { + Glib::Thread *thread1 = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &RawImageSource::hphd_green), 3, H/2), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + Glib::Thread *thread2 = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &RawImageSource::hphd_green), H/2, H-3), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread1->join (); + thread2->join (); + } + else + hphd_green (3, H-3); + + if (plistener) + plistener->setProgress (1.0); +} + +void RawImageSource::HLRecovery_Luminance (unsigned short* rin, unsigned short* gin, unsigned short* bin, unsigned short* rout, unsigned short* gout, unsigned short* bout, int width, int maxval) { + + for (int i=0; imaxval || g>maxval || b>maxval) { + int ro = MIN (r, maxval); + int go = MIN (g, maxval); + int bo = MIN (b, maxval); + double L = r + g + b; + double C = 1.732050808 * (r - g); + double H = 2 * b - r - g; + double Co = 1.732050808 * (ro - go); + double Ho = 2 * bo - ro - go; + if (r!=g && g!=b) { + double ratio = sqrt ((Co*Co+Ho*Ho) / (C*C+H*H)); + C *= ratio; + H *= ratio; + } + int rr = L / 3.0 - H / 6.0 + C / 3.464101615; + int gr = L / 3.0 - H / 6.0 - C / 3.464101615; + int br = L / 3.0 + H / 3.0; + rout[i] = CLIP(rr); + gout[i] = CLIP(gr); + bout[i] = CLIP(br); + } + else { + rout[i] = rin[i]; + gout[i] = gin[i]; + bout[i] = bin[i]; + } + } +} + +void RawImageSource::HLRecovery_CIELab (unsigned short* rin, unsigned short* gin, unsigned short* bin, unsigned short* rout, unsigned short* gout, unsigned short* bout, int width, int maxval, double cam[3][3], double icam[3][3]) { + + static bool crTableReady = false; + static double fv[0x10000]; + if (!crTableReady) { + for (int ix=0; ix < 0x10000; ix++) { + double rx = ix / 65535.0; + fv[ix] = rx > 0.008856 ? exp(1.0/3 * log(rx)) : 7.787*rx + 16/116.0; + } + crTableReady = true; + } + + for (int i=0; imaxval || g>maxval || b>maxval) { + int ro = MIN (r, maxval); + int go = MIN (g, maxval); + int bo = MIN (b, maxval); + double yy = cam[0][1]*r + cam[1][1]*g + cam[2][1]*b; + double fy = fv[CLIP((int)yy)]; + // compute LCH decompostion of the clipped pixel (only color information, thus C and H will be used) + double x = cam[0][0]*ro + cam[1][0]*go + cam[2][0]*bo; + double y = cam[0][1]*ro + cam[1][1]*go + cam[2][1]*bo; + double z = cam[0][2]*ro + cam[1][2]*go + cam[2][2]*bo; + x = fv[CLIP((int)x)]; + y = fv[CLIP((int)y)]; + z = fv[CLIP((int)z)]; + // convert back to rgb + double fz = fy - y + z; + double fx = fy + x - y; + double zr = (fz<=0.206893) ? ((116.0*fz-16.0)/903.3) : (fz * fz * fz); + double xr = (fx<=0.206893) ? ((116.0*fx-16.0)/903.3) : (fx * fx * fx); + x = xr*65535.0 - 0.5; + y = yy; + z = zr*65535.0 - 0.5; + int rr = icam[0][0]*x + icam[1][0]*y + icam[2][0]*z; + int gr = icam[0][1]*x + icam[1][1]*y + icam[2][1]*z; + int br = icam[0][2]*x + icam[1][2]*y + icam[2][2]*z; + rout[i] = CLIP(rr); + gout[i] = CLIP(gr); + bout[i] = CLIP(br); + } + else { + rout[i] = rin[i]; + gout[i] = gin[i]; + bout[i] = bin[i]; + } + } +} + +void RawImageSource::hlRecovery (std::string method, unsigned short* red, unsigned short* green, unsigned short* blue, int i, int sx1, int width, int skip) { + + if (method=="Luminance") + HLRecovery_Luminance (red, green, blue, red, green, blue, width, 65535 / ri->defgain); + else if (method=="CIELab blending") + HLRecovery_CIELab (red, green, blue, red, green, blue, width, 65535 / ri->defgain, cam, icam); + else if (method=="Color") + HLRecovery_ColorPropagation (red, green, blue, i, sx1, width, skip); +} + +int RawImageSource::getAEHistogram (int* histogram, int& histcompr) { + + histcompr = 3; + + memset (histogram, 0, (65536>>histcompr)*sizeof(int)); + + for (int i=border; iheight-border; i++) { + int start, end; + if (fuji) { + int fw = ri->fuji_width; + start = ABS(fw-i) + border; + end = MIN( ri->height+ ri->width-fw-i, fw+i) - border; + } + else { + start = border; + end = ri->width-border; + } + if (ri->filters) + for (int j=start; jdata[i][j]>>histcompr]+=2; + else + histogram[ri->data[i][j]>>histcompr]+=4; + else + for (int j=start; j<3*end; j++) { + histogram[ri->data[i][j+0]>>histcompr]++; + histogram[ri->data[i][j+1]>>histcompr]++; + histogram[ri->data[i][j+2]>>histcompr]++; + } + } + return 1; +} + +ColorTemp RawImageSource::getAutoWB () { + + double avg_r = 0; + double avg_g = 0; + double avg_b = 0; + int rn = 0, gn = 0, bn = 0; + + if (fuji) { + for (int i=32; iheight-32; i++) { + int fw = ri->fuji_width; + int start = ABS(fw-i) + 32; + int end = MIN(ri->height+ri->width-fw-i, fw+i) - 32; + for (int j=start; jfilters) { + double d = CLIP(ri->defgain*ri->data[i][3*j]); + if (d>64000) + continue; + avg_r += d*d*d*d*d*d; rn++; + d = CLIP(ri->defgain*ri->data[i][3*j+1]); + if (d>64000) + continue; + avg_g += d*d*d*d*d*d; gn++; + d = CLIP(ri->defgain*ri->data[i][3*j+2]); + if (d>64000) + continue; + avg_b += d*d*d*d*d*d; bn++; + } + else { + double d = CLIP(ri->defgain*ri->data[i][j]); + if (d>64000) + continue; + double dp = d*d*d*d*d*d; + if (ISRED(ri,i,j)) { + avg_r += dp; + rn++; + } + else if (ISGREEN(ri,i,j)) { + avg_g += dp; + gn++; + } + else if (ISBLUE(ri,i,j)) { + avg_b += dp; + bn++; + } + } + } + } + } + else { + for (int i=32; iheight-32; i++) + for (int j=32; jwidth-32; j++) { + if (!ri->filters) { + double d = CLIP(ri->defgain*ri->data[i][3*j]); + if (d>64000) + continue; + avg_r += d*d*d*d*d*d; rn++; + d = CLIP(ri->defgain*ri->data[i][3*j+1]); + if (d>64000) + continue; + avg_g += d*d*d*d*d*d; gn++; + d = CLIP(ri->defgain*ri->data[i][3*j+2]); + if (d>64000) + continue; + avg_b += d*d*d*d*d*d; bn++; + } + else { + double d = CLIP(ri->defgain*ri->data[i][j]); + if (d>64000) + continue; + double dp = d*d*d*d*d*d; + if (ISRED(ri,i,j)) { + avg_r += dp; + rn++; + } + else if (ISGREEN(ri,i,j)) { + avg_g += dp; + gn++; + } + else if (ISBLUE(ri,i,j)) { + avg_b += dp; + bn++; + } + } + } + } + + printf ("AVG: %g %g %g\n", avg_r/rn, avg_g/gn, avg_b/bn); + +// double img_r, img_g, img_b; +// wb.getMultipliers (img_r, img_g, img_b); + +// return ColorTemp (pow(avg_r/rn, 1.0/6.0)*img_r, pow(avg_g/gn, 1.0/6.0)*img_g, pow(avg_b/bn, 1.0/6.0)*img_b); + + double reds = pow (avg_r/rn, 1.0/6.0) * ri->camwb_red; + double greens = pow (avg_g/gn, 1.0/6.0) * ri->camwb_green; + double blues = pow (avg_b/bn, 1.0/6.0) * ri->camwb_blue; + + double rm = coeff[0][0]*reds + coeff[0][1]*greens + coeff[0][2]*blues; + double gm = coeff[1][0]*reds + coeff[1][1]*greens + coeff[1][2]*blues; + double bm = coeff[2][0]*reds + coeff[2][1]*greens + coeff[2][2]*blues; + + return ColorTemp (rm, gm, bm); +} + +void RawImageSource::transformPosition (int x, int y, int tran, int& ttx, int& tty) { + + tran = defTransform (tran); + + x += border; + y += border; + + if (d1x) { + if ((tran & TR_ROT) == TR_R90 || (tran & TR_ROT) == TR_R270) + x /= 2; + else + y /= 2; + } + + int w = W, h = H; + if (fuji) { + w = ri->fuji_width * 2 + 1; + h = (H - ri->fuji_width)*2 + 1; + } + int sw = w, sh = h; + if ((tran & TR_ROT) == TR_R90 || (tran & TR_ROT) == TR_R270) { + sw = h; + sh = w; + } + + int ppx = x, ppy = y; + if (tran & TR_HFLIP) + ppx = sw - 1 - x ; + if (tran & TR_VFLIP) + ppy = sh - 1 - y; + + int tx = ppx; + int ty = ppy; + + if ((tran & TR_ROT) == TR_R180) { + tx = w - 1 - ppx; + ty = h - 1 - ppy; + } + else if ((tran & TR_ROT) == TR_R90) { + tx = ppy; + ty = h - 1 - ppx; + } + else if ((tran & TR_ROT) == TR_R270) { + tx = w - 1 - ppy; + ty = ppx; + } + + if (fuji) { + ttx = (tx+ty) / 2; + tty = (ty-tx) / 2 + ri->fuji_width; + } + else { + ttx = tx; + tty = ty; + } +} + +ColorTemp RawImageSource::getSpotWB (std::vector red, std::vector green, std::vector& blue, int tran) { + + int x; int y; + int d[9][2] = {0,0, -1,-1, -1,0, -1,1, 0,-1, 0,1, 1,-1, 1,0, 1,1}; + double reds = 0, greens = 0, blues = 0; + int rn = 0, gn = 0, bn = 0; + + if (!ri->filters) { + for (int i=0; i=0 && y>=0 && xdata[y][3*x]; + rn++; + } + transformPosition (green[i].x, green[i].y, tran, x, y); + if (x>=0 && y>=0 && xdata[y][3*x+1]; + gn++; + } + transformPosition (blue[i].x, blue[i].y, tran, x, y); + if (x>=0 && y>=0 && xdata[y][3*x+2]; + bn++; + } + } + } + else { + for (int i=0; i=0 && yv>=0 && xvdata[yv][xv]; + rn++; + break; + } + } + transformPosition (green[i].x, green[i].y, tran, x, y); + for (int k=0; k<9; k++) { + int xv = x + d[k][0]; + int yv = y + d[k][1]; + if (ISGREEN(ri,yv,xv) && xv>=0 && yv>=0 && xvdata[yv][xv]; + gn++; + break; + } + } + transformPosition (blue[i].x, blue[i].y, tran, x, y); + for (int k=0; k<9; k++) { + int xv = x + d[k][0]; + int yv = y + d[k][1]; + if (ISBLUE(ri,yv,xv) && xv>=0 && yv>=0 && xvdata[yv][xv]; + bn++; + break; + } + } + } + } + + reds = reds/rn * ri->camwb_red; + greens = greens/gn * ri->camwb_green; + blues = blues/bn * ri->camwb_blue; + + double rm = coeff[0][0]*reds + coeff[0][1]*greens + coeff[0][2]*blues; + double gm = coeff[1][0]*reds + coeff[1][1]*greens + coeff[1][2]*blues; + double bm = coeff[2][0]*reds + coeff[2][1]*greens + coeff[2][2]*blues; + + return ColorTemp (rm, gm, bm); +} + +#define FORCC for (c=0; c < colors; c++) +#define fc(row,col) \ + (ri->prefilters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3) +typedef unsigned short ushort; +void RawImageSource::vng4_demosaic () { + + static const signed char *cp, terms[] = { + -2,-2,+0,-1,0,0x01, -2,-2,+0,+0,1,0x01, -2,-1,-1,+0,0,0x01, + -2,-1,+0,-1,0,0x02, -2,-1,+0,+0,0,0x03, -2,-1,+0,+1,1,0x01, + -2,+0,+0,-1,0,0x06, -2,+0,+0,+0,1,0x02, -2,+0,+0,+1,0,0x03, + -2,+1,-1,+0,0,0x04, -2,+1,+0,-1,1,0x04, -2,+1,+0,+0,0,0x06, + -2,+1,+0,+1,0,0x02, -2,+2,+0,+0,1,0x04, -2,+2,+0,+1,0,0x04, + -1,-2,-1,+0,0,0x80, -1,-2,+0,-1,0,0x01, -1,-2,+1,-1,0,0x01, + -1,-2,+1,+0,1,0x01, -1,-1,-1,+1,0,0x88, -1,-1,+1,-2,0,0x40, + -1,-1,+1,-1,0,0x22, -1,-1,+1,+0,0,0x33, -1,-1,+1,+1,1,0x11, + -1,+0,-1,+2,0,0x08, -1,+0,+0,-1,0,0x44, -1,+0,+0,+1,0,0x11, + -1,+0,+1,-2,1,0x40, -1,+0,+1,-1,0,0x66, -1,+0,+1,+0,1,0x22, + -1,+0,+1,+1,0,0x33, -1,+0,+1,+2,1,0x10, -1,+1,+1,-1,1,0x44, + -1,+1,+1,+0,0,0x66, -1,+1,+1,+1,0,0x22, -1,+1,+1,+2,0,0x10, + -1,+2,+0,+1,0,0x04, -1,+2,+1,+0,1,0x04, -1,+2,+1,+1,0,0x04, + +0,-2,+0,+0,1,0x80, +0,-1,+0,+1,1,0x88, +0,-1,+1,-2,0,0x40, + +0,-1,+1,+0,0,0x11, +0,-1,+2,-2,0,0x40, +0,-1,+2,-1,0,0x20, + +0,-1,+2,+0,0,0x30, +0,-1,+2,+1,1,0x10, +0,+0,+0,+2,1,0x08, + +0,+0,+2,-2,1,0x40, +0,+0,+2,-1,0,0x60, +0,+0,+2,+0,1,0x20, + +0,+0,+2,+1,0,0x30, +0,+0,+2,+2,1,0x10, +0,+1,+1,+0,0,0x44, + +0,+1,+1,+2,0,0x10, +0,+1,+2,-1,1,0x40, +0,+1,+2,+0,0,0x60, + +0,+1,+2,+1,0,0x20, +0,+1,+2,+2,0,0x10, +1,-2,+1,+0,0,0x80, + +1,-1,+1,+1,0,0x88, +1,+0,+1,+2,0,0x08, +1,+0,+2,-1,0,0x40, + +1,+0,+2,+1,0,0x10 + }, chood[] = { -1,-1, -1,0, -1,+1, 0,+1, +1,+1, +1,0, +1,-1, 0,-1 }; + + if (plistener) { + plistener->setProgressStr ("Demosaicing..."); + plistener->setProgress (0.0); + } + + ushort (*brow[5])[4], *pix; + int prow=7, pcol=1, *ip, *code[16][16], gval[8], gmin, gmax, sum[4]; + int row, col, x, y, x1, x2, y1, y2, t, weight, grads, color, diag; + int g, diff, thold, num, c, width=W, height=H, colors=4; + ushort (*image)[4]; + int lcode[16][16][32], shift, i, j; + + image = (ushort (*)[4]) calloc (H*W, sizeof *image); + for (int ii=0; iidata[ii][jj]; + +// first linear interpolation + for (row=0; row < 16; row++) + for (col=0; col < 16; col++) { + ip = lcode[row][col]; + memset (sum, 0, sizeof sum); + for (y=-1; y <= 1; y++) + for (x=-1; x <= 1; x++) { + shift = (y==0) + (x==0); + if (shift == 2) continue; + color = fc(row+y,col+x); + *ip++ = (width*y + x)*4 + color; + *ip++ = shift; + *ip++ = color; + sum[color] += 1 << shift; + } + FORCC + if (c != fc(row,col)) { + *ip++ = c; + *ip++ = 256 / sum[c]; + } + } + + for (row=1; row < height-1; row++) + for (col=1; col < width-1; col++) { + pix = image[row*width+col]; + ip = lcode[row & 15][col & 15]; + memset (sum, 0, sizeof sum); + for (i=8; i--; ip+=3) + sum[ip[2]] += pix[ip[0]] << ip[1]; + for (i=colors; --i; ip+=2) + pix[ip[0]] = sum[ip[0]] * ip[1] >> 8; + } + +// lin_interpolate(); + + + ip = (int *) calloc ((prow+1)*(pcol+1), 1280); + for (row=0; row <= prow; row++) /* Precalculate for VNG */ + for (col=0; col <= pcol; col++) { + code[row][col] = ip; + for (cp=terms, t=0; t < 64; t++) { + y1 = *cp++; x1 = *cp++; + y2 = *cp++; x2 = *cp++; + weight = *cp++; + grads = *cp++; + color = fc(row+y1,col+x1); + if (fc(row+y2,col+x2) != color) continue; + diag = (fc(row,col+1) == color && fc(row+1,col) == color) ? 2:1; + if (abs(y1-y2) == diag && abs(x1-x2) == diag) continue; + *ip++ = (y1*width + x1)*4 + color; + *ip++ = (y2*width + x2)*4 + color; + *ip++ = weight; + for (g=0; g < 8; g++) + if (grads & 1< gval[g]) gmin = gval[g]; + if (gmax < gval[g]) gmax = gval[g]; + } + if (gmax == 0) { + memcpy (brow[2][col], pix, sizeof *image); + continue; + } + thold = gmin + (gmax >> 1); + memset (sum, 0, sizeof sum); + for (num=g=0; g < 8; g++,ip+=2) { /* Average the neighbors */ + if (gval[g] <= thold) { + FORCC + if (c == color && ip[1]) + sum[c] += (pix[c] + pix[ip[1]]) >> 1; + else + sum[c] += pix[ip[0] + c]; + num++; + } + } + FORCC { /* Save to buffer */ + t = pix[color]; + if (c != color) + t += (sum[c] - sum[color]) / num; + brow[2][col][c] = CLIP(t); + } + } + if (row > 3) /* Write buffer to image */ + memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image); + for (g=0; g < 4; g++) + brow[(g-1) & 3] = brow[g]; + if (!(row%20) && plistener) + plistener->setProgress ((double)row / (H-2)); + } + memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image); + memcpy (image[(row-1)*width+2], brow[1]+2, (width-4)*sizeof *image); + free (brow[4]); + free (code[0][0]); + + green = new unsigned short*[H]; + for (int i=0; i> 1; + } + free (image); +} +} + diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h new file mode 100755 index 000000000..8922b1248 --- /dev/null +++ b/rtengine/rawimagesource.h @@ -0,0 +1,143 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _RAWIMAGESOURCE_ +#define _RAWIMAGESOURCE_ + +#include +#include +#define HR_SCALE 2 + +namespace rtengine { + +template void freeArray (T** a, int H) { + for (int i=0; i T** allocArray (int W, int H) { + + T** t = new T*[H]; + for (int i=0; i void freeArray2 (T** a, int H) { + for (int i=0; i red, std::vector green, std::vector& blue, int tran); + + double getDefGain () { return defGain; } + double getGamma () { return 2.2; } + + void getFullSize (int& w, int& h, int tr = TR_NONE); + void getSize (int tran, PreviewProps pp, int& w, int& h); + + ImageData* getImageData () { return idata; } + void setProgressListener (ProgressListener* pl) { plistener = pl; } + int getAEHistogram (int* histogram, int& histcompr); + + static void colorSpaceConversion (Image16* im, ColorManagementParams cmp, cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], double& defgain); + static void inverse33 (double (*coeff)[3], double (*icoeff)[3]); + + static void HLRecovery_Luminance (unsigned short* rin, unsigned short* gin, unsigned short* bin, unsigned short* rout, unsigned short* gout, unsigned short* bout, int width, int maxval); + static void HLRecovery_CIELab (unsigned short* rin, unsigned short* gin, unsigned short* bin, unsigned short* rout, unsigned short* gout, unsigned short* bout, int width, int maxval, double cam[3][3], double icam[3][3]); + + protected: + void correction_YIQ_LQ (Image16* i, int times); + inline void convert_row_to_YIQ (unsigned short* r, unsigned short* g, unsigned short* b, int* Y, int* I, int* Q, int W); + inline void convert_row_to_RGB (unsigned short* r, unsigned short* g, unsigned short* b, int* Y, int* I, int* Q, int W); + + inline void convert_to_cielab_row (unsigned short* ar, unsigned short* ag, unsigned short* ab, short* oL, short* oa, short* ob); + inline void interpolate_row_g (unsigned short* agh, unsigned short* agv, int i); + inline void interpolate_row_rb (unsigned short* ar, unsigned short* ab, unsigned short* pg, unsigned short* cg, unsigned short* ng, int i); + inline void interpolate_row_rb_mul_pp (unsigned short* ar, unsigned short* ab, unsigned short* pg, unsigned short* cg, unsigned short* ng, int i, double r_mul, double g_mul, double b_mul, int x1, int width, int skip); + + void eahd_demosaic (); + void hphd_demosaic (); + void vng4_demosaic (); + + void transLine (unsigned short* red, unsigned short* green, unsigned short* blue, int i, Image16* image, int tran, int imw, int imh, int fw); + void hflip (Image16* im); + void vflip (Image16* im); + +}; +}; +#endif diff --git a/rtengine/rawmetadatalocation.h b/rtengine/rawmetadatalocation.h new file mode 100755 index 000000000..0e74b9446 --- /dev/null +++ b/rtengine/rawmetadatalocation.h @@ -0,0 +1,32 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _RAWMETADATALOCATION_ +#define _RAWMETADATALOCATION_ + +namespace rtengine { + + struct RawMetaDataLocation { + int exifBase; + int ciffBase; + int ciffLength; + }; +} + +#endif + diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc new file mode 100755 index 000000000..2e561aa7f --- /dev/null +++ b/rtengine/refreshmap.cc @@ -0,0 +1,106 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +int refreshmap[] = { +ALL, // EvPhotoLoaded, +ALL, // EvProfileLoaded, +ALL, // EvProfileChanged, +ALL, // EvHistoryBrowsed, +RGBCURVE, // EvBrightness, +RGBCURVE, // EvContrast, +RGBCURVE, // EvBlack, +RGBCURVE, // EvExpComp, +RGBCURVE, // EvHLCompr, +RGBCURVE, // EvSHCompr, +RGBCURVE, // EvToneCurve, +AUTOEXP, // EvAutoExp, +AUTOEXP, // EvClip, +LUMINANCECURVE, // EvLBrightness, +LUMINANCECURVE, // EvLContrast, +LUMINANCECURVE, // EvLBlack, +LUMINANCECURVE, // EvLHLCompr, +LUMINANCECURVE, // EvLSHCompr, +LUMINANCECURVE, // EvLCurve, +SHARPENING, // EvShrEnabled, +SHARPENING, // EvShrRadius, +SHARPENING, // EvShrAmount, +SHARPENING, // EvShrThresh, +SHARPENING, // EvShrEdgeOnly, +SHARPENING, // EvShrEdgeRadius, +SHARPENING, // EvShrEdgeTolerance, +SHARPENING, // EvShrHaloControl, +SHARPENING, // EvShrHaloAmount, +SHARPENING, // EvShrMethod, +SHARPENING, // EvShrDRadius, +SHARPENING, // EvShrDAmount, +SHARPENING, // EvShrDDamping, +SHARPENING, // EvShrDIterations, +COLORBOOST, // EvCBAvoidClip, +COLORBOOST, // EvCBSatLimiter, +COLORBOOST, // EvCBSatLimit, +COLORBOOST, // EvCBBoost, +WHITEBALANCE, // EvWBMethod, +WHITEBALANCE, // EvWBTemp, +WHITEBALANCE, // EvWBGreen, +COLORBOOST, // EvCShiftA, +COLORBOOST, // EvCShiftB, +LUMADENOISE, // EvLDNEnabled, +LUMADENOISE, // EvLDNRadius, +LUMADENOISE, // EvLDNEdgeTolerance, +COLORDENOISE, // EvCDNEnabled, +COLORDENOISE, // EvCDNRadius, +COLORDENOISE, // EvCDNEdgeTolerance, +COLORDENOISE, // EvCDNEdgeSensitive, +RETINEX, // EvSHEnabled, +RGBCURVE, // EvSHHighlights, +RGBCURVE, // EvSHShadows, +RGBCURVE, // EvSHHLTonalW, +RGBCURVE, // EvSHSHTonalW, +RGBCURVE, // EvSHLContrast, +RETINEX, // EvSHRadius, +ALL, // EvCTRotate, +ALL, // EvCTHFlip, +ALL, // EvCTVFlip, +TRANSFORM, // EvROTDegree, +TRANSFORM, // EvROTFill, +TRANSFORM, // EvDISTAmount, +ALL, // EvBookmarkSelected, +CROP, // EvCrop, +TRANSFORM, // EvCACorr, +ALL, // EvHREnabled, +ALL, // EvHRAmount, +ALL, // EvHRMethod, +ALL, // EvWProfile, +ALL, // EvOProfile, +ALL, // EvIProfile, +TRANSFORM, // EvVignetting, +RGBCURVE, // EvChMixer, +ALL, // EvResizeScale, +ALL, // EvResizeMethod, +EXIF, // EvExif, +IPTC, // EvIPTC +ALL, // EvResizeSpec, +ALL, // EvResizeWidth +ALL, // EvResizeHeight +ALL, // EvResizeEnabled +ALL, // EvProfileChangeNotification +RETINEX // EvShrHighQuality + }; + diff --git a/rtengine/refreshmap.h b/rtengine/refreshmap.h new file mode 100755 index 000000000..b7daf7be0 --- /dev/null +++ b/rtengine/refreshmap.h @@ -0,0 +1,53 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef __REFRESHMAP__ +#define __REFRESHMAP__ + +#include + +#define NUMOFEVENTS 83 + +#define FIRST 65535 +#define ALL 65535 +#define TRANSFORM 127 +#define RETINEX 63 +#define AUTOEXP 31 +#define RGBCURVE 15 +#define LUMINANCECURVE 6 +#define SHARPENING 2 +#define LUMADENOISE 2 +#define WHITEBALANCE 255 +#define COLORBOOST 1 +#define COLORDENOISE 1 +#define CROP 16384 +#define EXIF 32768 +#define IPTC 32768 +#define NONE 0 + +#define M_INIT 128 +#define M_TRANSFORM 64 +#define M_BLURMAP 32 +#define M_AUTOEXP 16 +#define M_RGBCURVE 8 +#define M_LUMACURVE 4 +#define M_LUMINANCE 2 +#define M_COLOR 1 + +extern int refreshmap[]; +#endif diff --git a/rtengine/rtcmd b/rtengine/rtcmd new file mode 100755 index 0000000000000000000000000000000000000000..1c30444dfe9107b35b2ef9bdee64918fff53af4c GIT binary patch literal 31928 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 literal 0 HcmV?d00001 diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h new file mode 100755 index 000000000..18709b419 --- /dev/null +++ b/rtengine/rtengine.h @@ -0,0 +1,386 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _RTENGINE_ +#define _RTENGINE_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/** + * @file + * This file contains the main functionality of the raw therapee engine. + * + */ + + +namespace rtengine { + + /** + * This class represents provides functions to obtain exif and IPTC metadata information + * from the image file + */ + class ImageMetaData { + + public: + /** Checks the availability of exif metadata tags. + * @return Returns true if image contains exif metadata tags */ + virtual bool hasExif () const {} + /** Returns the directory of exif metadata tags. + * @return The directory of exif metadata tags */ + virtual const rtexif::TagDirectory* getExifData () const {} + /** Checks the availability of IPTC tags. + * @return Returns true if image contains IPTC tags */ + virtual bool hasIPTC () const {} + /** Returns the directory of IPTC tags. + * @return The directory of IPTC tags */ + virtual const std::vector getIPTCData () const {} + /** @return a struct containing the date and time of the image */ + virtual struct tm getDateTime () const {} + /** @return the ISO of the image */ + virtual int getISOSpeed () const {} + /** @return the F number of the image */ + virtual double getFNumber () const {} + /** @return the focal length used at the exposure */ + virtual double getFocalLen () const {} + /** @return the shutter speed */ + virtual double getShutterSpeed () const {} + /** @return the maker of the camera */ + virtual std::string getMake () const {} + /** @return the model of the camera */ + virtual std::string getModel () const {} + /** @return the lens on the camera */ + virtual std::string getLens () const {} + /** Functions to convert between floating point and string representation of shutter and aperture */ + static std::string apertureToString (double aperture); + /** Functions to convert between floating point and string representation of shutter and aperture */ + static std::string shutterToString (double shutter); + /** Functions to convert between floating point and string representation of shutter and aperture */ + static double apertureFromString (std::string shutter); + /** Functions to convert between floating point and string representation of shutter and aperture */ + static double shutterFromString (std::string shutter); + + /** Reads metadata from file. + * @param fname is the name of the file + * @param rml is a struct containing information about metadata location. Use it only for raw files. In case + * of jpgs and tiffs pass a NULL pointer. + * @return The metadata */ + static ImageMetaData* fromFile (const Glib::ustring& fname, RawMetaDataLocation* rml); + }; + + /** This listener interface is used to indicate the progress of time consuming operations */ + class ProgressListener { + + public: + /** This member function is called when the percentage of the progress has been changed. + * @param p is a number between 0 and 1 */ + virtual void setProgress (double p) {} + /** This member function is called when a textual information corresponding to the progress has been changed. + * @param str is the textual information corresponding to the progress */ + virtual void setProgressStr (Glib::ustring str) {} + /** This member function is called when the state of the processing has been changed. + * @param state =1 if the processing has been started, =0 if it has been stopped */ + virtual void setProgressState (int state) {} + /** This member function is called when an error occurs during the operation. + * @param descr is the error message */ + virtual void error (Glib::ustring descr) {} + }; + + class ImageSource; + + /** + * This class represents an image loaded into the memory. It is the basis of further processing. + * In case of raw files the most time consuming operation, the demosaicing is already performed. + * The embedded icc profile and metadata information can be obtained through this class, too. + */ + class InitialImage { + + public: + /** Returns the file name of the image. + * @return The file name of the image */ + virtual Glib::ustring getFileName () {} + /** Returns the embedded icc profile of the image. + * @return The handle of the embedded profile */ + virtual cmsHPROFILE getEmbeddedProfile () {} + /** Returns a class providing access to the exif and iptc metadata tags of the image. + * @return An instance of the ImageMetaData class */ + virtual const ImageMetaData* getMetaData () {} + /** This is a function used for internal purposes only. */ + virtual ImageSource* getImageSource () {} + /** This class has manual reference counting. You have to call this function each time to make a new reference to an instance. */ + virtual void increaseRef () {} + /** This class has manual reference counting. You have to call this function each time to remove a reference + * (the last one deletes the instance automatically). */ + virtual void decreaseRef () {} + + + /** Loads an image into the memory. If it is a raw file, is is partially demosaiced (the time consuming part is done) + * @param fname the name of the file + * @param isRaw shall be true if it is a raw file + * @param errorCode is a pointer to a variable that is set to nonzero if an error happened (output) + * @param pl is a pointer pointing to an object implementing a progress listener. It can be NULL, in this case progress is not reported. + * @return an object representing the loaded and pre-processed image */ + static InitialImage* load (const Glib::ustring& fname, bool isRaw, int* errorCode, ProgressListener* pl = NULL); + }; + + /** When the preview image is ready for display during staged processing (thus the changes have been updated), + * the staged processor notifies the listener class implementing a PreviewImageListener. + * It is important to note that the file passed to the listener can be used in a shared manner (copying it is not + * needed) as long as the mutex corresponding to the image is used every time the image is accessed. + * If the scale of the preview image is >1, no sharpening, no denoising and no cropping is applied, and + * the transform operations (rotate, c/a, vignetting correction) are performed using a faster less quality algorithm. + * The image you get with this listener is created to display on the monitor (monitor profile has been already applied). */ + class PreviewImageListener { + public: + /** With this member function the staged processor notifies the listener that it allocated a new + * image to store the end result of the processing. It can be used in a shared manner. + * @param img is a pointer to the image + * @param scale describes the current scaling applied compared to the 100% size (preview scale + resize scale) + * @param cp holds the coordinates of the current crop rectangle */ + virtual void setImage (IImage8* img, double scale, procparams::CropParams cp) {} + /** With this member function the staged processor notifies the listener that the image passed as parameter + * will be deleted, and no longer used to store the preview image. + * @param img the pointer to the image to be destroyed. The listener has to free the image! */ + virtual void delImage (IImage8* img) {} + /** With this member function the staged processor notifies the listener that the preview image has been updated. + * @param cp holds the coordinates of the current crop rectangle */ + virtual void imageReady (procparams::CropParams cp) {} + }; + + /** When the detailed crop image is ready for display during staged processing (thus the changes have been updated), + * the staged processor notifies the listener class implementing a DetailedCropListener. + * It is important to note that the file passed to the listener can not be used in a shared manner, the class + * implementing this interface has to store a copy of it. */ + class DetailedCropListener { + public: + /** With this member function the staged processor notifies the listener that the detailed crop image has been updated. + * @param img is a pointer to the detailed crop image */ + virtual void setDetailedCrop (IImage8* img, procparams::CropParams cp, int cx, int cy, int cw, int ch, int skip) {} + virtual bool getWindow (int& cx, int& cy, int& cw, int& ch, int& skip) { return false; } + }; + + /** This listener is used when the full size of the final image has been changed (e.g. rotated by 90 deg.) */ + class SizeListener { + public: + /** This member function is called when the size of the final image has been changed + * @param w is the width of the final image (without cropping) + * @param h is the height of the final image (without cropping) + * @param ow is the width of the final image (without resizing and cropping) + * @param oh is the height of the final image (without resizing and cropping) */ + virtual void sizeChanged (int w, int h, int ow, int oh) {} + }; + + /** This listener is used when the histogram of the final image has changed. */ + class HistogramListener { + public: + /** This member function is called when the histogram of the final image has changed. + * @param redh is the array of size 256 containing the histogram of the red channel + * @param greenh is the array of size 256 containing the histogram of the green channel + * @param blueh is the array of size 256 containing the histogram of the blue channel + * @param lumah is the array of size 256 containing the histogram of the luminance channel */ + virtual void histogramChanged (unsigned int* redh, unsigned int* greenh, unsigned int* blueh, unsigned int* lumah) {} + }; + + /** This listener is used when the auto exposure has been recomputed (e.g. when the clipping ratio changed). */ + class AutoExpListener { + public: + /** This member function is called when the auto exposure has been recomputed. + * @param brightness is the new brightness value (in logarithmic scale) + * @param black is the new black level (measured in absolute pixel data) */ + virtual void autoExpChanged (double brightness, int black) {} + }; + + /** This class represents a detailed part of the image (looking through a kind of window). + * It can be created and destroyed with the appropriate members of StagedImageProcessor. + * Several crops can be assigned to the same image. */ + class DetailedCrop { + public: + /** Sets the window defining the crop. */ + virtual void setWindow (int cx, int cy, int cw, int ch, int skip) {} + /** Perform a full recalculation of the part of the image corresponding to the crop. */ + virtual void fullUpdate () {} + /** Sets the listener of the crop. */ + virtual void setListener (DetailedCropListener* il) {} + /** Destroys the crop. */ + virtual void destroy () {} + }; + + /** This is a staged, cached image processing manager with partial image update support. */ + class StagedImageProcessor { + + public: + /** Returns the inital image corresponding to the image processor. + * @return the inital image corresponding to the image processor */ + virtual InitialImage* getInitialImage () {} + /** Returns the current processing parameters. + * @param dst is the location where the image processing parameters are copied (it is assumed that the memory is allocated by the caller) */ + virtual void getParams (procparams::ProcParams* dst) {} + /** An essential member function. Call this when a setting has been changed. This function returns a pointer to the + * processing parameters, that you have to update to reflect the changed situation. When ready, call the paramsUpdateReady + * function to start the image update. + * @param change is the ID of the changed setting */ + virtual procparams::ProcParams* getParamsForUpdate (ProcEvent change) {} + /** An essential member function. This indicates that you are ready with the update of the processing parameters you got + * with the getParamsForUpdate call, so the image can be updated. This function returns immediately. + * The image update starts immediately in the background. If it is ready, the result is passed to a PreviewImageListener + * and to a DetailedCropListener (if enabled). */ + virtual void paramsUpdateReady () {} + /** Stops image processing. When it returns, the image processing is already stopped. */ + virtual void stopProcessing () {} + /** Sets the scale of the preview image. The larger the number is, the faster the image updates are (typical values are 4-5). + * @param scale is the scale of the preview image */ + virtual void setPreviewScale (int scale) {} + /** Returns the scale of the preview image. + * @return the current scale of the preview image */ + virtual int getPreviewScale () {} + /** Performs a full update on the preview image. The resulting image is passed to the listener. */ + virtual void fullUpdatePreviewImage () {} + /** Performs a full update on the detailed crops corresponding to the image. The resulting images are passed to the listeners of the crops. */ + virtual void fullUpdateDetailedCrops () {} + /** Returns the full width of the resulting image (in 1:1 scale). + * @return the width of the final image */ + virtual int getFullWidth () {} + /** Returns the full height of the resulting image (in 1:1 scale). + * @return the height of the final image */ + virtual int getFullHeight () {} + /** Returns the width of the preview image. + * @return the width of the preview image */ + virtual int getPreviewWidth () {} + /** Returns the height of the preview image. + * @return the height of the preview image */ + virtual int getPreviewHeight () {} + + /** Creates and returns a Crop instance that acts as a window on the image */ + virtual DetailedCrop* createCrop () {} + + virtual void getAutoWB (double& temp, double& green) {} + virtual void getCamWB (double& temp, double& green) {} + virtual void getSpotWB (int x, int y, int rectSize, double& temp, double& green) {} + virtual void getAutoCrop (double ratio, int &x, int &y, int &w, int &h) {} + + virtual void saveInputICCReference (const Glib::ustring& fname) {} + + virtual void setProgressListener (ProgressListener* l) {} + virtual void setSizeListener (SizeListener* l) {} + virtual void delSizeListener (SizeListener* l) {} + virtual void setAutoExpListener (AutoExpListener* l) {} + virtual void setHistogramListener (HistogramListener *l) {} + virtual void setPreviewImageListener (PreviewImageListener* l) {} + + virtual ~StagedImageProcessor () {} + + /** Returns a staged, cached image processing manager supporting partial updates + * @param initialImage is a loaded and pre-processed initial image + * @return the staged image processing manager */ + static StagedImageProcessor* create (InitialImage* initialImage); + static void destroy (StagedImageProcessor* sip); + }; + + +/** + * Initializes the RT engine + * @param s is a struct of basic settings */ + int init (const Settings* s); + +/** Checks if a raw file is supported + * @param fname the name of the file + * @param rml is a struct constaining informations on the location of the metadata in the raw file + * @param rotation is the default angle of rotation (0, 90, 180, 270) + * @param thumbWidth is the width of the embedded thumbnail file + * @param thumbHeight is the height of the embedded thumbnail file + * @param thumbOffset is the offset of the embedded thumbnail in the raw file + * @param thumbType is the type of the embedded thumbnail (=0: no thumbnail, =1: jpeg format, =2: simple continuous image data in rgbrgb... order) + * @return =0 if not supported */ + int getRawFileBasicInfo (const Glib::ustring& fname, rtengine::RawMetaDataLocation& rml, int& rotation, int& thumbWidth, int& thumbHeight, int& thumbOffset, int& thumbType); + +/** Returns the available output profile names + * @return a vector of the available output profile names */ + std::vector getOutputProfiles (); + +/** Returns the available working profile names + * @return a vector of the available working profile names */ + std::vector getWorkingProfiles (); + + /** This class holds all the necessary informations to accomplish the full processing of the image */ + class ProcessingJob { + + public: + + /** Creates a processing job from a file name. This function always succeeds. It only stores the data into the ProcessingJob class, it does not load + * the image thus it returns immediately. + * @param fname the name of the file + * @param isRaw shall be true if it is a raw file + * @param pparams is a struct containing the processing parameters + * @return an object containing the data above. It can be passed to the functions that do the actual image processing. */ + static ProcessingJob* create (const Glib::ustring& fname, bool isRaw, const procparams::ProcParams& pparams); + + /** Creates a processing job from a file name. This function always succeeds. It only stores the data into the ProcessingJob class, it does not load + * the image thus it returns immediately. This function increases the reference count of the initialImage. If you decide not the process the image you + * have to cancel it by calling the member function void cancel(). If the image is processed the reference count of initialImage is decreased automatically, thus the ProcessingJob + * instance gets invalid. You can not use a ProcessingJob instance to process an image twice. + * @param initialImage is a loaded and pre-processed initial image + * @param pparams is a struct containing the processing parameters + * @return an object containing the data above. It can be passed to the functions that do the actual image processing. */ + static ProcessingJob* create (InitialImage* initialImage, const procparams::ProcParams& pparams); + + /** Cancels and destroys a processing job. The reference count of the corresponding initialImage (if any) is decreased. After the call of this function the ProcessingJob instance + * gets invalid, you must not use it any more. Dont call this function while the job is being processed. + * @param job is the job to destroy */ + static void destroy (ProcessingJob* job); + }; + +/** This function performs all the image processinf steps corresponding to the given ProcessingJob. It returns when it is ready, so it can be slow. + * The ProcessingJob passed becomes invalid, you can not use it any more. + * @param job the ProcessingJob to cancel. + * @param errorCode is the error code if an error occured (e.g. the input image could not be loaded etc.) + * @param pl is an optional ProgressListener if you want to keep track of the progress + * @return the resulting image, with the output profile applied, exif and iptc data set. You have to save it or you can access the pixel data directly. */ + IImage16* processImage (ProcessingJob* job, int& errorCode, ProgressListener* pl = NULL); + +/** This class is used to control the batch processing. The class implementing this interface will be called when the full processing of an + * image is ready and the next job to process is needed. */ + class BatchProcessingListener : public ProgressListener { + public: + /** This function is called when an image gets ready during the batch processing. It has to return with the next job, or with NULL if + * there is no jobs left. + * @param img is the result of the last ProcessingJob + * @return the next ProcessingJob to process */ + virtual ProcessingJob* imageReady (IImage16* img) {} + }; +/** This function performs all the image processinf steps corresponding to the given ProcessingJob. It runs in the background, thus it returns immediately, + * When it finishes, it calls the BatchProcessingListener with the resulting image and asks for the next job. It the listener gives a new job, it goes on + * with processing. If no new job is given, it finishes. + * The ProcessingJob passed becomes invalid, you can not use it any more. + * @param job the ProcessingJob to cancel. + * @param bpl is the BatchProcessingListener that is called when the image is ready or the next job is needed. It also acts as a ProgressListener. */ + void startBatchProcessing (ProcessingJob* job, BatchProcessingListener* bpl); + + + extern Glib::Mutex* lcmsMutex; +} + +#endif + diff --git a/rtengine/rtetest.cc b/rtengine/rtetest.cc new file mode 100755 index 000000000..5ee8409db --- /dev/null +++ b/rtengine/rtetest.cc @@ -0,0 +1,71 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +//#include +#include + +class PListener : public rtengine::ProgressListener { + + public: + void setProgressStr (Glib::ustring str) { + std::cout << str << std::endl; + } + void setProgress (double p) { + std::cout << p << std::endl; + } +}; + +int main (int argc, char* argv[]) { + + if (argc<4) { + std::cout << "Usage: rtcmd " << std::endl; + exit(1); + } + + rtengine::Settings s; + s.dualThreadEnabled = true; + s.demosaicMethod = "hphd"; + s.colorCorrectionSteps = 2; + s.iccDirectory = ""; + s.colorimetricIntent = 1; + s.monitorProfile = ""; + + Glib::thread_init (); + rtengine::init (s); + PListener pl; + + rtengine::InitialImage* ii; + int errorCode; + ii = rtengine::InitialImage::load (argv[1], true, errorCode, &pl); + if (!ii) + ii = rtengine::InitialImage::load (argv[1], false, errorCode, &pl); + if (!ii) { + std::cout << "Input file not supported." << std::endl; + exit(2); + } + + rtengine::procparams::ProcParams params; + params.load (argv[2]); + + rtengine::ProcessingJob* job = ProcessingJob::create (ii, params); + rtengine::IImage16* res = rtengine::processImage (job, errorCode, &pl); + res->saveToFile (argv[3]); +} + diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc new file mode 100755 index 000000000..cfd51421a --- /dev/null +++ b/rtengine/rtthumbnail.cc @@ -0,0 +1,890 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +extern "C" { +#include +extern jmp_buf jpeg_jmp_buf; +extern GLOBAL(struct jpeg_error_mgr *) +my_jpeg_std_error (struct jpeg_error_mgr * err); +extern GLOBAL(void) +my_jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile); +} + +#define MAXVAL 0xffff +#define CLIP(a) ((a)>0?((a)load (fname); + if (err) { + delete img; + return NULL; + } + + Thumbnail* tpp = new Thumbnail (); + + tpp->camwbRed = 1.0; + tpp->camwbGreen = 1.0; + tpp->camwbBlue = 1.0; + + tpp->embProfileLength = 0; + unsigned char* data; + img->getEmbeddedProfileData (tpp->embProfileLength, data); + if (data && tpp->embProfileLength) { + tpp->embProfileData = new unsigned char [tpp->embProfileLength]; + memcpy (tpp->embProfileData, data, tpp->embProfileLength); + } + else { + tpp->embProfileLength = 0; + tpp->embProfileData = NULL; + } + + tpp->redMultiplier = 1.0; + tpp->greenMultiplier = 1.0; + tpp->blueMultiplier = 1.0; + + tpp->scaleForSave = 8192; + tpp->defGain = 1.0; + tpp->gammaCorrected = false; + tpp->isRaw = 0; + memset (tpp->colorMatrix, 0, sizeof(tpp->colorMatrix)); + tpp->colorMatrix[0][0] = 1.0; + tpp->colorMatrix[1][1] = 1.0; + tpp->colorMatrix[2][2] = 1.0; + + if (fixwh==1) { + w = h * img->width / img->height; + tpp->scale = (double)img->height / h; + } + else { + h = w * img->height / img->width; + tpp->scale = (double)img->width / w; + } + + // bilinear interpolation + tpp->thumbImg = img->resize (w, h, TI_Bilinear); + + // histogram computation + tpp->aeHistCompression = 3; + tpp->aeHistogram = new int[65536>>tpp->aeHistCompression]; + memset (tpp->aeHistogram, 0, (65536>>tpp->aeHistCompression)*sizeof(int)); + int ix = 0; + for (int i=0; iheight*img->width; i++) { + tpp->aeHistogram[CurveFactory::igamma_srgb (img->data[ix++])>>tpp->aeHistCompression]++; + tpp->aeHistogram[CurveFactory::igamma_srgb (img->data[ix++])>>tpp->aeHistCompression]++; + tpp->aeHistogram[CurveFactory::igamma_srgb (img->data[ix++])>>tpp->aeHistCompression]++; + } + + // autowb computation + double avg_r = 0; + double avg_g = 0; + double avg_b = 0; + int n = 0; + int p = 6; + for (int i=1; iheight-1; i++) + for (int j=1; jwidth-1; j++) { + int ofs = 3*(i*img->width + j); + if (img->data[ofs]>250 || img->data[ofs+1]>250 || img->data[ofs+2]>250) + continue; + avg_r += StdImageSource::intpow((double)img->data[ofs]*256, p); + avg_g += StdImageSource::intpow((double)img->data[ofs+1]*256, p); + avg_b += StdImageSource::intpow((double)img->data[ofs+2]*256, p); + n++; + } + ColorTemp::mul2temp (pow(avg_r/n, 1.0/p), pow(avg_g/n, 1.0/p), pow(avg_b/n, 1.0/p), tpp->autowbTemp, tpp->autowbGreen); + + delete img; + tpp->init (); + return tpp; +} + +void Thumbnail::init () { + + RawImageSource::inverse33 (colorMatrix, iColorMatrix); + memset (camToD50, 0, sizeof(camToD50)); + for (int i=0; i<3; i++) + for (int j=0; j<3; j++) + for (int k=0; k<3; k++) + camToD50[i][j] += colorMatrix[k][i] * sRGB_d50[k][j]; + camProfile = iccStore.createFromMatrix (camToD50, false, "Camera"); +} + +bool Thumbnail::igammacomputed = false; +unsigned short Thumbnail::igammatab[256]; +unsigned char Thumbnail::gammatab[65536]; + +Thumbnail::Thumbnail () : + embProfile(NULL), camProfile(NULL), aeHistogram(NULL), thumbImg(NULL), embProfileData(NULL) { + + if (!igammacomputed) { + for (int i=0; i<256; i++) + igammatab[i] = (unsigned short)(255.0*pow(i/255.0,1.0/0.45)); + for (int i=0; i<65536; i++) + gammatab[i] = (unsigned char)(255.0*pow(i/65535.0,0.45)); + igammacomputed = true; + } +} + +Thumbnail::~Thumbnail () { + + delete thumbImg; + delete [] aeHistogram; + delete [] embProfileData; + if (embProfile) + cmsCloseProfile(embProfile); + if (camProfile) + cmsCloseProfile(camProfile); +} + +IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rheight, TypeInterpolation interp, double& myscale) { + + // compute WB multipliers + ColorTemp currWB = ColorTemp (params.wb.temperature, params.wb.green); + if (params.wb.method=="Camera") { + double cam_r = colorMatrix[0][0]*camwbRed + colorMatrix[0][1]*camwbGreen + colorMatrix[0][2]*camwbBlue; + double cam_g = colorMatrix[1][0]*camwbRed + colorMatrix[1][1]*camwbGreen + colorMatrix[1][2]*camwbBlue; + double cam_b = colorMatrix[2][0]*camwbRed + colorMatrix[2][1]*camwbGreen + colorMatrix[2][2]*camwbBlue; + currWB = ColorTemp (cam_r, cam_g, cam_b); + } + else if (params.wb.method=="Auto") + currWB = ColorTemp (autowbTemp, autowbGreen); + double r, g, b; + currWB.getMultipliers (r, g, b); + double rm = iColorMatrix[0][0]*r + iColorMatrix[0][1]*g + iColorMatrix[0][2]*b; + double gm = iColorMatrix[1][0]*r + iColorMatrix[1][1]*g + iColorMatrix[1][2]*b; + double bm = iColorMatrix[2][0]*r + iColorMatrix[2][1]*g + iColorMatrix[2][2]*b; + rm = camwbRed / rm; + gm = camwbGreen / gm; + bm = camwbBlue / bm; + double mul_lum = 0.299*rm + 0.587*gm + 0.114*bm; + double logDefGain = log(defGain) / log(2.0); + int rmi, gmi, bmi; + if (!isRaw || !params.hlrecovery.enabled) { + logDefGain = 0.0; + rmi = 16384.0 * rm * defGain / mul_lum; + gmi = 16384.0 * gm * defGain / mul_lum; + bmi = 16384.0 * bm * defGain / mul_lum; + } + else { + rmi = 1024.0 * rm / mul_lum; + gmi = 1024.0 * gm / mul_lum; + bmi = 1024.0 * bm / mul_lum; + } + // resize to requested with and perform coarse transformation + int rwidth; + if (params.coarse.rotate==90 || params.coarse.rotate==270) { + rwidth = rheight; + rheight = thumbImg->height * rwidth / thumbImg->width; + } + else + rwidth = thumbImg->width * rheight / thumbImg->height; + + Image16* baseImg = thumbImg->resize (rwidth, rheight, interp); + + if (params.coarse.rotate) { + Image16* tmp = baseImg->rotate (params.coarse.rotate); + rwidth = tmp->width; + rheight = tmp->height; + delete baseImg; + baseImg = tmp; + } + if (params.coarse.hflip) { + Image16* tmp = baseImg->hflip (); + delete baseImg; + baseImg = tmp; + } + if (params.coarse.vflip) { + Image16* tmp = baseImg->vflip (); + delete baseImg; + baseImg = tmp; + } + // apply white balance + int val; + for (int i=0; ir[i][j]*rmi>>10; + baseImg->r[i][j] = CLIP(val); + val = baseImg->g[i][j]*gmi>>10; + baseImg->g[i][j] = CLIP(val); + val = baseImg->b[i][j]*bmi>>10; + baseImg->b[i][j] = CLIP(val); + } + + // appy highlight recovery, if needed + if (isRaw && params.hlrecovery.enabled) { + int maxval = 65535 / defGain; + if (params.hlrecovery.method=="Luminance" || params.hlrecovery.method=="Color") + for (int i=0; ir[i], baseImg->g[i], baseImg->b[i], baseImg->r[i], baseImg->g[i], baseImg->b[i], rwidth, maxval); + else if (params.hlrecovery.method=="CIELab blending") { + double icamToD50[3][3]; + RawImageSource::inverse33 (camToD50, icamToD50); + for (int i=0; ir[i], baseImg->g[i], baseImg->b[i], baseImg->r[i], baseImg->g[i], baseImg->b[i], rwidth, maxval, camToD50, icamToD50); + } + } + + // perform color space transformation + if (isRaw) + RawImageSource::colorSpaceConversion (baseImg, params.icm, embProfile, camProfile, camToD50, logDefGain); + else + StdImageSource::colorSpaceConversion (baseImg, params.icm, embProfile); + + int fw = baseImg->width; + int fh = baseImg->height; + + ImProcFunctions ipf; + int* hist16 = new int [65536]; + ipf.firstAnalysis (baseImg, ¶ms, hist16, isRaw ? 2.2 : 0.0); + + // perform transform + bool needstransform = fabs(params.rotate.degree)>1e-15 || fabs(params.distortion.amount)>1e-15 || fabs(params.cacorrection.red)>1e-15 || fabs(params.cacorrection.blue)>1e-15; + bool needsvignetting = params.vignetting.amount!=0; + + if (!needstransform && needsvignetting) { + Image16* trImg = new Image16 (fw, fh); + ipf.vignetting (baseImg, trImg, ¶ms, 0, 0, fw, fh); + delete baseImg; + baseImg = trImg; + } + else if (needstransform) { + Image16* trImg = new Image16 (fw, fh); + ipf.simpltransform (baseImg, trImg, ¶ms, 0, 0, 0, 0, fw, fh); + delete baseImg; + baseImg = trImg; + } + + // update blurmap + SHMap* shmap = NULL; + if (params.sh.enabled) { + unsigned short** buffer = NULL; + if (params.sh.hq) { + buffer = new unsigned short*[fh]; + for (int i=0; iupdate (baseImg, buffer, shradius, ipf.lumimul, params.sh.hq); + if (buffer) { + for (int i=0; iL[i][j]]++; + + // luminance processing + CurveFactory::updateCurve2 (curve, hist16, params.lumaCurve.curve, 0, params.lumaCurve.brightness, params.lumaCurve.black, params.lumaCurve.hlcompr, params.lumaCurve.shcompr, params.lumaCurve.contrast, 0.0, false); + ipf.luminanceCurve (labView, labView, curve, 0, fh); + + delete [] curve; + delete [] hist16; + + // color processing + ipf.colorCurve (labView, labView, ¶ms); + + // obtain final image + Image8* readyImg = new Image8 (fw, fh); + ipf.lab2rgb (labView, readyImg); + ipf.release (); + delete baseImg; + + // calculate scale + if (params.coarse.rotate==90 || params.coarse.rotate==270) + myscale = scale * thumbImg->width / fh; + else + myscale = scale * thumbImg->height / fh; + + if (params.resize.enabled) { + if (params.resize.dataspec==0) + myscale *= params.resize.scale; + else if (params.resize.dataspec==1) + myscale *= (double)params.resize.width / (params.coarse.rotate==90 || params.coarse.rotate==270 ? thumbImg->height : thumbImg->width) / scale; + else if (params.resize.dataspec==2) + myscale *= (double)params.resize.height / (params.coarse.rotate==90 || params.coarse.rotate==270 ? thumbImg->width : thumbImg->height) / scale; + } + myscale = 1.0 / myscale; + +/* // apply crop + if (params.crop.enabled) { + int ix = 0; + for (int i=0; i(params.crop.y+params.crop.h)/myscale || j(params.crop.x+params.crop.w)/myscale) { + readyImg->data[ix++] /= 3; + readyImg->data[ix++] /= 3; + readyImg->data[ix++] /= 3; + } + else + ix += 3; + }*/ + return readyImg; +} + +int Thumbnail::getImageWidth (const procparams::ProcParams& params, int rheight) { + + int rwidth; + if (params.coarse.rotate==90 || params.coarse.rotate==270) + rwidth = thumbImg->height * rheight / thumbImg->width; + else + rwidth = thumbImg->width * rheight / thumbImg->height; + + return rwidth; +} + +void Thumbnail::getFinalSize (const rtengine::procparams::ProcParams& params, int& fullw, int& fullh) { + + double fw = thumbImg->width*scale; + double fh = thumbImg->height*scale; + + if (params.coarse.rotate==90 || params.coarse.rotate==270) { + fh = thumbImg->width*scale; + fw = thumbImg->height*scale; + } + if (!params.resize.enabled) { + fullw = fw; + fullh = fh; + } + else if (params.resize.dataspec==0) { + fullw = fw*params.resize.scale; + fullh = fh*params.resize.scale; + } + else if (params.resize.dataspec==1) { + fullw = params.resize.width; + fullh = (double)fh*params.resize.width/(params.coarse.rotate==90 || params.coarse.rotate==270 ? fh : fw); + } + else if (params.resize.dataspec==2) { + fullw = (double)fw*params.resize.height/(params.coarse.rotate==90 || params.coarse.rotate==270 ? fw : fh); + fullh = params.resize.height; + } +} + +void Thumbnail::getCamWB (double& temp, double& green) { + + double cam_r = colorMatrix[0][0]*camwbRed + colorMatrix[0][1]*camwbGreen + colorMatrix[0][2]*camwbBlue; + double cam_g = colorMatrix[1][0]*camwbRed + colorMatrix[1][1]*camwbGreen + colorMatrix[1][2]*camwbBlue; + double cam_b = colorMatrix[2][0]*camwbRed + colorMatrix[2][1]*camwbGreen + colorMatrix[2][2]*camwbBlue; + ColorTemp currWB = ColorTemp (cam_r, cam_g, cam_b); + temp = currWB.getTemp (); + green = currWB.getGreen (); +} + +void Thumbnail::getAutoWB (double& temp, double& green) { + + temp = autowbTemp; + green = autowbGreen; +} + +void Thumbnail::applyAutoExp (procparams::ProcParams& params) { + + if (params.toneCurve.autoexp && aeHistogram) + ImProcFunctions::getAutoExp (aeHistogram, aeHistCompression, log(defGain) / log(2.0), params.toneCurve.clip, params.toneCurve.expcomp, params.toneCurve.black); +} + +void Thumbnail::getSpotWB (const procparams::ProcParams& params, int xp, int yp, int rect, double& rtemp, double& rgreen) { + + std::vector points, red, green, blue; + for (int i=yp-rect; i<=yp+rect; i++) + for (int j=xp-rect; j<=xp+rect; j++) + points.push_back (Coord2D (j, i)); + + int fw = thumbImg->width, fh = thumbImg->height; + if (params.coarse.rotate==90 || params.coarse.rotate==270) { + fw = thumbImg->height; + fh = thumbImg->width; + } + ImProcFunctions ipf; + ipf.transCoord (¶ms, fw, fh, points, red, green, blue); + int tr = TR_NONE; + if (params.coarse.rotate==90) tr |= TR_R90; + if (params.coarse.rotate==180) tr |= TR_R180; + if (params.coarse.rotate==270) tr |= TR_R270; + if (params.coarse.hflip) tr |= TR_HFLIP; + if (params.coarse.vflip) tr |= TR_VFLIP; + + // calculate spot wb (copy & pasted from stdimagesource) + unsigned short igammatab[256]; + for (int i=0; i<256; i++) + igammatab[i] = (unsigned short)(255.0*pow(i/255.0,1.0/0.45)); + int x; int y; + double reds = 0, greens = 0, blues = 0; + int rn = 0, gn = 0, bn = 0; + for (int i=0; i=0 && y>=0 && xwidth && yheight) { + reds += thumbImg->r[y][x]; + rn++; + } + transformPixel (green[i].x, green[i].y, tr, x, y); + if (x>=0 && y>=0 && xwidth && yheight) { + greens += thumbImg->g[y][x]; + gn++; + } + transformPixel (blue[i].x, blue[i].y, tr, x, y); + if (x>=0 && y>=0 && xwidth && yheight) { + blues += thumbImg->b[y][x]; + bn++; + } + } + reds = reds/rn * camwbRed; + greens = greens/gn * camwbGreen; + blues = blues/bn * camwbBlue; + + double rm = colorMatrix[0][0]*reds + colorMatrix[0][1]*greens + colorMatrix[0][2]*blues; + double gm = colorMatrix[1][0]*reds + colorMatrix[1][1]*greens + colorMatrix[1][2]*blues; + double bm = colorMatrix[2][0]*reds + colorMatrix[2][1]*greens + colorMatrix[2][2]*blues; + + ColorTemp ct (rm, gm, bm); + rtemp = ct.getTemp (); + rgreen = ct.getGreen (); +} +void Thumbnail::transformPixel (int x, int y, int tran, int& tx, int& ty) { + + int W = thumbImg->width; + int H = thumbImg->height; + int sw = W, sh = H; + if ((tran & TR_ROT) == TR_R90 || (tran & TR_ROT) == TR_R270) { + sw = H; + sh = W; + } + + int ppx = x, ppy = y; + if (tran & TR_HFLIP) + ppx = sw - 1 - x ; + if (tran & TR_VFLIP) + ppy = sh - 1 - y; + + tx = ppx; + ty = ppy; + + if ((tran & TR_ROT) == TR_R180) { + tx = W - 1 - ppx; + ty = H - 1 - ppy; + } + else if ((tran & TR_ROT) == TR_R90) { + tx = ppy; + ty = H - 1 - ppx; + } + else if ((tran & TR_ROT) == TR_R270) { + tx = W - 1 - ppy; + ty = ppx; + } + tx/=scale; + ty/=scale; +} + +bool Thumbnail::writeImage (const Glib::ustring& fname, int format) { + + if (!thumbImg) + return false; + + if (format==1 || format==3) { + // to utilize the 8 bit color range of the thumbnail we brighten it and apply gamma correction + int max = 0; + for (int row=0; rowheight; row++) + for (int col=0; colwidth; col++) { + if (thumbImg->r[row][col]>max) + max = thumbImg->r[row][col]; + if (thumbImg->g[row][col]>max) + max = thumbImg->r[row][col]; + if (thumbImg->b[row][col]>max) + max = thumbImg->r[row][col]; + } + if (max < 16384) + max = 16384; + scaleForSave = 65535*8192 / max; + unsigned char* tmpdata = new unsigned char[thumbImg->height*thumbImg->width*3]; + int ix = 0; + if (gammaCorrected) { + for (int i=0; iheight; i++) + for (int j=0; jwidth; j++) { + tmpdata[ix++] = gammatab[thumbImg->r[i][j]*scaleForSave >> 13]; + tmpdata[ix++] = gammatab[thumbImg->g[i][j]*scaleForSave >> 13]; + tmpdata[ix++] = gammatab[thumbImg->b[i][j]*scaleForSave >> 13]; + } + } + else { + for (int i=0; iheight; i++) + for (int j=0; jwidth; j++) { + tmpdata[ix++] = thumbImg->r[i][j]*scaleForSave >> 21; + tmpdata[ix++] = thumbImg->g[i][j]*scaleForSave >> 21; + tmpdata[ix++] = thumbImg->b[i][j]*scaleForSave >> 21; + } + } + if (format==1) { + FILE* f = g_fopen (fname.c_str(), "wb"); + if (!f) { + delete [] tmpdata; + return false; + } + fwrite (&thumbImg->width, 1, sizeof (int), f); + fwrite (&thumbImg->height, 1, sizeof (int), f); + fwrite (tmpdata, thumbImg->width*thumbImg->height, 3, f); + fclose (f); + } + else if (format==3) { + FILE* f = g_fopen (fname.c_str(), "wb"); + if (!f) { + delete [] tmpdata; + return false; + } + jpeg_compress_struct cinfo; + jpeg_error_mgr jerr; + cinfo.err = jpeg_std_error (&jerr); + jpeg_create_compress (&cinfo); + jpeg_stdio_dest (&cinfo, f); + cinfo.image_width = thumbImg->width; + cinfo.image_height = thumbImg->height; + cinfo.in_color_space = JCS_RGB; + cinfo.input_components = 3; + jpeg_set_defaults (&cinfo); + cinfo.write_JFIF_header = FALSE; + jpeg_set_quality (&cinfo, 85, true); + jpeg_start_compress(&cinfo, TRUE); + int rowlen = thumbImg->width*3; + while (cinfo.next_scanline < cinfo.image_height) { + unsigned char* row = tmpdata + cinfo.next_scanline*thumbImg->width*3; + if (jpeg_write_scanlines (&cinfo, &row, 1) < 1) { + jpeg_finish_compress (&cinfo); + jpeg_destroy_compress (&cinfo); + fclose (f); + delete [] tmpdata; + return false; + } + } + jpeg_finish_compress (&cinfo); + jpeg_destroy_compress (&cinfo); + fclose (f); + } + delete [] tmpdata; + return true; + } + else if (format==2) { + FILE* f = g_fopen (fname.c_str(), "wb"); + if (!f) + return false; + fwrite (&thumbImg->width, 1, sizeof (int), f); + fwrite (&thumbImg->height, 1, sizeof (int), f); + for (int i=0; iheight; i++) + fwrite (thumbImg->r[i], thumbImg->width, 2, f); + for (int i=0; iheight; i++) + fwrite (thumbImg->g[i], thumbImg->width, 2, f); + for (int i=0; iheight; i++) + fwrite (thumbImg->b[i], thumbImg->width, 2, f); + fclose (f); + return true; + } + else + return false; +} + +bool Thumbnail::readImage (const Glib::ustring& fname) { + + delete thumbImg; + thumbImg = NULL; + + int imgType = 0; + if (Glib::file_test (fname+".cust16", Glib::FILE_TEST_EXISTS)) + imgType = 2; + if (Glib::file_test (fname+".cust", Glib::FILE_TEST_EXISTS)) + imgType = 1; + else if (Glib::file_test (fname+".jpg", Glib::FILE_TEST_EXISTS)) + imgType = 3; + + if (!imgType) + return false; + else if (imgType==1) { + FILE* f = g_fopen ((fname+".cust").c_str(), "rb"); + if (!f) + return false; + int width, height; + fread (&width, 1, sizeof (int), f); + fread (&height, 1, sizeof (int), f); + unsigned char* tmpdata = new unsigned char [width*height*3]; + fread (tmpdata, width*height, 3, f); + fclose (f); + thumbImg = new Image16 (width, height); + int ix = 0, val; + for (int i=0; ir[i][j] = CLIP(val); + val = igammatab[tmpdata[ix++]]*256*8192/scaleForSave; + thumbImg->g[i][j] = CLIP(val); + val = igammatab[tmpdata[ix++]]*256*8192/scaleForSave; + thumbImg->b[i][j] = CLIP(val); + } + else { + val = tmpdata[ix++]*256*8192/scaleForSave; + thumbImg->r[i][j] = CLIP(val); + val = tmpdata[ix++]*256*8192/scaleForSave; + thumbImg->g[i][j] = CLIP(val); + val = tmpdata[ix++]*256*8192/scaleForSave; + thumbImg->b[i][j] = CLIP(val); + } + delete [] tmpdata; + return true; + } + else if (imgType==2) { + FILE* f = g_fopen ((fname+".cust16").c_str(), "rb"); + if (!f) + return false; + int width, height; + fread (&width, 1, sizeof (int), f); + fread (&height, 1, sizeof (int), f); + thumbImg = new Image16 (width, height); + for (int i=0; ir[i], width, 2, f); + for (int i=0; ig[i], width, 2, f); + for (int i=0; ib[i], width, 2, f); + fclose (f); + return true; + } + else if (imgType==3) { + FILE* f = g_fopen ((fname+".jpg").c_str(), "rb"); + if (!f) + return false; + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + if (!setjmp(jpeg_jmp_buf)) { + cinfo.err = my_jpeg_std_error (&jerr); + jpeg_create_decompress (&cinfo); + my_jpeg_stdio_src (&cinfo,f); + jpeg_read_header (&cinfo, TRUE); + int width, height; + width = cinfo.image_width; + height = cinfo.image_height; + cinfo.dct_method = JDCT_FASTEST; + cinfo.do_fancy_upsampling = 1; + jpeg_start_decompress(&cinfo); + thumbImg = new Image16 (width, height); + unsigned char* row = new unsigned char [width*3]; + while (cinfo.output_scanline < cinfo.output_height) { + jpeg_read_scanlines (&cinfo, &row, 1); + int ix = 0, val; + for (int j=0; jr[cinfo.output_scanline-1][j] = CLIP(val); + val = igammatab[row[ix++]]*256*8192/scaleForSave; + thumbImg->g[cinfo.output_scanline-1][j] = CLIP(val); + val = igammatab[row[ix++]]*256*8192/scaleForSave; + thumbImg->b[cinfo.output_scanline-1][j] = CLIP(val); + } + else { + val = row[ix++]*256*8192/scaleForSave; + thumbImg->r[cinfo.output_scanline-1][j] = CLIP(val); + val = row[ix++]*256*8192/scaleForSave; + thumbImg->g[cinfo.output_scanline-1][j] = CLIP(val); + val = row[ix++]*256*8192/scaleForSave; + thumbImg->b[cinfo.output_scanline-1][j] = CLIP(val); + } + } + } + jpeg_finish_decompress (&cinfo); + jpeg_destroy_decompress (&cinfo); + fclose (f); + delete [] row; + return true; + } + else { + fclose (f); + return false; + } + return true; + } +} + +bool Thumbnail::readData (const Glib::ustring& fname) { + + Glib::KeyFile keyFile; + + try { + if (!keyFile.load_from_file (fname)) + return false; + + if (keyFile.has_group ("LiveThumbData")) { + if (keyFile.has_key ("LiveThumbData", "CamWBRed")) camwbRed = keyFile.get_double ("LiveThumbData", "CamWBRed"); + if (keyFile.has_key ("LiveThumbData", "CamWBGreen")) camwbGreen = keyFile.get_double ("LiveThumbData", "CamWBGreen"); + if (keyFile.has_key ("LiveThumbData", "CamWBBlue")) camwbBlue = keyFile.get_double ("LiveThumbData", "CamWBBlue"); + if (keyFile.has_key ("LiveThumbData", "AutoWBTemp")) autowbTemp = keyFile.get_double ("LiveThumbData", "AutoWBTemp"); + if (keyFile.has_key ("LiveThumbData", "AutoWBGreen")) autowbGreen = keyFile.get_double ("LiveThumbData", "AutoWBGreen"); + if (keyFile.has_key ("LiveThumbData", "AEHistCompression")) aeHistCompression = keyFile.get_integer ("LiveThumbData", "AEHistCompression"); + if (keyFile.has_key ("LiveThumbData", "RedMultiplier")) redMultiplier = keyFile.get_double ("LiveThumbData", "RedMultiplier"); + if (keyFile.has_key ("LiveThumbData", "GreenMultiplier")) greenMultiplier = keyFile.get_double ("LiveThumbData", "GreenMultiplier"); + if (keyFile.has_key ("LiveThumbData", "BlueMultiplier")) blueMultiplier = keyFile.get_double ("LiveThumbData", "BlueMultiplier"); + if (keyFile.has_key ("LiveThumbData", "Scale")) scale = keyFile.get_double ("LiveThumbData", "Scale"); + if (keyFile.has_key ("LiveThumbData", "DefaultGain")) defGain = keyFile.get_double ("LiveThumbData", "DefaultGain"); + if (keyFile.has_key ("LiveThumbData", "ScaleForSave")) scaleForSave = keyFile.get_integer ("LiveThumbData", "ScaleForSave"); + if (keyFile.has_key ("LiveThumbData", "GammaCorrected")) gammaCorrected = keyFile.get_boolean ("LiveThumbData", "GammaCorrected"); + if (keyFile.has_key ("LiveThumbData", "ColorMatrix")) { + std::vector cm = keyFile.get_double_list ("LiveThumbData", "ColorMatrix"); + int ix = 0; + for (int i=0; i<3; i++) + for (int j=0; j<3; j++) + colorMatrix[i][j] = cm[ix++]; + } + } + return true; + } + catch (Glib::Error) { + return false; + } +} + +bool Thumbnail::writeData (const Glib::ustring& fname) { + + Glib::KeyFile keyFile; + + try { + keyFile.load_from_file (fname); + } catch (...) {} + + keyFile.set_double ("LiveThumbData", "CamWBRed", camwbRed); + keyFile.set_double ("LiveThumbData", "CamWBGreen", camwbGreen); + keyFile.set_double ("LiveThumbData", "CamWBBlue", camwbBlue); + keyFile.set_double ("LiveThumbData", "AutoWBTemp", autowbTemp); + keyFile.set_double ("LiveThumbData", "AutoWBGreen", autowbGreen); + keyFile.set_integer ("LiveThumbData", "AEHistCompression", aeHistCompression); + keyFile.set_double ("LiveThumbData", "RedMultiplier", redMultiplier); + keyFile.set_double ("LiveThumbData", "GreenMultiplier", greenMultiplier); + keyFile.set_double ("LiveThumbData", "BlueMultiplier", blueMultiplier); + keyFile.set_double ("LiveThumbData", "Scale", scale); + keyFile.set_double ("LiveThumbData", "DefaultGain", defGain); + keyFile.set_integer ("LiveThumbData", "ScaleForSave", scaleForSave); + keyFile.set_boolean ("LiveThumbData", "GammaCorrected", gammaCorrected); + Glib::ArrayHandle cm ((double*)colorMatrix, 9, Glib::OWNERSHIP_NONE); + keyFile.set_double_list ("LiveThumbData", "ColorMatrix", cm); + + FILE *f = g_fopen (fname.c_str(), "wt"); + if (!f) + return false; + else { + fprintf (f, "%s", keyFile.to_data().c_str()); + fclose (f); + return true; + } +} + +bool Thumbnail::readEmbProfile (const Glib::ustring& fname) { + + FILE* f = fopen (fname.c_str(), "rb"); + if (!f) { + embProfileData = NULL; + embProfile = NULL; + embProfileLength = 0; + } + else { + fseek (f, 0, SEEK_END); + embProfileLength = ftell (f); + fseek (f, 0, SEEK_SET); + embProfileData = new unsigned char[embProfileLength]; + fread (embProfileData, 1, embProfileLength, f); + fclose (f); + embProfile = cmsOpenProfileFromMem (embProfileData, embProfileLength); + return true; + } + return false; +} + +bool Thumbnail::writeEmbProfile (const Glib::ustring& fname) { + + if (embProfileLength) { + FILE* f = fopen (fname.c_str(), "wb"); + if (f) { + fwrite (embProfileData, 1, embProfileLength, f); + fclose (f); + return true; + } + } + return false; +} + +bool Thumbnail::readAEHistogram (const Glib::ustring& fname) { + + FILE* f = fopen (fname.c_str(), "rb"); + if (!f) + aeHistogram = NULL; + else { + aeHistogram = new int[65536>>aeHistCompression]; + fread (aeHistogram, 1, (65536>>aeHistCompression)*sizeof(int), f); + fclose (f); + return true; + } + return false; +} + +bool Thumbnail::writeAEHistogram (const Glib::ustring& fname) { + + if (aeHistogram) { + FILE* f = fopen (fname.c_str(), "wb"); + if (f) { + fwrite (aeHistogram, 1, (65536>>aeHistCompression)*sizeof(int), f); + fclose (f); + return true; + } + } + return false; +} + +} diff --git a/rtengine/rtthumbnail.h b/rtengine/rtthumbnail.h new file mode 100755 index 000000000..dfad657e4 --- /dev/null +++ b/rtengine/rtthumbnail.h @@ -0,0 +1,99 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _THUMBPROCESSINGPARAMETERS_ +#define _THUMBPROCESSINGPARAMETERS_ + +#include +#include +#include +#include +#include + +namespace rtengine { + + class Thumbnail { + + cmsHPROFILE camProfile; + double iColorMatrix[3][3]; + double camToD50[3][3]; + + + void transformPixel (int x, int y, int tran, int& tx, int& ty); + + static bool igammacomputed; + static unsigned short igammatab[256]; + static unsigned char gammatab[65536]; + + Image16* thumbImg; + double camwbRed; + double camwbGreen; + double camwbBlue; + double autowbTemp; + double autowbGreen; + int* aeHistogram; + int aeHistCompression; + int embProfileLength; + unsigned char* embProfileData; + cmsHPROFILE embProfile; + double redMultiplier; + double greenMultiplier; + double blueMultiplier; + double scale; + double defGain; + int scaleForSave; + bool gammaCorrected; + double colorMatrix[3][3]; + + public: + + bool isRaw; + + ~Thumbnail (); + Thumbnail (); + + void init (); + + IImage8* processImage (const procparams::ProcParams& pparams, int rheight, TypeInterpolation interp, double& scale); + int getImageWidth (const procparams::ProcParams& pparams, int rheight); + void getFinalSize (const rtengine::procparams::ProcParams& pparams, int& w, int& h); + + static Thumbnail* loadFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, int &w, int &h, int fixwh); + static Thumbnail* loadFromImage (const Glib::ustring& fname, int &w, int &h, int fixwh); + + void getCamWB (double& temp, double& green); + void getAutoWB (double& temp, double& green); + void getSpotWB (const procparams::ProcParams& params, int x, int y, int rect, double& temp, double& green); + void applyAutoExp (procparams::ProcParams& pparams); + + bool writeImage (const Glib::ustring& fname, int format); + bool readImage (const Glib::ustring& fname); + + bool readData (const Glib::ustring& fname); + bool writeData (const Glib::ustring& fname); + + bool readEmbProfile (const Glib::ustring& fname); + bool writeEmbProfile (const Glib::ustring& fname); + + bool readAEHistogram (const Glib::ustring& fname); + bool writeAEHistogram (const Glib::ustring& fname); + }; +} + +#endif + diff --git a/rtengine/settings.h b/rtengine/settings.h new file mode 100755 index 000000000..e9ba64fd1 --- /dev/null +++ b/rtengine/settings.h @@ -0,0 +1,45 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _RTSETTINGS_ +#define _RTSETTINGS_ + +namespace rtengine { + + /** This structure holds the global parameters used by the RT engine. */ + class Settings { + public: + bool dualThreadEnabled; ///< If true, the image processing operations with utilize two processor cores (if possible) + std::string demosaicMethod; ///< The algorithm used for demosaicing. Can be "eahd", "hphd" or "vng4". + int colorCorrectionSteps; ///< The number of color correction steps applied right after the demosaicing + Glib::ustring iccDirectory; ///< The directory containing the possible output icc profiles + int colorimetricIntent; ///< Colorimetric intent used at color space conversions + Glib::ustring monitorProfile; ///< ICC profile of the monitor (full path recommended) + bool verbose; + + /** Creates a new instance of Settings. + * @return a pointer to the new Settings instance. */ + static Settings* create (); + /** Destroys an instance of Settings. + * @param s a pointer to the Settings instance to destroy. */ + static void destroy (Settings* s); + }; +} + +#endif + diff --git a/rtengine/shmap.cc b/rtengine/shmap.cc new file mode 100755 index 000000000..f0e4579d4 --- /dev/null +++ b/rtengine/shmap.cc @@ -0,0 +1,135 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include + +#undef THREAD_PRIORITY_NORMAL +#define MAXVAL 0xffff +#define CLIP(a) ((a)>0?((a)r[i][j] + lumi[1]*img->g[i][j] + lumi[2]*img->b[i][j]; + map[i][j] = CLIP(val); + } + +//MyTime t1,t2; +//t1.set (); + + if (!hq) { + + AlignedBuffer* buffer1 = new AlignedBuffer (MAX(W,H)*5); + AlignedBuffer* buffer2 = new AlignedBuffer (MAX(W,H)*5); + + // blur + if (settings->dualThreadEnabled) { + Glib::Thread *thread1 = Glib::Thread::create(sigc::bind(sigc::ptr_fun(gaussHorizontal_unsigned), map, map, buffer1, W, 0, H/2, radius), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + Glib::Thread *thread2 = Glib::Thread::create(sigc::bind(sigc::ptr_fun(gaussHorizontal_unsigned), map, map, buffer2, W, H/2, H, radius), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread1->join (); + thread2->join (); + thread1 = Glib::Thread::create(sigc::bind(sigc::ptr_fun(gaussVertical_unsigned), map, map, buffer1, H, 0, W/2, radius), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread2 = Glib::Thread::create(sigc::bind(sigc::ptr_fun(gaussVertical_unsigned), map, map, buffer2, H, W/2, W, radius), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread1->join (); + thread2->join (); + } + else { + gaussHorizontal_unsigned (map, map, buffer1, W, 0, H, radius); + gaussVertical_unsigned (map, map, buffer1, H, 0, W, radius); + } + + delete buffer1; + delete buffer2; + } + else { + if (settings->dualThreadEnabled) { + bilateralparams r1, r2; + r1.row_from = 0; + r1.row_to = H/2; + r2.row_from = H/2; + r2.row_to = H; + Glib::Thread *thread1 = Glib::Thread::create(sigc::bind(sigc::ptr_fun(bilateral_box_unsigned), map, buffer, W, H, 8000, radius, r1), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + Glib::Thread *thread2 = Glib::Thread::create(sigc::bind(sigc::ptr_fun(bilateral_box_unsigned), map, buffer, W, H, 8000, radius, r2), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread1->join (); + thread2->join (); + } + else { + bilateralparams r1; + r1.row_from = 0; + r1.row_to = H; + bilateral_box_unsigned (map, buffer, W, H, 8000, radius, r1); + } + for (int i=0; i0 && j>0 && i max) + max = val; + _avg = 1.0/n * val + (1.0 - 1.0/n) * _avg; + n++; + } + avg = (int) _avg; +} + +void SHMap::forceStat (unsigned short max_, unsigned short min_, unsigned short avg_) { + + max = max_; + min = min_; + avg = avg_; +} } + diff --git a/rtengine/shmap.h b/rtengine/shmap.h new file mode 100755 index 000000000..1a7b6064e --- /dev/null +++ b/rtengine/shmap.h @@ -0,0 +1,40 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef __SHMAP__ +#define __SHMAP__ + +#include + +namespace rtengine { + +class SHMap { + + public: + int W, H; + unsigned short** map; + unsigned short max, min, avg; + + SHMap (int w, int h); + ~SHMap (); + + void update (Image16* img, unsigned short** buffer, double radius, double lumi[3], bool hq); + void forceStat (unsigned short max_, unsigned short min_, unsigned short avg_); +}; +}; +#endif diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc new file mode 100755 index 000000000..3f008c870 --- /dev/null +++ b/rtengine/simpleprocess.cc @@ -0,0 +1,229 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include +#include +#include +#include +#include + +namespace rtengine { + +IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* pl) { + + errorCode = 0; + + ProcessingJobImpl* job = (ProcessingJobImpl*) pjob; + + if (pl) { + pl->setProgressStr ("Processing..."); + pl->setProgress (0.0); + } + + InitialImage* ii = job->initialImage; + if (!ii) { + ii = InitialImage::load (job->fname, job->isRaw, &errorCode); + if (errorCode) { + ii->decreaseRef (); + delete job; + return NULL; + } + } + procparams::ProcParams& params = job->pparams; + + // aquire image from imagesource + ImageSource* imgsrc = ii->getImageSource (); + ColorTemp currWB = ColorTemp (params.wb.temperature, params.wb.green); + if (params.wb.method=="Camera") + currWB = imgsrc->getWB (); + else if (params.wb.method=="Auto") + currWB = imgsrc->getAutoWB (); + + int tr = TR_NONE; + if (params.coarse.rotate==90) tr |= TR_R90; + if (params.coarse.rotate==180) tr |= TR_R180; + if (params.coarse.rotate==270) tr |= TR_R270; + if (params.coarse.hflip) tr |= TR_HFLIP; + if (params.coarse.vflip) tr |= TR_VFLIP; + + int fw, fh; + imgsrc->getFullSize (fw, fh, tr); + + ImProcFunctions ipf; + + Image16* baseImg; + PreviewProps pp (0, 0, fw, fh, 1); + if (fabs(params.resize.scale-1.0)<1e-5) { + baseImg = new Image16 (fw, fh); + imgsrc->getImage (currWB, tr, baseImg, pp, params.hlrecovery, params.icm); + } + else { + Image16* oorig = new Image16 (fw, fh); + imgsrc->getImage (currWB, tr, oorig, pp, params.hlrecovery, params.icm); + fw *= params.resize.scale; + fh *= params.resize.scale; + baseImg = new Image16 (fw, fh); + ipf.resize (oorig, baseImg, params.resize); + delete oorig; + } + if (pl) + pl->setProgress (0.25); + + // perform first analysis + int* hist16 = new int[65536]; + ipf.firstAnalysis (baseImg, ¶ms, hist16, imgsrc->getGamma()); + + // perform transform + bool needstransform = fabs(params.rotate.degree)>1e-15 || fabs(params.distortion.amount)>1e-15 || fabs(params.cacorrection.red)>1e-15 || fabs(params.cacorrection.blue)>1e-15; + bool needsvignetting = params.vignetting.amount!=0; + + if (!needstransform && needsvignetting) { + Image16* trImg = new Image16 (fw, fh); + ipf.vignetting (baseImg, trImg, ¶ms, 0, 0, fw, fh); + delete baseImg; + baseImg = trImg; + } + else if (needstransform) { + Image16* trImg = new Image16 (fw, fh); + ipf.transform (baseImg, trImg, ¶ms, 0, 0, 0, 0, fw, fh); + delete baseImg; + baseImg = trImg; + } + + // update blurmap + int** buffer = new int*[fh]; + for (int i=0; iupdate (baseImg, (unsigned short**)buffer, shradius, ipf.lumimul, params.sh.hq); + } + // RGB processing +//!!!// auto exposure!!! + double br = params.toneCurve.expcomp; + int bl = params.toneCurve.black; + + if (params.toneCurve.autoexp) { + int aehist[65536]; int aehistcompr; + imgsrc->getAEHistogram (aehist, aehistcompr); + ipf.getAutoExp (aehist, aehistcompr, imgsrc->getDefGain(), params.toneCurve.clip, br, bl); + } + + int* curve = new int [65536]; + CurveFactory::updateCurve3 (curve, hist16, params.toneCurve.curve, imgsrc->getDefGain(), br, bl, params.toneCurve.hlcompr, params.toneCurve.shcompr, params.toneCurve.brightness, params.toneCurve.contrast, imgsrc->getGamma(), true); + + LabImage* labView = new LabImage (baseImg); + ipf.rgbProc (baseImg, labView, ¶ms, curve, shmap); + + if (shmap) + delete shmap; + + if (pl) + pl->setProgress (0.5); + + // luminance histogram update + memset (hist16, 0, 65536*sizeof(int)); + for (int i=0; iL[i][j]]++; + + // luminance processing + CurveFactory::updateCurve2 (curve, hist16, params.lumaCurve.curve, 0, params.lumaCurve.brightness, params.lumaCurve.black, params.lumaCurve.hlcompr, params.lumaCurve.shcompr, params.lumaCurve.contrast, 0.0, false); + ipf.luminanceCurve (labView, labView, curve, 0, fh); + ipf.lumadenoise (labView, ¶ms, 1, buffer); + ipf.sharpening (labView, ¶ms, 1, (unsigned short**)buffer); + + delete [] curve; + delete [] hist16; + + // color processing + ipf.colorCurve (labView, labView, ¶ms); + ipf.colordenoise (labView, ¶ms, 1, buffer); + + for (int i=0; isetProgress (0.75); + + // obtain final image + Image16* readyImg; + int cx = 0, cy = 0, cw = labView->W, ch = labView->H; + if (params.crop.enabled) { + cx = params.crop.x; + cy = params.crop.y; + cw = params.crop.w; + ch = params.crop.h; + } + readyImg = ipf.lab2rgb16 (labView, cx, cy, cw, ch, params.icm.output); + ipf.release (); + + if (pl) + pl->setProgress (1.0); + + readyImg->setMetadata (ii->getMetaData()->getExifData (), params.exif, params.iptc); + + ProfileContent pc; + if (params.icm.output.compare (0, 6, "No ICM") && params.icm.output!="") + pc = iccStore.getContent (params.icm.output); + + readyImg->setOutputProfile (pc.data, pc.length); + + delete baseImg; + + if (!job->initialImage) + ii->decreaseRef (); + + delete job; + + if (pl) { + pl->setProgress (1.0); + pl->setProgressStr ("Ready."); + } + + return readyImg; +} + +void batchProcessingThread (ProcessingJob* job, BatchProcessingListener* bpl) { + + ProcessingJob* currentJob = job; + + while (currentJob) { + int errorCode; + IImage16* img = processImage (currentJob, errorCode, bpl); + if (errorCode) + bpl->error ("Can not load input image."); + currentJob = bpl->imageReady (img); + } +} + +void startBatchProcessing (ProcessingJob* job, BatchProcessingListener* bpl) { + + if (bpl) + Glib::Thread::create(sigc::bind(sigc::ptr_fun(batchProcessingThread), job, bpl), 0, false, true, Glib::THREAD_PRIORITY_NORMAL); +} + +} diff --git a/rtengine/sizes.txt b/rtengine/sizes.txt new file mode 100755 index 000000000..a207aaca4 --- /dev/null +++ b/rtengine/sizes.txt @@ -0,0 +1,24 @@ +sizes of procparams: + + ToneCurveParams 53+3 + CurveParams 36 + SharpeningParams 68 + ColorBoostParams 24 + WBParams 16 + ColorShiftParams 16 + LumaDenoiseParams 16 + ColorDenoiseParams 20 + SHParams 28 + CropParams 36 + CoarseTransformParams 12 + RotateParams 12 + DistortionParams 8 + CACorrParams 16 + VignettingParams 8 + ChannelMixerParams 36 + HRecParams 8 + ResizeParams 12 + ColorManagementParams 16 + std::vector 12 + std::vector 12 + diff --git a/rtengine/stdimagesource.cc b/rtengine/stdimagesource.cc new file mode 100755 index 000000000..101b7013e --- /dev/null +++ b/rtengine/stdimagesource.cc @@ -0,0 +1,546 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#define MAXVAL 0xffff +#define CLIP(a) ((a)>0?((a) + +#undef THREAD_PRIORITY_NORMAL + +namespace rtengine { + +extern const Settings* settings; + +template void freeArray (T** a, int H) { + for (int i=0; i T** allocArray (int W, int H) { + + T** t = new T*[H]; + for (int i=0; iheight/HR_SCALE; + freeArray(hrmap[0], dh); + freeArray(hrmap[1], dh); + freeArray(hrmap[2], dh); + } + + delete img; + + if (needhr) + freeArray(needhr, img->height); +} + +int StdImageSource::load (Glib::ustring fname) { + + fileName = fname; + + img = new Image16 (); + if (plistener) { + plistener->setProgressStr ("Loading..."); + plistener->setProgress (0.0); + img->setProgressListener (plistener); + } + + int error = img->load (fname); + if (error) { + delete img; + img = NULL; + return error; + } + + embProfile = img->getEmbeddedProfile (); + idata = new ImageData (fname); + + if (plistener) { + plistener->setProgressStr ("Ready."); + plistener->setProgress (1.0); + } + + wb = ColorTemp (1.0, 1.0, 1.0); + + return 0; +} + +void StdImageSource::transform (PreviewProps pp, int tran, int &sx1, int &sy1, int &sx2, int &sy2) { + + int W = img->width; + int H = img->height; + int sw = W, sh = H; + if ((tran & TR_ROT) == TR_R90 || (tran & TR_ROT) == TR_R270) { + sw = H; + sh = W; + } + int ppx = pp.x, ppy = pp.y; + if (tran & TR_HFLIP) + ppx = sw - pp.x - pp.w; + if (tran & TR_VFLIP) + ppy = sh - pp.y - pp.h; + + sx1 = ppx; + sy1 = ppy; + sx2 = ppx + pp.w; + sy2 = ppy + pp.h; + + if ((tran & TR_ROT) == TR_R180) { + sx1 = W - ppx - pp.w; + sy1 = H - ppy - pp.h; + sx2 = sx1 + pp.w; + sy2 = sy1 + pp.h; + } + else if ((tran & TR_ROT) == TR_R90) { + sx1 = ppy; + sy1 = H - ppx - pp.w; + sx2 = sx1 + pp.h; + sy2 = sy1 + pp.w; + } + else if ((tran & TR_ROT) == TR_R270) { + sx1 = W - ppy - pp.h; + sy1 = ppx; + sx2 = sx1 + pp.h; + sy2 = sy1 + pp.w; + } + printf ("ppx %d ppy %d ppw %d pph %d s: %d %d %d %d\n",pp.x, pp.y,pp.w,pp.h,sx1,sy1,sx2,sy2); +} + +void StdImageSource::getImage_ (ColorTemp ctemp, int tran, Image16* image, PreviewProps pp, bool first, HRecParams hrp) { + + // compute channel multipliers + double rm, gm, bm; + ctemp.getMultipliers (rm, gm, bm); + rm = 1.0 / rm; + gm = 1.0 / gm; + bm = 1.0 / bm; + double mul_lum = 0.299*rm + 0.587*gm + 0.114*bm; + rm /= mul_lum; + gm /= mul_lum; + bm /= mul_lum; + + int sx1, sy1, sx2, sy2; + transform (pp, tran, sx1, sy1, sx2, sy2); + + int imwidth = (sx2 - sx1) / pp.skip + ((sx2 - sx1) % pp.skip > 0); + int imheight = (sy2 - sy1) / pp.skip + ((sy2 - sy1) % pp.skip > 0); + + int istart = sy1, iend = sy2, ix = 0; + if (first) { + iend = istart; + while (iend<(sy1+sy2)/2) { + iend+=pp.skip; + } + } + else { + while (istart<(sy1+sy2)/2) { + ix++; + istart+=pp.skip; + } + } + + int mtran = tran; + int skip = pp.skip; + + unsigned short* red = new unsigned short[imwidth]; + unsigned short* grn = new unsigned short[imwidth]; + unsigned short* blue = new unsigned short[imwidth]; + + for (int i=istart; ir[i][jx]; + grn[j] = img->g[i][jx]; + blue[j] = img->b[i][jx]; + } +// if (hrp.enabled) +// hlRecovery (red, grn, blue, i, sx1, sx2, pp.skip); + + if ((mtran & TR_ROT) == TR_R180) + for (int j=0; jr[imheight-1-ix][imwidth-1-j] = (int)CLIP(rm*red[j]); + image->g[imheight-1-ix][imwidth-1-j] = (int)CLIP(gm*grn[j]); + image->b[imheight-1-ix][imwidth-1-j] = (int)CLIP(bm*blue[j]); + } + else if ((mtran & TR_ROT) == TR_R90) + for (int j=0,jx=sx1; jr[j][imheight-1-ix] = (int)CLIP(rm*red[j]); + image->g[j][imheight-1-ix] = (int)CLIP(gm*grn[j]); + image->b[j][imheight-1-ix] = (int)CLIP(bm*blue[j]); + } + else if ((mtran & TR_ROT) == TR_R270) + for (int j=0,jx=sx1; jr[imwidth-1-j][ix] = (int)CLIP(rm*red[j]); + image->g[imwidth-1-j][ix] = (int)CLIP(gm*grn[j]); + image->b[imwidth-1-j][ix] = (int)CLIP(bm*blue[j]); + } + else { + for (int j=0,jx=sx1; jr[ix][j] = (int)CLIP(rm*red[j]); + image->g[ix][j] = (int)CLIP(gm*grn[j]); + image->b[ix][j] = (int)CLIP(bm*blue[j]); + } + } + } + + delete [] red; + delete [] grn; + delete [] blue; +} + +void StdImageSource::getImage (ColorTemp ctemp, int tran, Image16* image, PreviewProps pp, HRecParams hrp, ColorManagementParams cmp) { + + MyTime t1,t2; + + t1.set (); + +// if (hrp.enabled==true && hrmap[0]==NULL) +// updateHLRecoveryMap (); + if (settings->dualThreadEnabled) { + Glib::Thread *thread1 = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &StdImageSource::getImage_), ctemp, tran, image, pp, true, hrp), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + Glib::Thread *thread2 = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &StdImageSource::getImage_), ctemp, tran, image, pp, false, hrp), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + thread1->join (); + thread2->join (); + } + else { + getImage_ (ctemp, tran, image, pp, true, hrp); + getImage_ (ctemp, tran, image, pp, false, hrp); + } + + colorSpaceConversion (image, cmp, embProfile); + + // Flip if needed + if (tran & TR_HFLIP) + hflip (image); + if (tran & TR_VFLIP) + vflip (image); + + t2.set (); +} + +void StdImageSource::colorSpaceConversion (Image16* im, ColorManagementParams cmp, cmsHPROFILE embedded) { + + cmsHPROFILE in; + cmsHPROFILE out = iccStore.workingSpace (cmp.working); + if (cmp.input=="(embedded)" || cmp.input=="" || cmp.input=="(camera)") { + if (embedded) + in = embedded; + else + in = iccStore.getsRGBProfile (); + } + else if (cmp.input!="(none)") { + in = iccStore.getProfile (cmp.input); + if (in==NULL && embedded) + in = embedded; + else if (in==NULL) + in = iccStore.getsRGBProfile (); + else if (cmp.gammaOnInput) + for (int i=0; iheight; i++) + for (int j=0; jwidth; j++) { + im->r[i][j] = CurveFactory::gamma (im->r[i][j]); + im->g[i][j] = CurveFactory::gamma (im->g[i][j]); + im->b[i][j] = CurveFactory::gamma (im->b[i][j]); + } + } + + if (cmp.input!="(none)") { + lcmsMutex->lock (); + cmsHTRANSFORM hTransform = cmsCreateTransform (in, TYPE_RGB_16_PLANAR, out, TYPE_RGB_16_PLANAR, settings->colorimetricIntent, 0); + lcmsMutex->unlock (); + cmsDoTransform (hTransform, im->data, im->data, im->planestride/2); + cmsDeleteTransform(hTransform); + } +} + +void StdImageSource::getFullSize (int& w, int& h, int tr) { + + w = img->width; + h = img->height; + if ((tr & TR_ROT) == TR_R90 || (tr & TR_ROT) == TR_R270) { + w = img->height; + h = img->width; + } +} + +void StdImageSource::getSize (int tran, PreviewProps pp, int& w, int& h) { + + w = pp.w / pp.skip + (pp.w % pp.skip > 0); + h = pp.h / pp.skip + (pp.h % pp.skip > 0); +} + +void StdImageSource::hflip (Image16* image) { + int width = image->width; + int height = image->height; + + unsigned short* rowr = new unsigned short[width]; + unsigned short* rowg = new unsigned short[width]; + unsigned short* rowb = new unsigned short[width]; + for (int i=0; ir[i][width-1-j]; + rowg[j] = image->g[i][width-1-j]; + rowb[j] = image->b[i][width-1-j]; + } + memcpy (image->r[i], rowr, width*sizeof(unsigned short)); + memcpy (image->g[i], rowg, width*sizeof(unsigned short)); + memcpy (image->b[i], rowb, width*sizeof(unsigned short)); + } + delete [] rowr; + delete [] rowg; + delete [] rowb; +} + +void StdImageSource::vflip (Image16* image) { + int width = image->width; + int height = image->height; + + register unsigned short tmp; + for (int i=0; ir[i][j]; + image->r[i][j] = image->r[height-1-i][j]; + image->r[height-1-i][j] = tmp; + tmp = image->g[i][j]; + image->g[i][j] = image->g[height-1-i][j]; + image->g[height-1-i][j] = tmp; + tmp = image->b[i][j]; + image->b[i][j] = image->b[height-1-i][j]; + image->b[height-1-i][j] = tmp; + } +} +/* +void hlRecovery (unsigned short* red, unsigned short* green, unsigned short* blue, int H, int W, int i, int sx1, int sx2, int skip, char** needhr, float** hrmap[3]); +void hlmultipliers (int** rec[3], int max[3], int dh, int dw); + +void StdImageSource::updateHLRecoveryMap () { + + // detect maximal pixel values + int maxr = 0, maxg = 0, maxb = 0; + for (int i=32; iheight-32; i++) + for (int j=32; jwidth-32; j++) { + if (img->r[i][j] > maxr) maxr = img->r[i][j]; + if (img->g[i][j] > maxg) maxg = img->g[i][j]; + if (img->b[i][j] > maxb) maxb = img->b[i][j]; + } + + maxr = maxr * 19 / 20; + maxg = maxg * 19 / 20; + maxb = maxb * 19 / 20; + max[0] = maxr; + max[1] = maxg; + max[2] = maxb; + + // downscale image + int dw = img->width/HR_SCALE; + int dh = img->height/HR_SCALE; + Image16* ds = new Image16 (dw, dh); + + // overburnt areas + int** rec[3]; + for (int i=0; i<3; i++) + rec[i] = allocArray (dw, dh); + + if (needhr) + freeArray(needhr, img->height); + needhr = allocArray (img->width, img->height); + + for (int i=0; iheight; i++) + for (int j=0; jwidth; j++) + if (img->r[i][j]>=max[0] || img->g[i][j]>=max[1] || img->b[i][j]>=max[2]) + needhr[i][j] = 1; + else + needhr[i][j] = 0; + + + for (int i=0; iheight; i++) + for (int j=0; jwidth; j++) { + int sumr = 0; int cr = 0; + int sumg = 0; int cg = 0; + int sumb = 0; int cb = 0; + for (int x=0; xr[ix][jy]; + if (img->r[ix][jy] < maxr) cr++; + sumg += img->g[ix][jy]; + if (img->g[ix][jy] < maxg) cg++; + sumb += img->b[ix][jy]; + if (img->b[ix][jy] < maxb) cb++; + } + if (crr[i][j] = sumr / HR_SCALE/HR_SCALE; + ds->g[i][j] = sumg / HR_SCALE/HR_SCALE; + ds->b[i][j] = sumb / HR_SCALE/HR_SCALE; + + } + + hlmultipliers (rec, max, dh, dw); + + if (hrmap[0]!=NULL) { + freeArray (hrmap[0], dh); + freeArray (hrmap[1], dh); + freeArray (hrmap[2], dh); + } + + hrmap[0] = allocArray (dw, dh); + hrmap[1] = allocArray (dw, dh); + hrmap[2] = allocArray (dw, dh); + + for (int i=0; ir[i][j]>0 ? (double)rec[0][i][j] / ds->r[i][j] : 1.0; + hrmap[1][i][j] = ds->g[i][j]>0 ? (double)rec[1][i][j] / ds->g[i][j] : 1.0; + hrmap[2][i][j] = ds->b[i][j]>0 ? (double)rec[2][i][j] / ds->b[i][j] : 1.0; + } + + delete ds; + + freeArray (rec[0], dh); + freeArray (rec[1], dh); + freeArray (rec[2], dh); +} + +void StdImageSource::hlRecovery (unsigned short* red, unsigned short* green, unsigned short* blue, int i, int sx1, int sx2, int skip) { + + rtengine::hlRecovery (red, green, blue, img->height, img->width, i, sx1, sx2, skip, needhr, hrmap); +} +*/ +int StdImageSource::getAEHistogram (int* histogram, int& histcompr) { + + histcompr = 3; + + memset (histogram, 0, (65536>>histcompr)*sizeof(int)); + + for (int i=0; iheight; i++) + for (int j=0; jwidth; j++) { + histogram[CurveFactory::igamma_srgb (img->r[i][j])>>histcompr]++; + histogram[CurveFactory::igamma_srgb (img->g[i][j])>>histcompr]++; + histogram[CurveFactory::igamma_srgb (img->b[i][j])>>histcompr]++; + } + return 1; +} + +ColorTemp StdImageSource::getAutoWB () { + + double avg_r = 0; + double avg_g = 0; + double avg_b = 0; + int n = 0; + int p = 6; + + for (int i=1; iheight-1; i++) + for (int j=1; jwidth-1; j++) { + if (img->r[i][j]>64000 || img->g[i][j]>64000 || img->b[i][j]>64000) + continue; + avg_r += intpow((double)img->r[i][j], p); + avg_g += intpow((double)img->g[i][j], p); + avg_b += intpow((double)img->b[i][j], p); + n++; + } + return ColorTemp (pow(avg_r/n, 1.0/p), pow(avg_g/n, 1.0/p), pow(avg_b/n, 1.0/p)); +} + +void StdImageSource::transformPixel (int x, int y, int tran, int& tx, int& ty) { + + int W = img->width; + int H = img->height; + int sw = W, sh = H; + if ((tran & TR_ROT) == TR_R90 || (tran & TR_ROT) == TR_R270) { + sw = H; + sh = W; + } + + int ppx = x, ppy = y; + if (tran & TR_HFLIP) + ppx = sw - 1 - x ; + if (tran & TR_VFLIP) + ppy = sh - 1 - y; + + tx = ppx; + ty = ppy; + + if ((tran & TR_ROT) == TR_R180) { + tx = W - 1 - ppx; + ty = H - 1 - ppy; + } + else if ((tran & TR_ROT) == TR_R90) { + tx = ppy; + ty = H - 1 - ppx; + } + else if ((tran & TR_ROT) == TR_R270) { + tx = W - 1 - ppy; + ty = ppx; + } +} + +ColorTemp StdImageSource::getSpotWB (std::vector red, std::vector green, std::vector& blue, int tran) { + + int x; int y; + double reds = 0, greens = 0, blues = 0; + int rn = 0, gn = 0, bn = 0; + for (int i=0; i=0 && y>=0 && xwidth && yheight) { + reds += img->r[y][x]; +// img->r[y][x]=0; // debug!!! + rn++; + } + transformPixel (green[i].x, green[i].y, tran, x, y); + if (x>=0 && y>=0 && xwidth && yheight) { + greens += img->g[y][x]; +// img->g[y][x]=0; // debug!!! + gn++; + } + transformPixel (blue[i].x, blue[i].y, tran, x, y); + if (x>=0 && y>=0 && xwidth && yheight) { + blues += img->b[y][x]; +// img->b[y][x]=0; // debug!!! + bn++; + } + } + double img_r, img_g, img_b; + wb.getMultipliers (img_r, img_g, img_b); + printf ("AVG: %g %g %g\n", reds/rn, greens/gn, blues/bn); + + return ColorTemp (reds/rn*img_r, greens/gn*img_g, blues/bn*img_b); +} +} + diff --git a/rtengine/stdimagesource.h b/rtengine/stdimagesource.h new file mode 100755 index 000000000..488597d76 --- /dev/null +++ b/rtengine/stdimagesource.h @@ -0,0 +1,73 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _STDIMAGESOURCE_ +#define _STDIMAGESOURCE_ + +#include + +namespace rtengine { + +class StdImageSource : public ImageSource { + + protected: + Image16* img; + ColorTemp wb; + ProgressListener* plistener; + bool full; + float** hrmap[3]; + char** needhr; + int max[3]; + + void updateHLRecoveryMap (); + void hlRecovery (unsigned short* red, unsigned short* green, unsigned short* blue, int i, int sx1, int sx2, int skip); + void transform (PreviewProps pp, int tran, int &sx1, int &sy1, int &sx2, int &sy2); + void transformPixel (int x, int y, int tran, int& tx, int& ty); + + public: + StdImageSource (); + ~StdImageSource (); + + int load (Glib::ustring fname); + void getImage (ColorTemp ctemp, int tran, Image16* image, PreviewProps pp, HRecParams hrp, ColorManagementParams cmp); + ColorTemp getWB () { return wb; } + ColorTemp getAutoWB (); + ColorTemp getSpotWB (std::vector red, std::vector green, std::vector& blue, int tran); + + int getAEHistogram (int* histogram, int& histcompr); + + double getDefGain () { return 0.0; } + double getGamma () { return 0.0; } + + void getFullSize (int& w, int& h, int tr = TR_NONE); + void getSize (int tran, PreviewProps pp, int& w, int& h); + + ImageData* getImageData () { return idata; } + void setProgressListener (ProgressListener* pl) { plistener = pl; } + static void colorSpaceConversion (Image16* im, ColorManagementParams cmp, cmsHPROFILE embedded); + + + static inline double intpow (double a, int b) { double r = 1.0; for (int i=0; i + * + * 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 + +Updater::Updater () : + change (0), + ipc (NULL), + pl (NULL), + running (false) +{ +} + +ProcParams* Updater::changing (int what) { + + mutex.lock (); + change |= what; + return ¶ms; +} + +void Updater::changed () { + + mutex.unlock (); + startProcessing (); +} + +void Updater::clearState () { + + mutex.lock (); + change = 0; + mutex.unlock (); +} + +ProcParams* Updater::getParams () { + + return ¶ms; +} + +void Updater::startProcessing () { + + #undef THREAD_PRIORITY_NORMAL + + tstart.lock (); + if (ipc && !running) { + running = true; + tstart.unlock (); + Glib::Thread::create(sigc::mem_fun(*this, &Updater::process), 0, false, true, Glib::THREAD_PRIORITY_NORMAL); + } + else + tstart.unlock (); +} + +void Updater::process () { + + processing.lock (); + if (pl) + pl->setProcessingState (true); + + int ch; + + mutex.lock (); + while (change && ipc) { + ipc->params.copy (¶ms); + ch = change; + change = 0; + mutex.unlock (); + if (ch<=16384) + ipc->update (ch); + mutex.lock (); + } + mutex.unlock (); + tstart.lock (); + running = false; + tstart.unlock (); + + if (pl) + pl->setProcessingState (false); + processing.unlock (); +} + +void Updater::stop () { + + if (running) { + change = 0; + processing.lock (); + processing.unlock (); + + } +} + diff --git a/rtengine/updater.h b/rtengine/updater.h new file mode 100755 index 000000000..550e73f5f --- /dev/null +++ b/rtengine/updater.h @@ -0,0 +1,57 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _UPDATER_ +#define _UPDATER_ + +#include +#include +#include +#include + +class Updater { + + protected: + int change; + ProcParams params; + Glib::Mutex mutex; + Glib::Mutex tstart; + Glib::Mutex processing; + ImProcCoordinator* ipc; + ProgressListener* pl; + bool running; + + public: + + Updater (); + void setProgressListener (ProgressListener* l) { pl = l; } + void setIPC (ImProcCoordinator* ipc) { this->ipc = ipc; } + + ProcParams* changing (int what); + void changed (); + void clearState (); + int getClear (); + ProcParams* getParams (); + int getChange (); + void startProcessing (); + void process (); + + void stop (); +}; + +#endif diff --git a/rtengine/utils.cc b/rtengine/utils.cc new file mode 100755 index 000000000..cefd38bec --- /dev/null +++ b/rtengine/utils.cc @@ -0,0 +1,144 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include + +namespace rtengine { + +void bilinearInterp (const unsigned char* src, int sw, int sh, unsigned char* dst, int dw, int dh) { + + int ix = 0; + for (int i=0; i=sh) sy = sh-1; + double dy = (double)i*sh/dh - sy; + int ny = sy+1; + if (ny>=sh) ny = sy; + int or1 = 3*sw*sy; + int or2 = 3*sw*ny; + for (int j=0; j=sw) sx = sw; + double dx = (double)j*sw/dw - sx; + int nx = sx+1; + if (nx>=sw) nx = sx; + int ofs11 = or1 + 3*sx; + int ofs12 = or1 + 3*nx; + int ofs21 = or2 + 3*sx; + int ofs22 = or2 + 3*nx; + unsigned int val = src[ofs11]*(1-dx)*(1-dy) + src[ofs12]*dx*(1-dy) + src[ofs21]*(1-dx)*dy + src[ofs22]*dx*dy; + dst[ix++] = val; + ofs11++; ofs12++; ofs21++; ofs22++; + val = src[ofs11]*(1-dx)*(1-dy) + src[ofs12]*dx*(1-dy) + src[ofs21]*(1-dx)*dy + src[ofs22]*dx*dy; + dst[ix++] = val; + ofs11++; ofs12++; ofs21++; ofs22++; + val = src[ofs11]*(1-dx)*(1-dy) + src[ofs12]*dx*(1-dy) + src[ofs21]*(1-dx)*dy + src[ofs22]*dx*dy; + dst[ix++] = val; + } + } +} + +void nearestInterp (const unsigned char* src, int sw, int sh, unsigned char* dst, int dw, int dh) { + + int ix = 0; + for (int i=0; i + * + * 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 . + */ +#ifndef _SIMPLEUTILS_ +#define _SIMPLEUTILS_ + +namespace rtengine { + +void bilinearInterp (const unsigned char* src, int sw, int sh, unsigned char* dst, int dw, int dh); +void nearestInterp (const unsigned char* src, int sw, int sh, unsigned char* dst, int dw, int dh); +void rotate (unsigned char* img, int& w, int& h, int deg); +void hflip (unsigned char* img, int w, int h); +void vflip (unsigned char* img, int w, int h); + +} +#endif diff --git a/rtexif/CMakeLists.txt b/rtexif/CMakeLists.txt new file mode 100755 index 000000000..320a21a50 --- /dev/null +++ b/rtexif/CMakeLists.txt @@ -0,0 +1,10 @@ +include_directories (.) +add_library (rtexif rtexif.cc stdattribs.cc nikonattribs.cc canonattribs.cc + pentaxattribs.cc fujiattribs.cc sonyminoltaattribs.cc olympusattribs.cc) + +IF (WIN32) + set_target_properties (rtexif PROPERTIES COMPILE_FLAGS "-O3 -ffast-math -fexpensive-optimizations") +ELSE (WIN32) + set_target_properties (rtexif PROPERTIES COMPILE_FLAGS "-O3 -ffast-math -fexpensive-optimizations -fPIC") +ENDIF (WIN32) + \ No newline at end of file diff --git a/rtexif/canonattribs.cc b/rtexif/canonattribs.cc new file mode 100755 index 000000000..f02465ab7 --- /dev/null +++ b/rtexif/canonattribs.cc @@ -0,0 +1,812 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _CANONATTRIBS_ +#define _CANONATTRIBS_ + +#include +#include +#include +#include +#include +#include + +namespace rtexif { + +class CAIntSerNumInterpreter : public Interpreter { + public: + CAIntSerNumInterpreter () {} + virtual std::string toString (Tag* t) { return ""; } +}; + +CAIntSerNumInterpreter caIntSerNumInterpreter; + +class CAFocalLengthInterpreter : public Interpreter { + public: + CAFocalLengthInterpreter () {} + virtual std::string toString (Tag* t) { + std::ostringstream str; + str << "FocalType = " << t->toInt(0,SHORT) << std::endl; + str << "FocalLength = " << t->toInt(2,SHORT) << std::endl; + str << "FocalPlaneXSize = " << t->toInt(4,SHORT) << std::endl; + str << "FocalPlaneYSize = " << t->toInt(6,SHORT); + return str.str(); + } +}; +CAFocalLengthInterpreter caFocalLengthInterpreter; + + +class CACameraSettingsInterpreter : public Interpreter { + std::map machoices; + std::map qlchoices; + std::map fmchoices; + std::map cdchoices; + std::map fochoices; + std::map rmchoices; + std::map ischoices; + std::map mmchoices; + std::map dzchoices; + std::map emchoices; + std::map frchoices; + std::map afchoices; + std::map exchoices; + std::map fcchoices; + std::map aechoices; + std::map stchoices; + std::map smchoices; + std::map pechoices; + std::map mfchoices; + std::map choices; + public: + CACameraSettingsInterpreter () { + machoices[1] = "Macro"; + machoices[2] = "Normal"; + qlchoices[1] = "Economy"; + qlchoices[2] = "Normal"; + qlchoices[3] = "Fine"; + qlchoices[4] = "RAW"; + qlchoices[5] = "Superfine"; + fmchoices[0] = "Off"; + fmchoices[1] = "Auto"; + fmchoices[2] = "On"; + fmchoices[3] = "Red-eye reduction"; + fmchoices[4] = "Slow-sync"; + fmchoices[5] = "Red-eye reduction (Auto)"; + fmchoices[6] = "Red-eye reduction (On)"; + fmchoices[16] = "External flash"; + cdchoices[0] = "Single"; + cdchoices[1] = "Continuous"; + cdchoices[2] = "Movie"; + cdchoices[3] = "Continuous, Speed Priority"; + cdchoices[4] = "Continuous, Low"; + cdchoices[5] = "Continuous, High"; + fochoices[0] = "One-shot AF"; + fochoices[1] = "AI Servo AF"; + fochoices[2] = "AI Focus AF"; + fochoices[3] = "Manual Focus"; + fochoices[4] = "Single"; + fochoices[5] = "Continuous"; + fochoices[6] = "Manual Focus"; + fochoices[16] = "Pan Focus"; + rmchoices[1] = "JPEG"; + rmchoices[2] = "CRW+THM"; + rmchoices[3] = "AVI+THM"; + rmchoices[4] = "TIF"; + rmchoices[5] = "TIF+JPEG"; + rmchoices[6] = "CR2"; + rmchoices[7] = "CR2+JPEG"; + ischoices[0] = "Large"; + ischoices[1] = "Medium"; + ischoices[2] = "Small"; + ischoices[5] = "Medium 1"; + ischoices[6] = "Medium 2"; + ischoices[7] = "Medium 3"; + ischoices[8] = "Postcard"; + ischoices[9] = "Widescreen"; + emchoices[0] = "Full auto "; + emchoices[1] = "Manual "; + emchoices[2] = "Landscape "; + emchoices[3] = "Fast shutter "; + emchoices[4] = "Slow shutter "; + emchoices[5] = "Night "; + emchoices[6] = "Gray Scale "; + emchoices[7] = "Sepia "; + emchoices[8] = "Portrait "; + emchoices[9] = "Sports "; + emchoices[10] = "Macro "; + emchoices[11] = "Black & White"; + emchoices[12] = "Pan focus"; + emchoices[13] = "Vivid"; + emchoices[14] = "Neutral"; + emchoices[15] = "Flash Off"; + emchoices[16] = "Long Shutter"; + emchoices[17] = "Super Macro"; + emchoices[18] = "Foliage"; + emchoices[19] = "Indoor"; + emchoices[20] = "Fireworks"; + emchoices[21] = "Beach"; + emchoices[22] = "Underwater"; + emchoices[23] = "Snow"; + emchoices[24] = "Kids & Pets"; + emchoices[25] = "Night Snapshot"; + emchoices[26] = "Digital Macro"; + emchoices[27] = "My Colors"; + emchoices[28] = "Still Image"; + emchoices[30] = "Color Accent"; + emchoices[31] = "Color Swap"; + emchoices[32] = "Aquarium"; + emchoices[33] = "ISO 3200"; + dzchoices[0] = "None"; + dzchoices[1] = "2x"; + dzchoices[2] = "4x"; + dzchoices[3] = "Other"; + mmchoices[0] = "Default"; + mmchoices[1] = "Spot"; + mmchoices[2] = "Average"; + mmchoices[3] = "Evaluative"; + mmchoices[4] = "Partial"; + mmchoices[5] = "Center-weighted averaging"; + frchoices[0] = "Manual"; + frchoices[1] = "Auto"; + frchoices[2] = "Not Known"; + frchoices[3] = "Macro"; + frchoices[4] = "Very Close"; + frchoices[5] = "Close"; + frchoices[6] = "Middle Range"; + frchoices[7] = "Far Range"; + frchoices[8] = "Pan Focus"; + frchoices[9] = "Super Macro"; + frchoices[10] = "Infinity"; + afchoices[0x2005] = "Manual AF point selection "; + afchoices[0x3000] = "None (MF)"; + afchoices[0x3001] = "Auto AF point selection "; + afchoices[0x3002] = "Right "; + afchoices[0x3003] = "Center "; + afchoices[0x3004] = "Left "; + afchoices[0x4001] = "Auto AF point selection "; + afchoices[0x4006] = "Face Detect"; + exchoices[0] = "Easy"; + exchoices[1] = "Program AE"; + exchoices[2] = "Shutter speed priority AE"; + exchoices[3] = "Aperture-priority AE"; + exchoices[4] = "Manual"; + exchoices[5] = "Depth-of-field AE"; + exchoices[6] = "M-Dep"; + fcchoices[0] = "Single"; + fcchoices[1] = "Continuous"; + aechoices[0] = "Normal AE"; + aechoices[1] = "Exposure Compensation"; + aechoices[2] = "AE Lock"; + aechoices[3] = "AE Lock + Exposure Comp."; + aechoices[4] = "No AE"; + stchoices[0] = "Off"; + stchoices[1] = "On"; + stchoices[2] = "On, Shot Only"; + stchoices[3] = "On, Panning"; + smchoices[0] = "Center"; + smchoices[1] = "AF Point"; + pechoices[0] = "Off"; + pechoices[1] = "Vivid"; + pechoices[2] = "Neutral"; + pechoices[3] = "Smooth"; + pechoices[4] = "Sepia"; + pechoices[5] = "B&W"; + pechoices[6] = "Custom"; + pechoices[100] = "My Color Data"; + mfchoices[0] = "N/A"; + mfchoices[0x500] = "Full"; + mfchoices[0x502] = "Medium"; + mfchoices[0x504] = "Low"; + mfchoices[0x7fff] = "N/A"; + choices[1] = "Canon EF 50mm f/1.8"; + choices[2] = "Canon EF 28mm f/2.8"; + choices[3] = "Canon EF 135mm f/2.8 Soft"; + choices[4] = "Sigma UC Zoom 35-135mm f/4-5.6"; + choices[6] = "Tokina AF193-2 19-35mm f/3.5-4.5 or Sigma Lens"; + choices[7] = "Canon EF 100-300mm F5.6L"; + choices[10] = "Canon EF 50mm f/2.5 Macro or Sigma"; + choices[11] = "Canon EF 35mm f/2"; + choices[13] = "Canon EF 15mm f/2.8"; + choices[21] = "Canon EF 80-200mm f/2.8L"; + choices[22] = "Tokina AT-X280AF PRO 28-80mm F2.8 ASPHERICAL"; + choices[26] = "Canon EF 100mm f/2.8 Macro or Cosina 100mm f/3.5 Macro AF or Tamron"; + choices[28] = "Tamron AF Aspherical 28-200mm f/3.8-5.6 or 28-75mm f/2.8 or 28-105mm f/2.8"; + choices[29] = "Canon EF 50mm f/1.8 MkII"; + choices[31] = "Tamron SP AF 300mm f/2.8 LD IF"; + choices[32] = "Canon EF 24mm f/2.8 or Sigma 15mm f/2.8 EX Fisheye"; + choices[39] = "Canon EF 75-300mm f/4-5.6"; + choices[40] = "Canon EF 28-80mm f/3.5-5.6"; + choices[43] = "Canon EF 28-105mm f/4-5.6"; + choices[45] = "Canon EF-S 18-55mm f/3.5-5.6"; + choices[48] = "Canon EF-S 18-55mm f/3.5-5.6 IS"; + choices[49] = "Canon EF-S 55-250mm f/4-5.6 IS"; + choices[124] = "Canon MP-E 65mm f/2.8 1-5x Macro Photo"; + choices[125] = "Canon TS-E 24mm f/3.5L"; + choices[126] = "Canon TS-E 45mm f/2.8"; + choices[127] = "Canon TS-E 90mm f/2.8"; + choices[130] = "Canon EF 50mm f/1.0L"; + choices[131] = "Sigma 17-35mm f2.8-4 EX Aspherical HSM"; + choices[134] = "Canon EF 600mm f/4L IS"; + choices[135] = "Canon EF 200mm f/1.8L"; + choices[136] = "Canon EF 300mm f/2.8L"; + choices[137] = "Canon EF 85mm f/1.2L"; + choices[139] = "Canon EF 400mm f/2.8L"; + choices[141] = "Canon EF 500mm f/4.5L"; + choices[142] = "Canon EF 300mm f/2.8L IS"; + choices[143] = "Canon EF 500mm f/4L IS"; + choices[149] = "Canon EF 100mm f/2"; + choices[150] = "Canon EF 14mm f/2.8L or Sigma 20mm EX f/1.8"; + choices[151] = "Canon EF 200mm f/2.8L"; + choices[152] = "Sigma Lens (various models)"; + choices[153] = "Canon EF 35-350mm f/3.5-5.6L or Tamron or Sigma Bigma"; + choices[155] = "Canon EF 85mm f/1.8 USM"; + choices[156] = "Canon EF 28-105mm f/3.5-4.5 USM"; + choices[160] = "Canon EF 20-35mm f/3.5-4.5 USM"; + choices[161] = "Canon EF 28-70mm f/2.8L or Sigma 24-70mm EX f/2.8 or Tamron 90mm f/2.8"; + choices[162] = "Canon EF 200mm f/2.8L"; + choices[163] = "Canon EF 300mm f/4L"; + choices[164] = "Canon EF 400mm f/5.6L"; + choices[165] = "Canon EF 70-200mm f/2.8 L"; + choices[166] = "Canon EF 70-200mm f/2.8 L + x1.4"; + choices[167] = "Canon EF 70-200mm f/2.8 L + x2"; + choices[168] = "Canon EF 28mm f/1.8 USM"; + choices[169] = "Canon EF17-35mm f/2.8L or Sigma Lens"; + choices[170] = "Canon EF 200mm f/2.8L II"; + choices[171] = "Canon EF 300mm f/4L"; + choices[172] = "Canon EF 400mm f/5.6L"; + choices[173] = "Canon EF 180mm Macro f/3.5L or Sigma 180mm F3.5 or 150mm f/2.8 Macro"; + choices[174] = "Canon EF 135mm f/2L"; + choices[175] = "Canon EF 400mm f/2.8L"; + choices[176] = "Canon EF 24-85mm f/3.5-4.5 USM"; + choices[177] = "Canon EF 300mm f/4L IS"; + choices[178] = "Canon EF 28-135mm f/3.5-5.6 IS"; + choices[179] = "Canon EF 24mm f/1.4L USM"; + choices[180] = "Canon EF 35mm f/1.4L"; + choices[181] = "Canon EF 100-400mm f/4.5-5.6L IS + x1.4"; + choices[182] = "Canon EF 100-400mm f/4.5-5.6L IS + x2"; + choices[183] = "Canon EF 100-400mm f/4.5-5.6L IS"; + choices[184] = "Canon EF 400mm f/2.8L + x2"; + choices[185] = "Canon EF 600mm f/4L IS"; + choices[186] = "Canon EF 70-200mm f/4L"; + choices[187] = "Canon EF 70-200mm f/4L + 1.4x"; + choices[188] = "Canon EF 70-200mm f/4L + 2x"; + choices[189] = "Canon EF 70-200mm f/4L + 2.8x"; + choices[190] = "Canon EF 100mm f/2.8 Macro"; + choices[191] = "Canon EF 400mm f/4 DO IS"; + choices[193] = "Canon EF 35-80mm f/4-5.6 USM"; + choices[194] = "Canon EF 80-200mm f/4.5-5.6 USM"; + choices[195] = "Canon EF 35-105mm f/4.5-5.6 USM"; + choices[196] = "Canon EF 75-300mm f/4-5.6 USM"; + choices[197] = "Canon EF 75-300mm f/4-5.6 IS"; + choices[198] = "Canon EF 50mm f/1.4 USM"; + choices[199] = "Canon EF 28-80mm f/3.5-5.6 USM"; + choices[200] = "Canon EF 75-300mm f/4-5.6 USM"; + choices[201] = "Canon EF 28-80mm f/3.5-5.6 USM"; + choices[202] = "Canon EF 28-80 f/3.5-5.6 USM IV"; + choices[208] = "Canon EF 22-55mm f/4-5.6 USM"; + choices[209] = "Canon EF 55-200mm f/4.5-5.6"; + choices[210] = "Canon EF 28-90mm f/4-5.6 USM"; + choices[211] = "Canon EF 28-200mm f/3.5-5.6"; + choices[213] = "Canon EF 90-300mm f/4.5-5.6"; + choices[214] = "Canon EF-S 18-55mm f/3.5-4.5 USM"; + choices[215] = "Canon EF 55-200mm f/4.5-5.6 II USM"; + choices[224] = "Canon EF 70-200mm f/2.8L IS USM"; + choices[225] = "Canon EF 70-200mm f/2.8L IS USM + x1.4"; + choices[226] = "Canon EF 70-200mm f/2.8L IS USM + x2"; + choices[229] = "Canon EF 16-35mm f/2.8L"; + choices[230] = "Canon EF 24-70mm f/2.8L"; + choices[231] = "Canon EF 17-40mm f/4L"; + choices[232] = "Canon EF 70-300mm f/4.5-5.6 DO IS USM"; + choices[234] = "Canon EF-S 17-85mm f4-5.6 IS USM"; + choices[235] = "Canon EF-S10-22mm F3.5-4.5 USM"; + choices[236] = "Canon EF-S60mm F2.8 Macro USM"; + choices[237] = "Canon EF 24-105mm f/4L IS"; + choices[238] = "Canon EF 70-300mm f/4-5.6 IS USM"; + choices[239] = "Canon EF 85mm f/1.2L II USM"; + choices[240] = "Canon EF-S 17-55mm f/2.8 IS USM"; + choices[241] = "Canon EF 50mm f/1.2L USM"; + choices[242] = "Canon EF 70-200mm f/4L IS USM"; + choices[243] = "Canon EF 70-200mm f/4L IS + 1.4x"; + choices[244] = "Canon EF 70-200mm f/4L IS + 2x"; + choices[245] = "Canon EF 70-200mm f/4L IS + 2.8x"; + choices[246] = "Canon EF 16-35mm f/2.8L II"; + choices[247] = "Canon EF 14mm f/2.8L II USM"; + } + virtual std::string toString (Tag* t) { + std::ostringstream str; + str << "MacroMode = " << machoices[t->toInt(2,SHORT)] << std::endl; + str << "Self-timer = " << t->toInt(4,SHORT) << std::endl; + str << "Quality = " << qlchoices[t->toInt(6,SHORT)] << std::endl; + str << "CanonFlashMode = " << fmchoices[t->toInt(8,SHORT)] << std::endl; + str << "ContinuousDrive = " << cdchoices[t->toInt(10,SHORT)] << std::endl; + str << "FocusMode = " << fochoices[t->toInt(14,SHORT)] << std::endl; + str << "RecordMode = " << rmchoices[t->toInt(18,SHORT)] << std::endl; + str << "CanonImageSize = " << ischoices[t->toInt(20,SHORT)] << std::endl; + str << "EasyMode = " << emchoices[t->toInt(22,SHORT)] << std::endl; + str << "DigitalZoom = " << dzchoices[t->toInt(24,SHORT)] << std::endl; + str << "Contrast = " << t->toInt(26,SHORT) << std::endl; + str << "Saturation = " << t->toInt(28,SHORT) << std::endl; + str << "Sharpness = " << t->toInt(30,SHORT) << std::endl; + str << "CameraISO = " << t->toInt(32,SHORT) << std::endl; + str << "MeteringMode = " << mmchoices[t->toInt(34,SHORT)] << std::endl; + str << "FocusRange = " << frchoices[t->toInt(36,SHORT)] << std::endl; + str << "AFPoint = " << afchoices[t->toInt(38,SHORT)] << std::endl; + str << "CanonExposureMode = " << exchoices[t->toInt(40,SHORT)] << std::endl; + str << "LensType = " << choices[t->toInt(44,SHORT)] << " (" << t->toInt(44,SHORT) << ")" << std::endl; + str << "LongFocal = " << (double)t->toInt(46,SHORT)/t->toInt(50,SHORT) << " mm" << std::endl; + str << "ShortFocal = " << (double)t->toInt(48,SHORT)/t->toInt(50,SHORT) << " mm" << std::endl; + str << "FocalUnits = " << t->toInt(50,SHORT) << std::endl; + str << "MaxAperture = " << pow (2, t->toInt(52,SHORT)/64.0) << std::endl; + str << "MinAperture = " << pow (2, t->toInt(54,SHORT)/64.0) << std::endl; + str << "FlashActivity = " << t->toInt(56,SHORT) << std::endl; + str << "FlashBits = "; + int f = t->toInt(58,SHORT); + if (f&1) + str << "Manual "; + if (f&2) + str << "TTL "; + if (f&4) + str << "A-TTL "; + if (f&8) + str << "E-TTL "; + if (f&16) + str << "FP sync enabled "; + if (f&(1<<7)) + str << "2nd-curtain sync used "; + if (f&(1<<11)) + str << "FP sync used "; + if (f&(1<<13)) + str << "Built-in "; + if (f&(1<<14)) + str << "External "; + str << std::endl; + str << "FocusContinuous = " << fcchoices[t->toInt(64,SHORT)] << std::endl; + str << "AESetting = " << aechoices[t->toInt(66,SHORT)] << std::endl; + str << "ImageStabilization = " << stchoices[t->toInt(68,SHORT)] << " (" << t->toInt(68,SHORT) << ")" << std::endl; + str << "DisplayAperture = " << t->toInt(70,SHORT) << std::endl; + str << "ZoomSourceWidth = " << t->toInt(72,SHORT) << std::endl; + str << "ZoomTargetWidth = " << t->toInt(74,SHORT) << std::endl; + str << "SpotMeteringMode = " << smchoices[t->toInt(78,SHORT)] << std::endl; + str << "PhotoEffect = " << pechoices[t->toInt(80,SHORT)] << std::endl; + str << "ManualFlashOutput = " << mfchoices[t->toInt(82,SHORT)] << std::endl; + str << "ColorTone = " << t->toInt(84,SHORT); + return str.str(); + } +}; +CACameraSettingsInterpreter caCameraSettingsInterpreter; + + +class CAProcessingInfoInterpreter : public Interpreter { + std::map tcchoices; + std::map sfchoices; + std::map wbchoices; + std::map pschoices; + public: + CAProcessingInfoInterpreter () { + tcchoices[0] = "Standard"; + tcchoices[1] = "Manual"; + tcchoices[2] = "Custom"; + sfchoices[0] = "N/A"; + sfchoices[1] = "Lowest"; + sfchoices[2] = "Low"; + sfchoices[3] = "Standard"; + sfchoices[4] = "High"; + sfchoices[5] = "Highest"; + wbchoices[0] = "Auto"; + wbchoices[1] = "Daylight"; + wbchoices[2] = "Cloudy"; + wbchoices[3] = "Tungsten"; + wbchoices[4] = "Fluorescent"; + wbchoices[5] = "Flash"; + wbchoices[6] = "Custom"; + wbchoices[7] = "Black & White"; + wbchoices[8] = "Shade"; + wbchoices[9] = "Manual Temperature (Kelvin)"; + wbchoices[10] = "PC Set1"; + wbchoices[11] = "PC Set2"; + wbchoices[12] = "PC Set3"; + wbchoices[14] = "Daylight Fluorescent"; + wbchoices[15] = "Custom 1"; + wbchoices[16] = "Custom 2"; + wbchoices[17] = "Underwater"; + pschoices[0] = "None"; + pschoices[1] = "Standard "; + pschoices[2] = "Set 1"; + pschoices[3] = "Set 2"; + pschoices[4] = "Set 3"; + pschoices[0x21] = "User Def. 1"; + pschoices[0x22] = "User Def. 2"; + pschoices[0x23] = "User Def. 3"; + pschoices[0x41] = "External 1"; + pschoices[0x42] = "External 2"; + pschoices[0x43] = "External 3"; + pschoices[0x81] = "Standard"; + pschoices[0x82] = "Portrait"; + pschoices[0x83] = "Landscape"; + pschoices[0x84] = "Neutral"; + pschoices[0x85] = "Faithful"; + pschoices[0x86] = "Monochrome"; + } + virtual std::string toString (Tag* t) { + std::ostringstream str; + str << "ToneCurve = " << tcchoices[t->toInt(2,SHORT)] << std::endl; + str << "Sharpness = " << t->toInt(4,SHORT) << std::endl; + str << "SharpnessFrequency = " << sfchoices[t->toInt(6,SHORT)] << std::endl; + str << "SensorRedLevel = " << t->toInt(8,SHORT) << std::endl; + str << "SensorBlueLevel = " << t->toInt(10,SHORT) << std::endl; + str << "WhiteBalanceRed = " << t->toInt(12,SHORT) << std::endl; + str << "WhiteBalanceBlue = " << t->toInt(14,SHORT) << std::endl; + str << "WhiteBalance = " << wbchoices[t->toInt(16,SHORT)] << std::endl; + str << "ColorTemperature = " << t->toInt(18,SHORT) << std::endl; + str << "PictureStyle = " << pschoices[t->toInt(20,SHORT)] << std::endl; + str << "DigitalGain = " << t->toInt(22,SHORT) << std::endl; + str << "WBShiftAB = " << t->toInt(24,SHORT) << std::endl; + str << "WBShiftGM = " << t->toInt(26,SHORT); + return str.str(); + } +}; +CAProcessingInfoInterpreter caProcessingInfoInterpreter; + +class CAShotInfoInterpreter : public Interpreter { + std::map sschoices; + std::map afchoices; + std::map aechoices; + std::map wbchoices; + std::map ctchoices; + std::map cmchoices; + std::map archoices; + std::map ndchoices; + public: + CAShotInfoInterpreter () { + sschoices[0] = "Off"; + sschoices[1] = "Night Scene"; + sschoices[2] = "On"; + sschoices[3] = "None"; + afchoices[0x3000] = "None (MF)"; + afchoices[0x3001] = "Right"; + afchoices[0x3002] = "Center"; + afchoices[0x3003] = "Center+Right"; + afchoices[0x3004] = "Left"; + afchoices[0x3005] = "Left+Right"; + afchoices[0x3006] = "Left+Center"; + afchoices[0x3007] = "All"; + wbchoices[0] = "Auto"; + wbchoices[1] = "Daylight"; + wbchoices[2] = "Cloudy"; + wbchoices[3] = "Tungsten"; + wbchoices[4] = "Fluorescent"; + wbchoices[5] = "Flash"; + wbchoices[6] = "Custom"; + wbchoices[7] = "Black & White"; + wbchoices[8] = "Shade"; + wbchoices[9] = "Manual Temperature (Kelvin)"; + wbchoices[10] = "PC Set1"; + wbchoices[11] = "PC Set2"; + wbchoices[12] = "PC Set3"; + wbchoices[14] = "Daylight Fluorescent"; + wbchoices[15] = "Custom 1"; + wbchoices[16] = "Custom 2"; + wbchoices[17] = "Underwater"; + aechoices[-1] = "On "; + aechoices[0] = "Off "; + aechoices[1] = "On (shot 1)"; + aechoices[2] = "On (shot 2)"; + aechoices[3] = "On (shot 3)"; + cmchoices[0] = "n/a"; + cmchoices[1] = "Camera Local Control"; + cmchoices[3] = "Computer Remote Control"; + ctchoices[248] = "EOS High-end"; + ctchoices[250] = "Compact"; + ctchoices[252] = "EOS Mid-end"; + ctchoices[255] = "DV Camera"; + ctchoices[0x23] = "User Def. 3"; + archoices[-1] = "Rotated by Software"; + archoices[0] = "None"; + archoices[1] = "Rotate 90 CW"; + archoices[2] = "Rotate 180"; + archoices[3] = "Rotate 270 CW"; + ndchoices[0] = "Off"; + ndchoices[1] = "On"; + } + virtual std::string toString (Tag* t) { + std::ostringstream str; + str << "AutoISO = " << t->toInt(2,SHORT) << std::endl; + str << "BaseISO = " << pow (2, t->toInt(4,SHORT)/32.0 - 4) * 50 << std::endl; + str << "MeasuredEV = " << t->toInt(6,SHORT) << std::endl; + str << "TargetAperture = " << pow (2, t->toInt(8,SHORT)/64.0) << std::endl; + str << "TargetExposureTime = " << pow (2, -t->toInt(10,SHORT)/32.0) << std::endl; + str << "ExposureCompensation = " << t->toInt(12,SHORT)/32.0 << std::endl; + str << "WhiteBalance = " << wbchoices[t->toInt(14,SHORT)] << std::endl; + str << "SlowShutter = " << sschoices[t->toInt(16,SHORT)] << std::endl; + str << "SequenceNumber = " << t->toInt(18,SHORT) << std::endl; + str << "OpticalZoomCode = " << t->toInt(20,SHORT) << std::endl; + str << "FlashGuideNumber = " << t->toInt(26,SHORT) << std::endl; + str << "AFPointsInFocus = " << afchoices[t->toInt(28,SHORT)] << std::endl; + str << "FlashExposureComp = " << t->toInt(30,SHORT) << std::endl; + str << "AutoExposureBracketing = " << afchoices[t->toInt(32,SHORT)] << std::endl; + str << "AEBBracketValue = " << t->toInt(34,SHORT) << std::endl; + str << "ControlMode = " << cmchoices[t->toInt(36,SHORT)] << std::endl; + str << "FocusDistanceUpper = " << t->toInt(38,SHORT) << std::endl; + str << "FocusDistanceLower = " << t->toInt(40,SHORT) << std::endl; + str << "FNumber = " << pow (2, t->toInt(42,SHORT)/64.0) << std::endl; + str << "ExposureTime = " << pow (2, -t->toInt(44,SHORT)/32.0) << std::endl; + str << "BulbDuration = " << t->toInt(48,SHORT) << std::endl; + str << "CameraType = " << ctchoices[t->toInt(52,SHORT)] << std::endl; + str << "AutoRotate = " << archoices[t->toInt(54,SHORT)] << std::endl; + str << "NDFilter = " << ndchoices[t->toInt(56,SHORT)] << std::endl; + str << "Self-timer2 = " << t->toInt(58,SHORT) << std::endl; + str << "FlashOutput = " << t->toInt(66,SHORT); + return str.str(); + } +}; +CAShotInfoInterpreter caShotInfoInterpreter; + + +class CAFileInfoInterpreter : public Interpreter { + std::map bmchoices; + std::map rjqchoices; + std::map rjschoices; + std::map nrchoices; + std::map wbchoices; + std::map fechoices; + std::map techoices; + public: + CAFileInfoInterpreter () { + bmchoices[0] = "Off"; + bmchoices[1] = "AEB"; + bmchoices[2] = "FEB"; + bmchoices[3] = "ISO"; + bmchoices[4] = "WB"; + + rjqchoices[1] = "Economy"; + rjqchoices[2] = "Normal"; + rjqchoices[3] = "Fine"; + rjqchoices[4] = "RAW"; + rjqchoices[5] = "Superfine"; + + rjschoices[0] = "Large"; + rjschoices[1] = "Medium"; + rjschoices[2] = "Small"; + rjschoices[5] = "Medium 1"; + rjschoices[6] = "Medium 2"; + rjschoices[7] = "Medium 3"; + rjschoices[8] = "Postcard"; + rjschoices[9] = "Widescreen"; + + nrchoices[0] = "Off"; + nrchoices[1] = "On (mode 1)"; + nrchoices[2] = "On (mode 2)"; + nrchoices[3] = "On (mode 3)"; + nrchoices[4] = "On (mode 4)"; + + wbchoices[0] = "Off"; + wbchoices[1] = "On (shift AB)"; + wbchoices[2] = "On (shift GM)"; + + fechoices[0] = "None"; + fechoices[1] = "Yellow"; + fechoices[2] = "Orange"; + fechoices[3] = "Red"; + fechoices[4] = "Green"; + + techoices[0] = "None"; + techoices[1] = "Sepia"; + techoices[2] = "Blue"; + techoices[3] = "Purple"; + techoices[4] = "Green"; + + } + virtual std::string toString (Tag* t) { + + std::ostringstream str; + str << "FileNumber = " << t->toInt(1,SHORT) << std::endl; + str << "ShutterCount = " << t->toInt(0,LONG) << std::endl; + str << "BracketMode = " << bmchoices[t->toInt(6,SHORT)] << std::endl; + str << "BracketValue = " << t->toInt(8,SHORT) << std::endl; + str << "BracketShotNumber = " << t->toInt(10,SHORT) << std::endl; + str << "RawJpgQuality = " << rjqchoices[t->toInt(12,SHORT)] << std::endl; + str << "RawJpgSize = " << rjschoices[t->toInt(14,SHORT)] << std::endl; + str << "NoiseReduction = " << nrchoices[t->toInt(16,SHORT)] << std::endl; + str << "WBBracketMode = " << t->toInt(18,SHORT) << std::endl; + str << "WBBracketValueAB = " << t->toInt(24,SHORT) << std::endl; + str << "FilterEffect = " << fechoices[t->toInt(26,SHORT)] << std::endl; + str << "ToningEffect = " << techoices[t->toInt(30,SHORT)]; + return str.str(); + } +}; +CAFileInfoInterpreter caFileInfoInterpreter; + +class CAModelIDInterpreter : public ChoiceInterpreter { + public: + CAModelIDInterpreter () { + choices[0x1010000] = "PowerShot A30"; + choices[0x1040000] = "PowerShot S300 / Digital IXUS 300 / IXY Digital 300"; + choices[0x1060000] = "PowerShot A20"; + choices[0x1080000] = "PowerShot A10"; + choices[0x1090000] = "PowerShot S110 / Digital IXUS v / IXY Digital 200"; + choices[0x1100000] = "PowerShot G2"; + choices[0x1110000] = "PowerShot S40"; + choices[0x1120000] = "PowerShot S30"; + choices[0x1130000] = "PowerShot A40"; + choices[0x1140000] = "EOS D30"; + choices[0x1150000] = "PowerShot A100"; + choices[0x1160000] = "PowerShot S200 / Digital IXUS v2 / IXY Digital 200a"; + choices[0x1170000] = "PowerShot A200"; + choices[0x1180000] = "PowerShot S330 / Digital IXUS 330 / IXY Digital 300a"; + choices[0x1190000] = "PowerShot G3"; + choices[0x1210000] = "PowerShot S45"; + choices[0x1230000] = "PowerShot SD100 / Digital IXUS II / IXY Digital 30"; + choices[0x1240000] = "PowerShot S230 / Digital IXUS v3 / IXY Digital 320"; + choices[0x1250000] = "PowerShot A70"; + choices[0x1260000] = "PowerShot A60"; + choices[0x1270000] = "PowerShot S400 / Digital IXUS 400 / IXY Digital 400"; + choices[0x1290000] = "PowerShot G5"; + choices[0x1300000] = "PowerShot A300"; + choices[0x1310000] = "PowerShot S50"; + choices[0x1340000] = "PowerShot A80"; + choices[0x1350000] = "PowerShot SD10 / Digital IXUS i / IXY Digital L"; + choices[0x1360000] = "PowerShot S1 IS"; + choices[0x1370000] = "PowerShot Pro1"; + choices[0x1380000] = "PowerShot S70"; + choices[0x1390000] = "PowerShot S60"; + choices[0x1400000] = "PowerShot G6"; + choices[0x1410000] = "PowerShot S500 / Digital IXUS 500 / IXY Digital 500"; + choices[0x1420000] = "PowerShot A75"; + choices[0x1440000] = "PowerShot SD110 / Digital IXUS IIs / IXY Digital 30a"; + choices[0x1450000] = "PowerShot A400"; + choices[0x1470000] = "PowerShot A310"; + choices[0x1490000] = "PowerShot A85"; + choices[0x1520000] = "PowerShot S410 / Digital IXUS 430 / IXY Digital 450"; + choices[0x1530000] = "PowerShot A95"; + choices[0x1540000] = "PowerShot SD300 / Digital IXUS 40 / IXY Digital 50"; + choices[0x1550000] = "PowerShot SD200 / Digital IXUS 30 / IXY Digital 40"; + choices[0x1560000] = "PowerShot A520"; + choices[0x1570000] = "PowerShot A510"; + choices[0x1590000] = "PowerShot SD20 / Digital IXUS i5 / IXY Digital L2"; + choices[0x1640000] = "PowerShot S2 IS"; + choices[0x1650000] = "PowerShot SD430 / IXUS Wireless / IXY Wireless"; + choices[0x1660000] = "PowerShot SD500 / Digital IXUS 700 / IXY Digital 600"; + choices[0x1668000] = "EOS D60"; + choices[0x1700000] = "PowerShot SD30 / Digital IXUS i zoom / IXY Digital L3"; + choices[0x1740000] = "PowerShot A430"; + choices[0x1750000] = "PowerShot A410"; + choices[0x1760000] = "PowerShot S80"; + choices[0x1780000] = "PowerShot A620"; + choices[0x1790000] = "PowerShot A610"; + choices[0x1800000] = "PowerShot SD630 / Digital IXUS 65 / IXY Digital 80"; + choices[0x1810000] = "PowerShot SD450 / Digital IXUS 55 / IXY Digital 60"; + choices[0x1820000] = "PowerShot TX1"; + choices[0x1870000] = "PowerShot SD400 / Digital IXUS 50 / IXY Digital 55"; + choices[0x1880000] = "PowerShot A420"; + choices[0x1890000] = "PowerShot SD900 / Digital IXUS 900 Ti / IXY Digital 1000"; + choices[0x1900000] = "PowerShot SD550 / Digital IXUS 750 / IXY Digital 700"; + choices[0x1920000] = "PowerShot A700"; + choices[0x1940000] = "PowerShot SD700 IS / Digital IXUS 800 IS / IXY Digital 800 IS"; + choices[0x1950000] = "PowerShot S3 IS"; + choices[0x1960000] = "PowerShot A540"; + choices[0x1970000] = "PowerShot SD600 / Digital IXUS 60 / IXY Digital 70"; + choices[0x1980000] = "PowerShot G7"; + choices[0x1990000] = "PowerShot A530"; + choices[0x2000000] = "PowerShot SD800 IS / Digital IXUS 850 IS / IXY Digital 900 IS"; + choices[0x2010000] = "PowerShot SD40 / Digital IXUS i7 / IXY Digital L4"; + choices[0x2020000] = "PowerShot A710 IS"; + choices[0x2030000] = "PowerShot A640"; + choices[0x2040000] = "PowerShot A630"; + choices[0x2090000] = "PowerShot S5 IS"; + choices[0x2100000] = "PowerShot A460"; + choices[0x2120000] = "PowerShot SD850 IS / Digital IXUS 950 IS / IXY Digital 810 IS"; + choices[0x2130000] = "PowerShot A570 IS"; + choices[0x2140000] = "PowerShot A560"; + choices[0x2150000] = "PowerShot SD750 / Digital IXUS 75 / IXY Digital 90"; + choices[0x2160000] = "PowerShot SD1000 / Digital IXUS 70 / IXY Digital 10"; + choices[0x2180000] = "PowerShot A550"; + choices[0x2190000] = "PowerShot A450"; + choices[0x2230000] = "PowerShot G9"; + choices[0x2240000] = "PowerShot A650 IS"; + choices[0x2260000] = "PowerShot A720 IS"; + choices[0x2290000] = "PowerShot SX100 IS"; + choices[0x2300000] = "PowerShot SD950 IS / Digital IXUS 960 IS / IXY Digital 2000 IS"; + choices[0x2310000] = "PowerShot SD870 IS / Digital IXUS 860 IS / IXY Digital 910 IS"; + choices[0x3010000] = "PowerShot Pro90 IS"; + choices[0x4040000] = "PowerShot G1"; + choices[0x6040000] = "PowerShot S100 / Digital IXUS / IXY Digital"; + choices[0x4007d675] = "HV10"; + choices[0x4007d777] = "iVIS DC50"; + choices[0x4007d778] = "iVIS HV20"; + choices[0x80000001] = "EOS-1D"; + choices[0x80000167] = "EOS-1DS"; + choices[0x80000168] = "EOS 10D"; + choices[0x80000169] = "EOS-1D Mark III"; + choices[0x80000170] = "EOS Digital Rebel / 300D / Kiss Digital"; + choices[0x80000174] = "EOS-1D Mark II"; + choices[0x80000175] = "EOS 20D"; + choices[0x80000188] = "EOS-1Ds Mark II"; + choices[0x80000189] = "EOS Digital Rebel XT / 350D / Kiss Digital N"; + choices[0x80000190] = "EOS 40D"; + choices[0x80000213] = "EOS 5D"; + choices[0x80000215] = "EOS-1Ds Mark III"; + choices[0x80000232] = "EOS-1D Mark II N"; + choices[0x80000234] = "EOS 30D"; + choices[0x80000236] = "EOS Digital Rebel XTi / 400D / Kiss Digital X"; + choices[0x80000254] = "EOS Rebel XS / 1000D / Kiss F"; + choices[0x80000261] = "EOS 50D"; + } +}; + +CAModelIDInterpreter caModelIDInterpreter; + + +const TagAttrib canonAttribs[] = { + 0, 1, 0, 0, 0x0001, "CanonCameraSettings", &caCameraSettingsInterpreter, + 0, 1, 0, 0, 0x0002, "CanonFocalLength", &caFocalLengthInterpreter, + 0, 1, 0, 0, 0x0003, "CanonFlashInfo", &stdInterpreter, + 0, 1, 0, 0, 0x0004, "CanonShotInfo", &caShotInfoInterpreter, + 0, 1, 0, 0, 0x0005, "CanonPanorama", &stdInterpreter, + 0, 1, 0, 0, 0x0006, "CanonImageType", &stdInterpreter, + 0, 1, 0, 0, 0x0007, "CanonFirmwareVersion", &stdInterpreter, + 0, 1, 0, 0, 0x0008, "FileNumber", &stdInterpreter, + 0, 1, 0, 0, 0x0009, "OwnerName", &stdInterpreter, + 0, 1, 0, 0, 0x000a, "ColorInfoD30", &stdInterpreter, + 0, 1, 0, 0, 0x000c, "SerialNumber", &stdInterpreter, + 0, 1, 0, 0, 0x000d, "CanonCameraInfo", &stdInterpreter, + 0, 1, 0, 0, 0x000e, "CanonFileLength", &stdInterpreter, + 0, 1, 0, 0, 0x000f, "CustomFunctions", &stdInterpreter, + 0, 1, 0, 0, 0x0010, "CanonModelID", &caModelIDInterpreter, + 0, 1, 0, 0, 0x0012, "CanonAFInfo", &stdInterpreter, + 0, 1, 0, 0, 0x0015, "SerialNumberFormat", &stdInterpreter, + 0, 1, 0, 0, 0x001c, "DateStampMode", &stdInterpreter, + 0, 1, 0, 0, 0x001d, "MyColors", &stdInterpreter, + 0, 1, 0, 0, 0x001e, "FirmwareRevision", &stdInterpreter, + 0, 3, 0, 0, 0x0024, "FaceDetect1", &stdInterpreter, + 0, 3, 0, 0, 0x0025, "FaceDetect2", &stdInterpreter, + 0, 1, 0, 0, 0x0026, "CanonAFInfo2", &stdInterpreter, + 0, 1, 0, 0, 0x0083, "OriginalDecisionData", &stdInterpreter, + 0, 1, 0, 0, 0x0090, "CustomFunctions1D", &stdInterpreter, + 0, 1, 0, 0, 0x0091, "PersonalFunctions", &stdInterpreter, + 0, 1, 0, 0, 0x0092, "PersonalFunctionValues", &stdInterpreter, + 0, 1, 0, 0, 0x0093, "CanonFileInfo", &caFileInfoInterpreter, + 0, 1, 0, 0, 0x0094, "AFPointsInFocus1D", &stdInterpreter, + 0, 1, 0, 0, 0x0095, "LensType", &stdInterpreter, + 0, 1, 0, 0, 0x0096, "InternalSerialNumber", &caIntSerNumInterpreter, + 0, 1, 0, 0, 0x0097, "DustRemovalData", &stdInterpreter, + 0, 1, 0, 0, 0x0099, "CustomFunctions2", &stdInterpreter, + 0, 1, 0, 0, 0x00a0, "ProccessingInfo", &caProcessingInfoInterpreter, + 0, 1, 0, 0, 0x00a1, "ToneCurveTable", &stdInterpreter, + 0, 1, 0, 0, 0x00a2, "SharpnessTable", &stdInterpreter, + 0, 1, 0, 0, 0x00a3, "SharpnessFreqTable", &stdInterpreter, + 0, 1, 0, 0, 0x00a4, "WhiteBalanceTable", &stdInterpreter, + 0, 1, 0, 0, 0x00a9, "ColorBalance", &stdInterpreter, + 0, 1, 0, 0, 0x00ae, "ColorTemperature", &stdInterpreter, + 0, 3, 0, 0, 0x00b0, "CanonFlags", &stdInterpreter, + 0, 1, 0, 0, 0x00b1, "ModifiedInfo", &stdInterpreter, + 0, 1, 0, 0, 0x00b2, "ToneCurveMatching", &stdInterpreter, + 0, 1, 0, 0, 0x00b3, "WhiteBalanceMatching", &stdInterpreter, + 0, 1, 0, 0, 0x00b4, "ColorSpace", &stdInterpreter, + 1, 1, 0, 0, 0x00b6, "PreviewImageInfo", &stdInterpreter, + 0, 1, 0, 0, 0x00d0, "VRDOffset", &stdInterpreter, + 0, 1, 0, 0, 0x00e0, "SensorInfo", &stdInterpreter, + 0, 1, 0, 0, 0x4001, "ColorBalance", &stdInterpreter, + 0, 1, 0, 0, 0x4002, "UnknownBlock1", &stdInterpreter, + 0, 1, 0, 0, 0x4003, "ColorInfo", &stdInterpreter, + 1, 1, 0, 0, 0x4005, "UnknownBlock2", &stdInterpreter, + 1, 1, 0, 0, 0x4008, "BlackLevel", &stdInterpreter, + -1, 0, 0, 0, 0, "", NULL}; + +}; + #endif + diff --git a/rtexif/fujiattribs.cc b/rtexif/fujiattribs.cc new file mode 100755 index 000000000..9f946dd03 --- /dev/null +++ b/rtexif/fujiattribs.cc @@ -0,0 +1,263 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _FUJIATTRIBS_ +#define _FUJIATTRIBS_ + +#include +#include +#include +#include +#include +#include + +namespace rtexif { + +class FAOnOffInterpreter : public ChoiceInterpreter { + public: + FAOnOffInterpreter () { + choices[0] = "Off"; + choices[1] = "On"; + } +}; +FAOnOffInterpreter faOnOffInterpreter; + +class FASharpnessInterpreter : public ChoiceInterpreter { + public: + FASharpnessInterpreter () { + choices[1] = "Soft"; + choices[2] = "Soft2"; + choices[3] = "Normal"; + choices[4] = "Hard"; + choices[5] = "Hard2"; + choices[0x82] = "Medium Soft"; + choices[0x84] = "Medium Hard"; + choices[0x8000] = "Film Simulation"; + choices[0xffff] = "n/a"; + } +}; +FASharpnessInterpreter faSharpnessInterpreter; + +class FAWhiteBalanceInterpreter : public ChoiceInterpreter { + public: + FAWhiteBalanceInterpreter () { + choices[0] = "Auto"; + choices[0x100] = "Daylight"; + choices[0x200] = "Cloudy"; + choices[0x300] = "Daylight Fluorescent"; + choices[0x301] = "Day White Fluorescent"; + choices[0x302] = "White Fluorescent"; + choices[0x303] = "Warm White Fluorescent"; + choices[0x304] = "Living Room Warm White Fluorescent"; + choices[0x400] = "Incandescent"; + choices[0x500] = "Flash"; + choices[0xf00] = "Custom"; + choices[0xf01] = "Custom2"; + choices[0xf02] = "Custom3"; + choices[0xf03] = "Custom4"; + choices[0xf04] = "Custom5"; + choices[0xff0] = "Kelvin"; + } +}; +FAWhiteBalanceInterpreter faWhiteBalanceInterpreter; + +class FASaturationInterpreter : public ChoiceInterpreter { + public: + FASaturationInterpreter () { + choices[0] = "Normal"; + choices[0x80] = "Medium High"; + choices[0x100] = "High"; + choices[0x180] = "Medium Low"; + choices[0x200] = "Low"; + choices[0x300] = "None (B&W)"; + choices[0x8000] = "Film Simulation"; + } +}; +FASaturationInterpreter faSaturationInterpreter; + +class FAContrastInterpreter : public ChoiceInterpreter { + public: + FAContrastInterpreter () { + choices[0] = "Normal"; + choices[0x80] = "Medium High"; + choices[0x100] = "High"; + choices[0x180] = "Medium Low"; + choices[0x200] = "Low"; + choices[0x8000] = "Film Simulation"; + } +}; +FAContrastInterpreter faContrastInterpreter; + +class FAContrast2Interpreter : public ChoiceInterpreter { + public: + FAContrast2Interpreter () { + choices[0] = "Normal"; + choices[0x100] = "High"; + choices[0x300] = "Low"; + } +}; +FAContrast2Interpreter faContrast2Interpreter; + +class FANoiseReductionInterpreter : public ChoiceInterpreter { + public: + FANoiseReductionInterpreter () { + choices[0x40] = "Low"; + choices[0x80] = "Normal"; + } +}; +FANoiseReductionInterpreter faNoiseReductionInterpreter; + +class FAFlashInterpreter : public ChoiceInterpreter { + public: + FAFlashInterpreter () { + choices[0] = "Auto"; + choices[1] = "On"; + choices[2] = "Off"; + choices[3] = "Red-eye reduction"; + choices[4] = "External"; + } +}; +FAFlashInterpreter faFlashInterpreter; + +class FAFocusModeInterpreter : public ChoiceInterpreter { + public: + FAFocusModeInterpreter () { + choices[0] = "Auto"; + choices[1] = "Manual"; + } +}; +FAFocusModeInterpreter faFocusModeInterpreter; + +class FAColorModeInterpreter : public ChoiceInterpreter { + public: + FAColorModeInterpreter () { + choices[0] = "Standard"; + choices[0x10] = "Chrome"; + choices[0x30] = "B & W"; + } +}; +FAColorModeInterpreter faColorModeInterpreter; + +class FADynamicRangeInterpreter : public ChoiceInterpreter { + public: + FADynamicRangeInterpreter () { + choices[1] = "Standard"; + choices[3] = "Wide"; + } +}; +FADynamicRangeInterpreter faDynamicRangeInterpreter; + +class FAFilmModeInterpreter : public ChoiceInterpreter { + public: + FAFilmModeInterpreter () { + choices[0] = "F0/Standard"; + choices[0x100] = "F1/Studio Portrait"; + choices[0x110] = "F1a/Studio Portrait Enhanced Saturation"; + choices[0x120] = "F1b/Studio Portrait Smooth Skin Tone"; + choices[0x130] = "F1c/Studio Portrait Increased Sharpness "; + choices[0x200] = "F2/Fujichrome"; + choices[0x300] = "F3/Studio Portrait Ex"; + choices[0x400] = "F4/Velvia"; + } +}; +FAFilmModeInterpreter faFilmModeInterpreter; + +class FADRSettingInterpreter : public ChoiceInterpreter { + public: + FADRSettingInterpreter () { + choices[0] = "Auto (100-400%)"; + choices[0x1] = "RAW"; + choices[0x100] = "Standard (100%)"; + choices[0x200] = "Wide1 (230%)"; + choices[0x201] = "Wide2 (400%)"; + choices[0x8000] = "Film Simulation"; + } +}; +FADRSettingInterpreter faDRSettingInterpreter; + +class FAPictureModeInterpreter : public ChoiceInterpreter { + public: + FAPictureModeInterpreter () { + choices[0] = "Auto"; + choices[1] = "Portrait"; + choices[2] = "Landscape"; + choices[3] = "Macro"; + choices[4] = "Sports"; + choices[5] = "Night Scene"; + choices[6] = "Program AE"; + choices[7] = "Natural Light"; + choices[8] = "Anti-blur"; + choices[9] = "Beach & Snow"; + choices[10] = "Sunset"; + choices[11] = "Museum"; + choices[12] = "Party"; + choices[13] = "Flower"; + choices[14] = "Text"; + choices[15] = "Natural Light & Flash"; + choices[16] = "Beach"; + choices[17] = "Fireworks"; + choices[18] = "Underwater"; + choices[0x100] = "Aperture-priority AE"; + choices[0x200] = "Shutter speed priority AE"; + choices[0x300] = "Manual"; + } +}; +FAPictureModeInterpreter faPictureModeInterpreter; + + + +const TagAttrib fujiAttribs[] = { + 0, 1, 0, 0, 0x0000, "Version", &stdInterpreter, + 0, 1, 0, 0, 0x0010, "InternalSerialNumber", &stdInterpreter, + 0, 1, 0, 0, 0x1000, "Quality", &stdInterpreter, + 0, 1, 0, 0, 0x1001, "Sharpness", &faSharpnessInterpreter, + 0, 1, 0, 0, 0x1002, "WhiteBalance", &faWhiteBalanceInterpreter, + 0, 1, 0, 0, 0x1003, "Saturation", &faSaturationInterpreter, + 0, 1, 0, 0, 0x1004, "Contrast", &faContrastInterpreter, + 0, 1, 0, 0, 0x1005, "ColorTemperature", &stdInterpreter, + 0, 1, 0, 0, 0x1006, "Contrast2", &faContrast2Interpreter, + 0, 1, 0, 0, 0x100a, "WhiteBalanceFineTune", &stdInterpreter, + 0, 1, 0, 0, 0x100b, "NoiseReduction", &faNoiseReductionInterpreter, + 0, 1, 0, 0, 0x100b, "FujiFlashMode", &faFlashInterpreter, + 0, 1, 0, 0, 0x1011, "FlashExposureComp", &stdInterpreter, + 0, 1, 0, 0, 0x1020, "Macro", &faOnOffInterpreter, + 0, 1, 0, 0, 0x1021, "FocusMode", &faFocusModeInterpreter, + 0, 1, 0, 0, 0x1023, "FocusPixel", &stdInterpreter, + 0, 1, 0, 0, 0x1030, "SlowSync", &faOnOffInterpreter, + 0, 1, 0, 0, 0x1031, "PictureMode", &faPictureModeInterpreter, + 0, 1, 0, 0, 0x1100, "AutoBracketing", &faOnOffInterpreter, + 0, 1, 0, 0, 0x1101, "SequenceNumber", &stdInterpreter, + 0, 1, 0, 0, 0x1210, "ColorMode", &faColorModeInterpreter, + 0, 1, 0, 0, 0x1300, "BlurWarning", &faOnOffInterpreter, + 0, 1, 0, 0, 0x1301, "FocusWarning", &faOnOffInterpreter, + 0, 1, 0, 0, 0x1302, "ExposureWarning", &faOnOffInterpreter, + 0, 1, 0, 0, 0x1400, "DynamicRange", &faDynamicRangeInterpreter, + 0, 1, 0, 0, 0x1401, "FilmMode", &faFilmModeInterpreter, + 0, 1, 0, 0, 0x1402, "DynamicRangeSetting", &faDRSettingInterpreter, + 0, 1, 0, 0, 0x1403, "DevelopmentDynamicRange", &stdInterpreter, + 0, 1, 0, 0, 0x1404, "MinFocalLength", &stdInterpreter, + 0, 1, 0, 0, 0x1405, "MaxFocalLength", &stdInterpreter, + 0, 1, 0, 0, 0x1406, "MaxApertureAtMinFocal", &stdInterpreter, + 0, 1, 0, 0, 0x1407, "MaxApertureAtMaxFocal", &stdInterpreter, + 0, 1, 0, 0, 0x8000, "FileSource", &stdInterpreter, + 0, 1, 0, 0, 0x8002, "OrderNumber", &stdInterpreter, + 0, 1, 0, 0, 0x8003, "FrameNumber", &stdInterpreter, + -1, 0, 0, 0, 0, "", NULL}; +}; + #endif + diff --git a/rtexif/nikonattribs.cc b/rtexif/nikonattribs.cc new file mode 100755 index 000000000..361fa2217 --- /dev/null +++ b/rtexif/nikonattribs.cc @@ -0,0 +1,617 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _NIKONATTRIBS_ +#define _NIKONATTRIBS_ + +#include +#include +#include +#include +#include +#include +#include + +namespace rtexif { + +class NAISOInterpreter : public Interpreter { + public: + NAISOInterpreter () {} + virtual std::string toString (Tag* t) { + sprintf (buffer, "%d", t->toInt(2)); + return buffer; + } +}; +NAISOInterpreter naISOInterpreter; + +class NALensTypeInterpreter : public Interpreter { + public: + NALensTypeInterpreter () {} + virtual std::string toString (Tag* t) { + int a = t->toInt(); + std::ostringstream str; + str << "MF = " << (a&1 ? "Yes" : "No") << std::endl; + str << "D = " << (a&2 ? "Yes" : "No") << std::endl; + str << "G = " << (a&4 ? "Yes" : "No") << std::endl; + str << "VR = " << (a&8 ? "Yes" : "No"); + return str.str(); + } +}; +NALensTypeInterpreter naLensTypeInterpreter; + +class NAFlashModeInterpreter : public ChoiceInterpreter { + public: + NAFlashModeInterpreter () { + choices[0] = "Did Not Fire"; + choices[1] = "Fired, Manual"; + choices[7] = "Fired, External"; + choices[8] = "Fired, Commander Mode"; + choices[9] = "Fired, TTL Mode"; + } +}; +NAFlashModeInterpreter naFlashModeInterpreter; + +class NAHiISONRInterpreter : public ChoiceInterpreter { + public: + NAHiISONRInterpreter () { + choices[0] = "Off"; + choices[1] = "Minimal"; + choices[2] = "Low"; + choices[4] = "Normal"; + choices[6] = "High"; + } +}; +NAHiISONRInterpreter naHiISONRInterpreter; + +class NAShootingModeInterpreter : public Interpreter { + public: + NAShootingModeInterpreter () {} + virtual std::string toString (Tag* t) { + int a = t->toInt(); + std::ostringstream str; + str << "Continuous = " << (a&1 ? "Yes" : "No") << std::endl; + str << "Delay = " << (a&2 ? "Yes" : "No") << std::endl; + str << "PC Control = " << (a&4 ? "Yes" : "No") << std::endl; + str << "Exposure Bracketing = " << (a&8 ? "Yes" : "No") << std::endl; + str << "Auto ISO = " << (a&16 ? "Yes" : "No") << std::endl; + str << "White-Balance Bracketing = " << (a&32 ? "Yes" : "No") << std::endl; + str << "IR Control = " << (a&64 ? "Yes" : "No"); + return str.str(); + } +}; +NAShootingModeInterpreter naShootingModeInterpreter; + +class NAAFInfoInterpreter : public Interpreter { + std::map amchoices; + std::map afpchoices; + public: + NAAFInfoInterpreter () { + amchoices[0] = "Single Area"; + amchoices[1] = "Dynamic Area"; + amchoices[2] = "Dynamic Area, Closest Subject"; + amchoices[3] = "Group Dynamic"; + amchoices[4] = "Single Area (wide)"; + amchoices[5] = "Dynamic Area (wide)"; + afpchoices[0] = "Center"; + afpchoices[1] = "Top"; + afpchoices[2] = "Bottom"; + afpchoices[3] = "Left"; + afpchoices[4] = "Right"; + afpchoices[5] = "Upper-left"; + afpchoices[6] = "Upper-right"; + afpchoices[7] = "Lower-left"; + afpchoices[8] = "Lower-right"; + afpchoices[9] = "Far Left"; + afpchoices[10] = "Far Right"; + } + virtual std::string toString (Tag* t) { + int am = t->toInt (0, BYTE); + int afp = t->toInt (1, BYTE); + int aff = t->toInt (2, SHORT); + std::ostringstream str; + str << "AFAreaMode = " << amchoices[am] << std::endl; + str << "AFAreaMode = " << afpchoices[afp] << std::endl; + + std::ostringstream af; + if (aff&1) + if (af.str()=="") af << "Center"; + else af << ", Center"; + else if (aff&2) + if (af.str()=="") af << "Top"; + else af << ", Top"; + else if (aff&4) + if (af.str()=="") af << "Bottom"; + else af << ", Bottom"; + else if (aff&8) + if (af.str()=="") af << "Left"; + else af << ", Left"; + else if (aff&16) + if (af.str()=="") af << "Right"; + else af << ", Right"; + else if (aff&32) + if (af.str()=="") af << "Upper-left"; + else af << ", Upper-left"; + else if (aff&64) + if (af.str()=="") af << "Upper-right"; + else af << ", Upper-right"; + else if (aff&128) + if (af.str()=="") af << " Lower-left"; + else af << ", Lower-left"; + else if (aff&256) + if (af.str()=="") af << "Lower-right"; + else af << ", Lower-right"; + else if (aff&512) + if (af.str()=="") af << "Far Left"; + else af << ", Far Left"; + else if (aff&1024) + if (af.str()=="") af << "Far Right"; + else af << ", Far Right"; + + str << "AFPointsInFocus = " << af.str(); + return str.str(); + } +}; +NAAFInfoInterpreter naAFInfoInterpreter; + +class NALensDataInterpreter : public Interpreter { + std::map lenses; + public: + NALensDataInterpreter () { + lenses["00 36 1C 2D 34 3C 00 06"] = "Tamron SP AF11-18mm f/4.5-5.6 Di II LD Aspherical (IF)"; + lenses["00 3C 1F 37 30 30 00 06"] = "Tokina AT-X 124 AF PRO DX - AF 12-24mm F4"; + lenses["00 3E 80 A0 38 3F 00 02"] = "Tamron SP AF200-500mm f/5-6.3 Di LD (IF)"; + lenses["00 3F 2D 80 2B 40 00 06"] = "Tamron AF18-200mm f/3.5-6.3 XR Di II LD Aspherical (IF)"; + lenses["00 3F 2D 80 2C 40 00 06"] = "Tamron AF18-200mm f/3.5-6.3 XR Di II LD Aspherical (IF) Macro"; + lenses["00 3F 80 A0 38 3F 00 02"] = "Tamron SP AF200-500mm f/5-6.3 Di"; + lenses["00 40 18 2B 2C 34 00 06"] = "Tokina AT-X 107 DX Fish-Eye - AF 10-17mm F3.5-4.5"; + lenses["00 40 2B 2B 2C 2C 00 02"] = "Tokina AT-X 17 AF PRO - AF 17mm F3.5"; + lenses["00 44 60 98 34 3C 00 02"] = "Tokina AT-X 840D 80-400mm F4.5-5.6"; + lenses["00 47 53 80 30 3C 00 06"] = "Tamron AF55-200mm f/4-5.6 Di II LD"; + lenses["00 48 29 50 24 24 00 06"] = "Tokina AT-X 165 PRO DX - AF 16-50mm F2.8"; + lenses["00 48 3C 60 24 24 00 02"] = "Tokina AT-X 280 AF PRO 28-80mm F2.8 Aspherical"; + lenses["00 48 3C 6A 24 24 00 02"] = "Tamron SP AF28-105mm f/2.8"; + lenses["00 48 50 72 24 24 00 06"] = "Tokina AT-X 535 PRO DX - AF 50-135mm F2.8"; + lenses["00 49 30 48 22 2B 00 02"] = "Tamron SP AF20-40mm f/2.7-3.5"; + lenses["00 4C 7C 7C 2C 2C 00 02"] = "Tamron SP AF180mm f/3.5 Di Model B01"; + lenses["00 53 2B 50 24 24 00 06"] = "Tamron SP AF17-50mm f/2.8 (A16)"; + lenses["00 54 68 68 24 24 00 02"] = "Tokina AT-X M100 PRO D - 100mm F2.8"; + lenses["00 54 8E 8E 24 24 00 02"] = "Tokina AT-X 300 AF PRO 300mm F2.8"; + lenses["01 00 00 00 00 00 02 00"] = "AF Teleconverter TC-16A 1.6x"; + lenses["01 00 00 00 00 00 08 00"] = "AF Teleconverter TC-16A 1.6x"; + lenses["01 58 50 50 14 14 02 00"] = "AF Nikkor 50mm f/1.8"; + lenses["02 2F 98 98 3D 3D 02 00"] = "Sigma 400mm F5.6 APO"; + lenses["02 37 5E 8E 35 3D 02 00"] = "Sigma 75-300mm F4.5-5.6 APO"; + lenses["02 37 A0 A0 34 34 02 00"] = "Sigma APO 500mm F4.5"; + lenses["02 3F 24 24 2C 2C 02 00"] = "Sigma 14mm F3.5"; + lenses["02 3F 3C 5C 2D 35 02 00"] = "Sigma 28-70mm F3.5-4.5 UC"; + lenses["02 40 44 73 2B 36 02 00"] = "Sigma 35-135mm F3.5-4.5 a"; + lenses["02 42 44 5C 2A 34 02 00"] = "AF Zoom-Nikkor 35-70mm f/3.3-4.5"; + lenses["02 42 44 5C 2A 34 08 00"] = "AF Zoom-Nikkor 35-70mm f/3.3-4.5"; + lenses["02 46 37 37 25 25 02 00"] = "Sigma 24mm F2.8 Macro"; + lenses["02 46 3C 5C 25 25 02 00"] = "Sigma 28-70mm F2.8"; + lenses["02 46 5C 82 25 25 02 00"] = "Sigma 70-210mm F2.8 APO"; + lenses["02 48 65 65 24 24 02 00"] = "Sigma 90mm F2.8 Macro"; + lenses["03 43 5C 81 35 35 02 00"] = "Soligor AF C/D ZOOM UMCS 70-210mm 1:4.5"; + lenses["03 48 5C 81 30 30 02 00"] = "AF Zoom-Nikkor 70-210mm f/4"; + lenses["04 48 3C 3C 24 24 03 00"] = "AF Nikkor 28mm f/2.8"; + lenses["05 54 50 50 0C 0C 04 00"] = "AF Nikkor 50mm f/1.4"; + lenses["06 3F 68 68 2C 2C 06 00"] = "Cosina 100mm f/3.5 Macro"; + lenses["06 54 53 53 24 24 06 00"] = "AF Micro-Nikkor 55mm f/2.8"; + lenses["07 40 2F 44 2C 34 03 02"] = "Tamron AF19-35mm f/3.5-4.5 N"; + lenses["07 40 30 45 2D 35 03 02"] = "Tamron AF19-35mm f/3.5-4.5"; + lenses["07 40 3C 62 2C 34 03 00"] = "AF Zoom-Nikkor 28-85mm f/3.5-4.5"; + lenses["07 46 2B 44 24 30 03 02"] = "Tamron SP AF17-35mm f/2.8-4 Di LD Aspherical (IF)"; + lenses["08 40 44 6A 2C 34 04 00"] = "AF Zoom-Nikkor 35-105mm f/3.5-4.5"; + lenses["09 48 37 37 24 24 04 00"] = "AF Nikkor 24mm f/2.8"; + lenses["0A 48 8E 8E 24 24 03 00"] = "AF Nikkor 300mm f/2.8 IF-ED"; + lenses["0B 3E 3D 7F 2F 3D 0E 00"] = "Tamron AF28-200mm f/3.8-5.6"; + lenses["0B 3E 3D 7F 2F 3D 0E 02"] = "Tamron AF28-200mm f/3.8-5.6D"; + lenses["0B 48 7C 7C 24 24 05 00"] = "AF Nikkor 180mm f/2.8 IF-ED"; + lenses["0D 40 44 72 2C 34 07 00"] = "AF Zoom-Nikkor 35-135mm f/3.5-4.5"; + lenses["0E 48 5C 81 30 30 05 00"] = "AF Zoom-Nikkor 70-210mm f/4"; + lenses["0E 4A 31 48 23 2D 0E 02"] = "Tamron SP AF20-40mm f/2.7-3.5"; + lenses["0F 58 50 50 14 14 05 00"] = "AF Nikkor 50mm f/1.8 N"; + lenses["10 3D 3C 60 2C 3C D2 02"] = "Tamron AF28-80mm f/3.5-5.6 Aspherical"; + lenses["10 48 8E 8E 30 30 08 00"] = "AF Nikkor 300mm f/4 IF-ED"; + lenses["11 48 44 5C 24 24 08 00"] = "AF Zoom-Nikkor 35-70mm f/2.8"; + lenses["12 3B 68 8D 3D 43 09 02"] = "Unknown 100-290mm f/5.6-6.7"; + lenses["12 48 5C 81 30 3C 09 00"] = "AF Nikkor 70-210mm f/4-5.6"; + lenses["13 42 37 50 2A 34 0B 00"] = "AF Zoom-Nikkor 24-50mm f/3.3-4.5"; + lenses["14 48 60 80 24 24 0B 00"] = "AF Zoom-Nikkor 80-200mm f/2.8 ED"; + lenses["14 48 68 8E 30 30 0B 00"] = "Tokina AT-X 340 AF II 100-300mm F4"; + lenses["14 54 60 80 24 24 0B 00"] = "Tokina AT-X 828 AF 80-200mm F2.8"; + lenses["15 4C 62 62 14 14 0C 00"] = "AF Nikkor 85mm f/1.8"; + lenses["17 3C A0 A0 30 30 11 00"] = "Nikkor 500mm f/4 P"; + lenses["18 40 44 72 2C 34 0E 00"] = "AF Zoom-Nikkor 35-135mm f/3.5-4.5 N"; + lenses["1A 54 44 44 18 18 11 00"] = "AF Nikkor 35mm f/2"; + lenses["1B 44 5E 8E 34 3C 10 00"] = "AF Zoom-Nikkor 75-300mm f/4.5-5.6"; + lenses["1C 48 30 30 24 24 12 00"] = "AF Nikkor 20mm f/2.8"; + lenses["1D 42 44 5C 2A 34 12 00"] = "AF Zoom-Nikkor 35-70mm f/3.3-4.5 N"; + lenses["1E 54 56 56 24 24 13 00"] = "AF Micro-Nikkor 60mm f/2.8"; + lenses["1E 5D 64 64 20 20 13 00"] = "Unknown 90mm f/2.5"; + lenses["1F 54 6A 6A 24 24 14 00"] = "AF Micro-Nikkor 105mm f/2.8"; + lenses["20 3C 80 98 3D 3D 1E 02"] = "Tamron AF200-400mm f/5.6 LD IF"; + lenses["20 48 60 80 24 24 15 00"] = "AF Zoom-Nikkor ED 80-200mm f/2.8"; + lenses["21 40 3C 5C 2C 34 16 00"] = "AF Zoom-Nikkor 28-70mm f/3.5-4.5"; + lenses["22 48 72 72 18 18 16 00"] = "AF DC-Nikkor 135mm f/2"; + lenses["24 44 60 98 34 3C 1A 02"] = "Tokina AT-X 840 AF II 80-400mm F4.5-5.6"; + lenses["24 48 60 80 24 24 1A 02"] = "AF Zoom-Nikkor ED 80-200mm f/2.8D"; + lenses["25 48 3C 5C 24 24 1B 02"] = "Tokina AT-X 287 AF PRO SV 28-70mm F2.8"; + lenses["25 48 44 5C 24 24 1B 02"] = "AF Zoom-Nikkor 35-70mm f/2.8D"; + lenses["25 48 44 5C 24 24 52 02"] = "AF Zoom-Nikkor 35-70mm f/2.8D"; + lenses["26 3C 54 80 30 3C 1C 06"] = "Sigma 55-200mm F4-5.6 DC"; + lenses["26 3C 5C 82 30 3C 1C 02"] = "Sigma 70-210mm F4-5.6 UC-II"; + lenses["26 3C 5C 8E 30 3C 1C 02"] = "Sigma 70-300mm F4-5.6 DG Macro"; + lenses["26 3E 3C 6A 2E 3C 1C 02"] = "Sigma 28-105mm F3.8-5.6 UC-III Aspherical IF"; + lenses["26 40 27 3F 2C 34 1C 02"] = "Sigma 15-30mm F3.5-4.5 EX Aspherical DG DF"; + lenses["26 40 2D 44 2B 34 1C 02"] = "Sigma 18-35 F3.5-4.5 Aspherical"; + lenses["26 40 2D 50 2C 3C 1C 06"] = "Sigma 18-50mm F3.5-5.6 DC"; + lenses["26 40 2D 70 2B 3C 1C 06"] = "Sigma 18-125mm F3.5-5.6 DC"; + lenses["26 40 2D 80 2C 40 1C 06"] = "Sigma 18-200mm F3.5-6.3 DC"; + lenses["26 40 37 5C 2C 3C 1C 02"] = "Sigma 24-70mm F3.5-5.6 Aspherical HF"; + lenses["26 40 3C 60 2C 3C 1C 02"] = "Sigma 28-80mm F3.5-5.6 Mini Zoom Macro II Aspherical"; + lenses["26 40 3C 65 2C 3C 1C 02"] = "Sigma 28-90mm F3.5-5.6 Macro"; + lenses["26 40 3C 80 2B 3C 1C 02"] = "Sigma 28-200mm F3.5-5.6 Compact Aspherical Hyperzoom Macro"; + lenses["26 40 3C 80 2C 3C 1C 02"] = "Sigma 28-200mm F3.5-5.6 Compact Aspherical Hyperzoom Macro"; + lenses["26 40 3C 8E 2C 40 1C 02"] = "Sigma 28-300mm F3.5-6.3 Macro"; + lenses["26 40 7B A0 34 40 1C 02"] = "Sigma APO 170-500mm F5-6.3 Aspherical RF"; + lenses["26 41 3C 8E 2C 40 1C 02"] = "Sigma 28-300mm F3.5-6.3 DG Macro"; + lenses["26 44 73 98 34 3C 1C 02"] = "Sigma 135-400mm F4.5-5.6 APO Aspherical"; + lenses["26 48 11 11 30 30 1C 02"] = "Sigma 8mm F4 EX Circular Fisheye"; + lenses["26 48 27 27 24 24 1C 02"] = "Sigma 15mm F2.8 EX Diagonal Fish-Eye"; + lenses["26 48 2D 50 24 24 1C 06"] = "Sigma 18-50mm F2.8 EX DC"; + lenses["26 48 31 49 24 24 1C 02"] = "Sigma 20-40mm F2.8"; + lenses["26 48 37 56 24 24 1C 02"] = "Sigma 24-60mm F2.8 EX DG"; + lenses["26 48 3C 5C 24 24 1C 06"] = "Sigma 28-70mm F2.8 EX DG"; + lenses["26 48 3C 5C 24 30 1C 02"] = "Sigma 28-70mm F2.8-4 High Speed Zoom"; + lenses["26 48 3C 6A 24 30 1C 02"] = "Sigma 28-105mm F2.8-4 Aspherical"; + lenses["26 48 8E 8E 30 30 1C 02"] = "Sigma APO TELE MACRO 300mm F4"; + lenses["26 54 2B 44 24 30 1C 02"] = "Sigma 17-35mm F2.8-4 EX Aspherical"; + lenses["26 54 37 5C 24 24 1C 02"] = "Sigma 24-70mm F2.8 EX DG Macro"; + lenses["26 54 37 73 24 34 1C 02"] = "Sigma 24-135mm F2.8-4.5"; + lenses["26 54 3C 5C 24 24 1C 02"] = "Sigma 28-70mm F2.8 EX"; + lenses["26 58 31 31 14 14 1C 02"] = "Sigma 20mm F1.8 EX Aspherical DG DF RF"; + lenses["26 58 37 37 14 14 1C 02"] = "Sigma 24mm F1.8 EX Aspherical DG DF MACRO"; + lenses["26 58 3C 3C 14 14 1C 02"] = "Sigma 28mm F1.8 EX DG DF"; + lenses["27 48 8E 8E 24 24 1D 02"] = "AF-I Nikkor 300mm f/2.8D IF-ED"; + lenses["27 48 8E 8E 24 24 E1 02"] = "AF-I Nikkor 300mm f/2.8D IF-ED + TC-17E"; + lenses["27 48 8E 8E 24 24 F1 02"] = "AF-I Nikkor 300mm f/2.8D IF-ED + TC-14E"; + lenses["27 48 8E 8E 24 24 F2 02"] = "AF-I Nikkor 300mm f/2.8D IF-ED + TC-20E"; + lenses["28 3C A6 A6 30 30 1D 02"] = "AF-I Nikkor 600mm f/4D IF-ED"; + lenses["2A 54 3C 3C 0C 0C 26 02"] = "AF Nikkor 28mm f/1.4D"; + lenses["2C 48 6A 6A 18 18 27 02"] = "AF DC-Nikkor 105mm f/2D"; + lenses["2D 48 80 80 30 30 21 02"] = "AF Micro-Nikkor 200mm f/4D IF-ED"; + lenses["2E 48 5C 82 30 3C 28 02"] = "AF Nikkor 70-210mm f/4-5.6D"; + lenses["2F 40 30 44 2C 34 29 02"] = "Unknown 20-35mm f/3.5-4.5D"; + lenses["2F 48 30 44 24 24 29 02"] = "Tokina AT-X 235 AF PRO - AF 20-35mm f/2.8"; + lenses["31 54 56 56 24 24 25 02"] = "AF Micro-Nikkor 60mm f/2.8D"; + lenses["32 53 64 64 24 24 35 02"] = "Tamron SP AF90mm f/2.8 Di Macro 1:2 (272E)"; + lenses["32 54 50 50 24 24 35 02"] = "Sigma 50mm F2.8 EX DG Macro"; + lenses["32 54 6A 6A 24 24 35 02"] = "AF Micro-Nikkor 105mm f/2.8D"; + lenses["33 48 2D 2D 24 24 31 02"] = "AF Nikkor 18mm f/2.8D"; + lenses["33 54 3C 5E 24 24 62 02"] = "Tamron SP AF28-75mm f/2.8 XR Di LD Aspherical (IF) Macro"; + lenses["34 48 29 29 24 24 32 02"] = "AF Fisheye Nikkor 16mm f/2.8D"; + lenses["36 48 37 37 24 24 34 02"] = "AF Nikkor 24mm f/2.8D"; + lenses["37 48 30 30 24 24 36 02"] = "AF Nikkor 20mm f/2.8D"; + lenses["38 4C 62 62 14 14 37 02"] = "AF Nikkor 85mm f/1.8D"; + lenses["3A 40 3C 5C 2C 34 39 02"] = "AF Zoom-Nikkor 28-70mm f/3.5-4.5D"; + lenses["3B 48 44 5C 24 24 3A 02"] = "AF Zoom-Nikkor 35-70mm f/2.8D N"; + lenses["3D 3C 44 60 30 3C 3E 02"] = "AF Zoom-Nikkor 35-80mm f/4-5.6D"; + lenses["3E 48 3C 3C 24 24 3D 02"] = "AF Nikkor 28mm f/2.8D"; + lenses["41 48 7C 7C 24 24 43 02"] = "AF Nikkor 180mm f/2.8D IF-ED"; + lenses["42 54 44 44 18 18 44 02"] = "AF Nikkor 35mm f/2D"; + lenses["43 54 50 50 0C 0C 46 02"] = "AF Nikkor 50mm f/1.4D"; + lenses["45 3D 3C 60 2C 3C 48 02"] = "Tamron AF28-80mm f/3.5-5.6 Aspherical"; + lenses["45 40 3C 60 2C 3C 48 02"] = "AF Zoom-Nikkor 28-80mm F/3.5-5.6D"; + lenses["45 41 37 72 2C 3C 48 02"] = "Tamron SP AF24-135mm f/3.5-5.6 AD Aspherical (IF) Macro"; + lenses["46 3C 44 60 30 3C 49 02"] = "AF Zoom-Nikkor 35-80mm f/4-5.6D N"; + lenses["47 42 37 50 2A 34 4A 02"] = "AF Zoom-Nikkor 24-50mm f/3.3-4.5D"; + lenses["48 38 1F 37 34 3C 4B 06"] = "Sigma 12-24mm F4.5-5.6 EX Aspherical DG HSM"; + lenses["48 3C 19 31 30 3C 4B 06"] = "Sigma 10-20mm F4-5.6 EX DC HSM"; + lenses["48 3C 50 A0 30 40 4B 02"] = "Sigma 50-500mm F4-6.3 EX APO RF HSM"; + lenses["48 3C 8E B0 3C 3C 4B 02"] = "Sigma APO 300-800 F5.6 EX DG HSM"; + lenses["48 48 24 24 24 24 4B 02"] = "Sigma 14mm F2.8 EX Aspherical HSM"; + lenses["48 48 2B 44 24 30 4B 06"] = "Sigma 17-35mm F2.8-4 EX DG Aspherical HSM"; + lenses["48 48 68 8E 30 30 4B 02"] = "Sigma 100-300mm F4 EX IF HSM"; + lenses["48 48 76 76 24 24 4B 06"] = "Sigma 150mm F2.8 EX DG APO Macro HSM"; + lenses["48 48 8E 8E 24 24 4B 02"] = "AF-S Nikkor 300mm f/2.8D IF-ED"; + lenses["48 4C 7C 7C 2C 2C 4B 02"] = "Sigma 180mm F3.5 EX DG Macro"; + lenses["48 4C 7D 7D 2C 2C 4B 02"] = "Sigma APO MACRO 180mm F3.5 EX DG HSM"; + lenses["48 54 3E 3E 0C 0C 4B 06"] = "Sigma 30mm F1.4 EX DC HSM"; + lenses["48 54 5C 80 24 24 4B 02"] = "Sigma 70-200mm F2.8 EX APO IF HSM"; + lenses["48 54 6F 8E 24 24 4B 02"] = "Sigma APO 120-300mm F2.8 EX DG HSM"; + lenses["48 54 8E 8E 24 24 4B 02"] = "Sigma APO 300mm F2.8 EX DG HSM"; + lenses["49 3C A6 A6 30 30 4C 02"] = "AF-S Nikkor 600mm f/4D IF-ED"; + lenses["49 3C A6 A6 30 30 F1 02"] = "AF-S Nikkor 600mm f/4D IF-ED + TC-14E"; + lenses["49 3C A6 A6 30 30 F2 02"] = "AF-S Nikkor 600mm f/4D IF-ED + TC-20E"; + lenses["4A 54 62 62 0C 0C 4D 02"] = "AF Nikkor 85mm f/1.4D IF"; + lenses["4C 40 37 6E 2C 3C 4F 02"] = "AF Zoom-Nikkor 24-120mm f/3.5-5.6D IF"; + lenses["4D 40 3C 80 2C 3C 62 02"] = "AF Zoom-Nikkor 28-200mm f/3.5-5.6D IF"; + lenses["4D 41 3C 8E 2B 40 62 02"] = "Tamron AF28-300mm f/3.5-6.3 XR Di LD Aspherical (IF)"; + lenses["4D 41 3C 8E 2C 40 62 02"] = "Tamron AF28-300mm f/3.5-6.3 XR LD Aspherical (IF)"; + lenses["4E 48 72 72 18 18 51 02"] = "AF DC-Nikkor 135mm f/2D"; + lenses["4F 40 37 5C 2C 3C 53 06"] = "IX-Nikkor 24-70mm f/3.5-5.6"; + lenses["53 48 60 80 24 24 60 02"] = "AF Zoom-Nikkor 80-200mm f/2.8D ED"; + lenses["54 44 5C 7C 34 3C 58 02"] = "AF Zoom-Micro Nikkor 70-180mm f/4.5-5.6D ED"; + lenses["56 3C 5C 8E 30 3C 1C 02"] = "Sigma 70-300mm F4-5.6 APO Macro Super II"; + lenses["56 48 5C 8E 30 3C 5A 02"] = "AF Zoom-Nikkor 70-300mm f/4-5.6D ED"; + lenses["59 48 98 98 24 24 5D 02"] = "AF-S Nikkor 400mm f/2.8D IF-ED"; + lenses["5A 3C 3E 56 30 3C 5E 06"] = "IX-Nikkor 30-60mm f/4-5.6"; + lenses["5D 48 3C 5C 24 24 63 02"] = "AF-S Zoom-Nikkor 28-70mm f/2.8D IF-ED"; + lenses["5E 48 60 80 24 24 64 02"] = "AF-S Zoom-Nikkor 80-200mm f/2.8D IF-ED"; + lenses["5F 40 3C 6A 2C 34 65 02"] = "AF Zoom-Nikkor 28-105mm f/3.5-4.5D IF"; + lenses["60 40 3C 60 2C 3C 66 02"] = "AF Zoom-Nikkor 28-80mm f/3.5-5.6D"; + lenses["61 44 5E 86 34 3C 67 02"] = "AF Zoom-Nikkor 75-240mm f/4.5-5.6D"; + lenses["63 48 2B 44 24 24 68 02"] = "AF-S Nikkor 17-35mm f/2.8D IF-ED"; + lenses["64 00 62 62 24 24 6A 02"] = "PC Micro-Nikkor 85mm f/2.8D"; + lenses["65 44 60 98 34 3C 6B 0A"] = "AF VR Zoom-Nikkor 80-400mm f/4.5-5.6D ED"; + lenses["66 40 2D 44 2C 34 6C 02"] = "AF Zoom-Nikkor 18-35mm f/3.5-4.5D IF-ED"; + lenses["67 48 37 62 24 30 6D 02"] = "AF Zoom-Nikkor 24-85mm f/2.8-4D IF"; + lenses["67 54 37 5C 24 24 1C 02"] = "Sigma 24-70mm F2.8 EX DG Macro"; + lenses["68 42 3C 60 2A 3C 6E 06"] = "AF Zoom-Nikkor 28-80mm f/3.3-5.6G"; + lenses["69 48 5C 8E 30 3C 6F 02"] = "Tamron AF70-300mm f/4-5.6 LD Macro 1:2"; + lenses["69 48 5C 8E 30 3C 6F 06"] = "AF Zoom-Nikkor 70-300mm f/4-5.6G"; + lenses["6A 48 8E 8E 30 30 70 02"] = "AF-S Nikkor 300mm f/4D IF-ED"; + lenses["6B 48 24 24 24 24 71 02"] = "AF Nikkor ED 14mm f/2.8D"; + lenses["6D 48 8E 8E 24 24 73 02"] = "AF-S Nikkor 300mm f/2.8D IF-ED II"; + lenses["6E 48 98 98 24 24 74 02"] = "AF-S Nikkor 400mm f/2.8D IF-ED II"; + lenses["6F 3C A0 A0 30 30 75 02"] = "AF-S Nikkor 500mm f/4D IF-ED II"; + lenses["70 3C A6 A6 30 30 76 02"] = "AF-S Nikkor 600mm f/4D IF-ED II"; + lenses["72 48 4C 4C 24 24 77 00"] = "Nikkor 45mm f/2.8 P"; + lenses["74 40 37 62 2C 34 78 06"] = "AF-S Zoom-Nikkor 24-85mm f/3.5-4.5G IF-ED"; + lenses["75 40 3C 68 2C 3C 79 06"] = "AF Zoom-Nikkor 28-100mm f/3.5-5.6G"; + lenses["76 58 50 50 14 14 7A 02"] = "AF Nikkor 50mm f/1.8D"; + lenses["77 44 61 98 34 3C 7B 0E"] = "Sigma 80-400mm f4.5-5.6 EX OS"; + lenses["77 48 5C 80 24 24 7B 0E"] = "AF-S VR Zoom-Nikkor 70-200mm f/2.8G IF-ED"; + lenses["78 40 37 6E 2C 3C 7C 0E"] = "AF-S VR Zoom-Nikkor 24-120mm f/3.5-5.6G IF-ED"; + lenses["79 40 11 11 2C 2C 1C 06"] = "Sigma 8mm F3.5 EX"; + lenses["79 40 3C 80 2C 3C 7F 06"] = "AF Zoom-Nikkor 28-200mm f/3.5-5.6G IF-ED"; + lenses["79 48 5C 5C 24 24 1C 06"] = "Sigma 70mm F2.8 EX DG Macro"; + lenses["7A 3B 53 80 30 3C 4B 06"] = "Sigma 55-200mm F4-5.6 DC HSM"; + lenses["7A 3C 1F 37 30 30 7E 06"] = "AF-S DX Zoom-Nikkor 12-24mm f/4G IF-ED"; + lenses["7A 40 2D 50 2C 3C 4B 06"] = "Sigma 18-50mm F3.5-5.6 DC HSM"; + lenses["7A 47 2B 5C 24 34 4B 06"] = "Sigma 17-70mm F2.8-4.5 DC Macro Asp. IF HSM"; + lenses["7A 47 50 76 24 24 4B 06"] = "Sigma APO 50-150mm F2.8 EX DC HSM"; + lenses["7A 48 2D 50 24 24 4B 06"] = "Sigma 18-50mm F2.8 EX DC HSM"; + lenses["7B 48 80 98 30 30 80 0E"] = "AF-S VR Zoom-Nikkor 200-400mm f/4G IF-ED"; + lenses["7D 48 2B 53 24 24 82 06"] = "AF-S DX Zoom-Nikkor 17-55mm f/2.8G IF-ED"; + lenses["7F 40 2D 5C 2C 34 84 06"] = "AF-S DX Zoom-Nikkor 18-70mm f/3.5-4.5G IF-ED"; + lenses["7F 48 2B 5C 24 34 1C 06"] = "Sigma 17-70mm F2.8-4.5 DC Macro Asp. IF"; + lenses["80 48 1A 1A 24 24 85 06"] = "AF DX Fisheye-Nikkor 10.5mm f/2.8G ED"; + lenses["81 54 80 80 18 18 86 0E"] = "AF-S VR Nikkor 200mm f/2G IF-ED"; + lenses["82 48 8E 8E 24 24 87 0E"] = "AF-S VR Nikkor 300mm f/2.8G IF-ED"; + lenses["89 3C 53 80 30 3C 8B 06"] = "AF-S DX Zoom-Nikkor 55-200mm f/4-5.6G ED"; + lenses["8A 54 6A 6A 24 24 8C 0E"] = "AF-S VR Micro-Nikkor 105mm f/2.8G IF-ED"; + lenses["8B 40 2D 80 2C 3C 8D 0E"] = "AF-S DX VR Zoom-Nikkor 18-200mm f/3.5-5.6G IF-ED"; + lenses["8B 40 2D 80 2C 3C FD 0E"] = "AF-S DX VR Zoom-Nikkor 18-200mm f/3.5-5.6G IF-ED"; + lenses["8C 40 2D 53 2C 3C 8E 06"] = "AF-S DX Zoom-Nikkor 18-55mm f/3.5-5.6G ED"; + lenses["8D 44 5C 8E 34 3C 8F 0E"] = "AF-S VR Zoom-Nikkor 70-300mm f/4.5-5.6G IF-ED"; + lenses["8F 40 2D 72 2C 3C 91 06"] = "AF-S DX Zoom-Nikkor 18-135mm f/3.5-5.6G IF-ED"; + lenses["90 3B 53 80 30 3C 92 0E"] = "AF-S DX VR Zoom-Nikkor 55-200mm f/4-5.6G IF-ED"; + lenses["92 48 24 37 24 24 94 06"] = "AF-S Zoom-Nikkor 14-24mm f/2.8G ED"; + lenses["93 48 37 5C 24 24 95 06"] = "AF-S Zoom-Nikkor 24-70mm f/2.8G ED"; + lenses["94 40 2D 53 2C 3C 96 06"] = "AF-S DX Zoom-Nikkor 18-55mm f/3.5-5.6G ED II"; + lenses["95 00 37 37 2C 2C 97 06"] = "PC-E Nikkor 24mm f/3.5D ED"; + lenses["95 4C 37 37 2C 2C 97 02"] = "PC-E Nikkor 24mm f/3.5D ED"; + lenses["96 48 98 98 24 24 98 0E"] = "AF-S VR Nikkor 400mm f/2.8G ED"; + lenses["97 3C A0 A0 30 30 99 0E"] = "AF-S VR Nikkor 500mm f/4G ED"; + lenses["98 3C A6 A6 30 30 9A 0E"] = "AF-S VR Nikkor 600mm f/4G ED"; + lenses["99 40 29 62 2C 3C 9B 0E"] = "AF-S DX VR Zoom-Nikkor 16-85mm f/3.5-5.6G ED"; + lenses["9A 40 2D 53 2C 3C 9C 0E"] = "AF-S DX VR Zoom-Nikkor 18-55mm f/3.5-5.6G"; + lenses["9C 54 56 56 24 24 9E 06"] = "AF-S Micro Nikkor 60mm f/2.8G ED"; + lenses["9E 40 2D 6A 2C 3C A0 0E"] = "AF-S DX VR Zoom-Nikkor 18-105mm f/3.5-5.6G ED"; + lenses["B6 48 37 56 24 24 1C 02"] = "Sigma 24-60mm F2.8 EX DG"; + lenses["CE 34 76 A0 38 40 4B 0E"] = "Sigma 150-500mm F5-6.3 DG OS APO HSM"; + lenses["E0 3C 5C 8E 30 3C 4B 06"] = "Sigma 70-300mm F4-5.6 APO DG Macro HSM"; + lenses["EE 48 5C 80 24 24 4B 06"] = "Sigma 70-200mm F2.8 EX APO DG Macro HSM II"; + lenses["F5 48 76 76 24 24 4B 06"] = "Sigma 150mm F2.8 EX DG APO Macro HSM"; + lenses["F8 54 3E 3E 0C 0C 4B 06"] = "Sigma 30mm F1.4 EX DC HSM"; + lenses["F9 3C 19 31 30 3C 4B 06"] = "Sigma 10-20mm F4-5.6 EX DC HSM"; + lenses["FE 47 00 00 24 24 4B 06"] = "Sigma 4.5mm F2.8 EX DC Circular Fisheye HSM"; + } + virtual std::string toString (Tag* t) { + + static const unsigned char xlat[2][256] = { + { 0xc1,0xbf,0x6d,0x0d,0x59,0xc5,0x13,0x9d,0x83,0x61,0x6b,0x4f,0xc7,0x7f,0x3d,0x3d, + 0x53,0x59,0xe3,0xc7,0xe9,0x2f,0x95,0xa7,0x95,0x1f,0xdf,0x7f,0x2b,0x29,0xc7,0x0d, + 0xdf,0x07,0xef,0x71,0x89,0x3d,0x13,0x3d,0x3b,0x13,0xfb,0x0d,0x89,0xc1,0x65,0x1f, + 0xb3,0x0d,0x6b,0x29,0xe3,0xfb,0xef,0xa3,0x6b,0x47,0x7f,0x95,0x35,0xa7,0x47,0x4f, + 0xc7,0xf1,0x59,0x95,0x35,0x11,0x29,0x61,0xf1,0x3d,0xb3,0x2b,0x0d,0x43,0x89,0xc1, + 0x9d,0x9d,0x89,0x65,0xf1,0xe9,0xdf,0xbf,0x3d,0x7f,0x53,0x97,0xe5,0xe9,0x95,0x17, + 0x1d,0x3d,0x8b,0xfb,0xc7,0xe3,0x67,0xa7,0x07,0xf1,0x71,0xa7,0x53,0xb5,0x29,0x89, + 0xe5,0x2b,0xa7,0x17,0x29,0xe9,0x4f,0xc5,0x65,0x6d,0x6b,0xef,0x0d,0x89,0x49,0x2f, + 0xb3,0x43,0x53,0x65,0x1d,0x49,0xa3,0x13,0x89,0x59,0xef,0x6b,0xef,0x65,0x1d,0x0b, + 0x59,0x13,0xe3,0x4f,0x9d,0xb3,0x29,0x43,0x2b,0x07,0x1d,0x95,0x59,0x59,0x47,0xfb, + 0xe5,0xe9,0x61,0x47,0x2f,0x35,0x7f,0x17,0x7f,0xef,0x7f,0x95,0x95,0x71,0xd3,0xa3, + 0x0b,0x71,0xa3,0xad,0x0b,0x3b,0xb5,0xfb,0xa3,0xbf,0x4f,0x83,0x1d,0xad,0xe9,0x2f, + 0x71,0x65,0xa3,0xe5,0x07,0x35,0x3d,0x0d,0xb5,0xe9,0xe5,0x47,0x3b,0x9d,0xef,0x35, + 0xa3,0xbf,0xb3,0xdf,0x53,0xd3,0x97,0x53,0x49,0x71,0x07,0x35,0x61,0x71,0x2f,0x43, + 0x2f,0x11,0xdf,0x17,0x97,0xfb,0x95,0x3b,0x7f,0x6b,0xd3,0x25,0xbf,0xad,0xc7,0xc5, + 0xc5,0xb5,0x8b,0xef,0x2f,0xd3,0x07,0x6b,0x25,0x49,0x95,0x25,0x49,0x6d,0x71,0xc7 }, + { 0xa7,0xbc,0xc9,0xad,0x91,0xdf,0x85,0xe5,0xd4,0x78,0xd5,0x17,0x46,0x7c,0x29,0x4c, + 0x4d,0x03,0xe9,0x25,0x68,0x11,0x86,0xb3,0xbd,0xf7,0x6f,0x61,0x22,0xa2,0x26,0x34, + 0x2a,0xbe,0x1e,0x46,0x14,0x68,0x9d,0x44,0x18,0xc2,0x40,0xf4,0x7e,0x5f,0x1b,0xad, + 0x0b,0x94,0xb6,0x67,0xb4,0x0b,0xe1,0xea,0x95,0x9c,0x66,0xdc,0xe7,0x5d,0x6c,0x05, + 0xda,0xd5,0xdf,0x7a,0xef,0xf6,0xdb,0x1f,0x82,0x4c,0xc0,0x68,0x47,0xa1,0xbd,0xee, + 0x39,0x50,0x56,0x4a,0xdd,0xdf,0xa5,0xf8,0xc6,0xda,0xca,0x90,0xca,0x01,0x42,0x9d, + 0x8b,0x0c,0x73,0x43,0x75,0x05,0x94,0xde,0x24,0xb3,0x80,0x34,0xe5,0x2c,0xdc,0x9b, + 0x3f,0xca,0x33,0x45,0xd0,0xdb,0x5f,0xf5,0x52,0xc3,0x21,0xda,0xe2,0x22,0x72,0x6b, + 0x3e,0xd0,0x5b,0xa8,0x87,0x8c,0x06,0x5d,0x0f,0xdd,0x09,0x19,0x93,0xd0,0xb9,0xfc, + 0x8b,0x0f,0x84,0x60,0x33,0x1c,0x9b,0x45,0xf1,0xf0,0xa3,0x94,0x3a,0x12,0x77,0x33, + 0x4d,0x44,0x78,0x28,0x3c,0x9e,0xfd,0x65,0x57,0x16,0x94,0x6b,0xfb,0x59,0xd0,0xc8, + 0x22,0x36,0xdb,0xd2,0x63,0x98,0x43,0xa1,0x04,0x87,0x86,0xf7,0xa6,0x26,0xbb,0xd6, + 0x59,0x4d,0xbf,0x6a,0x2e,0xaa,0x2b,0xef,0xe6,0x78,0xb6,0x4e,0xe0,0x2f,0xdc,0x7c, + 0xbe,0x57,0x19,0x32,0x7e,0x2a,0xd0,0xb8,0xba,0x29,0x00,0x3c,0x52,0x7d,0xa8,0x49, + 0x3b,0x2d,0xeb,0x25,0x49,0xfa,0xa3,0xaa,0x39,0xa7,0xc5,0xa7,0x50,0x11,0x36,0xfb, + 0xc6,0x67,0x4a,0xf5,0xa5,0x12,0x65,0x7e,0xb0,0xdf,0xaf,0x4e,0xb3,0x61,0x7f,0x2f } }; + + int ver = (t->toInt (0, BYTE) - '0') * 1000 + (t->toInt (1, BYTE) - '0') * 100 + (t->toInt (2, BYTE) - '0') * 10 + (t->toInt (3, BYTE) - '0'); + + std::ostringstream ld; + ld << "Version = " << ver << std::endl; + + int lenstype = t->getParent()->getTag(0x0083)->toInt(0,BYTE); + + std::ostringstream lid; + lid.setf (std::ios_base::hex, std::ios_base::basefield); + lid.setf (std::ios_base::uppercase); + + std::string model = t->getParent()->getParent()->getParent()->getTag(0x0110)->valueToString(); + int lidoffs = 7; + bool d100 = false; + if (model.substr(0,10)=="NIKON D100" || model.substr(0,9)=="NIKON D1X") { + lidoffs = 0; + d100 = true; + } + + unsigned char buffer[15]; + if (d100) + memcpy (buffer, t->getValue()+6, 7); + else + memcpy (buffer, t->getValue()+4, 15); + + if (ver>=201) { + const unsigned char* serval = t->getParent()->getTag(0x001d)->getValue (); + int serial = 0; + for (int i=0; serval[i]; i++) + serial = serial*10 + (isdigit(serval[i]) ? serval[i] - '0' : serval[i] % 10); + const unsigned char* scval = t->getParent()->getTag(0x00a7)->getValue (); + int key = 0; + for (int i=0; i<4; i++) + key ^= scval[i]; + + unsigned char ci = xlat[0][serial & 0xff]; + unsigned char cj = xlat[1][key]; + unsigned char ck = 0x60; + for (int i=0; i < 15; i++) + buffer[i] ^= (cj += ci * ck++); + } + + if (!d100) { + ld << "ExitPupilPosition = " << (int) buffer[0] << std::endl; + ld << "AFAperture = " << (int) buffer[1] << std::endl; + ld << "FocusPosition = " << (int) buffer[4] << std::endl; + ld << "FocusDistance = " << (int) buffer[5] << std::endl; + ld << "FocalLength = " << (int) buffer[6] << std::endl; + ld << "EffectiveMaxAperture = " << (int) buffer[14] << std::endl; + } + + for (int i=0; i<7; i++) + lid << std::setw(2) << std::setfill('0') << (int)buffer[lidoffs+i] << ' '; + lid << std::setw(2) << std::setfill('0') << lenstype; + + std::map::iterator r = lenses.find (lid.str()); + if (r!=lenses.end()) + ld << "Lens = " << r->second; + else + ld << "Lens = Unknown, ID=" << lid.str(); + + return ld.str(); + } + +}; +NALensDataInterpreter naLensDataInterpreter; + +const TagAttrib nikon2Attribs[] = { + 0, 1, 0, 0, 0x0002, "Unknown", &stdInterpreter, + 0, 1, 0, 0, 0x0003, "Quality", &stdInterpreter, + 0, 1, 0, 0, 0x0004, "ColorMode", &stdInterpreter, + 0, 1, 0, 0, 0x0005, "ImageAdjustment", &stdInterpreter, + 0, 1, 0, 0, 0x0006, "ISOSpeed", &naISOInterpreter, + 0, 1, 0, 0, 0x0007, "WhiteBalance", &stdInterpreter, + 0, 1, 0, 0, 0x0008, "Focus", &stdInterpreter, + 0, 1, 0, 0, 0x0009, "Unknown", &stdInterpreter, + 0, 1, 0, 0, 0x000a, "DigitalZoom", &stdInterpreter, + 0, 1, 0, 0, 0x000b, "AuxiliaryLens", &stdInterpreter, + 0, 1, 0, 0, 0x0f00, "Unknown", &stdInterpreter, + -1, 0, 0, 0, 0, "", NULL}; + +const TagAttrib nikon3Attribs[] = { + 0, 1, 0, 0, 0x0001, "MakerNoteVersion", &stdInterpreter, + 0, 1, 0, 0, 0x0002, "ISOSpeed", &naISOInterpreter, + 0, 1, 0, 0, 0x0003, "ColorMode", &stdInterpreter, + 0, 1, 0, 0, 0x0004, "Quality", &stdInterpreter, + 0, 1, 0, 0, 0x0005, "WhiteBalance", &stdInterpreter, + 0, 1, 0, 0, 0x0006, "Sharpness", &stdInterpreter, + 0, 1, 0, 0, 0x0007, "FocusMode", &stdInterpreter, + 0, 1, 0, 0, 0x0008, "FlashSetting", &stdInterpreter, + 0, 1, 0, 0, 0x0009, "FlashType", &stdInterpreter, + 0, 1, 0, 0, 0x000b, "WhiteBalanceFineTune", &stdInterpreter, + 0, 3, 0, 0, 0x000c, "ColorBalance1", &stdInterpreter, + 0, 1, 0, 0, 0x000d, "ProgramShift", &stdInterpreter, + 0, 1, 0, 0, 0x000e, "ExposureDifference", &stdInterpreter, + 0, 1, 0, 0, 0x000f, "ISOSelection", &naISOInterpreter, + 0, 1, 0, 0, 0x0010, "DataDump", &stdInterpreter, + 1, 1, 0, 0, 0x0011, "NikonPreview", &stdInterpreter, + 0, 1, 0, 0, 0x0012, "FlashExposureComp", &stdInterpreter, + 0, 1, 0, 0, 0x0013, "ISOSetting", &stdInterpreter, + 0, 1, 0, 0, 0x0016, "ImageBoundary", &stdInterpreter, + 0, 1, 0, 0, 0x0018, "FlashExposureBracketValue", &stdInterpreter, + 0, 1, 0, 0, 0x0019, "ExposureBracketValue", &stdInterpreter, + 0, 1, 0, 0, 0x001a, "ImageProcessing", &stdInterpreter, + 0, 1, 0, 0, 0x001b, "CropHiSpeed", &stdInterpreter, + 0, 1, 0, 0, 0x001d, "SerialNumber", &stdInterpreter, + 0, 1, 0, 0, 0x001e, "ColorSpace", &stdInterpreter, + 0, 1, 0, 0, 0x0020, "ImageAuthentication", &stdInterpreter, + 0, 1, 0, 0, 0x0080, "ImageAdjustment", &stdInterpreter, + 0, 1, 0, 0, 0x0081, "ToneComp", &stdInterpreter, + 0, 1, 0, 0, 0x0082, "AuxiliaryLens", &stdInterpreter, + 0, 1, 0, 0, 0x0083, "LensType", &naLensTypeInterpreter, + 0, 1, 0, 0, 0x0084, "Lens", &stdInterpreter, + 0, 1, 0, 0, 0x0085, "ManualFocusDistance", &stdInterpreter, + 0, 1, 0, 0, 0x0086, "DigitalZoom", &stdInterpreter, + 0, 1, 0, 0, 0x0087, "FlashMode", &naFlashModeInterpreter, + 0, 1, 0, 0, 0x0088, "AFInfo", &naAFInfoInterpreter, + 0, 1, 0, 0, 0x0089, "ShootingMode", &naShootingModeInterpreter, + 0, 1, 0, 0, 0x008a, "AutoBracketRelease", &stdInterpreter, + 0, 1, 0, 0, 0x008b, "LensFStops", &stdInterpreter, + 0, 1, 0, 0, 0x008c, "NEFCurve1", &stdInterpreter, + 0, 1, 0, 0, 0x008d, "ColorHue", &stdInterpreter, + 0, 1, 0, 0, 0x008f, "SceneMode", &stdInterpreter, + 0, 1, 0, 0, 0x0090, "LightSource", &stdInterpreter, + 0, 1, 0, 0, 0x0091, "ShotInfo", &stdInterpreter, + 0, 1, 0, 0, 0x0092, "HueAdjustment", &stdInterpreter, + 0, 1, 0, 0, 0x0094, "Saturation", &stdInterpreter, + 0, 1, 0, 0, 0x0095, "NoiseReduction", &stdInterpreter, + 0, 1, 0, 0, 0x0096, "NEFCurve2", &stdInterpreter, + 0, 3, 0, 0, 0x0097, "ColorBalance", &stdInterpreter, + 0, 1, 0, 0, 0x0098, "LensData", &naLensDataInterpreter, + 0, 1, 0, 0, 0x0099, "RawImageCenter", &stdInterpreter, + 0, 1, 0, 0, 0x009a, "SensorPixelSize", &stdInterpreter, + 0, 1, 0, 0, 0x00a0, "SerialNumber", &stdInterpreter, + 0, 1, 0, 0, 0x00a2, "ImageDataSize", &stdInterpreter, + 0, 1, 0, 0, 0x00a5, "ImageCount", &stdInterpreter, + 0, 1, 0, 0, 0x00a6, "DeletedImageCount", &stdInterpreter, + 0, 1, 0, 0, 0x00a7, "ShutterCount", &stdInterpreter, + 0, 1, 0, 0, 0x00a9, "ImageOptimization", &stdInterpreter, + 0, 1, 0, 0, 0x00aa, "Saturation", &stdInterpreter, + 0, 1, 0, 0, 0x00ab, "VariProgram", &stdInterpreter, + 0, 1, 0, 0, 0x00ac, "ImageStabilization", &stdInterpreter, + 0, 1, 0, 0, 0x00ad, "AFResponse", &stdInterpreter, + 0, 1, 0, 0, 0x00b0, "MultiExposure", &stdInterpreter, + 0, 1, 0, 0, 0x00b1, "HighISONoiseReduction", &naHiISONRInterpreter, + 0, 1, 0, 0, 0x0e00, "PrintIM", &stdInterpreter, + 0, 0, 0, 0, 0x0e01, "NikonCaptureData", &stdInterpreter, + 0, 0, 0, 0, 0x0e09, "NikonCaptureVersion", &stdInterpreter, + 0, 0, 0, 0, 0x0e0e, "NikonCaptureOffsets", &stdInterpreter, + 0, 0, 0, 0, 0x0e10, "NikonScanIFD", &stdInterpreter, + -1, 0, 0, 0, 0, "", NULL}; + +} +#endif + diff --git a/rtexif/olympusattribs.cc b/rtexif/olympusattribs.cc new file mode 100755 index 000000000..079c8c259 --- /dev/null +++ b/rtexif/olympusattribs.cc @@ -0,0 +1,673 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _OLYMPUSATTRIBS_ +#define _OLYMPUSATTRIBS_ + +#include +#include +#include +#include +#include +#include + +namespace rtexif { + +class OLOnOffInterpreter : public Interpreter { + public: + OLOnOffInterpreter () {} + virtual std::string toString (Tag* t) { + if (t->toInt()==0) + return "Off"; + else + return "On"; + } +}; +OLOnOffInterpreter olOnOffInterpreter; + +class OLYesNoInterpreter : public Interpreter { + public: + OLYesNoInterpreter () {} + virtual std::string toString (Tag* t) { + if (t->toInt()==0) + return "No"; + else + return "Yes"; + } +}; +OLYesNoInterpreter olYesNoInterpreter; + +class OLApertureInterpreter : public Interpreter { + public: + OLApertureInterpreter () {} + virtual std::string toString (Tag* t) { + std::ostringstream str; + str.precision(2); + str << pow(2, t->toInt() / 512.0); + return str.str(); + } +}; +OLApertureInterpreter olApertureInterpreter; + +class OLLensTypeInterpreter : public Interpreter { + std::map lenses; + public: + OLLensTypeInterpreter () { + lenses[1] = "Zuiko Digital ED 50mm F2.0 Macro"; + lenses[1 +65536] = "Zuiko Digital 40-150mm F3.5-4.5"; + lenses[2] = "Zuiko Digital ED 150mm F2.0"; + lenses[3] = "Zuiko Digital ED 300mm F2.8"; + lenses[5] = "Zuiko Digital 14-54mm F2.8-3.5"; + lenses[5 +65536] = "Zuiko Digital Pro ED 90-250mm F2.8"; + lenses[6] = "Zuiko Digital ED 50-200mm F2.8-3.5"; + lenses[6 +65536] = "Zuiko Digital ED 8mm F3.5 Fisheye"; + lenses[7] = "Zuiko Digital 11-22mm F2.8-3.5"; + lenses[7 +65536] = "Zuiko Digital 18-180mm F3.5-6.3"; + lenses[8] = "Zuiko Digital 70-300mm F4.0-5.6"; + lenses[21] = "Zuiko Digital ED 7-14mm F4.0"; + lenses[23] = "Zuiko Digital Pro ED 35-100mm F2.0"; + lenses[24] = "Zuiko Digital 14-45mm F3.5-5.6"; + lenses[32] = "Zuiko Digital 35mm F3.5 Macro"; + lenses[34] = "Zuiko Digital 17.5-45mm F3.5-5.6"; + lenses[35] = "Zuiko Digital ED 14-42mm F3.5-5.6"; + lenses[36] = "Zuiko Digital ED 40-150mm F4.0-5.6"; + lenses[48] = "Zuiko Digital ED 50-200mm SWD F2.8-3.5"; + lenses[49] = "Zuiko Digital ED 12-60mm SWD F2.8-4.0"; + lenses[256+ 1] = "18-50mm F3.5-5.6"; + lenses[256+ 2] = "55-200mm F4.0-5.6 DC"; + lenses[256+ 3] = "18-125mm F3.5-5.6 DC"; + lenses[256+ 4] = "18-125mm F3.5-5.6"; + lenses[256+ 5] = "30mm F1.4"; + lenses[256+ 6] = "50-500mm F4.0-6.3 EX DG APO HSM RF"; + lenses[256+ 7] = "105mm F2.8 DG"; + lenses[256+ 8] = "150mm F2.8 DG HSM"; + lenses[256+ 17] = "135-400mm F4.5-5.6 DG ASP APO RF"; + lenses[256+ 18] = "300-800mm F5.6 EX DG APO"; + lenses[512+ 1] = "D Vario Elmarit 14-50mm, F2.8-3.5 Asph."; + lenses[512+ 2] = "D Summilux 25mm, F1.4 Asph."; + lenses[512+ 4] = "Vario Elmar 14-150mm f3.5-5.6"; + lenses[768+ 1] = "D Vario Elmarit 14-50mm, F2.8-3.5 Asph."; + lenses[768+ 2] = "D Summilux 25mm, F1.4 Asph."; + } + virtual std::string toString (Tag* t) { + int make = t->toInt(0); + int model = t->toInt(2); + int add = 0; + if (make==0 && (model==1 || model==5 || model==7 || model==6)) + add += 65536 * t->toInt(3); + return lenses [256 * make + model + add]; + } +}; +OLLensTypeInterpreter olLensTypeInterpreter; + +class OLFlashTypeInterpreter : public ChoiceInterpreter { + public: + OLFlashTypeInterpreter () { + choices[0] = "None"; + choices[2] = "Simple E-System"; + choices[3] = "E-System"; + } +}; +OLFlashTypeInterpreter olFlashTypeInterpreter; + +class OLExposureModeInterpreter : public ChoiceInterpreter { + public: + OLExposureModeInterpreter () { + choices[1] = "Manual"; + choices[2] = "Program"; + choices[3] = "Aperture-priority AE"; + choices[4] = "Shutter speed priority AE"; + choices[5] = "Program-shift"; + } +}; +OLExposureModeInterpreter olExposureModeInterpreter; + +class OLMeteringModeInterpreter : public ChoiceInterpreter { + public: + OLMeteringModeInterpreter () { + choices[2] = "Center-weighted average"; + choices[3] = "Spot"; + choices[5] = "ESP"; + choices[261] = "Pattern+AF"; + choices[515] = "Spot+Highlight control"; + choices[1027] = "Spot+Shadow control"; + } +}; +OLMeteringModeInterpreter olMeteringModeInterpreter; + +class OLFocusModeInterpreter : public ChoiceInterpreter { + public: + OLFocusModeInterpreter () { + choices[0] = "Single AF"; + choices[1] = "Sequential shooting AF"; + choices[2] = "Continuous AF"; + choices[3] = "Multi AF"; + choices[10] = "MF"; + } +}; +OLFocusModeInterpreter olFocusModeInterpreter; + +class OLWhitebalance2Interpreter : public ChoiceInterpreter { + public: + OLWhitebalance2Interpreter () { + choices[0] = "Auto"; + choices[16] = "7500K (Fine Weather with Shade)"; + choices[17] = "6000K (Cloudy)"; + choices[18] = "5300K (Fine Weather)"; + choices[20] = "3000K (Tungsten light)"; + choices[21] = "3600K (Tungsten light-like)"; + choices[33] = "6600K (Daylight fluorescent)"; + choices[34] = "4500K (Neutral white fluorescent)"; + choices[35] = "4000K (Cool white fluorescent)"; + choices[48] = "3600K (Tungsten light-like)"; + choices[256] = "Custom WB 1"; + choices[257] = "Custom WB 2"; + choices[258] = "Custom WB 3"; + choices[259] = "Custom WB 4"; + choices[512] = "Custom WB 5400K"; + choices[513] = "Custom WB 2900K"; + choices[514] = "Custom WB 8000K"; + } +}; +OLWhitebalance2Interpreter olWhitebalance2Interpreter; + +class OLSceneModeInterpreter : public ChoiceInterpreter { + public: + OLSceneModeInterpreter () { + choices[0] = "Standard"; + choices[6] = "Auto"; + choices[7] = "Sport"; + choices[8] = "Portrait"; + choices[9] = "Landscape+Portrait"; + choices[10] = "Landscape"; + choices[11] = "Night Scene"; + choices[12] = "Self Portrait"; + choices[13] = "Panorama"; + choices[14] = "2 in 1"; + choices[15] = "Movie"; + choices[16] = "Landscape+Portrait"; + choices[17] = "Night+Portrait"; + choices[18] = "Indoor"; + choices[19] = "Fireworks"; + choices[20] = "Sunset"; + choices[22] = "Macro"; + choices[23] = "Super Macro"; + choices[24] = "Food"; + choices[25] = "Documents"; + choices[26] = "Museum"; + choices[27] = "Shoot & Select"; + choices[28] = "Beach & Snow"; + choices[29] = "Self Protrait+Timer"; + choices[30] = "Candle"; + choices[31] = "Available Light"; + choices[32] = "Behind Glass"; + choices[33] = "My Mode"; + choices[34] = "Pet"; + choices[35] = "Underwater Wide1"; + choices[36] = "Underwater Macro"; + choices[37] = "Shoot & Select1"; + choices[38] = "Shoot & Select2"; + choices[39] = "High Key"; + choices[40] = "Digital Image Stabilization"; + choices[41] = "Auction"; + choices[42] = "Beach"; + choices[43] = "Snow"; + choices[44] = "Underwater Wide2"; + choices[45] = "Low Key"; + choices[46] = "Children"; + choices[47] = "Vivid"; + choices[48] = "Nature Macro"; + choices[49] = "Underwater Snapshot"; + choices[50] = "Shooting Guide"; + } +}; +OLSceneModeInterpreter olSceneModeInterpreter; + +class OLPictureModeBWFilterInterpreter : public ChoiceInterpreter { + public: + OLPictureModeBWFilterInterpreter () { + choices[0] = "n/a"; + choices[1] = "Neutral"; + choices[2] = "Yellow"; + choices[3] = "Orange"; + choices[4] = "Red"; + choices[5] = "Green"; + } +}; +OLPictureModeBWFilterInterpreter olPictureModeBWFilterInterpreter; + +class OLPictureModeToneInterpreter : public ChoiceInterpreter { + public: + OLPictureModeToneInterpreter () { + choices[0] = "n/a"; + choices[1] = "Neutral"; + choices[2] = "Sepia"; + choices[3] = "Blue"; + choices[4] = "Purple"; + choices[5] = "Green"; + } +}; +OLPictureModeToneInterpreter olPictureModeToneInterpreter; + +class OLImageQuality2Interpreter : public ChoiceInterpreter { + public: + OLImageQuality2Interpreter () { + choices[1] = "SQ"; + choices[2] = "HQ"; + choices[3] = "SHQ"; + choices[4] = "RAW"; + } +}; +OLImageQuality2Interpreter olImageQuality2Interpreter; + +class OLDevEngineInterpreter : public ChoiceInterpreter { + public: + OLDevEngineInterpreter () { + choices[0] = "High Speed"; + choices[1] = "High Function"; + choices[2] = "Advanced High Speed"; + choices[3] = "Advanced High Function"; + } +}; +OLDevEngineInterpreter olDevEngineInterpreter; + +class OLPictureModeInterpreter : public ChoiceInterpreter { + public: + OLPictureModeInterpreter () { + choices[1] = "Vivid"; + choices[2] = "Natural"; + choices[3] = "Muted"; + choices[4] = "Portrait"; + choices[256] = "Monotone"; + choices[512] = "Sepia"; + } +}; +OLPictureModeInterpreter olPictureModeInterpreter; + +class OLColorSpaceInterpreter : public ChoiceInterpreter { + public: + OLColorSpaceInterpreter () { + choices[0] = "sRGB"; + choices[1] = "Adobe RGB"; + choices[2] = "Pro Photo RGB"; + } +}; +OLColorSpaceInterpreter olColorSpaceInterpreter; + +class OLNoiseFilterInterpreter : public Interpreter { + public: + OLNoiseFilterInterpreter () {} + virtual std::string toString (Tag* t) { + int a = t->toInt (0); + int b = t->toInt (2); + int c = t->toInt (4); + if (a==-1 && b==-2 && c==1) + return "Low"; + else if (a==-2 && b==-2 && c==1) + return "Off"; + else if (a==0 && b==-2 && c==1) + return "Standard"; + else if (a==1 && b==-2 && c==1) + return "High"; + else return "Unknown"; + } +}; +OLNoiseFilterInterpreter olNoiseFilterInterpreter; + +class OLFlashModeInterpreter : public Interpreter { + public: + OLFlashModeInterpreter () {} + virtual std::string toString (Tag* t) { + std::ostringstream str; + int a = t->toInt (); + str << "Flash Used = " << ((a&1) ? "Yes" : "No") << std::endl; + str << "Fill-in = " << ((a&2) ? "On" : "Off") << std::endl; + str << "Red-eye = " << ((a&4) ? "On" : "Off") << std::endl; + str << "Slow-sync = " << ((a&8) ? "On" : "Off") << std::endl; + str << "Forced On = " << ((a&16) ? "On" : "Off") << std::endl; + str << "2nd Curtain = " << ((a&32) ? "On" : "Off"); + return str.str(); + } +}; +OLFlashModeInterpreter olFlashModeInterpreter; + +class OLNoiseReductionInterpreter : public Interpreter { + public: + OLNoiseReductionInterpreter () {} + virtual std::string toString (Tag* t) { + std::ostringstream str; + int a = t->toInt (); + str << "Noise Reduction = " << ((a&1) ? "On" : "Off") << std::endl; + str << "Noise Filter = " << ((a&2) ? "On" : "Off") << std::endl; + str << "Noise Filter (ISO Boost) = " << ((a&4) ? "On" : "Off"); + return str.str(); + } +}; +OLNoiseReductionInterpreter olNoiseReductionInterpreter; + +class OLFlashModelInterpreter : public ChoiceInterpreter { + public: + OLFlashModelInterpreter () { + choices[0] = "None"; + choices[1] = "FL-20"; + choices[2] = "FL-50"; + choices[3] = "RF-11"; + choices[4] = "TF-22"; + choices[5] = "FL-36"; + choices[6] = "FL-50R"; + choices[7] = "FL-36R"; + } +}; +OLFlashModelInterpreter olFlashModelInterpreter; + +const TagAttrib olyFocusInfoAttribs[] = { + 0, 1, 0, 0, 0x0000, "FocusInfoVersion", &stdInterpreter, + 0, 1, 0, 0, 0x0209, "AutoFocus", &olOnOffInterpreter, + 0, 1, 0, 0, 0x0210, "SceneDetect", &stdInterpreter, + 0, 1, 0, 0, 0x0211, "SceneArea", &stdInterpreter, + 0, 1, 0, 0, 0x0212, "SceneDetectData", &stdInterpreter, + 0, 1, 0, 0, 0x0300, "ZoomStepCount", &stdInterpreter, + 0, 1, 0, 0, 0x0301, "FocusStepCount", &stdInterpreter, + 0, 1, 0, 0, 0x0303, "FocusStepInfinity", &stdInterpreter, + 0, 1, 0, 0, 0x0304, "FocusStepNear", &stdInterpreter, + 0, 1, 0, 0, 0x0305, "FocusDistance", &stdInterpreter, + 0, 1, 0, 0, 0x0308, "AFPoint", &stdInterpreter, + 0, 1, 0, 0, 0x1201, "ExternalFlash", &olOnOffInterpreter, + 0, 1, 0, 0, 0x1203, "ExternalFlashGuideNumber", &stdInterpreter, + 0, 1, 0, 0, 0x1204, "ExternalFlashBounce", &stdInterpreter, + 0, 1, 0, 0, 0x1205, "ExternalFlashZoom", &stdInterpreter, + 0, 1, 0, 0, 0x1208, "InternalFlash", &olOnOffInterpreter, + 0, 1, 0, 0, 0x1209, "ManualFlash", &olOnOffInterpreter, + 0, 1, 0, 0, 0x1500, "SensorTemperature", &stdInterpreter, + 0, 1, 0, 0, 0x1600, "ImageStabilization", &stdInterpreter, +-1, 0, 0, 0, 0, "", NULL}; + +const TagAttrib olyImageProcessingAttribs[] = { + 0, 1, 0, 0, 0x0000, "ImageProcessingVersion", &stdInterpreter, + 0, 1, 0, 0, 0x0100, "WB_RBLevels", &stdInterpreter, + 0, 1, 0, 0, 0x0102, "WB_RBLevels3000K", &stdInterpreter, + 0, 1, 0, 0, 0x0103, "WB_RBLevels3300K", &stdInterpreter, + 0, 1, 0, 0, 0x0104, "WB_RBLevels3600K", &stdInterpreter, + 0, 1, 0, 0, 0x0105, "WB_RBLevels3900K", &stdInterpreter, + 0, 1, 0, 0, 0x0106, "WB_RBLevels4000K", &stdInterpreter, + 0, 1, 0, 0, 0x0107, "WB_RBLevels4300K", &stdInterpreter, + 0, 1, 0, 0, 0x0108, "WB_RBLevels4500K", &stdInterpreter, + 0, 1, 0, 0, 0x0109, "WB_RBLevels4800K", &stdInterpreter, + 0, 1, 0, 0, 0x010a, "WB_RBLevels5300K", &stdInterpreter, + 0, 1, 0, 0, 0x010b, "WB_RBLevels6000K", &stdInterpreter, + 0, 1, 0, 0, 0x010c, "WB_RBLevels6600K", &stdInterpreter, + 0, 1, 0, 0, 0x010d, "WB_RBLevels7500K", &stdInterpreter, + 0, 1, 0, 0, 0x010e, "WB_RBLevelsCWB1", &stdInterpreter, + 0, 1, 0, 0, 0x010f, "WB_RBLevelsCWB2", &stdInterpreter, + 0, 1, 0, 0, 0x0110, "WB_RBLevelsCWB3", &stdInterpreter, + 0, 1, 0, 0, 0x0111, "WB_RBLevelsCWB4", &stdInterpreter, + 0, 1, 0, 0, 0x0113, "WB_GLevel3000K", &stdInterpreter, + 0, 1, 0, 0, 0x0114, "WB_GLevel3300K", &stdInterpreter, + 0, 1, 0, 0, 0x0115, "WB_GLevel3600K", &stdInterpreter, + 0, 1, 0, 0, 0x0116, "WB_GLevel3900K", &stdInterpreter, + 0, 1, 0, 0, 0x0117, "WB_GLevel4000K", &stdInterpreter, + 0, 1, 0, 0, 0x0118, "WB_GLevel4300K", &stdInterpreter, + 0, 1, 0, 0, 0x0119, "WB_GLevel4500K", &stdInterpreter, + 0, 1, 0, 0, 0x011a, "WB_GLevel4800K", &stdInterpreter, + 0, 1, 0, 0, 0x011b, "WB_GLevel5300K", &stdInterpreter, + 0, 1, 0, 0, 0x011c, "WB_GLevel6000K", &stdInterpreter, + 0, 1, 0, 0, 0x011d, "WB_GLevel6600K", &stdInterpreter, + 0, 1, 0, 0, 0x011e, "WB_GLevel7500K", &stdInterpreter, + 0, 1, 0, 0, 0x011f, "WB_GLevel", &stdInterpreter, + 0, 1, 0, 0, 0x0200, "ColorMatrix", &stdInterpreter, + 0, 1, 0, 0, 0x0300, "Enhancer", &stdInterpreter, + 0, 1, 0, 0, 0x0301, "EnhancerValues", &stdInterpreter, + 0, 1, 0, 0, 0x0310, "CoringFilter", &stdInterpreter, + 0, 1, 0, 0, 0x0311, "CoringValues", &stdInterpreter, + 0, 1, 0, 0, 0x0600, "BlackLevel2", &stdInterpreter, + 0, 1, 0, 0, 0x0610, "GainBase", &stdInterpreter, + 0, 1, 0, 0, 0x0611, "ValidBits", &stdInterpreter, + 0, 1, 0, 0, 0x0612, "CropLeft", &stdInterpreter, + 0, 1, 0, 0, 0x0613, "CropTop", &stdInterpreter, + 0, 1, 0, 0, 0x0614, "CropWidth", &stdInterpreter, + 0, 1, 0, 0, 0x0615, "CropHeight", &stdInterpreter, + 0, 1, 0, 0, 0x1010, "NoiseReduction2", &stdInterpreter, + 0, 1, 0, 0, 0x1011, "DistortionCorrection2", &olOnOffInterpreter, + 0, 1, 0, 0, 0x1012, "ShadingCompensation2", &olOnOffInterpreter, + 1, 1, 0, 0, 0x1103, "UnknownBlock", &stdInterpreter, + 0, 1, 0, 0, 0x1200, "FaceDetect", &olOnOffInterpreter, + 0, 1, 0, 0, 0x1201, "FaceDetectArea", &stdInterpreter, +-1, 0, 0, 0, 0, "", NULL}; + +const TagAttrib olyRawDevelopmentAttribs[] = { + 0, 1, 0, 0, 0x0000, "RawDevVersion", &stdInterpreter, + 0, 1, 0, 0, 0x0100, "RawDevExposureBiasValue", &stdInterpreter, + 0, 1, 0, 0, 0x0101, "RawDevWhiteBalanceValue", &stdInterpreter, + 0, 1, 0, 0, 0x0102, "RawDevWBFineAdjustment", &stdInterpreter, + 0, 1, 0, 0, 0x0103, "RawDevGrayPoint", &stdInterpreter, + 0, 1, 0, 0, 0x0104, "RawDevSaturationEmphasis", &stdInterpreter, + 0, 1, 0, 0, 0x0105, "RawDevMemoryColorEmphasis", &stdInterpreter, + 0, 1, 0, 0, 0x0106, "RawDevContrastValue", &stdInterpreter, + 0, 1, 0, 0, 0x0107, "RawDevSharpnessValue", &stdInterpreter, + 0, 1, 0, 0, 0x0108, "RawDevColorSpace", &olColorSpaceInterpreter, + 0, 1, 0, 0, 0x0109, "RawDevEngine", &olDevEngineInterpreter, + 0, 1, 0, 0, 0x010a, "RawDevNoiseReduction", &olNoiseReductionInterpreter, + 0, 1, 0, 0, 0x010b, "RawDevEditStatus", &stdInterpreter, + 0, 1, 0, 0, 0x010c, "RawDevSettings", &stdInterpreter, +-1, 0, 0, 0, 0, "", NULL}; + +const TagAttrib olyRawDevelopment2Attribs[] = { + 0, 1, 0, 0, 0x0000, "RawDevVersion", &stdInterpreter, + 0, 1, 0, 0, 0x0100, "RawDevExposureBiasValue", &stdInterpreter, + 0, 1, 0, 0, 0x0101, "RawDevWhiteBalance", &stdInterpreter, + 0, 1, 0, 0, 0x0102, "RawDevWhiteBalanceValue", &stdInterpreter, + 0, 1, 0, 0, 0x0103, "RawDevWBFineAdjustment", &stdInterpreter, + 0, 1, 0, 0, 0x0104, "RawDevGrayPoint", &stdInterpreter, + 0, 1, 0, 0, 0x0105, "RawDevContrastValue", &stdInterpreter, + 0, 1, 0, 0, 0x0106, "RawDevSharpnessValue", &stdInterpreter, + 0, 1, 0, 0, 0x0107, "RawDevSaturationEmphasis", &stdInterpreter, + 0, 1, 0, 0, 0x0108, "RawDevMemoryColorEmphasis", &stdInterpreter, + 0, 1, 0, 0, 0x0109, "RawDevColorSpace", &olColorSpaceInterpreter, + 0, 1, 0, 0, 0x010a, "RawDevNoiseReduction", &olNoiseReductionInterpreter, + 0, 1, 0, 0, 0x010b, "RawDevEngine", &olDevEngineInterpreter, + 0, 1, 0, 0, 0x010c, "RawDevPictureMode", &olPictureModeInterpreter, + 0, 1, 0, 0, 0x010d, "RawDevPMSaturation", &stdInterpreter, + 0, 1, 0, 0, 0x010e, "RawDevPMContrast", &stdInterpreter, + 0, 1, 0, 0, 0x010f, "RawDevPMSharpness", &stdInterpreter, + 0, 1, 0, 0, 0x0110, "RawDevPM_BWFilter", &olPictureModeBWFilterInterpreter, + 0, 1, 0, 0, 0x0111, "RawDevPMPictureTone", &olPictureModeToneInterpreter, + 0, 1, 0, 0, 0x0112, "RawDevGradation", &stdInterpreter, + 0, 1, 0, 0, 0x0113, "RawDevSaturation3", &stdInterpreter, + 0, 1, 0, 0, 0x0119, "RawDevAutoGradation", &olOnOffInterpreter, + 0, 1, 0, 0, 0x0120, "RawDevPMNoiseFilter", &stdInterpreter, +-1, 0, 0, 0, 0, "", NULL}; + +const TagAttrib olyCameraSettingsAttribs[] = { + 0, 1, 0, 0, 0x0000, "CameraSettingsVersion", &stdInterpreter, + 1, 1, 0, 0, 0x0100, "PreviewImageValid", &olYesNoInterpreter, + 1, 1, 0, 0, 0x0101, "PreviewImageStart", &stdInterpreter, + 1, 1, 0, 0, 0x0102, "PreviewImageLength", &stdInterpreter, + 0, 1, 0, 0, 0x0200, "ExposureMode", &olExposureModeInterpreter, + 0, 1, 0, 0, 0x0201, "AELock", &olOnOffInterpreter, + 0, 1, 0, 0, 0x0202, "MeteringMode", &olMeteringModeInterpreter, + 0, 1, 0, 0, 0x0300, "MacroMode", &olOnOffInterpreter, + 0, 1, 0, 0, 0x0301, "FocusMode", &olFocusModeInterpreter, + 0, 1, 0, 0, 0x0302, "FocusProcess", &stdInterpreter, + 0, 1, 0, 0, 0x0303, "AFSearch", &stdInterpreter, + 0, 1, 0, 0, 0x0304, "AFAreas", &stdInterpreter, + 0, 1, 0, 0, 0x0400, "FlashMode", &stdInterpreter, + 0, 1, 0, 0, 0x0401, "FlashExposureComp", &stdInterpreter, + 0, 1, 0, 0, 0x0500, "WhiteBalance2", &olWhitebalance2Interpreter, + 0, 1, 0, 0, 0x0501, "WhiteBalanceTemperature", &stdInterpreter, + 0, 1, 0, 0, 0x0502, "WhiteBalanceBracket", &stdInterpreter, + 0, 1, 0, 0, 0x0503, "CustomSaturation", &stdInterpreter, + 0, 1, 0, 0, 0x0504, "ModifiedSaturation", &stdInterpreter, + 0, 1, 0, 0, 0x0505, "ContrastSetting", &stdInterpreter, + 0, 1, 0, 0, 0x0506, "SharpnessSetting", &stdInterpreter, + 0, 1, 0, 0, 0x0507, "ColorSpace", &olColorSpaceInterpreter, + 0, 1, 0, 0, 0x0509, "SceneMode", &olSceneModeInterpreter, + 0, 1, 0, 0, 0x050a, "NoiseReduction", &olNoiseReductionInterpreter, + 0, 1, 0, 0, 0x050b, "DistortionCorrection", &olOnOffInterpreter, + 0, 1, 0, 0, 0x050c, "ShadingCompensation", &olOnOffInterpreter, + 0, 1, 0, 0, 0x050d, "CompressionFactor", &stdInterpreter, + 0, 1, 0, 0, 0x050f, "Gradation", &stdInterpreter, + 0, 1, 0, 0, 0x0520, "PictureMode", &olPictureModeInterpreter, + 0, 1, 0, 0, 0x0521, "PictureModeSaturation", &stdInterpreter, + 0, 1, 0, 0, 0x0522, "PictureModeHue", &stdInterpreter, + 0, 1, 0, 0, 0x0523, "PictureModeContrast", &stdInterpreter, + 0, 1, 0, 0, 0x0524, "PictureModeSharpness", &stdInterpreter, + 0, 1, 0, 0, 0x0525, "PictureModeBWFilter", &olPictureModeBWFilterInterpreter, + 0, 1, 0, 0, 0x0526, "PictureModeTone", &olPictureModeToneInterpreter, + 0, 1, 0, 0, 0x0527, "NoiseFilter", &olNoiseFilterInterpreter, + 0, 1, 0, 0, 0x0600, "DriveMode", &stdInterpreter, + 0, 1, 0, 0, 0x0601, "PanoramaMode", &stdInterpreter, + 0, 1, 0, 0, 0x0603, "ImageQuality2", &olImageQuality2Interpreter, + 0, 1, 0, 0, 0x0900, "ManometerPressure", &stdInterpreter, + 0, 1, 0, 0, 0x0901, "ManometerReading", &stdInterpreter, + 0, 1, 0, 0, 0x0902, "ExtendedWBDetect", &olOnOffInterpreter, + -1, 0, 0, 0, 0, "", NULL}; + +const TagAttrib olyEquipmentAttribs[] = { + 0, 1, 0, 0, 0x0000, "EquipmentVersion", &stdInterpreter, + 0, 1, 0, 0, 0x0100, "CameraType2", &stdInterpreter, + 0, 1, 0, 0, 0x0101, "SerialNumber", &stdInterpreter, + 0, 1, 0, 0, 0x0102, "InternalSerialNumber", &stdInterpreter, + 0, 1, 0, 0, 0x0103, "FocalPlaneDiagonal", &stdInterpreter, + 0, 1, 0, 0, 0x0104, "BodyFirmwareVersion", &stdInterpreter, + 0, 1, 0, 0, 0x0201, "LensType", &olLensTypeInterpreter, + 0, 1, 0, 0, 0x0202, "LensSerialNumber", &stdInterpreter, + 0, 1, 0, 0, 0x0204, "LensFirmwareVersion", &stdInterpreter, + 0, 1, 0, 0, 0x0205, "MaxApertureAtMinFocal", &olApertureInterpreter, + 0, 1, 0, 0, 0x0206, "MaxApertureAtMaxFocal", &olApertureInterpreter, + 0, 1, 0, 0, 0x0207, "MinFocalLength", &stdInterpreter, + 0, 1, 0, 0, 0x0208, "MaxFocalLength", &stdInterpreter, + 0, 1, 0, 0, 0x020a, "MaxApertureAtCurrentFocal", &olApertureInterpreter, + 0, 1, 0, 0, 0x020b, "LensProperties", &stdInterpreter, + 0, 1, 0, 0, 0x0301, "Extender", &stdInterpreter, + 0, 1, 0, 0, 0x0302, "ExtenderSerialNumber", &stdInterpreter, + 0, 1, 0, 0, 0x0303, "ExtenderModel", &stdInterpreter, + 0, 1, 0, 0, 0x0304, "ExtenderFirmwareVersion", &stdInterpreter, + 0, 1, 0, 0, 0x1000, "FlashType", &olFlashTypeInterpreter, + 0, 1, 0, 0, 0x1001, "FlashModel", &olFlashModelInterpreter, + 0, 1, 0, 0, 0x1002, "FlashFirmwareVersion", &stdInterpreter, + 0, 1, 0, 0, 0x1003, "FlashSerialNumber", &stdInterpreter, + -1, 0, 0, 0, 0, "", NULL}; + +const TagAttrib olympusAttribs[] = { + 0, 1, 0, 0, 0x0104, "BodyFirmwareVersion", &stdInterpreter, + 0, 1, 0, 0, 0x0200, "SpecialMode", &stdInterpreter, + 0, 1, 0, 0, 0x0201, "Quality", &stdInterpreter, + 0, 1, 0, 0, 0x0202, "Macro", &olOnOffInterpreter, + 0, 1, 0, 0, 0x0203, "BWMode", &olOnOffInterpreter, + 0, 1, 0, 0, 0x0204, "DigitalZoom", &stdInterpreter, + 0, 1, 0, 0, 0x0205, "FocalPlaneDiagonal", &stdInterpreter, + 0, 1, 0, 0, 0x0206, "LensDistortionParams", &stdInterpreter, + 0, 1, 0, 0, 0x0207, "CameraType", &stdInterpreter, + 1, 1, 0, 0, 0x0208, "TextInfo", &stdInterpreter, + 0, 1, 0, 0, 0x0209, "CameraID", &stdInterpreter, + 0, 1, 0, 0, 0x020b, "EpsonImageWidth", &stdInterpreter, + 0, 1, 0, 0, 0x020c, "EpsonImageHeight", &stdInterpreter, + 0, 1, 0, 0, 0x020d, "EpsonSoftware", &stdInterpreter, + 0, 2, 0, 0, 0x0280, "PreviewImage", &stdInterpreter, + 0, 1, 0, 0, 0x0300, "PreCaptureFrames", &stdInterpreter, + 0, 1, 0, 0, 0x0301, "WhiteBoard", &stdInterpreter, + 0, 1, 0, 0, 0x0302, "OneTouchWB", &olOnOffInterpreter, + 0, 1, 0, 0, 0x0303, "WhiteBalanceBracket", &stdInterpreter, + 0, 1, 0, 0, 0x0304, "WhiteBalanceBias", &stdInterpreter, + 0, 1, 0, 0, 0x0403, "SceneMode", &stdInterpreter, + 0, 1, 0, 0, 0x0404, "SerialNumber", &stdInterpreter, + 0, 1, 0, 0, 0x0405, "Firmware", &stdInterpreter, + 1, 1, 0, 0, 0x0e00, "PrintIM", &stdInterpreter, + 0, 1, 0, 0, 0x0f00, "DataDump", &stdInterpreter, + 0, 1, 0, 0, 0x0f01, "DataDump2", &stdInterpreter, + 0, 1, 0, 0, 0x1000, "ShutterSpeedValue", &stdInterpreter, + 0, 1, 0, 0, 0x1001, "ISOValue", &stdInterpreter, + 0, 1, 0, 0, 0x1002, "ApertureValue", &stdInterpreter, + 0, 1, 0, 0, 0x1003, "BrightnessValue", &stdInterpreter, + 0, 1, 0, 0, 0x1004, "FlashMode", &stdInterpreter, + 0, 1, 0, 0, 0x1005, "FlashDevice", &stdInterpreter, + 0, 1, 0, 0, 0x1006, "ExposureCompensation", &stdInterpreter, + 0, 1, 0, 0, 0x1007, "SensorTemperature", &stdInterpreter, + 0, 1, 0, 0, 0x1008, "LensTemperature", &stdInterpreter, + 0, 1, 0, 0, 0x1009, "LightCondition", &stdInterpreter, + 0, 1, 0, 0, 0x100a, "FocusRange", &stdInterpreter, + 0, 1, 0, 0, 0x100b, "FocusMode", &stdInterpreter, + 0, 1, 0, 0, 0x100c, "ManualFocusDistance", &stdInterpreter, + 0, 1, 0, 0, 0x100d, "ZoomStepCount", &stdInterpreter, + 0, 1, 0, 0, 0x100e, "FocusStepCount", &stdInterpreter, + 0, 1, 0, 0, 0x100f, "Sharpness", &stdInterpreter, + 0, 1, 0, 0, 0x1010, "FlashChargeLevel", &stdInterpreter, + 0, 1, 0, 0, 0x1011, "ColorMatrix", &stdInterpreter, + 0, 1, 0, 0, 0x1012, "BlackLevel", &stdInterpreter, + 0, 1, 0, 0, 0x1013, "ColorTemperatureBG", &stdInterpreter, + 0, 1, 0, 0, 0x1014, "ColorTemperatureRG", &stdInterpreter, + 0, 1, 0, 0, 0x1015, "WBMode", &stdInterpreter, + 0, 1, 0, 0, 0x1017, "RedBalance", &stdInterpreter, + 0, 1, 0, 0, 0x1018, "BlueBalance", &stdInterpreter, + 0, 1, 0, 0, 0x1019, "ColorMatrixNumber", &stdInterpreter, + 0, 1, 0, 0, 0x101a, "SerialNumber", &stdInterpreter, + 0, 1, 0, 0, 0x101b, "ExternalFlashAE1_0", &stdInterpreter, + 0, 1, 0, 0, 0x101c, "ExternalFlashAE2_0", &stdInterpreter, + 0, 1, 0, 0, 0x101d, "InternalFlashAE1_0", &stdInterpreter, + 0, 1, 0, 0, 0x101e, "InternalFlashAE2_0", &stdInterpreter, + 0, 1, 0, 0, 0x101f, "ExternalFlashAE1", &stdInterpreter, + 0, 1, 0, 0, 0x1020, "ExternalFlashAE2", &stdInterpreter, + 0, 1, 0, 0, 0x1021, "InternalFlashAE1", &stdInterpreter, + 0, 1, 0, 0, 0x1022, "InternalFlashAE2", &stdInterpreter, + 0, 1, 0, 0, 0x1023, "FlashExposureComp", &stdInterpreter, + 0, 1, 0, 0, 0x1024, "InternalFlashTable", &stdInterpreter, + 0, 1, 0, 0, 0x1025, "ExternalFlashGValue", &stdInterpreter, + 0, 1, 0, 0, 0x1026, "ExternalFlashBounce", &olYesNoInterpreter, + 0, 1, 0, 0, 0x1027, "ExternalFlashZoom", &stdInterpreter, + 0, 1, 0, 0, 0x1028, "ExternalFlashMode", &stdInterpreter, + 0, 1, 0, 0, 0x1029, "Contrast", &stdInterpreter, + 0, 1, 0, 0, 0x102a, "SharpnessFactor", &stdInterpreter, + 0, 1, 0, 0, 0x102b, "ColorControl", &stdInterpreter, + 0, 1, 0, 0, 0x102c, "ValidBits", &stdInterpreter, + 0, 1, 0, 0, 0x102d, "CoringFilter", &stdInterpreter, + 0, 1, 0, 0, 0x102e, "OlympusImageWidth", &stdInterpreter, + 0, 1, 0, 0, 0x102f, "OlympusImageHeight", &stdInterpreter, + 0, 1, 0, 0, 0x1030, "SceneDetect", &stdInterpreter, + 0, 1, 0, 0, 0x1031, "SceneArea", &stdInterpreter, + 0, 1, 0, 0, 0x1033, "SceneDetectData", &stdInterpreter, + 0, 1, 0, 0, 0x1034, "CompressionRatio", &stdInterpreter, + 1, 1, 0, 0, 0x1035, "PreviewImageValid", &olYesNoInterpreter, + 1, 1, 0, 0, 0x1036, "PreviewImageStart", &stdInterpreter, + 1, 1, 0, 0, 0x1037, "PreviewImageLength", &stdInterpreter, + 0, 1, 0, 0, 0x1038, "AFResult", &stdInterpreter, + 0, 1, 0, 0, 0x1039, "CCDScanMode", &stdInterpreter, + 0, 1, 0, 0, 0x103a, "NoiseReduction", &olOnOffInterpreter, + 0, 1, 0, 0, 0x103b, "InfinityLensStep", &stdInterpreter, + 0, 1, 0, 0, 0x103c, "NearLensStep", &stdInterpreter, + 0, 1, 0, 0, 0x103d, "LightValueCenter", &stdInterpreter, + 0, 1, 0, 0, 0x103e, "LightValuePeriphery", &stdInterpreter, + 0, 1, 0, 0, 0x103f, "FieldCount", &stdInterpreter, + 0, 1, 0, olyEquipmentAttribs, 0x2010, "Equipment", &stdInterpreter, + 0, 1, 0, olyCameraSettingsAttribs, 0x2020, "CameraSettings", &stdInterpreter, + 0, 1, 0, olyRawDevelopmentAttribs, 0x2030, "RawDevelopment", &stdInterpreter, + 0, 1, 0, olyRawDevelopment2Attribs, 0x2031, "RawDev2", &stdInterpreter, + 0, 1, 0, olyImageProcessingAttribs, 0x2040, "ImageProcessing", &stdInterpreter, + 0, 1, 0, olyFocusInfoAttribs, 0x2050, "FocusInfo", &stdInterpreter, + 1, 1, 0, 0, 0x2100, "Olympus2100", &stdInterpreter, + 1, 1, 0, 0, 0x2300, "Olympus2300", &stdInterpreter, + 1, 1, 0, 0, 0x2400, "Olympus2400", &stdInterpreter, + 1, 1, 0, 0, 0x2500, "Olympus2500", &stdInterpreter, + 1, 1, 0, 0, 0x2600, "Olympus2600", &stdInterpreter, + 1, 1, 0, 0, 0x2700, "Olympus2700", &stdInterpreter, + 1, 1, 0, 0, 0x2800, "Olympus2800", &stdInterpreter, + 1, 1, 0, 0, 0x2900, "Olympus2900", &stdInterpreter, + 0, 1, 0, 0, 0x3000, "RawInfo", &stdInterpreter, + -1, 0, 0, 0, 0, "", NULL}; +}; + #endif + diff --git a/rtexif/pentaxattribs.cc b/rtexif/pentaxattribs.cc new file mode 100755 index 000000000..fbc4364e8 --- /dev/null +++ b/rtexif/pentaxattribs.cc @@ -0,0 +1,556 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _PENTAXATTRIBS_ +#define _PENTAXATTRIBS_ + +#include +#include +#include +#include +#include +#include + +namespace rtexif { + + +class PAQualityInterpreter : public ChoiceInterpreter { + public: + PAQualityInterpreter () { + choices[0] = "Good"; + choices[1] = "Better"; + choices[2] = "Best"; + choices[3] = "TIFF"; + choices[4] = "RAW"; + } +}; +PAQualityInterpreter paQualityInterpreter; + +class PAOnOffInterpreter : public ChoiceInterpreter { + public: + PAOnOffInterpreter () { + choices[0] = "Off"; + choices[1] = "On"; + } +}; +PAOnOffInterpreter paOnOffInterpreter; + +class PAPictureModeInterpreter : public ChoiceInterpreter { + public: + PAPictureModeInterpreter () { + choices[0] = "Program"; + choices[2] = "Program AE"; + choices[3] = "Manual"; + choices[5] = "Portrait"; + choices[6] = "Landscape"; + choices[8] = "Sport"; + choices[9] = "Night Scene"; + choices[11] = "Soft"; + choices[12] = "Surf & Snow"; + choices[13] = "Candlelight"; + choices[14] = "Autumn"; + choices[15] = "Macro"; + choices[17] = "Fireworks"; + choices[18] = "Text"; + choices[19] = "Panorama"; + choices[30] = "Self Portrait"; + choices[31] = "Illustrations"; + choices[33] = "Digital Filter"; + choices[37] = "Museum"; + choices[38] = "Food"; + choices[40] = "Green Mode"; + choices[49] = "Light Pet"; + choices[50] = "Dark Pet"; + choices[51] = "Medium Pet"; + choices[53] = "Underwater"; + choices[54] = "Candlelight"; + choices[55] = "Natural Skin Tone"; + choices[56] = "Synchro Sound Record"; + choices[58] = "Frame Composite"; + choices[60] = "Kids"; + choices[61] = "Blur Reduction"; + } +}; +PAPictureModeInterpreter paPictureModeInterpreter; + +class PAFlashModeInterpreter : public ChoiceInterpreter { + public: + PAFlashModeInterpreter () { + choices[0x0] = "Auto, Did not fire"; + choices[0x1] = "Off"; + choices[0x2] = "On, Did not fire"; + choices[0x3] = "Auto, Did not fire, Red-eye reduction"; + choices[0x100] = "Auto, Fired"; + choices[0x102] = "On"; + choices[0x103] = "Auto, Fired, Red-eye reduction"; + choices[0x104] = "On, Red-eye reduction"; + choices[0x105] = "On, Wireless (Master)"; + choices[0x106] = "On, Wireless (Control)"; + choices[0x108] = "On, Soft"; + choices[0x109] = "On, Slow-sync"; + choices[0x10a] = "On, Slow-sync, Red-eye reduction"; + choices[0x10b] = "On, Trailing-curtain Sync"; + } +}; +PAFlashModeInterpreter paFlashModeInterpreter; + +class PAFocusModeInterpreter : public ChoiceInterpreter { + public: + PAFocusModeInterpreter () { + choices[0] = "Normal"; + choices[1] = "Macro"; + choices[2] = "Infinity"; + choices[3] = "Manual"; + choices[5] = "Pan Focus"; + choices[16] = "AF-S"; + choices[17] = "AF-C"; + } +}; +PAFocusModeInterpreter paFocusModeInterpreter; + +class PAAFPointInterpreter : public ChoiceInterpreter { + public: + PAAFPointInterpreter () { + choices[1] = "Upper-left"; + choices[2] = "Top"; + choices[3] = "Upper-right"; + choices[4] = "Left"; + choices[5] = "Mid-left"; + choices[6] = "Center"; + choices[7] = "Mid-right"; + choices[8] = "Right"; + choices[9] = "Lower-left"; + choices[10] = "Bottom"; + choices[11] = "Lower-right"; + choices[65534] = "Fixed Center"; + choices[65535] = "Auto"; + } +}; +PAAFPointInterpreter paAFPointInterpreter; + +class PAAFFocusInterpreter : public ChoiceInterpreter { + public: + PAAFFocusInterpreter () { + choices[0x0] = "Fixed Center or Multiple"; + choices[0x1] = "Top-left"; + choices[0x2] = "Top-center"; + choices[0x3] = "Top-right"; + choices[0x4] = "Left"; + choices[0x5] = "Center"; + choices[0x6] = "Right"; + choices[0x7] = "Bottom-left"; + choices[0x8] = "Bottom-center"; + choices[0x9] = "Bottom-right"; + choices[0xffff] = "None"; + } +}; +PAAFFocusInterpreter paAFFocusInterpreter; + +class PAISOInterpreter : public ChoiceInterpreter { + public: + PAISOInterpreter () { + choices[3] = "50"; + choices[4] = "64"; + choices[5] = "80"; + choices[6] = "100"; + choices[7] = "125"; + choices[8] = "160"; + choices[9] = "200"; + choices[10] = "250"; + choices[11] = "320"; + choices[12] = "400"; + choices[13] = "500"; + choices[14] = "640"; + choices[15] = "800"; + choices[16] = "1000"; + choices[17] = "1250"; + choices[18] = "1600"; + choices[19] = "2000"; + choices[20] = "2500"; + choices[21] = "3200"; + choices[50] = "50"; + choices[100] = "100"; + choices[200] = "200"; + choices[258] = "50"; + choices[259] = "70"; + choices[260] = "100"; + choices[261] = "140"; + choices[262] = "200"; + choices[263] = "280"; + choices[264] = "400"; + choices[265] = "560"; + choices[266] = "800"; + choices[267] = "1100"; + choices[268] = "1600"; + choices[269] = "2200"; + choices[270] = "3200"; + choices[400] = "400"; + choices[800] = "800"; + choices[1600] = "1600"; + choices[3200] = "320"; + } +}; +PAISOInterpreter paISOInterpreter; + +class PAMeteringModeInterpreter : public ChoiceInterpreter { + public: + PAMeteringModeInterpreter () { + choices[0] = "Multi-segment"; + choices[1] = "Center-weighted average"; + choices[2] = "Spot"; + } +}; +PAMeteringModeInterpreter paMeteringModeInterpreter; + +class PAWhiteBalanceInterpreter : public ChoiceInterpreter { + public: + PAWhiteBalanceInterpreter () { + choices[0] = "Auto"; + choices[1] = "Daylight"; + choices[2] = "Shade"; + choices[3] = "Fluorescent"; + choices[4] = "Tungsten"; + choices[5] = "Manual"; + choices[6] = "DaylightFluorescent"; + choices[7] = "DaywhiteFluorescent"; + choices[8] = "WhiteFluorescent"; + choices[9] = "Flash"; + choices[10] = "Cloudy"; + choices[17] = "Kelvin"; + choices[65534] = "Unknown"; + choices[65535] = "User Selected"; + } +}; +PAWhiteBalanceInterpreter paWhiteBalanceInterpreter; + +class PAWhiteBalanceModeInterpreter : public ChoiceInterpreter { + public: + PAWhiteBalanceModeInterpreter () { + choices[1] = "Auto (Daylight)"; + choices[2] = "Auto (Shade)"; + choices[3] = "Auto (Flash)"; + choices[4] = "Auto (Tungsten)"; + choices[6] = "Auto (DaylightFluorescent)"; + choices[7] = "Auto (DaywhiteFluorescent)"; + choices[8] = "Auto (WhiteFluorescent)"; + choices[10] = "Auto (Cloudy)"; + choices[65534] = "Preset (Fireworks?)"; + choices[65535] = "User-Selected"; + } +}; +PAWhiteBalanceModeInterpreter paWhiteBalanceModeInterpreter; + +class PASaturationInterpreter : public ChoiceInterpreter { + public: + PASaturationInterpreter () { + choices[0] = "Low"; + choices[1] = "Normal"; + choices[2] = "High"; + choices[3] = "Med Low"; + choices[4] = "Med High"; + choices[5] = "Very Low"; + choices[6] = "Very High"; + } +}; +PASaturationInterpreter paSaturationInterpreter; + +class PAContrastInterpreter : public ChoiceInterpreter { + public: + PAContrastInterpreter () { + choices[0] = "Low"; + choices[1] = "Normal"; + choices[2] = "High"; + choices[3] = "Med Low"; + choices[4] = "Med High"; + choices[5] = "Very Low"; + choices[6] = "Very High"; + } +}; +PAContrastInterpreter paContrastInterpreter; + +class PASharpnessInterpreter : public ChoiceInterpreter { + public: + PASharpnessInterpreter () { + choices[0] = "Soft"; + choices[1] = "Normal"; + choices[2] = "Hard"; + choices[3] = "Med Soft"; + choices[4] = "Med Hard"; + choices[5] = "Very Soft"; + choices[6] = "Very Hard"; + } +}; +PASharpnessInterpreter paSharpnessInterpreter; + +class PALensTypeInterpreter : public ChoiceInterpreter { + public: + PALensTypeInterpreter () { + choices[256*0+ 0] = "M-42 or No Lens"; + choices[256*1+ 0] = "K,M Lens"; + choices[256*2+ 0] = "A Series Lens"; + choices[256*3+ 0] = "SIGMA"; + choices[256*3+ 17] = "smc PENTAX-FA SOFT 85mm F2.8"; + choices[256*3+ 18] = "smc PENTAX-F 1.7X AF ADAPTER"; + choices[256*3+ 19] = "smc PENTAX-F 24-50mm F4"; + choices[256*3+ 20] = "smc PENTAX-F 35-80mm F4-5.6"; + choices[256*3+ 21] = "smc PENTAX-F 80-200mm F4.7-5.6"; + choices[256*3+ 22] = "smc PENTAX-F FISH-EYE 17-28mm F3.5-4.5"; + choices[256*3+ 23] = "smc PENTAX-F 100-300mm F4.5-5.6"; + choices[256*3+ 24] = "smc PENTAX-F 35-135mm F3.5-4.5"; + choices[256*3+ 25] = "smc PENTAX-F 35-105mm F4-5.6 or SIGMA or Tokina"; + choices[256*3+ 26] = "smc PENTAX-F* 250-600mm F5.6 ED[IF]"; + choices[256*3+ 27] = "smc PENTAX-F 28-80mm F3.5-4.5"; + choices[256*3+ 28] = "smc PENTAX-F 35-70mm F3.5-4.5"; + choices[256*3+ 29] = "PENTAX-F 28-80mm F3.5-4.5 or SIGMA AF 18-125mm F3.5-5.6 DC"; + choices[256*3+ 30] = "PENTAX-F 70-200mm F4-5.6"; + choices[256*3+ 31] = "smc PENTAX-F 70-210mm F4-5.6"; + choices[256*3+ 32] = "smc PENTAX-F 50mm F1.4"; + choices[256*3+ 33] = "smc PENTAX-F 50mm F1.7"; + choices[256*3+ 34] = "smc PENTAX-F 135mm F2.8 [IF]"; + choices[256*3+ 35] = "smc PENTAX-F 28mm F2.8"; + choices[256*3+ 36] = "SIGMA 20mm F1.8 EX DG ASPHERICAL RF"; + choices[256*3+ 38] = "smc PENTAX-F* 300mm F4.5 ED[IF]"; + choices[256*3+ 39] = "smc PENTAX-F* 600mm F4 ED[IF]"; + choices[256*3+ 40] = "smc PENTAX-F MACRO 100mm F2.8"; + choices[256*3+ 41] = "smc PENTAX-F MACRO 50mm F2.8 or Sigma 50mm F2,8 MACRO"; + choices[256*3+ 44] = "Tamron 35-90mm F4 AF or various SIGMA models"; + choices[256*3+ 46] = "SIGMA APO 70-200mm F2.8 EX"; + choices[256*3+ 51] = "SIGMA 28mm F1.8 EX DG ASPHERICAL MACRO"; + choices[256*3+ 52] = "smc PENTAX-FA 28-200mm F3.8-5.6 AL[IF]"; + choices[256*3+ 53] = "smc PENTAX-FA 28-80mm F3.5-5.6 AL"; + choices[256*3+ 247] = "smc PENTAX-DA FISH-EYE 10-17mm F3.5-4.5 ED[IF]"; + choices[256*3+ 248] = "smc PENTAX-DA 12-24mm F4 ED AL[IF]"; + choices[256*3+ 250] = "smc PENTAX-DA 50-200mm F4-5.6 ED"; + choices[256*3+ 251] = "smc PENTAX-DA 40mm F2.8 Limited"; + choices[256*3+ 252] = "smc PENTAX-DA 18-55mm F3.5-5.6 AL"; + choices[256*3+ 253] = "smc PENTAX-DA 14mm F2.8 ED[IF]"; + choices[256*3+ 254] = "smc PENTAX-DA 16-45mm F4 ED AL"; + choices[256*3+ 255] = "SIGMA"; + choices[256*4+ 1] = "smc PENTAX-FA SOFT 28mm F2.8"; + choices[256*4+ 2] = "smc PENTAX-FA 80-320mm F4.5-5.6"; + choices[256*4+ 3] = "smc PENTAX-FA 43mm F1.9 Limited"; + choices[256*4+ 6] = "smc PENTAX-FA 35-80mm F4-5.6"; + choices[256*4+ 12] = "smc PENTAX-FA 50mm F1.4"; + choices[256*4+ 15] = "smc PENTAX-FA 28-105mm F4-5.6 [IF]"; + choices[256*4+ 16] = "TAMRON AF 80-210mm F4-5.6 (178D)"; + choices[256*4+ 19] = "TAMRON SP AF 90mm F2.8 (172E)"; + choices[256*4+ 20] = "smc PENTAX-FA 28-80mm F3.5-5.6"; + choices[256*4+ 22] = "TOKINA 28-80mm F3.5-5.6"; + choices[256*4+ 23] = "smc PENTAX-FA 20-35mm F4 AL"; + choices[256*4+ 24] = "smc PENTAX-FA 77mm F1.8 Limited"; + choices[256*4+ 25] = "TAMRON SP AF 14mm F2.8"; + choices[256*4+ 26] = "smc PENTAX-FA MACRO 100mm F3.5"; + choices[256*4+ 27] = "TAMRON AF28-300mm F/3.5-6.3 LD Aspherical[IF] MACRO (285D)"; + choices[256*4+ 28] = "smc PENTAX-FA 35mm F2 AL"; + choices[256*4+ 29] = "TAMRON AF 28-200mm F/3.8-5.6 LD Super II MACRO (371D)"; + choices[256*4+ 34] = "smc PENTAX-FA 24-90mm F3.5-4.5 AL[IF]"; + choices[256*4+ 35] = "smc PENTAX-FA 100-300mm F4.7-5.8"; + choices[256*4+ 36] = "TAMRON AF70-300mm F/4-5.6 LD MACRO"; + choices[256*4+ 37] = "TAMRON SP AF 24-135mm F3.5-5.6 AD AL (190D)"; + choices[256*4+ 38] = "smc PENTAX-FA 28-105mm F3.2-4.5 AL[IF]"; + choices[256*4+ 39] = "smc PENTAX-FA 31mm F1.8AL Limited"; + choices[256*4+ 41] = "TAMRON AF 28-200mm Super Zoom F3.8-5.6 Aspherical XR [IF] MACRO (A03)"; + choices[256*4+ 43] = "smc PENTAX-FA 28-90mm F3.5-5.6"; + choices[256*4+ 44] = "smc PENTAX-FA J 75-300mm F4.5-5.8 AL"; + choices[256*4+ 45] = "TAMRON 28-300mm F3.5-6.3 Ultra zoom XR"; + choices[256*4+ 46] = "smc PENTAX-FA J 28-80mm F3.5-5.6 AL"; + choices[256*4+ 47] = "smc PENTAX-FA J 18-35mm F4-5.6 AL"; + choices[256*4+ 49] = "TAMRON SP AF 28-75mm F2.8 XR Di (A09)"; + choices[256*4+ 51] = "smc PENTAX-D FA 50mm F2.8 MACRO"; + choices[256*4+ 52] = "smc PENTAX-D FA 100mm F2.8 MACRO"; + choices[256*4+ 244] = "smc PENTAX-DA 21mm F3.2 AL Limited"; + choices[256*4+ 245] = "Schneider D-XENON 50-200mm"; + choices[256*4+ 246] = "Schneider D-XENON 18-55mm"; + choices[256*4+ 247] = "smc PENTAX-DA 10-17mm F3.5-4.5 ED [IF] Fisheye zoom"; + choices[256*4+ 248] = "smc PENTAX-DA 12-24mm F4 ED AL [IF]"; + choices[256*4+ 249] = "TAMRON XR DiII 18-200mm F3.5-6.3 (A14)"; + choices[256*4+ 250] = "smc PENTAX-DA 50-200mm F4-5.6 ED"; + choices[256*4+ 251] = "smc PENTAX-DA 40mm F2.8 Limited"; + choices[256*4+ 252] = "smc PENTAX-DA 18-55mm F3.5-5.6 AL"; + choices[256*4+ 253] = "smc PENTAX-DA 14mm F2.8 ED[IF]"; + choices[256*4+ 254] = "smc PENTAX-DA 16-45mm F4 ED AL"; + choices[256*5+ 1] = "smc PENTAX-FA* 24mm F2 AL[IF]"; + choices[256*5+ 2] = "smc PENTAX-FA 28mm F2.8 AL"; + choices[256*5+ 3] = "smc PENTAX-FA 50mm F1.7"; + choices[256*5+ 4] = "smc PENTAX-FA 50mm F1.4"; + choices[256*5+ 5] = "smc PENTAX-FA* 600mm F4 ED[IF]"; + choices[256*5+ 6] = "smc PENTAX-FA* 300mm F4.5 ED[IF]"; + choices[256*5+ 7] = "smc PENTAX-FA 135mm F2.8 [IF]"; + choices[256*5+ 8] = "smc PENTAX-FA MACRO 50mm F2.8"; + choices[256*5+ 9] = "smc PENTAX-FA MACRO 100mm F2.8"; + choices[256*5+ 10] = "smc PENTAX-FA* 85mm F1.4 [IF]"; + choices[256*5+ 11] = "smc PENTAX-FA* 200mm F2.8 ED[IF]"; + choices[256*5+ 12] = "smc PENTAX-FA 28-80mm F3.5-4.7"; + choices[256*5+ 13] = "smc PENTAX-FA 70-200mm F4-5.6"; + choices[256*5+ 14] = "smc PENTAX-FA* 250-600mm F5.6 ED[IF]"; + choices[256*5+ 15] = "smc PENTAX-FA 28-105mm F4-5.6"; + choices[256*5+ 16] = "smc PENTAX-FA 100-300mm F4.5-5.6"; + choices[256*6+ 1] = "smc PENTAX-FA* 85mm F1.4 [IF]"; + choices[256*6+ 2] = "smc PENTAX-FA* 200mm F2.8 ED[IF]"; + choices[256*6+ 3] = "smc PENTAX-FA* 300mm F2.8 ED[IF]"; + choices[256*6+ 4] = "smc PENTAX-FA* 28-70mm F2.8 AL"; + choices[256*6+ 5] = "smc PENTAX-FA* 80-200mm F2.8 ED[IF]"; + choices[256*6+ 6] = "smc PENTAX-FA* 28-70mm F2.8 AL"; + choices[256*6+ 7] = "smc PENTAX-FA* 80-200mm F2.8 ED[IF]"; + choices[256*6+ 8] = "smc PENTAX-FA 28-70mm F4AL"; + choices[256*6+ 9] = "smc PENTAX-FA 20mm F2.8"; + choices[256*6+ 10] = "smc PENTAX-FA* 400mm F5.6 ED[IF]"; + choices[256*6+ 13] = "smc PENTAX-FA* 400mm F5.6 ED[IF]"; + choices[256*6+ 14] = "smc PENTAX-FA* MACRO 200mm F4 ED[IF]"; + choices[256*7+ 0] = "smc PENTAX-DA 21mm F3.2 AL Limited"; + choices[256*7+ 229] = "smc PENTAX-DA 18-55mm F3.5-5.6 AL II"; + choices[256*7+ 231] = "smc PENTAX-DA 18-250mm F3.5-6.3 ED AL [IF]"; + choices[256*7+ 233] = "smc PENTAX-DA 35mm F2.8 Macro Limited"; + choices[256*7+ 235] = "smc PENTAX-DA* 200mm F2.8 ED [IF] SDM (SDM unused)"; + choices[256*7+ 238] = "TAMRON AF 18-250mm F3.5-6.3 Di II LD Aspherical [IF] MACRO"; + choices[256*7+ 241] = "smc PENTAX-DA* 50-135mm F2.8 ED [IF] SDM (SDM unused)"; + choices[256*7+ 242] = "smc PENTAX-DA* 16-50mm F2.8 ED AL [IF] SDM (SDM unused)"; + choices[256*7+ 243] = "smc PENTAX-DA 70mm F2.4 Limited"; + choices[256*7+ 244] = "smc PENTAX-DA 21mm F3.2 AL Limited"; + choices[256*8+ 235] = "smc PENTAX-DA* 200mm F2.8 ED [IF] SDM"; + choices[256*8+ 241] = "smc PENTAX-DA* 50-135mm F2.8 ED [IF] SDM"; + choices[256*8+ 242] = "smc PENTAX-DA* 16-50mm F2.8 ED AL [IF] SDM"; + choices[256*8+ 232] = "smc PENTAX-DA 17-70mm F4 AL [IF] SDM"; + choices[256*8+ 234] = "smc PENTAX-DA* 300mm F4 ED [IF] SDM"; + choices[256*8+ 235] = "smc PENTAX-DA* 200mm F2.8 ED [IF] SDM"; + choices[256*8+ 241] = "smc PENTAX-DA* 50-135mm F2.8 ED [IF] SDM"; + choices[256*8+ 242] = "smc PENTAX-DA* 16-50mm F2.8 ED AL [IF] SDM"; + choices[256*8+ 255] = "Sigma 70-200mm F2.8 EX DG Macro HSM II"; + + } + virtual std::string toString (Tag* t) { + return choices[256*t->toInt(0,BYTE) + t->toInt(1,BYTE)]; + } +}; +PALensTypeInterpreter paLensTypeInterpreter; + +class PASRInfoInterpreter : public Interpreter { + public: + PASRInfoInterpreter () { } + + virtual std::string toString (Tag* t) { + std::ostringstream str; + int b = t->toInt(0,BYTE); + if (!b) + str << "SRResult = Not stabilized" << std::endl; + else if (b & 1) + str << "SRResult = Stabilized" << std::endl; + b = t->toInt(1,BYTE); + if (!b) + str << "ShakeReduction = Off" << std::endl; + else + str << "ShakeReduction = On" << std::endl; + str << "SRHalfPressTime = " << t->toInt(2,BYTE) << std::endl; + str << "SRFocalLength = " << t->toInt(3,BYTE); + return str.str(); + } +}; +PASRInfoInterpreter paSRInfoInterpreter; + + +const TagAttrib pentaxAttribs[] = { + 0, 1, 0, 0, 0x0001, "PentaxVersion", &stdInterpreter, + 0, 1, 0, 0, 0x0001, "PentaxModelType", &stdInterpreter, + 0, 2, 0, 0, 0x0002, "PreviewImageSize", &stdInterpreter, + 0, 2, 0, 0, 0x0003, "PreviewImageLength", &stdInterpreter, + 0, 2, 0, 0, 0x0004, "PreviewImageStart", &stdInterpreter, + 0, 1, 0, 0, 0x0005, "PentaxModelID", &stdInterpreter, + 0, 1, 0, 0, 0x0006, "Date", &stdInterpreter, + 0, 1, 0, 0, 0x0007, "Time", &stdInterpreter, + 0, 1, 0, 0, 0x0008, "Quality", &paQualityInterpreter, + 0, 1, 0, 0, 0x0009, "PentaxImageSize", &stdInterpreter, + 0, 1, 0, 0, 0x000b, "PictureMode", &paPictureModeInterpreter, + 0, 1, 0, 0, 0x000c, "FlashMode", &paFlashModeInterpreter, + 0, 1, 0, 0, 0x000d, "FocusMode", &paFocusModeInterpreter, + 0, 1, 0, 0, 0x000e, "AFPointSelected", &paAFPointInterpreter, + 0, 1, 0, 0, 0x000f, "AFPointsInFocus", &paAFFocusInterpreter, + 0, 1, 0, 0, 0x0010, "FocusPosition", &stdInterpreter, + 0, 1, 0, 0, 0x0012, "ExposureTime", &stdInterpreter, + 0, 1, 0, 0, 0x0013, "FNumber", &stdInterpreter, + 0, 1, 0, 0, 0x0014, "ISO", &paISOInterpreter, + 0, 1, 0, 0, 0x0015, "LightReading", &stdInterpreter, + 0, 1, 0, 0, 0x0016, "ExposureCompensation", &stdInterpreter, + 0, 1, 0, 0, 0x0017, "MeteringMode", &paMeteringModeInterpreter, + 0, 1, 0, 0, 0x0018, "AutoBracketing", &stdInterpreter, + 0, 1, 0, 0, 0x0019, "WhiteBalance", &paWhiteBalanceInterpreter, + 0, 1, 0, 0, 0x001a, "WhiteBalanceMode", &paWhiteBalanceModeInterpreter, + 0, 1, 0, 0, 0x001b, "BlueBalance", &stdInterpreter, + 0, 1, 0, 0, 0x001c, "RedBalance", &stdInterpreter, + 0, 1, 0, 0, 0x001d, "FocalLength", &stdInterpreter, + 0, 1, 0, 0, 0x001e, "DigitalZoom", &stdInterpreter, + 0, 1, 0, 0, 0x001f, "Saturation", &paSaturationInterpreter, + 0, 1, 0, 0, 0x0020, "Contrast", &paContrastInterpreter, + 0, 1, 0, 0, 0x0021, "Sharpness", &paSharpnessInterpreter, + 0, 1, 0, 0, 0x0022, "WorldTimeLocation", &stdInterpreter, + 0, 1, 0, 0, 0x0023, "HometownCity", &stdInterpreter, + 0, 3, 0, 0, 0x0024, "DestinationCity", &stdInterpreter, + 0, 3, 0, 0, 0x0025, "HometownDST", &stdInterpreter, + 0, 1, 0, 0, 0x0026, "DestinationDST", &stdInterpreter, + 0, 1, 0, 0, 0x0027, "DSPFirmwareVersion", &stdInterpreter, + 0, 1, 0, 0, 0x0028, "CPUFirmwareVersion", &stdInterpreter, + 0, 1, 0, 0, 0x0029, "FrameNumber", &stdInterpreter, + 0, 1, 0, 0, 0x002d, "EffectiveLV", &stdInterpreter, + 0, 1, 0, 0, 0x0032, "ImageProcessing", &stdInterpreter, + 0, 1, 0, 0, 0x0033, "PictureMode", &stdInterpreter, + 0, 1, 0, 0, 0x0034, "DriveMode", &stdInterpreter, + 0, 1, 0, 0, 0x0037, "ColorSpace", &stdInterpreter, + 0, 1, 0, 0, 0x0038, "ImageAreaOffset", &stdInterpreter, + 0, 1, 0, 0, 0x0039, "RawImageSize", &stdInterpreter, + 0, 1, 0, 0, 0x003c, "AFPointsInFocus", &stdInterpreter, + 0, 1, 0, 0, 0x003e, "PreviewImageBorders", &stdInterpreter, + 0, 1, 0, 0, 0x003f, "LensType", &paLensTypeInterpreter, + 0, 1, 0, 0, 0x0040, "SensitivityAdjust", &stdInterpreter, + 0, 1, 0, 0, 0x0041, "ImageProcessingCount", &stdInterpreter, + 0, 1, 0, 0, 0x0047, "CameraTemperature", &stdInterpreter, + 0, 1, 0, 0, 0x0048, "AELock", &paOnOffInterpreter, + 0, 1, 0, 0, 0x0049, "NoiseReduction", &paOnOffInterpreter, + 0, 1, 0, 0, 0x004d, "FlashExposureComp", &stdInterpreter, + 0, 1, 0, 0, 0x004f, "ImageTone", &stdInterpreter, + 0, 1, 0, 0, 0x0050, "ColorTemperature", &stdInterpreter, + 0, 1, 0, 0, 0x005c, "ShakeReductionInfo", &paSRInfoInterpreter, + 0, 1, 0, 0, 0x005d, "ShutterCount", &stdInterpreter, + 0, 1, 0, 0, 0x0200, "BlackPoint", &stdInterpreter, + 0, 1, 0, 0, 0x0201, "WhitePoint", &stdInterpreter, + 0, 1, 0, 0, 0x0205, "ShotInfo", &stdInterpreter, + 0, 1, 0, 0, 0x0206, "AEInfo", &stdInterpreter, + 0, 1, 0, 0, 0x0207, "LensInfo", &stdInterpreter, + 0, 1, 0, 0, 0x0208, "FlashInfo", &stdInterpreter, + 0, 1, 0, 0, 0x0209, "AEMeteringSegments", &stdInterpreter, + 0, 1, 0, 0, 0x020a, "FlashADump", &stdInterpreter, + 0, 1, 0, 0, 0x020b, "FlashBDump", &stdInterpreter, + 0, 1, 0, 0, 0x020d, "WB_RGGBLevelsDaylight", &stdInterpreter, + 0, 1, 0, 0, 0x020e, "WB_RGGBLevelsShade", &stdInterpreter, + 0, 1, 0, 0, 0x020f, "WB_RGGBLevelsCloudy", &stdInterpreter, + 0, 1, 0, 0, 0x0210, "WB_RGGBLevelsTungsten", &stdInterpreter, + 0, 1, 0, 0, 0x0211, "WB_RGGBLevelsFluorescentD", &stdInterpreter, + 0, 1, 0, 0, 0x0212, "WB_RGGBLevelsFluorescentN", &stdInterpreter, + 0, 1, 0, 0, 0x0213, "WB_RGGBLevelsFluorescentW", &stdInterpreter, + 0, 1, 0, 0, 0x0214, "WB_RGGBLevelsFlash", &stdInterpreter, + 0, 1, 0, 0, 0x0215, "CameraInfo", &stdInterpreter, + 0, 1, 0, 0, 0x0216, "BatteryInfo", &stdInterpreter, + 0, 1, 0, 0, 0x021f, "AFInfo", &stdInterpreter, + 0, 1, 0, 0, 0x0222, "ColorInfo", &stdInterpreter, + 0, 1, 0, 0, 0x03fe, "DataDump", &stdInterpreter, + 0, 1, 0, 0, 0x03ff, "UnknownInfo", &stdInterpreter, + 0, 1, 0, 0, 0x0402, "ToneCurve", &stdInterpreter, + 0, 1, 0, 0, 0x0403, "ToneCurves", &stdInterpreter, + 0, 1, 0, 0, 0x0e00, "PrintIM", &stdInterpreter, + -1, 0, 0, 0, 0, "", NULL}; +}; + #endif + diff --git a/rtexif/rtexif.cc b/rtexif/rtexif.cc new file mode 100755 index 000000000..033beee4a --- /dev/null +++ b/rtexif/rtexif.cc @@ -0,0 +1,1384 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * Some parts of the source code (e.g. ciff support) are taken from dcraw + * that is copyrighted by Dave Coffin + * + * 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 +#include +#include +#include +#include + +namespace rtexif { + +StdInterpreter stdInterpreter; + +//--------------- class TagDirectory ------------------------------------------ +// this class is a collection (an array) of tags +//----------------------------------------------------------------------------- + +#define TAG_SUBFILETYPE 0x00fe + +TagDirectory::TagDirectory () + : attribs(ifdAttribs), parent(NULL), order(INTEL) {} + +TagDirectory::TagDirectory (TagDirectory* p, const TagAttrib* ta, ByteOrder border) + : attribs(ta), order(border), parent(p) {} + +TagDirectory::TagDirectory (TagDirectory* p, FILE* f, int base, const TagAttrib* ta, ByteOrder border) { + + attribs = ta; + order = border; + parent = p; + + int numOfTags = get2 (f, order); + if (numOfTags<=0 || numOfTags>200) + return; + + bool thumbdescr = false; + for (int i=0; igetType()==0) { + delete newTag; + continue; + } + + int id = newTag->getID(); + + // detect and possibly ignore tags of directories belonging to the embedded thumbnail image + if (attribs==ifdAttribs && id==TAG_SUBFILETYPE && newTag->toInt()!=0) + thumbdescr = true; + + const TagAttrib* attrib = getAttrib (id); + + if (!attrib || attrib->ignore==1 || (thumbdescr && attrib->ignore==2)) + delete newTag; + else + addTag (newTag); + } +} + +TagDirectory::~TagDirectory () { + + for (int i=0; igetID() < b->getID(); + } +}; + +void TagDirectory::sort () { + + std::sort (tags.begin(), tags.end(), CompareTags()); + for (int i=0; iisDirectory()) + for (int j=0; tags[i]->getDirectory(j); j++) + tags[i]->getDirectory(j)->sort (); +} + +const TagAttrib* TagDirectory::getAttrib (int id) { + + if (attribs) + for (int i=0; attribs[i].ignore!=-1; i++) + if (attribs[i].ID==id) + return &attribs[i]; + + return NULL; +} + +const TagAttrib* TagDirectory::getAttrib (const char* name) { + + if (attribs) + for (int i=0; attribs[i].ignore!=-1; i++) + if (!strcmp (attribs[i].name, name)) + return &attribs[i]; + + return NULL; +} + +void TagDirectory::printAll () const { + + for (int i=0; inameToString (); + if (tags[i]->isDirectory()) + for (int j=0; tags[i]->getDirectory(j); j++) { + printf ("==== DIRECTORY %s[%d]: ====\n", name.c_str(), j); + tags[i]->getDirectory(j)->printAll (); + printf ("==== END OF DIRECTORY %s[%d] ====\n", name.c_str(), j); + } + else { + std::string value = tags[i]->valueToString (); + printf ("%s: %s\n", name.c_str(), value.c_str()); + } + } +} + +void TagDirectory::addTag (Tag* tag) { + + // look up if it already exists: + if (getTag (tag->getID())) + delete tag; + else + tags.push_back (tag); +} + +void TagDirectory::addTagFront (Tag* tag) { + + // look up if it already exists: + if (getTag (tag->getID())) + delete tag; + else + tags.insert (tags.begin(), tag); +} + +void TagDirectory::replaceTag (Tag* tag) { + + // look up if it already exists: + for (int i=0; igetID()==tag->getID()) { + delete tags[i]; + tags[i] = tag; + return; + } + tags.push_back (tag); +} + +Tag* TagDirectory::getTag (int ID) { + + for (int i=0; igetID()==ID) + return tags[i]; + return NULL; +} + +Tag* TagDirectory::getTag (const char* name) { + + if (attribs) { + for (int i=0; attribs[i].ignore!=-1; i++) + if (!strcmp (attribs[i].name, name)) + return getTag (attribs[i].ID); + } + return NULL; +} + +int TagDirectory::calculateSize () { + + int size = 2; // space to store the number of tags + for (int i=0; igetKeep()) + size += 12 + tags[i]->calculateSize (); + + size += 4; // next ifd pointer + return size; +} + +TagDirectory* TagDirectory::clone (TagDirectory* parent) { + + TagDirectory* td = new TagDirectory (parent, attribs, order); + for (int i=0; itags.push_back (tags[i]->clone (td)); + return td; +} + +int TagDirectory::write (int start, unsigned char* buffer) { + + int size = calculateSize (); + int tagnum = 0; + int nondirspace = 0; + for (int i=0; igetKeep()) { + tagnum++; + if (!tags[i]->isDirectory()) + nondirspace += tags[i]->calculateSize(); + } + int nextValOffs = start + 2 + tagnum * 12 + 4; + int nextDirOffs = nextValOffs + nondirspace; + int pos = start; + sset2 (tagnum, buffer+start, order); + pos += 2; + int maxPos = start + size; + for (int i=0; igetKeep()) { + if (!tags[i]->isDirectory()) + nextValOffs = tags[i]->write (pos, nextValOffs, buffer); // pos: where to put the tag, dataoffset: the place where the value can be put. return: next data offset + else + nextDirOffs = tags[i]->write (pos, nextDirOffs, buffer); // pos: where to put the tag, dataoffset: the place where the value can be put. return: next data offset + + pos += 12; + } + } + sset4 (0, buffer+pos, order); + return maxPos; +} + +void TagDirectory::applyChange (std::string name, std::string value) { + + std::string::size_type dp = name.find_first_of ('.'); + std::string fseg = name.substr (0,dp); + // this is a final segment: apply change + if (dp==std::string::npos) { + + Tag* t = NULL; + for (int i=0; inameToString()==fseg) { + t = tags[i]; + break; + } + + if (value=="#keep" && t) + t->setKeep (true); + else if (value=="#delete" && t) + t->setKeep (false); + else if (t && !t->isDirectory()) + t->valueFromString (value); + else { + const TagAttrib* attrib = NULL; + for (int i=0; attribs[i].ignore!=-1; i++) + if (!strcmp (attribs[i].name, fseg.c_str())) { + attrib = &attribs[i]; + break; + } + if (attrib) { + Tag* nt = new Tag (this, attrib); + nt->initString (value.c_str()); + addTag (nt); + } + } + } + // this is a subdirectory + else { + // try to find it + std::string::size_type dp1 = fseg.find_first_of ('['); + std::string::size_type dp2 = fseg.find_first_of (']'); + std::string basename = fseg.substr (0,dp1); + Tag* t = NULL; + int dirnum = -1; + for (int i=0; iisDirectory()) { + for (int j=0; tags[i]->getDirectory(j); j++) { + if (tags[i]->nameToString(j) == fseg) { + t = tags[i]; + dirnum = j; + break; + } + } + if (!t && tags[i]->nameToString() == basename) { // found it, but that directory index does not exist + t = tags[i]; + dirnum = -1; + } + } + if (!t && value!="#keep" && value!="#delete") { + const TagAttrib* attrib = NULL; + for (int i=0; attribs[i].ignore!=-1; i++) + if (!strcmp (attribs[i].name, fseg.c_str())) { + attrib = &attribs[i]; + break; + } + if (attrib && attrib->subdirAttribs) { + t = new Tag (this, attrib); + t->initSubDir (); + addTag (t); + } + dirnum = 0; + } + if (t && dirnum>=0) + t->getDirectory(dirnum)->applyChange (name.substr (dp+1, std::string::npos), value); + } +} + +//--------------- class Tag --------------------------------------------------- +// this class represents a tag stored in the directory +//----------------------------------------------------------------------------- + +Tag::Tag (TagDirectory* p, FILE* f, int base) + : parent(p), value(NULL), directory(NULL), count(0), attrib(NULL), type(INVALID) { + + tag = get2 (f, getOrder()); + type = (TagType)get2 (f, getOrder()); + count = get4 (f, getOrder()); + + makerNoteKind = NOMK; + keep = false; + + // filter out invalid tags + if ((int)type<1 || (int)type>14 || count>900000 || count<0) { + type = INVALID; + return; + } + + // save file position + int save = ftell(f) + 4; + + // load value field (possibly seek before) + valuesize = count * ("11124811248484"[type<14?type:0]-'0'); + + if (valuesize > 4) + fseek (f, get4(f, getOrder()) + base, SEEK_SET); + + attrib = parent->getAttrib (tag); + + if (attrib && (attrib->action==1 || attrib->action==3)) + keep = true; + + // if this tag is the makernote, it needs special treatment (brand specific parsing) + if (tag==0x927C && attrib && !strcmp (attrib->name, "MakerNote")) { + value = NULL; + // select format of makernote + char make[128], model[128]; + Tag* tmake = parent->getParent()->getTag ("Make"); + if (tmake) + tmake->toString (make); + else + make[0] = 0; + Tag* tmodel = parent->getParent()->getTag ("Model"); + if (tmodel) + tmodel->toString (model); + else + model[0] = 0; + if (!strncmp(make, "NIKON", 5)) { + if (!strncmp(model, "NIKON E700",10)||!strncmp(model, "NIKON E800",10)||!strncmp(model, "NIKON E900",10)||!strncmp(model, "NIKON E900S",11)||!strncmp(model, "NIKON E910", 10)||!strncmp(model, "NIKON E950", 10)) { + makerNoteKind = HEADERIFD; + valuesize = 8; + value = new unsigned char[8]; + fread (value, 1, 8, f); + directory = new TagDirectory*[2]; + directory[0] = new TagDirectory (parent, f, base, nikon2Attribs, getOrder()); + directory[1] = NULL; + } + else if (!strncmp(model, "NIKON E990",10)||(!strncmp(model, "NIKON D1",8) && model[8]!='0')) { + makerNoteKind = IFD; + directory = new TagDirectory*[2]; + directory[0] = new TagDirectory (parent, f, base, nikon3Attribs, getOrder()); + directory[1] = NULL; + } + else { + // needs refinement! (embedded tiff header parsing) + makerNoteKind = NIKON3; + valuesize = 18; + value = new unsigned char[18]; + int basepos = ftell (f); + fread (value, 1, 18, f); + directory = new TagDirectory*[2]; + directory[0] = new TagDirectory (parent, f, basepos+10, nikon3Attribs, getOrder()); + directory[1] = NULL; + } + } + else if (!strncmp(make, "Canon", 5)) { + makerNoteKind = IFD; + directory = new TagDirectory*[2]; + directory[0] = new TagDirectory (parent, f, base, canonAttribs, getOrder()); + directory[1] = NULL; + } + else if (!strncmp(make, "PENTAX", 6)) { + makerNoteKind = HEADERIFD; + valuesize = 6; + value = new unsigned char[6]; + fread (value, 1, 6, f); + directory = new TagDirectory*[2]; + directory[0] = new TagDirectory (parent, f, base, pentaxAttribs, getOrder()); + directory[1] = NULL; + } + else if (!strncmp(make, "FUJIFILM", 8)) { + makerNoteKind = FUJI; + valuesize = 12; + value = new unsigned char[12]; + fread (value, 1, 12, f); + directory = new TagDirectory*[2]; + directory[0] = new TagDirectory (parent, f, ftell(f)-12, fujiAttribs, INTEL); + directory[1] = NULL; + } + else if (!strncmp(make, "KONICA MINOLTA", 14) || !strncmp(make, "Minolta", 7)) { + makerNoteKind = IFD; + directory = new TagDirectory*[2]; + directory[0] = new TagDirectory (parent, f, base, minoltaAttribs, getOrder()); + directory[1] = NULL; + } + else if (!strncmp(make, "SONY", 4)) { + valuesize = 12; + value = new unsigned char[12]; + fread (value, 1, 12, f); + if (!strncmp((char*)value, "SONY DSC", 8)) + makerNoteKind = HEADERIFD; + else { + makerNoteKind = IFD; + fseek (f, -12, SEEK_CUR); + } + directory = new TagDirectory*[2]; + directory[0] = new TagDirectory (parent, f, base, sonyAttribs, getOrder()); + directory[1] = NULL; + } + else if (!strncmp(make, "OLYMPUS", 7)) { + makerNoteKind = HEADERIFD; + valuesize = 8; + value = new unsigned char[12]; + fread (value, 1, 8, f); + directory = new TagDirectory*[2]; + directory[1] = NULL; + if (!strncmp((char*)value, "OLYMPUS", 7)) { + makerNoteKind = OLYMPUS2; + fread (value+8, 1, 4, f); + valuesize = 12; + directory[0] = new TagDirectory (parent, f, ftell(f)-12, olympusAttribs, value[8]=='I' ? INTEL : MOTOROLA); + } + else + directory[0] = new TagDirectory (parent, f, base, olympusAttribs, getOrder()); + } + else { + type = INVALID; + fseek (f, save, SEEK_SET); + return; + } + } + else if (type==UNDEFINED && attrib && attrib->subdirAttribs) { + count = 1; + type = LONG; + directory = new TagDirectory*[2]; + directory[0] = new TagDirectory (parent, f, base, attrib->subdirAttribs, getOrder()); + directory[1] = NULL; + } + else { + // read value + value = new unsigned char [valuesize]; + fread (value, 1, valuesize, f); + + // if it is a subdirectory, load it (there may be several directories if count>1) + if (attrib && attrib->subdirAttribs) { + int pos = ftell (f); + // count the number of valid subdirs + int sdcount = count; + if (sdcount>0) { + if (parent->getAttribTable()==olympusAttribs) + sdcount = 1; + // allocate space + directory = new TagDirectory*[sdcount+1]; + // load directories + for (int j=0,i=0; jsubdirAttribs, getOrder()); + fseek (f, pos, SEEK_SET); + } + // set the terminating NULL + directory[sdcount] = NULL; + } + else + type = INVALID; + } + } + // seek back to the saved position + fseek (f, save, SEEK_SET); +} + +Tag* Tag::clone (TagDirectory* parent) { + + Tag* t = new Tag (parent, attrib); + + t->tag = tag; + t->type = type; + t->count = count; + t->keep = keep; + t->valuesize = valuesize; + if (value) { + t->value = new unsigned char [valuesize]; + memcpy (t->value, value, valuesize); + } + else + value = NULL; + t->makerNoteKind = makerNoteKind; + if (directory) { + int ds = 0; + for (; directory[ds]; ds++); + t->directory = new TagDirectory*[ds+1]; + for (int i=0; idirectory[i] = directory[i]->clone (parent); + t->directory[ds] = NULL; + } + else + t->directory = NULL; + return t; +} + +Tag::~Tag () { + + // delete value + if (value) + delete [] value; + + // if there are directories behind the tag, delete them + int i = 0; + if (directory) { + while (directory[i]) + delete directory[i++]; + delete [] directory; + } +} + +void Tag::setInt (int v, int ofs, TagType astype) { + + if (astype==SHORT) + sset2 (v, value+ofs, getOrder()); + else if (astype==RATIONAL) { + sset4 (v, value+ofs, getOrder()); + sset4 (1, value+ofs+4, getOrder()); + } + else + sset4 (v, value+ofs, getOrder()); +} + +void Tag::fromInt (int v) { + + if (type==SHORT) + sset2 (v, value, getOrder()); + else + sset4 (v, value, getOrder()); +} + +void Tag::fromString (const char* v, int size) { + + delete value; + if (size<0) + valuesize = strlen (v) + 1; + else + valuesize = size; + count = valuesize; + value = new unsigned char [valuesize]; + memcpy ((char*)value, v, valuesize); +} + +int Tag::toInt (int ofs, TagType astype) { + + int a; + if (astype == INVALID) + astype = type; + switch (astype) { + case BYTE: return value[ofs]; + case ASCII: return 0; + case SSHORT:return (int)int2_to_signed(sget2 (value+ofs, getOrder())); + case SHORT: return (int)sget2 (value+ofs, getOrder()); + case SLONG: + case LONG: return (int)sget4 (value+ofs, getOrder()); + case SRATIONAL: + case RATIONAL: a = (int)sget4 (value+ofs+4, getOrder()); return a==0 ? 0 : (int)sget4 (value+ofs, getOrder()) / a; + case FLOAT: return (int)((float) sget4 (value+ofs, getOrder())); + case UNDEFINED: return 0; + } +} + +double Tag::toDouble (int ofs) { + + double ud, dd; + switch (type) { + case BYTE: return (double)((int)value[ofs]); + case ASCII: return 0.0; + case SSHORT:return (double)int2_to_signed(sget2 (value+ofs, getOrder())); + case SHORT: return (double)((int)sget2 (value+ofs, getOrder())); + case SLONG: + case LONG: return (double)((int)sget4 (value+ofs, getOrder())); + case SRATIONAL: + case RATIONAL: ud = (int)sget4 (value+ofs, getOrder()); dd = (int)sget4 (value+ofs+4, getOrder()); return dd==0 ? 0 : (double)ud / (double)dd; + case FLOAT: return (float) sget4 (value+ofs, getOrder()); + case UNDEFINED: return 0; + } +} + +void Tag::toRational (int& num, int& denom, int ofs) { + + switch (type) { + case BYTE: num = (int)value[ofs]; denom = 1; break; + case ASCII: num = 0; denom = 0; break; + case SSHORT: + case SHORT: num = (int)sget2 (value+ofs, getOrder()); denom = 1; break; + case SLONG: + case LONG: num = (int)sget4 (value+ofs, getOrder()); denom = 1; break; + case SRATIONAL: + case RATIONAL: num = (int)sget4 (value+ofs, getOrder()); denom = (int)sget4 (value+ofs+4, getOrder()); break; + case FLOAT: num = 0; denom = 0; break; + case UNDEFINED: num = 0; denom = 0; break; + } +} + +void Tag::toString (char* buffer, int ofs) { + + if (type==UNDEFINED && !directory) { + bool isstring = true; + int i=0; + for (i=0; i+ofs126) + isstring = false; + if (isstring) { + int j = 0; + for (i=0; i+ofs') + buffer[j++] = '\\'; + buffer[j++] = value[i+ofs]; + } + buffer[j++] = 0; + return; + } + } + else if (type==ASCII) { + sprintf (buffer, "%s", value+ofs); + return; + } + + int maxcount = 4; + if (count<4) + maxcount = count; + + strcpy (buffer, ""); + for (int i=0; i0) + strcat (buffer, ", "); + char* b = buffer + strlen(buffer); + + switch (type) { + case UNDEFINED: + case BYTE: sprintf (b, "%d", value[i+ofs]); break; + case SSHORT: + case SHORT: sprintf (b, "%d", toInt(2*i+ofs)); break; + case SLONG: + case LONG: sprintf (b, "%d", toInt(4*i+ofs)); break; + case SRATIONAL: + case RATIONAL: sprintf (b, "%d/%d", (int)sget4 (value+8*i+ofs, getOrder()), (int)sget4 (value+8*i+ofs+4, getOrder())); break; + case FLOAT: sprintf (b, "%g", toDouble(8*i+ofs)); break; + } + } + if (count > maxcount) + strcat (buffer, "..."); +} + +std::string Tag::nameToString (int i) { + + static char buffer[1024]; + if (attrib) + strcpy (buffer, attrib->name); + else + sprintf (buffer, "0x%x", tag); + if (i>0) + sprintf (buffer+strlen(buffer)-1, "[%d]", i); + return buffer; +} + +std::string Tag::valueToString () { + + static char buffer[1024]; + if (attrib && attrib->interpreter) + return attrib->interpreter->toString (this); + else { + toString (buffer); + return buffer; + } +} + +void Tag::valueFromString (const std::string& value) { + + if (attrib && attrib->interpreter) + attrib->interpreter->fromString (this, value); +} + +int Tag::calculateSize () { + int size = 0; + + if (directory) { + int j; + for (j=0; directory[j]; j++) + size += directory[j]->calculateSize (); + if (j>1) + size += 4*j; + } + else if (valuesize > 4) + size += valuesize + (valuesize%2); // we align tags to even byte positions + + if (makerNoteKind!=NOMK) + count = directory[0]->calculateSize (); + + if (makerNoteKind==NIKON3 || makerNoteKind==OLYMPUS2 || makerNoteKind==FUJI) + size += valuesize; + else if (makerNoteKind==HEADERIFD) + size += valuesize; + + return size; +} + +int Tag::write (int offs, int dataOffs, unsigned char* buffer) { + + if ((int)type==0 || offs>65500) + return dataOffs; + + sset2 (tag, buffer+offs, parent->getOrder()); + offs += 2; + unsigned short typ = type; + sset2 (typ, buffer+offs, parent->getOrder()); + offs += 2; + sset4 (count, buffer+offs, parent->getOrder()); + offs += 4; + if (!directory) { + if (valuesize>4) { + sset4 (dataOffs, buffer+offs, parent->getOrder()); + memcpy (buffer+dataOffs, value, valuesize); + if (valuesize%2) + buffer[dataOffs+valuesize] = 0; // zero padding required by the exif standard + return dataOffs + valuesize + (valuesize%2); + } + else { + memcpy (buffer+offs, value, valuesize); + return dataOffs; + } + } + else { + if (makerNoteKind==NIKON3) { + sset4 (dataOffs, buffer+offs, parent->getOrder()); + memcpy (buffer+dataOffs, value, 18); + dataOffs += 10; + dataOffs += directory[0]->write (8, buffer+dataOffs); + return dataOffs; + } + else if (makerNoteKind==OLYMPUS2 || makerNoteKind==FUJI) { + sset4 (dataOffs, buffer+offs, parent->getOrder()); + memcpy (buffer+dataOffs, value, valuesize); + dataOffs += valuesize + directory[0]->write (valuesize, buffer+dataOffs); + return dataOffs; + } + else if (makerNoteKind==HEADERIFD) { + sset4 (dataOffs, buffer+offs, parent->getOrder()); + memcpy (buffer+dataOffs, value, valuesize); + dataOffs += valuesize; + dataOffs += directory[0]->write (dataOffs, buffer); + return dataOffs; + } + else if (!directory[1]) { + sset4 (dataOffs, buffer+offs, parent->getOrder()); + return directory[0]->write (dataOffs, buffer); + } + else { + sset4 (dataOffs, buffer+offs, parent->getOrder()); + int linkOffs = dataOffs; + for (int i=0; directory[i]; i++) + dataOffs += 4; + for (int i=0; directory[i]; i++) { + sset4 (dataOffs, buffer+linkOffs, parent->getOrder()); + linkOffs += 4; + dataOffs = directory[i]->write (dataOffs, buffer); + } + return dataOffs; + } + } +} + +Tag::Tag (TagDirectory* p, const TagAttrib* attr) + : parent(p), attrib(attr), makerNoteKind (NOMK), directory(NULL), keep(true), tag(attr ? attr->ID : -1), count(0), valuesize(0), value(NULL), type(INVALID) { +} + +Tag::Tag (TagDirectory* p, const TagAttrib* attr, int data, TagType t) + : parent(p), attrib(attr), makerNoteKind (NOMK), directory(NULL), keep(true), tag(attr ? attr->ID : -1), count(1), valuesize(0), value(NULL), type(t) { + + initInt (data, t); +} + +Tag::Tag (TagDirectory* p, const TagAttrib* attr, const char* text) + : parent(p), attrib(attr), makerNoteKind (NOMK), directory(NULL), keep(true), tag(attr ? attr->ID : -1), count(1), valuesize(0), value(NULL), type(ASCII) { + + initString (text); +} + +void Tag::initInt (int data, TagType t, int cnt) { + + type = t; + if (t==LONG) + valuesize = 4; + else if (t==SHORT) + valuesize = 2; + else if (t==RATIONAL) + valuesize = 8; + + count = cnt; + valuesize *= count; + value = new unsigned char[valuesize]; + setInt (data, 0, t); +} + +void Tag::initString (const char* text) { + + type = ASCII; + count = strlen(text)+1; + valuesize = count; + value = new unsigned char[valuesize]; + strcpy ((char*)value, text); +} + +void Tag::initSubDir () { + type = LONG; + valuesize = 4; + count = 1; + value = new unsigned char[4]; + setInt (0); + directory = new TagDirectory*[2]; + directory[0] = new TagDirectory (parent, attrib ? attrib->subdirAttribs : NULL, parent->getOrder()); + directory[1] = NULL; +} + +void Tag::initMakerNote (MNKind mnk, const TagAttrib* ta) { + type = UNDEFINED; + valuesize = 4; + count = 1; + value = new unsigned char[4]; + setInt (0); + directory = new TagDirectory*[2]; + directory[0] = new TagDirectory (parent, ta, parent->getOrder()); + directory[1] = NULL; + makerNoteKind = mnk; +} + +void Tag::initUndefArray (const char* data, int len) { + type = UNDEFINED; + count = valuesize = len; + value = new unsigned char[valuesize]; + memcpy (value, data, len); +} + +void Tag::initLongArray (const char* data, int len) { + type = LONG; + count = (len+3)/4; + valuesize = count * 4; + value = new unsigned char[valuesize]; + memcpy (value, data, len); +} + +void Tag::initRational (int num, int den) { + count = 1; + valuesize = 8; + value = new unsigned char[8]; + type = RATIONAL; + setInt (num, 0); + setInt (den, 4); +} + +//--------------- class IFDParser --------------------------------------------- +// static functions to read tag directoryes from different kinds of files +//----------------------------------------------------------------------------- + + +const TagAttrib* lookupAttrib (const TagAttrib* dir, const char* field) { + + for (int i=0; dir[i].ignore!=-1; i++) + if (!strcmp (dir[i].name, field)) + return &dir[i]; +} + + +TagDirectory* ExifManager::parseCIFF (FILE* f, int base, int length) { + + TagDirectory* root = new TagDirectory (NULL, ifdAttribs, INTEL); + Tag* exif = new Tag (root, lookupAttrib(ifdAttribs,"Exif")); + exif->initSubDir (); + Tag* mn = new Tag (exif->getDirectory(), lookupAttrib(exifAttribs,"MakerNote")); + mn->initMakerNote (IFD, canonAttribs); + root->addTag (exif); + exif->getDirectory()->addTag (mn); + parseCIFF (f, base, length, root); + root->sort (); + return root; +} + +Tag* ExifManager::saveCIFFMNTag (FILE* f, TagDirectory* root, int len, const char* name) { + int s = ftell (f); + char* data = new char [len]; + fread (data, len, 1, f); + TagDirectory* mn = root->getTag ("Exif")->getDirectory()->getTag("MakerNote")->getDirectory(); + Tag* cs = new Tag (mn, lookupAttrib(canonAttribs, name)); + cs->initUndefArray (data, len); + mn->addTag (cs); + fseek (f, s, SEEK_SET); + return cs; +} + +void ExifManager::parseCIFF (FILE* f, int base, int length, TagDirectory* root) { + + static char buffer[1024]; + Tag* t; + + fseek (f, base+length-4, SEEK_SET); + + int dirStart = get4 (f, INTEL) + base; + fseek (f, dirStart, SEEK_SET); + + int numOfTags = get2 (f, INTEL); + + if (numOfTags > 100) return; + + float exptime, shutter, aperture, fnumber, ev; + exptime = fnumber = shutter = aperture = ev = -1000; + int focal_len, iso; + focal_len = iso = -1; + + TagDirectory* exif = root->getTag("Exif")->getDirectory(); + + time_t timestamp = time (NULL); + + for (int i=0; i> 8) + 8) | 8) == 0x38) + parseCIFF (f, ftell(f), len, root); // Parse a sub-table + + if (type == 0x0810) { + fread (buffer, 64, 1, f); + t = new Tag (root, lookupAttrib(ifdAttribs,"Artist")); + t->initString (buffer); + root->addTag (t); + } + if (type == 0x080a) { + fread (buffer, 64, 1, f); + t = new Tag (root, lookupAttrib(ifdAttribs,"Make")); + t->initString (buffer); + root->addTag (t); + fseek (f, strlen(buffer) - 63, SEEK_CUR); + fread (buffer, 64, 1, f); + t = new Tag (root, lookupAttrib(ifdAttribs,"Model")); + t->initString (buffer); + root->addTag (t); + } + if (type == 0x1818) { + ev = int_to_float(get4(f, INTEL)); + shutter = int_to_float(get4(f, INTEL)); + exptime = pow (2, -shutter); + aperture = int_to_float(get4(f, INTEL)); + fnumber = pow (2, aperture/2); + + } + if (type == 0x102d) { + Tag* t = saveCIFFMNTag (f, root, len, "CanonCameraSettings"); + int mm = t->toInt (34, SHORT); + Tag* nt = new Tag (exif, lookupAttrib(exifAttribs,"MeteringMode")); + switch (mm) { + case 0: nt->initInt (5, SHORT); break; + case 1: nt->initInt (3, SHORT); break; + case 2: nt->initInt (1, SHORT); break; + case 3: nt->initInt (5, SHORT); break; + case 4: nt->initInt (6, SHORT); break; + case 5: nt->initInt (2, SHORT); break; + } + exif->addTag (nt); + nt = new Tag (exif, lookupAttrib(exifAttribs,"MaxApertureValue")); + nt->initRational (t->toInt(52,SHORT), 32); + exif->addTag (nt); + int em = t->toInt(40,SHORT); + nt = new Tag (exif, lookupAttrib(exifAttribs,"ExposureProgram")); + switch (em) { + case 0: nt->initInt (2, SHORT); break; + case 1: nt->initInt (2, SHORT); break; + case 2: nt->initInt (4, SHORT); break; + case 3: nt->initInt (3, SHORT); break; + case 4: nt->initInt (1, SHORT); break; + default: nt->initInt (0, SHORT); break; + } + exif->addTag (nt); + nt = new Tag (exif, lookupAttrib(exifAttribs,"Flash")); + if (t->toInt(8,SHORT)==0) + nt->initInt (0, SHORT); + else + nt->initInt (1, SHORT); + exif->addTag (nt); + nt = new Tag (exif, lookupAttrib(exifAttribs,"MaxApertureValue")); + nt->initRational (t->toInt(52,SHORT), 32); + exif->addTag (nt); + } + if (type == 0x1029) + saveCIFFMNTag (f, root, len, "CanonFocalLength"); + if (type == 0x1031) + saveCIFFMNTag (f, root, len, "SensorInfo"); + if (type == 0x1033) + saveCIFFMNTag (f, root, len, "CustomFunctions"); + if (type == 0x1038) + saveCIFFMNTag (f, root, len, "CanonAFInfo"); + if (type == 0x1093) + saveCIFFMNTag (f, root, len, "CanonFileInfo"); + if (type == 0x10a9) + saveCIFFMNTag (f, root, len, "ColorBalance"); + if (type == 0x102a) { + saveCIFFMNTag (f, root, len, "CanonShotInfo"); + + iso = pow (2, (get4(f, INTEL),get2(f, INTEL))/32.0 - 4) * 50; + aperture = ((get2(f, INTEL),(short)get2(f, INTEL))/32.0); + fnumber = pow (2, aperture/2); + shutter = ((short)get2(f, INTEL))/32.0; + ev = ((short)get2(f, INTEL))/32.0; + fseek (f, 34, SEEK_CUR); + if (shutter > 1e6) shutter = get2 (f, INTEL) / 10.0; + exptime = pow (2,-shutter); + } + if (type == 0x5029) { + focal_len = len >> 16; + if ((len & 0xffff) == 2) focal_len /= 32; + } +// if (type == 0x5813) flash_used = int_to_float(len); + if (type == 0x580e) timestamp = len; + if (type == 0x180e) timestamp = get4 (f, INTEL); + if ((type | 0x4000) == 0x580e) + timestamp = mktime (gmtime (×tamp)); + fseek (f, nextPos, SEEK_SET); + } + if (shutter>-999) { + t = new Tag (exif, lookupAttrib(exifAttribs,"ShutterSpeedValue")); + t->initRational ((int)(shutter*10000), 10000); + exif->addTag (t); + } + if (exptime>-999) { + t = new Tag (exif, lookupAttrib(exifAttribs,"ExposureTime")); + t->initRational ((int)(exptime*10000), 10000); + exif->addTag (t); + } + if (aperture>-999) { + t = new Tag (exif, lookupAttrib(exifAttribs,"ApertureValue")); + t->initRational ((int)(aperture*10), 10); + exif->addTag (t); + } + if (fnumber>-999) { + t = new Tag (exif, lookupAttrib(exifAttribs,"FNumber")); + t->initRational ((int)(fnumber*10), 10); + exif->addTag (t); + } + if (ev>-999) { + t = new Tag (exif, lookupAttrib(exifAttribs,"ExposureBiasValue")); + t->initRational ((int)(ev*1000), 1000); + exif->addTag (t); + } + if (iso>0) { + t = new Tag (exif, lookupAttrib(exifAttribs,"ISOSpeedRatings")); + t->initInt (iso, LONG); + exif->addTag (t); + } + if (focal_len>0) { + t = new Tag (exif, lookupAttrib(exifAttribs,"FocalLength")); + t->initRational (focal_len*32, 32); + exif->addTag (t); + } + + if (timestamp!=time(NULL)) { + struct tm* tim = localtime (×tamp); + strftime (buffer, 20, "%Y:%m:%d %H:%M:%S", tim); + t = new Tag (exif, lookupAttrib(exifAttribs,"DateTimeOriginal")); + t->initString (buffer); + exif->addTag (t); + t = new Tag (exif, lookupAttrib(exifAttribs,"DateTimeDigitized")); + t->initString (buffer); + exif->addTag (t); + t = new Tag (root, lookupAttrib(ifdAttribs,"DateTime")); + t->initString (buffer); + root->addTag (t); + } +} + +TagDirectory* ExifManager::parse (FILE* f, int base) { + + // read tiff header + fseek (f, base, SEEK_SET); + unsigned short bo; + fread (&bo, 1, 2, f); + ByteOrder order = (ByteOrder)((int)bo); + get2 (f, order); + int firstifd = get4 (f, order); + + // seek to IFD0 + fseek (f, base+firstifd, SEEK_SET); + + // first read the IFD directory + TagDirectory* root = new TagDirectory (NULL, f, base, ifdAttribs, order); + + // fix ISO issue with nikon and panasonic cameras + Tag* exif = root->getTag ("Exif"); + if (exif && !exif->getDirectory()->getTag("ISOSpeedRatings")) { + Tag* make = root->getTag ("Make"); + if (make && !strncmp((char*)make->getValue(), "NIKON", 5)) { + Tag* mn = exif->getDirectory()->getTag("MakerNote"); + if (mn) { + Tag* iso = mn->getDirectory()->getTag("ISOSpeed"); + if (iso) { + std::string isov = iso->valueToString (); + Tag* niso = new Tag (exif->getDirectory(), exif->getDirectory()->getAttrib ("ISOSpeedRatings")); + niso->initInt (atoi(isov.c_str()), SHORT); + exif->getDirectory()->addTagFront (niso); + } + } + } + else if (make && (!strncmp((char*)make->getValue(), "Panasonic", 9) || !strncmp((char*)make->getValue(), "LEICA", 5))) { + Tag* iso = root->getTag("PanaISO"); + if (iso) { + std::string isov = iso->valueToString (); + Tag* niso = new Tag (exif->getDirectory(), exif->getDirectory()->getAttrib ("ISOSpeedRatings")); + niso->initInt (atoi(isov.c_str()), SHORT); + exif->getDirectory()->addTagFront (niso); + } + } + } + +// root->printAll (); + + return root; +} + +TagDirectory* ExifManager::parseJPEG (FILE* f) { + + fseek (f, 0, SEEK_SET); + unsigned char markerl = 0xff; + unsigned char c; + fread (&c, 1, 1, f); + const char exifid[] = "Exif\0\0"; + char idbuff[8]; + bool success = false; + int tiffbase = -1; + while (fread (&c, 1, 1, f)) { + if (c!=markerl) continue; + if (fread (&c, 1, 1, f) && c==0xe1) { // APP1 marker found + if (fread (idbuff, 1, 8, f)<8) + return NULL; + if (!memcmp(idbuff+2, exifid, 6)) { // Exif info found + tiffbase = ftell (f); + return parse (f, tiffbase); + } + } + } + return NULL; +} + +TagDirectory* ExifManager::parseTIFF (FILE* f) { + + return parse (f, 0); +} + +std::vector ExifManager::defTags; + +// forthis: the byte order will be taken from directory "forthis" +const std::vector& ExifManager::getDefaultTIFFTags (TagDirectory* forthis) { + + for (int i=0; i >& changeList, int W, int H, unsigned char* buffer) { + + // write tiff header + int offs = 6; + memcpy (buffer, "Exif\0\0", 6); + ByteOrder order = INTEL; + if (root) + order = root->getOrder (); + sset2 ((unsigned short)order, buffer+offs, order); offs += 2; + sset2 (42, buffer+offs, order); offs += 2; + sset4 (8, buffer+offs, order); offs += 4; + + TagDirectory* cl; + if (root) + cl = ((TagDirectory*)root)->clone (NULL); + else + cl = new TagDirectory (NULL, ifdAttribs, INTEL); + + for (int i=0; iapplyChange (changeList[i].first, changeList[i].second); + + getDefaultTIFFTags (cl); + + defTags[0]->setInt (W, 0, LONG); + defTags[1]->setInt (H, 0, LONG); + defTags[8]->setInt (8, 0, SHORT); + + for (int i=defTags.size()-1; i>=0; i--) + cl->replaceTag (defTags[i]->clone (cl)); + cl->sort (); + int size = cl->write (8, buffer+6); + + delete cl; + + return size + 6; +} + +int ExifManager::createTIFFHeader (const TagDirectory* root, const std::vector< std::pair >& changeList, int W, int H, int bps, const char* profiledata, int profilelen, const char* iptcdata, int iptclen, unsigned char* buffer) { + +// write tiff header + int offs = 0; + ByteOrder order = INTEL; + if (root) + order = root->getOrder (); + sset2 ((unsigned short)order, buffer+offs, order); offs += 2; + sset2 (42, buffer+offs, order); offs += 2; + sset4 (8, buffer+offs, order); offs += 4; + + TagDirectory* cl; + if (root) + cl = ((TagDirectory*)root)->clone (NULL); + else + cl = new TagDirectory (NULL, ifdAttribs, INTEL); + +// add tiff strip data + int rps = 8; + int strips = ceil((double)H/rps); + cl->replaceTag (new Tag (cl, lookupAttrib(ifdAttribs,"RowsPerStrip"), rps, LONG)); + Tag* stripBC = new Tag (cl, lookupAttrib(ifdAttribs,"StripByteCounts")); + stripBC->initInt (0, LONG, strips); + cl->replaceTag (stripBC); + Tag* stripOffs = new Tag (cl, lookupAttrib(ifdAttribs,"StripOffsets")); + stripOffs->initInt (0, LONG, strips); + cl->replaceTag (stripOffs); + for (int i=0; isetInt (rps*W*3*bps/8, i*4); + int remaining = (H-rps*floor((double)H/rps))*W*3*bps/8; + if (remaining) + stripBC->setInt (remaining, (strips-1)*4); + else + stripBC->setInt (rps*W*3*bps/8, (strips-1)*4); + if (profiledata) { + Tag* icc = new Tag (cl, lookupAttrib(ifdAttribs,"ICCProfile")); + icc->initUndefArray (profiledata, profilelen); + cl->replaceTag (icc); + } + if (iptcdata) { + Tag* iptc = new Tag (cl, lookupAttrib(ifdAttribs,"IPTCData")); + iptc->initLongArray (iptcdata, iptclen); + cl->replaceTag (iptc); + } + +// apply list of changes + for (int i=0; iapplyChange (changeList[i].first, changeList[i].second); + + // append default properties + getDefaultTIFFTags (cl); + + defTags[0]->setInt (W, 0, LONG); + defTags[1]->setInt (H, 0, LONG); + defTags[8]->setInt (bps, 0, SHORT); + + for (int i=defTags.size()-1; i>=0; i--) + cl->replaceTag (defTags[i]->clone (cl)); + +// calculate strip offsets + int size = cl->calculateSize (); + int byps = bps / 8; + for (int i=0; isetInt (size + 8 + i*rps*W*3*byps, i*4); + + cl->sort (); + int endOffs = cl->write (8, buffer); + +// cl->printAll(); + delete cl; + + return endOffs; +} + +//----------------------------------------------------------------------------- +// global functions to read byteorder dependent data +//----------------------------------------------------------------------------- +unsigned short sget2 (unsigned char *s, rtexif::ByteOrder order) { + + if (order == rtexif::INTEL) return s[0] | s[1] << 8; + else return s[0] << 8 | s[1]; +} + +int sget4 (unsigned char *s, rtexif::ByteOrder order) { + + if (order == rtexif::INTEL) return s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24; + else return s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]; +} + +unsigned short get2 (FILE* f, rtexif::ByteOrder order) { + + unsigned char str[2] = { 0xff,0xff }; + fread (str, 1, 2, f); + return rtexif::sget2 (str, order); +} + +int get4 (FILE* f, rtexif::ByteOrder order) { + + unsigned char str[4] = { 0xff,0xff,0xff,0xff }; + fread (str, 1, 4, f); + return rtexif::sget4 (str, order); +} + +void sset2 (unsigned short v, unsigned char *s, rtexif::ByteOrder order) { + + if (order == rtexif::INTEL) { + s[0] = v & 0xff; v >>= 8; + s[1] = v; + } + else { + s[1] = v & 0xff; v >>= 8; + s[0] = v; + } +} + +void sset4 (int v, unsigned char *s, rtexif::ByteOrder order) { + + if (order == rtexif::INTEL) { + s[0] = v & 0xff; v >>= 8; + s[1] = v & 0xff; v >>= 8; + s[2] = v & 0xff; v >>= 8; + s[3] = v; + } + else { + s[3] = v & 0xff; v >>= 8; + s[2] = v & 0xff; v >>= 8; + s[1] = v & 0xff; v >>= 8; + s[0] = v; + } +} + +float int_to_float (int i) { + union { int i; float f; } u; + u.i = i; + return u.f; +} + +short int int2_to_signed (short unsigned int i) { + union { short unsigned int i; short int s; } u; + u.i = i; + return u.s; +} + +} diff --git a/rtexif/rtexif.h b/rtexif/rtexif.h new file mode 100755 index 000000000..3f029db33 --- /dev/null +++ b/rtexif/rtexif.h @@ -0,0 +1,244 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _MEXIF3_ +#define _MEXIF3_ + +#include +#include +#include +#include +#include + +namespace rtexif { + +enum TagType {INVALID=0, BYTE=1, ASCII=2, SHORT=3, LONG=4, RATIONAL=5, UNDEFINED=7, SSHORT=8, SLONG=9, SRATIONAL=10, FLOAT=11, DOUBLE=12, OLYUNDEF=13, SUBDIR=99}; +enum ActionCode {DONTWRITE=0, WRITE=1, SYSTEM=2}; +enum ByteOrder {INTEL=0x4949, MOTOROLA=0x4D4D}; +enum MNKind {NOMK, IFD, HEADERIFD, NIKON3, OLYMPUS2, FUJI}; + +struct TIFFHeader { + + unsigned short byteOrder; + unsigned short fixed; + unsigned int ifdOffset; +}; + +class Tag; +class Interpreter; + +// structure of informations describing an exif tag +struct TagAttrib { + int ignore; // =0: never ignore, =1: always ignore, =2: ignore if the subdir type is reduced image, =-1: end of table + int action; //=0: dont write it to the output, =1: write it to the output, =2: dont write, dont show, =3: write, dont show + int editable; + const TagAttrib* subdirAttribs; // =0 ->not subdir + unsigned short ID; + const char* name; + Interpreter* interpreter; +}; + +// a directory of tags +class TagDirectory { + + protected: + std::vector tags; // tags in the directory + const TagAttrib* attribs; // descriptor table to decode the tags + ByteOrder order; // byte order + TagDirectory* parent; // parent directory (NULL if root) + + public: + TagDirectory (); + TagDirectory (TagDirectory* p, FILE* f, int base, const TagAttrib* ta, ByteOrder border); + TagDirectory (TagDirectory* p, const TagAttrib* ta, ByteOrder border); + ~TagDirectory (); + + inline ByteOrder getOrder () const { return order; } + TagDirectory* getParent () { return parent; } + inline int getCount () const { return tags.size (); } + const TagAttrib* getAttrib (int id); + const TagAttrib* getAttrib (const char* name); + const TagAttrib* getAttribTable() { return attribs; } + Tag* getTag (const char* name); + Tag* getTag (int ID); + void addTag (Tag* a); + void addTagFront (Tag* a); + void replaceTag (Tag* a); + inline Tag* getTagByIndex (int ix) { return tags[ix]; } + inline void setOrder (ByteOrder bo) { order = bo; } + + int calculateSize (); + int write (int start, unsigned char* buffer); + TagDirectory* clone (TagDirectory* parent); + void applyChange (std::string field, std::string value); + + void printAll () const; + void sort (); +}; + +// a class representing a single tag +class Tag { + + protected: + unsigned short tag; + TagType type; + unsigned int count; + unsigned char* value; + int valuesize; + bool keep; + + const TagAttrib* attrib; + TagDirectory* parent; + TagDirectory** directory; + MNKind makerNoteKind; + + public: + Tag (TagDirectory* parent, FILE* f, int base); // parse next tag from the file + Tag (TagDirectory* parent, const TagAttrib* attr); + Tag (TagDirectory* parent, const TagAttrib* attr, int data, TagType t); // create a new tag from array (used + Tag (TagDirectory* parent, const TagAttrib* attr, const char* data); // create a new tag from array (used + ~Tag (); + void initInt (int data, TagType t, int count=1); + void initString (const char* text); + void initSubDir (); + void initMakerNote (MNKind mnk, const TagAttrib* ta); + void initUndefArray (const char* data, int len); + void initLongArray (const char* data, int len); + void initRational (int num, int den); + + // get basic tag properties + int getID () const { return tag; } + int getCount () const { return count; } + TagType getType () const { return type; } + unsigned char* getValue () const { return value; } + const TagAttrib* getAttrib () const { return attrib; } + inline ByteOrder getOrder () const { return parent ? parent->getOrder() : INTEL; } + inline TagDirectory* getParent () const { return parent; } + int getValueSize () const { return valuesize; } + + // read/write value + int toInt (int ofs=0, TagType astype=INVALID); + void fromInt (int v); + double toDouble (int ofs=0); + void toRational (int& num, int& denom, int ofs=0); + void toString (char* buffer, int ofs=0); + void fromString (const char* v, int size=-1); + void setInt (int v, int ofs=0, TagType astype=LONG); + + // additional getter/setter for more confortable use + std::string valueToString (); + std::string nameToString (int i=0); + void valueFromString (const std::string& value); + + // functions for writing + int calculateSize (); + int write (int offs, int dataOffs, unsigned char* buffer); + Tag* clone (TagDirectory* parent); + + // to control if the tag shall be written + bool getKeep () { return keep; } + void setKeep (bool k) { keep = k; } + + // get subdirectory (there can be several, the last is NULL) + bool isDirectory () { return directory!=NULL; } + TagDirectory* getDirectory (int i=0) { return directory[i]; } + + MNKind getMakerNoteFormat () { return makerNoteKind; } + }; + +class ExifManager { + + static std::vector defTags; + + static Tag* saveCIFFMNTag (FILE* f, TagDirectory* root, int len, const char* name); + public: + static TagDirectory* parse (FILE*f, int base); + static TagDirectory* parseJPEG (FILE*f); + static TagDirectory* parseTIFF (FILE*f); + static TagDirectory* parseCIFF (FILE* f, int base, int length); + static void parseCIFF (FILE* f, int base, int length, TagDirectory* root); + + static const std::vector& getDefaultTIFFTags (TagDirectory* forthis); + static int createJPEGMarker (const TagDirectory* root, const std::vector< std::pair >& changeList, int W, int H, unsigned char* buffer); + static int createTIFFHeader (const TagDirectory* root, const std::vector< std::pair >& changeList, int W, int H, int bps, const char* profiledata, int profilelen, const char* iptcdata, int iptclen, unsigned char* buffer); +}; + +class Interpreter { + protected: + char buffer[1024]; + public: + Interpreter () {} + virtual std::string toString (Tag* t) { return ""; } + virtual void fromString (Tag* t, const std::string& value) {} +}; + +class StdInterpreter : public Interpreter { + public: + StdInterpreter () {} + virtual std::string toString (Tag* t) { + t->toString (buffer); + return std::string (buffer); + } + virtual void fromString (Tag* t, const std::string& value) { + if (t->getType()==SHORT || t->getType()==LONG) + t->fromInt (atoi(value.c_str())); + else + t->fromString (value.c_str()); + } +}; +extern StdInterpreter stdInterpreter; +class ChoiceInterpreter : public Interpreter { + protected: + std::map choices; + public: + ChoiceInterpreter () {}; + virtual std::string toString (Tag* t) { + std::map::iterator r = choices.find (t->toInt()); + if (r!=choices.end()) + return r->second; + else { + t->toString (buffer); + return std::string (buffer); + } + } +}; + +inline unsigned short sget2 (unsigned char *s, ByteOrder order); +inline int sget4 (unsigned char *s, ByteOrder order); +inline unsigned short get2 (FILE* f, ByteOrder order); +inline int get4 (FILE* f, ByteOrder order); +inline void sset2 (unsigned short v, unsigned char *s, ByteOrder order); +inline void sset4 (int v, unsigned char *s, ByteOrder order); +inline float int_to_float (int i); +inline short int int2_to_signed (short unsigned int i); + + +extern const TagAttrib exifAttribs[]; +extern const TagAttrib gpsAttribs[]; +extern const TagAttrib iopAttribs[]; +extern const TagAttrib ifdAttribs[]; +extern const TagAttrib nikon2Attribs[]; +extern const TagAttrib nikon3Attribs[]; +extern const TagAttrib canonAttribs[]; +extern const TagAttrib pentaxAttribs[]; +extern const TagAttrib fujiAttribs[]; +extern const TagAttrib minoltaAttribs[]; +extern const TagAttrib sonyAttribs[]; +extern const TagAttrib olympusAttribs[]; +}; +#endif diff --git a/rtexif/sonyminoltaattribs.cc b/rtexif/sonyminoltaattribs.cc new file mode 100755 index 000000000..eb53a3746 --- /dev/null +++ b/rtexif/sonyminoltaattribs.cc @@ -0,0 +1,391 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _SONYMINOLTAATTRIBS_ +#define _SONYMINOLTAATTRIBS_ + +#include +#include +#include +#include +#include +#include + +namespace rtexif { + +class SAOnOffInterpreter : public ChoiceInterpreter { + public: + SAOnOffInterpreter () { + choices[0] = "Off"; + choices[1] = "On"; + choices[5] = "On"; + } +}; +SAOnOffInterpreter saOnOffInterpreter; + +class SASceneModeInterpreter : public ChoiceInterpreter { + public: + SASceneModeInterpreter () { + choices[0] = "Normal (P,A,S or M)"; + choices[1] = "Portrait"; + choices[2] = "Text"; + choices[3] = "Night Scene"; + choices[4] = "Sunset"; + choices[5] = "Sports"; + choices[6] = "Landscape"; + choices[8] = "Macro"; + choices[8] = "Super Macro"; + choices[16] = "Auto"; + choices[17] = "Night Portrait"; + } +}; +SASceneModeInterpreter saSceneModeInterpreter; + +class SAZoneMatchingInterpreter : public ChoiceInterpreter { + public: + SAZoneMatchingInterpreter () { + choices[0] = "ISO Setting Used"; + choices[1] = "High Key"; + choices[2] = "Low Key"; + } +}; +SAZoneMatchingInterpreter saZoneMatchingInterpreter; + +class SADynamicRangeOptimizerInterpreter : public ChoiceInterpreter { + public: + SADynamicRangeOptimizerInterpreter () { + choices[0] = "Off"; + choices[1] = "Standard"; + choices[2] = "Advanced"; + } +}; +SADynamicRangeOptimizerInterpreter saDynamicRangeOptimizerInterpreter; + +class SAColorModeInterpreter : public ChoiceInterpreter { + public: + SAColorModeInterpreter () { + choices[0] = "Standard"; + choices[1] = "Vivid"; + choices[2] = "Portrait"; + choices[3] = "Landscape"; + choices[4] = "Sunset"; + choices[5] = "Night Scene"; + choices[6] = "B&W"; + choices[7] = "Adobe RGB"; + choices[12] = "Neutral"; + } +}; +SAColorModeInterpreter saColorModeInterpreter; + +class SAExposureModeInterpreter : public ChoiceInterpreter { + public: + SAExposureModeInterpreter () { + choices[0] = "Auto"; + choices[5] = "Landscape"; + choices[6] = "Program"; + choices[7] = "Aperture Priority"; + choices[8] = "Shutter Priority"; + choices[9] = "Night Scene"; + choices[15] = "Manual"; + } +}; +SAExposureModeInterpreter saExposureModeInterpreter; + +class SAQualityInterpreter : public ChoiceInterpreter { + public: + SAQualityInterpreter () { + choices[0] = "Normal"; + choices[1] = "Fine"; + } +}; +SAQualityInterpreter saQualityInterpreter; + +class SAAntiBlurInterpreter : public ChoiceInterpreter { + public: + SAAntiBlurInterpreter () { + choices[0] = "Off"; + choices[1] = "On (Continuous)"; + choices[2] = "On (Shooting)"; + choices[65535] = "n/a"; + } +}; +SAAntiBlurInterpreter saAntiBlurInterpreter; + +class SALensIDInterpreter : public ChoiceInterpreter { + public: + SALensIDInterpreter () { + choices[0] = "Minolta AF 28-85mm F3.5-4.5"; + choices[1] = "Minolta AF 80-200mm F2.8 HS-APO G"; + choices[2] = "Minolta AF 28-70mm F2.8 G"; + choices[3] = "Minolta AF 28-80mm F4-5.6"; + choices[5] = "Minolta AF 35-70mm F3.5-4.5"; + choices[6] = "Minolta AF 24-85mm F3.5-4.5 [New]"; + choices[7] = "Minolta AF 100-300mm F4.5-5.6 APO [New]"; + choices[8] = "Minolta AF 70-210mm F4.5-5.6"; + choices[9] = "Minolta AF 50mm F3.5 Macro"; + choices[10] = "Minolta AF 28-105mm F3.5-4.5 [New]"; + choices[11] = "Minolta AF 300mm F4 HS-APO G"; + choices[12] = "Minolta AF 100mm F2.8 Soft Focus"; + choices[13] = "Minolta AF 75-300mm F4.5-5.6"; + choices[14] = "Minolta AF 100-400mm F4.5-6.7 APO"; + choices[15] = "Minolta AF 400mm F4.5 HS-APO G"; + choices[16] = "Minolta AF 17-35mm F3.5 G"; + choices[17] = "Minolta AF 20-35mm F3.5-4.5"; + choices[18] = "Minolta AF 28-80mm F3.5-5.6 II"; + choices[19] = "Minolta AF 35mm F1.4"; + choices[20] = "Minolta/Sony STF 135mm F2.8 [T4.5]"; + choices[22] = "Minolta AF 35-80mm F4-5.6"; + choices[23] = "Minolta AF 200mm F4 G APO Macro"; + choices[24] = "Minolta/Sony AF 24-105mm F3.5-4.5 (D)"; + choices[25] = "Minolta AF 100-300mm F4.5-5.6 (APO D)"; + choices[27] = "Minolta AF 85mm F1.4 G"; + choices[28] = "Minolta AF 100mm F2.8 Macro (D)"; + choices[29] = "Minolta AF 75-300mm F4.5-5.6 (D)"; + choices[30] = "Minolta AF 28-80mm F3.5-5.6 (D)"; + choices[31] = "Minolta/Sony AF 50mm F2.8 Macro (D) or AF 50mm F3.5 Macro"; + choices[32] = "Minolta AF 300mm F2.8 G"; + choices[33] = "Minolta/Sony AF 70-200mm F2.8 G (D) SSM"; + choices[35] = "Minolta AF 85mm F1.4 G (D) Limited"; + choices[36] = "Minolta AF 28-100mm F3.5-5.6 (D)"; + choices[38] = "Minolta AF 17-35mm F2.8-4 (D)"; + choices[39] = "Minolta AF 28-75mm F2.8 (D)"; + choices[40] = "Minolta/Sony AF DT 18-70mm F3.5-5.6 (D)"; + choices[41] = "Minolta/Sony AF DT 11-18mm F4.5-5.6 (D)"; + choices[42] = "Minolta AF DT 18-200mm F3.5-6.3 (D)"; + choices[43] = "Minolta AF 35mm F1.4 G"; + choices[44] = "Minolta AF 50mm F1.4"; + choices[45] = "Carl Zeiss Planar T* 85mm F1.4 ZA"; + choices[46] = "Carl Zeiss Vario-Sonnar T* DT 16-80mm F3.5-4.5 ZA"; + choices[47] = "Carl Zeiss Sonnar T* 135mm F1.8 ZA"; + choices[50] = "Sony AF DT 18-250mm F3.5-6.3"; + choices[51] = "Sony AF DT 16-105mm F3.5-5.6 or 55-200mm f/4-5.5"; + choices[128] = "Tamron Lens (various models)"; + choices[129] = "Tamron 200-400mm F5.6 or 70-300mm f/4-5.6 LD"; + choices[137] = "Cosina 70-210mm F2.8-4 AF"; + choices[138] = "Soligor 19-35mm F3.5-4.5"; + choices[255] = "Tamron AF 70-300mm f/4-5.6 Di LD MACRO 1:2"; + choices[2550] = "Minolta AF 50mm F1.7"; + choices[2551] = "Minolta AF 35-70mm F4"; + choices[2552] = "Minolta AF 28-85mm F3.5-4.5 [New]"; + choices[2553] = "Minolta AF 28-135mm F4-4.5"; + choices[2554] = "Minolta AF 35-105mm F3.5-4.5"; + choices[2555] = "Minolta AF 70-210mm F4 Macro"; + choices[2556] = "Minolta AF 135mm F2.8"; + choices[2557] = "Minolta AF 28mm F2.8"; + choices[2558] = "Minolta AF 24-50mm F4"; + choices[2560] = "Minolta AF 100-200mm F4.5"; + choices[2561] = "Minolta AF 75-300mm F4.5-5.6"; + choices[2562] = "Minolta/Sony AF 50mm F1.4 [New]"; + choices[2563] = "Minolta AF 300mm F2.8 G"; + choices[2564] = "Minolta AF 50mm F2.8 Macro"; + choices[2565] = "Minolta AF 600mm F4"; + choices[2566] = "Minolta AF 24mm F2.8"; + choices[2572] = "Minolta/Sony AF 500mm F8 Reflex"; + choices[2578] = "Minolta AF 16mm F2.8 Fisheye"; + choices[2579] = "Minolta AF 20mm F2.8"; + choices[2581] = "Minolta/Sony AF 100mm F2.8 Macro New"; + choices[2585] = "Minolta AF 35-105mm F3.5-4.5 New"; + choices[2588] = "Minolta AF 70-210mm F3.5-4.5"; + choices[2589] = "Minolta AF 80-200 F2.8 APO"; + choices[2591] = "Minolta AF 35mm F1.4"; + choices[2592] = "Minolta AF 85mm F1.4 G (D)"; + choices[2593] = "Minolta AF 200mm F2.8 G APO"; + choices[2594] = "Minolta AF 3x-1x F1.7-2.8 Macro"; + choices[2596] = "Minolta AF 28mm F2"; + choices[2597] = "Minolta AF 35mm F2"; + choices[2598] = "Minolta AF 100mm F2"; + choices[2604] = "Minolta AF 80-200mm F4.5-5.6"; + choices[2605] = "Minolta AF 35-80mm F4-5.6"; + choices[2606] = "Minolta AF 100-300mm F4.5-5.6 (D)"; + choices[2607] = "Minolta AF 35-80mm F4-5.6"; + choices[2608] = "Minolta AF 300mm F2.8 G"; + choices[2609] = "Minolta AF 600mm F4 HS-APO G"; + choices[2612] = "Minolta AF 200mm F2.8 G HS-APO"; + choices[2613] = "Minolta AF 50mm F1.7 New"; + choices[2615] = "Minolta AF 28-105mm F3.5-4.5 Power Zoom"; + choices[2616] = "Minolta AF 35-200mm F4.5-5.6 Power Zoom"; + choices[2618] = "Minolta AF 28-80mm F4-5.6 Power Zoom"; + choices[2619] = "Minolta AF 80-200mm F4.5-5.6 Power Zoom"; + choices[2620] = "Minolta AF 28-70mm F2.8 G"; + choices[2621] = "Minolta AF 100-300mm F4.5-5.6 Power Zoom"; + choices[2624] = "Minolta AF 35-80mm F4-5.6 Power Zoom"; + choices[2628] = "Minolta AF 80-200mm F2.8 G"; + choices[2629] = "Minolta AF 85mm F1.4 New"; + choices[2631] = "Minolta/Sony AF 100-300mm F4.5-5.6 APO"; + choices[2632] = "Minolta AF 24-50mm F4 New"; + choices[2638] = "Minolta AF 50mm F2.8 Macro New"; + choices[2639] = "Minolta AF 100mm F2.8 Macro"; + choices[2641] = "Minolta AF 20mm F2.8 New"; + choices[2642] = "Minolta AF 24mm F2.8 New"; + choices[2644] = "Minolta AF 100-400mm F4.5-6.7 APO"; + choices[2662] = "Minolta AF 50mm F1.4 New"; + choices[2667] = "Minolta AF 35mm F2 New"; + choices[2668] = "Minolta AF 28mm F2 New"; + choices[2672] = "Minolta AF 24-105mm F3.5-4.5 (D)"; + choices[4574] = "Minolta AF 200mm F2.8 G x2"; + choices[4585] = "Tamron - SP AF 300 F2.8 LD IF"; + choices[25501] = "Minolta AF 50mm F1.7"; + choices[25511] = "Minolta AF 35-70mm F4"; + choices[25521] = "Minolta AF 28-85mm F3.5-4.5 [New]"; + choices[25531] = "Minolta AF 28-135mm F4-4.5"; + choices[25541] = "Minolta AF 35-105mm F3.5-4.5"; + choices[25551] = "Minolta AF 70-210mm F4 Macro"; + choices[25561] = "Minolta AF 135mm F2.8"; + choices[25571] = "Minolta AF 28mm F2.8"; + choices[25581] = "Minolta AF 24-50mm F4"; + choices[25601] = "Minolta AF 100-200mm F4.5"; + choices[25611] = "Minolta AF 75-300mm F4.5-5.6"; + choices[25621] = "Minolta/Sony AF 50mm F1.4 [New]"; + choices[25631] = "Minolta AF 300mm F2.8 G"; + choices[25641] = "Minolta AF 50mm F2.8 Macro"; + choices[25651] = "Minolta AF 600mm F4"; + choices[25661] = "Minolta AF 24mm F2.8"; + choices[25721] = "Minolta/Sony AF 500mm F8 Reflex"; + choices[25781] = "Minolta AF 16mm F2.8 Fisheye"; + choices[25791] = "Minolta AF 20mm F2.8"; + choices[25811] = "Minolta/Sony AF 100mm F2.8 Macro New"; + choices[25858] = "Minolta AF 35-105mm F3.5-4.5 New"; + choices[25881] = "Minolta AF 70-210mm F3.5-4.5"; + choices[25891] = "Minolta AF 80-200 F2.8 APO"; + choices[25911] = "Minolta AF 35mm F1.4"; + choices[25921] = "Minolta AF 85mm F1.4 G (D)"; + choices[25931] = "Minolta AF 200mm F2.8 G APO"; + choices[25941] = "Minolta AF 3x-1x F1.7-2.8 Macro"; + choices[25961] = "Minolta AF 28mm F2"; + choices[25971] = "Minolta AF 35mm F2"; + choices[25981] = "Minolta AF 100mm F2"; + choices[26041] = "Minolta AF 80-200mm F4.5-5.6"; + choices[26051] = "Minolta AF 35-80mm F4-5.6"; + choices[26061] = "Minolta AF 100-300mm F4.5-5.6 (D)"; + choices[26071] = "Minolta AF 35-80mm F4-5.6"; + choices[26081] = "Minolta AF 300mm F2.8 G"; + choices[26091] = "Minolta AF 600mm F4 HS-APO G"; + choices[26121] = "Minolta AF 200mm F2.8 G HS-APO"; + choices[26131] = "Minolta AF 50mm F1.7 New"; + choices[26151] = "Minolta AF 28-105mm F3.5-4.5 Power Zoom"; + choices[26161] = "Minolta AF 35-200mm F4.5-5.6 Power Zoom"; + choices[26181] = "Minolta AF 28-80mm F4-5.6 Power Zoom"; + choices[26191] = "Minolta AF 80-200mm F4.5-5.6 Power Zoom"; + choices[26201] = "Minolta AF 28-70mm F2.8 G"; + choices[26211] = "Minolta AF 100-300mm F4.5-5.6 Power Zoom"; + choices[26241] = "Minolta AF 35-80mm F4-5.6 Power Zoom"; + choices[26281] = "Minolta AF 80-200mm F2.8 G"; + choices[26291] = "Minolta AF 85mm F1.4 New"; + choices[26311] = "Minolta/Sony AF 100-300mm F4.5-5.6 APO"; + choices[26321] = "Minolta AF 24-50mm F4 New"; + choices[26381] = "Minolta AF 50mm F2.8 Macro New"; + choices[26391] = "Minolta AF 100mm F2.8 Macro"; + choices[26411] = "Minolta AF 20mm F2.8 New"; + choices[26421] = "Minolta AF 24mm F2.8 New"; + choices[26441] = "Minolta AF 100-400mm F4.5-6.7 APO"; + choices[26621] = "Minolta AF 50mm F1.4 New"; + choices[26671] = "Minolta AF 35mm F2 New"; + choices[26681] = "Minolta AF 28mm F2 New"; + choices[26721] = "Minolta AF 24-105mm F3.5-4.5 (D)"; + choices[45741] = "Minolta AF 200mm F2.8 G x2"; + choices[45851] = "Tamron - SP AF 300 F2.8 LD I"; + } +}; +SALensIDInterpreter saLensIDInterpreter; + +class MATeleconverterInterpreter : public ChoiceInterpreter { + public: + MATeleconverterInterpreter () { + choices[0] = "None "; + choices[0x48] = "Minolta AF 2x APO (D)"; + choices[0x50] = "Minolta AF 2x APO II"; + choices[0x88] = "Minolta AF 1.4x APO (D)"; + choices[0x90] = "Minolta AF 1.4x APO II"; + } +}; +MATeleconverterInterpreter maTeleconverterInterpreter; + +class MAQualityInterpreter : public ChoiceInterpreter { + public: + MAQualityInterpreter () { + choices[0] = "Raw"; + choices[1] = "Super Fine"; + choices[2] = "Fine"; + choices[3] = "Standard"; + choices[4] = "Economy"; + choices[5] = "Extra fine"; + } +}; +MAQualityInterpreter maQualityInterpreter; + +class MAImageSizeInterpreter : public ChoiceInterpreter { + public: + MAImageSizeInterpreter () { + choices[1] = "1600x1200"; + choices[2] = "1280x960"; + choices[3] = "640x480"; + choices[5] = "2560x1920"; + choices[6] = "2272x1704"; + choices[7] = "2048x1536"; + } +}; +MAImageSizeInterpreter maImageSizeInterpreter; + +const TagAttrib minoltaAttribs[] = { + 0, 1, 0, 0, 0x0000, "MakerNoteVersion", &stdInterpreter, + 0, 1, 0, 0, 0x0001, "MinoltaCameraSettingsOld", &stdInterpreter, + 0, 1, 0, 0, 0x0003, "MinoltaCameraSettings", &stdInterpreter, + 0, 1, 0, 0, 0x0004, "MinoltaCameraSettings7D", &stdInterpreter, + 0, 1, 0, 0, 0x0018, "ImageStabilization", &stdInterpreter, + 0, 1, 0, 0, 0x0040, "CompressedImageSize", &stdInterpreter, + 1, 1, 0, 0, 0x0081, "PreviewImage", &stdInterpreter, + 1, 1, 0, 0, 0x0088, "PreviewImageStart", &stdInterpreter, + 1, 1, 0, 0, 0x0089, "PreviewImageLength", &stdInterpreter, + 0, 1, 0, 0, 0x0100, "SceneMode", &saSceneModeInterpreter, + 0, 1, 0, 0, 0x0101, "ColorMode", &saColorModeInterpreter, + 0, 1, 0, 0, 0x0102, "MinoltaQuality", &maQualityInterpreter, + 0, 1, 0, 0, 0x0103, "MinoltaImageSize", &maImageSizeInterpreter, + 0, 1, 0, 0, 0x0104, "FlashExposureComp", &stdInterpreter, + 0, 1, 0, 0, 0x0105, "Teleconverter", &maTeleconverterInterpreter, + 0, 1, 0, 0, 0x0107, "ImageStabilization", &saOnOffInterpreter, + 0, 1, 0, 0, 0x010a, "ZoneMatching", &saZoneMatchingInterpreter, + 0, 1, 0, 0, 0x010b, "ColorTemperature", &stdInterpreter, + 0, 1, 0, 0, 0x010c, "LensID", &saLensIDInterpreter, + 0, 1, 0, 0, 0x0113, "ImageStabilization", &saOnOffInterpreter, + 0, 1, 0, 0, 0x0114, "MinoltaCameraSettings", &stdInterpreter, + 1, 1, 0, 0, 0x0e00, "PrintIM", &stdInterpreter, + 0, 1, 0, 0, 0x0f00, "MinoltaCameraSettings2", &stdInterpreter, + -1, 0, 0, 0, 0, "", NULL}; + +const TagAttrib sonyAttribs[] = { + 1, 1, 0, 0, 0x0e00, "PrintIM", &stdInterpreter, + 1, 1, 0, 0, 0x2001, "PreviewImage", &stdInterpreter, + 0, 1, 0, 0, 0xb020, "ColorReproduction", &stdInterpreter, + 0, 1, 0, 0, 0xb021, "ColorTemperature", &stdInterpreter, + 0, 1, 0, 0, 0xb023, "SceneMode", &saSceneModeInterpreter, + 0, 1, 0, 0, 0xb024, "ZoneMatching", &saZoneMatchingInterpreter, + 0, 1, 0, 0, 0xb025, "DynamicRangeOptimizer", &saDynamicRangeOptimizerInterpreter, + 0, 1, 0, 0, 0xb026, "ImageStabilization", &saOnOffInterpreter, + 0, 1, 0, 0, 0xb027, "LensID", &saLensIDInterpreter, + 0, 1, 0, minoltaAttribs, 0xb028, "MinoltaMakerNote", &stdInterpreter, + 0, 1, 0, 0, 0xb029, "ColorMode", &saColorModeInterpreter, + 0, 1, 0, 0, 0xb040, "Macro", &saOnOffInterpreter, + 0, 1, 0, 0, 0xb041, "ExposureMode", &saExposureModeInterpreter, + 0, 1, 0, 0, 0xb047, "Quality", &saQualityInterpreter, + 0, 1, 0, 0, 0xb04b, "AntiBlur", &saAntiBlurInterpreter, + 0, 1, 0, 0, 0xb04e, "LongExposureNoiseReduction", &saOnOffInterpreter, + -1, 0, 0, 0, 0, "", NULL}; + +}; + #endif + diff --git a/rtexif/stdattribs.cc b/rtexif/stdattribs.cc new file mode 100755 index 000000000..3fa72010d --- /dev/null +++ b/rtexif/stdattribs.cc @@ -0,0 +1,486 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _STDATTRIBS_ +#define _STDATTRIBS_ + +#include +#include +#include +#include +#include + +namespace rtexif { + +class ColorSpaceInterpreter : public ChoiceInterpreter { + + public: + ColorSpaceInterpreter () { + choices[1] = "sRGB"; + choices[0xffff] = "Uncalibrated"; + } +}; +ColorSpaceInterpreter colorSpaceInterpreter; + +class ExposureProgramInterpreter : public ChoiceInterpreter { + + public: + ExposureProgramInterpreter () { + choices[0] = "Not defined"; + choices[1] = "Manual"; + choices[2] = "Normal program"; + choices[3] = "Aperture priority"; + choices[4] = "Shutter priority"; + choices[5] = "Creative program"; + choices[6] = "Action program"; + choices[7] = "Portrait mode"; + choices[8] = "Landscape mode"; + } +}; +ExposureProgramInterpreter exposureProgramInterpreter; + +class MeteringModeInterpreter : public ChoiceInterpreter { + + public: + MeteringModeInterpreter () { + choices[0] = "Unknown"; + choices[1] = "Average"; + choices[2] = "Center weighted"; + choices[3] = "Spot"; + choices[4] = "Multispot"; + choices[5] = "Pattern"; + choices[6] = "Partial"; + choices[255] = "Other"; + } +}; +MeteringModeInterpreter meteringModeInterpreter; + +class ExposureModeInterpreter : public ChoiceInterpreter { + + public: + ExposureModeInterpreter () { + choices[0] = "Auto exposure"; + choices[1] = "Manual exposure"; + choices[2] = "Auto bracket"; + } +}; +ExposureModeInterpreter exposureModeInterpreter; + +class WhiteBalanceInterpreter : public ChoiceInterpreter { + + public: + WhiteBalanceInterpreter () { + choices[0] = "Auto white balance"; + choices[1] = "Manual white balance"; + } +}; +WhiteBalanceInterpreter whiteBalanceInterpreter; + +class SceneCaptureInterpreter : public ChoiceInterpreter { + + public: + SceneCaptureInterpreter () { + choices[0] = "Standard"; + choices[1] = "Landscape"; + choices[2] = "Portrait"; + choices[3] = "Night scene"; + } +}; +SceneCaptureInterpreter sceneCaptureInterpreter; + +class GainControlInterpreter : public ChoiceInterpreter { + + public: + GainControlInterpreter () { + choices[0] = "None"; + choices[1] = "Low gain up"; + choices[2] = "High gain up"; + choices[3] = "Low gain down"; + choices[4] = "High gain down"; + } +}; +GainControlInterpreter gainControlInterpreter; + +class ContrastInterpreter : public ChoiceInterpreter { + + public: + ContrastInterpreter () { + choices[0] = "Normal"; + choices[1] = "Soft"; + choices[2] = "Hard"; + } +}; +ContrastInterpreter contrastInterpreter; + +class SharpnessInterpreter : public ChoiceInterpreter { + + public: + SharpnessInterpreter () { + choices[0] = "Normal"; + choices[1] = "Soft"; + choices[2] = "Hard"; + } +}; +SharpnessInterpreter sharpnessInterpreter; + +class SaturationInterpreter : public ChoiceInterpreter { + + public: + SaturationInterpreter () { + choices[0] = "Normal"; + choices[1] = "Low saturation"; + choices[2] = "High saturation"; + } +}; +SaturationInterpreter saturationInterpreter; + +class FlashInterpreter : public ChoiceInterpreter { + + public: + FlashInterpreter () { + choices[0x0000] = "Flash did not fire"; + choices[0x0001] = "Flash fired"; + choices[0x0005] = "Strobe return light not detected"; + choices[0x0007] = "Strobe return light detected"; + choices[0x0009] = "Flash fired, compulsory flash mode"; + choices[0x000D] = "Flash fired, compulsory flash mode, return light not detected"; + choices[0x000F] = "Flash fired, compulsory flash mode, return light detected"; + choices[0x0010] = "Flash did not fire, compulsory flash mode"; + choices[0x0018] = "Flash did not fire, auto mode"; + choices[0x0019] = "Flash fired, auto mode"; + choices[0x001D] = "Flash fired, auto mode, return light not detected"; + choices[0x001F] = "Flash fired, auto mode, return light detected"; + choices[0x0020] = "No flash function"; + choices[0x0041] = "Flash fired, red-eye reduction mode"; + choices[0x0045] = "Flash fired, red-eye reduction mode, return light not detected"; + choices[0x0047] = "Flash fired, red-eye reduction mode, return light detected"; + choices[0x0049] = "Flash fired, compulsory flash mode, red-eye reduction mode"; + choices[0x004D] = "Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected"; + choices[0x004F] = "Flash fired, compulsory flash mode, red-eye reduction mode, return light detected"; + choices[0x0059] = "Flash fired, auto mode, red-eye reduction mode"; + choices[0x005D] = "Flash fired, auto mode, return light not detected, red-eye reduction mode"; + choices[0x005F] = "Flash fired, auto mode, return light detected, red-eye reduction mode"; + } +}; +FlashInterpreter flashInterpreter; + +class LightSourceInterpreter : public ChoiceInterpreter { + + public: + LightSourceInterpreter () { + choices[0] = "Unknown"; + choices[1] = "Daylight"; + choices[2] = "Fluorescent"; + choices[3] = "Tungsten"; + choices[4] = "Flash"; + choices[9] = "Fine weather"; + choices[10] = "Cloudy weather"; + choices[11] = "Shade"; + choices[12] = "Daylight fluorescent"; + choices[13] = "Day white fluorescent"; + choices[14] = "Cool white fluorescent"; + choices[15] = "White fluorescent"; + choices[17] = "Standard light A"; + choices[18] = "Standard light B"; + choices[19] = "Standard light C"; + choices[20] = "D55"; + choices[21] = "D65"; + choices[22] = "D75"; + choices[23] = "D50"; + choices[24] = "ISO studio tungsten"; + choices[255] = "Other light source"; + } +}; +LightSourceInterpreter lightSourceInterpreter; + +class CompressionInterpreter : public ChoiceInterpreter { + + public: + CompressionInterpreter () { + choices[1] = "Uncompressed"; + choices[6] = "JPEG Compression"; + } +}; +CompressionInterpreter compressionInterpreter; + +class PhotometricInterpreter : public ChoiceInterpreter { + + public: + PhotometricInterpreter () { + choices[2] = "RGB"; + choices[6] = "YCbCr"; + } +}; +PhotometricInterpreter photometricInterpreter; + +class PlanarConfigInterpreter : public ChoiceInterpreter { + + public: + PlanarConfigInterpreter () { + choices[1] = "Chunky format"; + choices[2] = "Planar format"; + } +}; +PlanarConfigInterpreter planarConfigInterpreter; + +class FNumberInterpreter : public Interpreter { + public: + FNumberInterpreter () {} + virtual std::string toString (Tag* t) { + sprintf (buffer, "%0.1f", t->toDouble()); + return buffer; + } +}; +FNumberInterpreter fNumberInterpreter; + +class ApertureInterpreter : public Interpreter { + public: + ApertureInterpreter () {} + virtual std::string toString (Tag* t) { + sprintf (buffer, "%0.1f", pow(2.0, t->toDouble()/2.0)); + return buffer; + } +}; +ApertureInterpreter apertureInterpreter; + +class ExposureBiasInterpreter : public Interpreter { + public: + ExposureBiasInterpreter () {} + virtual std::string toString (Tag* t) { + sprintf (buffer, "%+0.2f", t->toDouble()); + return buffer; + } +}; +ExposureBiasInterpreter exposureBiasInterpreter; + +class ShutterSpeedInterpreter : public Interpreter { + public: + ShutterSpeedInterpreter () {} + virtual std::string toString (Tag* t) { + double d = pow (2.0, -t->toDouble()); + if (d > 0.0 && d < 0.9) + sprintf (buffer, "1/%0.0f", 1.0 / d); + else + sprintf (buffer, "%0.1f", d); + return buffer; + } +}; +ShutterSpeedInterpreter shutterSpeedInterpreter; + +class ExposureTimeInterpreter : public Interpreter { + public: + ExposureTimeInterpreter () {} + virtual std::string toString (Tag* t) { + double d = t->toDouble(); + if (d > 0.0 && d < 0.9) + sprintf (buffer, "1/%0.0f", 1.0 / d); + else + sprintf (buffer, "%0.1f", d); + return buffer; + } +}; +ExposureTimeInterpreter exposureTimeInterpreter; + +class FocalLengthInterpreter : public Interpreter { + public: + FocalLengthInterpreter () {} + virtual std::string toString (Tag* t) { + sprintf (buffer, "%0.1f", t->toDouble()); + return buffer; + } +}; +FocalLengthInterpreter focalLengthInterpreter; + +class UserCommentInterpreter : public Interpreter { + public: + UserCommentInterpreter () {} + virtual std::string toString (Tag* t) { + if (!strncmp((char*)t->getValue(), "ASCII\0\0\0",8)) + strncpy (buffer, (char*)t->getValue()+8, t->getCount()-8); + else + buffer[0]=0; + return buffer; + } + virtual void fromString (Tag* t, const std::string& value) { + memcpy (buffer, "ASCII\0\0\0", 8); + strcpy (buffer+8, value.c_str()); + t->fromString (buffer, value.size() + 9); + } +}; +UserCommentInterpreter userCommentInterpreter; + +const TagAttrib exifAttribs[] = { + 0, 2, 0, 0, 0x0103, "Compression", &compressionInterpreter, + 0, 2, 0, 0, 0xA000, "FlashpixVersion", &stdInterpreter, + 0, 2, 0, 0, 0xA001, "ColorSpace", &colorSpaceInterpreter, + 0, 1, 0, 0, 0x9000, "ExifVersion", &stdInterpreter, + 0, 1, 0, 0, 0x9003, "DateTimeOriginal", &stdInterpreter, + 0, 1, 0, 0, 0x9004, "DateTimeDigitized", &stdInterpreter, + 0, 2, 0, 0, 0x9101, "ComponentsConfiguration", &stdInterpreter, + 0, 2, 0, 0, 0x9102, "CompressedBitsPerPixel", &stdInterpreter, + 0, 2, 0, 0, 0xA002, "PixelXDimension", &stdInterpreter, + 0, 2, 0, 0, 0xA003, "PixelYDimension", &stdInterpreter, + 0, 1, 0, 0, 0x927C, "MakerNote", &stdInterpreter, + 0, 1, 1, 0, 0x9286, "UserComment", &userCommentInterpreter, + 1, 0, 0, 0, 0xA004, "RelatedSoundFile", &stdInterpreter, + 0, 1, 0, 0, 0x9290, "SubSecTime", &stdInterpreter, + 0, 1, 0, 0, 0x9291, "SubSecTimeOriginal", &stdInterpreter, + 0, 1, 0, 0, 0x9292, "SubSecTimeDigitized", &stdInterpreter, + 0, 1, 0, 0, 0xA420, "ImageUniqueID", &stdInterpreter, + 0, 1, 0, 0, 0x829A, "ExposureTime", &exposureTimeInterpreter, + 0, 1, 0, 0, 0x829D, "FNumber", &fNumberInterpreter, + 0, 1, 0, 0, 0x8822, "ExposureProgram", &exposureProgramInterpreter, + 0, 1, 0, 0, 0x8824, "SpectralSensitivity", &stdInterpreter, + 0, 1, 0, 0, 0x8827, "ISOSpeedRatings", &stdInterpreter, + 0, 1, 0, 0, 0x8828, "OECF", &stdInterpreter, + 0, 1, 0, 0, 0x9201, "ShutterSpeedValue", &shutterSpeedInterpreter, + 0, 1, 0, 0, 0x9202, "ApertureValue", &apertureInterpreter, + 0, 1, 0, 0, 0x9203, "BrightnessValue", &stdInterpreter, + 0, 1, 0, 0, 0x9204, "ExposureBiasValue", &exposureBiasInterpreter, + 0, 1, 0, 0, 0x9205, "MaxApertureValue", &apertureInterpreter, + 0, 1, 0, 0, 0x9206, "SubjectDistance", &stdInterpreter, + 0, 1, 0, 0, 0x9207, "MeteringMode", &meteringModeInterpreter, + 0, 1, 0, 0, 0x9208, "LightSource", &lightSourceInterpreter, + 0, 1, 0, 0, 0x9209, "Flash", &flashInterpreter, + 0, 1, 0, 0, 0x920A, "FocalLength", &focalLengthInterpreter, + 0, 1, 0, 0, 0x9214, "SubjectArea", &stdInterpreter, + 0, 0, 0, 0, 0x9216, "TIFFEPSStandardID", &stdInterpreter, + 0, 1, 0, 0, 0x9217, "SensingMethod", &stdInterpreter, + 0, 1, 0, 0, 0xA20B, "FlashEnergy", &stdInterpreter, + 0, 1, 0, 0, 0xA20C, "SpatialFrequencyResponse", &stdInterpreter, + 0, 1, 0, 0, 0xA20E, "FocalPlaneXResolution", &stdInterpreter, + 0, 1, 0, 0, 0xA20F, "FocalPlaneYResolution", &stdInterpreter, + 0, 1, 0, 0, 0xA210, "FocalPlaneResolutionUnit", &stdInterpreter, + 0, 1, 0, 0, 0xA214, "SubjectLocation", &stdInterpreter, + 0, 1, 0, 0, 0xA215, "ExposureIndex", &stdInterpreter, + 0, 1, 0, 0, 0xA217, "SensingMethod", &stdInterpreter, + 0, 1, 0, 0, 0xA300, "FileSource", &stdInterpreter, + 0, 1, 0, 0, 0xA301, "SceneType", &stdInterpreter, + 0, 0, 0, 0, 0xA302, "CFAPattern", &stdInterpreter, + 0, 1, 0, 0, 0xA401, "CustomRendered", &stdInterpreter, + 0, 1, 0, 0, 0xA402, "ExposureMode", &exposureModeInterpreter, + 0, 1, 0, 0, 0xA403, "WhiteBalance", &whiteBalanceInterpreter, + 0, 1, 0, 0, 0xA404, "DigitalZoomRatio", &stdInterpreter, + 0, 1, 0, 0, 0xA405, "FocalLengthIn35mmFilm", &stdInterpreter, + 0, 1, 0, 0, 0xA406, "SceneCaptureType", &sceneCaptureInterpreter, + 0, 1, 0, 0, 0xA407, "GainControl", &gainControlInterpreter, + 0, 1, 0, 0, 0xA408, "Contrast", &contrastInterpreter, + 0, 1, 0, 0, 0xA409, "Saturation", &saturationInterpreter, + 0, 1, 0, 0, 0xA40A, "Sharpness", &sharpnessInterpreter, + 0, 1, 0, 0, 0xA40B, "DeviceSettingDescription", &stdInterpreter, + 0, 1, 0, 0, 0xA40C, "SubjectDistanceRange", &stdInterpreter, + 0, 0, 0, 0, 0x828d, "CFAPattern", &stdInterpreter, + 0, 0, 0, 0, 0x828e, "CFARepeatPatternDim", &stdInterpreter, +-1, 0, 0, 0, 0, "", NULL }; +// 0, 0xA005, LONG, 1, "Interoperability tag", "Interoperability IFD Pointer"}; + +const TagAttrib gpsAttribs[] = { + 0, 1, 0, 0, 0x0000, "GPSVersionID", &stdInterpreter, + 0, 1, 0, 0, 0x0001, "GPSLatitudeRef", &stdInterpreter, + 0, 1, 0, 0, 0x0002, "GPSLatitude", &stdInterpreter, + 0, 1, 0, 0, 0x0003, "GPSLongitudeRef", &stdInterpreter, + 0, 1, 0, 0, 0x0004, "GPSLongitude", &stdInterpreter, + 0, 1, 0, 0, 0x0005, "GPSAltitudeRef", &stdInterpreter, + 0, 1, 0, 0, 0x0006, "GPSAltitude", &stdInterpreter, + 0, 1, 0, 0, 0x0007, "GPSTimeStamp", &stdInterpreter, + 0, 1, 0, 0, 0x0008, "GPSSatelites", &stdInterpreter, + 0, 1, 0, 0, 0x0009, "GPSStatus", &stdInterpreter, + 0, 1, 0, 0, 0x000a, "GPSMeasureMode", &stdInterpreter, + 0, 1, 0, 0, 0x000b, "GPSDOP", &stdInterpreter, + 0, 1, 0, 0, 0x000c, "GPSSpeedRef", &stdInterpreter, + 0, 1, 0, 0, 0x000d, "GPSSpeed", &stdInterpreter, + 0, 1, 0, 0, 0x000e, "GPSTrackRef", &stdInterpreter, + 0, 1, 0, 0, 0x000f, "GPSTrack", &stdInterpreter, + 0, 1, 0, 0, 0x0010, "GPSImgDirectionRef", &stdInterpreter, + 0, 1, 0, 0, 0x0011, "GPSImgDirection", &stdInterpreter, + 0, 1, 0, 0, 0x0012, "GPSMapDatum", &stdInterpreter, + 0, 1, 0, 0, 0x0013, "GPSDestLatitudeRef", &stdInterpreter, + 0, 1, 0, 0, 0x0014, "GPSDestLatitude", &stdInterpreter, + 0, 1, 0, 0, 0x0015, "GPSDestLongitudeRef", &stdInterpreter, + 0, 1, 0, 0, 0x0016, "GPSDestLongitude", &stdInterpreter, + 0, 1, 0, 0, 0x0017, "GPSDestBearingRef", &stdInterpreter, + 0, 1, 0, 0, 0x0018, "GPSDestBearing", &stdInterpreter, + 0, 1, 0, 0, 0x0019, "GPSDestDistanceRef", &stdInterpreter, + 0, 1, 0, 0, 0x001a, "GPSDestDistance", &stdInterpreter, + 0, 1, 0, 0, 0x001b, "GPSProcessingMethod", &stdInterpreter, + 0, 1, 0, 0, 0x001c, "GPSAreaInformation", &stdInterpreter, + 0, 1, 0, 0, 0x001d, "GPSDateStamp", &stdInterpreter, + 0, 1, 0, 0, 0x001e, "GPSDifferential", &stdInterpreter, + -1, 0, 0, 0, 0, "", NULL }; + + + +const TagAttrib iopAttribs[] = { + 0, 1, 0, 0, 0x0001, "InteroperabilityIndex", &stdInterpreter, + 0, 1, 0, 0, 0x0002, "InteroperabilityVersion", &stdInterpreter, +-1, 0, 0, 0, 0, "", NULL }; + + const TagAttrib ifdAttribs[] = { + 0, 2, 0, 0, 0x0017, "PanaISO", &stdInterpreter, + 0, 2, 0, 0, 0x0100, "ImageWidth", &stdInterpreter, + 0, 2, 0, 0, 0x0101, "ImageHeight", &stdInterpreter, + 0, 2, 0, 0, 0x0102, "BitsPerSample", &stdInterpreter, + 0, 2, 0, 0, 0x0103, "Compression", &compressionInterpreter, + 0, 2, 0, 0, 0x0106, "PhotometricInterpretation", &photometricInterpreter, + 0, 2, 0, 0, 0x0112, "Orientation", &stdInterpreter, + 0, 2, 0, 0, 0x0115, "SamplesPerPixel", &stdInterpreter, + 0, 2, 0, 0, 0x011C, "PlanarConfiguration", &planarConfigInterpreter, + 0, 2, 0, 0, 0x0212, "YCbCrSubSampling", &stdInterpreter, + 0, 2, 0, 0, 0x0213, "YCbCrPositioning", &stdInterpreter, + 0, 2, 0, 0, 0x011A, "XResolution", &stdInterpreter, + 0, 2, 0, 0, 0x011B, "YResolution", &stdInterpreter, + 0, 2, 0, 0, 0x0128, "ResolutionUnit", &stdInterpreter, + 1, 0, 0, 0, 0x0111, "StripOffsets", &stdInterpreter, + 1, 0, 0, 0, 0x0116, "RowsPerStrip", &stdInterpreter, + 1, 0, 0, 0, 0x0117, "StripByteCounts", &stdInterpreter, + 0, 2, 0, 0, 0x0201, "JPEGInterchangeFormat", &stdInterpreter, + 0, 2, 0, 0, 0x0202, "JPEGInterchangeFormatLength", &stdInterpreter, + 0, 2, 0, 0, 0x012D, "TransferFunction", &stdInterpreter, + 0, 2, 0, 0, 0x013E, "WhitePoint", &stdInterpreter, + 0, 2, 0, 0, 0x013F, "PriomaryChromaticities", &stdInterpreter, + 0, 2, 0, 0, 0x0211, "YCbCrCoefficients", &stdInterpreter, + 0, 2, 0, 0, 0x0214, "ReferenceBlackWhite", &stdInterpreter, + 0, 1, 0, 0, 0x0132, "DateTime", &stdInterpreter, + 0, 1, 1, 0, 0x010E, "ImageDescription", &stdInterpreter, + 0, 1, 0, 0, 0x010F, "Make", &stdInterpreter, + 0, 1, 0, 0, 0x0110, "Model", &stdInterpreter, + 0, 2, 0, 0, 0x0131, "Software", &stdInterpreter, + 0, 1, 1, 0, 0x013B, "Artist", &stdInterpreter, + 0, 1, 1, 0, 0x8298, "Copyright", &stdInterpreter, + 0, 1, 0, exifAttribs, 0x8769, "Exif", &stdInterpreter, + 0, 2, 0, 0, 0x8773, "ICCProfile", &stdInterpreter, + 0, 2, 0, 0, 0x83BB, "IPTCData", &stdInterpreter, + 0, 1, 0, gpsAttribs, 0x8825, "GPSInfo", &stdInterpreter, + 0, 1, 0, 0, 0x9003, "DateTimeOriginal", &stdInterpreter, + 0, 1, 0, 0, 0x9004, "DateTimeDigitized", &stdInterpreter, + 0, 1, 0, iopAttribs, 0xA005, "Interoperability", &stdInterpreter, + 1, 2, 0, ifdAttribs, 0x014A, "SubIFD", &stdInterpreter, + 0, 0, 0, 0, 0xC4A5, "PrintIMInformation", &stdInterpreter, + 0, 2, 0, 0, 0x00fe, "NewSubFileType", &stdInterpreter, + -1, 0, 0, 0, 0, "", NULL}; + +}; + +/*#include +#include +#include +#include +#include +#include */ + +#endif diff --git a/rtgui/CMakeCache.txt b/rtgui/CMakeCache.txt new file mode 100755 index 000000000..401913732 --- /dev/null +++ b/rtgui/CMakeCache.txt @@ -0,0 +1,503 @@ +# This is the CMakeCache file. +# For build in directory: /home/hgabor/RawTherapee/2.5/gui88/rtgui +# It was generated by CMake: /usr/bin/cmake +# You can edit this file to change values found and used by cmake. +# If you do not want to change any of the values, simply exit the editor. +# If you do want to change a value, simply edit, save, and exit the editor. +# The syntax for the file is as follows: +# KEY:TYPE=VALUE +# KEY is the name of a variable in the cache. +# TYPE is a hint to GUI's for the type of VALUE, DO NOT EDIT TYPE!. +# VALUE is the current value for the KEY. + +######################## +# EXTERNAL cache entries +######################## + +//Path to a program. +CMAKE_AR:FILEPATH=/usr/bin/ar + +//For backwards compatibility, what version of CMake commands and +// syntax should this version of CMake try to support. +CMAKE_BACKWARDS_COMPATIBILITY:STRING=2.4 + +//Choose the type of build, options are: None(CMAKE_CXX_FLAGS or +// CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel. +CMAKE_BUILD_TYPE:STRING= + +//Enable/Disable color output during build. +CMAKE_COLOR_MAKEFILE:BOOL=ON + +//CXX compiler. +CMAKE_CXX_COMPILER:FILEPATH=/usr/bin/c++ + +//Flags used by the compiler during all build types. +CMAKE_CXX_FLAGS:STRING= + +//Flags used by the compiler during debug builds. +CMAKE_CXX_FLAGS_DEBUG:STRING=-g + +//Flags used by the compiler during release minsize builds. +CMAKE_CXX_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG + +//Flags used by the compiler during release builds (/MD /Ob1 /Oi +// /Ot /Oy /Gs will produce slightly less optimized but smaller +// files). +CMAKE_CXX_FLAGS_RELEASE:STRING=-O3 -DNDEBUG + +//Flags used by the compiler during Release with Debug Info builds. +CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=-O2 -g + +//C compiler. +CMAKE_C_COMPILER:FILEPATH=/usr/bin/gcc + +//Flags used by the compiler during all build types. +CMAKE_C_FLAGS:STRING= + +//Flags used by the compiler during debug builds. +CMAKE_C_FLAGS_DEBUG:STRING=-g + +//Flags used by the compiler during release minsize builds. +CMAKE_C_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG + +//Flags used by the compiler during release builds (/MD /Ob1 /Oi +// /Ot /Oy /Gs will produce slightly less optimized but smaller +// files). +CMAKE_C_FLAGS_RELEASE:STRING=-O3 -DNDEBUG + +//Flags used by the compiler during Release with Debug Info builds. +CMAKE_C_FLAGS_RELWITHDEBINFO:STRING=-O2 -g + +//Flags used by the linker. +CMAKE_EXE_LINKER_FLAGS:STRING= + +//Flags used by the linker during debug builds. +CMAKE_EXE_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during release minsize builds. +CMAKE_EXE_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during release builds. +CMAKE_EXE_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during Release with Debug Info builds. +CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//Install path prefix, prepended onto install directories. +CMAKE_INSTALL_PREFIX:PATH=/usr/local + +//Path to a program. +CMAKE_LINKER:FILEPATH=/usr/bin/ld + +//Path to a program. +CMAKE_MAKE_PROGRAM:FILEPATH=/usr/bin/make + +//Flags used by the linker during the creation of modules. +CMAKE_MODULE_LINKER_FLAGS:STRING= + +//Flags used by the linker during debug builds. +CMAKE_MODULE_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during release minsize builds. +CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during release builds. +CMAKE_MODULE_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during Release with Debug Info builds. +CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//Path to a program. +CMAKE_NM:FILEPATH=/usr/bin/nm + +//Path to a program. +CMAKE_OBJCOPY:FILEPATH=/usr/bin/objcopy + +//Path to a program. +CMAKE_OBJDUMP:FILEPATH=/usr/bin/objdump + +//Path to a program. +CMAKE_RANLIB:FILEPATH=/usr/bin/ranlib + +//Flags used by the linker during the creation of dll's. +CMAKE_SHARED_LINKER_FLAGS:STRING= + +//Flags used by the linker during debug builds. +CMAKE_SHARED_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during release minsize builds. +CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during release builds. +CMAKE_SHARED_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during Release with Debug Info builds. +CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//If set, runtime paths are not added when using shared libraries. +CMAKE_SKIP_RPATH:BOOL=NO + +//Path to a program. +CMAKE_STRIP:FILEPATH=/usr/bin/strip + +//If true, cmake will use relative paths in makefiles and projects. +CMAKE_USE_RELATIVE_PATHS:BOOL=OFF + +//If this value is on, makefiles will be generated without the +// .SILENT directive, and all commands will be echoed to the console +// during the make. This is useful for debugging only. With Visual +// Studio IDE projects all commands are done without /nologo. +CMAKE_VERBOSE_MAKEFILE:BOOL=FALSE + +//Single output directory for building all executables. +EXECUTABLE_OUTPUT_PATH:PATH= + +//Single output directory for building all libraries. +LIBRARY_OUTPUT_PATH:PATH= + +//pkg-config executable +PKG_CONFIG_EXECUTABLE:FILEPATH=/usr/bin/pkg-config + +//Value Computed by CMake +Project_BINARY_DIR:STATIC=/home/hgabor/RawTherapee/2.5/gui88/rtgui + +//Value Computed by CMake +Project_SOURCE_DIR:STATIC=/home/hgabor/RawTherapee/2.5/gui88/rtgui + + +######################## +# INTERNAL cache entries +######################## + +//Advanced flag for variable: CMAKE_AR +CMAKE_AR-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_BUILD_TOOL +CMAKE_BUILD_TOOL-ADVANCED:INTERNAL=1 +//What is the target build tool cmake is generating for. +CMAKE_BUILD_TOOL:INTERNAL=/usr/bin/make +//This is the directory where this CMakeCahe.txt was created +CMAKE_CACHEFILE_DIR:INTERNAL=/home/hgabor/RawTherapee/2.5/gui88/rtgui +//Major version of cmake used to create the current loaded cache +CMAKE_CACHE_MAJOR_VERSION:INTERNAL=2 +//Minor version of cmake used to create the current loaded cache +CMAKE_CACHE_MINOR_VERSION:INTERNAL=6 +//Major version of cmake used to create the current loaded cache +CMAKE_CACHE_RELEASE_VERSION:INTERNAL=patch 0 +//Advanced flag for variable: CMAKE_COLOR_MAKEFILE +CMAKE_COLOR_MAKEFILE-ADVANCED:INTERNAL=1 +//Path to CMake executable. +CMAKE_COMMAND:INTERNAL=/usr/bin/cmake +//Path to cpack program executable. +CMAKE_CPACK_COMMAND:INTERNAL=/usr/bin/cpack +//Path to ctest program executable. +CMAKE_CTEST_COMMAND:INTERNAL=/usr/bin/ctest +//Advanced flag for variable: CMAKE_CXX_COMPILER +CMAKE_CXX_COMPILER-ADVANCED:INTERNAL=1 +CMAKE_CXX_COMPILER_WORKS:INTERNAL=1 +//Advanced flag for variable: CMAKE_CXX_FLAGS +CMAKE_CXX_FLAGS-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_CXX_FLAGS_DEBUG +CMAKE_CXX_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_CXX_FLAGS_MINSIZEREL +CMAKE_CXX_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_CXX_FLAGS_RELEASE +CMAKE_CXX_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_CXX_FLAGS_RELWITHDEBINFO +CMAKE_CXX_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_C_COMPILER +CMAKE_C_COMPILER-ADVANCED:INTERNAL=1 +CMAKE_C_COMPILER_WORKS:INTERNAL=1 +//Advanced flag for variable: CMAKE_C_FLAGS +CMAKE_C_FLAGS-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_C_FLAGS_DEBUG +CMAKE_C_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_C_FLAGS_MINSIZEREL +CMAKE_C_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_C_FLAGS_RELEASE +CMAKE_C_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_C_FLAGS_RELWITHDEBINFO +CMAKE_C_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//Result of TRY_COMPILE +CMAKE_DETERMINE_CXX_ABI_COMPILED:INTERNAL=TRUE +//Result of TRY_COMPILE +CMAKE_DETERMINE_C_ABI_COMPILED:INTERNAL=TRUE +//Path to cache edit program executable. +CMAKE_EDIT_COMMAND:INTERNAL=/usr/bin/ccmake +//Executable file format +CMAKE_EXECUTABLE_FORMAT:INTERNAL=ELF +//Advanced flag for variable: CMAKE_EXE_LINKER_FLAGS +CMAKE_EXE_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_EXE_LINKER_FLAGS_DEBUG +CMAKE_EXE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_EXE_LINKER_FLAGS_MINSIZEREL +CMAKE_EXE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_EXE_LINKER_FLAGS_RELEASE +CMAKE_EXE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//Name of generator. +CMAKE_GENERATOR:INTERNAL=Unix Makefiles +//Start directory with the top level CMakeLists.txt file for this +// project +CMAKE_HOME_DIRECTORY:INTERNAL=/home/hgabor/RawTherapee/2.5/gui88/rtgui +//Install .so files without execute permission. +CMAKE_INSTALL_SO_NO_EXE:INTERNAL=1 +//Advanced flag for variable: CMAKE_LINKER +CMAKE_LINKER-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_MAKE_PROGRAM +CMAKE_MAKE_PROGRAM-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_MODULE_LINKER_FLAGS +CMAKE_MODULE_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_MODULE_LINKER_FLAGS_DEBUG +CMAKE_MODULE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL +CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_MODULE_LINKER_FLAGS_RELEASE +CMAKE_MODULE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_NM +CMAKE_NM-ADVANCED:INTERNAL=1 +//number of local generators +CMAKE_NUMBER_OF_LOCAL_GENERATORS:INTERNAL=1 +//Advanced flag for variable: CMAKE_OBJCOPY +CMAKE_OBJCOPY-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_OBJDUMP +CMAKE_OBJDUMP-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_RANLIB +CMAKE_RANLIB-ADVANCED:INTERNAL=1 +//Path to CMake installation. +CMAKE_ROOT:INTERNAL=/usr/share/cmake-2.6 +//Advanced flag for variable: CMAKE_SHARED_LINKER_FLAGS +CMAKE_SHARED_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_SHARED_LINKER_FLAGS_DEBUG +CMAKE_SHARED_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL +CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_SHARED_LINKER_FLAGS_RELEASE +CMAKE_SHARED_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_SKIP_RPATH +CMAKE_SKIP_RPATH-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_STRIP +CMAKE_STRIP-ADVANCED:INTERNAL=1 +//uname command +CMAKE_UNAME:INTERNAL=/bin/uname +//Advanced flag for variable: CMAKE_USE_RELATIVE_PATHS +CMAKE_USE_RELATIVE_PATHS-ADVANCED:INTERNAL=1 +//Advanced flag for variable: CMAKE_VERBOSE_MAKEFILE +CMAKE_VERBOSE_MAKEFILE-ADVANCED:INTERNAL=1 +GIOMM_CFLAGS:INTERNAL=-I/usr/include/giomm-2.4;-I/usr/lib/giomm-2.4/include;-I/usr/include/glibmm-2.4;-I/usr/lib/glibmm-2.4/include;-I/usr/include/glib-2.0;-I/usr/lib/glib-2.0/include;-I/usr/include/sigc++-2.0;-I/usr/lib/sigc++-2.0/include +GIOMM_CFLAGS_I:INTERNAL= +GIOMM_CFLAGS_OTHER:INTERNAL= +GIOMM_FOUND:INTERNAL=1 +GIOMM_INCLUDEDIR:INTERNAL=/usr/include +GIOMM_INCLUDE_DIRS:INTERNAL=/usr/include/giomm-2.4;/usr/lib/giomm-2.4/include;/usr/include/glibmm-2.4;/usr/lib/glibmm-2.4/include;/usr/include/glib-2.0;/usr/lib/glib-2.0/include;/usr/include/sigc++-2.0;/usr/lib/sigc++-2.0/include +GIOMM_LDFLAGS:INTERNAL=-lgiomm-2.4;-lgio-2.0;-lglibmm-2.4;-lgmodule-2.0;-lgobject-2.0;-lsigc-2.0;-lglib-2.0 +GIOMM_LDFLAGS_OTHER:INTERNAL= +GIOMM_LIBDIR:INTERNAL=/usr/lib +GIOMM_LIBRARIES:INTERNAL=giomm-2.4;gio-2.0;glibmm-2.4;gmodule-2.0;gobject-2.0;sigc-2.0;glib-2.0 +GIOMM_LIBRARY_DIRS:INTERNAL= +GIOMM_LIBS:INTERNAL= +GIOMM_LIBS_L:INTERNAL= +GIOMM_LIBS_OTHER:INTERNAL= +GIOMM_LIBS_PATHS:INTERNAL= +GIOMM_PREFIX:INTERNAL=/usr +GIOMM_STATIC_CFLAGS:INTERNAL=-I/usr/include/giomm-2.4;-I/usr/lib/giomm-2.4/include;-I/usr/include/glibmm-2.4;-I/usr/lib/glibmm-2.4/include;-I/usr/include/glib-2.0;-I/usr/lib/glib-2.0/include;-I/usr/include/sigc++-2.0;-I/usr/lib/sigc++-2.0/include +GIOMM_STATIC_CFLAGS_I:INTERNAL= +GIOMM_STATIC_CFLAGS_OTHER:INTERNAL= +GIOMM_STATIC_INCLUDE_DIRS:INTERNAL=/usr/include/giomm-2.4;/usr/lib/giomm-2.4/include;/usr/include/glibmm-2.4;/usr/lib/glibmm-2.4/include;/usr/include/glib-2.0;/usr/lib/glib-2.0/include;/usr/include/sigc++-2.0;/usr/lib/sigc++-2.0/include +GIOMM_STATIC_LDFLAGS:INTERNAL=-lgiomm-2.4;-lgio-2.0;-lglibmm-2.4;-lgmodule-2.0;-ldl;-lgobject-2.0;-lsigc-2.0;-lglib-2.0 +GIOMM_STATIC_LDFLAGS_OTHER:INTERNAL= +GIOMM_STATIC_LIBDIR:INTERNAL= +GIOMM_STATIC_LIBRARIES:INTERNAL=giomm-2.4;gio-2.0;glibmm-2.4;gmodule-2.0;dl;gobject-2.0;sigc-2.0;glib-2.0 +GIOMM_STATIC_LIBRARY_DIRS:INTERNAL= +GIOMM_STATIC_LIBS:INTERNAL= +GIOMM_STATIC_LIBS_L:INTERNAL= +GIOMM_STATIC_LIBS_OTHER:INTERNAL= +GIOMM_STATIC_LIBS_PATHS:INTERNAL= +GIOMM_VERSION:INTERNAL=2.18.1 +GIOMM_giomm-2.4_INCLUDEDIR:INTERNAL= +GIOMM_giomm-2.4_LIBDIR:INTERNAL= +GIOMM_giomm-2.4_PREFIX:INTERNAL= +GIOMM_giomm-2.4_VERSION:INTERNAL= +GIO_CFLAGS:INTERNAL=-I/usr/include/glib-2.0;-I/usr/lib/glib-2.0/include +GIO_CFLAGS_I:INTERNAL= +GIO_CFLAGS_OTHER:INTERNAL= +GIO_FOUND:INTERNAL=1 +GIO_INCLUDEDIR:INTERNAL=/usr/include +GIO_INCLUDE_DIRS:INTERNAL=/usr/include/glib-2.0;/usr/lib/glib-2.0/include +GIO_LDFLAGS:INTERNAL=-lgio-2.0;-lgobject-2.0;-lgmodule-2.0;-lglib-2.0 +GIO_LDFLAGS_OTHER:INTERNAL= +GIO_LIBDIR:INTERNAL=/usr/lib +GIO_LIBRARIES:INTERNAL=gio-2.0;gobject-2.0;gmodule-2.0;glib-2.0 +GIO_LIBRARY_DIRS:INTERNAL= +GIO_LIBS:INTERNAL= +GIO_LIBS_L:INTERNAL= +GIO_LIBS_OTHER:INTERNAL= +GIO_LIBS_PATHS:INTERNAL= +GIO_PREFIX:INTERNAL=/usr +GIO_STATIC_CFLAGS:INTERNAL=-I/usr/include/glib-2.0;-I/usr/lib/glib-2.0/include +GIO_STATIC_CFLAGS_I:INTERNAL= +GIO_STATIC_CFLAGS_OTHER:INTERNAL= +GIO_STATIC_INCLUDE_DIRS:INTERNAL=/usr/include/glib-2.0;/usr/lib/glib-2.0/include +GIO_STATIC_LDFLAGS:INTERNAL=-lgio-2.0;-lgobject-2.0;-lgmodule-2.0;-ldl;-lglib-2.0 +GIO_STATIC_LDFLAGS_OTHER:INTERNAL= +GIO_STATIC_LIBDIR:INTERNAL= +GIO_STATIC_LIBRARIES:INTERNAL=gio-2.0;gobject-2.0;gmodule-2.0;dl;glib-2.0 +GIO_STATIC_LIBRARY_DIRS:INTERNAL= +GIO_STATIC_LIBS:INTERNAL= +GIO_STATIC_LIBS_L:INTERNAL= +GIO_STATIC_LIBS_OTHER:INTERNAL= +GIO_STATIC_LIBS_PATHS:INTERNAL= +GIO_VERSION:INTERNAL=2.18.2 +GIO_gio-2.0_INCLUDEDIR:INTERNAL= +GIO_gio-2.0_LIBDIR:INTERNAL= +GIO_gio-2.0_PREFIX:INTERNAL= +GIO_gio-2.0_VERSION:INTERNAL= +GLIB2_CFLAGS:INTERNAL=-I/usr/include/glib-2.0;-I/usr/lib/glib-2.0/include +GLIB2_CFLAGS_I:INTERNAL= +GLIB2_CFLAGS_OTHER:INTERNAL= +GLIB2_FOUND:INTERNAL=1 +GLIB2_INCLUDEDIR:INTERNAL=/usr/include +GLIB2_INCLUDE_DIRS:INTERNAL=/usr/include/glib-2.0;/usr/lib/glib-2.0/include +GLIB2_LDFLAGS:INTERNAL=-lglib-2.0 +GLIB2_LDFLAGS_OTHER:INTERNAL= +GLIB2_LIBDIR:INTERNAL=/usr/lib +GLIB2_LIBRARIES:INTERNAL=glib-2.0 +GLIB2_LIBRARY_DIRS:INTERNAL= +GLIB2_LIBS:INTERNAL= +GLIB2_LIBS_L:INTERNAL= +GLIB2_LIBS_OTHER:INTERNAL= +GLIB2_LIBS_PATHS:INTERNAL= +GLIB2_PREFIX:INTERNAL=/usr +GLIB2_STATIC_CFLAGS:INTERNAL=-I/usr/include/glib-2.0;-I/usr/lib/glib-2.0/include +GLIB2_STATIC_CFLAGS_I:INTERNAL= +GLIB2_STATIC_CFLAGS_OTHER:INTERNAL= +GLIB2_STATIC_INCLUDE_DIRS:INTERNAL=/usr/include/glib-2.0;/usr/lib/glib-2.0/include +GLIB2_STATIC_LDFLAGS:INTERNAL=-lglib-2.0 +GLIB2_STATIC_LDFLAGS_OTHER:INTERNAL= +GLIB2_STATIC_LIBDIR:INTERNAL= +GLIB2_STATIC_LIBRARIES:INTERNAL=glib-2.0 +GLIB2_STATIC_LIBRARY_DIRS:INTERNAL= +GLIB2_STATIC_LIBS:INTERNAL= +GLIB2_STATIC_LIBS_L:INTERNAL= +GLIB2_STATIC_LIBS_OTHER:INTERNAL= +GLIB2_STATIC_LIBS_PATHS:INTERNAL= +GLIB2_VERSION:INTERNAL=2.18.2 +GLIB2_glib-2.0_INCLUDEDIR:INTERNAL= +GLIB2_glib-2.0_LIBDIR:INTERNAL= +GLIB2_glib-2.0_PREFIX:INTERNAL= +GLIB2_glib-2.0_VERSION:INTERNAL= +GLIBMM_CFLAGS:INTERNAL=-I/usr/include/glibmm-2.4;-I/usr/lib/glibmm-2.4/include;-I/usr/include/sigc++-2.0;-I/usr/lib/sigc++-2.0/include;-I/usr/include/glib-2.0;-I/usr/lib/glib-2.0/include +GLIBMM_CFLAGS_I:INTERNAL= +GLIBMM_CFLAGS_OTHER:INTERNAL= +GLIBMM_FOUND:INTERNAL=1 +GLIBMM_INCLUDEDIR:INTERNAL=/usr/include +GLIBMM_INCLUDE_DIRS:INTERNAL=/usr/include/glibmm-2.4;/usr/lib/glibmm-2.4/include;/usr/include/sigc++-2.0;/usr/lib/sigc++-2.0/include;/usr/include/glib-2.0;/usr/lib/glib-2.0/include +GLIBMM_LDFLAGS:INTERNAL=-lglibmm-2.4;-lgobject-2.0;-lsigc-2.0;-lglib-2.0 +GLIBMM_LDFLAGS_OTHER:INTERNAL= +GLIBMM_LIBDIR:INTERNAL=/usr/lib +GLIBMM_LIBRARIES:INTERNAL=glibmm-2.4;gobject-2.0;sigc-2.0;glib-2.0 +GLIBMM_LIBRARY_DIRS:INTERNAL= +GLIBMM_LIBS:INTERNAL= +GLIBMM_LIBS_L:INTERNAL= +GLIBMM_LIBS_OTHER:INTERNAL= +GLIBMM_LIBS_PATHS:INTERNAL= +GLIBMM_PREFIX:INTERNAL=/usr +GLIBMM_STATIC_CFLAGS:INTERNAL=-I/usr/include/glibmm-2.4;-I/usr/lib/glibmm-2.4/include;-I/usr/include/sigc++-2.0;-I/usr/lib/sigc++-2.0/include;-I/usr/include/glib-2.0;-I/usr/lib/glib-2.0/include +GLIBMM_STATIC_CFLAGS_I:INTERNAL= +GLIBMM_STATIC_CFLAGS_OTHER:INTERNAL= +GLIBMM_STATIC_INCLUDE_DIRS:INTERNAL=/usr/include/glibmm-2.4;/usr/lib/glibmm-2.4/include;/usr/include/sigc++-2.0;/usr/lib/sigc++-2.0/include;/usr/include/glib-2.0;/usr/lib/glib-2.0/include +GLIBMM_STATIC_LDFLAGS:INTERNAL=-lglibmm-2.4;-lgobject-2.0;-lsigc-2.0;-lglib-2.0 +GLIBMM_STATIC_LDFLAGS_OTHER:INTERNAL= +GLIBMM_STATIC_LIBDIR:INTERNAL= +GLIBMM_STATIC_LIBRARIES:INTERNAL=glibmm-2.4;gobject-2.0;sigc-2.0;glib-2.0 +GLIBMM_STATIC_LIBRARY_DIRS:INTERNAL= +GLIBMM_STATIC_LIBS:INTERNAL= +GLIBMM_STATIC_LIBS_L:INTERNAL= +GLIBMM_STATIC_LIBS_OTHER:INTERNAL= +GLIBMM_STATIC_LIBS_PATHS:INTERNAL= +GLIBMM_VERSION:INTERNAL=2.18.1 +GLIBMM_glibmm-2.4_INCLUDEDIR:INTERNAL= +GLIBMM_glibmm-2.4_LIBDIR:INTERNAL= +GLIBMM_glibmm-2.4_PREFIX:INTERNAL= +GLIBMM_glibmm-2.4_VERSION:INTERNAL= +GTKMM_CFLAGS:INTERNAL=-I/usr/include/gtkmm-2.4;-I/usr/lib/gtkmm-2.4/include;-I/usr/include/glibmm-2.4;-I/usr/lib/glibmm-2.4/include;-I/usr/include/giomm-2.4;-I/usr/lib/giomm-2.4/include;-I/usr/include/gdkmm-2.4;-I/usr/lib/gdkmm-2.4/include;-I/usr/include/pangomm-1.4;-I/usr/include/atkmm-1.6;-I/usr/include/gtk-2.0;-I/usr/include/sigc++-2.0;-I/usr/lib/sigc++-2.0/include;-I/usr/include/glib-2.0;-I/usr/lib/glib-2.0/include;-I/usr/lib/gtk-2.0/include;-I/usr/include/cairomm-1.0;-I/usr/include/pango-1.0;-I/usr/include/cairo;-I/usr/include/pixman-1;-I/usr/include/freetype2;-I/usr/include/libpng12;-I/usr/include/atk-1.0 +GTKMM_CFLAGS_I:INTERNAL= +GTKMM_CFLAGS_OTHER:INTERNAL= +GTKMM_FOUND:INTERNAL=1 +GTKMM_INCLUDEDIR:INTERNAL=/usr/include +GTKMM_INCLUDE_DIRS:INTERNAL=/usr/include/gtkmm-2.4;/usr/lib/gtkmm-2.4/include;/usr/include/glibmm-2.4;/usr/lib/glibmm-2.4/include;/usr/include/giomm-2.4;/usr/lib/giomm-2.4/include;/usr/include/gdkmm-2.4;/usr/lib/gdkmm-2.4/include;/usr/include/pangomm-1.4;/usr/include/atkmm-1.6;/usr/include/gtk-2.0;/usr/include/sigc++-2.0;/usr/lib/sigc++-2.0/include;/usr/include/glib-2.0;/usr/lib/glib-2.0/include;/usr/lib/gtk-2.0/include;/usr/include/cairomm-1.0;/usr/include/pango-1.0;/usr/include/cairo;/usr/include/pixman-1;/usr/include/freetype2;/usr/include/libpng12;/usr/include/atk-1.0 +GTKMM_LDFLAGS:INTERNAL=-lgtkmm-2.4;-lgiomm-2.4;-lgdkmm-2.4;-latkmm-1.6;-lgtk-x11-2.0;-lpangomm-1.4;-lcairomm-1.0;-lglibmm-2.4;-lsigc-2.0;-lgdk-x11-2.0;-latk-1.0;-lpangoft2-1.0;-lgdk_pixbuf-2.0;-lm;-lpangocairo-1.0;-lgio-2.0;-lcairo;-lpango-1.0;-lfreetype;-lz;-lfontconfig;-lgobject-2.0;-lgmodule-2.0;-lglib-2.0 +GTKMM_LDFLAGS_OTHER:INTERNAL= +GTKMM_LIBDIR:INTERNAL=/usr/lib +GTKMM_LIBRARIES:INTERNAL=gtkmm-2.4;giomm-2.4;gdkmm-2.4;atkmm-1.6;gtk-x11-2.0;pangomm-1.4;cairomm-1.0;glibmm-2.4;sigc-2.0;gdk-x11-2.0;atk-1.0;pangoft2-1.0;gdk_pixbuf-2.0;m;pangocairo-1.0;gio-2.0;cairo;pango-1.0;freetype;z;fontconfig;gobject-2.0;gmodule-2.0;glib-2.0 +GTKMM_LIBRARY_DIRS:INTERNAL= +GTKMM_LIBS:INTERNAL= +GTKMM_LIBS_L:INTERNAL= +GTKMM_LIBS_OTHER:INTERNAL= +GTKMM_LIBS_PATHS:INTERNAL= +GTKMM_PREFIX:INTERNAL=/usr +GTKMM_STATIC_CFLAGS:INTERNAL=-I/usr/include/gtkmm-2.4;-I/usr/lib/gtkmm-2.4/include;-I/usr/include/glibmm-2.4;-I/usr/lib/glibmm-2.4/include;-I/usr/include/giomm-2.4;-I/usr/lib/giomm-2.4/include;-I/usr/include/gdkmm-2.4;-I/usr/lib/gdkmm-2.4/include;-I/usr/include/pangomm-1.4;-I/usr/include/atkmm-1.6;-I/usr/include/gtk-2.0;-I/usr/include/sigc++-2.0;-I/usr/lib/sigc++-2.0/include;-I/usr/include/glib-2.0;-I/usr/lib/glib-2.0/include;-I/usr/lib/gtk-2.0/include;-I/usr/include/cairomm-1.0;-I/usr/include/pango-1.0;-I/usr/include/cairo;-I/usr/include/pixman-1;-I/usr/include/freetype2;-I/usr/include/libpng12;-I/usr/include/atk-1.0 +GTKMM_STATIC_CFLAGS_I:INTERNAL= +GTKMM_STATIC_CFLAGS_OTHER:INTERNAL= +GTKMM_STATIC_INCLUDE_DIRS:INTERNAL=/usr/include/gtkmm-2.4;/usr/lib/gtkmm-2.4/include;/usr/include/glibmm-2.4;/usr/lib/glibmm-2.4/include;/usr/include/giomm-2.4;/usr/lib/giomm-2.4/include;/usr/include/gdkmm-2.4;/usr/lib/gdkmm-2.4/include;/usr/include/pangomm-1.4;/usr/include/atkmm-1.6;/usr/include/gtk-2.0;/usr/include/sigc++-2.0;/usr/lib/sigc++-2.0/include;/usr/include/glib-2.0;/usr/lib/glib-2.0/include;/usr/lib/gtk-2.0/include;/usr/include/cairomm-1.0;/usr/include/pango-1.0;/usr/include/cairo;/usr/include/pixman-1;/usr/include/freetype2;/usr/include/libpng12;/usr/include/atk-1.0 +GTKMM_STATIC_LDFLAGS:INTERNAL=-lgtkmm-2.4;-lgiomm-2.4;-lgdkmm-2.4;-latkmm-1.6;-lgtk-x11-2.0;-lpangomm-1.4;-lcairomm-1.0;-lglibmm-2.4;-lsigc-2.0;-lgdk-x11-2.0;-latk-1.0;-lpangoft2-1.0;-lXinerama;-lXi;-lXrandr;-lXcursor;-lXcomposite;-lXdamage;-lgdk_pixbuf-2.0;-ltiff;-ljpeg;-lpangocairo-1.0;-lgio-2.0;-lXext;-lXfixes;-lcairo;-lm;-lpixman-1;-lpng12;-lxcb-render-util;-lXrender;-lxcb-render;-lX11;-lpthread;-lxcb-xlib;-lxcb;-lXau;-lXdmcp;-lpango-1.0;-lfontconfig;-lexpat;-lfreetype;-lz;-lgobject-2.0;-lgmodule-2.0;-ldl;-lglib-2.0 +GTKMM_STATIC_LDFLAGS_OTHER:INTERNAL= +GTKMM_STATIC_LIBDIR:INTERNAL= +GTKMM_STATIC_LIBRARIES:INTERNAL=gtkmm-2.4;giomm-2.4;gdkmm-2.4;atkmm-1.6;gtk-x11-2.0;pangomm-1.4;cairomm-1.0;glibmm-2.4;sigc-2.0;gdk-x11-2.0;atk-1.0;pangoft2-1.0;Xinerama;Xi;Xrandr;Xcursor;Xcomposite;Xdamage;gdk_pixbuf-2.0;tiff;jpeg;pangocairo-1.0;gio-2.0;Xext;Xfixes;cairo;m;pixman-1;png12;xcb-render-util;Xrender;xcb-render;X11;pthread;xcb-xlib;xcb;Xau;Xdmcp;pango-1.0;fontconfig;expat;freetype;z;gobject-2.0;gmodule-2.0;dl;glib-2.0 +GTKMM_STATIC_LIBRARY_DIRS:INTERNAL= +GTKMM_STATIC_LIBS:INTERNAL= +GTKMM_STATIC_LIBS_L:INTERNAL= +GTKMM_STATIC_LIBS_OTHER:INTERNAL= +GTKMM_STATIC_LIBS_PATHS:INTERNAL= +GTKMM_VERSION:INTERNAL=2.14.1 +GTKMM_gtkmm-2.4_INCLUDEDIR:INTERNAL= +GTKMM_gtkmm-2.4_LIBDIR:INTERNAL= +GTKMM_gtkmm-2.4_PREFIX:INTERNAL= +GTKMM_gtkmm-2.4_VERSION:INTERNAL= +GTK_CFLAGS:INTERNAL=-I/usr/include/gtk-2.0;-I/usr/lib/gtk-2.0/include;-I/usr/include/atk-1.0;-I/usr/include/cairo;-I/usr/include/pango-1.0;-I/usr/include/glib-2.0;-I/usr/lib/glib-2.0/include;-I/usr/include/pixman-1;-I/usr/include/freetype2;-I/usr/include/libpng12 +GTK_CFLAGS_I:INTERNAL= +GTK_CFLAGS_OTHER:INTERNAL= +GTK_FOUND:INTERNAL=1 +GTK_INCLUDEDIR:INTERNAL=/usr/include +GTK_INCLUDE_DIRS:INTERNAL=/usr/include/gtk-2.0;/usr/lib/gtk-2.0/include;/usr/include/atk-1.0;/usr/include/cairo;/usr/include/pango-1.0;/usr/include/glib-2.0;/usr/lib/glib-2.0/include;/usr/include/pixman-1;/usr/include/freetype2;/usr/include/libpng12 +GTK_LDFLAGS:INTERNAL=-lgtk-x11-2.0;-lgdk-x11-2.0;-latk-1.0;-lpangoft2-1.0;-lgdk_pixbuf-2.0;-lm;-lpangocairo-1.0;-lgio-2.0;-lcairo;-lpango-1.0;-lfreetype;-lz;-lfontconfig;-lgobject-2.0;-lgmodule-2.0;-lglib-2.0 +GTK_LDFLAGS_OTHER:INTERNAL= +GTK_LIBDIR:INTERNAL=/usr/lib +GTK_LIBRARIES:INTERNAL=gtk-x11-2.0;gdk-x11-2.0;atk-1.0;pangoft2-1.0;gdk_pixbuf-2.0;m;pangocairo-1.0;gio-2.0;cairo;pango-1.0;freetype;z;fontconfig;gobject-2.0;gmodule-2.0;glib-2.0 +GTK_LIBRARY_DIRS:INTERNAL= +GTK_LIBS:INTERNAL= +GTK_LIBS_L:INTERNAL= +GTK_LIBS_OTHER:INTERNAL= +GTK_LIBS_PATHS:INTERNAL= +GTK_PREFIX:INTERNAL=/usr +GTK_STATIC_CFLAGS:INTERNAL=-I/usr/include/gtk-2.0;-I/usr/lib/gtk-2.0/include;-I/usr/include/atk-1.0;-I/usr/include/cairo;-I/usr/include/pango-1.0;-I/usr/include/glib-2.0;-I/usr/lib/glib-2.0/include;-I/usr/include/pixman-1;-I/usr/include/freetype2;-I/usr/include/libpng12 +GTK_STATIC_CFLAGS_I:INTERNAL= +GTK_STATIC_CFLAGS_OTHER:INTERNAL= +GTK_STATIC_INCLUDE_DIRS:INTERNAL=/usr/include/gtk-2.0;/usr/lib/gtk-2.0/include;/usr/include/atk-1.0;/usr/include/cairo;/usr/include/pango-1.0;/usr/include/glib-2.0;/usr/lib/glib-2.0/include;/usr/include/pixman-1;/usr/include/freetype2;/usr/include/libpng12 +GTK_STATIC_LDFLAGS:INTERNAL=-lgtk-x11-2.0;-lgdk-x11-2.0;-latk-1.0;-lpangoft2-1.0;-lXinerama;-lXi;-lXrandr;-lXcursor;-lXcomposite;-lXdamage;-lgdk_pixbuf-2.0;-ltiff;-ljpeg;-lpangocairo-1.0;-lgio-2.0;-lXext;-lXfixes;-lcairo;-lm;-lpixman-1;-lpng12;-lxcb-render-util;-lXrender;-lxcb-render;-lX11;-lpthread;-lxcb-xlib;-lxcb;-lXau;-lXdmcp;-lpango-1.0;-lfontconfig;-lexpat;-lfreetype;-lz;-lgobject-2.0;-lgmodule-2.0;-ldl;-lglib-2.0 +GTK_STATIC_LDFLAGS_OTHER:INTERNAL= +GTK_STATIC_LIBDIR:INTERNAL= +GTK_STATIC_LIBRARIES:INTERNAL=gtk-x11-2.0;gdk-x11-2.0;atk-1.0;pangoft2-1.0;Xinerama;Xi;Xrandr;Xcursor;Xcomposite;Xdamage;gdk_pixbuf-2.0;tiff;jpeg;pangocairo-1.0;gio-2.0;Xext;Xfixes;cairo;m;pixman-1;png12;xcb-render-util;Xrender;xcb-render;X11;pthread;xcb-xlib;xcb;Xau;Xdmcp;pango-1.0;fontconfig;expat;freetype;z;gobject-2.0;gmodule-2.0;dl;glib-2.0 +GTK_STATIC_LIBRARY_DIRS:INTERNAL= +GTK_STATIC_LIBS:INTERNAL= +GTK_STATIC_LIBS_L:INTERNAL= +GTK_STATIC_LIBS_OTHER:INTERNAL= +GTK_STATIC_LIBS_PATHS:INTERNAL= +GTK_VERSION:INTERNAL=2.14.4 +GTK_gtk+-2.0_INCLUDEDIR:INTERNAL= +GTK_gtk+-2.0_LIBDIR:INTERNAL= +GTK_gtk+-2.0_PREFIX:INTERNAL= +GTK_gtk+-2.0_VERSION:INTERNAL= +//Advanced flag for variable: PKG_CONFIG_EXECUTABLE +PKG_CONFIG_EXECUTABLE-ADVANCED:INTERNAL=1 +__pkg_config_checked_GIO:INTERNAL=1 +__pkg_config_checked_GIOMM:INTERNAL=1 +__pkg_config_checked_GLIB2:INTERNAL=1 +__pkg_config_checked_GLIBMM:INTERNAL=1 +__pkg_config_checked_GTK:INTERNAL=1 +__pkg_config_checked_GTKMM:INTERNAL=1 + diff --git a/rtgui/CMakeLists.txt b/rtgui/CMakeLists.txt new file mode 100755 index 000000000..1245c45b0 --- /dev/null +++ b/rtgui/CMakeLists.txt @@ -0,0 +1,101 @@ + +find_package(PkgConfig) + +pkg_check_modules (GLIB2 glib-2.0>=2.16) +pkg_check_modules (GLIBMM glibmm-2.4>=2.16) +pkg_check_modules (GTK gtk+-2.0>=2.12) +pkg_check_modules (GTKMM gtkmm-2.4>=2.12) +pkg_check_modules (GIO gio-2.0>=2.16) +pkg_check_modules (GIOMM giomm-2.4>=2.12) + +SET (BASESOURCEFILES + batchtoolpanelcoord.cc paramsedited.cc cropwindow.cc previewhandler.cc previewwindow.cc navigator.cc indclippedpanel.cc filterpanel.cc + cursormanager.cc rtwindow.cc renamedlg.cc recentbrowser.cc placesbrowser.cc filepanel.cc editorpanel.cc batchqueuepanel.cc + ilabel.cc thumbbrowserbase.cc adjuster.cc filebrowserentry.cc filebrowser.cc filethumbnailbuttonset.cc + cachemanager.cc cacheimagedata.cc + clipboard.cc thumbimageupdater.cc bqentryupdater.cc + coarsepanel.cc cacorrection.cc colorshift.cc hlrec.cc chmixer.cc + colorboost.cc resize.cc icmpanel.cc crop.cc shadowshighlights.cc + colordenoise.cc + exifpanel.cc + sharpening.cc + whitebalance.cc vignetting.cc rotate.cc distortion.cc + crophandler.cc curveeditor.cc dirbrowser.cc + filecatalog.cc + histogrampanel.cc history.cc imagearea.cc + imageareapanel.cc iptcpanel.cc lcurve.cc lumadenoise.cc main.cc + multilangmgr.cc mycurve.cc options.cc + preferences.cc profilepanel.cc saveasdlg.cc + saveformatpanel.cc splash.cc + thumbnail.cc tonecurve.cc toolbar.cc + guiutils.cc zoompanel.cc toolpanelcoord.cc + thumbbrowserentrybase.cc batchqueueentry.cc + batchqueue.cc lwbutton.cc lwbuttonset.cc + batchqueuebuttonset.cc browserfilter.cc exiffiltersettings.cc + profilestore.cc partialpastedlg.cc) + +IF (WIN32) + SET (EXTRA_LIBDIR "../lib") + SET (EXTRA_INCDIR "../winclude") + SET (EXTRA_SRC "windirmonitor.cc myicon.o") + SET (EXTRA_LIB "ws2_32") + +include_directories (/usr/local/lib ../rtengine . ../rtexif ${EXTRA_INCDIR} ${GLIB2_INCLUDE_DIRS} ${GLIBMM_INCLUDE_DIRS} + ${GTK_INCLUDE_DIRS} ${GTKMM_INCLUDE_DIRS} ${GIO_INCLUDE_DIRS} ${GIOMM_INCLUDE_DIRS}) +link_directories (. ../rtexif ${EXTRA_LIBDIR} ${GLIB2_LIBRARY_DIRS} ${GLIBMM_LIBRARY_DIRS} + ${GTK_LIBRARY_DIRS} ${GTKMM_LIBRARY_DIRS} ${GIO_LIBRARY_DIRS} ${GIOMM_LIBRARY_DIRS}) +#set_target_properties (rth PROPERTIES LINK_FLAGS "-mwindows") + + add_executable (rth windirmonitor.cc myicon.o ${BASESOURCEFILES}) + +ELSE (WIN32) + IF (CMAKE_SIZEOF_VOID_P EQUAL 4) + SET (EXTRA_INCDIR "../rawzor_lin32") + SET (EXTRA_LIBDIR "../rawzor_lin32") + ELSEIF (CMAKE_SIZEOF_VOID_P EQUAL 8) + SET (EXTRA_INCDIR "../rawzor_lin64") + SET (EXTRA_LIBDIR "../rawzor_lin64") + ENDIF (CMAKE_SIZEOF_VOID_P EQUAL 4) + +include_directories (/usr/local/lib ../rtengine . ../rtexif ${EXTRA_INCDIR} ${GLIB2_INCLUDE_DIRS} ${GLIBMM_INCLUDE_DIRS} + ${GTK_INCLUDE_DIRS} ${GTKMM_INCLUDE_DIRS} ${GIO_INCLUDE_DIRS} ${GIOMM_INCLUDE_DIRS}) +link_directories (. ../rtexif ${EXTRA_LIBDIR} ${GLIB2_LIBRARY_DIRS} ${GLIBMM_LIBRARY_DIRS} + ${GTK_LIBRARY_DIRS} ${GTKMM_LIBRARY_DIRS} ${GIO_LIBRARY_DIRS} ${GIOMM_LIBRARY_DIRS}) + + add_executable (rth ${BASESOURCEFILES}) +ENDIF (WIN32) + + +set_target_properties (rth PROPERTIES COMPILE_FLAGS "-O3") +target_link_libraries (rth rtengine liblcms.a iptcdata libjpeg.a libpng.a libz.a libtiff.a ${EXTRA_LIB} gthread-2.0 gobject-2.0 + ${GLIB2_LIBRARIES} ${GLIBMM_LIBRARIES} ${GTK_LIBRARIES} ${GTKMM_LIBRARIES} ${GIO_LIBRARIES} ${GIOMM_LIBRARIES}) + +IF (WIN32) + install (FILES rth.exe DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/../release + PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ + RENAME rt.exe) + install (FILES ../rawzor_win/rwz_sdk_s.dll DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/../release + PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ) + install (FILES ../options.win DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/../release + PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ + RENAME options) +ELSE (WIN32) + install (FILES rth DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/../release + PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ + RENAME rt) + install (FILES ../options.lin DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/../release + PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ + RENAME options) + install (FILES ../rtstart DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/../release + PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ) + IF (CMAKE_SIZEOF_VOID_P EQUAL 4) + install (FILES ../rawzor_lin32/librwz_sdk.so DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/../release + PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ + RENAME rwz_sdk.so) + ELSEIF (CMAKE_SIZEOF_VOID_P EQUAL 8) + install (FILES ../rawzor_lin64/librwz_sdk.so DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/../release + PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ + RENAME rwz_sdk.so) + ENDIF (CMAKE_SIZEOF_VOID_P EQUAL 4) +ENDIF (WIN32) + diff --git a/rtgui/RT.ico b/rtgui/RT.ico new file mode 100755 index 0000000000000000000000000000000000000000..d7befa1a7d8cd8b05b91294e625f06e986827959 GIT binary patch literal 127737 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 b)cJK1cFwPpaxg^u`b__`*!OhIL5}@@1zKpU literal 0 HcmV?d00001 diff --git a/rtgui/adjuster.cc b/rtgui/adjuster.cc new file mode 100755 index 000000000..477821c7f --- /dev/null +++ b/rtgui/adjuster.cc @@ -0,0 +1,273 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include + +extern Glib::ustring argv0; + +int Adjuster::delay = 1000; + +Adjuster::Adjuster (Glib::ustring vlabel, double vmin, double vmax, double vstep, double vdefault, bool editedcb) { + + adjusterListener = NULL; + afterReset = false; + + set_border_width (2); + + hbox = Gtk::manage (new Gtk::HBox ()); + + label = Gtk::manage (new Gtk::Label (vlabel, Gtk::ALIGN_LEFT)); + + if (editedcb) { + editedCheckBox = new Gtk::CheckButton (); + editedChange = editedCheckBox->signal_toggled().connect( sigc::mem_fun(*this, &Adjuster::editedToggled) ); + hbox->pack_start (*editedCheckBox); + } + else + editedCheckBox = NULL; + + hbox->pack_start (*label); + + reset = Gtk::manage (new Gtk::Button ()); + reset->add (*Gtk::manage (new Gtk::Image (argv0+"/images/undo.png"))); + reset->set_relief (Gtk::RELIEF_NONE); + reset->set_border_width (0); + reset->set_tooltip_text (M("ADJUSTER_RESET_TO_DEFAULT")); + + hbox->pack_end (*reset, Gtk::PACK_SHRINK, 0); + + spin = Gtk::manage (new Gtk::SpinButton ()); + spin->set_size_request (70, -1); + + hbox->pack_end (*spin, Gtk::PACK_SHRINK, 0); + + reset->set_size_request (-1, spin->get_height()); + + slider = Gtk::manage (new Gtk::HScale ()); + slider->set_draw_value (false); + + pack_start (*hbox, false, false); + pack_start (*slider, false, false); + + setLimits (vmin, vmax, vstep, vdefault); + + defaultVal = shapeValue (vdefault); + editedState = defEditedState = Irrelevant; + + sliderChange = slider->signal_value_changed().connect( sigc::mem_fun(*this, &Adjuster::sliderChanged) ); + spinChange = spin->signal_value_changed().connect ( sigc::mem_fun(*this, &Adjuster::spinChanged), true); + reset->signal_clicked().connect( sigc::mem_fun(*this, &Adjuster::resetPressed) ); + slider->set_update_policy (Gtk::UPDATE_CONTINUOUS); + + show_all (); +} + +Adjuster::~Adjuster () { + + sliderChange.block (true); + spinChange.block (true); + delayConnection.block (true); + adjusterListener = NULL; +} + +void Adjuster::setDefault (double def) { + + defaultVal = shapeValue (def); +} + +void Adjuster::setDefaultEditedState (EditedState eState) { + + defEditedState = eState; +} + +void Adjuster::resetPressed () { + + if (editedState!=Irrelevant) { + editedState = defEditedState; + if (editedCheckBox) { + editedChange.block (true); + editedCheckBox->set_active (defEditedState==Edited); + editedChange.block (false); + } + refreshLabelStyle (); + } + afterReset = true; + slider->set_value (defaultVal); +} + +double Adjuster::shapeValue (double a) { + + return round(a*pow(10, digits)) / pow(10, digits); +} + +void Adjuster::setLimits (double vmin, double vmax, double vstep, double vdefault) { + + sliderChange.block (true); + spinChange.block (true); + for (digits=0; fabs(vstep*pow(10,digits)-floor(vstep*pow(10,digits)))>0.000000000001; digits++); + spin->set_digits (digits); + spin->set_increments (vstep, 2.0*vstep); + spin->set_range (vmin, vmax); + spin->set_value (shapeValue(vdefault)); + slider->set_digits (digits); + slider->set_increments (vstep, 2.0*vstep); + slider->set_range (vmin, vmax); + slider->set_value (shapeValue(vdefault)); + defaultVal = shapeValue (vdefault); + sliderChange.block (false); + spinChange.block (false); +} + +void Adjuster::setAdjusterListener (AdjusterListener* alistener) { + + adjusterListener = alistener; +} + +void Adjuster::spinChanged () { + + sliderChange.block (true); + slider->set_value (spin->get_value ()); + sliderChange.block (false); + + if (delay==0) { + if (adjusterListener!=NULL) + adjusterListener->adjusterChanged (this, spin->get_value ()); + } + else + Glib::signal_idle().connect (sigc::mem_fun(*this, &Adjuster::notifyListener)); + + if (editedState==UnEdited) { + editedState = Edited; + if (editedCheckBox) { + editedChange.block (true); + editedCheckBox->set_active (true); + editedChange.block (false); + } + refreshLabelStyle (); + } + afterReset = false; +} + +void Adjuster::sliderChanged () { + + if (delayConnection.connected()) + delayConnection.disconnect (); + + spinChange.block (true); + spin->set_value (slider->get_value ()); + spinChange.block (false); + + if (delay==0) { + if (adjusterListener) + adjusterListener->adjusterChanged (this, spin->get_value ()); + } + else + delayConnection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &Adjuster::notifyListener), delay); + + if (!afterReset && editedState==UnEdited) { + editedState = Edited; + if (editedCheckBox) { + editedChange.block (true); + editedCheckBox->set_active (true); + editedChange.block (false); + } + refreshLabelStyle (); + } + afterReset = false; +} + +void Adjuster::setValue (double a) { + + spinChange.block (true); + sliderChange.block (true); + spin->set_value (shapeValue (a)); + slider->set_value (shapeValue (a)); + sliderChange.block (false); + spinChange.block (false); + afterReset = false; +} + +double Adjuster::getValue () { + + return spin->get_value (); +} + +bool Adjuster::notifyListener () { + + gdk_threads_enter(); + + if (adjusterListener!=NULL) + adjusterListener->adjusterChanged (this, spin->get_value ()); + gdk_threads_leave(); + + return false; +} + +void Adjuster::setEnabled (bool enabled) { + + spin->set_sensitive (enabled); + slider->set_sensitive (enabled); +} +void Adjuster::setEditedState (EditedState eState) { + + if (editedState!=eState) { + if (editedCheckBox) { + editedChange.block (true); + editedCheckBox->set_active (eState==Edited); + editedChange.block (false); + } + editedState = eState; + refreshLabelStyle (); + } +} + +EditedState Adjuster::getEditedState () { + + if (editedState!=Irrelevant && editedCheckBox) + editedState = editedCheckBox->get_active () ? Edited : UnEdited; + return editedState; +} + +void Adjuster::showEditedCB () { + + if (!editedCheckBox) { + editedCheckBox = new Gtk::CheckButton (); + hbox->pack_start (*editedCheckBox, Gtk::PACK_SHRINK, 2); + hbox->reorder_child (*editedCheckBox, 0); + editedChange = editedCheckBox->signal_toggled().connect( sigc::mem_fun(*this, &Adjuster::editedToggled) ); + } +} + +void Adjuster::refreshLabelStyle () { + +/* Glib::RefPtr style = label->get_style (); + Pango::FontDescription fd = style->get_font (); + fd.set_weight (editedState==Edited ? Pango::WEIGHT_BOLD : Pango::WEIGHT_NORMAL); + style->set_font (fd); + label->set_style (style); + label->queue_draw ();*/ +} + +void Adjuster::editedToggled () { + + if (adjusterListener) + adjusterListener->adjusterChanged (this, spin->get_value ()); +} diff --git a/rtgui/adjuster.h b/rtgui/adjuster.h new file mode 100755 index 000000000..c0222dde4 --- /dev/null +++ b/rtgui/adjuster.h @@ -0,0 +1,83 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _ADJUSTER_H_ +#define _ADJUSTER_H_ + +#include +#include + +class Adjuster; +class AdjusterListener { + + public: + virtual void adjusterChanged (Adjuster* a, double newval) {} +}; + + +class Adjuster : public Gtk::VBox { + + protected: + Gtk::HBox* hbox; + Gtk::Label* label; + Gtk::HScale* slider; + Gtk::SpinButton* spin; + Gtk::Button* reset; + AdjusterListener* adjusterListener; + sigc::connection delayConnection; + sigc::connection spinChange; + sigc::connection sliderChange; + sigc::connection editedChange; + bool listenerReady; + double defaultVal; + EditedState editedState; + EditedState defEditedState; + int digits; + Gtk::CheckButton* editedCheckBox; + bool afterReset; + + double shapeValue (double a); + void refreshLabelStyle (); + + public: + + static int delay; + + Adjuster (Glib::ustring label, double vmin, double vmax, double vstep, double vdefault, bool editedCheckBox=false); + virtual ~Adjuster (); + void setAdjusterListener (AdjusterListener* alistener); + + double getValue (); + void setValue (double a); + void setLimits (double vmin, double vmax, double vstep, double vdefault); + void setEnabled (bool enabled); + void setDefault (double def); + void setEditedState (EditedState eState); + EditedState getEditedState (); + void setDefaultEditedState (EditedState eState); + void showEditedCB (); + + + void spinChanged (); + void sliderChanged (); + bool notifyListener (); + void resetPressed (); + void editedToggled (); +}; + +#endif diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc new file mode 100755 index 000000000..c44bd9f2f --- /dev/null +++ b/rtgui/batchqueue.cc @@ -0,0 +1,403 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include +#include +#include + +using namespace rtengine; + +BatchQueue::BatchQueue () : processing(NULL), listener(NULL) { + + int p = 0; + pmenu = new Gtk::Menu (); + pmenu->attach (*(cancel = new Gtk::MenuItem (M("FILEBROWSER_POPUPCANCELJOB"))), 0, 1, p, p+1); p++; + pmenu->attach (*(new Gtk::SeparatorMenuItem ()), 0, 1, p, p+1); p++; + pmenu->attach (*(head = new Gtk::MenuItem (M("FILEBROWSER_POPUPMOVEHEAD"))), 0, 1, p, p+1); p++; + pmenu->attach (*(tail = new Gtk::MenuItem (M("FILEBROWSER_POPUPMOVEEND"))), 0, 1, p, p+1); p++; + pmenu->attach (*(new Gtk::SeparatorMenuItem ()), 0, 1, p, p+1); p++; + pmenu->attach (*(selall = new Gtk::MenuItem (M("FILEBROWSER_POPUPSELECTALL"))), 0, 1, p, p+1); p++; + pmenu->show_all (); + + cancel->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &BatchQueue::cancelItems), &selected)); + head->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &BatchQueue::headItems), &selected)); + tail->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &BatchQueue::tailItems), &selected)); + selall->signal_activate().connect (sigc::mem_fun(*this, &BatchQueue::selectAll)); +} + +void BatchQueue::rightClicked (ThumbBrowserEntryBase* entry) { + + pmenu->popup (3, 0); +} + +void BatchQueue::addEntry (BatchQueueEntry* entry, bool head) { + + entry->setParent (this); + entry->resize (options.thumbSize); + + entry->selected = false; + if (!head) + fd.push_back (entry); + else { + std::vector::iterator pos; + for (pos=fd.begin(); pos!=fd.end(); pos++) + if (!(*pos)->processing) { + fd.insert (pos, entry); + break; + } + if (pos==fd.end()) + fd.push_back (entry); + } + + if (entry->thumbnail) + entry->thumbnail->imageEnqueued (); + + BatchQueueButtonSet* bqbs = new BatchQueueButtonSet (entry); + bqbs->setButtonListener (this); + entry->addButtonSet (bqbs); + + arrangeFiles (); + queue_draw (); + notifyListener (); +} + +int deleteitem (void* data) { + + gdk_threads_enter (); + delete (BatchQueueEntry*)data; + gdk_threads_leave (); + return 0; +} + +void BatchQueue::cancelItems (std::vector* items) { + + for (int i=0; isize(); i++) { + BatchQueueEntry* entry = (BatchQueueEntry*)(*items)[i]; + if (entry->processing) + continue; + std::vector::iterator pos = std::find (fd.begin(), fd.end(), entry); + if (pos!=fd.end()) { + fd.erase (pos); + rtengine::ProcessingJob::destroy (entry->job); + if (entry->thumbnail) + entry->thumbnail->imageRemovedFromQueue (); + g_idle_add (deleteitem, entry); + } + } + for (int i=0; iselected = false; + lastClicked = NULL; + selected.clear (); + redraw (); + notifyListener (); +} + +void BatchQueue::headItems (std::vector* items) { + + for (int i=items->size()-1; i>=0; i--) { + BatchQueueEntry* entry = (BatchQueueEntry*)(*items)[i]; + if (entry->processing) + continue; + std::vector::iterator pos = std::find (fd.begin(), fd.end(), entry); + if (pos!=fd.end() && pos!=fd.begin()) { + fd.erase (pos); + // find the first item that is not under processing + for (pos=fd.begin(); pos!=fd.end(); pos++) + if (!(*pos)->processing) { + fd.insert (pos, entry); + break; + } + } + } + redraw (); +} + +void BatchQueue::tailItems (std::vector* items) { + + for (int i=0; isize(); i++) { + BatchQueueEntry* entry = (BatchQueueEntry*)(*items)[i]; + if (entry->processing) + continue; + std::vector::iterator pos = std::find (fd.begin(), fd.end(), entry); + if (pos!=fd.end()) { + fd.erase (pos); + fd.push_back (entry); + } + } + redraw (); +} + +void BatchQueue::selectAll () { + + lastClicked = NULL; + selected.clear (); + for (int i=0; iprocessing) + continue; + fd[i]->selected = true; + selected.push_back (fd[i]); + } + queue_draw (); +} +void BatchQueue::startProcessing () { + + if (!processing && fd.size()>0) { + BatchQueueEntry* next = (BatchQueueEntry*)fd[0]; + // tag it as processing + next->processing = true; + processing = next; + // remove from selection + if (processing->selected) { + std::vector::iterator pos = std::find (selected.begin(), selected.end(), processing); + if (pos!=selected.end()) + selected.erase (pos); + processing->selected = false; + } + // remove button set + next->removeButtonSet (); + // start batch processing + rtengine::startBatchProcessing (next->job, this); + queue_draw (); + } +} + +rtengine::ProcessingJob* BatchQueue::imageReady (rtengine::IImage16* img) { + + gdk_threads_enter (); + // save image img + Glib::ustring fname; + SaveFormat saveFormat; + if (processing->outFileName=="") { // auto file name + fname = obtainFileName (processing->filename); + saveFormat = options.saveFormat; + } + else { // use the save-as filename with automatic completion for uniqueness + fname = autoCompleteFileName (removeExtension(processing->outFileName), getExtension(processing->outFileName)); + saveFormat = processing->saveFormat; + } + printf ("fname=%s, %s\n", fname.c_str(), removeExtension(fname).c_str()); + if (img && fname!="") { + int err = 0; + if (saveFormat.format=="tif") + err = img->saveAsTIFF (fname, saveFormat.tiffBits); + else if (saveFormat.format=="png") + err = img->saveAsPNG (fname, saveFormat.pngCompression, saveFormat.pngBits); + else if (saveFormat.format=="jpg") + err = img->saveAsJPEG (fname, saveFormat.jpegQuality); + img->free (); + if (!err && saveFormat.saveParams) + processing->params.save (removeExtension(fname) + ".pp2"); + if (processing->thumbnail) { + processing->thumbnail->imageDeveloped (); + processing->thumbnail->imageRemovedFromQueue (); + if (listener) + listener->imageProcessingReady (processing->filename); + } + } + + // delete from the queue + delete processing; + processing = NULL; + fd.erase (fd.begin()); + // return next job + if (fd.size()==0) { + if (listener) + listener->queueEmpty (); + } + else if (listener && listener->canStartNext ()) { + BatchQueueEntry* next = (BatchQueueEntry*)fd[0]; + // tag it as selected + next->processing = true; + processing = next; + // remove from selection + if (processing->selected) { + std::vector::iterator pos = std::find (selected.begin(), selected.end(), processing); + if (pos!=selected.end()) + selected.erase (pos); + processing->selected = false; + } + // remove button set + next->removeButtonSet (); + } + redraw (); + notifyListener (); + gdk_threads_leave (); + return processing ? processing->job : NULL; +} + +Glib::ustring BatchQueue::obtainFileName (const Glib::ustring& origFileName) { + + std::vector pa; + std::vector da; + + for (int i=0; i=origFileName.size()) + break; + Glib::ustring tok = ""; + while ((i=0 && origFileName[extpos]!='.'; extpos--); + for (int k=extpos-1; k>=0 && origFileName[k]!='/' && origFileName[k]!='\\'; k--) + filename = origFileName[k] + filename; + +// printf ("%d, |%s|\n", extpos, filename.c_str()); + + // constructing full output path +// printf ("path=|%s|\n", options.savePath.c_str()); + + Glib::ustring path=""; + if (options.saveUsePathTemplate) { + int ix=0; + while (options.savePathTemplate[ix]!=0) { + if (options.savePathTemplate[ix]=='%') { + ix++; + if (options.savePathTemplate[ix]=='p') { + ix++; + int i = options.savePathTemplate[ix]-'0'; + if (iredraw(); + gdk_threads_leave (); + return 0; +} + +void BatchQueue::setProgress (double p) { + + if (processing) + processing->progress = p; + + g_idle_add (bqredraw, this); +} + +void BatchQueue::buttonPressed (LWButton* button, int actionCode, void* actionData) { + + std::vector bqe; + bqe.push_back ((BatchQueueEntry*)actionData); + + if (actionCode==10) // cancel + cancelItems (&bqe); + else if (actionCode==8) // to head + headItems (&bqe); + else if (actionCode==9) // to tail + tailItems (&bqe); +} + +struct NLParams { + BatchQueueListener* listener; + int qsize; +}; + +int bqnotifylistener (void* data) { + + gdk_threads_enter (); + NLParams* params = (NLParams*)data; + params->listener->queueSizeChanged (params->qsize); + delete params; + gdk_threads_leave (); + return 0; +} + +void BatchQueue::notifyListener () { + + if (listener) { + NLParams* params = new NLParams; + params->listener = listener; + params->qsize = fd.size(); + g_idle_add (bqnotifylistener, params); + } +} + +void BatchQueue::redrawNeeded (LWButton* button) { + + queue_draw (); +} diff --git a/rtgui/batchqueue.h b/rtgui/batchqueue.h new file mode 100755 index 000000000..2e968a47d --- /dev/null +++ b/rtgui/batchqueue.h @@ -0,0 +1,84 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _BATCHQUEUE_ +#define _BATCHQUEUE_ + +#include +#include +#include +#include +#include +#include + +class BatchQueueListener { + + public: + virtual void queueSizeChanged (int qsize) {} + virtual void imageProcessingReady (Glib::ustring fname) {} + virtual void queueEmpty () {} + virtual bool canStartNext () {} +}; + +class FileCatalog; +class BatchQueue : public ThumbBrowserBase, + public rtengine::BatchProcessingListener, + public LWButtonListener { + + protected: + + BatchQueueEntry* processing; + + Glib::ustring nameTemplate; + + Gtk::MenuItem* cancel; + Gtk::MenuItem* head; + Gtk::MenuItem* tail; + Gtk::MenuItem* selall; + Gtk::Menu* pmenu; + + BatchQueueListener* listener; + + Glib::ustring obtainFileName (const Glib::ustring& origFileName); + Glib::ustring autoCompleteFileName (const Glib::ustring& fileName, const Glib::ustring& format); + + public: + BatchQueue (); + + void addEntry (BatchQueueEntry* entry, bool head=false); + + void cancelItems (std::vector* items); + void headItems (std::vector* items); + void tailItems (std::vector* items); + void selectAll (); + + void startProcessing (); + + bool hasJobs () { return fd.size()>0; } + + rtengine::ProcessingJob* imageReady (rtengine::IImage16* img); + void setProgress (double p); + void rightClicked (ThumbBrowserEntryBase* entry); + void buttonPressed (LWButton* button, int actionCode, void* actionData); + void redrawNeeded (LWButton* button); + + void setBatchQueueListener (BatchQueueListener* l) { listener = l; } + void notifyListener (); +}; + +#endif diff --git a/rtgui/batchqueuebuttonset b/rtgui/batchqueuebuttonset new file mode 100755 index 000000000..ad92e1370 --- /dev/null +++ b/rtgui/batchqueuebuttonset @@ -0,0 +1,27 @@ +#ifndef _THUMBNAILBUTTONSET_ +#define _THUMBNAILBUTTONSET_ + +#include +#include +#include + +class ThumbBrowserEntry; +class ThumbnailButtonSet : public LWButtonSet { + + static bool iconsLoaded; + + public: + static Glib::RefPtr rankIcon; + static Glib::RefPtr gRankIcon; + static Glib::RefPtr unRankIcon; + static Glib::RefPtr trashIcon; + static Glib::RefPtr unTrashIcon; + static Glib::RefPtr processIcon; + + ThumbnailButtonSet (ThumbBrowserEntry* myEntry); + void setRank (int stars); + void setInTrash (bool inTrash); + +}; + +#endif diff --git a/rtgui/batchqueuebuttonset.cc b/rtgui/batchqueuebuttonset.cc new file mode 100755 index 000000000..36ebc4363 --- /dev/null +++ b/rtgui/batchqueuebuttonset.cc @@ -0,0 +1,42 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +extern Glib::ustring argv0; + +bool BatchQueueButtonSet::iconsLoaded = false; + +Cairo::RefPtr BatchQueueButtonSet::cancelIcon; +Cairo::RefPtr BatchQueueButtonSet::headIcon; +Cairo::RefPtr BatchQueueButtonSet::tailIcon; + +BatchQueueButtonSet::BatchQueueButtonSet (BatchQueueEntry* myEntry) { + + if (!iconsLoaded) { + cancelIcon = Cairo::ImageSurface::create_from_png (argv0+"/images/deltags.png"); + headIcon = Cairo::ImageSurface::create_from_png (argv0+"/images/head.png"); + tailIcon = Cairo::ImageSurface::create_from_png (argv0+"/images/tail.png"); + iconsLoaded = true; + } + + add (new LWButton (headIcon, 8, myEntry, LWButton::Left, LWButton::Center, M("FILEBROWSER_POPUPMOVEHEAD"))); + add (new LWButton (tailIcon, 9, myEntry, LWButton::Left, LWButton::Center, M("FILEBROWSER_POPUPMOVEEND"))); + add (new LWButton (cancelIcon, 10, myEntry, LWButton::Right, LWButton::Center, M("FILEBROWSER_POPUPCANCELJOB"))); +} diff --git a/rtgui/batchqueuebuttonset.h b/rtgui/batchqueuebuttonset.h new file mode 100755 index 000000000..4b92c3d85 --- /dev/null +++ b/rtgui/batchqueuebuttonset.h @@ -0,0 +1,38 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _BATCHQUEUEBUTTONSET_ +#define _BATCHQUEUEBUTTONSET_ + +#include +#include + +class BatchQueueEntry; +class BatchQueueButtonSet : public LWButtonSet { + + static bool iconsLoaded; + + public: + static Cairo::RefPtr cancelIcon; + static Cairo::RefPtr headIcon; + static Cairo::RefPtr tailIcon; + + BatchQueueButtonSet (BatchQueueEntry* myEntry); +}; + +#endif diff --git a/rtgui/batchqueueentry.cc b/rtgui/batchqueueentry.cc new file mode 100755 index 000000000..8a74829d7 --- /dev/null +++ b/rtgui/batchqueueentry.cc @@ -0,0 +1,156 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +BatchQueueEntry::BatchQueueEntry (rtengine::ProcessingJob* pjob, const rtengine::procparams::ProcParams& pparams, Glib::ustring fname, guint8* previmg, int prevw, int prevh, Thumbnail* thumbnail) + : job(pjob), ThumbBrowserEntryBase(fname), + opreview(previmg), origpw(prevw), origph(prevh), progress(0), thumbnail(thumbnail), + outFileName("") { + + params = pparams; + + bqih = new BatchQueueEntryIdleHelper; + bqih->bqentry = this; + bqih->destroyed = false; + bqih->pending = 0; + + if (thumbnail) + thumbnail->increaseRef (); +} + +BatchQueueEntry::~BatchQueueEntry () { + + batchQueueEntryUpdater.removeJobs (this); + delete [] opreview; + if (thumbnail) + thumbnail->decreaseRef (); + + if (bqih->pending) + bqih->destroyed = true; + else + delete bqih; +} + +void BatchQueueEntry::refreshThumbnailImage () { + + if (!opreview) + return; + + batchQueueEntryUpdater.add (opreview, origpw, origph, preh, this); + batchQueueEntryUpdater.process (); +} + +void BatchQueueEntry::calcThumbnailSize () { + + prew = preh * origpw / origph; +} + + +void BatchQueueEntry::drawProgressBar (Glib::RefPtr win, Glib::RefPtr gc, const Gdk::Color& foregr, const Gdk::Color& backgr, int x, int w, int y, int h) { + + if (processing) { + Cairo::RefPtr cr = win->create_cairo_context(); + cr->set_antialias (Cairo::ANTIALIAS_SUBPIXEL); + double px = x + w/6.0; + double pw = w*2.0/3.0; + double py = y + h/4.0; + double ph = h/2.0; + cr->move_to (px, py); + cr->line_to (px+pw, py); + cr->set_line_width (ph); + cr->set_line_cap (Cairo::LINE_CAP_ROUND); + cr->set_source_rgb (foregr.get_red_p(), foregr.get_green_p(), foregr.get_blue_p()); + cr->stroke (); + + cr->move_to (px, py); + cr->line_to (px+pw, py); + cr->set_line_width (ph*3.0/4.0); + cr->set_source_rgb (backgr.get_red_p(), backgr.get_green_p(), backgr.get_blue_p()); + cr->stroke (); + + cr->move_to (px, py); + cr->line_to (px+pw*progress, py); + cr->set_line_width (ph/2.0); + cr->set_source_rgb (foregr.get_red_p(), foregr.get_green_p(), foregr.get_blue_p()); + cr->stroke (); + } +} + +void BatchQueueEntry::removeButtonSet () { + + delete buttonSet; + buttonSet = NULL; +} +struct bqupdate { + BatchQueueEntryIdleHelper* bqih; + guint8* img; + int w,h; +}; + +int bqeupdate (void* data) { + + gdk_threads_enter (); + bqupdate* params = (bqupdate*)data; + + BatchQueueEntryIdleHelper* bqih = params->bqih; + + if (bqih->destroyed) { + if (bqih->pending == 1) + delete bqih; + else + bqih->pending--; + delete [] params->img; + delete params; + gdk_threads_leave (); + return 0; + } + + bqih->bqentry->_updateImage (params->img, params->w, params->h); + bqih->pending--; + + gdk_threads_leave (); + delete params; + return 0; +} + +void BatchQueueEntry::updateImage (guint8* img, int w, int h) { + + bqih->pending++; + + bqupdate* param = new bqupdate (); + param->bqih = bqih; + param->img = img; + param->w = w; + param->h = h; + g_idle_add (bqeupdate, param); +} + +void BatchQueueEntry::_updateImage (guint8* img, int w, int h) { + + if (preh == h) { + prew = w; + preview = new guint8 [prew*preh*3]; + memcpy (preview, img, prew*preh*3); + if (parent) + parent->redrawNeeded (this); + } + delete [] img; +} + diff --git a/rtgui/batchqueueentry.h b/rtgui/batchqueueentry.h new file mode 100755 index 000000000..d16d96f8f --- /dev/null +++ b/rtgui/batchqueueentry.h @@ -0,0 +1,66 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _BATCHQUEUEENTRY_ +#define _BATCHQUEUEENTRY_ + +#include +#include +#include +#include +#include + +class BatchQueueEntry; +struct BatchQueueEntryIdleHelper { + BatchQueueEntry* bqentry; + bool destroyed; + int pending; +}; + +class BatchQueueEntry : public ThumbBrowserEntryBase, public BQEntryUpdateListener { + + guint8* opreview; + int origpw, origph; + BatchQueueEntryIdleHelper* bqih; + +public: + Thumbnail* thumbnail; + rtengine::ProcessingJob* job; + rtengine::procparams::ProcParams params; + double progress; + Glib::ustring outFileName; + SaveFormat saveFormat; + + BatchQueueEntry (rtengine::ProcessingJob* job, const rtengine::procparams::ProcParams& pparams, Glib::ustring fname, guint8* previmg, int prevw, int prevh, Thumbnail* thumbnail=NULL); + ~BatchQueueEntry (); + + void refreshThumbnailImage (); + void calcThumbnailSize (); + + void drawProgressBar (Glib::RefPtr win, Glib::RefPtr gc, const Gdk::Color& foregr, const Gdk::Color& backgr, int x, int w, int y, int h); + + void removeButtonSet (); + + // bqentryupdatelistener interface + void updateImage (guint8* img, int w, int h); + void _updateImage (guint8* img, int w, int h); // inside gtk thread +}; + + + +#endif diff --git a/rtgui/batchqueuepanel.cc b/rtgui/batchqueuepanel.cc new file mode 100755 index 000000000..938e3d09a --- /dev/null +++ b/rtgui/batchqueuepanel.cc @@ -0,0 +1,241 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include +#include + +BatchQueuePanel::BatchQueuePanel () { + + batchQueue = new BatchQueue(); + + // construct batch queue panel with the extra "start" and "stop" button + Gtk::VBox* batchQueueButtonBox = Gtk::manage (new Gtk::VBox); + start = Gtk::manage (new Gtk::ToggleButton (M("FILEBROWSER_STARTPROCESSING"))); + stop = Gtk::manage (new Gtk::ToggleButton (M("FILEBROWSER_STOPPROCESSING"))); + autoStart = Gtk::manage (new Gtk::CheckButton ("Auto start")); + start->set_tooltip_text (M("FILEBROWSER_STARTPROCESSINGHINT")); + stop->set_tooltip_text (M("FILEBROWSER_STOPPROCESSINGHINT")); + autoStart->set_tooltip_text ("Start processing automatically when a new job arrives"); + start->set_active (false); + stop->set_active (true); + autoStart->set_active (options.procQueueEnabled); + + start->set_image (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-media-play"), Gtk::ICON_SIZE_BUTTON))); + startConnection = start->signal_toggled().connect (sigc::mem_fun(*this, &BatchQueuePanel::startBatchProc)); + stop->set_image (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-media-stop"), Gtk::ICON_SIZE_BUTTON))); + stopConnection = stop->signal_toggled().connect (sigc::mem_fun(*this, &BatchQueuePanel::stopBatchProc)); + batchQueueButtonBox->pack_start (*start, Gtk::PACK_SHRINK, 4); + batchQueueButtonBox->pack_start (*stop, Gtk::PACK_SHRINK, 4); + batchQueueButtonBox->pack_start (*autoStart, Gtk::PACK_SHRINK, 4); + + // Output directory selection + fdir = Gtk::manage (new Gtk::Frame (M("PREFERENCES_OUTDIR"))); + Gtk::VBox* odvb = Gtk::manage (new Gtk::VBox ()); + odvb->set_border_width (4); + Gtk::HBox* hb2 = Gtk::manage (new Gtk::HBox ()); + useTemplate = Gtk::manage (new Gtk::RadioButton (M("PREFERENCES_OUTDIRTEMPLATE")+":")); + hb2->pack_start (*useTemplate, Gtk::PACK_SHRINK,4); + outdirTemplate = Gtk::manage (new Gtk::Entry ()); + hb2->pack_start (*outdirTemplate); + odvb->pack_start (*hb2, Gtk::PACK_SHRINK, 4); + outdirTemplate->set_tooltip_markup (M("PREFERENCES_OUTDIRTEMPLATEHINT")); + useTemplate->set_tooltip_markup (M("PREFERENCES_OUTDIRTEMPLATEHINT")); + Gtk::HBox* hb3 = Gtk::manage (new Gtk::HBox ()); + useFolder = Gtk::manage (new Gtk::RadioButton (M("PREFERENCES_OUTDIRFOLDER")+":")); + hb3->pack_start (*useFolder, Gtk::PACK_SHRINK,4); + outdirFolder = Gtk::manage (new Gtk::FileChooserButton (M("PREFERENCES_OUTDIRFOLDER"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); + hb3->pack_start (*outdirFolder); + odvb->pack_start (*hb3, Gtk::PACK_SHRINK, 4); + outdirFolder->set_tooltip_markup (M("PREFERENCES_OUTDIRFOLDERHINT")); + useFolder->set_tooltip_markup (M("PREFERENCES_OUTDIRFOLDERHINT")); + Gtk::RadioButton::Group g = useTemplate->get_group(); + useFolder->set_group (g); + fdir->add (*odvb); + + // Output file format selection + fformat = Gtk::manage (new Gtk::Frame (M("PREFERENCES_FILEFORMAT"))); + saveFormatPanel = Gtk::manage (new SaveFormatPanel ()); + fformat->add (*saveFormatPanel); + + saveFormatPanel->init (options.saveFormat); + outdirTemplate->set_text (options.savePathTemplate); + if (Glib::file_test (options.savePathFolder, Glib::FILE_TEST_IS_DIR)) + outdirFolder->set_filename (options.savePathFolder); + useTemplate->set_active (options.saveUsePathTemplate); + useFolder->set_active (!options.saveUsePathTemplate); + + // setup signal handlers + outdirTemplate->signal_changed().connect (sigc::mem_fun(*this, &BatchQueuePanel::saveOptions)); + outdirFolder->signal_current_folder_changed().connect (sigc::mem_fun(*this, &BatchQueuePanel::saveOptions)); + useTemplate->signal_toggled().connect (sigc::mem_fun(*this, &BatchQueuePanel::saveOptions)); + useFolder->signal_toggled().connect (sigc::mem_fun(*this, &BatchQueuePanel::saveOptions)); + saveFormatPanel->setListener (this); + + // setup button bar + topBox = Gtk::manage (new Gtk::HBox ()); + pack_start (*topBox, Gtk::PACK_SHRINK); + + topBox->pack_start (*batchQueueButtonBox, Gtk::PACK_SHRINK, 4); + topBox->pack_start (*fdir); + topBox->pack_start (*fformat, Gtk::PACK_SHRINK, 4); + + // add middle browser area + Gtk::HBox* hBox = Gtk::manage (new Gtk::HBox ()); + pack_start (*batchQueue); + + // lower box with thumbnail zoom + bottomBox = Gtk::manage (new Gtk::HBox ()); + pack_start (*bottomBox, Gtk::PACK_SHRINK); + + // change thumbnail arrangement button + hAlignIcon = new Gtk::Image (argv0+"/images/horizontals.png"); + vAlignIcon = new Gtk::Image (argv0+"/images/verticals.png"); + hAlignIcon->show (); + vAlignIcon->show (); + chAlign = Gtk::manage (new Gtk::Button ()); + chAlign->show (); + bottomBox->pack_end (*chAlign, Gtk::PACK_SHRINK); + chAlign->set_image (*hAlignIcon); + chAlign->set_relief (Gtk::RELIEF_NONE); + chAlign->signal_pressed().connect (sigc::mem_fun(*this, &BatchQueuePanel::arrangementButtonPressed)); + chAlign->set_tooltip_text (M("FILEBROWSER_ARRANGEMENTHINT")); + bottomBox->pack_end (*Gtk::manage (new Gtk::VSeparator), Gtk::PACK_SHRINK, 4); + if (options.fbArrangement==1) + chAlign->set_image (*vAlignIcon); + else + chAlign->set_image (*hAlignIcon); + arrangementButtonPressed (); + + // thumbnail zoom + Gtk::HBox* zoomBox = Gtk::manage (new Gtk::HBox ()); + zoomBox->pack_start (*Gtk::manage (new Gtk::VSeparator), Gtk::PACK_SHRINK, 4); + Gtk::Label* zoomLabel = Gtk::manage (new Gtk::Label (Glib::ustring("")+M("FILEBROWSER_THUMBSIZE")+":")); + zoomLabel->set_use_markup (true); + zoomBox->pack_start (*zoomLabel, Gtk::PACK_SHRINK, 4); + zoomInButton = Gtk::manage (new Gtk::Button ()); + zoomInButton->set_image (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-zoom-in"), Gtk::ICON_SIZE_SMALL_TOOLBAR))); + zoomInButton->signal_pressed().connect (sigc::mem_fun(*batchQueue, &BatchQueue::zoomIn)); + zoomInButton->set_relief (Gtk::RELIEF_NONE); + zoomInButton->set_tooltip_text (M("FILEBROWSER_ZOOMINHINT")); + zoomBox->pack_end (*zoomInButton, Gtk::PACK_SHRINK); + zoomOutButton = Gtk::manage (new Gtk::Button ()); + zoomOutButton->set_image (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-zoom-out"), Gtk::ICON_SIZE_SMALL_TOOLBAR))); + zoomOutButton->signal_pressed().connect (sigc::mem_fun(*batchQueue, &BatchQueue::zoomOut)); + zoomOutButton->set_relief (Gtk::RELIEF_NONE); + zoomOutButton->set_tooltip_text (M("FILEBROWSER_ZOOMOUTHINT")); + zoomBox->pack_end (*zoomOutButton, Gtk::PACK_SHRINK); + bottomBox->pack_end (*zoomBox, Gtk::PACK_SHRINK); + + + batchQueue->setBatchQueueListener (this); + + show_all (); +} + +void BatchQueuePanel::arrangementButtonPressed () { + + if (chAlign->get_image()==hAlignIcon) { + chAlign->set_image (*vAlignIcon); + batchQueue->setArrangement (BatchQueue::TB_Vertical); + } + else { + chAlign->set_image (*hAlignIcon); + batchQueue->setArrangement (BatchQueue::TB_Horizontal); + } +} + +void BatchQueuePanel::queueSizeChanged (int qsize) { + + // TODO: write it somewhere +} + +void BatchQueuePanel::imageProcessingReady (Glib::ustring fname) { + + parent->imageDeveloped (fname); +} + +void BatchQueuePanel::startBatchProc () { + + stopConnection.block (true); + startConnection.block (true); + stop->set_active (false); + start->set_active (true); + stopConnection.block (false); + startConnection.block (false); + + if (batchQueue->hasJobs()) { + fdir->set_sensitive (false); + fformat->set_sensitive (false); + batchQueue->startProcessing (); + } + else + stopBatchProc (); +} + +void BatchQueuePanel::stopBatchProc () { + + stopConnection.block (true); + startConnection.block (true); + stop->set_active (true); + start->set_active (false); + stopConnection.block (false); + startConnection.block (false); +} + +void BatchQueuePanel::addBatchQueueJob (BatchQueueEntry* bqe, bool head) { + + batchQueue->addEntry (bqe, head); + + if (stop->get_active () && autoStart->get_active ()) + startBatchProc (); +} + +void BatchQueuePanel::queueEmpty () { + + stopBatchProc (); + fdir->set_sensitive (true); + fformat->set_sensitive (true); +} + +bool BatchQueuePanel::canStartNext () { + + if (start->get_active ()) + return true; + else { + fdir->set_sensitive (true); + fformat->set_sensitive (true); + return false; + } +} + +void BatchQueuePanel::saveOptions () { + + options.saveFormat = saveFormatPanel->getFormat (); + options.savePathTemplate = outdirTemplate->get_text(); + options.savePathFolder = outdirFolder->get_filename(); + options.saveUsePathTemplate = useTemplate->get_active(); + options.procQueueEnabled = autoStart->get_active (); +} + +void BatchQueuePanel::formatChanged () { + + saveOptions (); +} diff --git a/rtgui/batchqueuepanel.h b/rtgui/batchqueuepanel.h new file mode 100755 index 000000000..fa7436a70 --- /dev/null +++ b/rtgui/batchqueuepanel.h @@ -0,0 +1,78 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _BATCHQUEUEPANEL_ +#define _BATCHQUEUEPANEL_ + +#include +#include +#include + +class RTWindow; +class BatchQueuePanel : public Gtk::VBox, + public BatchQueueListener, + public FormatChangeListener { + + Gtk::Button* zoomInButton; + Gtk::Button* zoomOutButton; + Gtk::ToggleButton* start; + Gtk::ToggleButton* stop; + Gtk::CheckButton* autoStart; + sigc::connection startConnection; + sigc::connection stopConnection; + + Gtk::Entry* outdirTemplate; + Gtk::FileChooserButton* outdirFolder; + Gtk::RadioButton* useTemplate; + Gtk::RadioButton* useFolder; + SaveFormatPanel* saveFormatPanel; + Gtk::Frame *fdir, *fformat; + + Gtk::Image* hAlignIcon; + Gtk::Image* vAlignIcon; + Gtk::Button* chAlign; + + RTWindow* parent; + BatchQueue* batchQueue; + Gtk::HBox* bottomBox; + Gtk::HBox* topBox; + + public: + + BatchQueuePanel (); + + void setParent (RTWindow* p) { parent = p; } + void arrangementButtonPressed (); + + void addBatchQueueJob (BatchQueueEntry* bqe, bool head=false); + + // batchqueuelistener interface + void queueSizeChanged (int qsize); + void imageProcessingReady (Glib::ustring fname); + void queueEmpty (); + bool canStartNext (); + + void startBatchProc (); + void stopBatchProc (); + + void saveOptions (); + void formatChanged (); +}; + +#endif + diff --git a/rtgui/batchtoolpanelcoord.cc b/rtgui/batchtoolpanelcoord.cc new file mode 100755 index 000000000..72bbea093 --- /dev/null +++ b/rtgui/batchtoolpanelcoord.cc @@ -0,0 +1,295 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include +#include + +using namespace rtengine::procparams; + +BatchToolPanelCoordinator::BatchToolPanelCoordinator (FilePanel* parent) : ToolPanelCoordinator(), parent(parent) { + + // remove exif panel and iptc panel + std::vector::iterator epi = std::find (toolPanels.begin(), toolPanels.end(), exifpanel); + if (epi!=toolPanels.end()) + toolPanels.erase (epi); + std::vector::iterator ipi = std::find (toolPanels.begin(), toolPanels.end(), iptcpanel); + if (ipi!=toolPanels.end()) + toolPanels.erase (ipi); + toolPanelNotebook->remove_page (*metadataPanel); + + for (int i=0; isetBatchMode (true); +} + +void BatchToolPanelCoordinator::selectionChanged (const std::vector& selected) { + + if (selected!=this->selected) { + closeSession (); + this->selected = selected; + selFileNames.clear (); + for (int i=0; igetFileName ()); + initSession (); + } +} + +void BatchToolPanelCoordinator::closeSession (bool save) { + + pparamsEdited.set (false); + + for (int i=0; iremoveThumbnailListener (this); + + if (somethingChanged && save) { + + // read new values from the gui + for (int i=0; iwrite (&pparams, &pparamsEdited); + + // combine with initial parameters and set + ProcParams newParams; + for (int i=0; isetProcParams (newParams, BATCHEDITOR, true); + } + } + for (int i=0; iclearParamChanges (); +} + +void BatchToolPanelCoordinator::initSession () { + + somethingChanged = false; + + initialPP.resize (selected.size()); + for (int i=0; igetProcParams (); + selected[i]->applyAutoExp (initialPP[i]); + selected[i]->addThumbnailListener (this); + } + + pparamsEdited.initFrom (initialPP); + +/* curve->setAdjusterBehavior (false, false, false, false); + whitebalance->setAdjusterBehavior (false, false); + vignetting->setAdjusterBehavior (false); + rotate->setAdjusterBehavior (false); + distortion->setAdjusterBehavior (false); + cacorrection->setAdjusterBehavior (false, false); + colorshift->setAdjusterBehavior (false, false); + colorboost->setAdjusterBehavior (false); + lumadenoise->setAdjusterBehavior (false); + sharpening->setAdjusterBehavior (false); + shadowshighlights->setAdjusterBehavior (false, false, false); +*/ + crop->setDimensions (100000, 100000); + +/* if (selected.size()>0) { + pparams = selected[0]->getProcParams (); + for (int i=0; isetDefaults (&pparams, &pparamsEdited); + toolPanels[i]->read (&pparams, &pparamsEdited); + } + for (int i=0; iprocParamsChanged (&pparams, rtengine::EvPhotoLoaded, "batch processing", &pparamsEdited); + } +*/ + + if (selected.size()>0) { + + pparams = selected[0]->getProcParams (); + coarse->initBatchBehavior (); + + curve->setAdjusterBehavior (options.baBehav[0], options.baBehav[1], options.baBehav[2], options.baBehav[3]); + whitebalance->setAdjusterBehavior (options.baBehav[12], options.baBehav[13]); + vignetting->setAdjusterBehavior (options.baBehav[21]); + rotate->setAdjusterBehavior (options.baBehav[17]); + distortion->setAdjusterBehavior (options.baBehav[18]); + cacorrection->setAdjusterBehavior (options.baBehav[19], options.baBehav[20]); + colorshift->setAdjusterBehavior (options.baBehav[15], options.baBehav[16]); + colorboost->setAdjusterBehavior (options.baBehav[14]); + lumadenoise->setAdjusterBehavior (options.baBehav[11]); + sharpening->setAdjusterBehavior (options.baBehav[10]); + shadowshighlights->setAdjusterBehavior (options.baBehav[4], options.baBehav[5], options.baBehav[6]); + + if (options.baBehav[0]) pparams.toneCurve.expcomp = 0; + if (options.baBehav[1]) pparams.toneCurve.brightness = 0; + if (options.baBehav[2]) pparams.toneCurve.black = 0; + if (options.baBehav[3]) pparams.toneCurve.contrast = 0; + + if (options.baBehav[4]) pparams.sh.highlights = 0; + if (options.baBehav[5]) pparams.sh.shadows = 0; + if (options.baBehav[6]) pparams.sh.localcontrast = 0; + + if (options.baBehav[10]) pparams.sharpening.amount = 0; + if (options.baBehav[11]) pparams.lumaDenoise.edgetolerance = 0; + + if (options.baBehav[12]) pparams.wb.temperature = 0; + if (options.baBehav[13]) pparams.wb.green = 0; + + if (options.baBehav[14]) pparams.colorBoost.amount = 0; + + if (options.baBehav[15]) pparams.colorShift.a = 0; + if (options.baBehav[16]) pparams.colorShift.b = 0; + + if (options.baBehav[17]) pparams.rotate.degree = 0; + if (options.baBehav[18]) pparams.distortion.amount = 0; + if (options.baBehav[19]) pparams.cacorrection.red = 0; + if (options.baBehav[20]) pparams.cacorrection.blue = 0; + if (options.baBehav[21]) pparams.vignetting.amount = 0; + + for (int i=0; isetDefaults (&pparams, &pparamsEdited); + toolPanels[i]->read (&pparams, &pparamsEdited); + } + for (int i=0; iprocParamsChanged (&pparams, rtengine::EvPhotoLoaded, "batch processing", &pparamsEdited); + } +} + +void BatchToolPanelCoordinator::panelChanged (rtengine::ProcEvent event, const Glib::ustring& descr) { + + if (selected.size()==0) + return; + + somethingChanged = true; + + pparamsEdited.set (false); + // read new values from the gui + for (int i=0; iwrite (&pparams, &pparamsEdited); + + if (event==rtengine::EvAutoExp || event==rtengine::EvClip) + for (int i=0; iapplyAutoExp (initialPP[i]); + } + + // combine with initial parameters and set + ProcParams newParams; + for (int i=0; isetProcParams (newParams, BATCHEDITOR, false); + } + + for (int i=0; iprocParamsChanged (&pparams, event, descr, &pparamsEdited); +} + +void BatchToolPanelCoordinator::getAutoWB (double& temp, double& green) { + + if (selected.size()>0) + selected[0]->getAutoWB (temp, green); +} + +void BatchToolPanelCoordinator::getCamWB (double& temp, double& green) { + + if (selected.size()>0) + selected[0]->getCamWB (temp, green); +} + +void BatchToolPanelCoordinator::optionsChanged () { + + closeSession (); + initSession (); +} + +void BatchToolPanelCoordinator::procParamsChanged (Thumbnail* thm, int whoChangedIt) { + + if (whoChangedIt!=BATCHEDITOR) { + closeSession (false); + initSession (); + } +} + +void BatchToolPanelCoordinator::profileChange (const ProcParams *nparams, rtengine::ProcEvent event, const Glib::ustring& descr, const ParamsEdited* paramsEdited) { + + pparams = *nparams; + if (paramsEdited) + pparamsEdited = *paramsEdited; + + for (int i=0; iread (&pparams, &pparamsEdited); + + somethingChanged = true; + + // read new values from the gui + for (int i=0; iwrite (&pparams, &pparamsEdited); + + // combine with initial parameters and set + ProcParams newParams; + for (int i=0; isetProcParams (newParams, BATCHEDITOR, false); + } + + for (int i=0; iprocParamsChanged (&pparams, event, descr, &pparamsEdited); +} + +void BatchToolPanelCoordinator::cropSelectionReady () { + + toolBar->setTool (TMHand); +} + +CropGUIListener* BatchToolPanelCoordinator::startCropEditing (Thumbnail* thm) { + + if (thm) { + int w, h; + thm->getFinalSize (thm->getProcParams (), w, h); + printf ("final=%d %d\n", w, h); + crop->setDimensions (w, h); + } + return crop; +} + +void BatchToolPanelCoordinator::rotateSelectionReady (double rotate_deg, Thumbnail* thm) { + + toolBar->setTool (TMHand); + if (rotate_deg!=0.0) + rotate->straighten (rotate_deg); +} + +void BatchToolPanelCoordinator::spotWBselected (int x, int y, Thumbnail* thm) { + +// toolBar->setTool (TOOL_HAND); + if (x>0 && y>0 && thm) { + for (int i=0; igetSpotWB (x, y, whitebalance->getSize(), temp, green); + double otemp = initialPP[i].wb.temperature; + double ogreen = initialPP[i].wb.green; + if (options.baBehav[12]) + temp = temp - otemp; + if (options.baBehav[13]) + green = green - ogreen; + whitebalance->setWB (temp, green); + } + } +} + diff --git a/rtgui/batchtoolpanelcoord.h b/rtgui/batchtoolpanelcoord.h new file mode 100755 index 000000000..b743275d7 --- /dev/null +++ b/rtgui/batchtoolpanelcoord.h @@ -0,0 +1,76 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef __BATCHTOOLPANELCCORD__ +#define __BATCHTOOLPANELCCORD__ + +#include +#include +#include +#include +#include +#include + +class FilePanel; +class BatchToolPanelCoordinator : + public ToolPanelCoordinator, + public FileSelectionChangeListener, + public ThumbnailListener +{ + protected: + rtengine::procparams::ProcParams pparams; + ParamsEdited pparamsEdited; + std::vector selected; + std::vector selFileNames; + std::vector initialPP; + bool somethingChanged; + FilePanel* parent; + + void closeSession (bool save=true); + void initSession (); + + public: + + BatchToolPanelCoordinator (FilePanel* parent); + + // FileSelectionChangeListener interface + void selectionChanged (const std::vector& selected); + + // toolpanellistener interface + void panelChanged (rtengine::ProcEvent event, const Glib::ustring& descr); + + // profilechangelistener interface + void profileChange (const rtengine::procparams::ProcParams* nparams, rtengine::ProcEvent event, const Glib::ustring& descr, const ParamsEdited* paramsEdited=NULL); + + // wbprovider interface + void getAutoWB (double& temp, double& green); + void getCamWB (double& temp, double& green); + + // thumbnaillistener interface + void procParamsChanged (Thumbnail* thm, int whoChangedIt); + + // imageareatoollistener interface + void spotWBselected (int x, int y, Thumbnail* thm=NULL); + void cropSelectionReady (); + void rotateSelectionReady (double rotate_deg, Thumbnail* thm=NULL); + CropGUIListener* startCropEditing (Thumbnail* thm=NULL); + + void optionsChanged (); +}; + +#endif diff --git a/rtgui/bqentryupdater.cc b/rtgui/bqentryupdater.cc new file mode 100755 index 000000000..e4b9b720e --- /dev/null +++ b/rtgui/bqentryupdater.cc @@ -0,0 +1,137 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include + +BatchQueueEntryUpdater batchQueueEntryUpdater; + +BatchQueueEntryUpdater::BatchQueueEntryUpdater () + : tostop(false), stopped(true), qMutex(NULL) { +} + +void BatchQueueEntryUpdater::add (guint8* oimg, int ow, int oh, int newh, BQEntryUpdateListener* listener) { + + if (!qMutex) + qMutex = new Glib::Mutex (); + + qMutex->lock (); + // look up if an older version is in the queue + std::list::iterator i; + for (i=jqueue.begin(); i!=jqueue.end(); i++) + if (i->oimg==oimg && i->listener==listener) { + i->ow = ow; + i->oh = oh; + i->newh = newh; + i->listener = listener; + break; + } + // not found, create and append new job + if (i==jqueue.end ()) { + Job j; + j.oimg = oimg; + j.ow = ow; + j.oh = oh; + j.newh = newh; + j.listener = listener; + jqueue.push_back (j); + } + qMutex->unlock (); +} + +void BatchQueueEntryUpdater::process () { + + if (stopped) + #undef THREAD_PRIORITY_NORMAL + thread = Glib::Thread::create(sigc::mem_fun(*this, &BatchQueueEntryUpdater::process_), (unsigned long int)0, true, true, Glib::THREAD_PRIORITY_NORMAL); +} + +void BatchQueueEntryUpdater::process_ () { + + stopped = false; + tostop = false; + +// TODO: process visible jobs first + while (!tostop && !jqueue.empty ()) { + qMutex->lock (); + Job current = jqueue.front (); + jqueue.pop_front (); + qMutex->unlock (); + if (current.listener) { + int neww = current.newh * current.ow / current.oh; + guint8* img = new guint8 [current.newh*neww*3]; + thumbInterp (current.oimg, current.ow, current.oh, img, neww, current.newh); + current.listener->updateImage (img, neww, current.newh); + } + } + stopped = true; +} + +void BatchQueueEntryUpdater::stop () { + + if (stopped) { + tostop = true; + return; } + + gdk_threads_leave(); + tostop = true; + Glib::Thread::self()->yield(); + if (!stopped) + thread->join (); + gdk_threads_enter(); +} + +void BatchQueueEntryUpdater::removeJobs () { + + if (!qMutex) + return; + + qMutex->lock (); + while (!jqueue.empty()) + jqueue.pop_front (); + qMutex->unlock (); +} + +void BatchQueueEntryUpdater::removeJobs (BQEntryUpdateListener* listener) { + + if (!qMutex) + return; + + qMutex->lock (); + bool ready = false; + while (!ready) { + ready = true; + std::list::iterator i; + for (i=jqueue.begin(); i!=jqueue.end(); i++) + if (i->listener == listener) { + jqueue.erase (i); + ready = false; + break; + } + } + qMutex->unlock (); +} + +void BatchQueueEntryUpdater::terminate () { + + stop (); + removeJobs (); +} + + diff --git a/rtgui/bqentryupdater.h b/rtgui/bqentryupdater.h new file mode 100755 index 000000000..630180640 --- /dev/null +++ b/rtgui/bqentryupdater.h @@ -0,0 +1,62 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _BQENTRYUPDATER_ +#define _BQENTRYUPDATER_ + +#include +#include +#include + +class BQEntryUpdateListener { + + public: + virtual void updateImage (guint8* img, int w, int h) {} +}; + +class BatchQueueEntryUpdater { + + struct Job { + guint8* oimg; + int ow, oh, newh; + BQEntryUpdateListener* listener; + }; + + protected: + bool tostop; + bool stopped; + std::list jqueue; + Glib::Thread* thread; + Glib::Mutex* qMutex; + + public: + BatchQueueEntryUpdater (); + + void add (guint8* oimg, int ow, int oh, int newh, BQEntryUpdateListener* listener); + void process (); + void stop (); + void removeJobs (); + void removeJobs (BQEntryUpdateListener* listener); + void terminate (); + + void process_ (); +}; + +extern BatchQueueEntryUpdater batchQueueEntryUpdater; + +#endif diff --git a/rtgui/browserfilter.cc b/rtgui/browserfilter.cc new file mode 100755 index 000000000..3d44f113c --- /dev/null +++ b/rtgui/browserfilter.cc @@ -0,0 +1,26 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +BrowserFilter::BrowserFilter () : exifFilterEnabled (false) { + + showTrash = true; + for (int i=0; i<6; i++) + showRanked[i] = true; +} diff --git a/rtgui/browserfilter.h b/rtgui/browserfilter.h new file mode 100755 index 000000000..bfbb7039f --- /dev/null +++ b/rtgui/browserfilter.h @@ -0,0 +1,37 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _BROWSERFILTER_ +#define _BROWSERFILTER_ + +#include + +class BrowserFilter { + + public: + bool showRanked[6]; + bool showTrash; + bool showNotTrash; + + bool exifFilterEnabled; + ExifFilterSettings exifFilter; + + BrowserFilter (); +}; + +#endif diff --git a/rtgui/cacheimagedata.cc b/rtgui/cacheimagedata.cc new file mode 100755 index 000000000..b7e96ff8c --- /dev/null +++ b/rtgui/cacheimagedata.cc @@ -0,0 +1,138 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include + +CacheImageData::CacheImageData () + : md5(""), supported(false), format(FT_Invalid), rank(0), inTrash(false), recentlySaved(false), + timeValid(false), exifValid(false) { +} + +int CacheImageData::load (const Glib::ustring& fname) { + + Glib::KeyFile keyFile; + + try { + if (!keyFile.load_from_file (fname)) + return 1; + + if (keyFile.has_group ("General")) { + if (keyFile.has_key ("General", "MD5")) md5 = keyFile.get_string ("General", "MD5"); + if (keyFile.has_key ("General", "Version")) version = keyFile.get_integer ("General", "Version"); + if (keyFile.has_key ("General", "Supported")) supported = keyFile.get_boolean ("General", "Supported"); + if (keyFile.has_key ("General", "Format")) format = (ThFileType)keyFile.get_integer ("General", "Format"); + if (keyFile.has_key ("General", "Rank")) rank = keyFile.get_integer ("General", "Rank"); + if (keyFile.has_key ("General", "InTrash")) inTrash = keyFile.get_boolean ("General", "InTrash"); + if (keyFile.has_key ("General", "RecentlySaved")) recentlySaved = keyFile.get_boolean ("General", "RecentlySaved"); + } + + timeValid = keyFile.has_group ("DateTime"); + + if (timeValid) { + if (keyFile.has_key ("DateTime", "Year")) year = keyFile.get_integer ("DateTime", "Year"); + if (keyFile.has_key ("DateTime", "Month")) month = keyFile.get_integer ("DateTime", "Month"); + if (keyFile.has_key ("DateTime", "Day")) day = keyFile.get_integer ("DateTime", "Day"); + if (keyFile.has_key ("DateTime", "Hour")) hour = keyFile.get_integer ("DateTime", "Hour"); + if (keyFile.has_key ("DateTime", "Min")) min = keyFile.get_integer ("DateTime", "Min"); + if (keyFile.has_key ("DateTime", "Sec")) sec = keyFile.get_integer ("DateTime", "Sec"); + if (keyFile.has_key ("DateTime", "MSec")) msec = keyFile.get_integer ("DateTime", "MSec"); + } + + exifValid = false; + + if (keyFile.has_group ("ExifInfo")) { + exifValid = true; + if (keyFile.has_key ("ExifInfo", "Valid")) exifValid = keyFile.get_boolean ("ExifInfo", "Valid"); + + if (exifValid) { + if (keyFile.has_key ("ExifInfo", "FNumber")) fnumber = keyFile.get_double ("ExifInfo", "FNumber"); + if (keyFile.has_key ("ExifInfo", "Shutter")) shutter = keyFile.get_double ("ExifInfo", "Shutter"); + if (keyFile.has_key ("ExifInfo", "FocalLen")) focalLen = keyFile.get_double ("ExifInfo", "FocalLen"); + if (keyFile.has_key ("ExifInfo", "ISO")) iso = keyFile.get_integer ("ExifInfo", "ISO"); + } + if (keyFile.has_key ("ExifInfo", "Lens")) lens = keyFile.get_string ("ExifInfo", "Lens"); + if (keyFile.has_key ("ExifInfo", "Camera")) camera = keyFile.get_string ("ExifInfo", "Camera"); + } + + if (format==FT_Raw && keyFile.has_group ("ExtraRawInfo")) { + if (keyFile.has_key ("ExtraRawInfo", "ThumbImageType")) thumbImgType = keyFile.get_integer ("ExtraRawInfo", "ThumbImageType"); + if (keyFile.has_key ("ExtraRawInfo", "ThumbImageOffset")) thumbOffset = keyFile.get_integer ("ExtraRawInfo", "ThumbImageOffset"); + } + else { + rotate = 0; + thumbImgType = 0; + } + return 0; + } + catch (Glib::Error) { + return 1; + } +} + +int CacheImageData::save (const Glib::ustring& fname) { + + Glib::KeyFile keyFile; + + try { + keyFile.load_from_file (fname); + } catch (...) {} + + keyFile.set_string ("General", "MD5", md5); + keyFile.set_integer ("General", "Version", options.version); + keyFile.set_boolean ("General", "Supported", supported); + keyFile.set_integer ("General", "Format", format); + keyFile.set_integer ("General", "Rank", rank); + keyFile.set_boolean ("General", "InTrash", inTrash); + keyFile.set_boolean ("General", "RecentlySaved", recentlySaved); + + if (timeValid) { + keyFile.set_integer ("DateTime", "Year", year); + keyFile.set_integer ("DateTime", "Month", month); + keyFile.set_integer ("DateTime", "Day", day); + keyFile.set_integer ("DateTime", "Hour", hour); + keyFile.set_integer ("DateTime", "Min", min); + keyFile.set_integer ("DateTime", "Sec", sec); + keyFile.set_integer ("DateTime", "MSec", msec); + } + + keyFile.set_boolean ("ExifInfo", "Valid", exifValid); + if (exifValid) { + keyFile.set_double ("ExifInfo", "FNumber", fnumber); + keyFile.set_double ("ExifInfo", "Shutter", shutter); + keyFile.set_double ("ExifInfo", "FocalLen", focalLen); + keyFile.set_integer ("ExifInfo", "ISO", iso); + } + keyFile.set_string ("ExifInfo", "Lens", lens); + keyFile.set_string ("ExifInfo", "Camera", camera); + + if (format==FT_Raw) { + keyFile.set_integer ("ExtraRawInfo", "ThumbImageType", thumbImgType); + keyFile.set_integer ("ExtraRawInfo", "ThumbImageOffset", thumbOffset); + } + + FILE *f = g_fopen (fname.c_str(), "wt"); + if (!f) + return 1; + else { + fprintf (f, "%s", keyFile.to_data().c_str()); + fclose (f); + return 0; + } } + diff --git a/rtgui/cacheimagedata.h b/rtgui/cacheimagedata.h new file mode 100755 index 000000000..2ac4b42bf --- /dev/null +++ b/rtgui/cacheimagedata.h @@ -0,0 +1,67 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _CACHEIMAGEDATA_ +#define _CACHEIMAGEDATA_ + +#include +#include + +class CacheImageData { + + public: + + // basic informations + Glib::ustring md5; + int version; + bool supported; + ThFileType format; + char rank; + bool inTrash; + bool recentlySaved; + + // time/date info + bool timeValid; + short year; + char month; + char day; + char hour; + char min; + char sec; + char msec; + + // exif info + bool exifValid; + double fnumber; + double shutter; + double focalLen; + unsigned iso; + Glib::ustring lens; + Glib::ustring camera; + + // additional info on raw images + int rotate; + int thumbImgType; + int thumbOffset; + + CacheImageData (); + + int load (const Glib::ustring& fname); + int save (const Glib::ustring& fname); +}; +#endif diff --git a/rtgui/cachemanager.cc b/rtgui/cachemanager.cc new file mode 100755 index 000000000..9b7b44fd6 --- /dev/null +++ b/rtgui/cachemanager.cc @@ -0,0 +1,279 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include +#include +#include + +CacheManager cacheMgr; + +void CacheManager::init () { + + openEntries.clear (); + baseDir = options.cacheBaseDir; + + if (!Glib::file_test (baseDir, Glib::FILE_TEST_IS_DIR)) + g_mkdir_with_parents (baseDir.c_str(), 511); + if (!Glib::file_test (Glib::build_filename (baseDir, "profiles"), Glib::FILE_TEST_IS_DIR)) + g_mkdir_with_parents (Glib::ustring(Glib::build_filename (baseDir, "profiles")).c_str(), 511); + if (!Glib::file_test (Glib::build_filename (baseDir, "images"), Glib::FILE_TEST_IS_DIR)) + g_mkdir_with_parents (Glib::ustring(Glib::build_filename (baseDir, "images")).c_str(), 511); + if (!Glib::file_test (Glib::build_filename (baseDir, "aehistograms"), Glib::FILE_TEST_IS_DIR)) + g_mkdir_with_parents (Glib::ustring(Glib::build_filename (baseDir, "aehistograms")).c_str(), 511); + if (!Glib::file_test (Glib::build_filename (baseDir, "embprofiles"), Glib::FILE_TEST_IS_DIR)) + g_mkdir_with_parents (Glib::ustring(Glib::build_filename (baseDir, "embprofiles")).c_str(), 511); + if (!Glib::file_test (Glib::build_filename (baseDir, "data"), Glib::FILE_TEST_IS_DIR)) + g_mkdir_with_parents (Glib::ustring(Glib::build_filename (baseDir, "data")).c_str(), 511); +} + +Thumbnail* CacheManager::getEntry (const Glib::ustring& fname) { + + Thumbnail* res = NULL; + + std::map::iterator r = openEntries.find (fname); + // if it is open, return it + if (r!=openEntries.end()) { + r->second->increaseRef (); + return r->second; + } + + // compute the md5 + std::string md5 = getMD5 (fname); + if (md5=="") + return NULL; + + // build path name + Glib::ustring cfname = getCacheFileName ("data", fname, md5) + ".txt"; + + // let's see if we have it in the cache + if (Glib::file_test (cfname, Glib::FILE_TEST_EXISTS)) { + CacheImageData* cfs = new CacheImageData (); + int e = cfs->load (cfname); + if (!e && cfs->supported==true) + res = new Thumbnail (this, fname, cfs); + if (res && !res->isSupported ()) { + delete res; + res = NULL; + } + delete cfs; + } + // if not, create a new one + if (!res) { + res = new Thumbnail (this, fname, md5); + if (!res->isSupported ()) { + delete res; + res = NULL; + } + } + + if (res) + openEntries[fname] = res; + return res; +} + + +void CacheManager::deleteEntry (const Glib::ustring& fname) { + + // check if it is opened + std::map::iterator r = openEntries.find (fname); + // if it is open, dont delete it + if (r!=openEntries.end()) { + std::string md5 = r->second->getMD5 (); + r->second->decreaseRef (); + // if in the editor, the thumbnail still exists. If not, delete it: + r = openEntries.find (fname); + if (r==openEntries.end() && md5!="") { + ::g_remove ((getCacheFileName ("data", fname, md5) + ".txt").c_str()); + ::g_remove ((getCacheFileName ("profiles", fname, md5) + ".pp2").c_str()); + ::g_remove ((getCacheFileName ("images", fname, md5) + ".cust").c_str()); + ::g_remove ((getCacheFileName ("images", fname, md5) + ".jpg").c_str()); + ::g_remove ((getCacheFileName ("aehistograms", fname, md5)).c_str()); + ::g_remove ((getCacheFileName ("embprofiles", fname, md5) + ".icc").c_str()); + } + } + else { + std::string md5 = getMD5 (fname); + if (md5!="") { + ::g_remove ((getCacheFileName ("data", fname, md5) + ".txt").c_str()); + ::g_remove ((getCacheFileName ("profiles", fname, md5) + ".pp2").c_str()); + ::g_remove ((getCacheFileName ("images", fname, md5) + ".cust").c_str()); + ::g_remove ((getCacheFileName ("images", fname, md5) + ".jpg").c_str()); + ::g_remove ((getCacheFileName ("aehistograms", fname, md5)).c_str()); + ::g_remove ((getCacheFileName ("embprofiles", fname, md5) + ".icc").c_str()); + } + } +} + + +void CacheManager::renameEntry (const std::string& oldfilename, const std::string& oldmd5, const std::string& newfilename) { + + std::string newmd5 = getMD5 (newfilename); + + ::g_rename ((getCacheFileName ("profiles", oldfilename, oldmd5) + ".pp2").c_str(), (getCacheFileName ("profiles", newfilename, newmd5) + ".pp2").c_str()); + ::g_rename ((getCacheFileName ("images", oldfilename, oldmd5) + ".cust").c_str(), (getCacheFileName ("images", newfilename, newmd5) + ".cust").c_str()); + ::g_rename ((getCacheFileName ("images", oldfilename, oldmd5) + ".jpg").c_str(), (getCacheFileName ("images", newfilename, newmd5) + ".jpg").c_str()); + ::g_rename ((getCacheFileName ("aehistograms", oldfilename, oldmd5)).c_str(), (getCacheFileName ("aehistograms", newfilename, newmd5)).c_str()); + ::g_rename ((getCacheFileName ("embprofiles", oldfilename, oldmd5) + ".icc").c_str(), (getCacheFileName ("embprofiles", newfilename, newmd5) + ".icc").c_str()); + ::g_rename ((getCacheFileName ("data", oldfilename, oldmd5) + ".txt").c_str(), (getCacheFileName ("data", newfilename, newmd5) + ".txt").c_str()); + + // check if it is opened + std::map::iterator r = openEntries.find (oldfilename); + // if it is open, update md5 + if (r!=openEntries.end()) { + Thumbnail* t = r->second; + openEntries.erase (r); + t->setFileName (newfilename); + openEntries[newfilename] = t; + t->updateCache (); + t->reSaveThumbnail (); + } +} + +void CacheManager::closeThumbnail (Thumbnail* t) { + + t->updateCache (); + std::map::iterator r = openEntries.find (t->getFileName()); + if (r!=openEntries.end()) + openEntries.erase (r); + delete t; +} + +void CacheManager::closeCache () { + + applyCacheSizeLimitation (); +} + +void CacheManager::clearAll () { + + deleteDir ("images"); + deleteDir ("aehistograms"); + deleteDir ("embprofiles"); + deleteDir ("profiles"); + deleteDir ("data"); + + // re-generate thumbnail images and clear profiles of open thumbnails + std::map::iterator i; + for (i=openEntries.begin(); i!=openEntries.end(); i++) { + i->second->clearProcParams (CACHEMGR); + i->second->generateThumbnailImage (); + i->second->updateCache (); + } +} +void CacheManager::clearThumbImages () { + + deleteDir ("images"); + deleteDir ("aehistograms"); + deleteDir ("embprofiles"); + + // re-generate thumbnail images of open thumbnails + std::map::iterator i; + for (i=openEntries.begin(); i!=openEntries.end(); i++) + i->second->generateThumbnailImage (); +} + +void CacheManager::clearProfiles () { + + deleteDir ("profiles"); + // clear profiles of open thumbnails + std::map::iterator i; + for (i=openEntries.begin(); i!=openEntries.end(); i++) + i->second->clearProcParams (CACHEMGR); +} + +void CacheManager::deleteDir (const Glib::ustring& dirName) { + + try { + Glib::Dir* dir = new Glib::Dir (Glib::build_filename (baseDir, dirName)); + for (Glib::DirIterator i = dir->begin(); i!=dir->end(); ++i) + ::g_remove (Glib::build_filename (Glib::build_filename (baseDir, dirName), *i).c_str()); + delete dir; + } + catch (const Glib::FileError& fe) { + } +} + +std::string CacheManager::getMD5 (const Glib::ustring& fname) { + + try { + Glib::RefPtr file = Gio::File::create_for_path (fname); + if (!file) + return ""; + Glib::RefPtr info = file->query_info(); + if (!info) + return ""; + else + return Glib::Checksum::compute_checksum (Glib::Checksum::CHECKSUM_MD5, Glib::ustring::compose ("%1%2", fname, info->get_size())); + } + catch (...) { + return ""; + } +} + +Glib::ustring CacheManager::getCacheFileName (const Glib::ustring& subdir, const Glib::ustring& fname, const Glib::ustring& md5) { + + Glib::ustring cfn = Glib::build_filename (baseDir, subdir); + Glib::ustring cname = Glib::path_get_basename (fname) + "." + md5; + return Glib::build_filename (cfn, cname); +} + +class FileMTimeInfo { + + public: + Glib::ustring fname; + Glib::TimeVal mtime; + + FileMTimeInfo (Glib::ustring name, Glib::TimeVal mtime) : fname(name), mtime(mtime) {} + bool operator<(const FileMTimeInfo& other) const { return mtime flist; + try { + Glib::ustring dataDir = Glib::build_filename (baseDir, "data"); + Glib::RefPtr dir = Gio::File::create_for_path (dataDir); + if (!dir) + return; + Glib::RefPtr dirList = dir->enumerate_children (); + if (!dirList) + return; + + for (Glib::RefPtr info = dirList->next_file(); info; info = dirList->next_file()) + flist.push_back (FileMTimeInfo (removeExtension(info->get_name()), info->modification_time())); + if (flist.size() > options.maxCacheEntries) { + std::sort (flist.begin(), flist.end()); + while (flist.size() > options.maxCacheEntries) { + ::g_remove ((Glib::build_filename (Glib::build_filename (baseDir, "data"), flist.front().fname) + ".txt").c_str()); + ::g_remove ((Glib::build_filename (Glib::build_filename (baseDir, "images"), flist.front().fname) + ".cust").c_str()); + ::g_remove ((Glib::build_filename (Glib::build_filename (baseDir, "images"), flist.front().fname) + ".jpg").c_str()); + ::g_remove ((Glib::build_filename (Glib::build_filename (baseDir, "aehistograms"), flist.front().fname)).c_str()); + ::g_remove ((Glib::build_filename (Glib::build_filename (baseDir, "embprofiles"), flist.front().fname) + ".icc").c_str()); +// ::g_remove ((Glib::build_filename (Glib::build_filename (baseDir, "profiles"), flist.front().fname) + ".pp2").c_str()); + flist.erase (flist.begin()); + } + } + } + catch (Glib::Exception& ex) { + printf ("%s\n", ex.what().c_str()); + } + +} + diff --git a/rtgui/cachemanager.h b/rtgui/cachemanager.h new file mode 100755 index 000000000..d99d2a5ef --- /dev/null +++ b/rtgui/cachemanager.h @@ -0,0 +1,64 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _CACHEMANAGER_ +#define _CACHEMANAGER_ + +#include +#include +#include +#include +#include + +class Thumbnail; + +class CacheManager { + + std::map openEntries; + Glib::ustring baseDir; + + void deleteDir (const Glib::ustring& dirName); + + public: + CacheManager () {} + + void init (); + Thumbnail* getEntry (const Glib::ustring& fname); + void deleteEntry (const Glib::ustring& fname); + void renameEntry (const std::string& oldfilename, const std::string& oldmd5, const std::string& newfilename); + + void closeThumbnail (Thumbnail* t); + + const Glib::ustring& getBaseDir () { return baseDir; } + void closeCache (); + + static std::string getMD5 (const Glib::ustring& fname); + + void clearAll (); + void clearThumbImages (); + void clearProfiles (); + + void applyCacheSizeLimitation (); + + Glib::ustring getCacheFileName (const Glib::ustring& subdir, const Glib::ustring& fname, const Glib::ustring& md5); +}; + +extern CacheManager cacheMgr; + +#endif + diff --git a/rtgui/cacorrection.cc b/rtgui/cacorrection.cc new file mode 100755 index 000000000..c727a57f5 --- /dev/null +++ b/rtgui/cacorrection.cc @@ -0,0 +1,103 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +using namespace rtengine; +using namespace rtengine::procparams; + +CACorrection::CACorrection () : valaAdd(false), valbAdd(false) { + + red = Gtk::manage (new Adjuster (M("TP_CACORRECTION_RED"), -0.005, 0.005, 0.0001, 0)); + red->setAdjusterListener (this); + + blue = Gtk::manage (new Adjuster (M("TP_CACORRECTION_BLUE"), -0.005, 0.005, 0.0001, 0)); + blue->setAdjusterListener (this); + + pack_start (*red); + pack_start (*blue); + + show_all(); +} + +void CACorrection::read (const ProcParams* pp, const ParamsEdited* pedited) { + + disableListener (); + + if (pedited) { + red->setEditedState (pedited->cacorrection.red ? Edited : UnEdited); + blue->setEditedState (pedited->cacorrection.blue ? Edited : UnEdited); + } + + red->setValue (pp->cacorrection.red); + blue->setValue (pp->cacorrection.blue); + + enableListener (); +} + +void CACorrection::write (ProcParams* pp, ParamsEdited* pedited) { + + pp->cacorrection.red = red->getValue (); + pp->cacorrection.blue = blue->getValue (); + + if (pedited) { + pedited->cacorrection.red = red->getEditedState (); + pedited->cacorrection.blue = blue->getEditedState (); + } +} + +void CACorrection::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { + + red->setDefault (defParams->cacorrection.red); + blue->setDefault (defParams->cacorrection.blue); + + if (pedited) { + red->setDefaultEditedState (pedited->cacorrection.red ? Edited : UnEdited); + blue->setDefaultEditedState (pedited->cacorrection.blue ? Edited : UnEdited); + } + else { + red->setDefaultEditedState (Irrelevant); + blue->setDefaultEditedState (Irrelevant); + } +} + +void CACorrection::adjusterChanged (Adjuster* a, double newval) { + + if (listener) + listener->panelChanged (EvCACorr, Glib::ustring::compose ("%1=%3\n%2=%4", M("TP_CACORRECTION_RED"), M("TP_CACORRECTION_BLUE"), Glib::ustring::format (std::setw(5), std::fixed, std::setprecision(4), red->getValue()), Glib::ustring::format (std::setw(5), std::fixed, std::setprecision(4), blue->getValue()))); +} + +void CACorrection::setAdjusterBehavior (bool baadd, bool bbadd) { + + if (!valaAdd && baadd || valaAdd && !baadd) + red->setLimits (-0.005, 0.005, 0.0001, 0); + + if (!valbAdd && bbadd || valbAdd && !bbadd) + blue->setLimits (-0.005, 0.005, 0.0001, 0); + + valaAdd = baadd; + valbAdd = bbadd; +} + +void CACorrection::setBatchMode (bool batchMode) { + + ToolPanel::setBatchMode (batchMode); + red->showEditedCB (); + blue->showEditedCB (); +} diff --git a/rtgui/cacorrection.h b/rtgui/cacorrection.h new file mode 100755 index 000000000..d51dd73f0 --- /dev/null +++ b/rtgui/cacorrection.h @@ -0,0 +1,46 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _CACORRECTION_H_ +#define _CACORRECTION_H_ + +#include +#include +#include + +class CACorrection : public Gtk::VBox, public AdjusterListener, public ToolPanel { + + protected: + Adjuster* red; + Adjuster* blue; + bool valaAdd, valbAdd; + + public: + + CACorrection (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + + void adjusterChanged (Adjuster* a, double newval); + void setAdjusterBehavior (bool baadd, bool bbadd); +}; + +#endif diff --git a/rtgui/chmixer.cc b/rtgui/chmixer.cc new file mode 100755 index 000000000..10544f5f2 --- /dev/null +++ b/rtgui/chmixer.cc @@ -0,0 +1,151 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +using namespace rtengine; +using namespace rtengine::procparams; + +ChMixer::ChMixer () { + + Gtk::Label* rlabel = Gtk::manage (new Gtk::Label ()); + rlabel->set_markup (Glib::ustring("") + M("TP_CHMIXER_RED") + Glib::ustring(":")); + + red[0] = Gtk::manage (new Adjuster (M("TP_CHMIXER_RED"), -200, 200, 1, 100)); + red[1] = Gtk::manage (new Adjuster (M("TP_CHMIXER_GREEN"), -200, 200, 1, 0)); + red[2] = Gtk::manage (new Adjuster (M("TP_CHMIXER_BLUE"), -200, 200, 1, 0)); + + Gtk::HSeparator* rsep = Gtk::manage (new Gtk::HSeparator ()); + + pack_start (*rlabel); + for (int i=0; i<3; i++) + pack_start (*red[i]); + pack_start (*rsep); + + Gtk::Label* glabel = Gtk::manage (new Gtk::Label ()); + glabel->set_markup (Glib::ustring("") + M("TP_CHMIXER_GREEN") + Glib::ustring(":")); + + green[0] = Gtk::manage (new Adjuster (M("TP_CHMIXER_RED"), -200, 200, 1, 0)); + green[1] = Gtk::manage (new Adjuster (M("TP_CHMIXER_GREEN"), -200, 200, 1, 100)); + green[2] = Gtk::manage (new Adjuster (M("TP_CHMIXER_BLUE"), -200, 200, 1, 0)); + + Gtk::HSeparator* gsep = Gtk::manage (new Gtk::HSeparator ()); + + pack_start (*glabel); + for (int i=0; i<3; i++) + pack_start (*green[i]); + pack_start (*gsep); + + Gtk::Label* blabel = Gtk::manage (new Gtk::Label ()); + blabel->set_markup (Glib::ustring("") + M("TP_CHMIXER_BLUE") + Glib::ustring(":")); + + blue[0] = Gtk::manage (new Adjuster (M("TP_CHMIXER_RED"), -200, 200, 1, 0)); + blue[1] = Gtk::manage (new Adjuster (M("TP_CHMIXER_GREEN"), -200, 200, 1, 0)); + blue[2] = Gtk::manage (new Adjuster (M("TP_CHMIXER_BLUE"), -200, 200, 1, 100)); + + for (int i=0; i<3; i++) { + red[i]->setAdjusterListener (this); + green[i]->setAdjusterListener (this); + blue[i]->setAdjusterListener (this); + } + + pack_start (*blabel); + for (int i=0; i<3; i++) + pack_start (*blue[i]); + + show_all(); +} + +void ChMixer::read (const ProcParams* pp, const ParamsEdited* pedited) { + + disableListener (); + + if (pedited) + for (int i=0; i<3; i++) { + red[i]->setEditedState (pedited->chmixer.red[i] ? Edited : UnEdited); + green[i]->setEditedState (pedited->chmixer.green[i] ? Edited : UnEdited); + blue[i]->setEditedState (pedited->chmixer.blue[i] ? Edited : UnEdited); + } + + for (int i=0; i<3; i++) { + red[i]->setValue (pp->chmixer.red[i]); + green[i]->setValue (pp->chmixer.green[i]); + blue[i]->setValue (pp->chmixer.blue[i]); + } + + enableListener (); +} + +void ChMixer::write (ProcParams* pp, ParamsEdited* pedited) { + + for (int i=0; i<3; i++) { + pp->chmixer.red[i] = (int) red[i]->getValue (); + pp->chmixer.green[i] = (int) green[i]->getValue (); + pp->chmixer.blue[i] = (int) blue[i]->getValue (); + } + + if (pedited) + for (int i=0; i<3; i++) { + pedited->chmixer.red[i] = red[i]->getEditedState (); + pedited->chmixer.green[i] = green[i]->getEditedState (); + pedited->chmixer.blue[i] = blue[i]->getEditedState (); + } +} + +void ChMixer::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { + + for (int i=0; i<3; i++) { + red[i]->setDefault (defParams->chmixer.red[i]); + green[i]->setDefault (defParams->chmixer.green[i]); + blue[i]->setDefault (defParams->chmixer.blue[i]); + } + + if (pedited) + for (int i=0; i<3; i++) { + red[i]->setDefaultEditedState (pedited->chmixer.red[i] ? Edited : UnEdited); + green[i]->setDefaultEditedState (pedited->chmixer.green[i] ? Edited : UnEdited); + blue[i]->setDefaultEditedState (pedited->chmixer.blue[i] ? Edited : UnEdited); + } + else + for (int i=0; i<3; i++) { + red[i]->setDefaultEditedState (Irrelevant); + green[i]->setDefaultEditedState (Irrelevant); + blue[i]->setDefaultEditedState (Irrelevant); + } +} + +void ChMixer::adjusterChanged (Adjuster* a, double newval) { + + if (listener) { + Glib::ustring descr = Glib::ustring::compose ("R=%1,%2,%3\nG=%4,%5,%6\nB=%7,%8,%9", + (int)red[0]->getValue(), (int)red[1]->getValue(), (int)red[2]->getValue(), + (int)green[0]->getValue(), (int)green[1]->getValue(), (int)green[2]->getValue(), + (int)blue[0]->getValue(), (int)blue[1]->getValue(), (int)blue[2]->getValue()); + listener->panelChanged (EvChMixer, descr); + } +} + +void ChMixer::setBatchMode (bool batchMode) { + + ToolPanel::setBatchMode (batchMode); + for (int i=0; i<3; i++) { + red[i]->showEditedCB (); + green[i]->showEditedCB (); + blue[i]->showEditedCB (); + } +} diff --git a/rtgui/chmixer.h b/rtgui/chmixer.h new file mode 100755 index 000000000..b84ba222f --- /dev/null +++ b/rtgui/chmixer.h @@ -0,0 +1,45 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _CHMIXER_H_ +#define _CHMIXER_H_ + +#include +#include +#include + +class ChMixer : public Gtk::VBox, public AdjusterListener, public ToolPanel { + + protected: + Adjuster *red[3]; + Adjuster *green[3]; + Adjuster *blue[3]; + + public: + + ChMixer (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + + void adjusterChanged (Adjuster* a, double newval); +}; + +#endif diff --git a/rtgui/clipboard.cc b/rtgui/clipboard.cc new file mode 100755 index 000000000..48a8822f4 --- /dev/null +++ b/rtgui/clipboard.cc @@ -0,0 +1,21 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +Clipboard clipboard; diff --git a/rtgui/clipboard.h b/rtgui/clipboard.h new file mode 100755 index 000000000..76a386c3f --- /dev/null +++ b/rtgui/clipboard.h @@ -0,0 +1,44 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _CLIPBOARD_ +#define _CLIPBOARD_ + +#include +#include + +class Clipboard { + + bool _hasIPTC; + std::vector iptc; + bool _hasProcParams; + rtengine::procparams::ProcParams procParams; + + public: + void setIPTC (const std::vector& iptcc) { iptc = iptcc; _hasIPTC = true;} + const std::vector& getIPTC () { return iptc; } + bool hasIPTC () { return _hasIPTC; } + + void setProcParams (const rtengine::procparams::ProcParams& pparams) { procParams = pparams; _hasProcParams = true; } + const rtengine::procparams::ProcParams& getProcParams () { return procParams; } + bool hasProcParams () { return _hasProcParams; } +}; + +extern Clipboard clipboard; + +#endif diff --git a/rtgui/coarsepanel.cc b/rtgui/coarsepanel.cc new file mode 100755 index 000000000..775ffab05 --- /dev/null +++ b/rtgui/coarsepanel.cc @@ -0,0 +1,148 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +extern Glib::ustring argv0; + +using namespace rtengine; +using namespace rtengine::procparams; + +CoarsePanel::CoarsePanel () : ToolPanel () { + + degree = 0; + + Gtk::Image* rotateli = Gtk::manage (new Gtk::Image (argv0+"/images/stock-rotate-270-16.png")); + rotate_left = Gtk::manage (new Gtk::Button ()); + rotate_left->add (*rotateli); + rotate_left->set_relief(Gtk::RELIEF_NONE); + pack_start (*rotate_left); + + Gtk::Image* rotateri = Gtk::manage (new Gtk::Image (argv0+"/images/stock-rotate-90-16.png")); + rotate_right = Gtk::manage (new Gtk::Button ()); + rotate_right->add (*rotateri); + rotate_right->set_relief(Gtk::RELIEF_NONE); + pack_start (*rotate_right); + + Gtk::Image* fliphi = Gtk::manage (new Gtk::Image (argv0+"/images/stock-flip-horizontal-16.png")); + hflip = Gtk::manage (new Gtk::ToggleButton ()); + hflip->add (*fliphi); + hflip->set_relief(Gtk::RELIEF_NONE); + pack_start (*hflip); + + Gtk::Image* flipvi = Gtk::manage (new Gtk::Image (argv0+"/images/stock-flip-vertical-16.png")); + vflip = Gtk::manage (new Gtk::ToggleButton ()); + vflip->add (*flipvi); + vflip->set_relief(Gtk::RELIEF_NONE); + pack_start (*vflip); + + rotate_left->set_tooltip_text (M("TP_COARSETRAF_TOOLTIP_ROTLEFT")); + rotate_right->set_tooltip_text (M("TP_COARSETRAF_TOOLTIP_ROTRIGHT")); + vflip->set_tooltip_text (M("TP_COARSETRAF_TOOLTIP_VFLIP")); + hflip->set_tooltip_text (M("TP_COARSETRAF_TOOLTIP_HFLIP")); + + rotate_left->signal_pressed().connect( sigc::mem_fun(*this, &CoarsePanel::rotateLeft) ); + rotate_right->signal_pressed().connect( sigc::mem_fun(*this, &CoarsePanel::rotateRight) ); + hflip->signal_toggled().connect( sigc::mem_fun(*this, &CoarsePanel::flipHorizontal) ); + vflip->signal_toggled().connect( sigc::mem_fun(*this, &CoarsePanel::flipVertical) ); + + show_all_children (); +} + +void CoarsePanel::read (const ProcParams* pp, const ParamsEdited* pedited) { + + disableListener (); + + if (pedited) { + degree = 0; + hflip->set_active (pedited->coarse.hflip ? pp->coarse.hflip : false); + vflip->set_active (pedited->coarse.vflip ? pp->coarse.vflip : false); + oldhflip = pp->coarse.hflip; + oldvflip = pp->coarse.vflip; + } + else { + degree = pp->coarse.rotate; + hflip->set_active (pp->coarse.hflip); + vflip->set_active (pp->coarse.vflip); + } + enableListener (); +} + +void CoarsePanel::write (ProcParams* pp, ParamsEdited* pedited) { + + pp->coarse.rotate = degree; + + if (pedited) { + pedited->coarse.rotate = degree!=0; + pedited->coarse.hflip = oldhflip != hflip->get_active (); + pedited->coarse.vflip = oldvflip != vflip->get_active (); + pp->coarse.hflip = oldhflip != hflip->get_active (); + pp->coarse.vflip = oldvflip != vflip->get_active (); + } + else { + pp->coarse.hflip = hflip->get_active (); + pp->coarse.vflip = vflip->get_active (); + } +} + +void CoarsePanel::initBatchBehavior () { + + disableListener (); + + degree = 0; + hflip->set_active (false); + vflip->set_active (false); + + enableListener (); +} + +void CoarsePanel::rotateLeft () { + + degree = (degree + 270) % 360; + if (listener) + listener->panelChanged (EvCTRotate, Glib::ustring::format (degree)); +} + +void CoarsePanel::rotateRight () { + + degree = (degree + 90) % 360; + if (listener) + listener->panelChanged (EvCTRotate, Glib::ustring::format (degree)); +} + +void CoarsePanel::flipHorizontal () { + + if (listener) { + if (hflip->get_active ()) + listener->panelChanged (EvCTHFlip, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvCTHFlip, M("GENERAL_DISABLED")); + } +} + +void CoarsePanel::flipVertical () { + + if (listener) { + if (vflip->get_active ()) + listener->panelChanged (EvCTVFlip, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvCTVFlip, M("GENERAL_DISABLED")); + } +} + + diff --git a/rtgui/coarsepanel.h b/rtgui/coarsepanel.h new file mode 100755 index 000000000..0811b151a --- /dev/null +++ b/rtgui/coarsepanel.h @@ -0,0 +1,49 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef __COARSEPANEL__ +#define __COARSEPANEL__ + +#include +#include + +class CoarsePanel : public Gtk::HBox, public ToolPanel { + + protected: + Gtk::Button* rotate_left; + Gtk::Button* rotate_right; + Gtk::ToggleButton* hflip; + Gtk::ToggleButton* vflip; + int degree; + bool oldhflip, oldvflip; + + public: + + CoarsePanel (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void initBatchBehavior (); + + void rotateLeft (); + void rotateRight (); + void flipHorizontal (); + void flipVertical (); +}; + +#endif diff --git a/rtgui/colorboost.cc b/rtgui/colorboost.cc new file mode 100755 index 000000000..6221b675a --- /dev/null +++ b/rtgui/colorboost.cc @@ -0,0 +1,191 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include + +using namespace rtengine; +using namespace rtengine::procparams; + +ColorBoost::ColorBoost () : ToolPanel(), cbAdd(false) { + + colorboost = new Adjuster (M("TP_COLORBOOST_AMOUNT"), -100, 300, 1, 0); + + pack_start (*colorboost); + pack_start (*Gtk::manage (new Gtk::HSeparator())); + + avoidclip = Gtk::manage (new Gtk::CheckButton (M("TP_COLORBOOST_AVOIDCOLORCLIP"))); + + pack_start (*avoidclip); + pack_start (*Gtk::manage (new Gtk::HSeparator())); + + enablelimiter = Gtk::manage (new Gtk::CheckButton (M("TP_COLORBOOST_ENABLESATLIMITER"))); + pack_start (*enablelimiter); + + saturationlimiter = new Adjuster (M("TP_COLORBOOST_SATLIMIT"), 0, 200, 0.1, 100); + saturationlimiter->show (); + saturationlimiter->reference (); + + colorboost->setAdjusterListener (this); + saturationlimiter->setAdjusterListener (this); + acconn = avoidclip->signal_toggled().connect( sigc::mem_fun(*this, &ColorBoost::avoidclip_toggled) ); + elconn = enablelimiter->signal_toggled().connect( sigc::mem_fun(*this, &ColorBoost::enablelimiter_toggled) ); + + show_all_children (); +} + +ColorBoost::~ColorBoost () { + + delete saturationlimiter; +} + +void ColorBoost::read (const ProcParams* pp, const ParamsEdited* pedited) { + + disableListener (); + + if (pedited) { + colorboost->setEditedState (pedited->colorBoost.amount ? Edited : UnEdited); + saturationlimiter->setEditedState (pedited->colorBoost.saturationlimit ? Edited : UnEdited); + avoidclip->set_inconsistent (!pedited->colorBoost.avoidclip); + enablelimiter->set_inconsistent (!pedited->colorBoost.enable_saturationlimiter); + } + + colorboost->setValue (pp->colorBoost.amount); + saturationlimiter->setValue (pp->colorBoost.saturationlimit); + acconn.block (true); + avoidclip->set_active (pp->colorBoost.avoidclip); + acconn.block (false); + elconn.block (true); + enablelimiter->set_active (pp->colorBoost.enable_saturationlimiter); + elconn.block (false); + + removeIfThere (this, saturationlimiter, false); + if (enablelimiter->get_active () || enablelimiter->get_inconsistent()) + pack_start (*saturationlimiter); + + lastACVal = pp->colorBoost.avoidclip; + lastELVal = pp->colorBoost.enable_saturationlimiter; + + enableListener (); +} + +void ColorBoost::write (ProcParams* pp, ParamsEdited* pedited) { + + pp->colorBoost.amount = (int)colorboost->getValue(); + pp->colorBoost.avoidclip = avoidclip->get_active (); + pp->colorBoost.enable_saturationlimiter = enablelimiter->get_active (); + pp->colorBoost.saturationlimit = saturationlimiter->getValue (); + + if (pedited) { + pedited->colorBoost.amount = colorboost->getEditedState (); + pedited->colorBoost.avoidclip = !avoidclip->get_inconsistent(); + pedited->colorBoost.enable_saturationlimiter = !enablelimiter->get_inconsistent(); + pedited->colorBoost.saturationlimit = saturationlimiter->getEditedState (); + } +} + +void ColorBoost::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { + + colorboost->setDefault (defParams->colorBoost.amount); + saturationlimiter->setDefault (defParams->colorBoost.saturationlimit); + + if (pedited) { + colorboost->setDefaultEditedState (pedited->colorBoost.amount ? Edited : UnEdited); + saturationlimiter->setDefaultEditedState (pedited->colorBoost.saturationlimit ? Edited : UnEdited); + } + else { + colorboost->setDefaultEditedState (Irrelevant); + saturationlimiter->setDefaultEditedState (Irrelevant); + } +} + +void ColorBoost::avoidclip_toggled () { + + if (batchMode) { + if (avoidclip->get_inconsistent()) { + avoidclip->set_inconsistent (false); + acconn.block (true); + avoidclip->set_active (false); + acconn.block (false); + } + else if (lastACVal) + avoidclip->set_inconsistent (true); + + lastACVal = avoidclip->get_active (); + } + + if (listener) { + if (avoidclip->get_active ()) + listener->panelChanged (EvCBAvoidClip, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvCBAvoidClip, M("GENERAL_DISABLED")); + } +} + +void ColorBoost::enablelimiter_toggled () { + + if (batchMode) { + if (enablelimiter->get_inconsistent()) { + enablelimiter->set_inconsistent (false); + elconn.block (true); + enablelimiter->set_active (false); + elconn.block (false); + } + else if (lastELVal) + enablelimiter->set_inconsistent (true); + + lastELVal = enablelimiter->get_active (); + } + + removeIfThere (this, saturationlimiter, false); + if (enablelimiter->get_active () || enablelimiter->get_inconsistent()) + pack_start (*saturationlimiter); + + if (listener) { + if (enablelimiter->get_active ()) + listener->panelChanged (EvCBSatLimiter, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvCBSatLimiter, M("GENERAL_DISABLED")); + } +} + +void ColorBoost::adjusterChanged (Adjuster* a, double newval) { + + if (listener) { + if (a!=saturationlimiter) + listener->panelChanged (EvCBBoost, Glib::ustring::format ((int)a->getValue())); + else + listener->panelChanged (EvCBSatLimit, Glib::ustring::format (std::setw(2), std::fixed, std::setprecision(1), a->getValue())); + } +} + +void ColorBoost::setAdjusterBehavior (bool bcbadd) { + + if (!cbAdd && bcbadd || cbAdd && !bcbadd) + colorboost->setLimits (-100, 100, 1, 0); + + cbAdd = bcbadd; +} + +void ColorBoost::setBatchMode (bool batchMode) { + + ToolPanel::setBatchMode (batchMode); + colorboost->showEditedCB (); + saturationlimiter->showEditedCB (); +} diff --git a/rtgui/colorboost.h b/rtgui/colorboost.h new file mode 100755 index 000000000..cc581da87 --- /dev/null +++ b/rtgui/colorboost.h @@ -0,0 +1,53 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _COLORBOOST_H_ +#define _COLORBOOST_H_ + +#include +#include +#include + +class ColorBoost : public Gtk::VBox, public AdjusterListener, public ToolPanel { + + protected: + Adjuster* colorboost; + Gtk::CheckButton* avoidclip; + Gtk::CheckButton* enablelimiter; + Adjuster* saturationlimiter; + bool cbAdd; + sigc::connection acconn, elconn; + bool lastACVal, lastELVal; + + public: + + ColorBoost (); + virtual ~ColorBoost (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + + void adjusterChanged (Adjuster* a, double newval); + void avoidclip_toggled (); + void enablelimiter_toggled (); + void setAdjusterBehavior (bool bcbadd); +}; + +#endif diff --git a/rtgui/colordenoise.cc b/rtgui/colordenoise.cc new file mode 100755 index 000000000..646be0ec7 --- /dev/null +++ b/rtgui/colordenoise.cc @@ -0,0 +1,120 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include + +using namespace rtengine; +using namespace rtengine::procparams; + +ColorDenoise::ColorDenoise () : ToolPanel() { + + enabled = Gtk::manage (new Gtk::CheckButton (M("GENERAL_ENABLED"))); + enabled->set_active (false); + + amount = Gtk::manage (new Adjuster ("Amount", 1, 100, 1, 30)); + + pack_start (*enabled); + pack_start (*Gtk::manage (new Gtk::HSeparator())); + pack_start (*amount); + + enaConn = enabled->signal_toggled().connect( sigc::mem_fun(*this, &ColorDenoise::enabledChanged) ); + amount->setAdjusterListener (this); + + show_all_children (); +} + +void ColorDenoise::read (const ProcParams* pp, const ParamsEdited* pedited) { + + disableListener (); + + if (pedited) { + amount->setEditedState (pedited->colorDenoise.amount ? Edited : UnEdited); + enabled->set_inconsistent (!pedited->colorDenoise.enabled); + } + + enaConn.block (true); + enabled->set_active (pp->colorDenoise.enabled); + enaConn.block (false); + + lastEnabled = pp->colorDenoise.enabled; + + amount->setValue (pp->colorDenoise.amount); + + enableListener (); +} + +void ColorDenoise::write (ProcParams* pp, ParamsEdited* pedited) { + + pp->colorDenoise.amount = amount->getValue (); + pp->colorDenoise.enabled = enabled->get_active(); + + if (pedited) { + pedited->colorDenoise.amount = amount->getEditedState (); + pedited->colorDenoise.enabled = !enabled->get_inconsistent(); + } +} + +void ColorDenoise::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { + + amount->setDefault (defParams->colorDenoise.amount); + + if (pedited) + amount->setDefaultEditedState (pedited->colorDenoise.amount ? Edited : UnEdited); + else + amount->setDefaultEditedState (Irrelevant); +} + +void ColorDenoise::adjusterChanged (Adjuster* a, double newval) { + + if (listener && enabled->get_active()) { + + listener->panelChanged (EvCDNRadius, Glib::ustring::format (std::setw(2), std::fixed, std::setprecision(1), a->getValue())); + } +} + +void ColorDenoise::enabledChanged () { + + if (batchMode) { + if (enabled->get_inconsistent()) { + enabled->set_inconsistent (false); + enaConn.block (true); + enabled->set_active (false); + enaConn.block (false); + } + else if (lastEnabled) + enabled->set_inconsistent (true); + + lastEnabled = enabled->get_active (); + } + + if (listener) { + if (enabled->get_active ()) + listener->panelChanged (EvCDNEnabled, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvCDNEnabled, M("GENERAL_DISABLED")); + } +} + +void ColorDenoise::setBatchMode (bool batchMode) { + + ToolPanel::setBatchMode (batchMode); + amount->showEditedCB (); +} diff --git a/rtgui/colordenoise.h b/rtgui/colordenoise.h new file mode 100755 index 000000000..0114f7b6a --- /dev/null +++ b/rtgui/colordenoise.h @@ -0,0 +1,47 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _COLORDENOISE_H_ +#define _COLORDENOISE_H_ + +#include +#include +#include + +class ColorDenoise : public Gtk::VBox, public AdjusterListener, public ToolPanel { + + protected: + Adjuster* amount; + Gtk::CheckButton* enabled; + bool lastEnabled; + sigc::connection enaConn; + + public: + + ColorDenoise (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + + void adjusterChanged (Adjuster* a, double newval); + void enabledChanged (); +}; + +#endif diff --git a/rtgui/colorshift.cc b/rtgui/colorshift.cc new file mode 100755 index 000000000..63732c48c --- /dev/null +++ b/rtgui/colorshift.cc @@ -0,0 +1,108 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +using namespace rtengine; +using namespace rtengine::procparams; + +ColorShift::ColorShift () : ToolPanel(), aAdd(false), bAdd(false) { + + ashift = Gtk::manage (new Adjuster (M("TP_COLORSHIFT_GREENMAGENTA"), -25, 25, 0.1, 0)); + pack_start (*ashift); + + bshift = Gtk::manage (new Adjuster (M("TP_COLORSHIFT_BLUEYELLOW"), -25, 25, 0.1, 0)); + pack_start (*bshift); + + ashift->setAdjusterListener (this); + bshift->setAdjusterListener (this); + + show_all (); +} + +void ColorShift::read (const ProcParams* pp, const ParamsEdited* pedited) { + + disableListener (); + + if (pedited) { + ashift->setEditedState (pedited->colorShift.a ? Edited : UnEdited); + bshift->setEditedState (pedited->colorShift.b ? Edited : UnEdited); + } + + ashift->setValue (pp->colorShift.a); + bshift->setValue (pp->colorShift.b); + + enableListener (); +} + +void ColorShift::write (ProcParams* pp, ParamsEdited* pedited) { + + pp->colorShift.a = ashift->getValue (); + pp->colorShift.b = bshift->getValue (); + + if (pedited) { + pedited->colorShift.a = ashift->getEditedState (); + pedited->colorShift.b = bshift->getEditedState (); + } +} + +void ColorShift::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { + + ashift->setDefault (defParams->colorShift.a); + bshift->setDefault (defParams->colorShift.b); + + if (pedited) { + ashift->setDefaultEditedState (pedited->colorShift.a ? Edited : UnEdited); + bshift->setDefaultEditedState (pedited->colorShift.b ? Edited : UnEdited); + } + else { + ashift->setDefaultEditedState (Irrelevant); + bshift->setDefaultEditedState (Irrelevant); + } +} + +void ColorShift::adjusterChanged (Adjuster* a, double newval) { + + if (!listener) + return; + + if (a==ashift) + listener->panelChanged (EvCShiftA, Glib::ustring::format (std::setw(2), std::fixed, std::setprecision(1), a->getValue())); + else if (a==bshift) + listener->panelChanged (EvCShiftB, Glib::ustring::format (std::setw(2), std::fixed, std::setprecision(1), a->getValue())); +} + +void ColorShift::setAdjusterBehavior (bool baadd, bool bbadd) { + + if (!aAdd && baadd || aAdd && !baadd) + ashift->setLimits (-25, 25, 0.1, 0); + + if (!bAdd && bbadd || bAdd && !bbadd) + bshift->setLimits (-25, 25, 0.1, 0); + + aAdd = baadd; + bAdd = bbadd; +} + +void ColorShift::setBatchMode (bool batchMode) { + + ToolPanel::setBatchMode (batchMode); + ashift->showEditedCB (); + bshift->showEditedCB (); +} diff --git a/rtgui/colorshift.h b/rtgui/colorshift.h new file mode 100755 index 000000000..0dc3d009d --- /dev/null +++ b/rtgui/colorshift.h @@ -0,0 +1,46 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _COLORSHIFT_H_ +#define _COLORSHIFT_H_ + +#include +#include +#include + +class ColorShift : public Gtk::VBox, public AdjusterListener, public ToolPanel { + + protected: + Adjuster* ashift; + Adjuster* bshift; + bool aAdd, bAdd; + + public: + + ColorShift (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + + void adjusterChanged (Adjuster* a, double newval); + void setAdjusterBehavior (bool baadd, bool bbadd); +}; + +#endif diff --git a/rtgui/createicon.cc b/rtgui/createicon.cc new file mode 100755 index 000000000..ac11a61e2 --- /dev/null +++ b/rtgui/createicon.cc @@ -0,0 +1,200 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +void png_read_data(png_structp png_ptr, png_bytep data, png_size_t length) { + png_size_t check; + + /* fread() returns 0 on error, so it is OK to store this in a png_size_t + * instead of an int, which is what fread() actually returns. + */ + check = (png_size_t)fread(data, (png_size_t)1, length, (FILE *)png_ptr->io_ptr); + + if (check != length) + { + png_error(png_ptr, "Read Error"); + } +} + +void png_write_data(png_structp png_ptr, png_bytep data, png_size_t length) { + png_uint_32 check; + + check = fwrite(data, 1, length, (FILE *)(png_ptr->io_ptr)); + if (check != length) + { + png_error(png_ptr, "Write Error"); + } +} + +void png_flush(png_structp png_ptr) { + FILE *io_ptr; + io_ptr = (FILE *)CVT_PTR((png_ptr->io_ptr)); + if (io_ptr != NULL) + fflush(io_ptr); +} + + +unsigned char* loadPNG (char* fname, int& w, int& h) { + + FILE *file = fopen (fname,"rb"); + + unsigned char header[8]; + fread (header, 1, 8, file); + + png_structp png = png_create_read_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0); + png_infop info = png_create_info_struct (png); + png_infop end_info = png_create_info_struct (png); + if (setjmp (png_jmpbuf(png))) { + png_destroy_read_struct (&png, &info, &end_info); + fclose (file); + return NULL; + } + //set up png read + png_set_read_fn (png, file, png_read_data); + png_set_sig_bytes (png,8); + + png_read_info(png,info); + + unsigned long width,height; + int bit_depth,color_type,interlace_type,compression_type,filter_method; + png_get_IHDR(png,info,&width,&height,&bit_depth,&color_type,&interlace_type, + &compression_type, &filter_method); + + //converting to 32bpp format + if (color_type==PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png); + + if (color_type==PNG_COLOR_TYPE_GRAY || color_type==PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(png); + + if (png_get_valid(png,info,PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png); + + if (interlace_type!=PNG_INTERLACE_NONE) { + png_destroy_read_struct (&png, &info, &end_info); + fclose (file); + return NULL; + } + + if (color_type & PNG_COLOR_MASK_ALPHA) + png_set_strip_alpha(png); + + //setting gamma + double gamma; + if (png_get_gAMA(png,info,&gamma)) + png_set_gamma(png, 2.0, gamma); + else + png_set_gamma(png,2.0, 0.45455); + + int bps = 8; + + //updating png info struct + png_read_update_info(png,info); + png_get_IHDR(png,info,&width,&height,&bit_depth,&color_type,&interlace_type, + &compression_type, &filter_method); + + if (color_type & PNG_COLOR_MASK_ALPHA) + png_set_strip_alpha(png); + + png_read_update_info(png,info); + png_get_IHDR(png,info,&width,&height,&bit_depth,&color_type,&interlace_type, + &compression_type, &filter_method); + + + unsigned char* data = new unsigned char[width*height*3]; + int rowlen = width*3; + unsigned char *row = new unsigned char [rowlen]; + + for (unsigned int i=0;i + * + * 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 +#include +using namespace rtengine; +using namespace rtengine::procparams; + +extern Glib::ustring argv0; +extern Options options; + +class RefreshSpinHelper { + + public: + Crop* crop; + bool notify; + RefreshSpinHelper (Crop* _crop, bool _notify) + : crop(_crop), notify(_notify) {} +}; + +Crop::Crop () { + + clistener = NULL; + + maxw = 3000; + maxh = 2000; + + enabled = Gtk::manage (new Gtk::CheckButton (M("GENERAL_ENABLED"))); + enabled->set_active (false); + pack_start(*enabled); + + pack_start(*Gtk::manage (new Gtk::HSeparator())); + + Gtk::HBox* hb1 = Gtk::manage (new Gtk::HBox ()); + + hb1->pack_start (*Gtk::manage (new Gtk::Label (Glib::ustring(" ") + M("TP_CROP_X") +": "))); + x = Gtk::manage (new Gtk::SpinButton ()); + x->set_size_request (60, -1); + hb1->pack_start (*x); + + hb1->pack_start (*Gtk::manage (new Gtk::Label (Glib::ustring(" ") + M("TP_CROP_Y") + ": "))); + y = Gtk::manage (new Gtk::SpinButton ()); + y->set_size_request (60, -1); + hb1->pack_start (*y); + + pack_start (*hb1, Gtk::PACK_SHRINK, 2); + + Gtk::HBox* hb2 = Gtk::manage (new Gtk::HBox ()); + + hb2->pack_start (*Gtk::manage (new Gtk::Label (M("TP_CROP_W") + ": "))); + w = Gtk::manage (new Gtk::SpinButton ()); + w->set_size_request (60, -1); + hb2->pack_start (*w); + + hb2->pack_start (*Gtk::manage (new Gtk::Label (M("TP_CROP_H") + ": "))); + h = Gtk::manage (new Gtk::SpinButton ()); + h->set_size_request (60, -1); + hb2->pack_start (*h); + + pack_start (*hb2, Gtk::PACK_SHRINK, 4); + + selectCrop = Gtk::manage (new Gtk::Button (M("TP_CROP_SELECTCROP"))); + selectCrop->set_image (*Gtk::manage (new Gtk::Image (argv0+"/images/crop16.png"))); + + pack_start (*selectCrop, Gtk::PACK_SHRINK, 2); + + Gtk::HBox* hb3 = Gtk::manage (new Gtk::HBox ()); + + fixr = Gtk::manage (new Gtk::CheckButton (M("TP_CROP_FIXRATIO"))); + fixr->set_active (1); + + hb3->pack_start (*fixr, Gtk::PACK_SHRINK, 4); + + ratio = Gtk::manage (new Gtk::ComboBoxText ()); + hb3->pack_start (*ratio, Gtk::PACK_SHRINK, 4); + + orientation = Gtk::manage (new Gtk::ComboBoxText ()); + hb3->pack_start (*orientation); + + pack_start (*hb3, Gtk::PACK_SHRINK, 4); + + Gtk::HBox* hb31 = Gtk::manage (new Gtk::HBox ()); + + hb31->pack_start (*Gtk::manage (new Gtk::Label (M("TP_CROP_GUIDETYPE"))), Gtk::PACK_SHRINK, 4); + guide = Gtk::manage (new Gtk::ComboBoxText ()); + hb31->pack_start (*guide); + + pack_start (*hb31, Gtk::PACK_SHRINK, 4); + + dpibox = Gtk::manage (new Gtk::VBox()); + dpibox->pack_start (*Gtk::manage (new Gtk::HSeparator()), Gtk::PACK_SHRINK, 2); + + Gtk::HBox* hb4 = Gtk::manage (new Gtk::HBox ()); + hb4->pack_start (*Gtk::manage (new Gtk::Label (M("TP_CROP_DPI")))); + dpi = Gtk::manage (new Gtk::SpinButton ()); + dpi->set_size_request (60, -1); + hb4->pack_start (*dpi); + + dpibox->pack_start (*hb4, Gtk::PACK_SHRINK, 2); + + sizecm = Gtk::manage (new Gtk::Label (M("GENERAL_NA") + " cm x " + M("GENERAL_NA") + " cm")); + sizein = Gtk::manage (new Gtk::Label (M("GENERAL_NA") + " in x " + M("GENERAL_NA") + " in")); + + dpibox->pack_start (*sizecm, Gtk::PACK_SHRINK, 1); + dpibox->pack_start (*sizein, Gtk::PACK_SHRINK, 1); + + pack_start (*dpibox, Gtk::PACK_SHRINK, 0); + + dpi->set_value (300); + + ratio->append_text ("3:2"); + ratio->append_text ("4:3"); + ratio->append_text ("16:9"); + ratio->append_text ("16:10"); + ratio->append_text ("5:4"); + ratio->append_text ("2:1"); + ratio->append_text ("1:1"); + ratio->append_text ("DIN"); + ratio->set_active (0); + + orientation->append_text (M("GENERAL_LANDSCAPE")); + orientation->append_text (M("GENERAL_PORTRAIT")); + orientation->set_active (0); + + guide->append_text (M("TP_CROP_GTNONE")); + guide->append_text (M("TP_CROP_GTRULETHIRDS")); + guide->append_text (M("TP_CROP_GTDIAGONALS")); + guide->append_text (M("TP_CROP_GTHARMMEANS1")); + guide->append_text (M("TP_CROP_GTHARMMEANS2")); + guide->append_text (M("TP_CROP_GTHARMMEANS3")); + guide->append_text (M("TP_CROP_GTHARMMEANS4")); + guide->set_active (0); + + w->set_range (0, maxw); + h->set_range (0, maxh); + x->set_range (0, maxw); + y->set_range (0, maxh); + + x->set_digits (0); + x->set_increments (1,100); + x->set_value (0); + + y->set_digits (0); + y->set_increments (1,100); + y->set_value (0); + + w->set_digits (0); + w->set_increments (1,100); + w->set_value (200); + + h->set_digits (0); + h->set_increments (1,100); + h->set_value (200); + + dpi->set_digits (0); + dpi->set_increments (1,100); + dpi->set_range (50, 12000); + dpi->set_value (300); + + xconn = x->signal_value_changed().connect ( sigc::mem_fun(*this, &Crop::positionChanged), true); + yconn = y->signal_value_changed().connect ( sigc::mem_fun(*this, &Crop::positionChanged), true); + wconn = w->signal_value_changed().connect ( sigc::mem_fun(*this, &Crop::widthChanged), true); + hconn = h->signal_value_changed().connect ( sigc::mem_fun(*this, &Crop::heightChanged), true); + econn = enabled->signal_toggled().connect( sigc::mem_fun(*this, &Crop::enabledChanged) ); + fconn = fixr->signal_toggled().connect( sigc::mem_fun(*this, &Crop::ratioChanged) ); + rconn = ratio->signal_changed().connect( sigc::mem_fun(*this, &Crop::ratioChanged) ); + oconn = orientation->signal_changed().connect( sigc::mem_fun(*this, &Crop::ratioChanged) ); + gconn = guide->signal_changed().connect( sigc::mem_fun(*this, &Crop::notifyListener) ); + selectCrop->signal_pressed().connect( sigc::mem_fun(*this, &Crop::selectPressed) ); + dpi->signal_value_changed().connect( sigc::mem_fun(*this, &Crop::refreshSize) ); + + nx = ny = nw = nh = 0; + nsx = nsy = nsw = nsh = 0; + lastScale = 1.0; + lastRotationDeg = 0; + show_all (); +} + +void Crop::writeOptions () { + + options.cropDPI = (int)dpi->get_value (); +} + +void Crop::readOptions () { + + disableListener (); + + dpi->set_value (options.cropDPI); + + enableListener (); +} + +void Crop::read (const ProcParams* pp, const ParamsEdited* pedited) { + + disableListener (); + + xconn.block (true); + yconn.block (true); + wconn.block (true); + hconn.block (true); + rconn.block (true); + fconn.block (true); + oconn.block (true); + gconn.block (true); + enabled->set_active (pp->crop.enabled); + + // check if the new values are larger than the maximum + double tmp, maxw, maxh; + w->get_range (tmp, maxw); + h->get_range (tmp, maxh); + if (pp->crop.x + pp->crop.w > maxw || pp->crop.y + pp->crop.h > maxh) + setDimensions (pp->crop.x + pp->crop.w, pp->crop.y + pp->crop.h); + + ratio->set_active_text (pp->crop.ratio); + fixr->set_active (pp->crop.fixratio); + + if (pp->crop.orientation == "Landscape") + orientation->set_active (0); + else if (pp->crop.orientation == "Portrait") + orientation->set_active (1); + + if (pp->crop.guide == "None") + guide->set_active (0); + else if (pp->crop.guide == "Rule of thirds") + guide->set_active (1); + else if (pp->crop.guide == "Rule of diagonals") + guide->set_active (2); + else if (pp->crop.guide == "Harmonic means 1") + guide->set_active (3); + else if (pp->crop.guide == "Harmonic means 2") + guide->set_active (4); + else if (pp->crop.guide == "Harmonic means 3") + guide->set_active (5); + else if (pp->crop.guide == "Harmonic means 4") + guide->set_active (6); + + x->set_value (pp->crop.x); + y->set_value (pp->crop.y); + w->set_value (pp->crop.w); + h->set_value (pp->crop.h); + + nx = pp->crop.x; + ny = pp->crop.y; + nw = pp->crop.w; + nh = pp->crop.h; + + if (pp->resize.enabled) + lastScale = pp->resize.scale; + else + lastScale = 1.0; + nsx = nx / lastScale; + nsy = ny / lastScale; + nsw = nw / lastScale; + nsh = nh / lastScale; + lastRotationDeg = pp->coarse.rotate; + + wDirty = false; + hDirty = false; + xDirty = false; + yDirty = false; + + if (pedited) { + wDirty = pedited->crop.w; + hDirty = pedited->crop.h; + xDirty = pedited->crop.x; + yDirty = pedited->crop.y; + if (!pedited->crop.ratio) + ratio->set_active (8); + if (!pedited->crop.orientation) + orientation->set_active (2); + if (!pedited->crop.guide) + guide->set_active (7); + enabled->set_inconsistent (!pedited->crop.enabled); + fixr->set_inconsistent (!pedited->crop.fixratio); + } + + lastEnabled = pp->crop.enabled; + lastAspect = pp->crop.fixratio; + + xconn.block (false); + yconn.block (false); + wconn.block (false); + hconn.block (false); + rconn.block (false); + fconn.block (false); + oconn.block (false); + gconn.block (false); + + enableListener (); +} + +void Crop::write (ProcParams* pp, ParamsEdited* pedited) { + + pp->crop.enabled = enabled->get_active (); + pp->crop.x = nx; + pp->crop.y = ny; + pp->crop.w = nw; + pp->crop.h = nh; + pp->crop.fixratio = fixr->get_active (); + pp->crop.ratio = ratio->get_active_text (); + + if (orientation->get_active_row_number()==0) + pp->crop.orientation = "Landscape"; + else if (orientation->get_active_row_number()==1) + pp->crop.orientation = "Portrait"; + + if (guide->get_active_row_number()==0) + pp->crop.guide = "None"; + else if (guide->get_active_row_number()==1) + pp->crop.guide = "Rule of thirds"; + else if (guide->get_active_row_number()==2) + pp->crop.guide = "Rule of diagonals"; + else if (guide->get_active_row_number()==3) + pp->crop.guide = "Harmonic means 1"; + else if (guide->get_active_row_number()==4) + pp->crop.guide = "Harmonic means 2"; + else if (guide->get_active_row_number()==5) + pp->crop.guide = "Harmonic means 3"; + else if (guide->get_active_row_number()==6) + pp->crop.guide = "Harmonic means 4"; + + if (pedited) { + pedited->crop.enabled = !enabled->get_inconsistent(); + pedited->crop.ratio = ratio->get_active_row_number() != 8; + pedited->crop.orientation = orientation->get_active_row_number() != 2; + pedited->crop.guide = guide->get_active_row_number() != 7; + pedited->crop.fixratio = !fixr->get_inconsistent(); + pedited->crop.w = wDirty; + pedited->crop.h = hDirty; + pedited->crop.x = xDirty; + pedited->crop.y = yDirty; + } + +} + +void Crop::selectPressed () { + + if (clistener) + clistener->cropSelectRequested (); +} + +void Crop::notifyListener () { + + if (listener && enabled->get_active ()) + listener->panelChanged (EvCrop, Glib::ustring::compose ("%1=%2, %3=%4\n%5=%6, %7=%8", M("TP_CROP_X"), nx, M("TP_CROP_Y"), ny, M("TP_CROP_W"), nw, M("TP_CROP_H"), nh)); +} + +void Crop::enabledChanged () { + + if (batchMode) { + if (enabled->get_inconsistent()) { + enabled->set_inconsistent (false); + econn.block (true); + enabled->set_active (false); + econn.block (false); + } + else if (lastEnabled) + enabled->set_inconsistent (true); + + lastEnabled = enabled->get_active (); + } + + if (listener) { + if (enabled->get_active ()) + listener->panelChanged (EvCrop, Glib::ustring::compose ("%1=%2, %3=%4\n%5=%6, %7=%8", M("TP_CROP_X"), nx, M("TP_CROP_Y"), ny, M("TP_CROP_W"), nw, M("TP_CROP_H"), nh)); + else + listener->panelChanged (EvCrop, M("GENERAL_DISABLED")); + } +} + +int notifylistener (void* data) { + + gdk_threads_enter (); + ((Crop*)data)->notifyListener (); + gdk_threads_leave (); + return 0; +} + +int refreshspins (void* data) { + + gdk_threads_enter (); + RefreshSpinHelper* rsh = (RefreshSpinHelper*) data; + rsh->crop->refreshSpins (rsh->notify); + delete rsh; + gdk_threads_leave (); + return 0; +} + +void Crop::resizeScaleChanged (double rsc) { + + lastScale = rsc; + + nx = (int)round (nsx * rsc); + ny = (int)round (nsy * rsc); + nw = (int)round (nsw * rsc); + nh = (int)round (nsh * rsc); + + if (nx+nw > maxw || ny+nh > maxh) + setDimensions (nx+nw, ny+nh); + + g_idle_add (refreshspins, new RefreshSpinHelper (this, false)); +} + +void Crop::hFlipCrop () { + + nx = maxw - nx - nw; + nsx = nx / lastScale; + g_idle_add (refreshspins, new RefreshSpinHelper (this, false)); +} + +void Crop::vFlipCrop () { + + ny = maxh - ny - nh; + nsy = ny / lastScale; + g_idle_add (refreshspins, new RefreshSpinHelper (this, false)); +} + +void Crop::rotateCrop (int deg) { + + int tmp; + switch ((360+deg-lastRotationDeg)%360) { + case 90: + tmp = nx; + nx = maxh - ny - nh; + ny = tmp; + tmp = nw; + nw = nh; + nh = tmp; + break; + case 270: + tmp = ny; + ny = maxw - nx - nw; + nx = tmp; + tmp = nw; + nw = nh; + nh = tmp; + break; + case 180: + nx = maxw - nx - nw; + ny = maxh - ny - nh; + break; + } + nsx = nx / lastScale; + nsy = ny / lastScale; + nsw = nw / lastScale; + nsh = nh / lastScale; + + lastRotationDeg = deg; + g_idle_add (refreshspins, new RefreshSpinHelper (this, false)); +} + +void Crop::positionChanged () { + + xDirty = true; + yDirty = true; + + int X = (int)x->get_value (); + int Y = (int)y->get_value (); + int W = nw; + int H = nh; + cropMoved (X, Y, W, H); + g_idle_add (notifylistener, this); +} + +void Crop::widthChanged () { + + wDirty = true; + + int X = nx; + int Y = ny; + int W = (int)w->get_value (); + int H = nh; + cropWidth2Resized (X, Y, W, H); + g_idle_add (notifylistener, this); +} + +void Crop::heightChanged () { + + hDirty = true; + + int X = nx; + int Y = ny; + int W = nw; + int H = (int)h->get_value (); + cropHeight2Resized (X, Y, W, H); + g_idle_add (notifylistener, this); +} + + +void Crop::ratioChanged () { + + if (batchMode && lastAspect != fixr->get_active ()) { + if (fixr->get_inconsistent()) { + fixr->set_inconsistent (false); + fconn.block (true); + fixr->set_active (false); + fconn.block (false); + } + else if (lastAspect) + fixr->set_inconsistent (true); + + lastAspect = fixr->get_active (); + } + + + if (fixr->get_active() && !fixr->get_inconsistent()) { + +// int W = w->get_value (); +// int H = h->get_value (); + int W = nw; + int H = nh; + int X = nx; + int Y = ny; + if (W>=H) + cropWidth2Resized (X, Y, W, H); + else + cropHeight2Resized (X, Y, W, H); + + g_idle_add (refreshspins, new RefreshSpinHelper (this, true)); + } +} + +void Crop::refreshSize () { + + if (!batchMode) { + + std::ostringstream ostrin; + ostrin.precision (3); + // ostrin << h->get_value()/dpi->get_value() << " in x " << w->get_value()/dpi->get_value() << " in";; + ostrin << nh/dpi->get_value() << " in x " << nw/dpi->get_value() << " in";; + + sizein->set_text (ostrin.str ()); + + std::ostringstream ostrcm; + ostrcm.precision (3); + // ostrcm << h->get_value()/dpi->get_value()*2.54 << " cm x " << w->get_value()/dpi->get_value()*2.54 << " cm";; + ostrcm << nh/dpi->get_value()*2.54 << " cm x " << nw/dpi->get_value()*2.54 << " cm";; + + sizecm->set_text (ostrcm.str ()); + } +} + +void Crop::setDimensions (int mw, int mh) { + + maxw = mw; + maxh = mh; + + xconn.block (true); + yconn.block (true); + wconn.block (true); + hconn.block (true); + + w->set_range (0, maxw); + h->set_range (0, maxh); + x->set_range (0, maxw); + y->set_range (0, maxh); + + xconn.block (false); + yconn.block (false); + wconn.block (false); + hconn.block (false); + + if (enabled->get_active()==false) { + nx = 0; + ny = 0; + nw = mw; + nh = mh; + + nsx = nx / lastScale; + nsy = ny / lastScale; + nsw = nw / lastScale; + nsh = nh / lastScale; + refreshSpins (); + } + refreshSize (); +} + +struct setdimparams { + Crop* crop; + int x; + int y; +}; + +int setdim (void* data) { + + gdk_threads_enter (); + setdimparams* params = (setdimparams*)data; + params->crop->setDimensions (params->x, params->y); + delete params; + gdk_threads_leave (); + return 0; +} + +void Crop::sizeChanged (int x, int y, int ow, int oh) { + + setdimparams* params = new setdimparams; + params->x = x; + params->y = y; + params->crop = this; + g_idle_add (setdim, params); +} + +bool Crop::refreshSpins (bool notify) { + + xconn.block (true); + yconn.block (true); + wconn.block (true); + hconn.block (true); + + x->set_value (nx); + y->set_value (ny); + w->set_value (nw); + h->set_value (nh); + + xDirty = true; + yDirty = true; + wDirty = true; + hDirty = true; + + xconn.block (false); + yconn.block (false); + wconn.block (false); + hconn.block (false); + + refreshSize (); + if (notify) + notifyListener (); + + return false; +} + +void Crop::cropMoved (int &X, int &Y, int &W, int &H) { + +// W = w->get_value (); +// H = h->get_value (); + W = nw; + H = nh; + + if (X+W>maxw) + X = maxw-W; + if (Y+H>maxh) + Y = maxh-H; + if (X<0) + X = 0; + if (Y<0) + Y = 0; + + nx = X; + ny = Y; + nw = W; + nh = H; + + nsx = nx / lastScale; + nsy = ny / lastScale; + nsw = nw / lastScale; + nsh = nh / lastScale; + + g_idle_add (refreshspins, new RefreshSpinHelper (this, false)); +// Glib::signal_idle().connect (sigc::mem_fun(*this, &Crop::refreshSpins)); +} + +void Crop::cropWidth1Resized (int &X, int &Y, int &W, int &H) { + + if (W<0) + W = 0; + if (H<0) + H = 0; + + if (X<0) { + W += X; + X = 0; + } + if (fixr->get_active()) { + double r = getRatio(); + int W2max = (int)round(r*(maxh-Y)); + if (W>W2max) { + X += W - W2max; + W = W2max; + } + H = (int)round(W / r); + } + + nx = X; + ny = Y; + nw = W; + nh = H; + + nsx = nx / lastScale; + nsy = ny / lastScale; + nsw = nw / lastScale; + nsh = nh / lastScale; + + g_idle_add (refreshspins, new RefreshSpinHelper (this, false)); +// Glib::signal_idle().connect (sigc::mem_fun(*this, &Crop::refreshSpins)); +} + +void Crop::cropWidth2Resized (int &X, int &Y, int &W, int &H) { + +// X = x->get_value (); +// Y = y->get_value (); + X = nx; + Y = ny; + + if (W<0) + W = 0; + if (H<0) + H = 0; + + if (W>maxw-X) + W = maxw-X; + + if (fixr->get_active()) { + double r = getRatio(); + int W2max = (int)round(r*(maxh-Y)); + if (W>W2max) + W = W2max; + H = (int)round(W / r); + } + + nx = X; + ny = Y; + nw = W; + nh = H; + + nsx = nx / lastScale; + nsy = ny / lastScale; + nsw = nw / lastScale; + nsh = nh / lastScale; + + g_idle_add (refreshspins, new RefreshSpinHelper (this, false)); +// Glib::signal_idle().connect (sigc::mem_fun(*this, &Crop::refreshSpins)); +} + +void Crop::cropHeight1Resized (int &X, int &Y, int &W, int &H) { + + if (W<0) + W = 0; + if (H<0) + H = 0; + + if (Y<0) { + H += Y; + Y = 0; + } + + if (fixr->get_active()) { + double r = getRatio(); + int H2max = (int)round((maxw-X) / r); + if (H>H2max) { + Y += H - H2max; + H = H2max; + } + W = (int)round(H * r); + } + + nx = X; + ny = Y; + nw = W; + nh = H; + + nsx = nx / lastScale; + nsy = ny / lastScale; + nsw = nw / lastScale; + nsh = nh / lastScale; + + g_idle_add (refreshspins, new RefreshSpinHelper (this, false)); +// Glib::signal_idle().connect (sigc::mem_fun(*this, &Crop::refreshSpins)); +} + +void Crop::cropHeight2Resized (int &X, int &Y, int &W, int &H) { + +// X = x->get_value (); +// Y = y->get_value (); + X = nx; + Y = ny; + + if (W<0) + W = 0; + if (H<0) + H = 0; + int H1max = maxh-Y; + if (H>H1max) + H = H1max; + if (fixr->get_active()) { + double r = getRatio (); + int H2max = (int)round ((maxw-X) / r); + if (H>H2max) + H = H2max; + W = (int)round(H * r); + } + + nx = X; + ny = Y; + nw = W; + nh = H; + + nsx = nx / lastScale; + nsy = ny / lastScale; + nsw = nw / lastScale; + nsh = nh / lastScale; + + g_idle_add (refreshspins, new RefreshSpinHelper (this, false)); +// Glib::signal_idle().connect (sigc::mem_fun(*this, &Crop::refreshSpins)); +} + +void Crop::cropInit (int &x, int &y, int &w, int &h) { + + nx = x; + ny = y; + nw = 1; + nh = 1; + + nsx = nx / lastScale; + nsy = ny / lastScale; + nsw = nw / lastScale; + nsh = nh / lastScale; + + w = 1; h = 1; + + econn.block (true); + enabled->set_active (1); + econn.block (false); + g_idle_add (refreshspins, new RefreshSpinHelper (this, false)); +// Glib::signal_idle().connect (sigc::mem_fun(*this, &Crop::refreshSpins)); +} + +void Crop::cropResized (int &x, int &y, int& x2, int& y2) { + + if (x2<0) + x2 = 0; + if (y2<0) + y2 = 0; + if (x2>=maxw) + x2 = maxw-1; + if (y2>=maxh) + y2 = maxh-1; + + int X, Y; + int W; + if (xmaxw) + W = maxw; + if (H>maxh) + H = maxh; + + if (fixr->get_active()) { + double r = getRatio (); + if (y<=y2) { + int W2max = (int)round ((maxh-Y) * r); + if (W>W2max) + W = W2max; + } + else { + int W2max = (int)round (y * r); + if (W>W2max) + W = W2max; + } + H = (int)round(W / r); + if (xget_active()==false) + return r; + if (ratio->get_active_row_number()==0) + r = 3.0/2.0; + else if (ratio->get_active_row_number()==1) + r = 4.0/3.0; + else if (ratio->get_active_row_number()==2) + r = 16.0/9.0; + else if (ratio->get_active_row_number()==3) + r = 16.0/10.0; + else if (ratio->get_active_row_number()==4) + r = 5.0/4.0; + else if (ratio->get_active_row_number()==5) + r = 2.0/1.0; + else if (ratio->get_active_row_number()==6) + r = 1.0/1.0; + else if (ratio->get_active_row_number()==7) + r = 1.414; + if (orientation->get_active_row_number()==0) + return r; + else + return 1.0 / r; +} + +void Crop::setBatchMode (bool batchMode) { + + ToolPanel::setBatchMode (batchMode); + + ratio->append_text ("(Unchanged)"); + orientation->append_text ("(Unchanged)"); + guide->append_text ("(Unchanged)"); + removeIfThere (this, dpibox); +} diff --git a/rtgui/crop.h b/rtgui/crop.h new file mode 100755 index 000000000..c607b0e1e --- /dev/null +++ b/rtgui/crop.h @@ -0,0 +1,100 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _CROP_H_ +#define _CROP_H_ + +#include +#include +#include + +class CropPanelListener { + + public: + virtual void cropSelectRequested () {} +}; + + +class Crop : public Gtk::VBox, public CropGUIListener, public ToolPanel, public rtengine::SizeListener { + + protected: + Gtk::CheckButton* enabled; + Gtk::CheckButton* fixr; + Gtk::ComboBoxText* ratio; + Gtk::ComboBoxText* orientation; + Gtk::ComboBoxText* guide; + Gtk::Button* selectCrop; + CropPanelListener* clistener; + int opt; + Gtk::SpinButton* x; + Gtk::SpinButton* y; + Gtk::SpinButton* w; + Gtk::SpinButton* h; + Gtk::SpinButton* dpi; + Gtk::Label* sizecm; + Gtk::Label* sizein; + Gtk::VBox* dpibox; + int maxw, maxh; + int nx, ny, nw, nh; + double nsx, nsy, nsw, nsh, lastScale; + int lastRotationDeg; + sigc::connection xconn, yconn, wconn, hconn, econn, fconn, rconn, oconn, gconn; + bool wDirty, hDirty, xDirty, yDirty, lastEnabled, lastAspect; + + public: + + Crop (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + + void ratioChanged (); + void refreshSize (); + void selectPressed (); + void setDimensions (int mw, int mh); + void enabledChanged (); + void positionChanged (); + void widthChanged (); + void heightChanged (); + bool refreshSpins (bool notify=false); + void notifyListener (); + void sizeChanged (int w, int h, int ow, int oh); + + void readOptions (); + void writeOptions (); + + void cropMoved (int &x, int &y, int &w, int &h); + void cropWidth1Resized (int &x, int &y, int &w, int &h); + void cropWidth2Resized (int &x, int &y, int &w, int &h); + void cropHeight1Resized (int &x, int &y, int &w, int &h); + void cropHeight2Resized (int &x, int &y, int &w, int &h); + void cropInit (int &x, int &y, int &w, int &h); + void cropResized (int &x, int &y, int& x2, int& y2); + void cropManipReady (); + double getRatio (); + + void setCropPanelListener (CropPanelListener* cl) { clistener = cl; } + + void resizeScaleChanged (double rsc); + void hFlipCrop (); + void vFlipCrop (); + void rotateCrop (int deg); +}; + +#endif diff --git a/rtgui/cropguilistener.h b/rtgui/cropguilistener.h new file mode 100755 index 000000000..ca8574072 --- /dev/null +++ b/rtgui/cropguilistener.h @@ -0,0 +1,36 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef __CROPGUILISTENER__ +#define __CROPGUILISTENER__ + +class CropGUIListener { + + public: + virtual void cropMoved (int &x, int &y, int &w, int &h) {} + virtual void cropWidth1Resized (int &x, int &y, int &w, int &h) {} + virtual void cropWidth2Resized (int &x, int &y, int &w, int &h) {} + virtual void cropHeight1Resized (int &x, int &y, int &w, int &h) {} + virtual void cropHeight2Resized (int &x, int &y, int &w, int &h) {} + virtual void cropInit (int &x, int &y, int &w, int &h) {} + virtual void cropResized (int &x, int &y, int& x2, int& y2) {} + virtual void cropManipReady () {} + virtual double getRatio () {} +}; + +#endif diff --git a/rtgui/crophandler.cc b/rtgui/crophandler.cc new file mode 100755 index 000000000..ec56b9fdb --- /dev/null +++ b/rtgui/crophandler.cc @@ -0,0 +1,328 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +using namespace rtengine; + +CropHandler::CropHandler () + : crop(NULL), listener(NULL), cropimg(NULL), ipc(NULL), + cx(0), cy(0), cw(0), ch(0), + cropX(0), cropY(0), cropW(0), cropH(0), + zoom(1000), enabled(false) { + + chi = new CropHandlerIdleHelper; + chi->destroyed = false; + chi->pending = 0; + chi->cropHandler = this; +} + +CropHandler::~CropHandler () { + + if (ipc) + ipc->delSizeListener (this); + + setEnabled (false); + if (crop) + crop->destroy (); + cimg.lock (); + if (chi->pending) + chi->destroyed = true; + else + delete chi; + cimg.unlock (); +} + +void CropHandler::newImage (StagedImageProcessor* ipc_) { + + ipc = ipc_; + cx = 0; + cy = 0; + + if (!ipc) + return; + + crop = ipc->createCrop (); + ipc->setSizeListener (this); + crop->setListener (enabled ? this : NULL); + initial = true; +} + +void CropHandler::sizeChanged (int x, int y, int ow, int oh) { // the ipc notifies it to keep track size changes like rotation + + compDim (); + +// this should be put into an idle source!!! +/* if (listener) + listener->cropWindowChanged (); + */ +} + +double CropHandler::getFitZoom () { + + if (ipc) { + double z1 = (double) wh / ipc->getFullHeight (); + double z2 = (double) ww / ipc->getFullWidth (); + return z1=0) + x = centerx; + if (centery>=0) + y = centery; + + zoom = z; + if (zoom>=1000) { + cw = ww * 1000 / zoom; + ch = wh * 1000 / zoom; + } + else { + cw = ww * zoom; + ch = wh * zoom; + } + cx = x - cw / 2; + cy = y - ch / 2; + + compDim (); + if (enabled) + update (); +} + + +void CropHandler::setWSize (int w, int h) { + + ww = w; + wh = h; + if (zoom>=1000) { + cw = ww * 1000 / zoom; + ch = wh * 1000 / zoom; + } + else { + cw = ww * zoom; + ch = wh * zoom; + } + + compDim (); + if (enabled) + update (); +} + +void CropHandler::getWSize (int& w, int &h) { + + w = ww; + h = wh; +} + +void CropHandler::setPosition (int x, int y, bool update_) { + + cx = x; + cy = y; + + compDim (); + if (enabled && update_) + update (); +} + +void CropHandler::getPosition (int& x, int& y) { + + x = cropX; + y = cropY; +} + + +int createpixbufs (void* data) { + + gdk_threads_enter (); + + CropHandlerIdleHelper* chi = (CropHandlerIdleHelper*) data; + if (chi->destroyed) { + if (chi->pending == 1) + delete chi; + else + chi->pending--; + gdk_threads_leave (); + return 0; + } + + CropHandler* ch = chi->cropHandler; + + ch->cimg.lock (); + ch->cropPixbuf.clear (); + + if (!ch->enabled) { + delete [] ch->cropimg; + ch->cropimg = NULL; + ch->cimg.unlock (); + gdk_threads_leave (); + return 0; + } + + if (ch->cropimg) { + if (ch->cix==ch->cropX && ch->ciy==ch->cropY && ch->ciw==ch->cropW && ch->cih==ch->cropH && ch->cis==(ch->zoom>=1000?1:ch->zoom)) { + // calculate final image size + int czoom = ch->zoom<1000 ? 1000 : ch->zoom; + int imw = ch->cropimg_width * czoom / 1000; + int imh = ch->cropimg_height * czoom / 1000; + if (imw>ch->ww) + imw = ch->ww; + if (imh>ch->wh) + imh = ch->wh; + + Glib::RefPtr tmpPixbuf = Gdk::Pixbuf::create_from_data (ch->cropimg, Gdk::COLORSPACE_RGB, false, 8, ch->cropimg_width, ch->cropimg_height, 3*ch->cropimg_width); + ch->cropPixbuf = Gdk::Pixbuf::create (Gdk::COLORSPACE_RGB, false, 8, imw, imh); + tmpPixbuf->scale (ch->cropPixbuf, 0, 0, imw, imh, 0, 0, czoom/1000.0, czoom/1000.0, Gdk::INTERP_NEAREST); + tmpPixbuf.clear (); + } + delete [] ch->cropimg; + ch->cropimg = NULL; + } + ch->cimg.unlock (); + if (ch->listener) { + ch->listener->cropImageUpdated (); + if (ch->initial) { + ch->listener->initialImageArrived (); + ch->initial = false; + } + } + + chi->pending--; + + gdk_threads_leave (); + return 0; +} + +void CropHandler::setDetailedCrop (IImage8* im, rtengine::procparams::CropParams cp, int ax, int ay, int aw, int ah, int askip) { + + if (!enabled) + return; + + cimg.lock (); + + cropParams = cp; + + cropPixbuf.clear (); + if (cropimg) + delete [] cropimg; + cropimg = NULL; + + if (ax==cropX && ay==cropY && aw==cropW && ah==cropH && askip==(zoom>=1000?1:zoom)) { + cropimg_width = im->getWidth (); + cropimg_height = im->getHeight (); + cropimg = new unsigned char [3*cropimg_width*cropimg_height]; + memcpy (cropimg, im->getData(), 3*cropimg_width*cropimg_height); + cix = ax; + ciy = ay; + ciw = aw; + cih = ah; + cis = askip; + chi->pending++; + g_idle_add (createpixbufs, chi); + } + cimg.unlock (); + } + +bool CropHandler::getWindow (int& cwx, int& cwy, int& cww, int& cwh, int& cskip) { + + cwx = cropX; + cwy = cropY; + cww = cropW; + cwh = cropH; + + // hack: if called before first size allocation the size will be 0 + if (cww<10) + cww = 10; + if (cwh<32) + cwh = 32; + + cskip = zoom>=1000 ? 1 : zoom; + + return true; +} + +void CropHandler::update () { + + if (crop) { +// crop->setWindow (cropX, cropY, cropW, cropH, zoom>=1000 ? 1 : zoom); --> we use the "getWindow" hook instead of setting the size before + crop->setListener (this); + cropPixbuf.clear (); + Glib::Thread::create(sigc::mem_fun(*crop, &DetailedCrop::fullUpdate), 0, false, true, Glib::THREAD_PRIORITY_NORMAL); + } +} + +void CropHandler::setEnabled (bool e) { + + enabled = e; + if (!enabled) { + if (crop) + crop->setListener (NULL); + cimg.lock (); + delete [] cropimg; + cropimg = NULL; + cropPixbuf.clear (); + cimg.unlock (); + } + else + update (); +} + +bool CropHandler::getEnabled () { + + return enabled; +} + +void CropHandler::getSize (int& w, int& h) { + + w = cropW; + h = cropH; +} + +void CropHandler::compDim () { + + cropX = cx; + cropY = cy; + cropW = cw; + cropH = ch; + + cutRectToImgBounds (cropX, cropY, cropW, cropH); +} + +void CropHandler::cutRectToImgBounds (int& x, int& y, int& w, int& h) { + + if (ipc) { + if (w > ipc->getFullWidth()) + w = ipc->getFullWidth(); + if (h > ipc->getFullHeight()) + h = ipc->getFullHeight(); + if (x < 0) + x = 0; + if (y < 0) + y = 0; + if (x + w >= ipc->getFullWidth()) + x = ipc->getFullWidth() - w; + if (y + h >= ipc->getFullHeight()) + y = ipc->getFullHeight() - h; + } +} diff --git a/rtgui/crophandler.h b/rtgui/crophandler.h new file mode 100755 index 000000000..990316342 --- /dev/null +++ b/rtgui/crophandler.h @@ -0,0 +1,94 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef __CROPHANDLER__ +#define __CROPHANDLER__ + +#include +#include + +class CropHandlerListener { + + public: + virtual void cropImageUpdated () {} + virtual void cropWindowChanged () {} + virtual void initialImageArrived () {} +}; + +class CropHandler; +struct CropHandlerIdleHelper { + CropHandler* cropHandler; + bool destroyed; + int pending; +}; + +class CropHandler : public rtengine::DetailedCropListener, public rtengine::SizeListener { + + friend int createpixbufs (void* data); + + protected: + int zoom; + int ww, wh; // size of the crop view on the screen + int cx, cy, cw, ch; // position and size of the requested crop + int cropX, cropY, cropW, cropH; // position and size of the crop corresponding to cropPixbuf + bool enabled; + unsigned char* cropimg; + int cropimg_width, cropimg_height, cix, ciy, ciw, cih, cis; + bool initial; + + rtengine::StagedImageProcessor* ipc; + rtengine::DetailedCrop* crop; + + CropHandlerListener* listener; + CropHandlerIdleHelper* chi; + + void update (); + void compDim (); + public: + + rtengine::procparams::CropParams cropParams; + Glib::RefPtr cropPixbuf; + Glib::Mutex cimg; + + CropHandler (); + ~CropHandler (); + + void setCropHandlerListener (CropHandlerListener* l) { listener = l; } + + void newImage (rtengine::StagedImageProcessor* ipc_); + void setZoom (int z, int centerx=-1, int centery=-1); + double getFitZoom (); + void setWSize (int w, int h); + void getWSize (int& w, int &h); + void setPosition (int x, int y, bool update=true); + void getPosition (int& x, int& y); + void getSize (int& w, int& h); + + void setEnabled (bool e); + bool getEnabled (); + + // DetailedCropListener interface + void setDetailedCrop (rtengine::IImage8* im, rtengine::procparams::CropParams cp, int cx, int cy, int cw, int ch, int skip); + bool getWindow (int& cwx, int& cwy, int& cww, int& cwh, int& cskip); + // SizeListener interface + void sizeChanged (int w, int h, int ow, int oh); + + void cutRectToImgBounds (int& x, int& y, int& w, int& h); +}; + +#endif diff --git a/rtgui/cropwindow.cc b/rtgui/cropwindow.cc new file mode 100755 index 000000000..871108485 --- /dev/null +++ b/rtgui/cropwindow.cc @@ -0,0 +1,1030 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include +#include +#include +#include + +struct ZoomStep { + Glib::ustring label; + double zoom; + int czoom; +}; + +ZoomStep zoomSteps[] = {"10%", 0.1, 10, + "12.5%", 0.125, 8, + "16.6%", 1.0/6.0, 6, + "20%", 0.2, 5, + "25%", 0.25, 4, + "33%", 1.0/3.0, 3, + "50%", 0.5, 2, + "100%", 1.0, 1000, + "200%", 2.0, 2000, + "300%", 3.0, 3000, + "400%", 4.0, 4000, + "500%", 5.0, 5000, + "600%", 6.0, 6000, + "700%", 7.0, 7000, + "800%", 8.0, 8000}; +#define MAXZOOMSTEPS 14 +#define ZOOM11INDEX 7 + +CropWindow::CropWindow (ImageArea* parent, rtengine::StagedImageProcessor* ipc_) + : iarea(parent), cropgl(NULL), xpos(30), ypos(30), imgX(0), imgY(0), imgW(1), imgH(1), + titleHeight(30), sideBorderWidth(3), upperBorderWidth(1), lowerBorderWidth(3), sepWidth(2), + cropZoom(ZOOM11INDEX), deleted(false), onResizeArea(false), fitZoom(false), + fitZoomEnabled(true), decorated(true), backColor(0), observedCropWin(NULL), + pmlistener(NULL) { + + Glib::RefPtr context = parent->get_pango_context () ; + Pango::FontDescription fontd = context->get_font_description (); + fontd.set_weight (Pango::WEIGHT_BOLD); + fontd.set_size(8*Pango::SCALE); + context->set_font_description (fontd); + cropLabel = "100%"; + Glib::RefPtr cllayout = parent->create_pango_layout("1000%"); + + int iw, ih; + cllayout->get_pixel_size (iw, ih); + + titleHeight = ih; + + resizeSurface = Cairo::ImageSurface::create_from_png (argv0+"/images/resize.png"); + bZoomIn = new LWButton (Cairo::ImageSurface::create_from_png (argv0+"/images/gtk-zoom-in.png"), 0, NULL, LWButton::Left, LWButton::Center, "Zoom In"); + bZoomOut = new LWButton (Cairo::ImageSurface::create_from_png (argv0+"/images/gtk-zoom-out.png"), 1, NULL, LWButton::Left, LWButton::Center, "Zoom Out"); + bZoom100 = new LWButton (Cairo::ImageSurface::create_from_png (argv0+"/images/gtk-zoom-100.png"), 2, NULL, LWButton::Left, LWButton::Center, "Zoom 100/%"); + bZoomFit = new LWButton (Cairo::ImageSurface::create_from_png (argv0+"/images/gtk-zoom-fit.png"), 3, NULL, LWButton::Left, LWButton::Center, "Zoom Fit"); + bClose = new LWButton (Cairo::ImageSurface::create_from_png (argv0+"/images/gtk-close.png"), 4, NULL, LWButton::Right, LWButton::Center, "Close"); + + buttonSet.add (bZoomIn); + buttonSet.add (bZoomOut); + buttonSet.add (bZoom100); + buttonSet.add (bClose); + + buttonSet.setColors (Gdk::Color("black"), Gdk::Color("white")); + buttonSet.setButtonListener (this); + + int bsw, bsh; + buttonSet.getMinimalDimensions (bsw, bsh); + + if (bsh>titleHeight) + titleHeight = bsh; + + minWidth = bsw + iw + 2*sideBorderWidth; + + setSize (300, 300); + cropHandler.newImage (ipc_); + cropHandler.setPosition (0,0); + cropHandler.setEnabled (true); + cropHandler.setCropHandlerListener (this); + state = SNormal; +} + +CropWindow::~CropWindow () { + +} + +void CropWindow::setPosition (int x, int y) { + + if (y<0) + y = 0; + xpos = x; + ypos = y; + if (decorated) + buttonSet.arrangeButtons (xpos + sideBorderWidth, ypos + upperBorderWidth, width - 2*sideBorderWidth, titleHeight); +} + +void CropWindow::getPosition (int& x, int& y) { + + x = xpos; + y = ypos; +} + +void CropWindow::getCropPosition (int& x, int& y) { + + int cropX, cropY; + cropHandler.getPosition (cropX, cropY); + if (state!=SCropImgMove) { + x = cropX; + y = cropY; + } + else { + x = cropX + action_x; + y = cropY + action_y; + } +} + +void CropWindow::getCropRectangle (int& x, int& y, int& w, int& h) { + + int cropX, cropY, cropW, cropH; + cropHandler.getPosition (cropX, cropY); + cropHandler.getSize (cropW, cropH); + if (state!=SCropImgMove) { + x = cropX; + y = cropY; + } + else { + x = cropX + action_x; + y = cropY + action_y; + } + if (state!=SCropWinResize) { + w = cropW; + h = cropH; + } + else { + w = imgAreaW; + h = imgAreaH; + } + cropHandler.cutRectToImgBounds (x, y, w, h); +} + +void CropWindow::setCropPosition (int x, int y) { + + cropHandler.setPosition (x, y); + for (std::list::iterator i=listeners.begin(); i!=listeners.end(); i++) + (*i)->cropPositionChanged (this); +} + +void CropWindow::setSize (int w, int h, bool norefresh) { + + width = w; + height = h; + + fitZoom = false; + + if (widthredraw (); +} + +void CropWindow::getSize (int& w, int& h) { + + w = width; + h = height; +} + +void CropWindow::getCropSize (int& w, int& h) { + + w = imgAreaW; + h = imgAreaH; +} + +bool CropWindow::isInside (int x, int y) { + + return x>=xpos && x=ypos && ygrabFocus (this); + if (button==1 && type==GDK_2BUTTON_PRESS && onArea (CropImage, x, y) && (state==SNormal || state==SCropImgMove)) { + if (fitZoomEnabled) { + if (fitZoom) { + translateCoord (x, y, action_x, action_y); + changeZoom (ZOOM11INDEX, true, action_x, action_y); + fitZoom = false; + } + else + zoomFit (); + } + else + zoom11 (); + state = SNormal; + } + else if (button==1 && type==GDK_2BUTTON_PRESS && onArea (CropBorder, x, y)) { + backColor = (backColor+1) % 3; + } + else if (button==1 && type==GDK_BUTTON_PRESS && state==SNormal && onArea (CropToolBar, x, y)) { + if (!decorated || !buttonSet.pressNotify (x, y)) { + state = SCropWinMove; + action_x = x; + action_y = y; + press_x = xpos; + press_y = ypos; + } + } + else if (button==1 && type==GDK_BUTTON_PRESS && state==SNormal && onArea (CropResize, x, y)) { + state = SCropWinResize; + action_x = x; + action_y = y; + press_x = width; + press_y = height; + } + else if (button==1 && type==GDK_BUTTON_PRESS && state==SNormal && onArea (CropImage, x, y)) { + if (onArea (CropTop, x, y)) { + state = SResizeH1; + press_y = y; + action_y = cropHandler.cropParams.y; + } + else if (onArea (CropBottom, x, y)) { + state = SResizeH2; + press_y = y; + action_y = cropHandler.cropParams.h; + } + else if (onArea (CropLeft, x, y)) { + state = SResizeW1; + press_x = x; + action_x = cropHandler.cropParams.x; + } + else if (onArea (CropRight, x, y)) { + state = SResizeW2; + press_x = x; + action_x = cropHandler.cropParams.w; + } + else if (onArea (CropObserved, x, y)) { + state = SObservedMove; + press_x = x; + press_y = y; + } + else if ((bstate & GDK_SHIFT_MASK) && onArea (CropInside, x, y)) { + state = SCropMove; + press_x = x; + press_y = y; + action_x = cropHandler.cropParams.x; + action_y = cropHandler.cropParams.y; + } + else if (iarea->getToolMode () == TMHand) { + state = SCropImgMove; + action_x = 0; + action_y = 0; + press_x = x; + press_y = y; + } + else if (iarea->getToolMode () == TMStraighten) { + state = SRotateSelecting; + press_x = x; + press_y = y; + action_x = x; + action_y = y; + rot_deg = 0; + } + else if (iarea->getToolMode () == TMSpotWB) { + translateCoord (x, y, action_x, action_y); + iarea->spotWBSelected (action_x, action_y); + } + else if (iarea->getToolMode () == TMCropSelect && cropgl) { + state = SCropSelecting; + translateCoord (x, y, press_x, press_y); + cropHandler.cropParams.x = press_x; + cropHandler.cropParams.y = press_y; + cropHandler.cropParams.w = cropHandler.cropParams.h = 1; + cropgl->cropInit (cropHandler.cropParams.x, cropHandler.cropParams.y, cropHandler.cropParams.w, cropHandler.cropParams.h); + } + } + if (button==3) { + state = SNormal; + iarea->setToolHand (); + } + iarea->redraw (); + updateCursor (x, y); +} + +void CropWindow::buttonRelease (int button, int num, int bstate, int x, int y) { + + if (state==SCropWinResize) { + setSize (press_x + x - action_x, press_y + y - action_y); + state = SNormal; + for (std::list::iterator i=listeners.begin(); i!=listeners.end(); i++) + (*i)->cropWindowSizeChanged (this); + } + else if (state==SCropImgMove) { + int cropX, cropY; + cropHandler.getPosition (cropX, cropY); + cropHandler.setPosition (cropX + action_x, cropY + action_y); + cropHandler.getPosition (cropX, cropY); + state = SNormal; + for (std::list::iterator i=listeners.begin(); i!=listeners.end(); i++) + (*i)->cropPositionChanged (this); + } + else if (state==SRotateSelecting) { + iarea->straightenReady (rot_deg); + iarea->setToolHand (); + } + else if (state==SObservedMove) { + observedCropWin->remoteMoveReady (); + state = SNormal; + } + if (cropgl && (state==SCropSelecting || state==SResizeH1 || state==SResizeH2 || state==SResizeW1 || state==SResizeW2 || state==SCropMove)) { + cropgl->cropManipReady (); + iarea->setToolHand (); + } + + if (decorated) + buttonSet.releaseNotify (x, y); + if (deleted) + return; + + state = SNormal; + iarea->grabFocus (NULL); + iarea->redraw (); + updateCursor (x, y); +} + +void CropWindow::pointerMoved (int x, int y) { + + if (state==SCropWinMove) { + setPosition (press_x + x - action_x, press_y + y - action_y); + iarea->redraw (); + } + else if (state==SCropWinResize) { + setSize (press_x + x - action_x, press_y + y - action_y, true); + for (std::list::iterator i=listeners.begin(); i!=listeners.end(); i++) + (*i)->cropWindowSizeChanged (this); + iarea->redraw (); + } + else if (state==SCropImgMove) { + action_x = (press_x - x) / zoomSteps[cropZoom].zoom; + action_y = (press_y - y) / zoomSteps[cropZoom].zoom; + for (std::list::iterator i=listeners.begin(); i!=listeners.end(); i++) + (*i)->cropPositionChanged (this); + iarea->redraw (); + } + else if (state==SRotateSelecting) { + action_x = x; + action_y = y; + iarea->redraw (); + } + else if (state==SNormal && iarea->getToolMode () == TMSpotWB) { + action_x = x; + action_y = y; + iarea->redraw (); + } + else if (state==SResizeH1 && cropgl) { + int oy = cropHandler.cropParams.y; + cropHandler.cropParams.y = action_y + (y-press_y) / zoomSteps[cropZoom].zoom; + cropHandler.cropParams.h += oy - cropHandler.cropParams.y; + cropgl->cropHeight1Resized (cropHandler.cropParams.x, cropHandler.cropParams.y, cropHandler.cropParams.w, cropHandler.cropParams.h); + iarea->redraw (); + } + else if (state==SResizeH2 && cropgl) { + cropHandler.cropParams.h = action_y + (y-press_y) / zoomSteps[cropZoom].zoom; + cropgl->cropHeight2Resized (cropHandler.cropParams.x, cropHandler.cropParams.y, cropHandler.cropParams.w, cropHandler.cropParams.h); + iarea->redraw (); + } + else if (state==SResizeW1 && cropgl) { + int ox = cropHandler.cropParams.x; + cropHandler.cropParams.x = action_x + (x-press_x) / zoomSteps[cropZoom].zoom; + cropHandler.cropParams.w += ox - cropHandler.cropParams.x; + cropgl->cropWidth1Resized (cropHandler.cropParams.x, cropHandler.cropParams.y, cropHandler.cropParams.w, cropHandler.cropParams.h); + iarea->redraw (); + } + else if (state==SResizeW2 && cropgl) { + cropHandler.cropParams.w = action_x + (x-press_x) / zoomSteps[cropZoom].zoom; + cropgl->cropWidth2Resized (cropHandler.cropParams.x, cropHandler.cropParams.y, cropHandler.cropParams.w, cropHandler.cropParams.h); + iarea->redraw (); + } + else if (state==SCropMove && cropgl) { + cropHandler.cropParams.x = action_x + (x-press_x) / zoomSteps[cropZoom].zoom; + cropHandler.cropParams.y = action_y + (y-press_y) / zoomSteps[cropZoom].zoom; + cropgl->cropMoved (cropHandler.cropParams.x, cropHandler.cropParams.y, cropHandler.cropParams.w, cropHandler.cropParams.h); + iarea->redraw (); + } + else if (state==SCropSelecting && cropgl) { + translateCoord (x, y, action_x, action_y); + int cx1 = press_x, cy1 = press_y; + int cx2 = action_x, cy2 = action_y; + cropgl->cropResized (cx1, cy1, cx2, cy2); + if (cx2 > cx1) { + cropHandler.cropParams.x = cx1; + cropHandler.cropParams.w = cx2 - cx1 + 1; + } + else { + cropHandler.cropParams.x = cx2; + cropHandler.cropParams.w = cx1 - cx2 + 1; + } + if (cy2 > cy1) { + cropHandler.cropParams.y = cy1; + cropHandler.cropParams.h = cy2 - cy1 + 1; + } + else { + cropHandler.cropParams.y = cy2; + cropHandler.cropParams.h = cy1 - cy2 + 1; + } + iarea->redraw (); + } + else if (state==SObservedMove) { + observedCropWin->remoteMove ((x - press_x)/zoomSteps[cropZoom].zoom, (y - press_y)/zoomSteps[cropZoom].zoom); + iarea->redraw (); + } + updateCursor (x, y); + + bool oRA = onArea (CropResize, x, y); + if (oRA!=onResizeArea) { + onResizeArea = oRA; + iarea->redraw (); + } + + if (decorated) + buttonSet.motionNotify (x, y); + + if (pmlistener) { + int mx, my; + translateCoord (x, y, mx, my); + if (!onArea (CropImage, x, y) || !cropHandler.cropPixbuf) + pmlistener->pointerMoved (false, mx, my, -1, -1, -1); + else { + cropHandler.cimg.lock (); + int vx = x - xpos - imgX; + int vy = y - ypos - imgY; + guint8* pix = cropHandler.cropPixbuf->get_pixels() + vy*cropHandler.cropPixbuf->get_rowstride() + vx*3; + if (vx < cropHandler.cropPixbuf->get_width() && vy < cropHandler.cropPixbuf->get_height()) + pmlistener->pointerMoved (true, mx, my, pix[0], pix[1], pix[2]); + cropHandler.cimg.unlock (); + } + } +} + +bool CropWindow::onArea (CursorArea a, int x, int y) { + + int CROPRESIZEBORDER = 6 / zoomSteps[cropZoom].zoom; + int x1, y1, w, h; + switch (a) { + case CropWinButtons: + return decorated && buttonSet.inside (x, y); + case CropToolBar: + return x>xpos && y>ypos && x=xpos+imgX && y>=ypos+imgY && x=xpos+imgAreaX && y>=ypos+imgAreaY && x=xpos+imgX && y>=ypos+imgY && xcropHandler.cropParams.x+CROPRESIZEBORDER && + x1cropHandler.cropParams.y-CROPRESIZEBORDER && + y1cropHandler.cropParams.x+CROPRESIZEBORDER && + x1cropHandler.cropParams.y+cropHandler.cropParams.h-1-CROPRESIZEBORDER && + y1cropHandler.cropParams.y+CROPRESIZEBORDER && + y1cropHandler.cropParams.x-CROPRESIZEBORDER && + x1cropHandler.cropParams.y+CROPRESIZEBORDER && + y1cropHandler.cropParams.x+cropHandler.cropParams.w-1-CROPRESIZEBORDER && + x1cropHandler.cropParams.y && + y1cropHandler.cropParams.x && + x1=xpos+width-16 && y>=ypos+height-16 && xx1-6 && y>y1-6 && xx1+2 && y>y1+2 && xgetToolMode (); + + if (state==SNormal) { + if (onArea (CropWinButtons, x, y)) + cursorManager.setCursor (iarea->get_window(), CSArrow); + else if (onArea (CropToolBar, x, y)) + cursorManager.setCursor (iarea->get_window(), CSMove); + else if (onArea (CropResize, x, y)) + cursorManager.setCursor (iarea->get_window(), CSResizeDiagonal); + else if (tm==TMHand && (onArea (CropTop, x, y) || onArea (CropBottom, x, y))) + cursorManager.setCursor (iarea->get_window(), CSResizeHeight); + else if (tm==TMHand && (onArea (CropLeft, x, y) || onArea (CropRight, x, y))) + cursorManager.setCursor (iarea->get_window(), CSResizeWidth); + else if (onArea (CropImage, x, y)) { + if (tm==TMHand) { + if (onArea (CropObserved, x, y)) + cursorManager.setCursor (iarea->get_window(), CSMove); + else + cursorManager.setCursor (iarea->get_window(), CSOpenHand); + } + else if (tm==TMSpotWB) + cursorManager.setCursor (iarea->get_window(), CSSpotWB); + else if (tm==TMCropSelect) + cursorManager.setCursor (iarea->get_window(), CSCropSelect); + else if (tm==TMStraighten) + cursorManager.setCursor (iarea->get_window(), CSStraighten); + } + else + cursorManager.setCursor (iarea->get_window(), CSArrow); + } + else if (state==SCropSelecting) + cursorManager.setCursor (iarea->get_window(), CSCropSelect); + else if (state==SRotateSelecting) + cursorManager.setCursor (iarea->get_window(), CSStraighten); + else if (state==SCropMove || state==SCropWinMove || state==SObservedMove) + cursorManager.setCursor (iarea->get_window(), CSMove); + else if (state==SHandMove || state==SCropImgMove) + cursorManager.setCursor (iarea->get_window(), CSClosedHand); + else if (state==SResizeW1 || state==SResizeW2) + cursorManager.setCursor (iarea->get_window(), CSResizeWidth); + else if (state==SResizeH1 || state==SResizeH2) + cursorManager.setCursor (iarea->get_window(), CSResizeHeight); + else if (state==SCropWinResize) + cursorManager.setCursor (iarea->get_window(), CSResizeDiagonal); +} + +void CropWindow::expose (Cairo::RefPtr cr) { + + MyTime t1, t2, t3, t4; + + t1.set (); + + if (decorated) + drawDecoration (cr); + + int x = xpos, y = ypos, h = height, w = width; + + // draw border + if (backColor==0) { + Gdk::Color cback = iarea->get_style()->get_bg(Gtk::STATE_NORMAL); + cr->set_source_rgb (cback.get_red_p(), cback.get_green_p(), cback.get_blue_p()); + } + else if (backColor==1) + cr->set_source_rgb (0,0,0); + else if (backColor==2) + cr->set_source_rgb (1,1,1); + + cr->rectangle (x+imgAreaX+0.5, y+imgAreaY+0.5, imgAreaW, imgAreaH); + cr->stroke_preserve (); + cr->fill (); + + cropHandler.cimg.lock (); + // draw image + if (state==SCropImgMove || state==SCropWinResize) { + // draw a rough image + int cropX, cropY; + cropHandler.getPosition (cropX, cropY); + if (state==SCropImgMove) { + cropX += action_x; + cropY += action_y; + } + Glib::RefPtr rough = iarea->getPreviewHandler()->getRoughImage (cropX, cropY, imgAreaW, imgAreaH, zoomSteps[cropZoom].zoom); + if (rough) { + iarea->get_window()->draw_pixbuf (iarea->get_style()->get_base_gc(Gtk::STATE_NORMAL), rough, 0, 0, x+imgAreaX+(imgAreaW-rough->get_width())/2, y+imgAreaY+(imgAreaH-rough->get_height())/2, -1, -1, Gdk::RGB_DITHER_NORMAL, 0, 0); +// if (cropHandler.cropParams.enabled) +// drawCrop (cr, x+imgX, y+imgY, imgW, imgH, cropX, cropY, zoomSteps[cropZoom].zoom, cropHandler.cropParams); + } + } + else { + if (cropHandler.cropPixbuf) { + imgW = cropHandler.cropPixbuf->get_width (); + imgH = cropHandler.cropPixbuf->get_height (); + imgX = imgAreaX + (imgAreaW-imgW)/2; + imgY = imgAreaY + (imgAreaH-imgH)/2; +// PERFORMANCE BOTTLENECK STARTS HERE + t3.set (); + bool showcs = iarea->indClippedPanel->showClippedShadows(); + bool showch = iarea->indClippedPanel->showClippedHighlights(); + if (showcs || showch) { + Glib::RefPtr tmp = cropHandler.cropPixbuf->copy (); + guint8* pix = tmp->get_pixels(); + for (int i=0; iget_height(); i++) + for (int j=0; jget_width(); j++) { + guint8* curr = pix + i*tmp->get_rowstride () + j*3; + if (showch && (curr[0]>=options.highlightThreshold || curr[1]>=options.highlightThreshold || curr[2]>=options.highlightThreshold)) + curr[0] = curr[1] = curr[2] = 0; + else if (showcs && (curr[0]<=options.shadowThreshold || curr[1]<=options.shadowThreshold || curr[2]<=options.shadowThreshold)) + curr[0] = curr[1] = curr[2] = 255; + } + iarea->get_window()->draw_pixbuf (iarea->get_style()->get_base_gc(Gtk::STATE_NORMAL), tmp, 0, 0, x+imgX, y+imgY, -1, -1, Gdk::RGB_DITHER_NONE, 0, 0); + } + else + iarea->get_window()->draw_pixbuf (iarea->get_style()->get_base_gc(Gtk::STATE_NORMAL), cropHandler.cropPixbuf, 0, 0, x+imgX, y+imgY, -1, -1, Gdk::RGB_DITHER_NONE, 0, 0); + t4.set (); +// END OF BOTTLENECK + if (cropHandler.cropParams.enabled) { + int cropX, cropY; + cropHandler.getPosition (cropX, cropY); + drawCrop (cr, x+imgX, y+imgY, imgW, imgH, cropX, cropY, zoomSteps[cropZoom].zoom, cropHandler.cropParams); + } + } + else { + int cropX, cropY; + cropHandler.getPosition (cropX, cropY); + Glib::RefPtr rough = iarea->getPreviewHandler()->getRoughImage (cropX, cropY, imgAreaW, imgAreaH, zoomSteps[cropZoom].zoom); + if (rough) { + iarea->get_window()->draw_pixbuf (iarea->get_style()->get_base_gc(Gtk::STATE_NORMAL), rough, 0, 0, x+imgAreaX+(imgAreaW-rough->get_width())/2, y+imgAreaY+(imgAreaH-rough->get_height())/2, -1, -1, Gdk::RGB_DITHER_NORMAL, 0, 0); + if (cropHandler.cropParams.enabled) { + int cropX, cropY; + cropHandler.getPosition (cropX, cropY); + drawCrop (cr, x+imgX, y+imgY, imgW, imgH, cropX, cropY, zoomSteps[cropZoom].zoom, cropHandler.cropParams); + } + } + } + } + + if (observedCropWin) + drawObservedFrame (cr); + + // if cursor stays above resize area, draw the icon + if (decorated && (state==SCropWinResize || onResizeArea)) { + int rw = resizeSurface->get_width (); + int rh = resizeSurface->get_height (); + cr->set_source_rgb (0.5,0.5,0.5); + cr->rectangle (x+w-1.5-rw-1, y+h-1.5-rh-1, rw+1, rh+1); + cr->stroke_preserve (); + cr->fill (); + cr->set_source (resizeSurface, x+w-1.5-rw, y+h-1.5-rh); + cr->paint (); + cr->set_source_rgb (0,0,0); + cr->move_to (x+w-2.5-rw, y+h-1.5); + cr->line_to (x+w-2.5-rw, y+h-2.5-rh); + cr->line_to (x+w-1.5, y+h-2.5-rh); + cr->stroke (); + } + if (state==SRotateSelecting) + drawStraightenGuide (cr); + if (state==SNormal && iarea->getToolMode () == TMSpotWB) + drawSpotWBRectangle (cr); + + t2.set (); + cropHandler.cimg.unlock (); +// printf ("etime --> %d, %d\n", t2.etime (t1), t4.etime (t3)); +} + +void CropWindow::zoomIn () { + + changeZoom (cropZoom+1); + fitZoom = false; +} + +void CropWindow::zoomOut () { + + changeZoom (cropZoom-1); + fitZoom = false; +} + +void CropWindow::zoom11 () { + + changeZoom (ZOOM11INDEX); + fitZoom = false; +} + +double CropWindow::getZoom () { + + return zoomSteps[cropZoom].zoom; +} + +void CropWindow::setZoom (double zoom) { + + int cz = MAXZOOMSTEPS; + if (zoom < zoomSteps[0].zoom) + cz = 0; + else + for (int i=0; i zoom) { + cz = i; + break; + } + changeZoom (cz, false); +} + +void CropWindow::zoomFit () { + + double z = cropHandler.getFitZoom (); + int cz = MAXZOOMSTEPS; + if (z < zoomSteps[0].zoom) + cz = 0; + else + for (int i=0; i z) { + cz = i; + break; + } + changeZoom (cz); + fitZoom = true; +} + +void CropWindow::buttonPressed (LWButton* button, int actionCode, void* actionData) { + + if (button==bZoomIn) // zoom in + zoomIn (); + else if (button==bZoomOut) // zoom out + zoomOut (); + else if (button==bZoom100) // zoom 100 + zoom11 (); + else if (button==bClose) {// close + deleted = true; + iarea->cropWindowClosed (this); + } +} + +void CropWindow::redrawNeeded (LWButton* button) { + + iarea->redraw (); +} + +void CropWindow::changeZoom (int zoom, bool notify, int centerx, int centery) { + + cropZoom = zoom; + if (cropZoom<0) + cropZoom = 0; + else if (cropZoom>MAXZOOMSTEPS) + cropZoom = MAXZOOMSTEPS; + + cropLabel = zoomSteps[cropZoom].label; + cropHandler.setZoom (zoomSteps[cropZoom].czoom, centerx, centery); + if (notify) + for (std::list::iterator i=listeners.begin(); i!=listeners.end(); i++) + (*i)->cropZoomChanged (this); + iarea->redraw (); +} + +void CropWindow::translateCoord (int phyx, int phyy, int& imgx, int& imgy) { + + int cropX, cropY; + cropHandler.getPosition (cropX, cropY); + imgx = cropX + (phyx - xpos - imgX)/zoomSteps[cropZoom].zoom; + imgy = cropY + (phyy - ypos - imgY)/zoomSteps[cropZoom].zoom; +} + +void CropWindow::drawDecoration (Cairo::RefPtr cr) { + + int x = xpos, y = ypos; + // prepare label + Glib::RefPtr context = iarea->get_pango_context () ; + Pango::FontDescription fontd = context->get_font_description (); + fontd.set_weight (Pango::WEIGHT_BOLD); + fontd.set_size(8*Pango::SCALE); + context->set_font_description (fontd); + Glib::RefPtr cllayout = iarea->create_pango_layout(cropLabel); + int iw, ih; + cllayout->get_pixel_size (iw, ih); + + // draw decoration (border) + int h = height, w = width; + cr->set_source_rgb (0,0,0); + cr->set_line_width (1.0); + cr->move_to (x+0.5, y+h-0.5); + cr->line_to (x+0.5, y+0.5); + cr->line_to (x+w-0.5, y+0.5); + cr->stroke (); + cr->set_source_rgb (1,1,1); + cr->move_to (x+w-0.5, y+0.5); + cr->line_to (x+w-0.5, y+h-0.5); + cr->line_to (x+0.5, y+h-0.5); + cr->stroke (); + cr->set_source_rgb (0.5,0.5,0.5); + cr->rectangle (x+1.5, y+1.5+titleHeight, w-3, h-titleHeight-3); + cr->stroke (); + cr->set_source_rgb (1,1,1); + cr->move_to (x+2.5, y+h-2.5); + cr->line_to (x+2.5, y+titleHeight+2.5); + cr->line_to (x+w-2.5, y+titleHeight+2.5); + cr->stroke (); + cr->set_source_rgb (0,0,0); + cr->move_to (x+w-2.5, y+titleHeight+2.5); + cr->line_to (x+w-2.5, y+h-2.5); + cr->line_to (x+2.5, y+h-2.5); + cr->stroke (); + cr->set_source_rgb (0.5,0.5,0.5); + cr->rectangle (x+1.5, y+1.5, w-3, titleHeight); + cr->stroke_preserve (); + cr->fill (); + + // draw label + cr->set_source_rgb (1,1,1); + cr->move_to (x+6+sideBorderWidth+bZoomIn->getIcon()->get_width()+bZoomOut->getIcon()->get_width()+bZoom100->getIcon()->get_width(), y+upperBorderWidth+(titleHeight-ih)/2); + cllayout->add_to_cairo_context (cr); + cr->fill (); + + buttonSet.redraw (cr); +} + +void CropWindow::drawStraightenGuide (Cairo::RefPtr cr) { + + if (action_x!=press_x || action_y!=press_y) { + double arg = (press_x-action_x) / sqrt((press_x-action_x)*(press_x-action_x)+(press_y-action_y)*(press_y-action_y)); + double sol1, sol2; + double pi = M_PI; + if (press_y>action_y) { + sol1 = acos(arg)*180/pi; + sol2 = -acos(-arg)*180/pi; + } + else { + sol1 = acos(-arg)*180/pi; + sol2 = -acos(arg)*180/pi; + } + if (fabs(sol1)45) + rot_deg = - 90.0 + rot_deg; + } + else + rot_deg = 0; + + Glib::RefPtr context = iarea->get_pango_context () ; + Pango::FontDescription fontd = context->get_font_description (); + fontd.set_weight (Pango::WEIGHT_BOLD); + fontd.set_size (8*Pango::SCALE); + context->set_font_description (fontd); + Glib::RefPtr deglayout = iarea->create_pango_layout(Glib::ustring::compose ("%1 deg", Glib::ustring::format(std::setprecision(2), rot_deg))); + + int x1 = press_x; + int y1 = press_y; + int y2 = action_y; + int x2 = action_x; +/* if (x1<0) x1 = 0; + if (y1<0) y1 = 0; + if (x2<0) x2 = 0; + if (y2<0) y2 = 0; + if (x2>=image->getWidth()) x2 = image->getWidth()-1; + if (y2>=image->getHeight()) y2 = image->getHeight()-1; + if (x1>=image->getWidth()) x1 = image->getWidth()-1; + if (y1>=image->getHeight()) y1 = image->getHeight()-1; +*/ + + cr->set_line_width (1.5); + cr->set_source_rgb (1.0, 1.0, 1.0); + cr->move_to (x1, y1); + cr->line_to (x2, y2); + cr->stroke (); + cr->set_source_rgb (0.0, 0.0, 0.0); + std::valarray ds (1); + ds[0] = 4; + cr->set_dash (ds, 0); + cr->move_to (x1, y1); + cr->line_to (x2, y2); + cr->stroke (); + + if (press_x!=action_x && press_y!=action_y) { + cr->set_source_rgb (0.0, 0.0, 0.0); + cr->move_to ((x1+x2)/2+1, (y1+y2)/2+1); + deglayout->add_to_cairo_context (cr); + cr->move_to ((x1+x2)/2+1, (y1+y2)/2-1); + deglayout->add_to_cairo_context (cr); + cr->move_to ((x1+x2)/2-1, (y1+y2)/2+1); + deglayout->add_to_cairo_context (cr); + cr->move_to ((x1+x2)/2+1, (y1+y2)/2+1); + deglayout->add_to_cairo_context (cr); + cr->fill (); + cr->set_source_rgb (1.0, 1.0, 1.0); + cr->move_to ((x1+x2)/2, (y1+y2)/2); + deglayout->add_to_cairo_context (cr); + cr->fill (); + } +} + +void CropWindow::drawSpotWBRectangle (Cairo::RefPtr cr) { + + int rectsize = iarea->getSpotWBRectSize (); + int x1 = action_x/zoomSteps[cropZoom].zoom - rectsize; + int y1 = action_y/zoomSteps[cropZoom].zoom - rectsize; + int y2 = action_y/zoomSteps[cropZoom].zoom + rectsize; + int x2 = action_x/zoomSteps[cropZoom].zoom + rectsize; + + cr->set_line_width (1.0); + cr->rectangle (xpos+imgX-0.5, ypos+imgY-0.5, imgW, imgH); + cr->clip (); + + cr->set_source_rgb (1.0, 1.0, 1.0); + cr->rectangle (x1*zoomSteps[cropZoom].zoom-1.5, y1*zoomSteps[cropZoom].zoom-1.5, x2*zoomSteps[cropZoom].zoom-x1*zoomSteps[cropZoom].zoom+2, y2*zoomSteps[cropZoom].zoom-y1*zoomSteps[cropZoom].zoom+2); + cr->stroke (); + cr->set_source_rgb (0.0, 0.0, 0.0); + cr->rectangle (x1*zoomSteps[cropZoom].zoom-0.5, y1*zoomSteps[cropZoom].zoom-0.5, x2*zoomSteps[cropZoom].zoom-x1*zoomSteps[cropZoom].zoom, y2*zoomSteps[cropZoom].zoom-y1*zoomSteps[cropZoom].zoom); + cr->stroke (); + + cr->reset_clip (); +} + +void CropWindow::getObservedFrameArea (int& x, int& y, int& w, int& h) { + + int cropX, cropY, cropW, cropH; + observedCropWin->getCropRectangle (cropX, cropY, cropW, cropH); + int myCropX, myCropY, myCropW, myCropH; + getCropRectangle (myCropX, myCropY, myCropW, myCropH); + + // translate it to screen coordinates + x = xpos + imgX + (cropX-myCropX)*zoomSteps[cropZoom].zoom; + y = ypos + imgY + (cropY-myCropY)*zoomSteps[cropZoom].zoom; + w = cropW * zoomSteps[cropZoom].zoom; + h = cropH * zoomSteps[cropZoom].zoom; +} + +void CropWindow::drawObservedFrame (Cairo::RefPtr cr) { + + int x, y, w, h; + getObservedFrameArea (x, y, w, h); + + cr->set_source_rgb (1.0, 1.0, 1.0); + cr->set_line_width (4); + cr->rectangle (x-2, y-2, w+4, h+4); + cr->stroke (); + cr->set_source_rgb (1.0, 0.0, 0.0); + cr->set_line_width (2); + cr->rectangle (x-2, y-2, w+4, h+4); + cr->stroke (); +} + +void CropWindow::cropImageUpdated () { + + iarea->redraw (); +} + +void CropWindow::cropWindowChanged () { + + if (!decorated) + iarea->updateScrollbars (); + iarea->redraw (); +} + +void CropWindow::initialImageArrived () { + + for (std::list::iterator i=listeners.begin(); i!=listeners.end(); i++) + (*i)->initialImageArrived (this); +} + + +void CropWindow::remoteMove (int deltaX, int deltaY) { + + state = SCropImgMove; + action_x = deltaX; + action_y = deltaY; + for (std::list::iterator i=listeners.begin(); i!=listeners.end(); i++) + (*i)->cropPositionChanged (this); +} + +void CropWindow::remoteMoveReady () { + + int cropX, cropY; + cropHandler.getPosition (cropX, cropY); + cropHandler.setPosition (cropX + action_x, cropY + action_y); + cropHandler.getPosition (cropX, cropY); + state = SNormal; + for (std::list::iterator i=listeners.begin(); i!=listeners.end(); i++) + (*i)->cropPositionChanged (this); +} + +void CropWindow::delCropWindowListener (CropWindowListener* l) { + + std::list::iterator i=listeners.begin(); + while (i!=listeners.end()) + if (*i==l) + i = listeners.erase (i); + else + i++; +} diff --git a/rtgui/cropwindow.h b/rtgui/cropwindow.h new file mode 100755 index 000000000..35372efca --- /dev/null +++ b/rtgui/cropwindow.h @@ -0,0 +1,146 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _CROPWINDOW_ +#define _CROPWINDOW_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class CropWindow; +class CropWindowListener { + + public: + virtual void cropPositionChanged (CropWindow*) {} + virtual void cropWindowSizeChanged (CropWindow*) {} + virtual void cropZoomChanged (CropWindow*) {} + virtual void initialImageArrived (CropWindow*) {} +}; + +class ImageArea; +class CropWindow : public LWButtonListener, public CropHandlerListener { + + // state management + ImgEditState state; // current state of user (see enum State) + int action_x, action_y, press_x, press_y; + double rot_deg; + bool onResizeArea; + bool deleted; + bool fitZoomEnabled; + bool fitZoom; + + // decoration + Cairo::RefPtr resizeSurface; + LWButton *bZoomIn, *bZoomOut, *bZoom100, *bZoomFit, *bClose; + LWButtonSet buttonSet; + Glib::ustring cropLabel; + int backColor; + bool decorated; + + // sizes, positions + int titleHeight, sideBorderWidth, lowerBorderWidth, upperBorderWidth, sepWidth, minWidth; + int imgAreaX, imgAreaY, imgAreaW, imgAreaH; + int imgX, imgY, imgW, imgH; + int xpos, ypos, width, height; + + // image handling + CropHandler cropHandler; + ImageArea* iarea; + int cropZoom; // *1000 + + // crop gui listener + CropGUIListener* cropgl; + PointerMotionListener* pmlistener; + std::list listeners; + + CropWindow* observedCropWin; + + bool onArea (CursorArea a, int x, int y); + void updateCursor (int x, int y); + void drawDecoration (Cairo::RefPtr cr); + void drawStraightenGuide (Cairo::RefPtr cr); + void drawSpotWBRectangle (Cairo::RefPtr cr); + void drawObservedFrame (Cairo::RefPtr cr); + void translateCoord (int phyx, int phyy, int& imgx, int& imgy); + void changeZoom (int zoom, bool notify=true, int centerx=-1, int centery=-1); + void getObservedFrameArea(int& x, int& y, int& w, int& h); + + public: + CropWindow (ImageArea* parent, rtengine::StagedImageProcessor* ipc_); + ~CropWindow (); + + void setDecorated (bool decorated) { this->decorated = decorated; } + void setFitZoomEnabled (bool fze) { fitZoomEnabled = fze; } + void setObservedCropWin (CropWindow* cw) { observedCropWin = cw; } + + void setPosition (int x, int y); + void getPosition (int& x, int& y); + void setSize (int w, int h, bool norefresh=false); + void getSize (int& w, int& h); + + // zoomlistener interface + void zoomIn (); + void zoomOut (); + void zoom11 (); + void zoomFit (); + double getZoom (); + void setZoom (double zoom); + + bool isInside (int x, int y); + + void buttonPress (int button, int num, int state, int x, int y); + void buttonRelease (int button, int num, int state, int x, int y); + void pointerMoved (int x, int y); + + void expose (Cairo::RefPtr cr); + + // interface lwbuttonlistener + void buttonPressed (LWButton* button, int actionCode, void* actionData); + void redrawNeeded (LWButton* button); + + // crop handling + void getCropRectangle (int& x, int& y, int& w, int& h); + void getCropPosition (int& x, int& y); + void setCropPosition (int x, int y); + void getCropSize (int& w, int& h); + + // listeners + void setCropGUIListener (CropGUIListener* cgl) { cropgl = cgl; } + void setPointerMotionListener (PointerMotionListener* pml) { pmlistener = pml; } + + // crop window listeners + void addCropWindowListener (CropWindowListener* l) { listeners.push_back (l); } + void delCropWindowListener (CropWindowListener* l); + + // crophandlerlistener interface + void cropImageUpdated (); + void cropWindowChanged (); + void initialImageArrived (); + + void remoteMove (int deltaX, int deltaY); + void remoteMoveReady (); +}; + +#endif diff --git a/rtgui/cursormanager.cc b/rtgui/cursormanager.cc new file mode 100755 index 000000000..e4adec0e4 --- /dev/null +++ b/rtgui/cursormanager.cc @@ -0,0 +1,68 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +CursorManager cursorManager; + +void CursorManager::init (Glib::RefPtr mainWin) { + + cResizeWidth = new Gdk::Cursor (Gdk::SB_H_DOUBLE_ARROW); + cResizeHeight = new Gdk::Cursor (Gdk::SB_V_DOUBLE_ARROW); + cResizeDiag = new Gdk::Cursor (Gdk::BOTTOM_RIGHT_CORNER); + cCropMove = new Gdk::Cursor (Gdk::FLEUR); + cCropMoving = new Gdk::Cursor (Gdk::HAND2); + cCropSelection = new Gdk::Cursor (Gdk::CROSSHAIR); +#ifdef _WIN32 + cNormal = new Gdk::Cursor (Gdk::LAST_CURSOR); +#else + cNormal = new Gdk::Cursor (Gdk::ARROW); +#endif + cHand = new Gdk::Cursor (cNormal->get_display(), Gdk::Pixbuf::create_from_file(argv0+"/images/openhand22.png"), 10, 10); + cClosedHand = new Gdk::Cursor (cNormal->get_display(), Gdk::Pixbuf::create_from_file(argv0+"/images/closedhand22.png"), 10, 10); + cWB = new Gdk::Cursor (cNormal->get_display(), Gdk::Pixbuf::create_from_file(argv0+"/images/wbpicker16.png"), 1, 12); + + mainWindow = mainWin; +} + +void CursorManager::setCursor (Glib::RefPtr window, CursorShape shape) { + + if (shape==CSArrow) + window->set_cursor (*cNormal); + else if (shape==CSOpenHand) + window->set_cursor (*cHand); + else if (shape==CSClosedHand) + window->set_cursor (*cClosedHand); + else if (shape==CSMove) + window->set_cursor (*cCropMove); + else if (shape==CSResizeWidth) + window->set_cursor (*cResizeWidth); + else if (shape==CSResizeHeight) + window->set_cursor (*cResizeHeight); + else if (shape==CSResizeDiagonal) + window->set_cursor (*cResizeDiag); + else if (shape==CSSpotWB) + window->set_cursor (*cWB); + else if (shape==CSCropSelect) + window->set_cursor (*cCropSelection); + else if (shape==CSStraighten) + window->set_cursor (*cCropSelection); +} + + diff --git a/rtgui/cursormanager.h b/rtgui/cursormanager.h new file mode 100755 index 000000000..f214416c0 --- /dev/null +++ b/rtgui/cursormanager.h @@ -0,0 +1,49 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _CURSORMANAGER_ +#define _CURSORMANAGER_ + +#include + +enum CursorShape {CSArrow, CSOpenHand, CSClosedHand, CSMove, CSResizeWidth, CSResizeHeight, CSResizeDiagonal, CSSpotWB, CSCropSelect, CSStraighten}; + +class CursorManager { + + protected: + Gdk::Cursor* cResizeWidth; + Gdk::Cursor* cResizeHeight; + Gdk::Cursor* cResizeDiag; + Gdk::Cursor* cCropMove; + Gdk::Cursor* cCropMoving; + Gdk::Cursor* cNormal; + Gdk::Cursor* cCropSelection; + Gdk::Cursor* cHand; + Gdk::Cursor* cClosedHand; + Gdk::Cursor* cWB; + Glib::RefPtr mainWindow; + + public: + void init (Glib::RefPtr mainWin); + void setCursor (Glib::RefPtr window, CursorShape shape); +}; + +extern CursorManager cursorManager; + +#endif + diff --git a/rtgui/curveeditor.cc b/rtgui/curveeditor.cc new file mode 100755 index 000000000..713321fe6 --- /dev/null +++ b/rtgui/curveeditor.cc @@ -0,0 +1,194 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include + +CurveEditor::CurveEditor () { + + curve = Gtk::manage (new MyCurve ()); + Gtk::AspectFrame* af = Gtk::manage (new Gtk::AspectFrame ("",Gtk::ALIGN_CENTER,Gtk::ALIGN_CENTER,1,false)); + af->add (*curve); + curve->set_size_request (-1, 200); + pack_start (*af, Gtk::PACK_EXPAND_WIDGET); + + Gtk::HBox* bbox = Gtk::manage (new Gtk::HBox ()); + + linear = Gtk::manage (new Gtk::Button (M("CURVEEDITOR_LINEAR"))); + save = Gtk::manage (new Gtk::Button ()); + Gtk::Image* saveImg = Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-save"), Gtk::ICON_SIZE_BUTTON)); + saveImg->show (); + save->add (*saveImg); + load = Gtk::manage (new Gtk::Button ()); + Gtk::Image* loadImg = Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-open"), Gtk::ICON_SIZE_BUTTON)); + loadImg->show (); + load->add (*loadImg); + + bbox->pack_start (*linear); + bbox->pack_end (*save, Gtk::PACK_SHRINK, 4); + bbox->pack_end (*load, Gtk::PACK_SHRINK, 4); + + pack_end (*bbox, Gtk::PACK_SHRINK, 2); + show_all (); + + linear->signal_clicked().connect( sigc::mem_fun(*this, &CurveEditor::linearPressed) ); + save->signal_clicked().connect( sigc::mem_fun(*this, &CurveEditor::savePressed) ); + load->signal_clicked().connect( sigc::mem_fun(*this, &CurveEditor::loadPressed) ); + + linear->set_tooltip_text (M("CURVEEDITOR_TOOLTIPLINEAR")); + save->set_tooltip_text (M("CURVEEDITOR_TOOLTIPSAVE")); + load->set_tooltip_text (M("CURVEEDITOR_TOOLTIPLOAD")); +} + +void CurveEditor::linearPressed () { + + std::vector lcurve (5); + lcurve[0] = 1.0; + lcurve[1] = 0.0; + lcurve[2] = 0.0; + lcurve[3] = 1.0; + lcurve[4] = 1.0; + curve->setPoints (lcurve); + curve->queue_draw (); + curve->notifyListener (); +} + +void CurveEditor::savePressed () { + + Gtk::FileChooserDialog dialog(M("CURVEEDITOR_SAVEDLGLABEL"), Gtk::FILE_CHOOSER_ACTION_SAVE); +// if (options.multiUser) +// dialog.set_current_folder (Options::rtdir + "/" + options.profilePath); +// else +// dialog.set_current_folder (argv0 + "/" + options.profilePath); + + dialog.add_button(Gtk::StockID("gtk-cancel"), Gtk::RESPONSE_CANCEL); + dialog.add_button(Gtk::StockID("gtk-save"), Gtk::RESPONSE_OK); + + Gtk::FileFilter filter_pp; + filter_pp.set_name(M("CURVEEDITOR_FILEDLGFILTERCURVE")); + filter_pp.add_pattern("*.rtc"); + dialog.add_filter(filter_pp); + + Gtk::FileFilter filter_any; + filter_any.set_name(M("CURVEEDITOR_FILEDLGFILTERANY")); + filter_any.add_pattern("*"); + dialog.add_filter(filter_any); + + dialog.set_do_overwrite_confirmation (true); + + int result = dialog.run(); + + if (result==Gtk::RESPONSE_OK) { + + std::string fname = dialog.get_filename(); + + bool hasext = true; + int dotpos = fname.find_last_of ('.'); + if (dotpos==Glib::ustring::npos) + hasext = false; + int dirpos1 = fname.find_last_of ('/'); + if (dirpos1!=Glib::ustring::npos || dirpos1>dotpos) + hasext = false; + int dirpos2 = fname.find_last_of ('\\'); + if (dirpos2!=Glib::ustring::npos || dirpos2>dotpos) + hasext = false; + + if (!hasext) + fname = fname + ".rtc"; + + if (Glib::file_test (fname, Glib::FILE_TEST_EXISTS)) { + Glib::ustring msg_ = Glib::ustring("") + fname + ": " + M("MAIN_MSG_ALREADYEXISTS") + "\n" + M("MAIN_MSG_QOVERWRITE") + ""; + Gtk::MessageDialog msgd (msg_, true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true); + int response = msgd.run (); + if (response==Gtk::RESPONSE_NO) + return; + } + + std::ofstream f (fname.c_str()); + std::vector p = curve->getPoints (); + int ix = 0; + if (p[ix++]<0) + f << "Linear\n"; + else + f << "Spline\n"; + for (int i=0; i p; + std::string s; + f >> s; + if (s=="Linear") + p.push_back (-1); + else if (s=="Spline") + p.push_back (1); + else return; + double x; + while (f) { + f >> x; + if (f) + p.push_back (x); + } + curve->setPoints (p); + curve->queue_draw (); + curve->notifyListener (); + } + } +} + +void CurveEditor::setCurve (const std::vector& c) { + + if (c.size()>4) { + curve->setPoints (c); + curve->queue_draw (); + } + else + linearPressed (); +} + +std::vector CurveEditor::getCurve () { + + return curve->getPoints (); +} + diff --git a/rtgui/curveeditor.h b/rtgui/curveeditor.h new file mode 100755 index 000000000..834fd4950 --- /dev/null +++ b/rtgui/curveeditor.h @@ -0,0 +1,43 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _CURVEEDITOR_ +#define _CURVEEDITOR_ + +#include +#include + +class CurveEditor : public Gtk::VBox { + + MyCurve* curve; + Gtk::Button* linear; + Gtk::Button* save; + Gtk::Button* load; + + public: + CurveEditor (); + void setCurveListener (CurveListener* cl) { curve->setCurveListener (cl); } + void linearPressed (); + void savePressed (); + void loadPressed (); + void setCurve (const std::vector& c); + std::vector getCurve (); +}; + + +#endif diff --git a/rtgui/dirbrowser.cc b/rtgui/dirbrowser.cc new file mode 100755 index 000000000..409e337b9 --- /dev/null +++ b/rtgui/dirbrowser.cc @@ -0,0 +1,384 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#ifdef WIN32 +#define _WIN32_WINNT 0x0600 +#include +#endif +#include + +#define CHECKTIME 5000 +extern Glib::ustring argv0; + +DirBrowser::DirBrowser () { + + dirtree = new Gtk::TreeView(); + scrolledwindow4 = new Gtk::ScrolledWindow(); + +// dirtree->set_flags(Gtk::CAN_FOCUS); + dirtree->set_headers_visible(false); + dirtree->set_rules_hint(false); + dirtree->set_reorderable(false); + dirtree->set_enable_search(false); + scrolledwindow4->set_flags(Gtk::CAN_FOCUS); + scrolledwindow4->set_border_width(2); + scrolledwindow4->set_shadow_type(Gtk::SHADOW_NONE); + scrolledwindow4->set_policy(Gtk::POLICY_ALWAYS, Gtk::POLICY_ALWAYS); + scrolledwindow4->property_window_placement().set_value(Gtk::CORNER_TOP_LEFT); + scrolledwindow4->add(*dirtree); + + pack_start (*scrolledwindow4); + dirtree->show (); + scrolledwindow4->show (); +} + +void DirBrowser::fillDirTree () { + + openfolder = Gdk::Pixbuf::create_from_file (argv0+"/images/folder_open.png"); + closedfolder = Gdk::Pixbuf::create_from_file (argv0+"/images/folder.png"); + icdrom = Gdk::Pixbuf::create_from_file (argv0+"/images/cdrom.png"); + ifloppy = Gdk::Pixbuf::create_from_file (argv0+"/images/floppy.png"); + ihdd = Gdk::Pixbuf::create_from_file (argv0+"/images/hdd.png"); + iremovable = Gdk::Pixbuf::create_from_file (argv0+"/images/usbpendrive.png"); + inetwork = Gdk::Pixbuf::create_from_file (argv0+"/images/network.png"); + + //Create the Tree model: + dirTreeModel = Gtk::TreeStore::create(dtColumns); + dirtree->set_model (dirTreeModel); + + fillRoot (); + + Gtk::CellRendererPixbuf* render_pb = new Gtk::CellRendererPixbuf (); + tvc.pack_start (*render_pb, false); + tvc.add_attribute(*render_pb, "pixbuf-expander-closed", 1); + tvc.add_attribute(*render_pb, "pixbuf", 1); + tvc.add_attribute(*render_pb, "pixbuf-expander-open", 0); + tvc.pack_start (crt); + tvc.add_attribute(crt, "text", 2); + + crt.property_ypad() = 0; + render_pb->property_ypad() = 0; + + dirtree->append_column(tvc); + + dirtree->signal_row_expanded().connect(sigc::mem_fun(*this, &DirBrowser::row_expanded)); + dirtree->signal_row_activated().connect(sigc::mem_fun(*this, &DirBrowser::row_activated)); +} + +#ifdef WIN32 +void DirBrowser::addRoot (char letter) { + + char volume[4]; + volume[0] = letter; + strcpy (volume+1, ":\\"); + + Gtk::TreeModel::iterator root = dirTreeModel->append(); + root->set_value (dtColumns.filename, Glib::ustring(volume)); + root->set_value (dtColumns.dirname, Glib::ustring(volume)); + + int type = GetDriveType (volume); + if (type==DRIVE_CDROM) { + root->set_value (0, icdrom); + root->set_value (1, icdrom); + } + else if (type==DRIVE_REMOVABLE) { + if (letter-'A'<2) { + root->set_value (0, ifloppy); + root->set_value (1, ifloppy); + } + else { + root->set_value (0, iremovable); + root->set_value (1, iremovable); + } + } + else if (type==DRIVE_REMOTE) { + root->set_value (0, inetwork); + root->set_value (1, inetwork); + } + else if (type==DRIVE_FIXED) { + root->set_value (0, ihdd); + root->set_value (1, ihdd); + } + + Gtk::TreeModel::iterator child = dirTreeModel->append (root->children()); + child->set_value (dtColumns.filename, Glib::ustring("foo")); +} + +void DirBrowser::updateDirTreeRoot () { + + for (Gtk::TreeModel::iterator i=dirTreeModel->children().begin(); i!=dirTreeModel->children().end(); i++) + updateDirTree (i); +} + +void DirBrowser::updateDirTree (const Gtk::TreeModel::iterator& iter) { + + if (dirtree->row_expanded (dirTreeModel->get_path (iter))) { + updateDir (iter); + for (Gtk::TreeModel::iterator i=iter->children().begin(); i!=iter->children().end(); i++) + updateDirTree (i); + } +} + +void DirBrowser::updateVolumes () { + + int nvolumes = GetLogicalDrives (); + if (nvolumes!=volumes) { + for (int i=0; i<32; i++) + if (((volumes >> i) & 1) && !((nvolumes >> i) & 1)) { // volume i has been deleted + for (Gtk::TreeModel::iterator iter = dirTreeModel->children().begin(); iter!=dirTreeModel->children().end(); iter++) + if (iter->get_value (dtColumns.filename).c_str()[0]-'A' == i) { + dirTreeModel->erase (iter); + break; + } + } + else if (!((volumes >> i) & 1) && ((nvolumes >> i) & 1)) + addRoot ('A'+i); // volume i has been added + volumes = nvolumes; + } +} + +int _updateVolumes (void* br) { + + gdk_threads_enter (); + ((DirBrowser*)br)->updateVolumes (); + gdk_threads_leave (); + return 1; +} +int _updateDirTree (void* br) { + + gdk_threads_enter (); + ((DirBrowser*)br)->updateDirTreeRoot (); + gdk_threads_leave (); + return 0; +} + +void DirBrowser::winDirChanged () { + + g_idle_add (_updateDirTree, this); +} +#endif + +void DirBrowser::fillRoot () { + +#ifdef WIN32 + volumes = GetLogicalDrives (); + for (int i=0; i<32; i++) + if ((volumes >> i) & 1) + addRoot ('A'+i); + // since sigc++ is not thread safe, we have to use the glib function + g_timeout_add (CHECKTIME, _updateVolumes, this); +#else + Gtk::TreeModel::Row rootRow = *(dirTreeModel->append()); + rootRow[dtColumns.filename] = "/"; + rootRow[dtColumns.dirname] = "/"; + Gtk::TreeModel::Row childRow = *(dirTreeModel->append(rootRow.children())); + childRow[dtColumns.filename] = "foo"; +#endif +} + +void DirBrowser::row_expanded (const Gtk::TreeModel::iterator& iter, const Gtk::TreeModel::Path& path) { + + expandSuccess = false; + + int todel = iter->children().size(); + + try { + std::vector subDirs; + Glib::RefPtr dir = Gio::File::create_for_path (iter->get_value (dtColumns.dirname)); + if (!dir) + return; + Glib::RefPtr dirList = dir->enumerate_children (); + try { + for (Glib::RefPtr info = dirList->next_file(); info; info = dirList->next_file()) + if (info->get_file_type() == Gio::FILE_TYPE_DIRECTORY && (!info->is_hidden() || options.fbShowHidden)) + subDirs.push_back (info->get_name()); + } + catch (...) {} + std::sort (subDirs.begin(), subDirs.end()); + for (int i=0; ierase (iter->children().begin()); + expandSuccess = true; +#ifdef _WIN32 + Glib::RefPtr monitor = Glib::RefPtr(new WinDirMonitor (iter->get_value (dtColumns.dirname), this)); + iter->set_value (dtColumns.monitor, monitor); +#else + Glib::RefPtr monitor = dir->monitor_directory (); + iter->set_value (dtColumns.monitor, monitor); + monitor->signal_changed().connect (sigc::bind(sigc::mem_fun(*this, &DirBrowser::file_changed), iter, dir->get_parse_name())); +#endif + } + catch (Glib::Exception &ex) { +printf ("HEJJ!\n"); + dirtree->collapse_row (path); + } +} + +void DirBrowser::updateDir (const Gtk::TreeModel::iterator& iter) { + + // first test if some files are deleted + bool change = true; + while (change) { + change = false; + for (Gtk::TreeModel::iterator it=iter->children().begin(); it!=iter->children().end(); it++) + if (!Glib::file_test (it->get_value (dtColumns.dirname), Glib::FILE_TEST_EXISTS) + || !Glib::file_test (it->get_value (dtColumns.dirname), Glib::FILE_TEST_IS_DIR)) { + dirTreeModel->erase (it); + change = true; + break; + } + } + // test if new files are created + try { + std::vector subDirs; + Glib::RefPtr dir = Gio::File::create_for_path (iter->get_value (dtColumns.dirname)); + if (!dir) + return; + Glib::RefPtr dirList = dir->enumerate_children (); + for (Glib::RefPtr info = dirList->next_file(); info; info = dirList->next_file()) + if (info->get_file_type() == Gio::FILE_TYPE_DIRECTORY && (!info->is_hidden() || options.fbShowHidden)) + subDirs.push_back (info->get_name()); + + for (int i=0; ichildren().begin(); it!=iter->children().end(); it++) + if (it->get_value (dtColumns.filename)==subDirs[i]) { + found = true; + break; + } + if (!found) + addDir (iter, subDirs[i]); + } + } + catch (Glib::Exception &ex) { + printf ("HEJJ!\n"); + } +} + +void DirBrowser::addDir (const Gtk::TreeModel::iterator& iter, const Glib::ustring& dirname) { + + Gtk::TreeModel::iterator child = dirTreeModel->append(iter->children()); + child->set_value (dtColumns.filename, dirname); + child->set_value (0, openfolder); + child->set_value (1, closedfolder); + Glib::ustring fullname = Glib::build_filename (iter->get_value (dtColumns.dirname), dirname); + child->set_value (dtColumns.dirname, fullname); + Glib::RefPtr f = Gio::File::create_for_path (fullname); + Gtk::TreeModel::iterator fooRow = dirTreeModel->append(child->children()); + fooRow->set_value (dtColumns.filename, Glib::ustring("foo")); +} + +void DirBrowser::row_activated (const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column) { + + Glib::ustring dname = dirTreeModel->get_iter (path)->get_value (dtColumns.dirname); + if (Glib::file_test (dname, Glib::FILE_TEST_IS_DIR)) + for (int i=0; idirSelected (dname); +} + +Gtk::TreePath DirBrowser::expandToDir (const Glib::ustring& absDirPath) { + + Gtk::TreeModel::Path path; + path.append_index(0); + + int end = 0; + int beg = 0; + char* dir = new char [1024]; + char* dcpy = strdup (absDirPath.c_str()); + dir = strtok (dcpy, "/\\"); + int count = 0; + expandSuccess = true; + +#ifndef _WIN32 + Gtk::TreeModel::iterator j = dirTreeModel->get_iter (path); + path.up (); + path.append_index (0); + row_expanded(j, path); + path.append_index (0); +#endif + + while (dir) { + Glib::ustring dirstr = dir; +#ifdef _WIN32 + if (count==0) + dirstr = dirstr + "\\"; +#endif + Gtk::TreeModel::iterator i = dirTreeModel->get_iter (path); + int ix = 0; + while (i && expandSuccess) { + Gtk::TreeModel::Row crow = *i; + Glib::ustring str =crow[dtColumns.filename]; +#ifdef _WIN32 + if (str.casefold()==dirstr.casefold()) { +#else + if (str==dirstr) { +#endif + path.up (); + path.append_index (ix); + row_expanded(i, path); + path.append_index (0); + break; + } + ix++; + i++; + } + count++; + dir = strtok(NULL, "/\\"); + } + + delete dir; + delete dcpy; + + path.up (); + dirtree->expand_to_path (path); + + return path; +} + +void DirBrowser::open (const Glib::ustring& dirname, const Glib::ustring& fileName) { + + dirtree->collapse_all (); + + Glib::ustring absDirPath = Gio::File::create_for_path(dirname)->get_parse_name (); + Gtk::TreePath path = expandToDir (absDirPath); + + if (expandSuccess) { + dirtree->scroll_to_row (path); + dirtree->get_selection()->select (path); + for (int i=0; idirSelected (absDirPath, Glib::build_filename (absDirPath, fileName)); + } +} + +void DirBrowser::file_changed (const Glib::RefPtr& file, const Glib::RefPtr& other_file, Gio::FileMonitorEvent event_type, const Gtk::TreeModel::iterator& iter, const Glib::ustring& dirName) { + + if (!file || !Glib::file_test (dirName, Glib::FILE_TEST_IS_DIR) || event_type==Gio::FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED) + return; + + gdk_threads_enter(); + updateDir (iter); + gdk_threads_leave(); +} + void DirBrowser::selectDir (Glib::ustring dir) { + + open (dir, ""); +} + diff --git a/rtgui/dirbrowser.h b/rtgui/dirbrowser.h new file mode 100755 index 000000000..3c9ba970b --- /dev/null +++ b/rtgui/dirbrowser.h @@ -0,0 +1,103 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _DIRBROWSER_ +#define _DIRBROWSER_ + +#include +#include +#ifdef _WIN32 +#include +#endif +#include +#include + +class DirBrowser : public Gtk::VBox, public DirBrowserRemoteInterface +#ifdef _WIN32 + , public WinDirChangeListener +#endif + { + + private: + + Glib::RefPtr dirTreeModel; + + struct DirTreeColumns : public Gtk::TreeModelColumnRecord { + public: + Gtk::TreeModelColumn filename; + Gtk::TreeModelColumn > icon1; + Gtk::TreeModelColumn > icon2; + Gtk::TreeModelColumn dirname; + #ifdef _WIN32 + Gtk::TreeModelColumn > monitor; + #else + Gtk::TreeModelColumn > monitor; + #endif + + DirTreeColumns() { add(icon1); add(icon2); add(filename); add(dirname); add(monitor); } + }; + + Gtk::TreeViewColumn tvc; + Gtk::CellRendererText crt; + Gtk::CellRendererPixbuf crb; + DirTreeColumns dtColumns; + + Gtk::TreeView *dirtree; + Gtk::ScrolledWindow *scrolledwindow4; + std::vector dllisteners; + + void fillRoot (); + + Glib::RefPtr openfolder; + Glib::RefPtr closedfolder; + Glib::RefPtr icdrom; + Glib::RefPtr ifloppy; + Glib::RefPtr ihdd; + Glib::RefPtr inetwork; + Glib::RefPtr iremovable; + + bool expandSuccess; + + #ifdef WIN32 + int volumes; + public: + void updateVolumes (); + void updateDirTree (const Gtk::TreeModel::iterator& iter); + void updateDirTreeRoot (); + void winDirChanged (); + private: + void addRoot (char letter); + #endif + void addDir (const Gtk::TreeModel::iterator& iter, const Glib::ustring& dirname); + Gtk::TreePath expandToDir (const Glib::ustring& dirName); + void updateDir (const Gtk::TreeModel::iterator& iter); + void notifyListeners (); + + public: + DirBrowser (); + + void fillDirTree (); + void row_expanded (const Gtk::TreeModel::iterator& iter, const Gtk::TreeModel::Path& path); + void row_activated (const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column); + void file_changed (const Glib::RefPtr& file, const Glib::RefPtr& other_file, Gio::FileMonitorEvent event_type, const Gtk::TreeModel::iterator& iter, const Glib::ustring& dirName); + void open (const Glib::ustring& dirName, const Glib::ustring& fileName=""); // goes to dir "dirName" and selects file "fileName" + void addDirSelectionListener (DirSelectionListener* l) { dllisteners.push_back (l); } + void selectDir (Glib::ustring dir); +}; + +#endif diff --git a/rtgui/dirbrowserremoteinterface.h b/rtgui/dirbrowserremoteinterface.h new file mode 100755 index 000000000..7e435a93f --- /dev/null +++ b/rtgui/dirbrowserremoteinterface.h @@ -0,0 +1,31 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _DIRBROWSERREMOTEINTERFACE_ +#define _DIRBROWSERREMOTEINTERFACE_ + +#include + +class DirBrowserRemoteInterface { + + public: + virtual void selectDir (Glib::ustring dir) {} +}; + +#endif + diff --git a/rtgui/dirselectionlistener.h b/rtgui/dirselectionlistener.h new file mode 100755 index 000000000..b68238727 --- /dev/null +++ b/rtgui/dirselectionlistener.h @@ -0,0 +1,30 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _DIRSELECTIONLISTENER_ +#define _DIRSELECTIONLISTENER_ + +#include + +class DirSelectionListener { + + public: + virtual void dirSelected (const Glib::ustring& dirname, const Glib::ustring& openfile="") {} +}; + +#endif diff --git a/rtgui/distortion.cc b/rtgui/distortion.cc new file mode 100755 index 000000000..e16711181 --- /dev/null +++ b/rtgui/distortion.cc @@ -0,0 +1,83 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +using namespace rtengine; +using namespace rtengine::procparams; + +Distortion::Distortion () { + + distor = Gtk::manage (new Adjuster (M("TP_DISTORTION_AMOUNT"), -0.5, 0.5, 0.001, 0)); + distor->setAdjusterListener (this); + distor->show(); + pack_start (*distor); + distAdd = false; +} + +void Distortion::read (const ProcParams* pp, const ParamsEdited* pedited) { + + disableListener (); + + if (pedited) + distor->setEditedState (pedited->distortion.amount ? Edited : UnEdited); + + distor->setValue (pp->distortion.amount); + + enableListener (); +} + +void Distortion::write (ProcParams* pp, ParamsEdited* pedited) { + + pp->distortion.amount = distor->getValue (); + + if (pedited) + pedited->distortion.amount = distor->getEditedState (); +} + +void Distortion::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { + + distor->setDefault (defParams->distortion.amount); + + if (pedited) + distor->setDefaultEditedState (pedited->distortion.amount ? Edited : UnEdited); + else + distor->setDefaultEditedState (Irrelevant); +} + +void Distortion::adjusterChanged (Adjuster* a, double newval) { + + if (listener) + listener->panelChanged (EvDISTAmount, Glib::ustring::format (std::setw(4), std::fixed, std::setprecision(3), a->getValue())); +} + +void Distortion::setAdjusterBehavior (bool bvadd) { + + if (!distAdd && bvadd || distAdd && !bvadd) + distor->setLimits (-0.5, 0.5, 0.001, 0); + + distAdd = bvadd; +} + +void Distortion::setBatchMode (bool batchMode) { + + ToolPanel::setBatchMode (batchMode); + distor->showEditedCB (); +} + diff --git a/rtgui/distortion.h b/rtgui/distortion.h new file mode 100755 index 000000000..c4160bf94 --- /dev/null +++ b/rtgui/distortion.h @@ -0,0 +1,45 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _DISTORTION_H_ +#define _DISTORTION_H_ + +#include +#include +#include + +class Distortion : public Gtk::VBox, public AdjusterListener, public ToolPanel { + + protected: + Adjuster* distor; + bool distAdd; + + public: + + Distortion (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + + void adjusterChanged (Adjuster* a, double newval); + void setAdjusterBehavior (bool bvadd); +}; + +#endif diff --git a/rtgui/editedstate.h b/rtgui/editedstate.h new file mode 100755 index 000000000..1409f1237 --- /dev/null +++ b/rtgui/editedstate.h @@ -0,0 +1,25 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _EDITEDSTATE_ +#define _EDITEDSTATE_ + +enum EditedState { UnEdited=0, Edited=1, Irrelevant=2 }; + +#endif + diff --git a/rtgui/editenums.h b/rtgui/editenums.h new file mode 100755 index 000000000..adfc1e2a5 --- /dev/null +++ b/rtgui/editenums.h @@ -0,0 +1,25 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _EDITENUMS_ +#define _EDITENUMS_ + +enum ImgEditState {SNormal, SCropMove, SHandMove, SResizeW1, SResizeW2, SResizeH1, SResizeH2, SCropSelecting, SRotateSelecting, SCropWinMove, SCropFrameMove, SCropImgMove, SCropWinResize, SObservedMove}; +enum CursorArea {CropWinButtons, CropToolBar, CropImage, CropBorder, CropTop, CropBottom, CropLeft, CropRight, CropInside, CropResize, CropObserved}; + +#endif diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc new file mode 100755 index 000000000..44816e4c1 --- /dev/null +++ b/rtgui/editorpanel.cc @@ -0,0 +1,801 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include +#include +#include + +using namespace rtengine::procparams; + +EditorPanel::EditorPanel (Thumbnail* tmb, rtengine::InitialImage* isrc) : parent(NULL), beforeIarea(NULL), beforePreviewHandler(NULL), beforeIpc(NULL) { + + epih = new EditorPanelIdleHelper; + epih->epanel = this; + epih->destroyed = false; + epih->pending = 0; + +// construct toolpanelcoordinator + tpc = new ToolPanelCoordinator (); + +// build GUI + // build left side panel + leftbox = Gtk::manage (new Gtk::VBox ()); + leftbox->set_border_width (4); + + histogramPanel = Gtk::manage (new HistogramPanel ()); + histogramPanel->set_size_request (-1, 150); +// leftbox->pack_start (*histogramPanel, Gtk::PACK_SHRINK, 4); + + profilep = Gtk::manage (new ProfilePanel ()); + Gtk::Frame* ppframe = Gtk::manage (new Gtk::Frame ()); + ppframe->add (*profilep); + ppframe->set_label (M("PROFILEPANEL_LABEL")); +// leftbox->pack_start (*ppframe, Gtk::PACK_SHRINK, 4); + + navigator = Gtk::manage (new Navigator ()); + navigator->previewWindow->set_size_request (-1, 150); + leftbox->pack_start (*navigator, Gtk::PACK_SHRINK, 4); + + history = Gtk::manage (new History ()); + leftbox->pack_start (*history); + + leftbox->show_all (); + + // build the middle of the screen + Gtk::VBox* editbox = Gtk::manage (new Gtk::VBox ()); + + info = Gtk::manage (new Gtk::ToggleButton ()); + Gtk::Image* infoimg = Gtk::manage (new Gtk::Image (argv0+"/images/info.png")); + info->add (*infoimg); + info->set_relief(Gtk::RELIEF_NONE); + info->set_tooltip_text (M("MAIN_TOOLTIP_QINFO")); + + beforeAfter = Gtk::manage (new Gtk::ToggleButton ("B|A")); + beforeAfter->set_tooltip_text ("Toggle before/after view"); + + + Gtk::VSeparator* vsept = Gtk::manage (new Gtk::VSeparator ()); + Gtk::VSeparator* vsepz = Gtk::manage (new Gtk::VSeparator ()); + Gtk::VSeparator* vsepi = Gtk::manage (new Gtk::VSeparator ()); + Gtk::VSeparator* vseph = Gtk::manage (new Gtk::VSeparator ()); + + hidehp = Gtk::manage (new Gtk::ToggleButton ()); + Gtk::Label* hidehpLabel = Gtk::manage (new Gtk::Label ()); + hidehpLabel->set_markup ("H"); + Gtk::Image* hpimg = Gtk::manage (new Gtk::Image (argv0+"/images/left.png")); + Gtk::HBox* hidehpBox = Gtk::manage (new Gtk::HBox ()); + hidehpBox->pack_start (*hpimg, Gtk::PACK_SHRINK, 2); + hidehpBox->pack_start (*hidehpLabel, Gtk::PACK_SHRINK, 2); + hidehp->add (*hidehpBox); + hidehp->set_relief(Gtk::RELIEF_NONE); + hidehp->set_active (options.showHistory); + hidehp->set_tooltip_text (M("MAIN_TOOLTIP_HIDEHP")); + + Gtk::VSeparator* vsepcl = Gtk::manage (new Gtk::VSeparator ()); + Gtk::VSeparator* vsepz2 = Gtk::manage (new Gtk::VSeparator ()); + + iarea = new ImageAreaPanel (); + + Gtk::HBox* toolBarPanel = Gtk::manage (new Gtk::HBox ()); + toolBarPanel->pack_start (*hidehp, Gtk::PACK_SHRINK, 1); + toolBarPanel->pack_start (*vseph, Gtk::PACK_SHRINK, 2); + toolBarPanel->pack_start (*info, Gtk::PACK_SHRINK, 1); + toolBarPanel->pack_start (*beforeAfter, Gtk::PACK_SHRINK, 1); + toolBarPanel->pack_start (*vsepi, Gtk::PACK_SHRINK, 2); + toolBarPanel->pack_start (*tpc->getToolBar(), Gtk::PACK_SHRINK, 1); + toolBarPanel->pack_start (*vsept, Gtk::PACK_SHRINK, 2); + toolBarPanel->pack_end (*tpc->coarse, Gtk::PACK_SHRINK, 4); + toolBarPanel->pack_end (*vsepcl, Gtk::PACK_SHRINK, 4); + toolBarPanel->pack_end (*iarea->imageArea->indClippedPanel, Gtk::PACK_SHRINK, 0); + toolBarPanel->pack_end (*vsepz, Gtk::PACK_SHRINK, 2); + + afterBox = Gtk::manage (new Gtk::VBox ()); + afterBox->pack_start (*iarea); + + beforeAfterBox = Gtk::manage (new Gtk::HBox()); + beforeAfterBox->pack_start (*afterBox); + + editbox->pack_start (*toolBarPanel, Gtk::PACK_SHRINK); + editbox->pack_start (*beforeAfterBox); + + // build right side panel + vboxright = Gtk::manage (new Gtk::VBox (false, 0)); + vboxright->set_border_width (4); + vboxright->pack_start (*histogramPanel, Gtk::PACK_SHRINK, 4); + vboxright->pack_start (*ppframe, Gtk::PACK_SHRINK, 4); + // main notebook + vboxright->pack_start (*tpc->toolPanelNotebook); + + // buttons & status + Gtk::HBox* iops = Gtk::manage (new Gtk::HBox ()); + saveimgas = Gtk::manage (new Gtk::Button (M("MAIN_BUTTON_SAVE"))); + saveimgas->set_image (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-save"), Gtk::ICON_SIZE_BUTTON))); + queueimg = Gtk::manage (new Gtk::Button ("Put to queue")); + queueimg->set_image (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-execute"), Gtk::ICON_SIZE_BUTTON))); + sendtogimp = Gtk::manage (new Gtk::Button (M("MAIN_BUTTON_SENDTOEDITOR"))); + sendtogimp->set_image (*Gtk::manage(new Gtk::Image (argv0+"/images/gimp.png"))); + iops->pack_start (*saveimgas, Gtk::PACK_SHRINK); + iops->pack_start (*queueimg, Gtk::PACK_SHRINK); + iops->pack_start (*sendtogimp, Gtk::PACK_SHRINK); + + statusBox = Gtk::manage (new Gtk::HBox ()); + progressLabel = Gtk::manage (new Gtk::Label("")); + statusBox->pack_start (*progressLabel); + red = new Gtk::Image (argv0+"/images/red.png"); + green = new Gtk::Image (argv0+"/images/green.png"); + red->show (); + green->show (); + statusBox->pack_end (*green, Gtk::PACK_SHRINK, 4); + iops->pack_start(*statusBox, Gtk::PACK_SHRINK, 4); + + iops->pack_end (*iarea->imageArea->zoomPanel, Gtk::PACK_SHRINK, 1); + iops->pack_end (*vsepz2, Gtk::PACK_SHRINK, 2); + + + editbox->pack_start (*Gtk::manage(new Gtk::HSeparator()), Gtk::PACK_SHRINK, 4); + editbox->pack_start (*iops, Gtk::PACK_SHRINK, 4); + editbox->show_all (); + + // build screen + hpanedl = Gtk::manage (new Gtk::HPaned()); + hpanedr = Gtk::manage (new Gtk::HPaned()); + leftbox->reference (); + vboxright->reference (); + if (options.showHistory) { + hpanedl->pack1(*leftbox, false, true); + hpanedl->set_position (options.historyPanelWidth); + } + + Gtk::Frame* vbfr = Gtk::manage (new Gtk::Frame ()); + vbfr->add (*editbox); + hpanedl->pack2(*vbfr, true, true); + + hpanedr->pack1(*hpanedl, true, true); + hpanedr->pack2(*vboxright, false, true); + + pack_start (*hpanedr); + show_all (); + + // save as dialog + if (Glib::file_test (options.lastSaveAsPath, Glib::FILE_TEST_IS_DIR)) + saveAsDialog = new SaveAsDialog (options.lastSaveAsPath); + else + saveAsDialog = new SaveAsDialog (Glib::get_user_special_dir (G_USER_DIRECTORY_PICTURES)); + + +// connect listeners + profilep->setProfileChangeListener (tpc); + history->setProfileChangeListener (tpc); + history->setHistoryBeforeLineListener (this); + tpc->addPParamsChangeListener (profilep); + tpc->addPParamsChangeListener (history); + tpc->addPParamsChangeListener (this); + iarea->imageArea->setCropGUIListener (tpc->getCropGUIListener()); + iarea->imageArea->setPointerMotionListener (navigator); + iarea->imageArea->setImageAreaToolListener (tpc); + +// initialize components + info->set_active (options.showInfo); + tpc->readOptions (); + +// connect event handlers + info->signal_toggled().connect( sigc::mem_fun(*this, &EditorPanel::info_toggled) ); + beforeAfter->signal_toggled().connect( sigc::mem_fun(*this, &EditorPanel::beforeAfterToggled) ); + hidehp->signal_toggled().connect( sigc::mem_fun(*this, &EditorPanel::hideHistoryActivated) ); + saveimgas->signal_pressed().connect( sigc::mem_fun(*this, &EditorPanel::saveAsPressed) ); + queueimg->signal_pressed().connect( sigc::mem_fun(*this, &EditorPanel::queueImgPressed) ); + sendtogimp->signal_pressed().connect( sigc::mem_fun(*this, &EditorPanel::sendToGimpPressed) ); + +// open image + open (tmb, isrc); +} + +bool EditorPanel::beforeClosing () { + + options.toolPanelWidth = vboxright->get_width (); + return true; +} + +EditorPanel::~EditorPanel () { + + history->setHistoryBeforeLineListener (NULL); + // the order is important! + delete iarea; + delete beforeIarea; + + if (ipc) + ipc->setPreviewImageListener (NULL); + if (beforeIpc) + beforeIpc->setPreviewImageListener (NULL); + + delete previewHandler; + delete beforePreviewHandler; + + if (ipc) + close (); + + if (epih->pending) + epih->destroyed = true; + else + delete epih; + + delete tpc; + + delete red; + delete green; + delete leftbox; + delete vboxright; + + delete saveAsDialog; +} + +void EditorPanel::on_realize () { + + Gtk::VBox::on_realize (); + vboxright->set_size_request (options.toolPanelWidth, -1); +} + +rtengine::InitialImage* EditorPanel::loadImage (Thumbnail* tmb) { + + // try to load the image + Glib::ustring filename = tmb->getFileName (); + int error; +// InitialImage* isrc = InitialImage::load (filename, tmb->getType()==FT_Raw, error, this); + ProgressDialog* pdload = new ProgressDialog (M("PROGRESSDLG_LOADING")); + rtengine::InitialImage* isrc; + pdload->setFunc (sigc::bind(sigc::ptr_fun(&rtengine::InitialImage::load), filename, tmb->getType()==FT_Raw, &error, pdload->getProgressListener()), &isrc); + pdload->start (); + delete pdload; + + if (error) + return NULL; + else + return isrc; +} + +void EditorPanel::open (Thumbnail* tmb, rtengine::InitialImage* isrc) { + + // initialize everything + openThm = tmb; + openThm->increaseRef (); + + previewHandler = new PreviewHandler (); + + this->isrc = isrc; + ipc = rtengine::StagedImageProcessor::create (isrc); + ipc->setProgressListener (this); + ipc->setPreviewImageListener (previewHandler); + ipc->setPreviewScale (10); + tpc->initImage (ipc, tmb->getType()==FT_Raw); + ipc->setHistogramListener (histogramPanel); + +// iarea->fitZoom (); // tell to the editorPanel that the next image has to be fitted to the screen + iarea->imageArea->setPreviewHandler (previewHandler); + iarea->imageArea->setImProcCoordinator (ipc); + navigator->previewWindow->setPreviewHandler (previewHandler); + navigator->previewWindow->setImageArea (iarea->imageArea); + + // try to load the last saved parameters from the cache or from the pp2 file + ProcParams* ldprof = NULL; + if (openThm->hasProcParams()) { + ldprof = new ProcParams (); + *ldprof = openThm->getProcParams (); + } + + // initialize profile + if (openThm->getType()!=FT_Raw) + profilep->initProfile (options.defProfImg, ldprof, NULL); + else + profilep->initProfile (options.defProfRaw, ldprof, NULL); + + openThm->addThumbnailListener (this); + info_toggled (); +} + +void EditorPanel::close () { + + saveProfile (); + + // close image processor and the current thumbnail + tpc->closeImage (); // this call stops image processing + tpc->writeOptions (); + + if (ipc) + rtengine::StagedImageProcessor::destroy (ipc); + if (beforeIpc) + rtengine::StagedImageProcessor::destroy (beforeIpc); + + openThm->removeThumbnailListener (this); + openThm->decreaseRef (); +} + +void EditorPanel::saveProfile () { + + ProcParams params; + ipc->getParams (¶ms); + + if (options.saveParamsFile) + params.save (openThm->getFileName() + ".pp2"); + if (openThm && options.saveParamsCache) + openThm->setProcParams (params, EDITOR); +} + +Glib::ustring EditorPanel::getShortName () { + + return Glib::path_get_basename (openThm->getFileName ()); +} + +Glib::ustring EditorPanel::getFileName () { + + return openThm->getFileName (); +} + +// TODO!!! +void EditorPanel::procParamsChanged (rtengine::procparams::ProcParams* params, rtengine::ProcEvent ev, Glib::ustring descr, ParamsEdited* paramsEdited) { + +// if (ev!=EvPhotoLoaded) +// saveLabel->set_markup (Glib::ustring("") + M("MAIN_BUTTON_SAVE") + ""); +} + +struct spsparams { + bool state; + EditorPanelIdleHelper* epih; +}; + +int setprocstate (void* data) { + + gdk_threads_enter (); + spsparams* p = (spsparams*)data; + + if (p->epih->destroyed) { + if (p->epih->pending == 1) + delete p->epih; + else + p->epih->pending--; + delete p; + gdk_threads_leave (); + return 0; + } + + p->epih->epanel->refreshProcessingState (p->state); + p->epih->pending--; + delete p; + gdk_threads_leave (); + return 0; +} + +void EditorPanel::setProgressState (int state) { + + epih->pending++; + + spsparams* p = new spsparams; + p->state = state; + p->epih = epih; + g_idle_add (setprocstate, p); +} + +void EditorPanel::refreshProcessingState (bool state) { + + // Set proc params of thumbnail. It saves it into the cache and updates the file browser. + if (ipc && openThm && !state && tpc->getChangedState()) { + rtengine::procparams::ProcParams pparams; + ipc->getParams (&pparams); + openThm->setProcParams (pparams, EDITOR, false); + } + + // change state of the led + std::vector children = (std::vector) statusBox->get_children(); + if (children.size()>=1) { + Gtk::Widget* wlast = children[children.size()-1]; + if (wlast) + statusBox->remove (*wlast); + } + if (state) + statusBox->pack_end (*red, Gtk::PACK_SHRINK, 4); + else + statusBox->pack_end (*green, Gtk::PACK_SHRINK, 4); +} + +struct errparams { + Glib::ustring descr; + EditorPanelIdleHelper* epih; +}; + +void EditorPanel::displayError (Glib::ustring descr) { + + if (parent) { + Gtk::MessageDialog* msgd = new Gtk::MessageDialog (*parent, descr, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + msgd->set_title (M("MAIN_MSG_CANNOTSAVE")); + msgd->run (); + delete msgd; + } +} + +int disperror (void* data) { + + gdk_threads_enter (); + errparams* p = (errparams*)data; + + if (p->epih->destroyed) { + if (p->epih->pending == 1) + delete p->epih; + else + p->epih->pending--; + delete p; + gdk_threads_leave (); + return 0; + } + + p->epih->epanel->displayError (p->descr); + p->epih->pending--; + delete p; + gdk_threads_leave (); + return 0; +} + +void EditorPanel::error (Glib::ustring descr) { + + epih->pending++; + errparams* p = new errparams; + p->descr = descr; + p->epih = epih; + g_idle_add (disperror, p); +} + +void EditorPanel::info_toggled () { + + Glib::ustring infoString; + + const rtengine::ImageMetaData* idata = ipc->getInitialImage()->getMetaData(); + if (idata && idata->hasExif()) + infoString = Glib::ustring::compose ("%1 %2\nF/%3 %4 sec\n%5: %6\n%7: %8 mm\n", + Glib::ustring(idata->getMake()), Glib::ustring(idata->getModel()), + Glib::ustring(idata->apertureToString(idata->getFNumber())), Glib::ustring(idata->shutterToString(idata->getShutterSpeed())), + M("QINFO_ISO"), idata->getISOSpeed(), + M("QINFO_FOCALLENGTH"), idata->getFocalLen()) + + Glib::ustring::compose ("%1: %2", M("QINFO_LENS"), Glib::ustring(idata->getLens())); + else + infoString = M("QINFO_NOEXIF"); + + iarea->imageArea->setInfoText (infoString); + iarea->imageArea->infoEnabled (info->get_active ()); +} + +void EditorPanel::hideHistoryActivated () { + + removeIfThere (hpanedl, leftbox, false); + if (hidehp->get_active()) + hpanedl->pack1 (*leftbox, false, true); +} + +bool EditorPanel::handleShortcutKey (GdkEventKey* event) { + + if (event->keyval==GDK_H || event->keyval==GDK_h) { + hidehp->set_active (!hidehp->get_active()); + return true; + } + else if ((event->keyval==GDK_Z || event->keyval==GDK_z) && event->state & GDK_CONTROL_MASK && !(event->state & GDK_SHIFT_MASK)) { + history->undo (); + return true; + } + else if ((event->keyval==GDK_Z || event->keyval==GDK_z) && event->state & GDK_CONTROL_MASK && event->state & GDK_SHIFT_MASK) { + history->redo (); + return true; + } + else if (event->keyval==GDK_w || event->keyval==GDK_W) { + tpc->getToolBar()->wb_pressed (); + return true; + } + else if (event->keyval==GDK_c || event->keyval==GDK_C) { + tpc->getToolBar()->crop_pressed (); + return true; + } + else if (event->keyval==GDK_s || event->keyval==GDK_S) { + tpc->getToolBar()->stra_pressed (); + return true; + } + else if (event->keyval==GDK_n || event->keyval==GDK_N) { + tpc->getToolBar()->hand_pressed (); + return true; + } + else + return false; +} + +void EditorPanel::procParamsChanged (Thumbnail* thm, int whoChangedIt) { + + if (whoChangedIt!=EDITOR) + tpc->profileChange (&openThm->getProcParams(), rtengine::EvProfileChangeNotification, "Profile Changed in Browser"); +} + +rtengine::IImage16* EditorPanel::processImage () { + + rtengine::procparams::ProcParams pparams; + ipc->getParams (&pparams); + rtengine::ProcessingJob* job = rtengine::ProcessingJob::create (ipc->getInitialImage(), pparams); + int err = 0; + ProgressDialog* pdproc = new ProgressDialog (M("PROGRESSDLG_PROCESSING")); + rtengine::IImage16* img; + pdproc->setFunc (sigc::bind(sigc::ptr_fun(&rtengine::processImage), job, err, pdproc->getProgressListener()), &img); + pdproc->start (); + delete pdproc; + return img; +} + +BatchQueueEntry* EditorPanel::createBatchQueueEntry () { + + rtengine::procparams::ProcParams pparams; + ipc->getParams (&pparams); + rtengine::ProcessingJob* job = rtengine::ProcessingJob::create (ipc->getInitialImage(), pparams); + int prevh = options.maxThumbnailHeight; + int prevw = prevh; + guint8* prev = NULL;//(guint8*) previewHandler->getImagePreview (prevw, prevh); + return new BatchQueueEntry (job, pparams, openThm->getFileName(), prev, prevw, prevh, openThm); +} + +int EditorPanel::saveImage (rtengine::IImage16* img, Glib::ustring& fname, SaveFormat sf, bool findNewNameIfNeeded) { + + Glib::ustring fileName = Glib::ustring::compose ("%1.%2", fname, sf.format); + if (findNewNameIfNeeded) { + int tries = 1; + while (Glib::file_test (fileName, Glib::FILE_TEST_EXISTS) && tries<1000) { + fileName = Glib::ustring::compose("%1-%2.%3", fname, tries, sf.format); + tries++; + } + if (tries==1000) + return -1000; + } + + ProgressDialog* pdsave = new ProgressDialog (M("PROGRESSDLG_SAVING")); + img->setSaveProgressListener (pdsave->getProgressListener()); + + int err; + if (sf.format=="tif") + pdsave->setFunc (sigc::bind(sigc::mem_fun(img, &rtengine::IImage16::saveAsTIFF), fileName, sf.tiffBits), &err); + else if (sf.format=="png") + pdsave->setFunc (sigc::bind(sigc::mem_fun(img, &rtengine::IImage16::saveAsPNG), fileName, sf.pngCompression, sf.pngBits), &err); + else if (sf.format=="jpg") + pdsave->setFunc (sigc::bind(sigc::mem_fun(img, &rtengine::IImage16::saveAsJPEG), fileName, sf.jpegQuality), &err); + pdsave->start (); + delete pdsave; + + fname = fileName; + return err; +} + +void EditorPanel::saveAsPressed () { + + // obtaining short name without extension + saveAsDialog->setInitialFileName (removeExtension (Glib::path_get_basename (openThm->getFileName()))); + saveAsDialog->run (); + Glib::ustring fname = saveAsDialog->getFileName (); + if (fname=="") + return; + + SaveFormat sf = saveAsDialog->getFormat (); + if (getExtension (fname)!=sf.format) + fname = fname + "." + sf.format; + + if (saveAsDialog->getImmediately ()) { + // check if it exists + if (Glib::file_test (fname, Glib::FILE_TEST_EXISTS)) { + Glib::ustring msg_ = Glib::ustring("") + fname + ": " + M("MAIN_MSG_ALREADYEXISTS") + "\n" + M("MAIN_MSG_QOVERWRITE") + ""; + Gtk::MessageDialog msgd (*parent, msg_, true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true); + int response = msgd.run (); + if (response==Gtk::RESPONSE_NO) + return; + } + // save image + rtengine::IImage16* img = processImage (); + int err = 0; + if (img) { + fname = removeExtension (fname); + err = saveImage (img, fname, sf, false); + img->free (); + if (!err) { + openThm->imageDeveloped (); + // save processing parameters, if needed + if (sf.saveParams) { + rtengine::procparams::ProcParams pparams; + ipc->getParams (&pparams); + pparams.save (removeExtension (fname) + ".out.pp2"); + } + } + } + if (!img || err) { + Glib::ustring msg_ = Glib::ustring("") + fname + ": Error during image saving\n"; + Gtk::MessageDialog msgd (*parent, msg_, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + msgd.run (); + } + } + else { + BatchQueueEntry* bqe = createBatchQueueEntry (); + bqe->outFileName = fname; + bqe->saveFormat = saveAsDialog->getFormat (); + parent->addBatchQueueJob (bqe, saveAsDialog->getToHeadOfQueue ()); + } + // ask parent to redraw file browser + // ... or does it automatically when the tab is switched to it +} + +void EditorPanel::queueImgPressed () { + + saveProfile (); + parent->addBatchQueueJob (createBatchQueueEntry ()); +} + +void EditorPanel::sendToGimpPressed () { + + // develop image + rtengine::IImage16* img = processImage (); + if (img) { + // get file name base + Glib::ustring shortname = removeExtension (Glib::path_get_basename (openThm->getFileName())); + Glib::ustring dirname = Glib::get_tmp_dir (); + Glib::ustring filename = Glib::build_filename (dirname, shortname); + + SaveFormat sf; + sf.format = "tif"; + sf.tiffBits = 16; + int err = saveImage (img, filename, sf, true); + img->free (); + if (!err) { + bool success=false; + Glib::ustring cmdLine; + try { + // start gimp + if (options.editorToSendTo==1) { + #ifdef _WIN32 + cmdLine = Glib::ustring("\"") + Glib::build_filename (Glib::build_filename(options.gimpDir,"bin"), "gimp-win-remote") + "\" gimp-2.4.exe" + " \"" + filename + "\""; + #else + cmdLine = Glib::ustring("gimp-remote ") + " \"" + filename + "\""; + #endif + try { + printf ("command line: |%s|\n", Glib::filename_from_utf8(cmdLine).c_str()); + Glib::spawn_command_line_async (Glib::filename_from_utf8(cmdLine)); + success = true; + } + catch (const Glib::SpawnError&) { + #ifdef _WIN32 + int ver = 12; + while (!success && ver) { + cmdLine = Glib::ustring("\"") + Glib::build_filename (Glib::build_filename(options.gimpDir,"bin"), Glib::ustring::compose("gimp-2.%1.exe",ver)) + "\" \"" + filename + "\""; + ver--; + printf ("command line: |%s|\n", Glib::filename_from_utf8(cmdLine).c_str()); + try { + Glib::spawn_command_line_async (Glib::filename_from_utf8(cmdLine)); + success = true; + } + catch (const Glib::SpawnError&) { + success = false; + } + } + #else + cmdLine = Glib::ustring("gimp ") + " \"" + filename + "\""; + printf ("command line: |%s|\n", Glib::filename_from_utf8(cmdLine).c_str()); + try { + Glib::spawn_command_line_async (Glib::filename_from_utf8(cmdLine)); + success = true; + } + catch (const Glib::SpawnError&) { + success = false; + } + #endif + } + } + else if (options.editorToSendTo==2) { + cmdLine = Glib::ustring("\"") + Glib::build_filename(options.psDir,"Photoshop.exe") + "\" \"" + filename + "\""; + printf ("command line: |%s|\n", Glib::filename_from_utf8(cmdLine).c_str()); + Glib::spawn_command_line_async (Glib::filename_from_utf8(cmdLine)); + success = true; + } + else if (options.editorToSendTo==3) { + cmdLine = Glib::ustring("\"") + options.customEditorProg + "\" \"" + filename + "\""; + printf ("command line: |%s|\n", Glib::filename_from_utf8(cmdLine).c_str()); + Glib::spawn_command_line_async (Glib::filename_from_utf8(cmdLine)); + success = true; + } + } + catch (const Glib::SpawnError&) { + success = false; + } + if (!success) { + Gtk::MessageDialog* msgd = new Gtk::MessageDialog (*parent, M("MAIN_MSG_CANNOTSTARTEDITOR"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + msgd->set_secondary_text (M("MAIN_MSG_CANNOTSTARTEDITOR_SECONDARY")); + msgd->set_title (M("MAIN_BUTTON_SENDTOEDITOR")); + msgd->run (); + delete msgd; + } + } + } +} + +void EditorPanel::saveOptions () { + + options.historyPanelWidth = hpanedl->get_position (); + options.toolPanelWidth = vboxright->get_width (); +} + +void EditorPanel::historyBeforeLineChanged (const rtengine::procparams::ProcParams& params) { + + if (beforeIpc) { + ProcParams* pparams = beforeIpc->getParamsForUpdate (rtengine::EvProfileChanged); + *pparams = params; + beforeIpc->paramsUpdateReady (); + } +} + +void EditorPanel::beforeAfterToggled () { + + removeIfThere (beforeAfterBox, beforeBox, false); + removeIfThere (afterBox, afterLabel, false); + + if (beforeIarea) { + if (beforeIpc) + beforeIpc->stopProcessing (); + iarea->setBeforeAfterViews (NULL, iarea); + delete beforeIarea; + beforeIarea = NULL; + if (beforeIpc) + beforeIpc->setPreviewImageListener (NULL); + delete beforePreviewHandler; + beforePreviewHandler = NULL; + if (beforeIpc) + rtengine::StagedImageProcessor::destroy (beforeIpc); + beforeIpc = NULL; + } + + if (beforeAfter->get_active ()) { + + beforeIarea = new ImageAreaPanel (); + + beforeLabel = Gtk::manage (new Gtk::Label ()); + beforeLabel->set_markup ("Before:"); + beforeBox = Gtk::manage (new Gtk::VBox ()); + beforeBox->pack_start (*beforeLabel, Gtk::PACK_SHRINK, 2); + beforeBox->pack_start (*beforeIarea); + + afterLabel = Gtk::manage (new Gtk::Label ()); + afterLabel->set_markup ("After:"); + afterBox->pack_start (*afterLabel, Gtk::PACK_SHRINK, 2); + afterBox->reorder_child (*afterLabel, 0); + + beforeAfterBox->pack_start (*beforeBox); + beforeAfterBox->reorder_child (*beforeBox, 0); + beforeAfterBox->show_all (); + + beforePreviewHandler = new PreviewHandler (); + isrc->increaseRef (); + beforeIpc = rtengine::StagedImageProcessor::create (isrc); + beforeIpc->setPreviewScale (10); + beforeIpc->setPreviewImageListener (beforePreviewHandler); + beforeIarea->imageArea->setPreviewHandler (beforePreviewHandler); + beforeIarea->imageArea->setImProcCoordinator (beforeIpc); + + iarea->setBeforeAfterViews (beforeIarea, iarea); + beforeIarea->setBeforeAfterViews (beforeIarea, iarea); + + rtengine::procparams::ProcParams params; + if (history->getBeforeLineParams (params)) + historyBeforeLineChanged (params); + } +} + diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h new file mode 100755 index 000000000..e8c3e01a9 --- /dev/null +++ b/rtgui/editorpanel.h @@ -0,0 +1,141 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _EDITORPANEL_ +#define _EDITORPANEL_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class EditorPanel; +struct EditorPanelIdleHelper { + EditorPanel* epanel; + bool destroyed; + int pending; +}; + +class RTWindow; +class EditorPanel : public Gtk::VBox, + public PParamsChangeListener, + public rtengine::ProgressListener, + public ThumbnailListener, + public HistoryBeforeLineListener { + + protected: + Gtk::Label *progressLabel; + Gtk::ToggleButton* info; + Gtk::ToggleButton* hidehp; + Gtk::ToggleButton* beforeAfter; + Gtk::HPaned* hpanedl; + Gtk::HPaned* hpanedr; + Gtk::HBox* statusBox; + Gtk::Image* red; + Gtk::Image* green; + Gtk::VBox* leftbox, *vboxright; + + Gtk::Button* queueimg; + Gtk::Button* saveimgas; + Gtk::Button* sendtogimp; + + ImageAreaPanel* iarea; + PreviewHandler* previewHandler; + PreviewHandler* beforePreviewHandler; // for the before-after view + Navigator* navigator; + ImageAreaPanel* beforeIarea; // for the before-after view + Gtk::VBox* beforeBox; + Gtk::VBox* afterBox; + Gtk::Label* beforeLabel; + Gtk::Label* afterLabel; + Gtk::HBox* beforeAfterBox; + + ProfilePanel* profilep; + History* history; + HistogramPanel* histogramPanel; + ToolPanelCoordinator* tpc; + RTWindow* parent; + SaveAsDialog* saveAsDialog; + + Thumbnail* openThm; + rtengine::InitialImage* isrc; + rtengine::StagedImageProcessor* ipc; + rtengine::StagedImageProcessor* beforeIpc; // for the before-after view + + EditorPanelIdleHelper* epih; + + void open (Thumbnail* tmb, rtengine::InitialImage* isrc); + void close (); + + rtengine::IImage16* processImage (); + BatchQueueEntry* createBatchQueueEntry (); + int saveImage (rtengine::IImage16* img, Glib::ustring& fname, SaveFormat sf, bool findNewNameIfNeeded); + + public: + + static rtengine::InitialImage* loadImage (Thumbnail* tmb); + + EditorPanel (Thumbnail* tmb, rtengine::InitialImage* isrc); + virtual ~EditorPanel (); + + bool beforeClosing (); + void on_realize (); + + void setParent (RTWindow* p) { parent = p; } + + // progresslistener interface + void setProgressState (int state); + void error (Glib::ustring descr); + void refreshProcessingState (bool state); // this is called by setProcessingState in the gtk thread + void displayError (Glib::ustring descr); // this is called by error in the gtk thread + + // PParamsChangeListener interface + void procParamsChanged (rtengine::procparams::ProcParams* params, rtengine::ProcEvent ev, Glib::ustring descr, ParamsEdited* paramsEdited=NULL); + + // thumbnaillistener interface + void procParamsChanged (Thumbnail* thm, int whoChangedIt); + + // HistoryBeforeLineListener + void historyBeforeLineChanged (const rtengine::procparams::ProcParams& params); + + // event handlers + void info_toggled (); + void hideHistoryActivated (); + void beforeAfterToggled (); + void saveAsPressed (); + void queueImgPressed (); + void sendToGimpPressed (); + + void saveProfile (); + Glib::ustring getShortName (); + Glib::ustring getFileName (); + bool handleShortcutKey (GdkEventKey* event); + + void saveOptions (); +}; + +#endif + diff --git a/rtgui/exiffiltersettings.cc b/rtgui/exiffiltersettings.cc new file mode 100755 index 000000000..5a5fcd856 --- /dev/null +++ b/rtgui/exiffiltersettings.cc @@ -0,0 +1,44 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +ExifFilterSettings::ExifFilterSettings () { + + clear (); +} + +void ExifFilterSettings::clear () { + fnumberFrom = 100; + fnumberTo = 0; + shutterFrom = 100; + shutterTo = 0; + isoFrom = 100000000; + isoTo = 0; + focalFrom = 1e8; + focalTo = 0; + lenses.clear (); + cameras.clear (); + + filterFNumber = false; + filterShutter = false; + filterFocalLen = false; + filterISO = false; + filterCamera = false; + filterLens = false; +} diff --git a/rtgui/exiffiltersettings.h b/rtgui/exiffiltersettings.h new file mode 100755 index 000000000..cfcfce8b2 --- /dev/null +++ b/rtgui/exiffiltersettings.h @@ -0,0 +1,51 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _EXIFFILTERSETTINGS_ +#define _EXIFFILTERSETTINGS_ + +#include +#include + +class ExifFilterSettings { + + public: + std::set cameras; + std::set lenses; + double fnumberFrom; + double fnumberTo; + double shutterFrom; + double shutterTo; + double focalFrom; + double focalTo; + int isoFrom; + int isoTo; + + bool filterFNumber; + bool filterShutter; + bool filterFocalLen; + bool filterISO; + bool filterCamera; + bool filterLens; + + ExifFilterSettings (); + void clear (); +}; + +#endif + diff --git a/rtgui/exifpanel.cc b/rtgui/exifpanel.cc new file mode 100755 index 000000000..4a7b5a6bd --- /dev/null +++ b/rtgui/exifpanel.cc @@ -0,0 +1,568 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +using namespace rtengine; +using namespace rtengine::procparams; +using namespace rtexif; +extern Glib::ustring argv0; + +ExifPanel::ExifPanel () : idata(NULL) { + + recursiveOp = true; + + exifTree = Gtk::manage(new Gtk::TreeView()); + scrolledWindow = Gtk::manage(new Gtk::ScrolledWindow()); + + exifTree->set_headers_visible(false); + exifTree->set_rules_hint(false); + exifTree->set_reorderable(false); + exifTree->set_enable_search(true); + exifTree->get_selection()->set_mode (Gtk::SELECTION_MULTIPLE); + scrolledWindow->set_border_width(2); + scrolledWindow->set_shadow_type(Gtk::SHADOW_NONE); + scrolledWindow->set_policy(Gtk::POLICY_ALWAYS, Gtk::POLICY_ALWAYS); + scrolledWindow->property_window_placement().set_value(Gtk::CORNER_TOP_LEFT); + scrolledWindow->add(*exifTree); + + exifTreeModel = Gtk::TreeStore::create(exifColumns); + exifTree->set_model (exifTreeModel); + + delicon = Gdk::Pixbuf::create_from_file (argv0+"/images/deltags.png"); + keepicon = Gdk::Pixbuf::create_from_file (argv0+"/images/addtags.png"); + editicon = Gdk::Pixbuf::create_from_file (argv0+"/images/logoicon16.png"); + + Gtk::TreeView::Column *viewcol = Gtk::manage(new Gtk::TreeView::Column ("Field Name")); + Gtk::CellRendererPixbuf* render_pb = Gtk::manage(new Gtk::CellRendererPixbuf ()); + Gtk::CellRendererText *render_txt = Gtk::manage(new Gtk::CellRendererText()); + viewcol->pack_start (*render_pb, false); + viewcol->pack_start (*render_txt, true); + viewcol->add_attribute (*render_pb, "pixbuf", exifColumns.icon); + viewcol->add_attribute (*render_txt, "markup", exifColumns.field); + + render_pb->property_ypad() = 0; + render_txt->property_ypad() = 0; + render_pb->property_yalign() = 0; + render_txt->property_yalign() = 0; + + exifTree->append_column (*viewcol); + + Gtk::TreeView::Column *viewcolv = Gtk::manage(new Gtk::TreeView::Column ("Value")); + Gtk::CellRendererText *render_txtv = Gtk::manage(new Gtk::CellRendererText()); + viewcolv->pack_start (*render_txtv, true); + viewcolv->add_attribute (*render_txtv, "markup", exifColumns.value); + + render_txtv->property_ypad() = 0; + + exifTree->append_column (*viewcolv); + + pack_start (*scrolledWindow); + + Gtk::HBox* buttons1 = Gtk::manage(new Gtk::HBox ()); + Gtk::HBox* buttons2 = Gtk::manage(new Gtk::HBox ()); + + remove = Gtk::manage(new Gtk::Button (M("EXIFPANEL_REMOVE"))); + remove->set_image (*Gtk::manage(new Gtk::Image (delicon))); + remove->set_tooltip_text (M("EXIFPANEL_REMOVEHINT")); + buttons1->pack_start (*remove); + + keep = Gtk::manage(new Gtk::Button (M("EXIFPANEL_KEEP"))); + keep->set_image (*Gtk::manage(new Gtk::Image (keepicon))); + keep->set_tooltip_text (M("EXIFPANEL_KEEPHINT")); + buttons1->pack_start (*keep); + + add = Gtk::manage(new Gtk::Button (M("EXIFPANEL_ADDEDIT"))); + add->set_image (*Gtk::manage(new Gtk::Image (editicon))); + add->set_tooltip_text (M("EXIFPANEL_ADDEDITHINT")); + buttons1->pack_start (*add); + + reset = Gtk::manage(new Gtk::Button (M("EXIFPANEL_RESET"))); + reset->set_image (*Gtk::manage(new Gtk::Image (Gtk::StockID ("gtk-undo"), Gtk::IconSize (2)))); + reset->set_tooltip_text (M("EXIFPANEL_RESETHINT")); + buttons2->pack_start (*reset); + + resetAll = Gtk::manage(new Gtk::Button (M("EXIFPANEL_RESETALL"))); + resetAll->set_image (*Gtk::manage(new Gtk::Image (argv0+"/images/gtk-undo-ltr.png"))); + resetAll->set_tooltip_text (M("EXIFPANEL_RESETALLHINT")); + buttons2->pack_start (*resetAll); + + pack_end (*buttons2, Gtk::PACK_SHRINK); + pack_end (*buttons1, Gtk::PACK_SHRINK); + + exifTree->get_selection()->signal_changed().connect(sigc::mem_fun(*this, &ExifPanel::exifSelectionChanged)); + exifTree->signal_row_activated().connect(sigc::mem_fun(*this, &ExifPanel::row_activated)); + + remove->signal_clicked().connect( sigc::mem_fun(*this, &ExifPanel::removePressed) ); + keep->signal_clicked().connect( sigc::mem_fun(*this, &ExifPanel::keepPressed) ); + reset->signal_clicked().connect( sigc::mem_fun(*this, &ExifPanel::resetPressed) ); + resetAll->signal_clicked().connect( sigc::mem_fun(*this, &ExifPanel::resetAllPressed) ); + add->signal_clicked().connect( sigc::mem_fun(*this, &ExifPanel::addPressed) ); + + show_all (); +} + +ExifPanel::~ExifPanel () { +} + +void ExifPanel::read (const ProcParams* pp, const ParamsEdited* pedited) { + + disableListener (); + + changeList = pp->exif; + setImageData (idata); + applyChangeList (); + exifSelectionChanged (); + + enableListener (); +} + +void ExifPanel::write (ProcParams* pp, ParamsEdited* pedited) { + +// updateChangeList (); + pp->exif = changeList; +} + +void ExifPanel::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { + + defChangeList = defParams->exif; +} + +void ExifPanel::setImageData (const ImageMetaData* id) { + + idata = id; + exifTreeModel->clear (); + + const std::vector& defTags = ExifManager::getDefaultTIFFTags (NULL); + for (int i=0; inameToString() == "ImageWidth" || defTags[i]->nameToString() == "ImageHeight" || defTags[i]->nameToString() == "BitsPerSample") + addTag (exifTreeModel->children(), defTags[i]->nameToString(), "?", SYSTEM, false); + else + addTag (exifTreeModel->children(), defTags[i]->nameToString(), defTags[i]->valueToString(), SYSTEM, false); + + if (id && id->getExifData ()) { +// id->getExifData ()->printAll (); + addDirectory (id->getExifData (), exifTreeModel->children()); + } +} + +Gtk::TreeModel::Children ExifPanel::addTag (const Gtk::TreeModel::Children& root, Glib::ustring field, Glib::ustring value, int action, bool editable) { + + Gtk::TreeModel::Row row = *(exifTreeModel->append(root)); + row[exifColumns.action] = action; + row[exifColumns.editable] = editable; + row[exifColumns.edited] = false; + row[exifColumns.field_nopango] = field; + row[exifColumns.value_nopango] = value; + row[exifColumns.orig_value] = value; + + if (action==WRITE) + row[exifColumns.icon] = keepicon; + else if (action==DONTWRITE) + row[exifColumns.icon] = delicon; + + if (editable) { + row[exifColumns.field] = Glib::ustring("") + field + ""; + row[exifColumns.value] = Glib::ustring("") + value + ""; + } + else if (action==SYSTEM) { + row[exifColumns.field] = Glib::ustring("") + field + ""; + row[exifColumns.value] = Glib::ustring("") + value + ""; + } + else { + row[exifColumns.field] = field; + row[exifColumns.value] = value; + } + + return row.children(); +} + +void ExifPanel::addDirectory (const TagDirectory* dir, Gtk::TreeModel::Children root) { + + for (int i=0; igetCount(); i++) { + Tag* t = ((TagDirectory*)dir)->getTagByIndex (i); + if (t->getAttrib() && t->getAttrib()->action==SYSTEM) + continue; + if (t->isDirectory()) + for (int j=0; t->getDirectory(j); j++) { + Gtk::TreeModel::Children ch = addTag (root, t->nameToString (j), M("EXIFPANEL_SUBDIRECTORY"), t->getAttrib() ? t->getAttrib()->action : 0, t->getAttrib() && t->getAttrib()->editable); + addDirectory (t->getDirectory(j), ch); + } + else + addTag (root, t->nameToString (), t->valueToString (), t->getAttrib() ? t->getAttrib()->action : 0, t->getAttrib() && t->getAttrib()->editable); + } +} + +void ExifPanel::exifSelectionChanged () { + + Glib::RefPtr selection = exifTree->get_selection(); + std::vector sel = selection->get_selected_rows(); + if (sel.size()>1) { + remove->set_sensitive (1); + keep->set_sensitive (1); + reset->set_sensitive (1); + } + else if (sel.size()==1) { + Gtk::TreeModel::iterator iter = exifTreeModel->get_iter (sel[0]); + if (iter->get_value (exifColumns.action)==SYSTEM) { + remove->set_sensitive (0); + keep->set_sensitive (0); + reset->set_sensitive (0); + } + else if (iter->children().size()>0) { + remove->set_sensitive (1); + keep->set_sensitive (1); + reset->set_sensitive (1); + } + else if (iter->get_value(exifColumns.icon)==delicon) { + remove->set_sensitive (0); + keep->set_sensitive (1); + reset->set_sensitive (1); + } + else if (iter->get_value(exifColumns.icon)==keepicon || iter->get_value(exifColumns.icon)==editicon) { + keep->set_sensitive (0); + remove->set_sensitive (1); + reset->set_sensitive (1); + } + } + else { + remove->set_sensitive (0); + keep->set_sensitive (0); + reset->set_sensitive (0); + } +} + +void ExifPanel::delIt (Gtk::TreeModel::iterator iter) { + + if (!iter) + return; + + if (iter->get_value (exifColumns.action) != SYSTEM) + iter->set_value (exifColumns.icon, delicon); + if (recursiveOp) + for (Gtk::TreeModel::iterator i=iter->children().begin(); i!=iter->children().end(); i++) + delIt (i); +} + +void ExifPanel::removePressed () { + + std::vector sel = exifTree->get_selection()->get_selected_rows(); + for (int i=0; iget_iter (sel[i])); + + exifSelectionChanged (); + updateChangeList (); + notifyListener (); +} + +void ExifPanel::keepIt (Gtk::TreeModel::iterator iter) { + + if (!iter) + return; + + if (iter->get_value (exifColumns.action) != SYSTEM) + iter->set_value (exifColumns.icon, iter->get_value (exifColumns.edited) ? editicon : keepicon); + if (recursiveOp) + for (Gtk::TreeModel::iterator i=iter->children().begin(); i!=iter->children().end(); i++) + keepIt (i); +} + +void ExifPanel::keepPressed () { + + std::vector sel = exifTree->get_selection()->get_selected_rows(); + for (int i=0; iget_iter (sel[i])); + + exifSelectionChanged (); + updateChangeList (); + notifyListener (); +} + +/*void ExifPanel::resetIt (Gtk::TreeModel::iterator iter) { + + if (!iter) + return; + + if (iter->get_value (exifColumns.action)!=SYSTEM) + iter->set_value (exifColumns.icon, iter->get_value (exifColumns.action) ? keepicon : delicon); + if (iter->get_value (exifColumns.edited)) { + iter->set_value (exifColumns.value, Glib::ustring("") + iter->get_value(exifColumns.orig_value) + ""); + iter->set_value (exifColumns.value_nopango, iter->get_value(exifColumns.orig_value)); + iter->set_value (exifColumns.edited, false); + } + if (iter->get_value (exifColumns.action)==100) + exifTreeModel->erase (iter); + else + if (recursiveOp) + for (Gtk::TreeModel::iterator i=iter->children().begin(); i!=iter->children().end(); i++) + resetIt (i); +}*/ +Gtk::TreeModel::iterator ExifPanel::resetIt (Gtk::TreeModel::iterator iter) { + + if (!iter) + return iter; + + if (iter->get_value (exifColumns.action)!=SYSTEM) + iter->set_value (exifColumns.icon, iter->get_value (exifColumns.action) ? keepicon : delicon); + if (iter->get_value (exifColumns.edited)) { + iter->set_value (exifColumns.value, Glib::ustring("") + iter->get_value(exifColumns.orig_value) + ""); + iter->set_value (exifColumns.value_nopango, iter->get_value(exifColumns.orig_value)); + iter->set_value (exifColumns.edited, false); + } + if (iter->get_value (exifColumns.action)==100) { + return exifTreeModel->erase (iter); + } + else + if (recursiveOp) { + Gtk::TreeModel::iterator i = iter->children().begin(); + while (i && i != iter->children().end()) + i = resetIt (i); + } + return ++iter; +} +void ExifPanel::resetPressed () { + + std::vector sel = exifTree->get_selection()->get_selected_rows(); + for (int i=0; iget_iter (sel[i])); + + exifSelectionChanged (); + updateChangeList (); + notifyListener (); +} + +void ExifPanel::resetAllPressed () { + + setImageData (idata); + changeList = defChangeList; + applyChangeList (); + exifSelectionChanged (); + notifyListener (); +} + +void ExifPanel::addPressed () { + + Gtk::Dialog* dialog = new Gtk::Dialog (M("EXIFPANEL_ADDTAGDLG_TITLE"), *((Gtk::Window*)get_toplevel()), true, true); + dialog->add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK); + dialog->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + + Gtk::HBox* hb1 = new Gtk::HBox (); + Gtk::HBox* hb2 = new Gtk::HBox (); + + Gtk::Label* tlabel = new Gtk::Label (M("EXIFPANEL_ADDTAGDLG_SELECTTAG")+":"); + Gtk::ComboBoxText* tcombo = new Gtk::ComboBoxText (); + + tcombo->append_text ("Artist"); + tcombo->append_text ("Copyright"); + tcombo->append_text ("ImageDescription"); + tcombo->append_text ("Exif.UserComment"); + + hb1->pack_start (*tlabel, Gtk::PACK_SHRINK, 4); + hb1->pack_start (*tcombo); + + Gtk::Label* vlabel = new Gtk::Label (M("EXIFPANEL_ADDTAGDLG_ENTERVALUE")+":"); + Gtk::Entry* ventry = new Gtk::Entry (); + hb2->pack_start (*vlabel, Gtk::PACK_SHRINK, 4); + hb2->pack_start (*ventry); + + Glib::ustring sel = getSelection (true); + if (sel=="") + tcombo->set_active_text ("Exif.UserComment"); + else { + tcombo->set_active_text (sel); + if (tcombo->get_active ()<0) { + tcombo->append_text (sel); + tcombo->set_active_text (sel); + } + ventry->set_text (getSelectedValue ()); + } + + ventry->set_activates_default (true); + dialog->set_default_response (Gtk::RESPONSE_OK); + dialog->get_vbox()->pack_start (*hb1, Gtk::PACK_SHRINK); + dialog->get_vbox()->pack_start (*hb2, Gtk::PACK_SHRINK, 4); + tlabel->show (); + tcombo->show (); + vlabel->show (); + ventry->show (); + hb1->show (); + hb2->show (); + + if (dialog->run ()== Gtk::RESPONSE_OK) { + editTag (exifTreeModel->children(), tcombo->get_active_text(), ventry->get_text()); + updateChangeList (); + notifyListener (); + } + + delete dialog; + delete tlabel; + delete tcombo; + delete vlabel; + delete ventry; + delete hb1; + delete hb2; +} + +void ExifPanel::editTag (Gtk::TreeModel::Children root, Glib::ustring name, Glib::ustring value) { + + Glib::ustring::size_type dp = name.find_first_of ('.'); + Glib::ustring fseg = name.substr (0,dp); + // look up first segment of the path + Gtk::TreeModel::iterator iter; + for (iter = root.begin(); iter!=root.end(); iter++) + if (iter->get_value (exifColumns.field_nopango) == fseg) + break; + + if (iter==root.end() && value!="#keep" && value!="#delete") { + iter = exifTreeModel->append(root); + iter->set_value (exifColumns.field_nopango, fseg); + iter->set_value (exifColumns.action, 100); + if (dp==Glib::ustring::npos) { + iter->set_value (exifColumns.value, Glib::ustring("") + value + ""); + iter->set_value (exifColumns.value_nopango, value); + iter->set_value (exifColumns.orig_value, value); + iter->set_value (exifColumns.field, Glib::ustring("") + fseg + ""); + iter->set_value (exifColumns.edited, true); + iter->set_value (exifColumns.editable, true); + iter->set_value (exifColumns.icon, editicon); + } + else { + iter->set_value (exifColumns.value, Glib::ustring(M("EXIFPANEL_SUBDIRECTORY"))); + iter->set_value (exifColumns.value_nopango, Glib::ustring(M("EXIFPANEL_SUBDIRECTORY"))); + iter->set_value (exifColumns.field, fseg); + iter->set_value (exifColumns.icon, keepicon); + iter->set_value (exifColumns.orig_value, Glib::ustring(M("EXIFPANEL_SUBDIRECTORY"))); + } + } + + if (dp==Glib::ustring::npos) { + if (value=="#keep" && iter->get_value (exifColumns.action)!=SYSTEM) + iter->set_value (exifColumns.icon, iter->get_value (exifColumns.edited) ? editicon : keepicon); + else if (value=="#delete" && iter->get_value (exifColumns.action)!=SYSTEM) + iter->set_value (exifColumns.icon, delicon); + else { + iter->set_value (exifColumns.value, Glib::ustring("") + value + ""); + iter->set_value (exifColumns.value_nopango, value); + iter->set_value (exifColumns.edited, true); + iter->set_value (exifColumns.icon, editicon); + } + } + else + editTag (iter->children(), name.substr (dp+1, Glib::ustring::npos), value); +} + +Glib::ustring ExifPanel::getSelectedValue () { + + Glib::RefPtr selection = exifTree->get_selection(); + std::vector rows = selection->get_selected_rows(); + if (rows.size()!=1) + return ""; + Gtk::TreeModel::iterator iter = exifTreeModel->get_iter (rows[0]); + if (iter) + return iter->get_value (exifColumns.value_nopango); + return ""; +} + +Glib::ustring ExifPanel::getSelection (bool onlyeditable) { + + Glib::RefPtr selection = exifTree->get_selection(); + std::vector rows = selection->get_selected_rows(); + + if (rows.size()!=1) + return ""; + Gtk::TreeModel::iterator iter = exifTreeModel->get_iter (rows[0]); + + Glib::ustring ret = ""; + bool first = true; + bool editable = false; + while (iter) { + if (first) + ret = iter->get_value (exifColumns.field_nopango); + else + ret = iter->get_value (exifColumns.field_nopango) + "." + ret; + editable = iter->get_value (exifColumns.editable); + iter = iter->parent (); + first = false; + } + if (!editable && onlyeditable) + return ""; + return ret; +} + +void ExifPanel::updateChangeList (Gtk::TreeModel::Children root, std::string prefix) { + + if (prefix!="") + prefix = prefix + "."; + + Gtk::TreeModel::iterator iter; + for (iter = root.begin(); iter!=root.end(); iter++) { + if (iter->get_value (exifColumns.edited) == true) { + ExifPair ec; + ec.field = prefix + iter->get_value (exifColumns.field_nopango); + ec.value = iter->get_value (exifColumns.value_nopango); + changeList.push_back (ec); + } + else if (iter->get_value (exifColumns.action) == WRITE && iter->get_value (exifColumns.icon) == delicon) { + ExifPair ec; + ec.field = prefix + iter->get_value (exifColumns.field_nopango); + ec.value = "#delete"; + changeList.push_back (ec); + } + else if (iter->get_value (exifColumns.action) == DONTWRITE && iter->get_value (exifColumns.icon) == keepicon) { + ExifPair ec; + ec.field = prefix + iter->get_value (exifColumns.field_nopango); + ec.value = "#keep"; + changeList.push_back (ec); + } + if (iter->get_value (exifColumns.icon) == keepicon) + updateChangeList (iter->children(), prefix + iter->get_value (exifColumns.field_nopango)); + } +} + +void ExifPanel::updateChangeList () { + + changeList.clear (); + updateChangeList (exifTreeModel->children(), ""); +} + +void ExifPanel::applyChangeList () { + + for (int i=0; ichildren(), changeList[i].field, changeList[i].value); +} + +void ExifPanel::row_activated (const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column) { + + Gtk::TreeModel::iterator iter = exifTreeModel->get_iter (path); + if (iter) { + if (iter->children().size()>0) + if (exifTree->row_expanded (path)) + exifTree->collapse_row (path); + else + exifTree->expand_row (path, false); + else if (iter->get_value (exifColumns.editable)) + addPressed (); + } +} + + +void ExifPanel::notifyListener () { + + if (listener) + listener->panelChanged (EvExif, M("HISTORY_CHANGED")); +} diff --git a/rtgui/exifpanel.h b/rtgui/exifpanel.h new file mode 100755 index 000000000..54e310db0 --- /dev/null +++ b/rtgui/exifpanel.h @@ -0,0 +1,97 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _EXIFPANEL_ +#define _EXIFPANEL_ + +#include +#include + +class ExifPanel : public Gtk::VBox, public ToolPanel { + + private: + const rtengine::ImageMetaData* idata; + int fullw, fullh, cx, cy, cw, ch; + bool crenabled; + std::vector changeList; + std::vector defChangeList; + bool recursiveOp; + + class ExifColumns : public Gtk::TreeModelColumnRecord { + public: + Gtk::TreeModelColumn > icon; + Gtk::TreeModelColumn field; + Gtk::TreeModelColumn field_nopango; + Gtk::TreeModelColumn value; + Gtk::TreeModelColumn value_nopango; + Gtk::TreeModelColumn orig_value; + Gtk::TreeModelColumn action; // = 0: dont write to output, =1: write to output, =2: chagned by RT (not editable/deletable), =3: new addition + Gtk::TreeModelColumn editable; + Gtk::TreeModelColumn edited; + + ExifColumns() { add(field); add(value); add(icon); add(action); add(edited); add(field_nopango); add(value_nopango); add(editable); add(orig_value); } + }; + Glib::RefPtr delicon; + Glib::RefPtr keepicon; + Glib::RefPtr editicon; + + ExifColumns exifColumns; + Gtk::TreeView* exifTree; + Gtk::ScrolledWindow* scrolledWindow; + Glib::RefPtr exifTreeModel; + + Gtk::Button* remove; + Gtk::Button* keep; + Gtk::Button* add; + Gtk::Button* reset; + Gtk::Button* resetAll; + + Gtk::TreeModel::Children addTag (const Gtk::TreeModel::Children& root, Glib::ustring field, Glib::ustring value, int action, bool editable); + void editTag (Gtk::TreeModel::Children root, Glib::ustring name, Glib::ustring value); + void updateChangeList (Gtk::TreeModel::Children root, std::string prefix); + void addDirectory (const rtexif::TagDirectory* dir, Gtk::TreeModel::Children root); + Glib::ustring getSelection (bool onlyifeditable=false); + Glib::ustring getSelectedValue (); + void updateChangeList (); + void applyChangeList (); + void keepIt (Gtk::TreeModel::iterator iter); + void delIt (Gtk::TreeModel::iterator iter); + Gtk::TreeModel::iterator resetIt (Gtk::TreeModel::iterator iter); + public: + ExifPanel (); + virtual ~ExifPanel (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + + void setImageData (const rtengine::ImageMetaData* id); + + void exifSelectionChanged (); + void removePressed (); + void keepPressed (); + void resetPressed (); + void resetAllPressed (); + void addPressed (); + void row_activated (const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column); + + void notifyListener (); + +}; + +#endif diff --git a/rtgui/favoritbrowser.cc b/rtgui/favoritbrowser.cc new file mode 100755 index 000000000..90b7b610d --- /dev/null +++ b/rtgui/favoritbrowser.cc @@ -0,0 +1,112 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +FavoritBrowser::FavoritBrowser () : listener (NULL), lastSelectedDir ("") { + + scrollw = Gtk::manage (new Gtk::ScrolledWindow ()); + scrollw->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); + + Gtk::Frame* frame = Gtk::manage (new Gtk::Frame ("Favorite Folders")); + frame->add (*scrollw); + + pack_start (*frame); + + treeView = Gtk::manage (new Gtk::TreeView ()); + scrollw->add (*treeView); + + favoritModel = Gtk::ListStore::create (favoritColumns); + treeView->set_model (favoritModel); + treeView->set_headers_visible (false); + + Gtk::TreeView::Column *iviewcol = Gtk::manage (new Gtk::TreeView::Column ("icon")); + Gtk::CellRendererPixbuf *iconCR = Gtk::manage (new Gtk::CellRendererPixbuf()); + iviewcol->pack_start (*iconCR, false); + iviewcol->add_attribute (*iconCR, "gicon", 0); + + treeView->append_column (*iviewcol); + treeView->append_column ("text", favoritColumns.shortdir); + + treeView->set_tooltip_column (2); + treeView->get_selection()->signal_changed().connect(sigc::mem_fun(*this, &FavoritBrowser::selectionChanged)); + + add = Gtk::manage (new Gtk::Button ("Add")); + del = Gtk::manage (new Gtk::Button ("Del")); + add->set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::ADD, Gtk::ICON_SIZE_MENU))); + del->set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::REMOVE, Gtk::ICON_SIZE_MENU))); + Gtk::HBox* buttonBox = Gtk::manage (new Gtk::HBox ()); + buttonBox->pack_start (*add); + buttonBox->pack_start (*del); + + pack_start (*buttonBox, Gtk::PACK_SHRINK, 2); + + add->signal_clicked().connect(sigc::mem_fun(*this, &FavoritBrowser::addPressed)); + del->signal_clicked().connect(sigc::mem_fun(*this, &FavoritBrowser::delPressed)); + + show_all (); +} + +void FavoritBrowser::selectionChanged () { + + Glib::RefPtr selection = treeView->get_selection(); + Gtk::TreeModel::iterator iter = selection->get_selected(); + if (iter && listener) + listener->selectDir (iter->get_value (favoritColumns.fulldir)); +} + +void FavoritBrowser::dirSelected (const Glib::ustring& dirname, const Glib::ustring& openfile) { + + lastSelectedDir = dirname; +} + +void FavoritBrowser::addPressed () { + + if (lastSelectedDir=="") + return; + + // check if the dirname is already in the list. If yes, return. + Gtk::TreeModel::iterator iter = favoritModel->children ().begin(); + while (iter != favoritModel->children().end()) { + if (iter->get_value (favoritColumns.fulldir) == lastSelectedDir) + return; + iter++; + } + + Glib::RefPtr hfile = Gio::File::create_for_parse_name (lastSelectedDir); + if (hfile) { + Glib::RefPtr info = hfile->query_info (); + if (info) { + Gtk::TreeModel::Row newrow = *(favoritModel->append()); + newrow[favoritColumns.shortdir] = info->get_display_name (); + newrow[favoritColumns.fulldir] = lastSelectedDir; + newrow[favoritColumns.icon] = info->get_icon (); + } + } +} + +void FavoritBrowser::delPressed () { + + // lookup the selected item in the bookmark + Glib::RefPtr selection = treeView->get_selection(); + Gtk::TreeModel::iterator iter = selection->get_selected(); + + if (iter) + favoritModel->erase (iter); +} + diff --git a/rtgui/favoritbrowser.h b/rtgui/favoritbrowser.h new file mode 100755 index 000000000..b50cc5cba --- /dev/null +++ b/rtgui/favoritbrowser.h @@ -0,0 +1,58 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _FAVORITBROWSER_ +#define _FAVORITBROWSER_ + +#include +#include +#include + +class FavoritBrowser : public Gtk::VBox, public DirSelectionListener { + + class FavoritColumns : public Gtk::TreeModel::ColumnRecord { + public: + Gtk::TreeModelColumn > icon; + Gtk::TreeModelColumn shortdir; + Gtk::TreeModelColumn fulldir; + FavoritColumns() { add(icon); add(shortdir), add(fulldir); } + }; + + FavoritColumns favoritColumns; + Gtk::ScrolledWindow* scrollw; + Gtk::TreeView* treeView; + Glib::RefPtr favoritModel; + DirBrowserRemoteInterface* listener; + Glib::ustring lastSelectedDir; + Gtk::Button* add; + Gtk::Button* del; + public: + + FavoritBrowser (); + + void setDirBrowserRemoteInterface (DirBrowserRemoteInterface* l) { listener = l; } + void dirSelected (const Glib::ustring& dirname, const Glib::ustring& openfile=""); + + void addPressed (); + void delPressed (); + void selectionChanged (); +}; + +#endif + + diff --git a/rtgui/filebrowser.cc b/rtgui/filebrowser.cc new file mode 100755 index 000000000..12b7a940b --- /dev/null +++ b/rtgui/filebrowser.cc @@ -0,0 +1,581 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include +#include +#include +#include + +FileBrowser::FileBrowser () + : tbl(NULL) { + + fbih = new FileBrowserIdleHelper; + fbih->fbrowser = this; + fbih->destroyed = false; + fbih->pending = 0; + + profileStore.parseProfiles (); + + signal_style_changed().connect( sigc::mem_fun(*this, &FileBrowser::styleChanged) ); + + int p = 0; + pmenu = new Gtk::Menu (); + pmenu->attach (*(open = new Gtk::MenuItem (M("FILEBROWSER_POPUPOPEN"))), 0, 1, p, p+1); p++; + pmenu->attach (*(develop = new Gtk::MenuItem (M("FILEBROWSER_POPUPPROCESS"))), 0, 1, p, p+1); p++; + pmenu->attach (*(new Gtk::SeparatorMenuItem ()), 0, 1, p, p+1); p++; + pmenu->attach (*(rank[0] = new Gtk::MenuItem (M("FILEBROWSER_POPUPUNRANK"))), 0, 1, p, p+1); p++; + pmenu->attach (*(rank[1] = new Gtk::MenuItem (M("FILEBROWSER_POPUPRANK1"))), 0, 1, p, p+1); p++; + pmenu->attach (*(rank[2] = new Gtk::MenuItem (M("FILEBROWSER_POPUPRANK2"))), 0, 1, p, p+1); p++; + pmenu->attach (*(rank[3] = new Gtk::MenuItem (M("FILEBROWSER_POPUPRANK3"))), 0, 1, p, p+1); p++; + pmenu->attach (*(rank[4] = new Gtk::MenuItem (M("FILEBROWSER_POPUPRANK4"))), 0, 1, p, p+1); p++; + pmenu->attach (*(rank[5] = new Gtk::MenuItem (M("FILEBROWSER_POPUPRANK5"))), 0, 1, p, p+1); p++; + pmenu->attach (*(new Gtk::SeparatorMenuItem ()), 0, 1, p, p+1); p++; + pmenu->attach (*(trash = new Gtk::MenuItem (M("FILEBROWSER_POPUPTRASH"))), 0, 1, p, p+1); p++; + pmenu->attach (*(untrash = new Gtk::MenuItem (M("FILEBROWSER_POPUPUNTRASH"))), 0, 1, p, p+1); p++; + pmenu->attach (*(new Gtk::SeparatorMenuItem ()), 0, 1, p, p+1); p++; + pmenu->attach (*(rename = new Gtk::MenuItem (M("FILEBROWSER_POPUPRENAME"))), 0, 1, p, p+1); p++; + pmenu->attach (*(remove = new Gtk::MenuItem (M("FILEBROWSER_POPUPREMOVE"))), 0, 1, p, p+1); p++; + pmenu->attach (*(new Gtk::SeparatorMenuItem ()), 0, 1, p, p+1); p++; + pmenu->attach (*(selall = new Gtk::MenuItem (M("FILEBROWSER_POPUPSELECTALL"))), 0, 1, p, p+1); p++; + pmenu->attach (*(new Gtk::SeparatorMenuItem ()), 0, 1, p, p+1); p++; + pmenu->attach (*(copyprof = new Gtk::MenuItem (M("FILEBROWSER_COPYPROFILE"))), 0, 1, p, p+1); p++; + pmenu->attach (*(pasteprof = new Gtk::MenuItem (M("FILEBROWSER_PASTEPROFILE"))), 0, 1, p, p+1); p++; + pmenu->attach (*(partpasteprof = new Gtk::MenuItem (M("FILEBROWSER_PARTIALPASTEPROFILE"))), 0, 1, p, p+1); p++; + pmenu->attach (*(applyprof = new Gtk::MenuItem (M("FILEBROWSER_APPLYPROFILE"))), 0, 1, p, p+1); p++; + pmenu->attach (*(clearprof = new Gtk::MenuItem (M("FILEBROWSER_CLEARPROFILE"))), 0, 1, p, p+1); p++; + pmenu->show_all (); + + pmaccelgroup = Gtk::AccelGroup::create (); + pmenu->set_accel_group (pmaccelgroup); + selall->add_accelerator ("activate", pmenu->get_accel_group(), GDK_a, Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE); + trash->add_accelerator ("activate", pmenu->get_accel_group(), GDK_Delete, (Gdk::ModifierType)0, Gtk::ACCEL_VISIBLE); + untrash->add_accelerator ("activate", pmenu->get_accel_group(), GDK_Delete, Gdk::SHIFT_MASK, Gtk::ACCEL_VISIBLE); + develop->add_accelerator ("activate", pmenu->get_accel_group(), GDK_Q, Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE); + copyprof->add_accelerator ("activate", pmenu->get_accel_group(), GDK_C, Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE); + pasteprof->add_accelerator ("activate", pmenu->get_accel_group(), GDK_V, Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE); + partpasteprof->add_accelerator ("activate", pmenu->get_accel_group(), GDK_V, Gdk::CONTROL_MASK | Gdk::SHIFT_MASK, Gtk::ACCEL_VISIBLE); + + profmenu = new Gtk::Menu (); + + open->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), open)); + for (int i=0; i<6; i++) + rank[i]->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), rank[i])); + trash->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), trash)); + untrash->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), untrash)); + develop->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), develop)); + rename->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), rename)); + remove->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), remove)); + selall->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), selall)); + copyprof->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), copyprof)); + pasteprof->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), pasteprof)); + partpasteprof->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), partpasteprof)); + applyprof->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), applyprof)); + clearprof->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), clearprof)); +} + +void FileBrowser::rightClicked (ThumbBrowserEntryBase* entry) { + + trash->set_sensitive (false); + untrash->set_sensitive (false); + for (int i=0; ithumbnail->getStage()==1) { + untrash->set_sensitive (true); + break; + } + for (int i=0; ithumbnail->getStage()==0) { + trash->set_sensitive (true); + break; + } + + pasteprof->set_sensitive (clipboard.hasProcParams()); + partpasteprof->set_sensitive (clipboard.hasProcParams()); + copyprof->set_sensitive (selected.size()==1); + clearprof->set_sensitive (selected.size()>0); + + int p = 0; + Gtk::Menu* applmenu = Gtk::manage (new Gtk::Menu ()); + std::vector profnames = profileStore.getProfileNames (); + for (int i=0; iattach (*mi, 0, 1, p, p+1); p++; + mi->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::applyMenuItemActivated), profnames[i])); + mi->show (); + } + applyprof->set_submenu (*applmenu); + + pmenu->popup (3, this->eventTime); +} + +void FileBrowser::doubleClicked (ThumbBrowserEntryBase* entry) { + + if (tbl && entry) { + std::vector entries; + entries.push_back (((FileBrowserEntry*)entry)->thumbnail); + tbl->openRequested (entries); + } +} + +struct addparams { + FileBrowserIdleHelper* fbih; + FileBrowserEntry* entry; +}; + +int addfl (void* data) { + + addparams* ap = (addparams*) data; + FileBrowserIdleHelper* fbih = ap->fbih; + + gdk_threads_enter(); + + if (fbih->destroyed) { + if (fbih->pending == 1) + delete fbih; + else + fbih->pending--; + delete ap->entry; + delete ap; + gdk_threads_leave (); + return 0; + } + + ap->fbih->fbrowser->addEntry_ (ap->entry); + delete ap; + fbih->pending--; + gdk_threads_leave(); + return 0; +} + +void FileBrowser::addEntry (FileBrowserEntry* entry) { + + fbih->pending++; + entry->setParent (this); + addparams* ap = new addparams; + ap->fbih = fbih; + ap->entry = entry; + g_idle_add (addfl, ap); +} + +void FileBrowser::addEntry_ (FileBrowserEntry* entry) { + + entry->selected = false; + entry->drawable = false; + entry->framed = editedFiles.find (entry->filename)!=editedFiles.end(); + + // add button set to the thumbbrowserentry + entry->addButtonSet (new FileThumbnailButtonSet (entry)); + entry->getThumbButtonSet()->setRank (entry->thumbnail->getRank()); + entry->getThumbButtonSet()->setInTrash (entry->thumbnail->getStage()==1); + entry->getThumbButtonSet()->setButtonListener (this); + entry->resize (options.thumbSize); + + // find place in abc order + std::vector::iterator i = fd.begin(); + while (i!=fd.end() && *entry < *((FileBrowserEntry*)*i)) + i++; + + fd.insert (i, entry); + + initEntry (entry); + redraw (); +} + +FileBrowserEntry* FileBrowser::delEntry (const Glib::ustring& fname) { + + for (std::vector::iterator i=fd.begin(); i!=fd.end(); i++) + if ((*i)->filename==fname) { + ThumbBrowserEntryBase* entry = *i; + entry->selected = false; + fd.erase (i); + std::vector::iterator j = std::find (selected.begin(), selected.end(), entry); + if (j!=selected.end()) { + selected.erase (j); + notifySelectionListener (); + } + if (lastClicked==entry) + lastClicked = NULL; + redraw (); + return (FileBrowserEntry*)entry; + } + return NULL; +} + +FileBrowserEntry* FileBrowser::findEntry (const Glib::ustring& fname) { + + for (std::vector::iterator i=fd.begin(); i!=fd.end(); i++) + if ((*i)->filename==fname) + return (FileBrowserEntry*)*i; + return NULL; +} + +void FileBrowser::close () { + if (fbih->pending) + fbih->destroyed = true; + else + delete fbih; + + fbih = new FileBrowserIdleHelper; + fbih->fbrowser = this; + fbih->destroyed = false; + fbih->pending = 0; + + for (int i=0; ithumbnail->decreaseRef (); +} + +void FileBrowser::menuItemActivated (Gtk::MenuItem* m) { + + std::vector mselected; + for (int i=0; i entries; + for (int i=0; ithumbnail); + tbl->openRequested (entries); + } + else if (m==remove) + tbl->deleteRequested (mselected); + else if (m==trash) + toTrashRequested (mselected); + else if (m==untrash) + fromTrashRequested (mselected); + else if (m==develop) + tbl->developRequested (mselected); + else if (m==rename) + tbl->renameRequested (mselected); + else if (m==selall) { + lastClicked = NULL; + selected.clear (); + for (int i=0; iselected = true; + selected.push_back (fd[i]); + } + queue_draw (); + notifySelectionListener (); + } + else if (m==copyprof) + copyProfile (); + else if (m==pasteprof) + pasteProfile (); + else if (m==partpasteprof) + partPasteProfile (); + else if (m==clearprof) { + for (int i=0; ithumbnail->clearProcParams (FILEBROWSER); + queue_draw (); + } +} + +void FileBrowser::copyProfile () { + + if (selected.size()==1) + clipboard.setProcParams (((FileBrowserEntry*)selected[0])->thumbnail->getProcParams()); +} + +void FileBrowser::pasteProfile () { + + std::vector mselected; + for (int i=0; ithumbnail->setProcParams (clipboard.getProcParams(), FILEBROWSER); + + queue_draw (); +} + +void FileBrowser::partPasteProfile () { + + std::vector mselected; + for (int i=0; ithumbnail->getProcParams (); + partialPasteDlg.applyPaste (¶ms, &clipboard.getProcParams()); + mselected[i]->thumbnail->setProcParams (params, FILEBROWSER); + } + + queue_draw (); + } + partialPasteDlg.hide (); +} + +bool FileBrowser::keyPressed (GdkEventKey* event) { + + if ((event->keyval==GDK_C || event->keyval==GDK_c) && event->state & GDK_CONTROL_MASK) { + copyProfile (); + return true; + } + else if ((event->keyval==GDK_V || event->keyval==GDK_v) && event->state & GDK_CONTROL_MASK && !(event->state & GDK_SHIFT_MASK)) { + pasteProfile (); + return true; + } + else if ((event->keyval==GDK_V || event->keyval==GDK_v) && event->state & GDK_CONTROL_MASK && event->state & GDK_SHIFT_MASK) { + partPasteProfile (); + return true; + } + else if (event->keyval==GDK_Delete && !(event->state & GDK_SHIFT_MASK)) { + menuItemActivated (trash); + return true; + } + else if (event->keyval==GDK_Delete && event->state & GDK_SHIFT_MASK) { + menuItemActivated (untrash); + return true; + } + else if ((event->keyval==GDK_Q || event->keyval==GDK_q) && event->state & GDK_CONTROL_MASK) { + menuItemActivated (develop); + return true; + } + else if ((event->keyval==GDK_A || event->keyval==GDK_a) && event->state & GDK_CONTROL_MASK) { + menuItemActivated (selall); + return true; + } + + return false; +} + +void FileBrowser::applyMenuItemActivated (Glib::ustring ppname) { + + rtengine::procparams::ProcParams* pparams = profileStore.getProfile (ppname); + if (pparams && selected.size()>0) { + for (int i=0; ithumbnail->setProcParams (*pparams, FILEBROWSER); + queue_draw (); + } +} + +void FileBrowser::applyFilter (const BrowserFilter& filter) { + + this->filter = filter; + + // remove items not complying the filter from the selection + bool selchanged = false; + for (int i=0; iselected && !checkFilter (fd[i])) { + fd[i]->selected = false; + std::vector::iterator j = std::find (selected.begin(), selected.end(), fd[i]); + selected.erase (j); + if (lastClicked==fd[i]) + lastClicked = NULL; + selchanged = true; + } + if (selchanged) + notifySelectionListener (); + redraw (); +} + +bool FileBrowser::checkFilter (ThumbBrowserEntryBase* entryb) { // true -> entry complies filter + + FileBrowserEntry* entry = (FileBrowserEntry*)entryb; + // return false if basic filter settings are not satisfied + if (filter.showRanked[entry->thumbnail->getRank()]==false || (entry->thumbnail->getStage()==1 && !filter.showTrash) || (entry->thumbnail->getStage()==0 && !filter.showNotTrash)) + return false; + + // check exif filter + const CacheImageData* cfs = entry->thumbnail->getCacheImageData(); + double tol = 0.01; + double tol2 = 1e-8; + + if (!filter.exifFilterEnabled) + return true; + + if (!cfs->exifValid) + return (!filter.exifFilter.filterCamera || filter.exifFilter.cameras.count(cfs->camera)>0) + && (!filter.exifFilter.filterLens || filter.exifFilter.lenses.count(cfs->lens)>0); + + return + (!filter.exifFilter.filterShutter || (rtengine::ImageMetaData::shutterFromString(rtengine::ImageMetaData::shutterToString(cfs->shutter)) >= filter.exifFilter.shutterFrom-tol2 && rtengine::ImageMetaData::shutterFromString(rtengine::ImageMetaData::shutterToString(cfs->shutter)) <= filter.exifFilter.shutterTo+tol2)) + && (!filter.exifFilter.filterFNumber || (rtengine::ImageMetaData::apertureFromString(rtengine::ImageMetaData::apertureToString(cfs->fnumber)) >= filter.exifFilter.fnumberFrom-tol2 && rtengine::ImageMetaData::apertureFromString(rtengine::ImageMetaData::apertureToString(cfs->fnumber)) <= filter.exifFilter.fnumberTo+tol2)) + && (!filter.exifFilter.filterFocalLen || (cfs->focalLen >= filter.exifFilter.focalFrom-tol && cfs->focalLen <= filter.exifFilter.focalTo+tol)) + && (!filter.exifFilter.filterISO || (cfs->iso >= filter.exifFilter.isoFrom && cfs->iso <= filter.exifFilter.isoTo)) + && (!filter.exifFilter.filterCamera || filter.exifFilter.cameras.count(cfs->camera)>0) + && (!filter.exifFilter.filterLens || filter.exifFilter.lenses.count(cfs->lens)>0); +} + +void FileBrowser::toTrashRequested (std::vector tbe) { + + for (int i=0; ithumbnail->getStage()==1) + continue; + tbe[i]->thumbnail->setStage (1); + if (tbe[i]->getThumbButtonSet()) { + tbe[i]->getThumbButtonSet()->setRank (tbe[i]->thumbnail->getRank()); + tbe[i]->getThumbButtonSet()->setInTrash (true); + } + } + applyFilter (filter); +} + +void FileBrowser::fromTrashRequested (std::vector tbe) { + + for (int i=0; ithumbnail->getStage()==0) + continue; + tbe[i]->thumbnail->setStage (0); + if (tbe[i]->getThumbButtonSet()) { + tbe[i]->getThumbButtonSet()->setRank (tbe[i]->thumbnail->getRank()); + tbe[i]->getThumbButtonSet()->setInTrash (false); + } + } + applyFilter (filter); +} + +void FileBrowser::rankingRequested (std::vector tbe, int rank) { + + for (int i=0; ithumbnail->setRank (rank); + if (tbe[i]->getThumbButtonSet()) + tbe[i]->getThumbButtonSet()->setRank (tbe[i]->thumbnail->getRank()); + } + applyFilter (filter); +} + +void FileBrowser::buttonPressed (LWButton* button, int actionCode, void* actionData) { + + if (actionCode>=0 && actionCode<=5) { // rank + std::vector tbe; + tbe.push_back ((FileBrowserEntry*)actionData); + rankingRequested (tbe, actionCode); + } + else if (actionCode==6 && tbl) { // to processin queue + std::vector tbe; + tbe.push_back ((FileBrowserEntry*)actionData); + tbl->developRequested (tbe); + } + else if (actionCode==7) { // to trash / undelete + std::vector tbe; + FileBrowserEntry* entry = (FileBrowserEntry*)actionData; + tbe.push_back (entry); + if (entry->thumbnail->getStage()==0) + toTrashRequested (tbe); + else + fromTrashRequested (tbe); + } +} + +void FileBrowser::openNextImage () { + + if (fd.size()>0) { + for (int i=fd.size()-1; i>=0; i--) + if (editedFiles.find (fd[i]->filename)!=editedFiles.end()) + if (i entries; + entries.push_back (((FileBrowserEntry*)fd[i+1])->thumbnail); + tbl->openRequested (entries); + return; + } + if (tbl) { + std::vector entries; + entries.push_back (((FileBrowserEntry*)fd[0])->thumbnail); + tbl->openRequested (entries); + } + } +} + +void FileBrowser::openPrevImage () { + + if (fd.size()>0) { + for (int i=0; ifilename)!=editedFiles.end()) + if (i>0 && tbl) { + std::vector entries; + entries.push_back (((FileBrowserEntry*)fd[i-1])->thumbnail); + tbl->openRequested (entries); + return; + } + if (tbl) { + std::vector entries; + entries.push_back (((FileBrowserEntry*)fd[fd.size()-1])->thumbnail); + tbl->openRequested (entries); + } + } +} + +int redrawtb (void* data) { + + ((FileBrowser*)data)->_thumbRearrangementNeeded (); + return 0; +} + +void FileBrowser::_thumbRearrangementNeeded () { + + refreshThumbImages (); +} + +void FileBrowser::thumbRearrangementNeeded () { + + g_idle_add (redrawtb, this); +} +void FileBrowser::selectionChanged () { + + notifySelectionListener (); +} + +void FileBrowser::notifySelectionListener () { + + if (tbl) { + std::vector thm; + for (int i=0; ithumbnail); + tbl->selectionChanged (thm); + } +} + +void FileBrowser::redrawNeeded (ThumbBrowserEntryBase* entry) { + + if (entry->insideWindow (0, 0, internal.get_width(), internal.get_height())) { + if (!internal.isDirty ()) { + internal.setDirty (); + internal.queue_draw (); + } + } +} + +void FileBrowser::redrawNeeded (LWButton* button) { + + queue_draw (); +} diff --git a/rtgui/filebrowser.h b/rtgui/filebrowser.h new file mode 100755 index 000000000..33a2b1790 --- /dev/null +++ b/rtgui/filebrowser.h @@ -0,0 +1,116 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _FILEBROWSER_ +#define _FILEBROWSER_ + +#include +#include +#include +#include +#include +#include + +class FileBrowser; +class FileBrowserEntry; +class FileBrowserListener { + + public: + virtual void openRequested (std::vector tbe) {} + virtual void developRequested (std::vector tbe) {} + virtual void renameRequested (std::vector tbe) {} + virtual void deleteRequested (std::vector tbe) {} + virtual void selectionChanged (std::vector tbe) {} +}; + +struct FileBrowserIdleHelper { + FileBrowser* fbrowser; + bool destroyed; + int pending; +}; + +class FileBrowser : public ThumbBrowserBase, public LWButtonListener { + + protected: + + Gtk::MenuItem* rank[6]; + Gtk::MenuItem* trash; + Gtk::MenuItem* untrash; + Gtk::MenuItem* develop; + Gtk::MenuItem* rename; + Gtk::MenuItem* remove; + Gtk::MenuItem* open; + Gtk::MenuItem* selall; + Gtk::MenuItem* copyprof; + Gtk::MenuItem* pasteprof; + Gtk::MenuItem* partpasteprof; + Gtk::MenuItem* applyprof; + Gtk::MenuItem* clearprof; + Gtk::Menu* pmenu; + Gtk::Menu* profmenu; + Glib::RefPtr pmaccelgroup; + + FileBrowserListener* tbl; + BrowserFilter filter; + PartialPasteDlg partialPasteDlg; + + FileBrowserIdleHelper* fbih; + + void toTrashRequested (std::vector tbe); + void fromTrashRequested (std::vector tbe); + void rankingRequested (std::vector tbe, int rank); + void notifySelectionListener (); + + public: + + FileBrowser (); + + void addEntry (FileBrowserEntry* entry); // can be called from any thread + void addEntry_ (FileBrowserEntry* entry); // this must be executed inside the gtk thread + FileBrowserEntry* delEntry (const Glib::ustring& fname); // return the entry if found here return NULL otherwise + FileBrowserEntry* findEntry (const Glib::ustring& fname); // return the entry if found here return NULL otherwise + void close (); + + void setFileBrowserListener (FileBrowserListener* l) { tbl = l; } + + void menuItemActivated (Gtk::MenuItem* m); + void applyMenuItemActivated (Glib::ustring ppname); + + void applyFilter (const BrowserFilter& filter); + + void buttonPressed (LWButton* button, int actionCode, void* actionData); + void redrawNeeded (LWButton* button); + bool checkFilter (ThumbBrowserEntryBase* entry); + void rightClicked (ThumbBrowserEntryBase* entry); + void doubleClicked (ThumbBrowserEntryBase* entry); + bool keyPressed (GdkEventKey* event); + + void openNextImage (); + void openPrevImage (); + void copyProfile (); + void pasteProfile (); + void partPasteProfile (); + + void redrawNeeded (ThumbBrowserEntryBase* entry); + void thumbRearrangementNeeded (); + void _thumbRearrangementNeeded (); + + void selectionChanged (); +}; + +#endif diff --git a/rtgui/filebrowserentry.cc b/rtgui/filebrowserentry.cc new file mode 100755 index 000000000..43942e1f1 --- /dev/null +++ b/rtgui/filebrowserentry.cc @@ -0,0 +1,555 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include +#include + +#define CROPRESIZEBORDER 4 + +bool FileBrowserEntry::iconsLoaded = false; +Glib::RefPtr FileBrowserEntry::editedIcon; +Glib::RefPtr FileBrowserEntry::recentlySavedIcon; +Glib::RefPtr FileBrowserEntry::enqueuedIcon; + +FileBrowserEntry::FileBrowserEntry (Thumbnail* thm, const Glib::ustring& fname) + : ThumbBrowserEntryBase (fname), thumbnail(thm), iatlistener(NULL), state(SNormal), cropgl(NULL) { + + feih = new FileBrowserEntryIdleHelper; + feih->fbentry = this; + feih->destroyed = false; + feih->pending = 0; + + italicstyle = thumbnail->getType() != FT_Raw; + datetimeline = thumbnail->getDateTimeString (); + exifline = thumbnail->getExifString (); + + if (!iconsLoaded) { + editedIcon = Gdk::Pixbuf::create_from_file (argv0+"/images/edited.png"); + recentlySavedIcon = Gdk::Pixbuf::create_from_file (argv0+"/images/saved.png"); + enqueuedIcon = Gdk::Pixbuf::create_from_file (argv0+"/images/processing.png"); + } + + if (thm) + thm->addThumbnailListener (this); +} + +FileBrowserEntry::~FileBrowserEntry () { + + thumbImageUpdater.removeJobs (this); + if (thumbnail) + thumbnail->removeThumbnailListener (this); + + if (feih->pending) + feih->destroyed = true; + else + delete feih; +} + +void FileBrowserEntry::refreshThumbnailImage () { + + if (!thumbnail) + return; + + thumbImageUpdater.add (thumbnail, thumbnail->getProcParams(), preh, &updatepriority, this); + thumbImageUpdater.process (); +} + +void FileBrowserEntry::calcThumbnailSize () { + + if (thumbnail) + thumbnail->getThumbnailSize (prew, preh); +} + +std::vector > FileBrowserEntry::getIconsOnImageArea () { + + std::vector > ret; + + if (!thumbnail) + return ret; + + if (thumbnail->hasProcParams() && editedIcon) + ret.push_back (editedIcon); + if (thumbnail->isRecentlySaved() && recentlySavedIcon) + ret.push_back (recentlySavedIcon); + if (thumbnail->isEnqueued () && enqueuedIcon) + ret.push_back (enqueuedIcon); + + return ret; +} + +void FileBrowserEntry::customBackBufferUpdate (Cairo::RefPtr c) { + + if (state==SCropSelecting || state==SResizeH1 || state==SResizeH2 || state==SResizeW1 || state==SResizeW2 || state==SCropMove) + drawCrop (c, prex, prey, prew, preh, 0, 0, scale, cropParams); + else { + rtengine::procparams::CropParams cparams = thumbnail->getProcParams().crop; + if (cparams.enabled) + drawCrop (c, prex, prey, prew, preh, 0, 0, scale, cparams); + } +} + +void FileBrowserEntry::getIconSize (int& w, int& h) { + + w = editedIcon->get_width (); + h = editedIcon->get_height (); +} + +FileThumbnailButtonSet* FileBrowserEntry::getThumbButtonSet () { + + return (FileThumbnailButtonSet*)buttonSet; +} + +void FileBrowserEntry::procParamsChanged (Thumbnail* thm, int whoChangedIt) { + + refreshThumbnailImage (); +} + +struct tiupdate { + FileBrowserEntryIdleHelper* feih; + rtengine::IImage8* img; + double scale; + rtengine::procparams::CropParams cropParams; +}; + +int fbeupdate (void* data) { + + gdk_threads_enter (); + tiupdate* params = (tiupdate*)data; + FileBrowserEntryIdleHelper* feih = params->feih; + + if (feih->destroyed) { + if (feih->pending == 1) + delete feih; + else + feih->pending--; + params->img->free (); + delete params; + gdk_threads_leave (); + return 0; + } + + feih->fbentry->_updateImage (params->img, params->scale, params->cropParams); + feih->pending--; + + gdk_threads_leave (); + delete params; + + return 0; +} + +void FileBrowserEntry::updateImage (rtengine::IImage8* img, double scale, rtengine::procparams::CropParams cropParams) { + + redrawRequests++; + feih->pending++; + tiupdate* param = new tiupdate (); + param->feih = feih; + param->img = img; + param->scale = scale; + param->cropParams = cropParams; + g_idle_add (fbeupdate, param); +} + +void FileBrowserEntry::_updateImage (rtengine::IImage8* img, double s, rtengine::procparams::CropParams cropParams) { + + redrawRequests--; + scale = s; + this->cropParams = cropParams; + if (preh == img->getHeight ()) { + prew = img->getWidth (); + guint8* temp = preview; + preview = NULL; + delete [] temp; + temp = new guint8 [prew*preh*3]; + memcpy (temp, img->getData(), prew*preh*3); + preview = temp; + updateBackBuffer (); + } + if (redrawRequests==0 && parent) + parent->redrawNeeded (this); + img->free (); +} + +bool FileBrowserEntry::motionNotify (int x, int y) { + + bool b = ThumbBrowserEntryBase::motionNotify (x, y); + + int ix = x - startx - ofsX; + int iy = y - starty - ofsY; + + if (inside (x,y)) + updateCursor (ix, iy); + + if (state==SRotateSelecting) { + action_x = x; + action_y = y; + parent->redrawNeeded (this); + } + else if (state==SResizeH1 && cropgl) { + int oy = cropParams.y; + cropParams.y = action_y + (y-press_y) / scale; + cropParams.h += oy - cropParams.y; + cropgl->cropHeight1Resized (cropParams.x, cropParams.y, cropParams.w, cropParams.h); + updateBackBuffer (); + parent->redrawNeeded (this); + } + else if (state==SResizeH2 && cropgl) { + cropParams.h = action_y + (y-press_y) / scale; + cropgl->cropHeight2Resized (cropParams.x, cropParams.y, cropParams.w, cropParams.h); + updateBackBuffer (); + parent->redrawNeeded (this); + } + else if (state==SResizeW1 && cropgl) { + int ox = cropParams.x; + cropParams.x = action_x + (x-press_x) / scale; + cropParams.w += ox - cropParams.x; + cropgl->cropWidth1Resized (cropParams.x, cropParams.y, cropParams.w, cropParams.h); + updateBackBuffer (); + parent->redrawNeeded (this); + } + else if (state==SResizeW2 && cropgl) { + cropParams.w = action_x + (x-press_x) / scale; + cropgl->cropWidth2Resized (cropParams.x, cropParams.y, cropParams.w, cropParams.h); + updateBackBuffer (); + parent->redrawNeeded (this); + } + else if (state==SCropMove && cropgl) { + cropParams.x = action_x + (x-press_x) / scale; + cropParams.y = action_y + (y-press_y) / scale; + cropgl->cropMoved (cropParams.x, cropParams.y, cropParams.w, cropParams.h); + updateBackBuffer (); + parent->redrawNeeded (this); + } + else if (state==SCropSelecting && cropgl) { + int cx1 = press_x, cy1 = press_y; + int cx2 = (ix-prex) / scale, cy2 = (iy-prey) / scale; + cropgl->cropResized (cx1, cy1, cx2, cy2); + if (cx2 > cx1) { + cropParams.x = cx1; + cropParams.w = cx2 - cx1 + 1; + } + else { + cropParams.x = cx2; + cropParams.w = cx1 - cx2 + 1; + } + if (cy2 > cy1) { + cropParams.y = cy1; + cropParams.h = cy2 - cy1 + 1; + } + else { + cropParams.y = cy2; + cropParams.h = cy1 - cy2 + 1; + } + updateBackBuffer (); + parent->redrawNeeded (this); + } + + return b; +} + +bool FileBrowserEntry::pressNotify (int button, int type, int bstate, int x, int y) { + + bool b = ThumbBrowserEntryBase::pressNotify (button, type, bstate, x, y); + + ToolMode tm = iatlistener->getToolBar()->getTool (); + int ix = x - startx - ofsX; + int iy = y - starty - ofsY; + if (!b && selected && inside (x,y)) { + if (button==1 && type==GDK_BUTTON_PRESS && state==SNormal) { + if (onArea (CropTop, ix, iy)) { + state = SResizeH1; + press_y = y; + action_y = cropParams.y; + cropgl = iatlistener->startCropEditing (thumbnail); + b = true; + } + else if (onArea (CropBottom, ix, iy)) { + state = SResizeH2; + press_y = y; + action_y = cropParams.h; + cropgl = iatlistener->startCropEditing (thumbnail); + b = true; + } + else if (onArea (CropLeft, ix, iy)) { + state = SResizeW1; + press_x = x; + action_x = cropParams.x; + cropgl = iatlistener->startCropEditing (thumbnail); + b = true; + } + else if (onArea (CropRight, ix, iy)) { + state = SResizeW2; + press_x = x; + action_x = cropParams.w; + cropgl = iatlistener->startCropEditing (thumbnail); + b = true; + } + else if ((bstate & GDK_SHIFT_MASK) && onArea (CropInside, ix, iy)) { + state = SCropMove; + press_x = x; + press_y = y; + action_x = cropParams.x; + action_y = cropParams.y; + cropgl = iatlistener->startCropEditing (thumbnail); + b = true; + } + else if (onArea (CropImage, ix, iy)) { + if (tm == TMStraighten) { + state = SRotateSelecting; + press_x = x; + press_y = y; + action_x = x; + action_y = y; + rot_deg = 0; + b = true; + } + else if (tm == TMSpotWB) { + iatlistener->spotWBselected ((ix-prex)/scale, (iy-prey)/scale, thumbnail); + b = true; + } + else if (tm == TMCropSelect) { + cropgl = iatlistener->startCropEditing (thumbnail); + if (cropgl) { + state = SCropSelecting; + press_x = cropParams.x = (ix-prex) / scale; + press_y = cropParams.y = (iy-prey) / scale; + cropParams.w = cropParams.h = 1; + cropgl->cropInit (cropParams.x, cropParams.y, cropParams.w, cropParams.h); + b = true; + } + } + } + } + updateCursor (ix, iy); + } + return b; +} + +bool FileBrowserEntry::releaseNotify (int button, int type, int bstate, int x, int y) { + + bool b = ThumbBrowserEntryBase::releaseNotify (button, type, bstate, x, y); + + int ix = x - startx - ofsX; + int iy = y - starty - ofsY; + if (!b) { + if (state==SRotateSelecting) { + iatlistener->rotateSelectionReady (rot_deg, thumbnail); + iatlistener->getToolBar()->setTool (TMHand); + } + else if (cropgl && (state==SCropSelecting || state==SResizeH1 || state==SResizeH2 || state==SResizeW1 || state==SResizeW2 || state==SCropMove)) { + cropgl->cropManipReady (); + cropgl = NULL; + iatlistener->cropSelectionReady (); + iatlistener->getToolBar()->setTool (TMHand); + } + state = SNormal; + if (parent) + parent->redrawNeeded (this); + updateCursor (ix, iy); + } + + return b; +} + +bool FileBrowserEntry::onArea (CursorArea a, int x, int y) { + + if (!drawable || !preview) + return false; + + int x1 = (x-prex) / scale; + int y1 = (y-prey) / scale; + int cropResizeBorder = CROPRESIZEBORDER / scale; + switch (a) { + case CropImage: + return x>=prex && x=prey && ycropParams.x+cropResizeBorder && + x1cropParams.y-cropResizeBorder && + y1cropParams.x+cropResizeBorder && + x1cropParams.y+cropParams.h-1-cropResizeBorder && + y1cropParams.y+cropResizeBorder && + y1cropParams.x-cropResizeBorder && + x1cropParams.y+cropResizeBorder && + y1cropParams.x+cropParams.w-1-cropResizeBorder && + x1cropParams.y && + y1cropParams.x && + x1getToolBar()->getTool (); + Glib::RefPtr w = parent->getDrawingArea ()->get_window(); + + if (!selected) { + cursorManager.setCursor (w, CSArrow); + return; + } + + if (state==SNormal) { + if (tm==TMHand && (onArea (CropTop, x, y) || onArea (CropBottom, x, y))) + cursorManager.setCursor (w, CSResizeHeight); + else if (tm==TMHand && (onArea (CropLeft, x, y) || onArea (CropRight, x, y))) + cursorManager.setCursor (w, CSResizeWidth); + else if (onArea (CropImage, x, y)) { + if (tm==TMHand) + cursorManager.setCursor (w, CSArrow); + else if (tm==TMSpotWB) + cursorManager.setCursor (w, CSSpotWB); + else if (tm==TMCropSelect) + cursorManager.setCursor (w, CSCropSelect); + else if (tm==TMStraighten) + cursorManager.setCursor (w, CSStraighten); + } + else + cursorManager.setCursor (w, CSArrow); + } + else if (state==SCropSelecting) + cursorManager.setCursor (w, CSCropSelect); + else if (state==SRotateSelecting) + cursorManager.setCursor (w, CSStraighten); + else if (state==SCropMove) + cursorManager.setCursor (w, CSMove); + else if (state==SResizeW1 || state==SResizeW2) + cursorManager.setCursor (w, CSResizeWidth); + else if (state==SResizeH1 || state==SResizeH2) + cursorManager.setCursor (w, CSResizeHeight); +} + +void FileBrowserEntry::draw () { + + ThumbBrowserEntryBase::draw (); + if (state==SRotateSelecting) { + Cairo::RefPtr cr = parent->getDrawingArea ()->get_window()->create_cairo_context(); + drawStraightenGuide (cr); + } +} + +void FileBrowserEntry::drawStraightenGuide (Cairo::RefPtr cr) { + + if (action_x!=press_x || action_y!=press_y) { + double arg = (press_x-action_x) / sqrt((press_x-action_x)*(press_x-action_x)+(press_y-action_y)*(press_y-action_y)); + double sol1, sol2; + double pi = M_PI; + if (press_y>action_y) { + sol1 = acos(arg)*180/pi; + sol2 = -acos(-arg)*180/pi; + } + else { + sol1 = acos(-arg)*180/pi; + sol2 = -acos(arg)*180/pi; + } + if (fabs(sol1)45) + rot_deg = - 90.0 + rot_deg; + } + else + rot_deg = 0; + + Glib::RefPtr context = parent->getDrawingArea()->get_pango_context () ; + Pango::FontDescription fontd = context->get_font_description (); + fontd.set_weight (Pango::WEIGHT_BOLD); + fontd.set_size (8*Pango::SCALE); + context->set_font_description (fontd); + Glib::RefPtr deglayout = parent->getDrawingArea()->create_pango_layout(Glib::ustring::compose ("%1 deg", Glib::ustring::format(std::setprecision(2), rot_deg))); + + int x1 = press_x; + int y1 = press_y; + int y2 = action_y; + int x2 = action_x; + + if (x2=prew+prex+ofsX+startx) { + y2 = y1 - (double)(y1-y2)*(x1 - (prew+prex+ofsX+startx-1)) / (x1-x2); + x2 = prew+prex+ofsX+startx-1; + } + if (y2=preh+prey+ofsY+starty) { + x2 = x1 - (double)(x1-x2)*(y1 - (preh+prey+ofsY+starty-1)) / (y1-y2); + y2 = preh+prey+ofsY+starty-1; + } + + cr->set_line_width (1.5); + cr->set_source_rgb (1.0, 1.0, 1.0); + cr->move_to (x1, y1); + cr->line_to (x2, y2); + cr->stroke (); + cr->set_source_rgb (0.0, 0.0, 0.0); + std::valarray ds (1); + ds[0] = 4; + cr->set_dash (ds, 0); + cr->move_to (x1, y1); + cr->line_to (x2, y2); + cr->stroke (); + + if (press_x!=action_x && press_y!=action_y) { + cr->set_source_rgb (0.0, 0.0, 0.0); + cr->move_to ((x1+x2)/2+1, (y1+y2)/2+1); + deglayout->add_to_cairo_context (cr); + cr->move_to ((x1+x2)/2+1, (y1+y2)/2-1); + deglayout->add_to_cairo_context (cr); + cr->move_to ((x1+x2)/2-1, (y1+y2)/2+1); + deglayout->add_to_cairo_context (cr); + cr->move_to ((x1+x2)/2+1, (y1+y2)/2+1); + deglayout->add_to_cairo_context (cr); + cr->fill (); + cr->set_source_rgb (1.0, 1.0, 1.0); + cr->move_to ((x1+x2)/2, (y1+y2)/2); + deglayout->add_to_cairo_context (cr); + cr->fill (); + } +} + diff --git a/rtgui/filebrowserentry.h b/rtgui/filebrowserentry.h new file mode 100755 index 000000000..6c503ed4f --- /dev/null +++ b/rtgui/filebrowserentry.h @@ -0,0 +1,95 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _FILEBROWSERENTRY_ +#define _FILEBROWSERENTRY_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +class FileBrowserEntry; +struct FileBrowserEntryIdleHelper { + FileBrowserEntry* fbentry; + bool destroyed; + int pending; +}; + +class FileThumbnailButtonSet; +class FileBrowserEntry : public ThumbBrowserEntryBase, + public ThumbnailListener, + public ThumbImageUpdateListener { + + double scale; + static bool iconsLoaded; + ImageAreaToolListener* iatlistener; + int press_x, press_y, action_x, action_y; + double rot_deg; + rtengine::procparams::CropParams cropParams; + CropGUIListener* cropgl; + FileBrowserEntryIdleHelper* feih; + + ImgEditState state; + + bool onArea (CursorArea a, int x, int y); + void updateCursor (int x, int y); + void drawStraightenGuide (Cairo::RefPtr c); + void customBackBufferUpdate (Cairo::RefPtr c); + +public: + + static Glib::RefPtr editedIcon; + static Glib::RefPtr recentlySavedIcon; + static Glib::RefPtr enqueuedIcon; + + Thumbnail* thumbnail; + + FileBrowserEntry (Thumbnail* thm, const Glib::ustring& fname); + ~FileBrowserEntry (); + void draw (); + + void setImageAreaToolListener (ImageAreaToolListener* l) { iatlistener = l; } + + FileThumbnailButtonSet* getThumbButtonSet (); + + void refreshThumbnailImage (); + void calcThumbnailSize (); + + std::vector > getIconsOnImageArea (); + void getIconSize (int& w, int& h); + + // thumbnaillistener interface + void procParamsChanged (Thumbnail* thm, int whoChangedIt); + // thumbimageupdatelistener interface + void updateImage (rtengine::IImage8* img, double scale, rtengine::procparams::CropParams cropParams); + void _updateImage (rtengine::IImage8* img, double scale, rtengine::procparams::CropParams cropParams); // inside gtk thread + + bool motionNotify (int x, int y); + bool pressNotify (int button, int type, int bstate, int x, int y); + bool releaseNotify (int button, int type, int bstate, int x, int y); +}; + +#endif diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc new file mode 100755 index 000000000..52369a7f7 --- /dev/null +++ b/rtgui/filecatalog.cc @@ -0,0 +1,799 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include +#include +#include +#include +#include +#include + +#define CHECKTIME 2000 + +extern Glib::ustring argv0; + +#ifdef _WIN32 +int _directoryUpdater (void* cat) { + + ((FileCatalog*)cat)->checkCounter++; + if (((FileCatalog*)cat)->checkCounter==2) { + gdk_threads_enter (); + ((FileCatalog*)cat)->reparseDirectory (); + gdk_threads_leave (); + } + return 1; +} +#endif + +FileCatalog::FileCatalog (CoarsePanel* cp, ToolBar* tb) : listener(NULL), fslistener(NULL), hasValidCurrentEFS(false), coarsePanel(cp), filterPanel(NULL), toolBar(tb) { + + previewLoader.setPreviewLoaderListener (this); + + // construct and initialize thumbnail browsers + fileBrowser = new FileBrowser(); + fileBrowser->setFileBrowserListener (this); + fileBrowser->setArrangement (ThumbBrowserBase::TB_Vertical); + fileBrowser->show (); + + // construct trash panel with the extra "empty trash" button + trashButtonBox = new Gtk::VBox; + Gtk::Button* emptyT = new Gtk::Button (M("FILEBROWSER_EMPTYTRASH")); + emptyT->set_tooltip_text (M("FILEBROWSER_EMPTYTRASHHINT")); + emptyT->set_image (*(new Gtk::Image (Gtk::StockID("gtk-delete"), Gtk::ICON_SIZE_BUTTON))); + emptyT->signal_pressed().connect (sigc::mem_fun(*this, &FileCatalog::emptyTrash)); + trashButtonBox->pack_start (*emptyT, Gtk::PACK_SHRINK, 4); + emptyT->show (); + trashButtonBox->show (); + + // setup button bar + buttonBar = new Gtk::HBox (); + pack_start (*buttonBar, Gtk::PACK_SHRINK); + + buttonBar->pack_start (*(new Gtk::VSeparator), Gtk::PACK_SHRINK); + bDir = new Gtk::ToggleButton (); + bDir->set_active (true); + bDir->set_image (*(new Gtk::Image (argv0+"/images/folder.png"))); + bDir->set_relief (Gtk::RELIEF_NONE); + bDir->set_tooltip_text (M("FILEBROWSER_SHOWDIRHINT")); + bCateg[0] = bDir->signal_toggled().connect (sigc::bind(sigc::mem_fun(*this, &FileCatalog::categoryButtonToggled), bDir)); + buttonBar->pack_start (*bDir, Gtk::PACK_SHRINK); + buttonBar->pack_start (*(new Gtk::VSeparator), Gtk::PACK_SHRINK); + + bUnRanked = new Gtk::ToggleButton (); + bUnRanked->set_active (false); + bUnRanked->set_image (*(new Gtk::Image (argv0+"/images/unrated.png"))); + bUnRanked->set_relief (Gtk::RELIEF_NONE); + bUnRanked->set_tooltip_text (M("FILEBROWSER_SHOWUNRANKHINT")); + bCateg[1] = bUnRanked->signal_toggled().connect (sigc::bind(sigc::mem_fun(*this, &FileCatalog::categoryButtonToggled), bUnRanked)); + buttonBar->pack_start (*bUnRanked, Gtk::PACK_SHRINK); + buttonBar->pack_start (*(new Gtk::VSeparator), Gtk::PACK_SHRINK); + + for (int i=0; i<5; i++) { + iranked[i] = new Gtk::Image (argv0+"/images/rated.png"); + igranked[i] = new Gtk::Image (argv0+"/images/grayrated.png"); + iranked[i]->show (); + igranked[i]->show (); + bRank[i] = new Gtk::ToggleButton (); + bRank[i]->set_image (*igranked[i]); + bRank[i]->set_relief (Gtk::RELIEF_NONE); + buttonBar->pack_start (*bRank[i], Gtk::PACK_SHRINK); + bCateg[i+2] = bRank[i]->signal_toggled().connect (sigc::bind(sigc::mem_fun(*this, &FileCatalog::categoryButtonToggled), bRank[i])); + } + bRank[0]->set_tooltip_text (M("FILEBROWSER_SHOWRANK1HINT")); + bRank[1]->set_tooltip_text (M("FILEBROWSER_SHOWRANK2HINT")); + bRank[2]->set_tooltip_text (M("FILEBROWSER_SHOWRANK3HINT")); + bRank[3]->set_tooltip_text (M("FILEBROWSER_SHOWRANK4HINT")); + bRank[4]->set_tooltip_text (M("FILEBROWSER_SHOWRANK5HINT")); + buttonBar->pack_start (*(new Gtk::VSeparator), Gtk::PACK_SHRINK); + + bTrash = new Gtk::ToggleButton (); + bTrash->set_image (*(new Gtk::Image (Gtk::StockID("gtk-delete"), Gtk::ICON_SIZE_SMALL_TOOLBAR))); + bTrash->set_relief (Gtk::RELIEF_NONE); + bTrash->set_tooltip_text (M("FILEBROWSER_SHOWTRASHHINT")); + bCateg[7] = bTrash->signal_toggled().connect (sigc::bind(sigc::mem_fun(*this, &FileCatalog::categoryButtonToggled), bTrash)); + buttonBar->pack_start (*bTrash, Gtk::PACK_SHRINK); + buttonBar->pack_start (*(new Gtk::VSeparator), Gtk::PACK_SHRINK); + + categoryButtons[0] = bDir; + categoryButtons[1] = bUnRanked; + for (int i=0; i<5; i++) + categoryButtons[i+2] = bRank[i]; + categoryButtons[7] = bTrash; + + // thumbnail zoom + Gtk::HBox* zoomBox = new Gtk::HBox (); + zoomInButton = new Gtk::Button (); + zoomInButton->set_image (*(new Gtk::Image (Gtk::StockID("gtk-zoom-in"), Gtk::ICON_SIZE_SMALL_TOOLBAR))); + zoomInButton->signal_pressed().connect (sigc::mem_fun(*this, &FileCatalog::zoomIn)); + zoomInButton->set_relief (Gtk::RELIEF_NONE); + zoomInButton->set_tooltip_text (M("FILEBROWSER_ZOOMINHINT")); + zoomBox->pack_end (*zoomInButton, Gtk::PACK_SHRINK); + zoomOutButton = new Gtk::Button (); + zoomOutButton->set_image (*(new Gtk::Image (Gtk::StockID("gtk-zoom-out"), Gtk::ICON_SIZE_SMALL_TOOLBAR))); + zoomOutButton->signal_pressed().connect (sigc::mem_fun(*this, &FileCatalog::zoomOut)); + zoomOutButton->set_relief (Gtk::RELIEF_NONE); + zoomOutButton->set_tooltip_text (M("FILEBROWSER_ZOOMOUTHINT")); + zoomBox->pack_end (*zoomOutButton, Gtk::PACK_SHRINK); + + // add default panel + hBox = new Gtk::HBox (); + hBox->show (); + hBox->pack_end (*fileBrowser); + fileBrowser->applyFilter (getFilter()); + pack_start (*hBox); + + buttonBar2 = new Gtk::HBox (); + pack_end (*buttonBar2, Gtk::PACK_SHRINK); + progressBar = new Gtk::ProgressBar (); + buttonBar2->pack_start (*progressBar, Gtk::PACK_SHRINK, 4); + progressBar->set_size_request (-1, 16); + + buttonBar->pack_start (*zoomBox, Gtk::PACK_SHRINK); + + buttonBar->pack_end (*coarsePanel, Gtk::PACK_SHRINK); + buttonBar->pack_end (*Gtk::manage(new Gtk::VSeparator), Gtk::PACK_SHRINK, 4); + buttonBar->pack_end (*toolBar, Gtk::PACK_SHRINK); + buttonBar->pack_end (*Gtk::manage(new Gtk::VSeparator), Gtk::PACK_SHRINK, 4); + + enabled = true; + + lastScrollPos = 0; + for (int i=0; i<8; i++) { + hScrollPos[i] = 0; + vScrollPos[i] = 0; + } + + selectedDirectory = ""; +#ifdef _WIN32 + wdMonitor = NULL; + checkCounter = 2; + g_timeout_add (CHECKTIME, _directoryUpdater, this); +#endif +} + +void FileCatalog::on_realize() { + + Gtk::VBox::on_realize(); + Pango::FontDescription fontd = get_pango_context()->get_font_description (); + fileBrowser->get_pango_context()->set_font_description (fontd); +// batchQueue->get_pango_context()->set_font_description (fontd); +} + +void FileCatalog::closeDir () { + + if (filterPanel) + filterPanel->set_sensitive (false); + +#ifndef _WIN32 + if (dirMonitor) + dirMonitor->cancel (); +#else + if (wdMonitor) { + delete wdMonitor; + wdMonitor = NULL; + } +#endif + // terminate thumbnail preview loading + previewLoader.terminate (); + + // terminate thumbnail updater + thumbImageUpdater.terminate (); + + // remove entries + fileBrowser->close (); + fileNameList.clear (); + + dirEFS.clear (); + hasValidCurrentEFS = false; + selectedDirectory = ""; + redrawAll (); +} + +std::vector FileCatalog::getFileList () { + + std::vector names; + + try { + Glib::RefPtr dir = Gio::File::create_for_path (selectedDirectory); + if (!dir) + return names; + +// FILE enumerator api leaks memory. Fixed in glibmm 2.18.1. Waiting for new release... + Glib::RefPtr dirList = dir->enumerate_children (); + if (!dirList) + return names; + for (Glib::RefPtr info = dirList->next_file(); info; info = dirList->next_file()) + names.push_back (Glib::build_filename (selectedDirectory, info->get_name())); + } + catch (Glib::Exception& ex) { + std::cout << ex.what(); + } + return names; +} + +void FileCatalog::dirSelected (const Glib::ustring& dirname, const Glib::ustring& openfile) { + + try { + Glib::RefPtr dir = Gio::File::create_for_path (dirname); + + if (!dir) + return; + closeDir (); + previewsToLoad = 0; + previewsLoaded = 0; + // if openfile exists, we have to open it first (it is a command line argument) + if (openfile!="") + addAndOpenFile (openfile); + + selectedDirectory = dir->get_parse_name(); + fileNameList = getFileList (); + + for (int i=0; i f = Gio::File::create_for_path(fileNameList[i]); + if (f->get_parse_name() != openfile) // if we opened a file at the beginning dont add it again + checkAndAddFile (f); + } + + _refreshProgressBar (); + previewLoader.process (); + +#ifndef _WIN32 + dirMonitor = dir->monitor_directory (); + dirMonitor->signal_changed().connect (sigc::bind(sigc::mem_fun(*this, &FileCatalog::on_dir_changed), false)); +#else + wdMonitor = new WinDirMonitor (selectedDirectory, this); +#endif + } + catch (Glib::Exception& ex) { + std::cout << ex.what(); + } +} + +void FileCatalog::_refreshProgressBar () { + + // check if progress bar is visible +/* Glib::ListHandle list = buttonBar2->get_children (); + Glib::ListHandle::iterator i = list.begin (); + for (; i!=list.end() && *i!=progressBar; i++); + if (i==list.end()) { + buttonBar2->pack_start (*progressBar, Gtk::PACK_SHRINK, 4); + buttonBar2->reorder_child (*progressBar, 2); + } +*/ + progressBar->show (); + if (previewsToLoad>0) + progressBar->set_fraction ((double)previewsLoaded / previewsToLoad); + else + progressBar->set_fraction (1.0); +} + +int refreshpb (void* data) { + + gdk_threads_enter (); + ((FileCatalog*)data)->_refreshProgressBar (); + gdk_threads_leave (); + return 0; +} + +void FileCatalog::previewReady (FileBrowserEntry* fdn) { + + // put it into the "full directory" browser + fdn->setImageAreaToolListener (iatlistener); + fileBrowser->addEntry (fdn); + + // update exif filter settings (minimal & maximal values of exif tags, cameras, lenses, etc...) + const CacheImageData* cfs = fdn->thumbnail->getCacheImageData(); + if (cfs->exifValid) { + if (cfs->fnumber < dirEFS.fnumberFrom) + dirEFS.fnumberFrom = cfs->fnumber; + if (cfs->fnumber > dirEFS.fnumberTo) + dirEFS.fnumberTo = cfs->fnumber; + if (cfs->shutter < dirEFS.shutterFrom) + dirEFS.shutterFrom = cfs->shutter; + if (cfs->shutter > dirEFS.shutterTo) + dirEFS.shutterTo = cfs->shutter; + if (cfs->iso>0 && cfs->iso < dirEFS.isoFrom) + dirEFS.isoFrom = cfs->iso; + if (cfs->iso>0 && cfs->iso > dirEFS.isoTo) + dirEFS.isoTo = cfs->iso; + if (cfs->focalLen < dirEFS.focalFrom) + dirEFS.focalFrom = cfs->focalLen; + if (cfs->focalLen > dirEFS.focalTo) + dirEFS.focalTo = cfs->focalLen; + } + dirEFS.cameras.insert (cfs->camera); + dirEFS.lenses.insert (cfs->lens); + previewsLoaded++; + g_idle_add (refreshpb, this); +} + +int prevfinished (void* data) { + + gdk_threads_enter(); + ((FileCatalog*)data)->_previewsFinished (); + gdk_threads_leave(); + return 0; +} + +void FileCatalog::_previewsFinished () { + + redrawAll (); + previewsToLoad = 0; + previewsLoaded = 0; +// removeIfThere (buttonBar2, progressBar); + progressBar->hide (); + if (filterPanel) { + filterPanel->set_sensitive (true); + filterPanel->setFilter (currentEFS); + } +} + +void FileCatalog::previewsFinished () { + + if (!hasValidCurrentEFS) + currentEFS = dirEFS; + g_idle_add (prevfinished, this); +} + +void PreviewLoader::remove (Glib::ustring fname) { + std::list::iterator i; + for (i=jqueue.begin(); i!=jqueue.end(); i++) + if (i->fullName==fname) + break; + if (i!=jqueue.end()) + jqueue.erase (i); +} + +void PreviewLoader::start () { + + jqueue.sort (); +} + +void PreviewLoader::process (DirEntry& current) { + + if (Glib::file_test (current.fullName, Glib::FILE_TEST_EXISTS)) { + Thumbnail* tmb = cacheMgr.getEntry (current.fullName); + if (tmb && pl) + pl->previewReady (new FileBrowserEntry (tmb, current.fullName)); + } +} + +void PreviewLoader::end () { + + if (pl) + pl->previewsFinished (); +} + +void FileCatalog::setEnabled (bool e) { + + enabled = e; +} + +void FileCatalog::redrawAll () { + + fileBrowser->queue_draw (); +} + +void FileCatalog::refreshAll () { + + fileBrowser->refreshThumbImages (); +} + +void FileCatalog::_openImage (std::vector tmb) { + + if (enabled && listener!=NULL) { + previewLoader.stop (); + thumbImageUpdater.stop (); + for (int i=0; igetFileName())==editedFiles.end()) + listener->fileSelected (tmb[i]); + tmb[i]->decreaseRef (); + } + previewLoader.process (); + thumbImageUpdater.process (); + } +} + +struct FCOIParams { + FileCatalog* catalog; + std::vector tmb; +}; + +int fcopenimg (void* p) { + + gdk_threads_enter (); + FCOIParams* params = (FCOIParams*)p; + params->catalog->_openImage (params->tmb); + delete params; + gdk_threads_leave (); + return 0; +} + +void FileCatalog::openRequested (std::vector tmb) { + + FCOIParams* params = new FCOIParams; + params->catalog = this; + params->tmb = tmb; + for (int i=0; iincreaseRef (); + g_idle_add (fcopenimg, params); +} + +void FileCatalog::deleteRequested (std::vector tbe) { + + if (tbe.size()==0) + return; + + Gtk::MessageDialog msd (M("FILEBROWSER_DELETEDLGLABEL"), false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO, true); + msd.set_secondary_text(Glib::ustring::compose (M("FILEBROWSER_DELETEDLGMSG"), tbe.size())); + + if (msd.run()==Gtk::RESPONSE_YES) { + for (int i=0; ifilename; + // remove from browser + FileBrowserEntry* t = fileBrowser->delEntry (fname); +// t->thumbnail->decreaseRef (); + delete t; + // remove from cache + cacheMgr.deleteEntry (fname); + // delete from file system + ::g_remove (fname.c_str()); + // delete .pp2 if found + ::g_remove (Glib::ustring(fname+".pp2").c_str()); + ::g_remove (Glib::ustring(removeExtension(fname)+".pp2").c_str()); + // delete .thm file + ::g_remove (Glib::ustring(removeExtension(fname)+".thm").c_str()); + ::g_remove (Glib::ustring(removeExtension(fname)+".THM").c_str()); + } + redrawAll (); + } +} + +void FileCatalog::developRequested (std::vector tbe) { + + if (listener) { + thumbImageUpdater.stop (); + for (int i=0; ithumbnail->getProcParams(); + rtengine::ProcessingJob* pjob = rtengine::ProcessingJob::create (tbe[i]->filename, tbe[i]->thumbnail->getType()==FT_Raw, params); + double tmpscale; + rtengine::IImage8* img = tbe[i]->thumbnail->processThumbImage (params, options.maxThumbnailHeight, tmpscale); + if (img) { + int pw = img->getWidth (); + int ph = img->getHeight (); + guint8* prev = new guint8 [pw*ph*3]; + memcpy (prev, img->getData (), pw*ph*3); + listener->addBatchQueueJob (new BatchQueueEntry (pjob, params, tbe[i]->filename, prev, pw, ph, tbe[i]->thumbnail)); + } + else { + int pw, ph; + tbe[i]->thumbnail->getThumbnailSize (pw, ph); + listener->addBatchQueueJob (new BatchQueueEntry (pjob, params, tbe[i]->filename, NULL, pw, ph, tbe[i]->thumbnail)); + } + } + thumbImageUpdater.process (); + } +} + +void FileCatalog::renameRequested (std::vector tbe) { + + RenameDialog* renameDlg = new RenameDialog ((Gtk::Window*)get_toplevel()); + + for (int i=0; iinitName (Glib::path_get_basename (tbe[i]->filename), tbe[i]->thumbnail->getCacheImageData()); + + Glib::ustring ofname = tbe[i]->filename; + Glib::ustring dirName = Glib::path_get_dirname (tbe[i]->filename); + Glib::ustring baseName = Glib::path_get_basename (tbe[i]->filename); + + if (renameDlg->run ()== Gtk::RESPONSE_OK) { + Glib::ustring nBaseName = renameDlg->getNewName (); + // if path has directory components, exit + if (Glib::path_get_dirname (nBaseName) != ".") + continue; + // if no extension is given, concatenate the extension of the original file + Glib::ustring ext = getExtension (nBaseName); + if (ext=="") + nBaseName += "." + getExtension (baseName); + Glib::ustring nfname = Glib::build_filename (dirName, nBaseName); + if (!::g_rename (ofname.c_str(), nfname.c_str())) { + cacheMgr.renameEntry (ofname, tbe[i]->thumbnail->getMD5(), nfname); + reparseDirectory (); + } + renameDlg->hide (); + } + } + delete renameDlg; +/* // ask for new file name + Gtk::Dialog dialog (M("FILEBROWSER_RENAMEDLGLABEL"), *((Gtk::Window*)get_toplevel()), true, true); + + dialog.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK); + dialog.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + + Gtk::Label l; + dialog.get_vbox()->pack_start (l, Gtk::PACK_SHRINK); + + Gtk::Entry nfentry; + + dialog.get_vbox()->pack_start (nfentry, Gtk::PACK_SHRINK); + dialog.get_vbox()->show_all (); + + nfentry.set_activates_default (true); + dialog.set_default_response (Gtk::RESPONSE_OK); + + for (int i=0; ifilename; + Glib::ustring dirName = Glib::path_get_dirname (tbe[i]->filename); + Glib::ustring baseName = Glib::path_get_basename (tbe[i]->filename); + + l.set_markup (Glib::ustring("") + Glib::ustring::compose (M("FILEBROWSER_RENAMEDLGMSG"), baseName) + Glib::ustring("")); + nfentry.set_text (baseName); + nfentry.select_region (0, baseName.size()); + + if (dialog.run ()== Gtk::RESPONSE_OK) { + Glib::ustring nBaseName = nfentry.get_text (); + // if path has directory components, exit + if (Glib::path_get_dirname (nBaseName) != ".") + continue; + // if no extension is given, concatenate the extension of the original file + if (nBaseName.find ('.')==nBaseName.npos) { + int lastdot = baseName.find_last_of ('.'); + nBaseName += "." + (lastdot!=Glib::ustring::npos ? baseName.substr (lastdot+1) : ""); + } + Glib::ustring nfname = Glib::build_filename (dirName, nBaseName); + if (!::g_rename (ofname.c_str(), nfname.c_str())) { + cacheMgr.renameEntry (ofname, tbe[i]->thumbnail->getMD5(), nfname); + // the remaining part (removing old and adding new entry) is done by the directory monitor + reparseDirectory (); +// on_dir_changed (Gio::File::create_for_path (nfname), Gio::File::create_for_path (nfname), Gio::FILE_MONITOR_EVENT_CHANGED, true); + } + } + } + */ +} + +void FileCatalog::categoryButtonToggled (Gtk::ToggleButton* b) { + + for (int i=0; i<8; i++) + bCateg[i].block (true); + + fileBrowser->getScrollPosition (hScrollPos[lastScrollPos], vScrollPos[lastScrollPos]); + + // seek the one pressed + for (int i=0; i<8; i++) { + categoryButtons[i]->set_active (categoryButtons[i]==b); + if (categoryButtons[i]==b) + lastScrollPos = i; + } + + // change the images of the buttons to reflect current ranking + for (int i=0; i<5; i++) + bRank[i]->set_image (*igranked[i]); + for (int i=0; i<5; i++) + if (b==bRank[i]) + for (int j=0; j<=i; j++) + bRank[j]->set_image (*iranked[j]); + + fileBrowser->applyFilter (getFilter ()); + + // rearrange panels according to the selected filter + removeIfThere (hBox, trashButtonBox); + if (bTrash->get_active ()) + hBox->pack_start (*trashButtonBox, Gtk::PACK_SHRINK, 4); + hBox->queue_draw (); + + fileBrowser->setScrollPosition (hScrollPos[lastScrollPos], vScrollPos[lastScrollPos]); + + for (int i=0; i<8; i++) + bCateg[i].block (false); +} + +BrowserFilter FileCatalog::getFilter () { + + BrowserFilter filter; + filter.showRanked[0] = bDir->get_active() || bUnRanked->get_active () || bTrash->get_active (); + for (int i=1; i<=5; i++) + filter.showRanked[i] = bDir->get_active() || bRank[i-1]->get_active () || bTrash->get_active (); + filter.showTrash = bDir->get_active() || bTrash->get_active (); + filter.showNotTrash = !bTrash->get_active (); + if (!filterPanel) + filter.exifFilterEnabled = false; + else { + if (!hasValidCurrentEFS) + filter.exifFilter = dirEFS; + else + filter.exifFilter = currentEFS; + filter.exifFilterEnabled = filterPanel->isEnabled (); + } + return filter; +} + +void FileCatalog::filterChanged () { + + fileBrowser->applyFilter (getFilter()); +} + +int FileCatalog::reparseDirectory () { + + if (selectedDirectory=="") + return 0; + + if (!Glib::file_test (selectedDirectory, Glib::FILE_TEST_IS_DIR)) { + closeDir (); + return 0; + } + + std::vector nfileNameList = getFileList (); + + // check if a thumbnailed file has been deleted + const std::vector& t = fileBrowser->getEntries (); + std::vector fileNamesToDel; + for (int i=0; ifilename, Glib::FILE_TEST_EXISTS)) + fileNamesToDel.push_back (t[i]->filename); + for (int i=0; idelEntry (fileNamesToDel[i]); + cacheMgr.deleteEntry (fileNamesToDel[i]); + } + + // check if a new file has been added + for (int i=0; i& file, const Glib::RefPtr& other_file, Gio::FileMonitorEvent event_type, bool internal) { + + if (!internal) + gdk_threads_enter(); + + if (event_type == Gio::FILE_MONITOR_EVENT_CREATED || event_type == Gio::FILE_MONITOR_EVENT_DELETED || event_type == Gio::FILE_MONITOR_EVENT_CHANGED) + reparseDirectory (); + + if (!internal) + gdk_threads_leave(); +} + +void FileCatalog::checkAndAddFile (Glib::RefPtr file) { + + if (!file) + return; + Glib::RefPtr info = file->query_info(); + if (info && info->get_file_type() != Gio::FILE_TYPE_DIRECTORY && (!info->is_hidden() || !options.fbShowHidden)) { + int lastdot = info->get_name().find_last_of ('.'); + Glib::ustring ext = lastdot!=Glib::ustring::npos ? info->get_name().substr (lastdot+1) : ""; + // look up if it is supported + for (int j=0; jget_parse_name())); + previewsToLoad++; + break; + } + } +} + +void FileCatalog::addAndOpenFile (const Glib::ustring& fname) { + + Glib::RefPtr file = Gio::File::create_for_path (fname); + if (!file) + return; + Glib::RefPtr info = file->query_info(); + int lastdot = info->get_name().find_last_of ('.'); + Glib::ustring ext = lastdot!=Glib::ustring::npos ? info->get_name().substr (lastdot+1) : ""; + // look up if it is supported + for (int j=0; jget_parse_name()); + if (tmb) { + FileBrowserEntry* entry = new FileBrowserEntry (tmb, file->get_parse_name()); + previewReady (entry); + // open the file + FCOIParams* params = new FCOIParams; + params->catalog = this; + params->tmb.push_back (tmb); + tmb->increaseRef (); + g_idle_add (fcopenimg, params); + } + break; + } +} + +void FileCatalog::emptyTrash () { + + const std::vector t = fileBrowser->getEntries (); + std::vector toDel; + for (int i=0; ithumbnail->getStage()==1) + toDel.push_back (((FileBrowserEntry*)t[i])); + deleteRequested (toDel); +} + +void FileCatalog::zoomIn () { + + bool pLoad = previewLoader.runs(); + if (pLoad) + previewLoader.stop (); + + fileBrowser->zoomIn (); + + if (pLoad) + previewLoader.process (); +} +void FileCatalog::zoomOut () { + + bool pLoad = previewLoader.runs(); + if (pLoad) + previewLoader.stop (); + + fileBrowser->zoomOut (); + + if (pLoad) + previewLoader.process (); +} +void FileCatalog::refreshEditedState (const std::set& efiles) { + + editedFiles = efiles; + fileBrowser->refreshEditedState (efiles); +} + +void FileCatalog::selectionChanged (std::vector tbe) { + + if (fslistener) + fslistener->selectionChanged (tbe); +} + +void FileCatalog::exifFilterChanged () { + + currentEFS = filterPanel->getFilter (); + hasValidCurrentEFS = true; + fileBrowser->applyFilter (getFilter ()); +} + +void FileCatalog::setFilterPanel (FilterPanel* fpanel) { + + filterPanel = fpanel; + filterPanel->set_sensitive (false); + filterPanel->setFilterPanelListener (this); +} diff --git a/rtgui/filecatalog.h b/rtgui/filecatalog.h new file mode 100755 index 000000000..fde5489d2 --- /dev/null +++ b/rtgui/filecatalog.h @@ -0,0 +1,191 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _FILECATALOG_ +#define _FILECATALOG_ + +#ifdef _WIN32 +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class PreviewLoaderListener { + public: + virtual void previewReady (FileBrowserEntry* fd) {} + virtual void previewsFinished () {} +}; + +class DirEntry { + + public: + Glib::ustring fullName; + + DirEntry (const Glib::ustring& n) : fullName (n) {} + + bool operator< (DirEntry& other) { + return fullName.casefold() < other.fullName.casefold(); + } +}; + +class PreviewLoader : public ProcessingThread { + + protected: + PreviewLoaderListener* pl; + + public: + PreviewLoader () : pl(NULL) { ProcessingThread(); } + void setPreviewLoaderListener (PreviewLoaderListener* p) { pl = p; } + void start (); + void process () { ProcessingThread::process (); } + void process (DirEntry& current); + void remove (Glib::ustring fname); + void end (); +}; + +class FileCatalog : public Gtk::VBox, + public DirSelectionListener, + public PreviewLoaderListener, + public FilterPanelListener, + public FileBrowserListener +#ifdef _WIN32 + , public WinDirChangeListener +#endif + { + + // thumbnail browsers + FileBrowser* fileBrowser; + + Gtk::HBox* hBox; + Glib::ustring selectedDirectory; + bool enabled; + + PreviewLoader previewLoader; + FileSelectionListener* listener; + FileSelectionChangeListener* fslistener; + ImageAreaToolListener* iatlistener; + + Gtk::HBox* buttonBar; + Gtk::HBox* buttonBar2; + Gtk::ToggleButton* bDir; + Gtk::ToggleButton* bUnRanked; + Gtk::ToggleButton* bRank[5]; + Gtk::ToggleButton* bTrash; + Gtk::ToggleButton* categoryButtons[8]; + sigc::connection bCateg[8]; + Gtk::Image* iranked[5], *igranked[5]; + + double hScrollPos[8]; + double vScrollPos[8]; + int lastScrollPos; + + Gtk::VBox* trashButtonBox; + + Gtk::Button* zoomInButton; + Gtk::Button* zoomOutButton; + + ExifFilterSettings dirEFS; + ExifFilterSettings currentEFS; + bool hasValidCurrentEFS; + + FilterPanel* filterPanel; + + Glib::RefPtr dirMonitor; + + Gtk::ProgressBar* progressBar; + int previewsToLoad; + int previewsLoaded; + + +#ifdef _WIN32 + WinDirMonitor* wdMonitor; + public: + int checkCounter; + void winDirChanged (); + private: +#endif + std::vector fileNameList; + std::set editedFiles; + + void addAndOpenFile (const Glib::ustring& fname); + void checkAndAddFile (Glib::RefPtr info); + std::vector getFileList (); + BrowserFilter getFilter (); + + public: + CoarsePanel* coarsePanel; + ToolBar* toolBar; + + FileCatalog (CoarsePanel* cp, ToolBar* tb); + void dirSelected (const Glib::ustring& dirname, const Glib::ustring& openfile=""); + void closeDir (); + void refreshEditedState (const std::set& efiles); + + // previewloaderlistener interface + void previewReady (FileBrowserEntry* fdn); + void previewsFinished (); + void _previewsFinished (); + void _refreshProgressBar (); + + // filterpanel interface + void exifFilterChanged (); + + Glib::ustring lastSelectedDir () { return selectedDirectory; } + void setEnabled (bool e); // if not enabled, it does not open image + + void redrawAll (); + void refreshAll (); + + void openRequested (std::vector tbe); + void deleteRequested (std::vector tbe); + void developRequested (std::vector tbe); + void renameRequested (std::vector tbe); + void selectionChanged (std::vector tbe); + void emptyTrash (); + + void setFileSelectionListener (FileSelectionListener* l) { listener = l; } + void setFileSelectionChangeListener (FileSelectionChangeListener* l) { fslistener = l; } + void setImageAreaToolListener (ImageAreaToolListener* l) { iatlistener = l; } + void setFilterPanel (FilterPanel* fpanel); + + void categoryButtonToggled (Gtk::ToggleButton* b); + void filterChanged (); + void runFilterDialog (); + + void on_realize(); + void on_dir_changed (const Glib::RefPtr& file, const Glib::RefPtr& other_file, Gio::FileMonitorEvent event_type, bool internal); + int reparseDirectory (); + void _openImage (std::vector tmb); + + void zoomIn (); + void zoomOut (); + + void openNextImage () { fileBrowser->openNextImage(); } + void openPrevImage () { fileBrowser->openPrevImage(); } +}; + +#endif diff --git a/rtgui/filepanel.cc b/rtgui/filepanel.cc new file mode 100755 index 000000000..d7c7aba2d --- /dev/null +++ b/rtgui/filepanel.cc @@ -0,0 +1,186 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +int fbinit (void* data) { + + gdk_threads_enter (); + ((FilePanel*)data)->init (); + gdk_threads_leave (); + + return 0; +} + +FilePanel::FilePanel () : parent(NULL) { + + dirpaned = new Gtk::HPaned (); + dirpaned->set_position (options.dirBrowserWidth); + + dirBrowser = new DirBrowser (); + placesBrowser = new PlacesBrowser (); + recentBrowser = new RecentBrowser (); + + placespaned = new Gtk::VPaned (); + placespaned->set_position (options.dirBrowserHeight); + + Gtk::VBox* obox = Gtk::manage (new Gtk::VBox ()); + obox->pack_start (*recentBrowser, Gtk::PACK_SHRINK, 4); + obox->pack_start (*dirBrowser); + + placespaned->pack1 (*placesBrowser, false, true); + placespaned->pack2 (*obox, true, true); + + dirpaned->pack1 (*placespaned, Gtk::SHRINK); + + tpc = new BatchToolPanelCoordinator (this); + fileCatalog = new FileCatalog (tpc->coarse, tpc->getToolBar()); + dirpaned->pack2 (*fileCatalog, Gtk::EXPAND|Gtk::SHRINK); + + placesBrowser->setDirBrowserRemoteInterface (dirBrowser); + recentBrowser->setDirBrowserRemoteInterface (dirBrowser); + dirBrowser->addDirSelectionListener (fileCatalog); + dirBrowser->addDirSelectionListener (recentBrowser); + dirBrowser->addDirSelectionListener (placesBrowser); + fileCatalog->setFileSelectionListener (this); + + rightBox = new Gtk::HBox (); + rightNotebook = new Gtk::Notebook (); + Gtk::VBox* taggingBox = new Gtk::VBox (); + + history = new History (false); + + tpc->addPParamsChangeListener (history); + history->setProfileChangeListener (tpc); + + Gtk::ScrolledWindow* sFilterPanel = new Gtk::ScrolledWindow(); + filterPanel = new FilterPanel (); + sFilterPanel->add (*filterPanel); + sFilterPanel->set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); + + fileCatalog->setFilterPanel (filterPanel); + fileCatalog->setImageAreaToolListener (tpc); + + //------------------ + + rightNotebook->set_tab_pos (Gtk::POS_LEFT); + + Gtk::Label* devLab = new Gtk::Label ("Develop"); + devLab->set_angle (90); + Gtk::Label* filtLab = new Gtk::Label ("Filter"); + filtLab->set_angle (90); + Gtk::Label* tagLab = new Gtk::Label ("Tagging"); + tagLab->set_angle (90); + + Gtk::VPaned* tpcPaned = new Gtk::VPaned (); + tpcPaned->pack1 (*tpc->toolPanelNotebook, true, true); + tpcPaned->pack2 (*history, true, true); + + rightNotebook->append_page (*tpcPaned, *devLab); + rightNotebook->append_page (*sFilterPanel, *filtLab); + rightNotebook->append_page (*taggingBox, *tagLab); + + rightBox->pack_start (*rightNotebook); + + pack1(*dirpaned, true, true); + pack2(*rightBox, false, true); + + fileCatalog->setFileSelectionChangeListener (tpc); + + fileCatalog->setFileSelectionListener (this); + g_idle_add (fbinit, this); + + show_all (); +} + +void FilePanel::on_realize () { + + Gtk::HPaned::on_realize (); + rightBox->set_size_request (options.browserToolPanelWidth, -1); +} + +void FilePanel::init () { + + dirBrowser->fillDirTree (); + placesBrowser->refreshPlacesList (); + + if (argv1!="") + dirBrowser->open (argv1); + else { + if (options.startupDir==STARTUPDIR_HOME) + dirBrowser->open (Glib::get_home_dir()); + else if (options.startupDir==STARTUPDIR_CURRENT) + dirBrowser->open (argv0); + else if (options.startupDir==STARTUPDIR_CUSTOM || options.startupDir==STARTUPDIR_LAST) + dirBrowser->open (options.startupPath); + } +} + +bool FilePanel::fileSelected (Thumbnail* thm) { + + if (!parent) + return false; + + // try to open the file + bool succ = false; + fileCatalog->setEnabled (false); + rtengine::InitialImage* isrc = EditorPanel::loadImage (thm); + if (isrc) { + EditorPanel* epanel = Gtk::manage (new EditorPanel (thm, isrc)); + parent->addEditorPanel (epanel); + succ = true; + } + else { + Glib::ustring msg_ = Glib::ustring("") + M("MAIN_MSG_CANNOTLOAD") + " \"" + thm->getFileName() + "\" .\n"; + Gtk::MessageDialog msgd (msg_, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + msgd.run (); + } + fileCatalog->setEnabled (true); + return succ; +} + +void FilePanel::saveOptions () { + + options.dirBrowserWidth = dirpaned->get_position (); + options.dirBrowserHeight = placespaned->get_position (); + options.browserToolPanelWidth = rightBox->get_width (); + if (options.startupDir==STARTUPDIR_LAST && fileCatalog->lastSelectedDir ()!="") + options.startupPath = fileCatalog->lastSelectedDir (); + fileCatalog->closeDir (); +} + +void FilePanel::open (const Glib::ustring& d) { + + if (Glib::file_test (d, Glib::FILE_TEST_IS_DIR)) + dirBrowser->open (d.c_str()); + else if (Glib::file_test (d, Glib::FILE_TEST_EXISTS)) + dirBrowser->open (Glib::path_get_dirname(d), Glib::path_get_basename(d)); +} + +bool FilePanel::addBatchQueueJob (BatchQueueEntry* bqe) { + + if (parent) + parent->addBatchQueueJob (bqe); +} + +void FilePanel::optionsChanged () { + + tpc->optionsChanged (); + fileCatalog->refreshAll (); +} diff --git a/rtgui/filepanel.h b/rtgui/filepanel.h new file mode 100755 index 000000000..383590368 --- /dev/null +++ b/rtgui/filepanel.h @@ -0,0 +1,74 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _FILEPANEL_ +#define _FILEPANEL_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class RTWindow; +class FilePanel : public Gtk::HPaned, + public FileSelectionListener, + public PParamsChangeListener +{ + + protected: + Gtk::VPaned* placespaned; + Gtk::HPaned* dirpaned; + DirBrowser* dirBrowser; + PlacesBrowser* placesBrowser; + RecentBrowser* recentBrowser; + FileCatalog* fileCatalog; // filecatalog is the file browser with the button bar above it + Gtk::HBox* rightBox; + BatchToolPanelCoordinator* tpc; + History* history; + FilterPanel* filterPanel; + RTWindow* parent; + Gtk::Notebook* rightNotebook; + + public: + FilePanel (); + + void on_realize (); + + void setParent (RTWindow* p) { parent = p; } + void init (); // dont call it directly, the constructor calls it as idle source + void open (const Glib::ustring& d); // open a file or a directory + void refreshEditedState (const std::set& efiles) { fileCatalog->refreshEditedState (efiles); } + + // call this before closeing rt: it saves file browser relating things into options + void saveOptions (); + + // interface fileselectionlistener + bool fileSelected (Thumbnail* thm); + bool addBatchQueueJob (BatchQueueEntry* bqe); + + void optionsChanged (); +}; + +#endif + diff --git a/rtgui/fileselectionchangelistener.h b/rtgui/fileselectionchangelistener.h new file mode 100755 index 000000000..d03d4215d --- /dev/null +++ b/rtgui/fileselectionchangelistener.h @@ -0,0 +1,31 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _FILESELECTIONCHANGELISTENER_ +#define _FILESELECTIONCHANGELISTENER_ + +#include + +class FileSelectionChangeListener { + + public: + virtual void selectionChanged (const std::vector& selected) {} +}; + +#endif + diff --git a/rtgui/fileselectionlistener.h b/rtgui/fileselectionlistener.h new file mode 100755 index 000000000..57930c16d --- /dev/null +++ b/rtgui/fileselectionlistener.h @@ -0,0 +1,33 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _FILESELECTIONLISTENER_ +#define _FILESELECTIONLISTENER_ + +#include +#include + +class FileSelectionListener { + + public: + virtual bool fileSelected (Thumbnail* thm) {} + virtual bool addBatchQueueJob (BatchQueueEntry* bqe) {} +}; + +#endif + diff --git a/rtgui/filethumbnailbuttonset.cc b/rtgui/filethumbnailbuttonset.cc new file mode 100755 index 000000000..9154bb476 --- /dev/null +++ b/rtgui/filethumbnailbuttonset.cc @@ -0,0 +1,68 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +extern Glib::ustring argv0; + +bool FileThumbnailButtonSet::iconsLoaded = false; + +Cairo::RefPtr FileThumbnailButtonSet::rankIcon; +Cairo::RefPtr FileThumbnailButtonSet::gRankIcon; +Cairo::RefPtr FileThumbnailButtonSet::unRankIcon; +Cairo::RefPtr FileThumbnailButtonSet::trashIcon; +Cairo::RefPtr FileThumbnailButtonSet::unTrashIcon; +Cairo::RefPtr FileThumbnailButtonSet::processIcon; + +FileThumbnailButtonSet::FileThumbnailButtonSet (FileBrowserEntry* myEntry) { + + if (!iconsLoaded) { + unRankIcon = Cairo::ImageSurface::create_from_png (argv0+"/images/unrated.png"); + rankIcon = Cairo::ImageSurface::create_from_png (argv0+"/images/rated.png"); + gRankIcon = Cairo::ImageSurface::create_from_png (argv0+"/images/grayrated.png"); + trashIcon = Cairo::ImageSurface::create_from_png (argv0+"/images/trash.png"); + unTrashIcon = Cairo::ImageSurface::create_from_png (argv0+"/images/undelete.png"); + processIcon = Cairo::ImageSurface::create_from_png (argv0+"/images/processing.png"); + iconsLoaded = true; + } + + add (new LWButton (unRankIcon, 0, myEntry, LWButton::Left, LWButton::Center, M("FILEBROWSER_POPUPUNRANK"))); + for (int i=0; i<5; i++) + add (new LWButton (rankIcon, i+1, myEntry, LWButton::Left)); + add (new LWButton (processIcon, 6, myEntry, LWButton::Right, LWButton::Center, M("FILEBROWSER_POPUPPROCESS"))); + add (new LWButton (trashIcon, 7, myEntry, LWButton::Right, LWButton::Center, M("FILEBROWSER_POPUPTRASH"))); + + buttons[1]->setToolTip (M("FILEBROWSER_POPUPRANK1")); + buttons[2]->setToolTip (M("FILEBROWSER_POPUPRANK2")); + buttons[3]->setToolTip (M("FILEBROWSER_POPUPRANK3")); + buttons[4]->setToolTip (M("FILEBROWSER_POPUPRANK4")); + buttons[5]->setToolTip (M("FILEBROWSER_POPUPRANK5")); +} + +void FileThumbnailButtonSet::setRank (int stars) { + + for (int i=1; i<=5; i++) + buttons[i]->setIcon (i<=stars ? rankIcon : gRankIcon); +} + +void FileThumbnailButtonSet::setInTrash (bool inTrash) { + + buttons[7]->setIcon (inTrash ? unTrashIcon : trashIcon); + buttons[7]->setToolTip (inTrash ? M("FILEBROWSER_POPUPUNTRASH") : M("FILEBROWSER_POPUPTRASH")); +} diff --git a/rtgui/filethumbnailbuttonset.h b/rtgui/filethumbnailbuttonset.h new file mode 100755 index 000000000..228e9e82f --- /dev/null +++ b/rtgui/filethumbnailbuttonset.h @@ -0,0 +1,45 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _FILETHUMBNAILBUTTONSET_ +#define _FILETHUMBNAILBUTTONSET_ + +#include +#include +#include + +class FileBrowserEntry; +class FileThumbnailButtonSet : public LWButtonSet { + + static bool iconsLoaded; + + public: + static Cairo::RefPtr rankIcon; + static Cairo::RefPtr gRankIcon; + static Cairo::RefPtr unRankIcon; + static Cairo::RefPtr trashIcon; + static Cairo::RefPtr unTrashIcon; + static Cairo::RefPtr processIcon; + + FileThumbnailButtonSet (FileBrowserEntry* myEntry); + void setRank (int stars); + void setInTrash (bool inTrash); + +}; + +#endif diff --git a/rtgui/filterpanel.cc b/rtgui/filterpanel.cc new file mode 100755 index 000000000..f8970942d --- /dev/null +++ b/rtgui/filterpanel.cc @@ -0,0 +1,210 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include + +using namespace rtengine; + +FilterPanel::FilterPanel () : listener (NULL) { + + set_border_width (4); + + enabled = Gtk::manage (new Gtk::CheckButton ("Enable Metadata Filters")); + pack_start (*enabled, Gtk::PACK_SHRINK, 2); + pack_start (*Gtk::manage(new Gtk::HSeparator ()), Gtk::PACK_SHRINK, 2); + + enaFNumber = Gtk::manage (new Gtk::CheckButton (M("EXIFFILTER_APERTURE")+":")); + Gtk::VBox* fnvb = Gtk::manage(new Gtk::VBox ()); + Gtk::HBox* fnhb = Gtk::manage(new Gtk::HBox ()); + fnvb->pack_start (*enaFNumber, Gtk::PACK_SHRINK, 0); + fnumberFrom = Gtk::manage(new Gtk::Entry ()); + fnumberTo = Gtk::manage(new Gtk::Entry ()); + fnhb->pack_start (*fnumberFrom, true, true, 2); + fnhb->pack_start (*Gtk::manage(new Gtk::Label(" - ")), false, false, 4); + fnhb->pack_start (*fnumberTo, true, true, 2); + fnvb->pack_start (*fnhb, Gtk::PACK_SHRINK, 0); + pack_start (*fnvb, Gtk::PACK_SHRINK, 4); + + enaShutter = Gtk::manage(new Gtk::CheckButton(M("EXIFFILTER_SHUTTER")+":")); + Gtk::VBox* svb = Gtk::manage(new Gtk::VBox ()); + Gtk::HBox* shb = Gtk::manage(new Gtk::HBox ()); + svb->pack_start (*enaShutter, Gtk::PACK_SHRINK, 0); + shutterFrom = Gtk::manage(new Gtk::Entry ()); + shutterTo = Gtk::manage(new Gtk::Entry ()); + shb->pack_start (*shutterFrom, true, true, 2); + shb->pack_start (*Gtk::manage(new Gtk::Label(" - ")), false, false, 4); + shb->pack_start (*shutterTo, true, true, 2); + svb->pack_start (*shb, Gtk::PACK_SHRINK, 0); + pack_start (*svb, Gtk::PACK_SHRINK, 4); + + enaISO = Gtk::manage(new Gtk::CheckButton(M("EXIFFILTER_ISO")+":")); + Gtk::VBox* ivb = Gtk::manage(new Gtk::VBox ()); + Gtk::HBox* ihb = Gtk::manage(new Gtk::HBox ()); + ivb->pack_start (*enaISO, Gtk::PACK_SHRINK, 0); + isoFrom = Gtk::manage(new Gtk::Entry ()); + isoTo = Gtk::manage(new Gtk::Entry ()); + ihb->pack_start (*isoFrom, true, true, 2); + ihb->pack_start (*Gtk::manage(new Gtk::Label(" - ")), false, false, 4); + ihb->pack_start (*isoTo, true, true, 2); + ivb->pack_start (*ihb, Gtk::PACK_SHRINK, 0); + pack_start (*ivb, Gtk::PACK_SHRINK, 4); + + enaFocalLen = Gtk::manage(new Gtk::CheckButton(M("EXIFFILTER_FOCALLEN")+":")); + Gtk::VBox* fvb = Gtk::manage(new Gtk::VBox ()); + Gtk::HBox* fhb = Gtk::manage(new Gtk::HBox ()); + fvb->pack_start (*enaFocalLen, Gtk::PACK_SHRINK, 0); + focalFrom = Gtk::manage(new Gtk::Entry ()); + focalTo = Gtk::manage(new Gtk::Entry ()); + fhb->pack_start (*focalFrom, true, true, 2); + fhb->pack_start (*Gtk::manage(new Gtk::Label(" - ")), false, false, 4); + fhb->pack_start (*focalTo, true, true, 2); + fvb->pack_start (*fhb, Gtk::PACK_SHRINK, 0); + pack_start (*fvb, Gtk::PACK_SHRINK, 4); + + enaCamera = Gtk::manage(new Gtk::CheckButton(M("EXIFFILTER_CAMERA")+":")); + Gtk::VBox* cvb = Gtk::manage(new Gtk::VBox ()); + cvb->pack_start (*enaCamera, Gtk::PACK_SHRINK, 0); + camera = Gtk::manage(new Gtk::ListViewText (1, false, Gtk::SELECTION_MULTIPLE)); + camera->set_headers_visible (false); + Gtk::ScrolledWindow* scamera = Gtk::manage(new Gtk::ScrolledWindow()); + scamera->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS); + scamera->add(*camera); + cvb->pack_start (*scamera, Gtk::PACK_SHRINK, 0); + pack_start (*cvb, Gtk::PACK_SHRINK, 4); + + enaLens = Gtk::manage(new Gtk::CheckButton(M("EXIFFILTER_LENS")+":")); + Gtk::VBox* lvb = Gtk::manage(new Gtk::VBox ()); + lvb->pack_start (*enaLens, Gtk::PACK_SHRINK, 0); + lens = Gtk::manage(new Gtk::ListViewText (1, false, Gtk::SELECTION_MULTIPLE)); + lens->set_headers_visible (false); + Gtk::ScrolledWindow* slens = Gtk::manage(new Gtk::ScrolledWindow()); + slens->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS); + slens->add(*lens); + lvb->pack_start (*slens, Gtk::PACK_SHRINK, 0); + pack_start (*lvb, Gtk::PACK_SHRINK, 4); + + conns = 0; + sChange[conns++] = fnumberFrom->signal_changed().connect (sigc::mem_fun(*this, &FilterPanel::valueChanged)); + sChange[conns++] = fnumberTo->signal_changed().connect (sigc::mem_fun(*this, &FilterPanel::valueChanged)); + sChange[conns++] = shutterFrom->signal_changed().connect (sigc::mem_fun(*this, &FilterPanel::valueChanged)); + sChange[conns++] = shutterTo->signal_changed().connect (sigc::mem_fun(*this, &FilterPanel::valueChanged)); + sChange[conns++] = isoFrom->signal_changed().connect (sigc::mem_fun(*this, &FilterPanel::valueChanged)); + sChange[conns++] = isoTo->signal_changed().connect (sigc::mem_fun(*this, &FilterPanel::valueChanged)); + sChange[conns++] = focalFrom->signal_changed().connect (sigc::mem_fun(*this, &FilterPanel::valueChanged)); + sChange[conns++] = focalTo->signal_changed().connect (sigc::mem_fun(*this, &FilterPanel::valueChanged)); + sChange[conns++] = camera->get_selection()->signal_changed().connect(sigc::mem_fun(*this, &FilterPanel::valueChanged)); + sChange[conns++] = lens->get_selection()->signal_changed().connect(sigc::mem_fun(*this, &FilterPanel::valueChanged)); + sChange[conns++] = enaFNumber->signal_toggled().connect( sigc::mem_fun(*this, &FilterPanel::valueChanged) ); + sChange[conns++] = enaShutter->signal_toggled().connect( sigc::mem_fun(*this, &FilterPanel::valueChanged) ); + sChange[conns++] = enaFocalLen->signal_toggled().connect( sigc::mem_fun(*this, &FilterPanel::valueChanged) ); + sChange[conns++] = enaISO->signal_toggled().connect( sigc::mem_fun(*this, &FilterPanel::valueChanged) ); + sChange[conns++] = enaCamera->signal_toggled().connect( sigc::mem_fun(*this, &FilterPanel::valueChanged) ); + sChange[conns++] = enaLens->signal_toggled().connect( sigc::mem_fun(*this, &FilterPanel::valueChanged) ); + sChange[conns++] = enabled->signal_toggled().connect( sigc::mem_fun(*this, &FilterPanel::valueChanged) ); + + set_size_request (0, -1); + + show_all (); +} + +void FilterPanel::setFilter (ExifFilterSettings& defefs) { + + curefs = defefs; + + for (int i=0; iset_active (curefs.filterFNumber); + fnumberFrom->set_text (ImageMetaData::apertureToString (curefs.fnumberFrom)); + fnumberTo->set_text (ImageMetaData::apertureToString (curefs.fnumberTo)); + +// enaShutter->set_active (curefs.filterShutter); + shutterFrom->set_text (ImageMetaData::shutterToString (curefs.shutterFrom)); + shutterTo->set_text (ImageMetaData::shutterToString (curefs.shutterTo)); + +// enaISO->set_active (curefs.filterISO); + isoFrom->set_text (Glib::ustring::format (curefs.isoFrom)); + isoTo->set_text (Glib::ustring::format (curefs.isoTo)); + +// enaFocalLen->set_active (curefs.filterFocalLen); + focalFrom->set_text (Glib::ustring::format (curefs.focalFrom)); + focalTo->set_text (Glib::ustring::format (curefs.focalTo)); + +// enaCamera->set_active (curefs.filterCamera); + Glib::RefPtr cselection = camera->get_selection (); + int j=0; + for (std::set::iterator i = defefs.cameras.begin(); i!=defefs.cameras.end(); i++, j++) { + camera->append_text (*i); + if (curefs.cameras.count (*i)>0) + cselection->select (camera->get_model()->children()[j]); + } + +// enaLens->set_active (curefs.filterLens); + Glib::RefPtr lselection = lens->get_selection (); + j = 0; + for (std::set::iterator i = defefs.lenses.begin(); i!=defefs.lenses.end(); i++, j++) { + lens->append_text (*i); + if (curefs.lenses.count (*i)>0) + lselection->select (lens->get_model()->children()[j]); + } + + for (int i=0; iget_active () && is_sensitive(); +} + +ExifFilterSettings FilterPanel::getFilter () { + + ExifFilterSettings efs; + efs.fnumberFrom = atof (fnumberFrom->get_text().c_str()); + efs.fnumberTo = atof (fnumberTo->get_text().c_str()); + efs.focalFrom = atof (focalFrom->get_text().c_str()); + efs.focalTo = atof (focalTo->get_text().c_str()); + efs.isoFrom = atoi (isoFrom->get_text().c_str()); + efs.isoTo = atoi (isoTo->get_text().c_str()); + efs.shutterFrom = ImageMetaData::shutterFromString (shutterFrom->get_text()); + efs.shutterTo = ImageMetaData::shutterFromString (shutterTo->get_text()); + + efs.filterFNumber = enaFNumber->get_active (); + efs.filterShutter = enaShutter->get_active (); + efs.filterFocalLen = enaFocalLen->get_active (); + efs.filterISO = enaISO->get_active (); + efs.filterCamera = enaCamera->get_active (); + efs.filterLens = enaLens->get_active (); + + std::vector sel = camera->get_selected (); + for (int i=0; iget_text (sel[i])); + sel = lens->get_selected (); + for (int i=0; iget_text (sel[i])); + + return efs; +} + +void FilterPanel::valueChanged () { + + if (listener) + listener->exifFilterChanged (); +} diff --git a/rtgui/filterpanel.h b/rtgui/filterpanel.h new file mode 100755 index 000000000..924b56dae --- /dev/null +++ b/rtgui/filterpanel.h @@ -0,0 +1,71 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _FILTERPANEL_ +#define _FILTERPANEL_ + +#include +#include + +class FilterPanelListener { + + public: + virtual void exifFilterChanged () {} +}; + +class FilterPanel : public Gtk::VBox { + + protected: + Gtk::ListViewText* camera; + Gtk::ListViewText* lens; + Gtk::Entry* fnumberFrom; + Gtk::Entry* fnumberTo; + Gtk::Entry* shutterFrom; + Gtk::Entry* shutterTo; + Gtk::Entry* focalFrom; + Gtk::Entry* focalTo; + Gtk::Entry* isoFrom; + Gtk::Entry* isoTo; + Gtk::CheckButton* enabled; + Gtk::CheckButton* enaFNumber; + Gtk::CheckButton* enaShutter; + Gtk::CheckButton* enaFocalLen; + Gtk::CheckButton* enaISO; + Gtk::CheckButton* enaCamera; + Gtk::CheckButton* enaLens; + + int conns; + sigc::connection sChange[20]; + + ExifFilterSettings curefs; + FilterPanelListener* listener; + + public: + FilterPanel (); + + void setFilterPanelListener (FilterPanelListener* l) { listener = l; } + + void setFilter (ExifFilterSettings& defefs); + ExifFilterSettings getFilter (); + bool isEnabled (); + + + void valueChanged (); +}; + +#endif diff --git a/rtgui/guiutils.cc b/rtgui/guiutils.cc new file mode 100755 index 000000000..e1f757e0e --- /dev/null +++ b/rtgui/guiutils.cc @@ -0,0 +1,196 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include + +bool removeIfThere (Gtk::Container* cont, Gtk::Widget* w, bool increference) { + + Glib::ListHandle list = cont->get_children (); + Glib::ListHandle::iterator i = list.begin (); + for (; i!=list.end() && *i!=w; i++); + if (i!=list.end()) { + if (increference) + w->reference (); + cont->remove (*w); + return true; + } + else + return false; +} + +void thumbInterp (const unsigned char* src, int sw, int sh, unsigned char* dst, int dw, int dh) { + + if (options.thumbInterp==0) + rtengine::nearestInterp (src, sw, sh, dst, dw, dh); + else if (options.thumbInterp==1) + rtengine::bilinearInterp (src, sw, sh, dst, dw, dh); +} + +Glib::ustring removeExtension (const Glib::ustring& filename) { + + Glib::ustring bname = Glib::path_get_basename(filename); + int lastdot = bname.find_last_of ('.'); + if (lastdot!=bname.npos) + return filename.substr (0, filename.size()-(bname.size()-lastdot)); + else + return filename; +} + +Glib::ustring getExtension (const Glib::ustring& filename) { + + Glib::ustring bname = Glib::path_get_basename(filename); + int lastdot = bname.find_last_of ('.'); + if (lastdot!=bname.npos) + return filename.substr (filename.size()-(bname.size()-lastdot)+1, filename.npos); + else + return ""; +} + +void drawCrop (Cairo::RefPtr cr, int imx, int imy, int imw, int imh, int startx, int starty, double scale, const rtengine::procparams::CropParams& cparams) { + + cr->set_line_width (1.0); + cr->rectangle (imx+0.5, imy+0.5, imw, imh); + cr->clip (); + + double c1x = (cparams.x-startx)*scale; + double c1y = (cparams.y-starty)*scale; + double c2x = (cparams.x+cparams.w-1-startx)*scale; + double c2y = (cparams.y+cparams.h-1-starty)*scale; + + cr->set_source_rgba (0, 0, 0, 2.0/3.0); + cr->rectangle (imx+0.5, imy+0.5, imw, c1y); + cr->rectangle (imx+0.5, imy+0.5+c2y, imw, imh-c2y); + cr->rectangle (imx+0.5, imy+0.5+c1y, c1x, c2y-c1y+1); + cr->rectangle (imx+0.5+c2x, imy+0.5+c1y, imw-c2x, c2y-c1y+1); + cr->fill (); + + // rectangle around the cropped area and guides + if (cparams.guide!="None") { + double rectx1 = c1x + imx + 0.5; + double recty1 = c1y + imy + 0.5; + double rectx2 = c2x + imx + 0.5; + double recty2 = c2y + imy + 0.5; + cr->set_line_width (1.0); + cr->set_source_rgb (1.0, 1.0, 1.0); + cr->move_to (rectx1, recty1); + cr->line_to (rectx2, recty1); + cr->line_to (rectx2, recty2); + cr->line_to (rectx1, recty2); + cr->line_to (rectx1, recty1); + cr->stroke (); + cr->set_source_rgb (0.0, 0.0, 0.0); + std::valarray ds (1); + ds[0] = 4; + cr->set_dash (ds, 0); + cr->move_to (rectx1, recty1); + cr->line_to (rectx2, recty1); + cr->line_to (rectx2, recty2); + cr->line_to (rectx1, recty2); + cr->line_to (rectx1, recty1); + cr->stroke (); + ds.resize (0); + cr->set_dash (ds, 0); + + if (cparams.guide!="Rule of diagonals") { + // draw guide lines + std::vector horiz_ratios; + std::vector vert_ratios; + + if (cparams.guide=="Rule of thirds") { + horiz_ratios.push_back (1.0/3.0); + horiz_ratios.push_back (2.0/3.0); + vert_ratios.push_back (1.0/3.0); + vert_ratios.push_back (2.0/3.0); + } + else if (cparams.guide=="Harmonic means 1") { + horiz_ratios.push_back (1.0-0.618); + vert_ratios.push_back (1.0-0.618); + } + else if (cparams.guide=="Harmonic means 2") { + horiz_ratios.push_back (0.618); + vert_ratios.push_back (1.0-0.618); + } + else if (cparams.guide=="Harmonic means 3") { + horiz_ratios.push_back (1.0-0.618); + vert_ratios.push_back (0.618); + } + else if (cparams.guide=="Harmonic means 4") { + horiz_ratios.push_back (0.618); + vert_ratios.push_back (0.618); + } + for (int i=0; iset_source_rgb (1.0, 1.0, 1.0); + cr->move_to (rectx1 + (rectx2-rectx1) * vert_ratios[i], recty1); + cr->line_to (rectx1 + (rectx2-rectx1) * vert_ratios[i], recty2); + cr->move_to (rectx1, recty1 + (recty2-recty1) * horiz_ratios[i]); + cr->line_to (rectx2, recty1 + (recty2-recty1) * horiz_ratios[i]); + cr->stroke (); + cr->set_source_rgb (0.0, 0.0, 0.0); + std::valarray ds (1); + ds[0] = 4; + cr->set_dash (ds, 0); + cr->move_to (rectx1 + (rectx2-rectx1) * vert_ratios[i], recty1); + cr->line_to (rectx1 + (rectx2-rectx1) * vert_ratios[i], recty2); + cr->move_to (rectx1, recty1 + (recty2-recty1) * horiz_ratios[i]); + cr->line_to (rectx2, recty1 + (recty2-recty1) * horiz_ratios[i]); + cr->stroke (); + ds.resize (0); + cr->set_dash (ds, 0); + } + } + else { + int corners_from[4][2]; + int corners_to[4][2]; + int mindim = MIN (rectx2-rectx1+1, recty2-recty1+1); + corners_from[0][0] = rectx1; + corners_from[0][1] = recty1; + corners_to[0][0] = rectx1 + mindim; + corners_to[0][1] = recty1 + mindim; + corners_from[1][0] = rectx1; + corners_from[1][1] = recty2; + corners_to[1][0] = rectx1 + mindim; + corners_to[1][1] = recty2 - mindim; + corners_from[2][0] = rectx2; + corners_from[2][1] = recty1; + corners_to[2][0] = rectx2 - mindim; + corners_to[2][1] = recty1 + mindim; + corners_from[3][0] = rectx2; + corners_from[3][1] = recty2; + corners_to[3][0] = rectx2 - mindim; + corners_to[3][1] = recty2 - mindim; + for (int i=0; i<4; i++) { + cr->set_source_rgb (1.0, 1.0, 1.0); + cr->move_to (corners_from[i][0], corners_from[i][1]); + cr->line_to (corners_to[i][0], corners_to[i][1]); + cr->stroke (); + cr->set_source_rgb (0.0, 0.0, 0.0); + std::valarray ds (1); + ds[0] = 4; + cr->set_dash (ds, 0); + cr->move_to (corners_from[i][0], corners_from[i][1]); + cr->line_to (corners_to[i][0], corners_to[i][1]); + cr->stroke (); + ds.resize (0); + cr->set_dash (ds, 0); + } + } + } + cr->reset_clip (); +} diff --git a/rtgui/guiutils.h b/rtgui/guiutils.h new file mode 100755 index 000000000..8c170a598 --- /dev/null +++ b/rtgui/guiutils.h @@ -0,0 +1,31 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef __UTILS_ +#define __UTILS_ + +#include +#include + +bool removeIfThere (Gtk::Container* cont, Gtk::Widget* w, bool increference=true); +void thumbInterp (const unsigned char* src, int sw, int sh, unsigned char* dst, int dw, int dh); +Glib::ustring removeExtension (const Glib::ustring& filename); +Glib::ustring getExtension (const Glib::ustring& filename); +void drawCrop (Cairo::RefPtr cr, int imx, int imy, int imw, int imh, int startx, int starty, double scale, const rtengine::procparams::CropParams& cparams); + +#endif diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc new file mode 100755 index 000000000..c319d043f --- /dev/null +++ b/rtgui/histogrampanel.cc @@ -0,0 +1,464 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +HistogramPanel::HistogramPanel () { + + histogramArea = Gtk::manage (new HistogramArea ()); + showRed = Gtk::manage (new Gtk::ToggleButton ("R")); + showGreen = Gtk::manage (new Gtk::ToggleButton ("G")); + showBlue = Gtk::manage (new Gtk::ToggleButton ("B")); + showValue = Gtk::manage (new Gtk::ToggleButton ("L")); + Gtk::VBox* vbox = Gtk::manage (new Gtk::VBox (false, 0)); + + showRed->set_active (true); + showGreen->set_active (true); + showBlue->set_active (true); + showValue->set_active (true); + vbox->pack_start (*showRed, Gtk::PACK_SHRINK, 2); + vbox->pack_start (*showGreen, Gtk::PACK_SHRINK, 2); + vbox->pack_start (*showBlue, Gtk::PACK_SHRINK, 2); + vbox->pack_start (*showValue, Gtk::PACK_SHRINK, 2); + pack_start (*histogramArea); + pack_end (*vbox, Gtk::PACK_SHRINK, 2); + + showRed->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::rgbv_toggled) ); + showGreen->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::rgbv_toggled) ); + showBlue->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::rgbv_toggled) ); + showValue->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::rgbv_toggled) ); + + show_all (); + + showRed->set_tooltip_text (M("HISTOGRAM_TOOLTIP_R")); + showGreen->set_tooltip_text (M("HISTOGRAM_TOOLTIP_G")); + showBlue->set_tooltip_text (M("HISTOGRAM_TOOLTIP_B")); + showValue->set_tooltip_text (M("HISTOGRAM_TOOLTIP_L")); + + rconn = signal_size_allocate().connect( sigc::mem_fun(*this, &HistogramPanel::resized) ); +} + +void HistogramPanel::resized (Gtk::Allocation& req) { + + rconn.block (true); + + if (req.get_width()/2>150) + set_size_request (req.get_width(), 150); + else + set_size_request (req.get_width(), req.get_width()/2); + rconn.block (false); + histogramArea->renderHistogram (); + histogramArea->queue_draw (); +} + +void HistogramPanel::rgbv_toggled () { + + histogramArea->updateOptions (showRed->get_active(), showGreen->get_active(), showBlue->get_active(), showValue->get_active()); + histogramArea->queue_draw (); +} + +HistogramArea::HistogramArea () : + needVal(true), needRed(true), needGreen(true), needBlue(true), oldwidth(-1), valid(false), showFull(true) { + + haih = new HistogramAreaIdleHelper; + haih->harea = this; + haih->destroyed = false; + haih->pending = 0; + + signal_style_changed().connect( sigc::mem_fun(*this, &HistogramArea::styleChanged) ); +} + +HistogramArea::~HistogramArea () { + + if (haih->pending) + haih->destroyed = true; + else + delete haih; +} + +void HistogramArea::updateOptions (bool r, bool g, bool b, bool v) { + + needRed = r; + needGreen = g; + needBlue = b; + needVal = v; + + renderHistogram (); +} + +int histupdate (void* data) { + + gdk_threads_enter (); + + HistogramAreaIdleHelper* haih = (HistogramAreaIdleHelper*)data; + + if (haih->destroyed) { + if (haih->pending == 1) + delete haih; + else + haih->pending--; + gdk_threads_leave (); + return 0; + } + + haih->harea->renderHistogram (); + haih->harea->queue_draw (); + + haih->pending--; + gdk_threads_leave (); + return 0; +} + +void HistogramArea::update (unsigned int* rh, unsigned int* gh, unsigned int* bh, unsigned int* lh) { + + if (rh!=NULL) { + memcpy (lhist, lh, 256*sizeof(unsigned int)); + memcpy (rhist, rh, 256*sizeof(unsigned int)); + memcpy (ghist, gh, 256*sizeof(unsigned int)); + memcpy (bhist, bh, 256*sizeof(unsigned int)); + valid = true; + } + else + valid = false; + + haih->pending++; + g_idle_add (histupdate, haih); +} + +void HistogramArea::renderHistogram () { + + if (!is_realized ()) + return; + + Glib::RefPtr window = get_window(); + int winx, winy, winw, winh, wind; + window->get_geometry(winx, winy, winw, winh, wind); + + backBuffer = Gdk::Pixmap::create (window, winw, winh, -1); + + Glib::RefPtr bgc = Gdk::GC::create(backBuffer); + + bgc->set_foreground (white); + backBuffer->draw_rectangle (bgc, true, 0, 0, winw, winh); + + if (valid) { + + // compute height of the full histogram (realheight) and + + int fullhistheight = 0; + for (int i=0; i<256; i++) { + if (needVal && lhist[i]>fullhistheight) + fullhistheight = lhist[i]; + if (needRed && rhist[i]>fullhistheight) + fullhistheight = rhist[i]; + if (needGreen && ghist[i]>fullhistheight) + fullhistheight = ghist[i]; + if (needBlue && bhist[i]>fullhistheight) + fullhistheight = bhist[i]; + } + + // compute two hights, one for the magnified view and one for the threshold + int realhistheight = fullhistheight; + + if (!showFull) { + int area1thres = 0; + int area2thres = 0; + int area = 0; + for (int i=0; ii) || (needRed && rhist[j]>i) || (needGreen && ghist[j]>i) || (needBlue && bhist[j]>i)) + area++; + if (area1thres==0 && (double)area / (256*(i+1)) < 0.3) + area1thres = i; + if (area2thres==0 && (double)area / (256*(i+1)) < 0.3) + area2thres = i; + if (area1thres && area2thres) + break; + } + if (area1thres>0 && area2thres>0 && area1thres cr = backBuffer->create_cairo_context(); + cr->set_antialias (Cairo::ANTIALIAS_SUBPIXEL); + cr->set_line_width (1.0); + double stepSize = (winw-1) / 256.0; + if (needVal) { + cr->move_to (0, winh-1); + cr->set_source_rgb (0.75, 0.75, 0.75); + for (int i=0; i<256; i++) { + double val = lhist[i] * (double)(winh-2) / realhistheight; + if (val>winh-1) + val = winh-1; + if (i>0) + cr->line_to (i*stepSize, winh-1-val); + } + cr->save (); + cr->line_to (winw-1, winh-1); cr->fill_preserve (); + cr->restore (); + cr->set_source_rgb (0.5, 0.5, 0.5); + cr->stroke (); + } + if (needRed) { + cr->move_to (0, winh-1); + cr->set_source_rgb (1.0, 0.0, 0.0); + for (int i=0; i<256; i++) { + double val = rhist[i] * (double)(winh-2) / realhistheight; + if (val>winh-1) + val = winh-1; + if (i>0) + cr->line_to (i*stepSize, winh-1-val); + } + cr->stroke (); + } + if (needGreen) { cr->move_to (0, winh-1); + cr->set_source_rgb (0.0, 1.0, 0.0); + for (int i=0; i<256; i++) { + double val = ghist[i] * (double)(winh-2) / realhistheight; + if (val>winh-1) + val = winh-1; + if (i>0) + cr->line_to (i*stepSize, winh-1-val); + } + cr->stroke (); + } + if (needBlue) { + cr->move_to (0, winh-1); + cr->set_source_rgb (0.0, 0.0, 1.0); + for (int i=0; i<256; i++) { + int val = bhist[i] * (double)(winh-2) / realhistheight; + if (val>winh-1) + val = winh-1; + if (i>0) + cr->line_to (i*stepSize, winh-1-val); + } + cr->stroke (); + } + } + +/* + + // scale histogram to width winw-1 + + int* vval = new int[winw-1]; + int* vred = new int[winw-1]; + int* vgreen = new int[winw-1]; + int* vblue = new int[winw-1]; + + memset (vval, 0, sizeof(int)*(winw-1)); + memset (vred, 0, sizeof(int)*(winw-1)); + memset (vgreen, 0, sizeof(int)*(winw-1)); + memset (vblue, 0, sizeof(int)*(winw-1)); + + int index = 0; + double scale = 256.0 / (winw-2); + for (int i=0; i<=winw-2; i++) { + int samples = 0; + while (index < 256 && (int)(index/scale) == i) { + vval[i] += lhist[index]; + vred[i] += rhist[index]; + vgreen[i] += ghist[index]; + vblue[i] += bhist[index]; + index++; + samples++; + } + if (samples>0) { + vval[i] /= samples; + vred[i] /= samples; + vgreen[i] /= samples; + vblue[i] /= samples; + } + } + + // compute height of the full histogram (realheight) and + + int fullhistheight = 0; + for (int i=0; i<=winw-2; i++) { + if (needVal && vval[i]>fullhistheight) + fullhistheight = vval[i]; + if (needRed && vred[i]>fullhistheight) + fullhistheight = vred[i]; + if (needGreen && vgreen[i]>fullhistheight) + fullhistheight = vgreen[i]; + if (needBlue && vblue[i]>fullhistheight) + fullhistheight = vblue[i]; + } + + // compute two hights, one for the magnified view and one for the threshold + + int realhistheight = fullhistheight; + + if (!showFull) { + int area1thres = 0; + int area2thres = 0; + int area = 0; + for (int i=0; ii) || (needRed && vred[j]>i) || (needGreen && vgreen[j]>i) || (needBlue && vblue[j]>i)) + area++; + if (area1thres==0 && (double)area / ((winw-1)*(i+1)) < 0.3) + area1thres = i; + if (area2thres==0 && (double)area / ((winw-1)*(i+1)) < 0.3) + area2thres = i; + if (area1thres && area2thres) + break; + } + if (area1thres>0 && area2thres>0 && area1thres cr = backBuffer->create_cairo_context(); + cr->set_antialias (Cairo::ANTIALIAS_SUBPIXEL); + cr->set_line_width (1.0); + if (needVal) { + cr->move_to (0, winh-1); + cr->set_source_rgb (0.75, 0.75, 0.75); + for (int i=0; i<=winw-2; i++) { + int val = (int)(vval[i] * (double)(winh-2) / realhistheight); + if (val>winh-1) + val = winh-1; + if (i>0) + cr->line_to (i+1, winh-1-val); + } + cr->fill_preserve (); + cr->set_source_rgb (0.5, 0.5, 0.5); + cr->stroke (); + } + if (needRed) { + cr->move_to (0, winh-1); + cr->set_source_rgb (1.0, 0.0, 0.0); + for (int i=0; i<=winw-2; i++) { + int val = (int)(vred[i] * (double)(winh-2) / realhistheight); + if (val>winh-1) + val = winh-1; + if (i>0) + cr->line_to (i+1, winh-1-val); + } + cr->stroke (); + } + if (needGreen) { + cr->move_to (0, winh-1); + cr->set_source_rgb (0.0, 1.0, 0.0); + for (int i=0; i<=winw-2; i++) { + int val = (int)(vgreen[i] * (double)(winh-2) / realhistheight); + if (val>winh-1) + val = winh-1; + if (i>0) + cr->line_to (i+1, winh-1-val); + } + cr->stroke (); + } + if (needBlue) { + cr->move_to (0, winh-1); + cr->set_source_rgb (0.0, 0.0, 1.0); + for (int i=0; i<=winw-2; i++) { + int val = (int)(vblue[i] * (double)(winh-2) / realhistheight); + if (val>winh-1) + val = winh-1; + if (i>0) + cr->line_to (i+1, winh-1-val); + } + cr->stroke (); + } + + delete [] vval; + delete [] vred; + delete [] vgreen; + delete [] vblue; + } +*/ + bgc->set_foreground (mgray); + backBuffer->draw_rectangle (bgc, false, 0, 0, winw-1, winh-1); + + bgc->set_line_attributes (1, Gdk::LINE_ON_OFF_DASH, Gdk::CAP_NOT_LAST, Gdk::JOIN_MITER); + + backBuffer->draw_line (bgc, winw/3, 0, winw/3, winh-1); + backBuffer->draw_line (bgc, 2*winw/3, 0, 2*winw/3, winh-1); + backBuffer->draw_line (bgc, 0, winh/3, winw-1, winh/3); + backBuffer->draw_line (bgc, 0, 2*winh/3, winw-1, 2*winh/3); + + bgc->set_line_attributes (1, Gdk::LINE_SOLID, Gdk::CAP_NOT_LAST, Gdk::JOIN_MITER); + + oldwidth = winw; + oldheight = winh; +} + +void HistogramArea::on_realize () { + + Gtk::DrawingArea::on_realize(); + Glib::RefPtr window = get_window(); + gc_ = Gdk::GC::create(window); + add_events(Gdk::EXPOSURE_MASK | Gdk::BUTTON_PRESS_MASK); + Glib::RefPtr colormap = get_default_colormap(); + + black = Gdk::Color ("black"); + red = Gdk::Color ("red"); + green = Gdk::Color ("green"); + blue = Gdk::Color ("blue"); + lgray = Gdk::Color ("gray75"); + mgray = Gdk::Color ("gray50"); + dgray = Gdk::Color ("gray25"); + colormap->alloc_color(black); + colormap->alloc_color(white); + colormap->alloc_color(red); + colormap->alloc_color(green); + colormap->alloc_color(blue); + colormap->alloc_color(lgray); + colormap->alloc_color(mgray); + colormap->alloc_color(dgray); + +} + +void HistogramArea::styleChanged (const Glib::RefPtr& style) { + + white = get_style()->get_base(Gtk::STATE_NORMAL); + queue_draw (); +} + +bool HistogramArea::on_expose_event(GdkEventExpose* event) { + + Glib::RefPtr window = get_window(); + + int winx, winy, winw, winh, wind; + window->get_geometry(winx, winy, winw, winh, wind); + + if (winw!=oldwidth && winh!=oldheight) + renderHistogram (); + window->draw_drawable (gc_, backBuffer, 0, 0, 0, 0, -1, -1); + + return true; +} + + +bool HistogramArea::on_button_press_event (GdkEventButton* event) { + + if (event->type==GDK_2BUTTON_PRESS && event->button==1) { + showFull = !showFull; + renderHistogram (); + queue_draw (); + } +} + + diff --git a/rtgui/histogrampanel.h b/rtgui/histogrampanel.h new file mode 100755 index 000000000..04296ebf1 --- /dev/null +++ b/rtgui/histogrampanel.h @@ -0,0 +1,98 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _HISTOGRAMPANEL_ +#define _HISTOGRAMPANEL_ + +#include +#include +#include + +class HistogramArea; +struct HistogramAreaIdleHelper { + HistogramArea* harea; + bool destroyed; + int pending; +}; + +class HistogramArea : public Gtk::DrawingArea { + + protected: + + Glib::RefPtr gc_; + Glib::RefPtr backBuffer; + + Gdk::Color black; + Gdk::Color white; + Gdk::Color red; + Gdk::Color green; + Gdk::Color blue; + Gdk::Color lgray; + Gdk::Color mgray; + Gdk::Color dgray; + unsigned int lhist[256]; + unsigned int rhist[256]; + unsigned int ghist[256]; + unsigned int bhist[256]; + bool valid; + bool showFull; + int oldwidth, oldheight; + + bool needVal; + bool needRed; + bool needGreen; + bool needBlue; + + HistogramAreaIdleHelper* haih; + + public: + + HistogramArea(); + ~HistogramArea(); + + void renderHistogram (); + void update (unsigned int* rh, unsigned int* gh, unsigned int* bh, unsigned int* lh); + void updateOptions (bool r, bool g, bool b, bool v); + void on_realize(); + bool on_expose_event(GdkEventExpose* event); + bool on_button_press_event (GdkEventButton* event); + void styleChanged (const Glib::RefPtr& style); +}; + +class HistogramPanel : public Gtk::HBox, public rtengine::HistogramListener { + + protected: + + HistogramArea* histogramArea; + Gtk::ToggleButton* showRed; + Gtk::ToggleButton* showGreen; + Gtk::ToggleButton* showBlue; + Gtk::ToggleButton* showValue; + + sigc::connection rconn; + + public: + + HistogramPanel (); + + void histogramChanged (unsigned int* rh, unsigned int* gh, unsigned int* bh, unsigned int* lh) { histogramArea->update (rh, gh, bh, lh); } + void rgbv_toggled (); + void resized (Gtk::Allocation& req); +}; + +#endif diff --git a/rtgui/history.cc b/rtgui/history.cc new file mode 100755 index 000000000..46ea67b0b --- /dev/null +++ b/rtgui/history.cc @@ -0,0 +1,326 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +using namespace rtengine; +using namespace rtengine::procparams; + +Glib::ustring eventDescrArray[NUMOFEVENTS]; +extern Glib::ustring argv0; + +History::History (bool bookmarkSupport) : tpc (NULL), bmnum (1), blistener(NULL) { + + // fill history event message array + for (int i=0; iset_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); + + Gtk::Frame* histFrame = Gtk::manage (new Gtk::Frame (M("HISTORY_LABEL"))); + histFrame->add (*hscrollw); + + pack_start (*histFrame); + + hTreeView = Gtk::manage (new Gtk::TreeView ()); + hscrollw->add (*hTreeView); + + historyModel = Gtk::ListStore::create (historyColumns); + hTreeView->set_model (historyModel); +// hTreeView->set_headers_visible (false); + + Gtk::CellRendererText *changecrt = Gtk::manage (new Gtk::CellRendererText()); + Gtk::CellRendererText *valuecrt = Gtk::manage (new Gtk::CellRendererText()); + Gtk::TreeView::Column *hviewcol = Gtk::manage (new Gtk::TreeView::Column ("")); + hviewcol->pack_start (*changecrt, true); + hviewcol->add_attribute (changecrt->property_markup (), historyColumns.text); + hviewcol->set_resizable (true); + + Gtk::TreeView::Column *hviewcol2 = Gtk::manage (new Gtk::TreeView::Column ("")); + hviewcol2->pack_start (*valuecrt, true); + hviewcol2->add_attribute (valuecrt->property_markup (), historyColumns.value); + valuecrt->set_property ("xalign", 1.0); + + hTreeView->append_column (*hviewcol); + hTreeView->append_column (*hviewcol2); + + hviewcol2->set_sizing (Gtk::TREE_VIEW_COLUMN_FIXED); + + selchangehist = hTreeView->get_selection()->signal_changed().connect(sigc::mem_fun(*this, &History::historySelectionChanged)); + + // Bookmark List + // ~~~~~~~~~~~~~ + + Gtk::HSeparator* hsepb = Gtk::manage (new Gtk::HSeparator ()); + pack_end (*hsepb, Gtk::PACK_SHRINK, 0); + + Gtk::HBox* ahbox = Gtk::manage (new Gtk::HBox ()); + addBookmark = Gtk::manage (new Gtk::Button (M("HISTORY_NEWSNAPSHOT"))); + Gtk::Image* addimg = Gtk::manage (new Gtk::Image (argv0+"/images/list-add.png")); + addBookmark->set_image (*addimg); + ahbox->pack_start (*addBookmark); + + delBookmark = Gtk::manage (new Gtk::Button (M("HISTORY_DELSNAPSHOT"))); + Gtk::Image* delimg = Gtk::manage (new Gtk::Image (argv0+"/images/list-remove.png")); + delBookmark->set_image (*delimg); + ahbox->pack_start (*delBookmark); + + bscrollw = Gtk::manage (new Gtk::ScrolledWindow ()); +// bscrollw->set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); + bscrollw->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); + bscrollw->set_size_request (-1, 75); + + Gtk::Frame* bmFrame = Gtk::manage (new Gtk::Frame (M("HISTORY_SNAPSHOTS"))); + Gtk::VBox* bmBox = Gtk::manage (new Gtk::VBox ()); + bmFrame->add (*bmBox); + bmBox->pack_start (*bscrollw, Gtk::PACK_SHRINK, 4); + bmBox->pack_end (*ahbox, Gtk::PACK_SHRINK, 4); + + if (bookmarkSupport) + pack_end (*bmFrame, Gtk::PACK_SHRINK, 4); + + bTreeView = Gtk::manage (new Gtk::TreeView ()); + bscrollw->add (*bTreeView); + + bookmarkModel = Gtk::ListStore::create (bookmarkColumns); + bTreeView->set_model (bookmarkModel); + bTreeView->set_headers_visible (false); + bTreeView->append_column_editable (M("HISTORY_SNAPSHOTS"), bookmarkColumns.text); + + selchangebm = bTreeView->get_selection()->signal_changed().connect(sigc::mem_fun(*this, &History::bookmarkSelectionChanged)); + + addBookmark->signal_clicked().connect( sigc::mem_fun(*this, &History::addBookmarkPressed) ); + delBookmark->signal_clicked().connect( sigc::mem_fun(*this, &History::delBookmarkPressed) ); + +// hTreeView->set_grid_lines (Gtk::TREE_VIEW_GRID_LINES_HORIZONTAL); + hTreeView->set_grid_lines (Gtk::TREE_VIEW_GRID_LINES_BOTH); + hTreeView->signal_size_allocate().connect( sigc::mem_fun(*this, &History::resized) ); + + hTreeView->set_enable_search(false); + bTreeView->set_enable_search(false); + + show_all_children (); +} + +void History::initHistory () { + + historyModel->clear (); + bookmarkModel->clear (); +} + +void History::clearParamChanges () { + + initHistory (); +} + +void History::historySelectionChanged () { + + Glib::RefPtr selection = hTreeView->get_selection(); + Gtk::TreeModel::iterator iter = selection->get_selected(); + if (iter) { + Gtk::TreeModel::Row row = *iter; + if (row) + bTreeView->get_selection()->unselect_all (); + if (row && tpc) { + ProcParams params = row[historyColumns.params]; + ParamsEdited paramsEdited = row[historyColumns.paramsEdited]; + tpc->profileChange (¶ms, EvHistoryBrowsed, row[historyColumns.text], ¶msEdited); + } + if (blistener) { + Gtk::TreeModel::Path path = historyModel->get_path (iter); + path.prev (); + iter = historyModel->get_iter (path); + if (blistener && iter) + blistener->historyBeforeLineChanged (iter->get_value (historyColumns.params)); + } + } +} + +void History::bookmarkSelectionChanged () { + + Glib::RefPtr selection = bTreeView->get_selection(); + Gtk::TreeModel::iterator iter = selection->get_selected(); + if (iter) { + Gtk::TreeModel::Row row = *iter; + if (row) + hTreeView->get_selection()->unselect_all (); + if (row && tpc) { + ProcParams params = row[bookmarkColumns.params]; + ParamsEdited paramsEdited = row[bookmarkColumns.paramsEdited]; + tpc->profileChange (¶ms, EvBookmarkSelected, row[bookmarkColumns.text], ¶msEdited); + } + } +} + +void History::procParamsChanged (ProcParams* params, ProcEvent ev, Glib::ustring descr, ParamsEdited* paramsEdited) { + + // to prevent recursion, we filter out the events triggered by the history + if (ev==EvHistoryBrowsed) + return; + + selchangehist.block (true); + + if (ev==EvPhotoLoaded) + initHistory (); + // construct formatted list content + Glib::ustring text = Glib::ustring::compose ("%1", eventDescrArray[ev]); + + Glib::RefPtr selection = hTreeView->get_selection(); + Gtk::TreeModel::iterator iter = selection->get_selected(); + // remove all rows after the selection + if (iter) { + iter++; + while (iter) + iter = historyModel->erase (iter); + } + // lookup the last remaining item in the list + int size = historyModel->children().size (); + Gtk::TreeModel::Row row; + if (size>0) + row = historyModel->children()[size-1]; + // if there is no last item or its chev!=ev, create a new one + if (size==0 || !row || row[historyColumns.chev]!=ev) { + Gtk::TreeModel::Row newrow = *(historyModel->append()); + newrow[historyColumns.realText] = eventDescrArray[ev]; + newrow[historyColumns.text] = text; + newrow[historyColumns.value] = descr; + newrow[historyColumns.chev] = ev; + newrow[historyColumns.params] = *params; + newrow[historyColumns.paramsEdited] = paramsEdited ? *paramsEdited : defParamsEdited; + if (ev!=EvBookmarkSelected) + selection->select (newrow); + if (blistener && row) + blistener->historyBeforeLineChanged (row[historyColumns.params]); + else if (blistener && size==0) + blistener->historyBeforeLineChanged (newrow[historyColumns.params]); + } + // else just update it + else { + row[historyColumns.realText] = eventDescrArray[ev]; + row[historyColumns.text] = text; + row[historyColumns.value] = descr; + row[historyColumns.chev] = ev; + row[historyColumns.params] = *params; + row[historyColumns.paramsEdited] = paramsEdited ? *paramsEdited : defParamsEdited; + if (ev!=EvBookmarkSelected) + selection->select (row); + } + if (ev!=EvBookmarkSelected) + bTreeView->get_selection()->unselect_all (); + + + if (!selection->get_selected_rows().empty()) { + Gtk::TreeView::Selection::ListHandle_Path selp = selection->get_selected_rows(); + hTreeView->scroll_to_row (*selp.begin()); + } + selchangehist.block (false); +} + +void History::addBookmarkWithText (Glib::ustring text) { + + // lookup the selected item in the history + Glib::RefPtr selection = hTreeView->get_selection(); + Gtk::TreeModel::iterator iter = selection->get_selected(); + Gtk::TreeModel::Row row = *iter; + + if (!row) { + return; + } + + // append new row to bookmarks + Gtk::TreeModel::Row newrow = *(bookmarkModel->append()); + newrow[bookmarkColumns.text] = text; + ProcParams params = row[historyColumns.params]; + newrow[bookmarkColumns.params] = params; + ParamsEdited paramsEdited = row[historyColumns.paramsEdited]; + newrow[bookmarkColumns.paramsEdited] = paramsEdited; +} + +void History::addBookmarkPressed () { + + if (hTreeView->get_selection()->get_selected()) + addBookmarkWithText (Glib::ustring::compose ("%1 %2", M("HISTORY_SNAPSHOT"), bmnum++)); +} + +void History::delBookmarkPressed () { + + // lookup the selected item in the bookmark + Glib::RefPtr selection = bTreeView->get_selection(); + Gtk::TreeModel::iterator iter = selection->get_selected(); + + if (!iter) { + return; + } + // remove selected bookmark + bookmarkModel->erase (iter); + // select last item in history + int size = historyModel->children().size (); + Gtk::TreeModel::Row row = historyModel->children()[size-1]; + hTreeView->get_selection()->select (row); +} + +void History::undo () { + + Glib::RefPtr selection = hTreeView->get_selection(); + Gtk::TreeModel::iterator iter = selection->get_selected(); + + if (iter && iter!=historyModel->children().begin()) + selection->select (--iter); + else if (!iter) { + int size = historyModel->children().size (); + if (size>1) + selection->select (historyModel->children()[size-2]); + } +} + +void History::redo () { + + Glib::RefPtr selection = hTreeView->get_selection(); + Gtk::TreeModel::iterator iter = selection->get_selected(); + + if (iter) { + iter++; + if (iter!=historyModel->children().end()) + selection->select (iter); + } + else { + int size = historyModel->children().size (); + if (size>1) + selection->select (historyModel->children()[size-2]); + } +} + +void History::resized (Gtk::Allocation& req) { +} + +bool History::getBeforeLineParams (rtengine::procparams::ProcParams& params) { + + int size = historyModel->children().size (); + if (size==0 || !blistener) + return false; + + Gtk::TreeModel::Row row; + row = historyModel->children()[size==1 ? 0 : size-2]; + params = row[historyColumns.params]; + return true; +} + diff --git a/rtgui/history.h b/rtgui/history.h new file mode 100755 index 000000000..58d0a76c9 --- /dev/null +++ b/rtgui/history.h @@ -0,0 +1,105 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _HISTORY_ +#define _HISTORY_ + +#include +#include +#include +#include +#include + +class HistoryBeforeLineListener { + + public: + virtual void historyBeforeLineChanged (const rtengine::procparams::ProcParams& params) {} +}; + +class History : public Gtk::VBox, public PParamsChangeListener { + + public: + + class HistoryColumns : public Gtk::TreeModel::ColumnRecord { + public: + Gtk::TreeModelColumn realText; + Gtk::TreeModelColumn text; + Gtk::TreeModelColumn value; + Gtk::TreeModelColumn params; + Gtk::TreeModelColumn chev; + Gtk::TreeModelColumn paramsEdited; + HistoryColumns() { add(text); add(realText); add(value); add(chev); add(params); add(paramsEdited); } + }; + HistoryColumns historyColumns; + class BookmarkColumns : public Gtk::TreeModel::ColumnRecord { + public: + Gtk::TreeModelColumn text; + Gtk::TreeModelColumn params; + Gtk::TreeModelColumn paramsEdited; + BookmarkColumns() { add(text); add(params); add(paramsEdited); } + }; + BookmarkColumns bookmarkColumns; + + protected: + Gtk::ScrolledWindow* hscrollw; + Gtk::TreeView* hTreeView; + Glib::RefPtr historyModel; + + Gtk::ScrolledWindow* bscrollw; + Gtk::TreeView* bTreeView; + Glib::RefPtr bookmarkModel; + + Gtk::Button* addBookmark; + Gtk::Button* delBookmark; + + sigc::connection selchangehist; + sigc::connection selchangebm; + + HistoryBeforeLineListener * blistener; + ProfileChangeListener* tpc; + ParamsEdited defParamsEdited; + int bmnum; + + public: + + History (bool bookmarkSupport = true); + + void setProfileChangeListener (ProfileChangeListener* tpc_) { tpc = tpc_; } + void setHistoryBeforeLineListener (HistoryBeforeLineListener* bll) { blistener = bll; } + + // pparamschangelistener interface + void procParamsChanged (rtengine::procparams::ProcParams* params, rtengine::ProcEvent ev, Glib::ustring descr, ParamsEdited* paramsEdited=NULL); + void clearParamChanges (); + + void historySelectionChanged (); + void bookmarkSelectionChanged (); + void initHistory (); + + bool getBeforeLineParams (rtengine::procparams::ProcParams& params); + + void addBookmarkWithText (Glib::ustring text); + void addBookmarkPressed (); + void delBookmarkPressed (); + + void resized (Gtk::Allocation& req); + + void undo (); + void redo (); +}; + +#endif diff --git a/rtgui/hlrec.cc b/rtgui/hlrec.cc new file mode 100755 index 000000000..3dc08651f --- /dev/null +++ b/rtgui/hlrec.cc @@ -0,0 +1,131 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +using namespace rtengine; +using namespace rtengine::procparams; + +HLRecovery::HLRecovery () : ToolPanel() { + + enabled = Gtk::manage (new Gtk::CheckButton (M("GENERAL_ENABLE"))); + enabled->set_active (false); + pack_start (*enabled); + + method = Gtk::manage (new Gtk::ComboBoxText ()); + method->append_text (M("TP_HLREC_LUMINANCE")); + method->append_text (M("TP_HLREC_CIELAB")); + method->append_text (M("TP_HLREC_COLOR")); + method->set_active (0); + Gtk::HBox* hb = Gtk::manage (new Gtk::HBox ()); + Gtk::Label* lab = Gtk::manage (new Gtk::Label (M("TP_HLREC_METHOD"))); + hb->pack_start (*lab, Gtk::PACK_SHRINK, 4); + hb->pack_start (*method); + pack_start (*hb); + + enaconn = enabled->signal_toggled().connect( sigc::mem_fun(*this, &HLRecovery::enabledChanged) ); + methconn = method->signal_changed().connect ( sigc::mem_fun(*this, &HLRecovery::methodChanged) ); + + show_all (); +} + +void HLRecovery::read (const ProcParams* pp, const ParamsEdited* pedited) { + + disableListener (); + + + if (pedited) + enabled->set_inconsistent (!pedited->hlrecovery.enabled); + enaconn.block (true); + enabled->set_active (pp->hlrecovery.enabled); + enaconn.block (false); + + if (pedited && !pedited->hlrecovery.method) + method->set_active (3); + else if (pp->hlrecovery.method=="Luminance") + method->set_active (0); + else if (pp->hlrecovery.method=="CIELab blending") + method->set_active (1); + else if (pp->hlrecovery.method=="Color") + method->set_active (2); + + lastEnabled = pp->hlrecovery.enabled; + + enableListener (); +} + +void HLRecovery::write (ProcParams* pp, ParamsEdited* pedited) { + + if (pedited) { + pedited->hlrecovery.method = method->get_active_row_number()!=3; + pedited->hlrecovery.enabled = !enabled->get_inconsistent(); + } + + pp->hlrecovery.enabled = enabled->get_active(); + if (method->get_active_row_number()==0) + pp->hlrecovery.method = "Luminance"; + else if (method->get_active_row_number()==1) + pp->hlrecovery.method = "CIELab blending"; + else if (method->get_active_row_number()==2) + pp->hlrecovery.method = "Color"; +} + +void HLRecovery::enabledChanged () { + + if (batchMode) { + if (enabled->get_inconsistent()) { + enabled->set_inconsistent (false); + enaconn.block (true); + enabled->set_active (false); + enaconn.block (false); + } + else if (lastEnabled) + enabled->set_inconsistent (true); + + lastEnabled = enabled->get_active (); + } + + if (listener) { + if (enabled->get_active ()) + listener->panelChanged (EvHREnabled, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvHREnabled, M("GENERAL_DISABLED")); + } +} + +void HLRecovery::methodChanged () { + + if (listener) { + if (enabled->get_active ()) + listener->panelChanged (EvHRMethod, method->get_active_text ()); + } +} + +void HLRecovery::setRaw (bool raw) { + + disableListener (); + set_sensitive (raw); + enableListener (); +} + +void HLRecovery::setBatchMode (bool batchMode) { + + ToolPanel::setBatchMode (batchMode); + method->append_text ("(Unchanged)"); +} diff --git a/rtgui/hlrec.h b/rtgui/hlrec.h new file mode 100755 index 000000000..86f490232 --- /dev/null +++ b/rtgui/hlrec.h @@ -0,0 +1,48 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _HLREC_H_ +#define _HLREC_H_ + +#include +#include + +class HLRecovery : public Gtk::VBox, public ToolPanel { + + protected: + Gtk::CheckButton* enabled; + Gtk::ComboBoxText* method; + sigc::connection methconn; + sigc::connection enaconn; + bool lastEnabled; + + public: + + HLRecovery (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + + void setRaw (bool raw); + + void enabledChanged (); + void methodChanged (); +}; + +#endif diff --git a/rtgui/iccfromwindows.txt b/rtgui/iccfromwindows.txt new file mode 100755 index 000000000..6e3b29c08 --- /dev/null +++ b/rtgui/iccfromwindows.txt @@ -0,0 +1,21 @@ ++#elif defined G_OS_WIN32 ++ if (config->display_profile_from_gdk) ++ { ++ HDC hdc = GetDC (NULL); ++ ++ if (hdc) ++ { ++ gchar *path; ++ gint32 len = 0; ++ ++ GetICMProfile (hdc, &len, NULL); ++ path = g_new (gchar, len); ++ ++ if (GetICMProfile (hdc, &len, path)) ++ profile = cmsOpenProfileFromFile (path, "r"); ++ ++ g_free (path); ++ ReleaseDC (NULL, hdc); ++ } ++ } + #endif diff --git a/rtgui/icmpanel.cc b/rtgui/icmpanel.cc new file mode 100755 index 000000000..25cad1946 --- /dev/null +++ b/rtgui/icmpanel.cc @@ -0,0 +1,290 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include + +using namespace rtengine; +using namespace rtengine::procparams; + +extern Options options; + +ICMPanel::ICMPanel () : ToolPanel(), icmplistener(NULL), iunchanged(NULL) { + +// set_border_width (4); + + ipDialog = Gtk::manage (new Gtk::FileChooserButton (M("TP_ICM_INPUTDLGLABEL"), Gtk::FILE_CHOOSER_ACTION_OPEN)); + opDialog = Gtk::manage (new Gtk::FileChooserButton (M("TP_ICM_INPUTDLGLABEL"), Gtk::FILE_CHOOSER_ACTION_OPEN)); + + Gtk::Label* ilab = Gtk::manage (new Gtk::Label ()); + ilab->set_alignment (0.0, 0.5); + ilab->set_markup (Glib::ustring("") + M("TP_ICM_INPUTPROFILE") + ""); + pack_start (*ilab, Gtk::PACK_SHRINK, 4); + + iembedded = Gtk::manage (new Gtk::RadioButton (M("TP_ICM_INPUTEMBEDDED"))); + pack_start (*iembedded, Gtk::PACK_SHRINK, 4); + + icamera = Gtk::manage (new Gtk::RadioButton (M("TP_ICM_INPUTCAMERA"))); + pack_start (*icamera, Gtk::PACK_SHRINK, 4); + + ifromfile = Gtk::manage (new Gtk::RadioButton (M("TP_ICM_INPUTCUSTOM")+":")); + Gtk::HBox* ffbox = Gtk::manage (new Gtk::HBox ()); + ffbox->pack_start (*ifromfile, Gtk::PACK_SHRINK); + ffbox->pack_start (*ipDialog); + + pack_start (*ffbox, Gtk::PACK_SHRINK, 4); + + opts = icamera->get_group(); + iembedded->set_group (opts); + ifromfile->set_group (opts); + + igamma = Gtk::manage (new Gtk::CheckButton (M("TP_ICM_GAMMABEFOREINPUT"))); + igamma->set_sensitive (false); + pack_start (*igamma, Gtk::PACK_SHRINK, 4); + + saveRef = Gtk::manage (new Gtk::Button (M("TP_ICM_SAVEREFERENCE"))); + saveRef->set_image (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-save"), Gtk::ICON_SIZE_BUTTON))); + pack_start (*saveRef, Gtk::PACK_SHRINK, 4); + + + Gtk::HSeparator* hsep1 = Gtk::manage (new Gtk::HSeparator ()); + pack_start (*hsep1, Gtk::PACK_SHRINK, 2); + + Gtk::Label* wlab = Gtk::manage (new Gtk::Label ()); + wlab->set_alignment (0.0, 0.5); + wlab->set_markup (Glib::ustring("") + M("TP_ICM_WORKINGPROFILE") + ""); + + pack_start (*wlab, Gtk::PACK_SHRINK, 4); + wnames = Gtk::manage (new Gtk::ComboBoxText ()); + pack_start (*wnames, Gtk::PACK_SHRINK, 4); + + Gtk::HSeparator* hsep2 = Gtk::manage (new Gtk::HSeparator ()); + pack_start (*hsep2, Gtk::PACK_SHRINK, 2); + + Gtk::Label* olab = Gtk::manage (new Gtk::Label ()); + olab->set_alignment (0.0, 0.5); + olab->set_markup (Glib::ustring("") + M("TP_ICM_OUTPUTPROFILE") + ""); + + pack_start (*olab, Gtk::PACK_SHRINK, 4); + onames = Gtk::manage (new Gtk::ComboBoxText ()); + pack_start (*onames, Gtk::PACK_SHRINK, 4); + + std::vector wpnames = rtengine::getWorkingProfiles (); + for (int i=0; iappend_text (wpnames[i]); + + onames->append_text (M("TP_ICM_NOICM")); + onames->set_active (0); + + std::vector opnames = rtengine::getOutputProfiles (); + for (int i=0; iappend_text (opnames[i]); + + wnames->set_active (0); + onames->set_active (0); + + Gtk::FileFilter filter_icc; + filter_icc.set_name(M("TP_ICM_FILEDLGFILTERICM")); + filter_icc.add_pattern("*.icc"); + filter_icc.add_pattern("*.icm"); + filter_icc.add_pattern("*.ICC"); + filter_icc.add_pattern("*.ICM"); + Gtk::FileFilter filter_any; + filter_any.set_name(M("TP_ICM_FILEDLGFILTERANY")); + filter_any.add_pattern("*"); + + ipDialog->add_filter (filter_icc); + ipDialog->add_filter (filter_any); + opDialog->add_filter (filter_icc); + opDialog->add_filter (filter_any); + + if (Glib::file_test (options.rtSettings.iccDirectory, Glib::FILE_TEST_IS_DIR)) { + ipDialog->set_current_folder (options.rtSettings.iccDirectory); + opDialog->set_current_folder (options.rtSettings.iccDirectory); + } + + oldip = ""; + + wnames->signal_changed().connect( sigc::mem_fun(*this, &ICMPanel::wpChanged) ); + onames->signal_changed().connect( sigc::mem_fun(*this, &ICMPanel::opChanged) ); + icamera->signal_toggled().connect( sigc::mem_fun(*this, &ICMPanel::ipChanged) ); + iembedded->signal_toggled().connect( sigc::mem_fun(*this, &ICMPanel::ipChanged) ); + ifromfile->signal_toggled().connect( sigc::mem_fun(*this, &ICMPanel::ipChanged) ); + ipc = ipDialog->signal_selection_changed().connect( sigc::mem_fun(*this, &ICMPanel::ipSelectionChanged) ); + saveRef->signal_pressed().connect( sigc::mem_fun(*this, &ICMPanel::saveReferencePressed) ); + + show_all (); +} + +void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) { + + disableListener (); + + ipc.block (true); + if (pp->icm.input == "(embedded)" || ((pp->icm.input == "(camera)" || pp->icm.input=="") && icamera->get_state()==Gtk::STATE_INSENSITIVE)) { + iembedded->set_active (true); + igamma->set_sensitive (false); + } + else if ((pp->icm.input == "(camera)" || pp->icm.input=="") && icamera->get_state()!=Gtk::STATE_INSENSITIVE) { + icamera->set_active (true); + igamma->set_sensitive (false); + } + else { + ifromfile->set_active (true); + oldip = pp->icm.input.substr(5); + ipDialog->set_filename (pp->icm.input.substr(5)); + igamma->set_sensitive (true); + } + + wnames->set_active_text (pp->icm.working); + if (pp->icm.output=="No ICM: sRGB output") + onames->set_active_text (M("TP_ICM_NOICM")); + else + onames->set_active_text (pp->icm.output); + + if (onames->get_active_row_number()==-1) + onames->set_active_text (M("TP_ICM_NOICM")); + + igamma->set_active (pp->icm.gammaOnInput); + + if (pedited) { + iunchanged->set_active (!pedited->icm.input); + igamma->set_sensitive (false); + if (!pedited->icm.working) + wnames->set_active_text("(Unchanged)"); + if (!pedited->icm.output) + onames->set_active_text("(Unchanged)"); + } + + ipc.block (false); + + enableListener (); +} + +void ICMPanel::write (ProcParams* pp, ParamsEdited* pedited) { + + if (iembedded->get_active ()) + pp->icm.input = "(embedded)"; + else if (icamera->get_active ()) + pp->icm.input = "(camera)"; + else + pp->icm.input = "file:"+ipDialog->get_filename (); + + pp->icm.working = wnames->get_active_text (); + + if (onames->get_active_text()==M("TP_ICM_NOICM")) + pp->icm.output = "No ICM: sRGB output"; + else + pp->icm.output = onames->get_active_text(); + pp->icm.gammaOnInput = igamma->get_active (); + + if (pedited) { + pedited->icm.input = !iunchanged->get_active (); + pedited->icm.working = wnames->get_active_text()!="(Unchanged)"; + pedited->icm.output = onames->get_active_text()!="(Unchanged)"; + pedited->icm.gammaOnInput = !ifromfile->get_active (); + } +} + +void ICMPanel::wpChanged () { + + if (listener) + listener->panelChanged (EvWProfile, wnames->get_active_text ()); +} + +void ICMPanel::ipChanged () { + + std::string profname; + if (iembedded->get_active ()) { + profname = "(embedded)"; + igamma->set_sensitive (false); + } + else if (icamera->get_active ()) { + profname = "(camera)"; + igamma->set_sensitive (false); + } + else { + profname = ipDialog->get_filename (); + igamma->set_sensitive (true); + } + + if (listener && profname!=oldip) + listener->panelChanged (EvIProfile, profname); + + oldip = profname; +} + +void ICMPanel::opChanged () { + + if (listener) + listener->panelChanged (EvOProfile, onames->get_active_text()); +} + +void ICMPanel::setRaw (bool raw) { + + disableListener (); + + icamera->set_active (raw); + iembedded->set_active (!raw); + icamera->set_sensitive (raw); + iembedded->set_sensitive (!raw); + + enableListener (); +} + +void ICMPanel::ipSelectionChanged () { + + if (ipDialog->get_filename () == "") + return; + else + ipChanged (); + +} +void ICMPanel::saveReferencePressed () { + + if (!icmplistener) + return; + Gtk::FileChooserDialog dialog(M("TP_ICM_SAVEREFERENCEDLGLABEL"), Gtk::FILE_CHOOSER_ACTION_SAVE); + + dialog.add_button(Gtk::StockID("gtk-cancel"), Gtk::RESPONSE_CANCEL); + dialog.add_button(Gtk::StockID("gtk-save"), Gtk::RESPONSE_OK); + + Gtk::FileFilter filter_jpg; + filter_jpg.set_name(M("SAVEDLG_JPGFILTER")); + filter_jpg.add_pattern("*.jpg"); + dialog.add_filter(filter_jpg); + + dialog.set_do_overwrite_confirmation (true); + + if (dialog.run()==Gtk::RESPONSE_OK) + icmplistener->saveInputICCReference (dialog.get_filename()); + +} +void ICMPanel::setBatchMode (bool batchMode) { + + ToolPanel::setBatchMode (batchMode); + iunchanged = Gtk::manage (new Gtk::RadioButton ("(Unchanged)")); + iunchanged->set_group (opts); + pack_start (*iunchanged, Gtk::PACK_SHRINK, 4); + reorder_child (*iunchanged, 5); + removeIfThere (this, saveRef); + onames->append_text ("(Unchanged)"); + wnames->append_text ("(Unchanged)"); +} + diff --git a/rtgui/icmpanel.h b/rtgui/icmpanel.h new file mode 100755 index 000000000..072ecfff3 --- /dev/null +++ b/rtgui/icmpanel.h @@ -0,0 +1,70 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _ICMPANEL_ +#define _ICMPANEL_ + +#include +#include + +class ICMPanelListener { + + public: + virtual void saveInputICCReference (Glib::ustring fname) {} +}; + +class ICMPanel : public Gtk::VBox, public ToolPanel { + + private: + Gtk::RadioButton* iembedded; + Gtk::RadioButton* icamera; + Gtk::RadioButton* ifromfile; + Gtk::CheckButton* igamma; + Gtk::ComboBoxText* wnames; + Gtk::ComboBoxText* onames; + Gtk::RadioButton* ofromdir; + Gtk::RadioButton* ofromfile; + Gtk::RadioButton* iunchanged; + Gtk::FileChooserButton* ipDialog; + Gtk::FileChooserButton* opDialog; + Gtk::RadioButton::Group opts; + Gtk::Button* saveRef; + sigc::connection ipc; + Glib::ustring oldip; + ICMPanelListener* icmplistener; + + public: + ICMPanel (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + + void wpChanged (); + void opChanged (); + void ipChanged (); + + void ipSelectionChanged (); + + void setRaw (bool raw); + void saveReferencePressed (); + + void setICMPanelListener (ICMPanelListener* ipl) { icmplistener = ipl; } +}; + +#endif diff --git a/rtgui/ilabel.cc b/rtgui/ilabel.cc new file mode 100755 index 000000000..c576498b9 --- /dev/null +++ b/rtgui/ilabel.cc @@ -0,0 +1,63 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +ILabel::ILabel (Glib::ustring lab) : label(lab) {} + +void ILabel::on_realize() { + + Gtk::DrawingArea::on_realize(); + add_events(Gdk::EXPOSURE_MASK); + + Glib::RefPtr fn = create_pango_layout(label); + fn->set_markup (label); + int labw, labh; + fn->get_pixel_size (labw, labh); + set_size_request (2+labw,2+labh); + + signal_style_changed().connect( sigc::mem_fun(*this, &ILabel::styleChanged) ); +} + +bool ILabel::on_expose_event (GdkEventExpose* event) { + + Glib::RefPtr style = get_style (); + Glib::RefPtr window = get_window(); + Glib::RefPtr gc_ = style->get_bg_gc(get_state()); + Cairo::RefPtr cr = window->create_cairo_context(); + + Gdk::Color c = style->get_fg (get_state()); + cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p()); + cr->rectangle (0, 0, get_width (), get_height()); + cr->fill (); + + Glib::RefPtr fn = create_pango_layout (label); + fn->set_markup (label); + window->draw_layout(gc_, 1, 1, fn); + + return true; +} + +void ILabel::styleChanged (const Glib::RefPtr& style) { + + Glib::RefPtr fn = create_pango_layout(label); + fn->set_markup (label); + int labw, labh; + fn->get_pixel_size (labw, labh); + set_size_request (2+labw,2+labh); +} diff --git a/rtgui/ilabel.h b/rtgui/ilabel.h new file mode 100755 index 000000000..50a6fd942 --- /dev/null +++ b/rtgui/ilabel.h @@ -0,0 +1,36 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _ILABEL_ +#define _ILABEL_ + +#include + +class ILabel : public Gtk::DrawingArea { + + Glib::ustring label; + + public: + ILabel (Glib::ustring lab); + bool on_expose_event(GdkEventExpose* event); + void on_realize(); + void styleChanged (const Glib::RefPtr& style); +}; + +#endif + diff --git a/rtgui/imagearea.cc b/rtgui/imagearea.cc new file mode 100755 index 000000000..8fbeeeda6 --- /dev/null +++ b/rtgui/imagearea.cc @@ -0,0 +1,418 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include +#include +#include +#include + +ImageArea::ImageArea (ImageAreaPanel* p) : parent(p) { + + showInfo = false; + infotext = ""; + cropgl = NULL; + pmlistener = NULL; + focusGrabber = NULL; + mainCropWindow = NULL; + previewHandler = NULL; + lastClosedX = -1; + showClippedH = false; + showClippedS = false; + listener = NULL; + + zoomPanel = Gtk::manage (new ZoomPanel (this)); + indClippedPanel = Gtk::manage (new IndicateClippedPanel (this)); + + signal_style_changed().connect( sigc::mem_fun(*this, &ImageArea::styleChanged) ); + signal_size_allocate().connect( sigc::mem_fun(*this, &ImageArea::on_resized) ); + + dirty = false; +} + +void ImageArea::on_realize() +{ + Gtk::DrawingArea::on_realize(); + + add_events(Gdk::EXPOSURE_MASK | Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::SCROLL_MASK); + + Cairo::FontOptions cfo; + cfo.set_antialias (Cairo::ANTIALIAS_SUBPIXEL); + get_pango_context ()->set_cairo_font_options (cfo); +} + +void ImageArea::on_resized (Gtk::Allocation& req) { + + if (ipc && !mainCropWindow) { + mainCropWindow = new CropWindow (this, ipc); + mainCropWindow->setDecorated (false); + mainCropWindow->setFitZoomEnabled (true); + mainCropWindow->setPosition (0, 0); + mainCropWindow->setSize (get_width(), get_height()); + mainCropWindow->addCropWindowListener (this); + mainCropWindow->setCropGUIListener (cropgl); + mainCropWindow->setPointerMotionListener (pmlistener); + } + else if (ipc) { + mainCropWindow->setSize (get_width(), get_height()); + } +} + +void ImageArea::setImProcCoordinator (rtengine::StagedImageProcessor* ipc_) { + + ipc = ipc_; +} + +void ImageArea::setPreviewHandler (PreviewHandler* ph) { + + previewHandler = ph; +} + + +ImageArea::~ImageArea () { + + for (std::list::iterator i=cropWins.begin(); i!=cropWins.end(); i++) + delete *i; + cropWins.clear (); + + if (mainCropWindow) + delete mainCropWindow; +} + +void ImageArea::styleChanged (const Glib::RefPtr& style) { + + // TODO: notify all crop windows that the style has been changed + queue_draw (); +} + +void ImageArea::setInfoText (Glib::ustring text) { + + infotext = text; + + Glib::RefPtr context = get_pango_context () ; + Pango::FontDescription fontd = context->get_font_description (); + fontd.set_weight (Pango::WEIGHT_BOLD); + fontd.set_size (12*Pango::SCALE); + context->set_font_description (fontd); + ilayout = create_pango_layout(text); + int iw, ih; + ilayout->get_pixel_size (iw, ih); + ipixbuf = Gdk::Pixbuf::create (Gdk::COLORSPACE_RGB, true, 8, iw+8, ih+8); + ipixbuf->fill (128); +} + +void ImageArea::infoEnabled (bool e) { + + if (showInfo!=e) { + showInfo = e; + queue_draw (); + } +} + +CropWindow* ImageArea::getCropWindow (int x, int y) { + + CropWindow* cw = mainCropWindow; + for (std::list::iterator i=cropWins.begin(); i!=cropWins.end(); i++) + if ((*i)->isInside (x, y)) + return *i; + return cw; +} + +bool ImageArea::on_expose_event(GdkEventExpose* event) { + dirty = false; + + if (event->count) + return true; + + Glib::RefPtr window = get_window(); + Cairo::RefPtr cr = get_window()->create_cairo_context(); + + if (mainCropWindow) + mainCropWindow->expose (cr); + + if (showInfo==true && infotext!="") { + int fnw, fnh; + ilayout->get_pixel_size (fnw, fnh); + window->draw_pixbuf (get_style()->get_base_gc (Gtk::STATE_NORMAL), ipixbuf, 0, 0, 4, 4, fnw+8, fnh+8, Gdk::RGB_DITHER_NONE, 0, 0); + cr->set_source_rgb (1.0, 1.0, 1.0); + cr->move_to (8, 8); + ilayout->add_to_cairo_context (cr); + cr->fill (); + } + + for (std::list::reverse_iterator i=cropWins.rbegin(); i!=cropWins.rend(); i++) + (*i)->expose (cr); + + return true; +} + + +bool ImageArea::on_motion_notify_event (GdkEventMotion* event) { + + if (focusGrabber) + focusGrabber->pointerMoved (event->x, event->y); + else { + CropWindow* cw = getCropWindow (event->x, event->y); + if (cw) + cw->pointerMoved (event->x, event->y); + } + return true; +} + +bool ImageArea::on_button_press_event (GdkEventButton* event) { + + if (focusGrabber) + focusGrabber->buttonPress (event->button, event->type, event->state, event->x, event->y); + else { + CropWindow* cw = getCropWindow (event->x, event->y); + if (cw) + cw->buttonPress (event->button, event->type, event->state, event->x, event->y); + } + return true; +} + +bool ImageArea::on_scroll_event (GdkEventScroll* event) { + + CropWindow* cw = getCropWindow (event->x, event->y); + if (cw) { + if (event->direction==GDK_SCROLL_UP) + cw->zoomIn (); + else + cw->zoomOut (); + return true; + } + return true; +} + +bool ImageArea::on_button_release_event (GdkEventButton* event) { + + if (focusGrabber) + focusGrabber->buttonRelease (event->button, event->type, event->state, event->x, event->y); + else { + CropWindow* cw = getCropWindow (event->x, event->y); + if (cw) { + cw->buttonRelease (event->button, event->type, event->state, event->x, event->y); + } + } + return true; +} + + +void ImageArea::grabFocus (CropWindow* cw) { + + focusGrabber = cw; + if (cw && cw!=mainCropWindow) + cropWindowSelected (cw); +} + +void ImageArea::unGrabFocus () { + + focusGrabber = NULL; +} + +void ImageArea::addCropWindow () { + + CropWindow* cw = new CropWindow (this, ipc); + cw->setCropGUIListener (cropgl); + cw->setPointerMotionListener (pmlistener); + cropWins.push_front (cw); + + if (lastClosedX<0) { + int K = 2; + int hBorder = get_width()/K/8; + int vBorder = get_height()/K/8; + int N = cropWins.size()-1; + int layer = N/K/K; + int row = K-1 - (N % (K*K)) / K; + int col = K-1 - (N % (K*K)) % K; + + cw->setSize (get_width()/K - hBorder, get_height()/K - vBorder); + cw->setPosition (col*get_width()/K + hBorder/2 + layer*30, row*get_height()/K + vBorder/2 + layer*30); + } + else { + cw->setSize (lastClosedX, lastClosedY); + cw->setPosition (lastClosedW, lastClosedH); + } + + mainCropWindow->setObservedCropWin (cropWins.front()); + queue_draw (); +} + + +void ImageArea::cropWindowSelected (CropWindow* cw) { + + std::list::iterator i = std::find (cropWins.begin(), cropWins.end(), cw); + if (i!=cropWins.end()) + cropWins.erase (i); + cropWins.push_front (cw); + mainCropWindow->setObservedCropWin (cropWins.front()); +} + +void ImageArea::cropWindowClosed (CropWindow* cw) { + + focusGrabber = NULL; + cw->getPosition (lastClosedX, lastClosedY); + cw->getSize (lastClosedW, lastClosedH); + std::list::iterator i = std::find (cropWins.begin(), cropWins.end(), cw); + if (i!=cropWins.end()) + cropWins.erase (i); + delete cw; + if (!cropWins.empty()) + mainCropWindow->setObservedCropWin (cropWins.front()); + else + mainCropWindow->setObservedCropWin (NULL); + queue_draw (); +} + +void ImageArea::straightenReady (double rotDeg) { + + if (listener) + listener->rotateSelectionReady (rotDeg); +} + +void ImageArea::spotWBSelected (int x, int y) { + + if (listener) + listener->spotWBselected (x, y); +} + +void ImageArea::redraw () { + + if (!dirty) { + dirty = true; + queue_draw (); + } +} + +void ImageArea::getScrollImageSize (int& w, int& h) { + + if (mainCropWindow && ipc) { + double z = mainCropWindow->getZoom (); + w = ipc->getFullWidth() * z; + h = ipc->getFullHeight() * z; + } + else + w = h = 0; +} + +void ImageArea::getScrollPosition (int& x, int& y) { + + if (mainCropWindow) { + int cropX, cropY; + mainCropWindow->getCropPosition (cropX, cropY); + x = cropX*mainCropWindow->getZoom (); + y = cropY*mainCropWindow->getZoom (); + } + else + x = y = 0; +} + +void ImageArea::setScrollPosition (int x, int y) { + + if (mainCropWindow) { + mainCropWindow->delCropWindowListener (this); + mainCropWindow->setCropPosition (x/mainCropWindow->getZoom (), y/mainCropWindow->getZoom ()); + mainCropWindow->addCropWindowListener (this); + } +} + +void ImageArea::cropPositionChanged (CropWindow* cw) { + + updateScrollbars (); +} + +void ImageArea::cropWindowSizeChanged (CropWindow* cw) { + + updateScrollbars (); +} + +void ImageArea::cropZoomChanged (CropWindow* cw) { + + if (cw==mainCropWindow) { + parent->zoomChanged (); + updateScrollbars (); + zoomPanel->refreshZoomLabel (); + } +} + +double ImageArea::getZoom () { + + if (mainCropWindow) + return mainCropWindow->getZoom (); + else + return 1.0; +} + +void ImageArea::setZoom (double zoom) { + + if (mainCropWindow) + mainCropWindow->setZoom (zoom); + zoomPanel->refreshZoomLabel (); +} + +void ImageArea::initialImageArrived (CropWindow* cw) { + + if (mainCropWindow) + mainCropWindow->zoomFit (); +} + +void ImageArea::updateScrollbars () { + parent->refreshScrollBars (); +} + +void ImageArea::setCropGUIListener (CropGUIListener* l) { + + cropgl = l; + for (std::list::iterator i=cropWins.begin(); i!=cropWins.end(); i++) + (*i)->setCropGUIListener (cropgl); + if (mainCropWindow) + mainCropWindow->setCropGUIListener (cropgl); +} + +void ImageArea::setPointerMotionListener (PointerMotionListener* pml) { + + pmlistener = pml; + for (std::list::iterator i=cropWins.begin(); i!=cropWins.end(); i++) + (*i)->setPointerMotionListener (pml); + if (mainCropWindow) + mainCropWindow->setPointerMotionListener (pml); +} + +ToolMode ImageArea::getToolMode () { + + if (listener) + return listener->getToolBar()->getTool (); + else + return TMHand; +} + +void ImageArea::setToolHand () { + + if (listener) + listener->getToolBar()->setTool (TMHand); +} + +int ImageArea::getSpotWBRectSize () { + + if (listener) + return listener->getSpotWBRectSize (); + else + return 1; +} diff --git a/rtgui/imagearea.h b/rtgui/imagearea.h new file mode 100755 index 000000000..bb7163e40 --- /dev/null +++ b/rtgui/imagearea.h @@ -0,0 +1,125 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef __IMAGEAREA_H__ +#define __IMAGEAREA_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class ImageAreaPanel; +class ImageArea : public Gtk::DrawingArea, public CropWindowListener { + + friend class ZoomPanel; + + protected: + + bool showInfo; + Glib::ustring infotext; + Glib::RefPtr ilayout; + Glib::RefPtr deglayout; + Glib::RefPtr ipixbuf; + bool showClippedH, showClippedS; + + ImageAreaPanel* parent; + CropWindow* mainCropWindow; + std::list cropWins; + PreviewHandler* previewHandler; + rtengine::StagedImageProcessor* ipc; + + int lastClosedX, lastClosedY, lastClosedW, lastClosedH; + + bool dirty; + CropWindow* focusGrabber; + CropGUIListener* cropgl; + PointerMotionListener* pmlistener; + ImageAreaToolListener* listener; + + CropWindow* getCropWindow (int x, int y); + + public: + + ZoomPanel* zoomPanel; + IndicateClippedPanel* indClippedPanel; + + ImageArea (ImageAreaPanel* p); + ~ImageArea (); + + void setImProcCoordinator (rtengine::StagedImageProcessor* ipc_); + + void getScrollImageSize (int& w, int& h); + void getScrollPosition (int& x, int& y); + void setScrollPosition (int x, int y); // called by the imageareapanel when the scrollbars have been changed + + // enabling and setting text of info area + void setInfoText (Glib::ustring text); + void infoEnabled (bool e); + + // widget base events + void on_realize (); + bool on_expose_event (GdkEventExpose* event); + bool on_motion_notify_event (GdkEventMotion* event); + bool on_button_press_event (GdkEventButton* event); + bool on_button_release_event (GdkEventButton* event); + bool on_scroll_event (GdkEventScroll* event); + void on_resized (Gtk::Allocation& req); + void styleChanged (const Glib::RefPtr& style); + void updateScrollbars (); + + void setCropGUIListener (CropGUIListener* l); + void setPointerMotionListener (PointerMotionListener* pml); + void setImageAreaToolListener (ImageAreaToolListener* l) { listener = l; } + void setPreviewHandler (PreviewHandler* ph); + PreviewHandler* getPreviewHandler () { return previewHandler; } + + void grabFocus (CropWindow* cw); + void unGrabFocus (); + void addCropWindow (); + void cropWindowSelected (CropWindow* cw); + void cropWindowClosed (CropWindow* cw); + ToolMode getToolMode (); + void setToolHand (); + void straightenReady (double rotDeg); + void spotWBSelected (int x, int y); + int getSpotWBRectSize (); + void redraw (); + + void zoomFit (); + double getZoom (); + void setZoom (double zoom); + + // cropwindowlistener interface + void cropPositionChanged (CropWindow* cw); + void cropWindowSizeChanged (CropWindow* cw); + void cropZoomChanged (CropWindow* cw); + void initialImageArrived (CropWindow* cw) ; + + CropWindow* getMainCropWindow () { return mainCropWindow; } +}; + + + +#endif diff --git a/rtgui/imageareapanel.cc b/rtgui/imageareapanel.cc new file mode 100755 index 000000000..ecafd0446 --- /dev/null +++ b/rtgui/imageareapanel.cc @@ -0,0 +1,173 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +ImageAreaPanel::ImageAreaPanel () : before(NULL), after(NULL) { + + set_border_width (2); + + Gtk::HBox* hb1 = Gtk::manage (new Gtk::HBox ()); + Gtk::HBox* hb2 = Gtk::manage (new Gtk::HBox ()); + hscroll = Gtk::manage (new Gtk::HScrollbar ()); + vscroll = Gtk::manage (new Gtk::VScrollbar ()); + imageArea = new ImageArea (this); + Gtk::Frame* frame = Gtk::manage (new Gtk::Frame ()); + frame->add (*imageArea); + frame->set_shadow_type (Gtk::SHADOW_IN ); + hb1->pack_start (*frame); + hb1->pack_end (*vscroll, Gtk::PACK_SHRINK, 0); + + pack_start (*hb1); + vscroll->show (); + frame->show (); + imageArea->show (); + hb1->show (); + + Gtk::HBox* tmp = Gtk::manage (new Gtk::HBox ()); + hb2->pack_start (*hscroll); + Gtk::Requisition vcr = vscroll->size_request (); + tmp->set_size_request (vcr.width, vcr.width); + hb2->pack_end (*tmp, Gtk::PACK_SHRINK, 0); + + pack_start (*hb2,Gtk::PACK_SHRINK, 0); + hscroll->show (); + tmp->show (); + hb2->show (); + + hscroll->set_update_policy (Gtk::UPDATE_CONTINUOUS); + vscroll->set_update_policy (Gtk::UPDATE_CONTINUOUS); + + vscrollconn = vscroll->signal_value_changed().connect( sigc::mem_fun(*this, &ImageAreaPanel::scrollChanged) ); + hscrollconn = hscroll->signal_value_changed().connect( sigc::mem_fun(*this, &ImageAreaPanel::scrollChanged) ); + + imageArea->signal_size_allocate().connect( sigc::mem_fun(*this, &ImageAreaPanel::imageAreaResized) ); +} + +ImageAreaPanel::~ImageAreaPanel () { + + delete imageArea; +} + +void ImageAreaPanel::configScrollBars () { + + int imgw, imgh; + imageArea->getScrollImageSize (imgw, imgh); + + if (imgw>0 && imgh>0) { + + int iw = imageArea->get_width (); + int ih = imageArea->get_height (); + + hscrollconn.block (true); + vscrollconn.block (true); + + hscroll->get_adjustment()->set_upper (imgw); + vscroll->get_adjustment()->set_upper (imgh); + hscroll->get_adjustment()->set_lower (0); + vscroll->get_adjustment()->set_lower (0); + hscroll->get_adjustment()->set_step_increment (imgw/100); + vscroll->get_adjustment()->set_step_increment (imgh/100); + hscroll->get_adjustment()->set_page_increment (imgw/5); + vscroll->get_adjustment()->set_page_increment (imgh/5); + hscroll->get_adjustment()->set_page_size (iw); + vscroll->get_adjustment()->set_page_size (ih); + + int x, y; + imageArea->getScrollPosition (x, y); + hscroll->set_value (x); + vscroll->set_value (y); + + if (before && this==after) + before->synchronize (); + else if (after && this==before) + after->synchronize (); + + hscrollconn.block (false); + vscrollconn.block (false); + } +} + +void ImageAreaPanel::refreshScrollBars () { + + configScrollBars (); + queue_draw (); +} + +void ImageAreaPanel::imageAreaResized (Gtk::Allocation& req) { + + configScrollBars (); + queue_draw (); +} + +void ImageAreaPanel::scrollChanged () { + + imageArea->setScrollPosition ((int)(hscroll->get_value()), (int)(vscroll->get_value())); + imageArea->queue_draw (); +#ifdef _WIN32 + gdk_window_process_updates (get_window()->gobj(), true); +#endif + if (before && this==after) + before->synchronize (); + else if (after && this==before) + after->synchronize (); +} + +void ImageAreaPanel::setBeforeAfterViews (ImageAreaPanel* bef, ImageAreaPanel* aft) { + + before = bef; + after = aft; + configScrollBars (); +} + +void ImageAreaPanel::zoomChanged () { + + if (after && this==before) + after->imageArea->setZoom (imageArea->getZoom ()); + else if (before && this==after) + before->imageArea->setZoom (imageArea->getZoom ()); +} + +void ImageAreaPanel::synchronize () { + + hscrollconn.block (true); + vscrollconn.block (true); + + if (after && this==before) { + int imgw, imgh, x, y; + after->imageArea->getScrollImageSize (imgw, imgh); + after->imageArea->getScrollPosition (x, y); + int bimgw, bimgh; + imageArea->getScrollImageSize (bimgw, bimgh); + imageArea->setScrollPosition (x*bimgw/imgw, y*bimgh/imgh); + imageArea->queue_draw (); + } + else if (before && this==after) { + int imgw, imgh, x, y; + before->imageArea->getScrollImageSize (imgw, imgh); + before->imageArea->getScrollPosition (x, y); + int bimgw, bimgh; + imageArea->getScrollImageSize (bimgw, bimgh); + imageArea->setScrollPosition (x*bimgw/imgw, y*bimgh/imgh); + imageArea->queue_draw (); + } + + hscrollconn.block (false); + vscrollconn.block (false); +} + diff --git a/rtgui/imageareapanel.h b/rtgui/imageareapanel.h new file mode 100755 index 000000000..50a1d4644 --- /dev/null +++ b/rtgui/imageareapanel.h @@ -0,0 +1,53 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _IMAGEAREAPANEL_ +#define _IMAGEAREAPANEL_ + +#include + +class ImageArea; +class ImageAreaPanel : public Gtk::VBox { + + protected: + Gtk::HScrollbar* hscroll; + Gtk::VScrollbar* vscroll; + sigc::connection hscrollconn; + sigc::connection vscrollconn; + + void synchronize (); + void configScrollBars (); + + ImageAreaPanel *before, *after; + + public: + ImageArea* imageArea; + + ImageAreaPanel (); + ~ImageAreaPanel (); + + void scrollChanged (); + void imageAreaResized (Gtk::Allocation& req); + + void refreshScrollBars (); + void zoomChanged (); + + void setBeforeAfterViews (ImageAreaPanel* bef, ImageAreaPanel* aft); +}; + +#endif diff --git a/rtgui/imageareatoollistener.h b/rtgui/imageareatoollistener.h new file mode 100755 index 000000000..a1d1d7ac1 --- /dev/null +++ b/rtgui/imageareatoollistener.h @@ -0,0 +1,38 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _IMAGEAREATOOLLISTENER_ +#define _IMAGEAREATOOLLISTENER_ + +#include +#include +#include + +class ImageAreaToolListener { + + public: + virtual void spotWBselected (int x, int y, Thumbnail* thm=NULL) {} + virtual int getSpotWBRectSize () { return 8; } + virtual void cropSelectionReady () {} + virtual void rotateSelectionReady (double rotate_deg, Thumbnail* thm=NULL) {} + virtual ToolBar* getToolBar () { return NULL; } + virtual CropGUIListener* startCropEditing (Thumbnail* thm=NULL) { return NULL; } +}; + +#endif + diff --git a/rtgui/indclippedpanel.cc b/rtgui/indclippedpanel.cc new file mode 100755 index 000000000..61924c60c --- /dev/null +++ b/rtgui/indclippedpanel.cc @@ -0,0 +1,51 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include + +IndicateClippedPanel::IndicateClippedPanel (ImageArea* ia) : imageArea(ia) { + + indclippedh = Gtk::manage (new Gtk::ToggleButton ()); + indclippedh->set_relief(Gtk::RELIEF_NONE); + indclippedh->add (*Gtk::manage (new Gtk::Image (argv0+"/images/warnhl.png"))); + indclippedh->set_tooltip_text (M("MAIN_TOOLTIP_INDCLIPPEDH")); + + indclippeds = Gtk::manage (new Gtk::ToggleButton ()); + indclippeds->set_relief(Gtk::RELIEF_NONE); + indclippeds->add (*Gtk::manage (new Gtk::Image (argv0+"/images/warnsh.png"))); + indclippeds->set_tooltip_text (M("MAIN_TOOLTIP_INDCLIPPEDS")); + + indclippedh->set_active (options.showClippedHighlights); + indclippeds->set_active (options.showClippedShadows); + + pack_start (*indclippedh, Gtk::PACK_SHRINK, 0); + pack_start (*indclippeds, Gtk::PACK_SHRINK, 0); + + indclippedh->signal_toggled().connect( sigc::mem_fun(*this, &IndicateClippedPanel::buttonToggled) ); + indclippeds->signal_toggled().connect( sigc::mem_fun(*this, &IndicateClippedPanel::buttonToggled) ); + + show_all (); +} + +void IndicateClippedPanel::buttonToggled () { + + imageArea->queue_draw (); +} diff --git a/rtgui/indclippedpanel.h b/rtgui/indclippedpanel.h new file mode 100755 index 000000000..8acaccdf9 --- /dev/null +++ b/rtgui/indclippedpanel.h @@ -0,0 +1,41 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _INDCLIPPEDPANEL_ +#define _INDCLIPPEDPANEL_ + +#include + +class ImageArea; +class IndicateClippedPanel : public Gtk::HBox { + + protected: + Gtk::ToggleButton* indclippedh; + Gtk::ToggleButton* indclippeds; + ImageArea* imageArea; + + public: + IndicateClippedPanel (ImageArea* ia); + + void buttonToggled (); + + bool showClippedShadows () { return indclippeds->get_active (); } + bool showClippedHighlights () { return indclippedh->get_active (); } +}; + +#endif diff --git a/rtgui/iptcpanel.cc b/rtgui/iptcpanel.cc new file mode 100755 index 000000000..9c3eb7996 --- /dev/null +++ b/rtgui/iptcpanel.cc @@ -0,0 +1,600 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +extern Glib::ustring argv0; + +using namespace rtengine; +using namespace rtengine::procparams; + +IPTCPanel::IPTCPanel () { + + set_border_width (2); + + Gtk::Table* iptc = new Gtk::Table (27, 2); + + int row = 0; + + Gtk::Label* capl = new Gtk::Label (M("IPTCPANEL_CAPTION")+":"); + captionText = Gtk::TextBuffer::create (); + captionView = new Gtk::TextView (captionText); + Gtk::ScrolledWindow* scrolledWindowc = new Gtk::ScrolledWindow(); + scrolledWindowc->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS); + scrolledWindowc->add(*captionView); + capl->set_tooltip_text (M("IPTCPANEL_CAPTIONHINT")); + captionView->set_tooltip_text (M("IPTCPANEL_CAPTIONHINT")); + iptc->attach (*capl, 0, 1, row, row+1, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + iptc->attach (*scrolledWindowc, 1, 2, row, row+1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + + row++; + + Gtk::Label* capwl = new Gtk::Label (M("IPTCPANEL_CAPTIONWRITER")+":"); + captionWriter = new Gtk::Entry (); + capwl->set_tooltip_text (M("IPTCPANEL_CAPTIONWRITERHINT")); + captionWriter->set_tooltip_text (M("IPTCPANEL_CAPTIONWRITERHINT")); + iptc->attach (*capwl, 0, 1, row, row+1, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + iptc->attach (*captionWriter, 1, 2, row, row+1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + + row++; + + Gtk::Label* headl = new Gtk::Label (M("IPTCPANEL_HEADLINE")+":"); + headline = new Gtk::Entry (); + headl->set_tooltip_text (M("IPTCPANEL_HEADLINEHINT")); + headline->set_tooltip_text (M("IPTCPANEL_HEADLINEHINT")); + iptc->attach (*headl, 0, 1, row, row+1, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + iptc->attach (*headline, 1, 2, row, row+1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + + row++; + + Gtk::Label* instl = new Gtk::Label (M("IPTCPANEL_INSTRUCTIONS")+":"); + instructions = new Gtk::Entry (); + instl->set_tooltip_text (M("IPTCPANEL_INSTRUCTIONSHINT")); + instructions->set_tooltip_text (M("IPTCPANEL_INSTRUCTIONSHINT")); + iptc->attach (*instl, 0, 1, row, row+1, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + iptc->attach (*instructions, 1, 2, row, row+1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + + row++; + + Gtk::HSeparator* hsep1 = new Gtk::HSeparator (); + iptc->attach (*hsep1, 0, 2, row, row+1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + + row++; + + Gtk::Label* keyl = new Gtk::Label (M("IPTCPANEL_KEYWORDS")+":"); + keywords = new Gtk::ListViewText (1, false, Gtk::SELECTION_MULTIPLE); + keywords->set_headers_visible (false); + Gtk::ScrolledWindow* scrolledWindowkw = new Gtk::ScrolledWindow(); + scrolledWindowkw->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS); + scrolledWindowkw->add(*keywords); + keyword = new Gtk::ComboBoxEntryText (); + keyword->set_size_request (32, -1); + keyl->set_tooltip_text (M("IPTCPANEL_KEYWORDSHINT")); + keywords->set_tooltip_text (M("IPTCPANEL_KEYWORDSHINT")); + keyword->set_tooltip_text (M("IPTCPANEL_KEYWORDSHINT")); + addKW = new Gtk::Button (); + delKW = new Gtk::Button (); + Gtk::Image* addKWImg = new Gtk::Image (argv0+"/images/list-add12.png"); + Gtk::Image* delKWImg = new Gtk::Image (argv0+"/images/list-remove12r.png"); + addKW->add (*addKWImg); + delKW->add (*delKWImg); + Gtk::HBox* kwhb = new Gtk::HBox (); + kwhb->pack_start (*keyword); + kwhb->pack_start (*addKW, Gtk::PACK_SHRINK, 2); + kwhb->pack_start (*delKW, Gtk::PACK_SHRINK, 2); + iptc->attach (*keyl, 0, 1, row, row+1, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + iptc->attach (*kwhb, 1, 2, row, row+1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + row++; + iptc->attach (*scrolledWindowkw, 0, 2, row, row+1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + row++; + + Gtk::HSeparator* hsep2 = new Gtk::HSeparator (); + iptc->attach (*hsep2, 0, 2, row, row+1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + row++; + + Gtk::Label* catl = new Gtk::Label (M("IPTCPANEL_CATEGORY")+":"); + category = new Gtk::ComboBoxEntryText (); + category->set_size_request (32, -1); + catl->set_tooltip_text (M("IPTCPANEL_CATEGORYHINT")); + category->set_tooltip_text (M("IPTCPANEL_CATEGORYHINT")); + Gtk::Label* scl = new Gtk::Label (M("IPTCPANEL_SUPPCATEGORIES")+":"); + suppCategories = new Gtk::ListViewText (1, false, Gtk::SELECTION_MULTIPLE); + suppCategories->set_headers_visible (false); + Gtk::ScrolledWindow* scrolledWindowsc = new Gtk::ScrolledWindow(); + scrolledWindowsc->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS); + scrolledWindowsc->add(*suppCategories); + suppCategory = new Gtk::ComboBoxEntryText (); + suppCategory->set_size_request (32, -1); + scl->set_tooltip_text (M("IPTCPANEL_SUPPCATEGORIESHINT")); + suppCategories->set_tooltip_text (M("IPTCPANEL_SUPPCATEGORIESHINT")); + suppCategory->set_tooltip_text (M("IPTCPANEL_SUPPCATEGORIESHINT")); + addSC = new Gtk::Button (); + delSC = new Gtk::Button (); + Gtk::Image* addSCImg = new Gtk::Image (argv0+"/images/list-add12.png"); + Gtk::Image* delSCImg = new Gtk::Image (argv0+"/images/list-remove12r.png"); + addSC->add (*addSCImg); + delSC->add (*delSCImg); + Gtk::HBox* schb = new Gtk::HBox (); + schb->pack_start (*suppCategory); + schb->pack_start (*addSC, Gtk::PACK_SHRINK, 2); + schb->pack_start (*delSC, Gtk::PACK_SHRINK, 2); + iptc->attach (*catl, 0, 1, row, row+1, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + iptc->attach (*category, 1, 2, row, row+1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + row++; + iptc->attach (*scl, 0, 1, row, row+1, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + iptc->attach (*schb, 1, 2, row, row+1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + row++; + iptc->attach (*scrolledWindowsc, 0, 2, row, row+1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + row++; + + Gtk::HSeparator* hsep3 = new Gtk::HSeparator (); + iptc->attach (*hsep3, 0, 2, row, row+1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + row++; + + Gtk::Label* authl = new Gtk::Label (M("IPTCPANEL_AUTHOR")+":"); + author = new Gtk::Entry (); + authl->set_tooltip_text (M("IPTCPANEL_CREDITHINT")); + author->set_tooltip_text (M("IPTCPANEL_CREDITHINT")); + iptc->attach (*authl, 0, 1, row, row+1, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + iptc->attach (*author, 1, 2, row, row+1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + + row++; + + Gtk::Label* aupl = new Gtk::Label (M("IPTCPANEL_AUTHORSPOSITION")+":"); + authorPos = new Gtk::Entry (); + aupl->set_tooltip_text (M("IPTCPANEL_AUTHORSPOSITIONHINT")); + authorPos->set_tooltip_text (M("IPTCPANEL_AUTHORSPOSITIONHINT")); + iptc->attach (*aupl, 0, 1, row, row+1, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + iptc->attach (*authorPos, 1, 2, row, row+1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + + row++; + + Gtk::Label* credl = new Gtk::Label (M("IPTCPANEL_CREDIT")+":"); + credit = new Gtk::Entry (); + credl->set_tooltip_text (M("IPTCPANEL_CREDITHINT")); + credit->set_tooltip_text (M("IPTCPANEL_CREDITHINT")); + iptc->attach (*credl, 0, 1, row, row+1, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + iptc->attach (*credit, 1, 2, row, row+1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + + row++; + + Gtk::Label* sourl = new Gtk::Label (M("IPTCPANEL_SOURCE")+":"); + source = new Gtk::Entry (); + sourl->set_tooltip_text (M("IPTCPANEL_SOURCEHINT")); + source->set_tooltip_text (M("IPTCPANEL_SOURCEHINT")); + iptc->attach (*sourl, 0, 1, row, row+1, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + iptc->attach (*source, 1, 2, row, row+1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + + row++; + + Gtk::Label* cprl = new Gtk::Label (M("IPTCPANEL_COPYRIGHT")+":"); + copyright = new Gtk::Entry (); + cprl->set_tooltip_text (M("IPTCPANEL_COPYRIGHTHINT")); + copyright->set_tooltip_text (M("IPTCPANEL_COPYRIGHTHINT")); + iptc->attach (*cprl, 0, 1, row, row+1, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + iptc->attach (*copyright, 1, 2, row, row+1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + + row++; + + Gtk::HSeparator* hsep4 = new Gtk::HSeparator (); + iptc->attach (*hsep4, 0, 2, row, row+1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + + row++; + + Gtk::Label* cityl = new Gtk::Label (M("IPTCPANEL_CITY")+":"); + city = new Gtk::Entry (); + cityl->set_tooltip_text (M("IPTCPANEL_CITYHINT")); + city->set_tooltip_text (M("IPTCPANEL_CITYHINT")); + iptc->attach (*cityl, 0, 1, row, row+1, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + iptc->attach (*city, 1, 2, row, row+1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + + row++; + + Gtk::Label* provl = new Gtk::Label (M("IPTCPANEL_PROVINCE")+":"); + province = new Gtk::Entry (); + provl->set_tooltip_text (M("IPTCPANEL_PROVINCEHINT")); + province->set_tooltip_text (M("IPTCPANEL_PROVINCEHINT")); + iptc->attach (*provl, 0, 1, row, row+1, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + iptc->attach (*province, 1, 2, row, row+1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + + row++; + + Gtk::Label* ctrl = new Gtk::Label (M("IPTCPANEL_COUNTRY")+":"); + country = new Gtk::Entry (); + ctrl->set_tooltip_text (M("IPTCPANEL_COUNTRYHINT")); + country->set_tooltip_text (M("IPTCPANEL_COUNTRYHINT")); + iptc->attach (*ctrl, 0, 1, row, row+1, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + iptc->attach (*country, 1, 2, row, row+1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + + row++; + + Gtk::Label* titll = new Gtk::Label (M("IPTCPANEL_TITLE")+":"); + title = new Gtk::Entry (); + titll->set_tooltip_text (M("IPTCPANEL_TITLEHINT")); + title->set_tooltip_text (M("IPTCPANEL_TITLEHINT")); + iptc->attach (*titll, 0, 1, row, row+1, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + iptc->attach (*title, 1, 2, row, row+1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + + row++; + + Gtk::Label* dcl = new Gtk::Label (M("IPTCPANEL_DATECREATED")+":"); + dateCreated = new Gtk::Entry (); + dcl->set_tooltip_text (M("IPTCPANEL_DATECREATEDHINT")); + dateCreated->set_tooltip_text (M("IPTCPANEL_DATECREATEDHINT")); + iptc->attach (*dcl, 0, 1, row, row+1, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + iptc->attach (*dateCreated, 1, 2, row, row+1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + + row++; + + Gtk::Label* trl = new Gtk::Label (M("IPTCPANEL_TRANSREFERENCE")+":"); + transReference = new Gtk::Entry (); + trl->set_tooltip_text (M("IPTCPANEL_TRANSREFERENCEHINT")); + transReference->set_tooltip_text (M("IPTCPANEL_TRANSREFERENCEHINT")); + iptc->attach (*trl, 0, 1, row, row+1, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + iptc->attach (*transReference, 1, 2, row, row+1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + + row++; + + Gtk::ScrolledWindow* scrolledWindow = new Gtk::ScrolledWindow(); + scrolledWindow->set_border_width(2); + scrolledWindow->set_shadow_type(Gtk::SHADOW_NONE); + scrolledWindow->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS); + scrolledWindow->property_window_placement().set_value(Gtk::CORNER_TOP_LEFT); + scrolledWindow->add(*iptc); + + pack_start (*scrolledWindow); + + Gtk::HBox* bbox = new Gtk::HBox (); + + reset = new Gtk::Button (M("IPTCPANEL_RESET")); + reset->set_image (*(new Gtk::Image (Gtk::StockID ("gtk-undo"), Gtk::IconSize (2)))); + bbox->pack_start (*reset); + + file = new Gtk::Button (M("IPTCPANEL_EMBEDDED")); + file->set_image (*(new Gtk::Image (Gtk::StockID ("gtk-open"), Gtk::IconSize (2)))); + bbox->pack_start (*file); + + copy = new Gtk::Button (); + copy->set_image (*(new Gtk::Image (Gtk::StockID ("gtk-copy"), Gtk::IconSize (2)))); + bbox->pack_start (*copy, Gtk::PACK_SHRINK, 0); + + paste = new Gtk::Button (); + paste->set_image (*(new Gtk::Image (Gtk::StockID ("gtk-paste"), Gtk::IconSize (2)))); + bbox->pack_start (*paste, Gtk::PACK_SHRINK, 0); + + pack_end (*bbox, Gtk::PACK_SHRINK, 2); + + Gtk::Tooltips* toolTip = new Gtk::Tooltips (); + toolTip->set_tip (*reset, M("IPTCPANEL_RESETHINT")); + toolTip->set_tip (*file, M("IPTCPANEL_EMBEDDEDHINT")); + toolTip->set_tip (*copy, M("IPTCPANEL_COPYHINT")); + toolTip->set_tip (*paste, M("IPTCPANEL_PASTEHINT")); + + reset->signal_clicked().connect( sigc::mem_fun(*this, &IPTCPanel::resetClicked) ); + file->signal_clicked().connect( sigc::mem_fun(*this, &IPTCPanel::fileClicked) ); + copy->signal_clicked().connect( sigc::mem_fun(*this, &IPTCPanel::copyClicked) ); + paste->signal_clicked().connect( sigc::mem_fun(*this, &IPTCPanel::pasteClicked) ); + + + addKW->signal_clicked().connect( sigc::mem_fun(*this, &IPTCPanel::addKeyWord) ); + delKW->signal_clicked().connect( sigc::mem_fun(*this, &IPTCPanel::delKeyWord) ); + addSC->signal_clicked().connect( sigc::mem_fun(*this, &IPTCPanel::addSuppCategory) ); + delSC->signal_clicked().connect( sigc::mem_fun(*this, &IPTCPanel::delSuppCategory) ); + keyword->get_entry()->signal_activate().connect( sigc::mem_fun(*this, &IPTCPanel::addKeyWord) ); + suppCategory->get_entry()->signal_activate().connect( sigc::mem_fun(*this, &IPTCPanel::addSuppCategory) ); + + conns[0] = captionText->signal_changed().connect( sigc::mem_fun(*this, &IPTCPanel::updateChangeList) ); + conns[1] = captionWriter->signal_changed().connect( sigc::mem_fun(*this, &IPTCPanel::updateChangeList) ); + conns[2] = headline->signal_changed().connect( sigc::mem_fun(*this, &IPTCPanel::updateChangeList) ); + conns[3] = instructions->signal_changed().connect( sigc::mem_fun(*this, &IPTCPanel::updateChangeList) ); + conns[4] = category->get_entry()->signal_changed().connect( sigc::mem_fun(*this, &IPTCPanel::updateChangeList) ); + conns[5] = author->signal_changed().connect( sigc::mem_fun(*this, &IPTCPanel::updateChangeList) ); + conns[6] = authorPos->signal_changed().connect( sigc::mem_fun(*this, &IPTCPanel::updateChangeList) ); + conns[7] = credit->signal_changed().connect( sigc::mem_fun(*this, &IPTCPanel::updateChangeList) ); + conns[8] = source->signal_changed().connect( sigc::mem_fun(*this, &IPTCPanel::updateChangeList) ); + conns[9] = copyright->signal_changed().connect( sigc::mem_fun(*this, &IPTCPanel::updateChangeList) ); + conns[10] = city->signal_changed().connect( sigc::mem_fun(*this, &IPTCPanel::updateChangeList) ); + conns[11] = province->signal_changed().connect( sigc::mem_fun(*this, &IPTCPanel::updateChangeList) ); + conns[12] = country->signal_changed().connect( sigc::mem_fun(*this, &IPTCPanel::updateChangeList) ); + conns[13] = title->signal_changed().connect( sigc::mem_fun(*this, &IPTCPanel::updateChangeList) ); + conns[14] = dateCreated->signal_changed().connect( sigc::mem_fun(*this, &IPTCPanel::updateChangeList) ); + conns[15] = transReference->signal_changed().connect( sigc::mem_fun(*this, &IPTCPanel::updateChangeList) ); + + category->get_entry()->set_max_length (3); + keyword->get_entry()->set_max_length (64); + captionWriter->set_max_length (32); + instructions->set_max_length (256); + author->set_max_length (32); + authorPos->set_max_length (32); + credit->set_max_length (32); + source->set_max_length (32); + copyright->set_max_length (128); + city->set_max_length (32); + province->set_max_length (32); + country->set_max_length (64); + title->set_max_length (64); + dateCreated->set_max_length (8); + transReference->set_max_length (32); + + show_all (); +} + +void IPTCPanel::read (const ProcParams* pp, const ParamsEdited* pedited) { + + disableListener (); + if (pp->iptc.size()>0) + changeList = pp->iptc; + else + changeList = embeddedData; + applyChangeList (); + enableListener (); +} + +void IPTCPanel::write (ProcParams* pp, ParamsEdited* pedited) { + + pp->iptc = changeList; +} + +void IPTCPanel::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { + + defChangeList = defParams->iptc; +} + +void IPTCPanel::setImageData (const ImageMetaData* id) { + + if (id) + embeddedData = id->getIPTCData (); + else + embeddedData.clear (); + + file->set_sensitive (embeddedData.size() > 0); +} + +void IPTCPanel::notifyListener () { + + if (listener) + listener->panelChanged (EvIPTC, M("HISTORY_CHANGED")); +} + +void IPTCPanel::addKeyWord () { + + keyword->get_entry()->select_region (0, keyword->get_entry()->get_text().size()); + + for (int i=0; isize(); i++) + if (keywords->get_text (i) == keyword->get_entry()->get_text()) + return; + + keywords->append_text (keyword->get_entry()->get_text()); + keyword->prepend_text (keyword->get_entry()->get_text()); + std::vector items; + for (Gtk::TreeModel::iterator i = keyword->get_model()->children().begin(); i!=keyword->get_model()->children().end(); i++) { + Glib::ustring s; + i->get_value (0, s); + items.push_back (s); + } + keyword->clear_items (); + for (int i=0; i<10 && iappend_text (items[i]); + keywords->scroll_to_row (keywords->get_model()->get_path(--keywords->get_model()->children().end())); + + updateChangeList (); +} + +void IPTCPanel::delKeyWord () { + + std::vector selection = keywords->get_selected (); + if (selection.size()>0) { + std::vector keep; + for (int i=0; isize(); i++) + if (std::find (selection.begin(), selection.end(), i) == selection.end()) + keep.push_back (keywords->get_text (i)); + keywords->clear_items (); + for (int i=0; iappend_text (keep[i]); + } + + updateChangeList (); +} + +void IPTCPanel::addSuppCategory () { + + for (int i=0; isize(); i++) + if (suppCategories->get_text (i) == suppCategory->get_entry()->get_text()) + return; + + suppCategories->append_text (suppCategory->get_entry()->get_text()); + suppCategory->prepend_text (suppCategory->get_entry()->get_text()); + std::vector items; + for (Gtk::TreeModel::iterator i = suppCategory->get_model()->children().begin(); i!=suppCategory->get_model()->children().end(); i++) { + Glib::ustring s; + i->get_value (0, s); + items.push_back (s); + } + suppCategory->clear_items (); + for (int i=0; i<10 && iappend_text (items[i]); + suppCategories->scroll_to_row (suppCategories->get_model()->get_path(--suppCategories->get_model()->children().end())); + suppCategory->get_entry()->select_region (0, suppCategory->get_entry()->get_text().size()); + + updateChangeList (); +} + +void IPTCPanel::delSuppCategory () { + + std::vector selection = suppCategories->get_selected (); + if (selection.size()>0) { + std::vector keep; + for (int i=0; isize(); i++) + if (std::find (selection.begin(), selection.end(), i) == selection.end()) + keep.push_back (suppCategories->get_text (i)); + suppCategories->clear_items (); + for (int i=0; iappend_text (keep[i]); + } + + updateChangeList (); +} + +void IPTCPanel::updateChangeList () { + + changeList.clear (); + changeList.resize (18); + changeList[0].field = "Caption"; + changeList[0].values.push_back (captionText->get_text ()); + changeList[1].field = "CaptionWriter"; + changeList[1].values.push_back (captionWriter->get_text ()); + changeList[2].field = "Headline"; + changeList[2].values.push_back (headline->get_text ()); + changeList[3].field = "Instructions"; + changeList[3].values.push_back (instructions->get_text ()); + changeList[4].field = "Keywords"; + for (int i=0; isize(); i++) + changeList[4].values.push_back (keywords->get_text (i)); + changeList[5].field = "Category"; + changeList[5].values.push_back (category->get_entry()->get_text ()); + changeList[6].field = "SupplementalCategories"; + for (int i=0; isize(); i++) + changeList[6].values.push_back (suppCategories->get_text (i)); + changeList[7].field = "Author"; + changeList[7].values.push_back (author->get_text ()); + changeList[8].field = "AuthorsPosition"; + changeList[8].values.push_back (authorPos->get_text ()); + changeList[9].field = "Credit"; + changeList[9].values.push_back (credit->get_text ()); + changeList[10].field = "Source"; + changeList[10].values.push_back (source->get_text ()); + changeList[11].field = "Copyright"; + changeList[11].values.push_back (copyright->get_text ()); + changeList[12].field = "City"; + changeList[12].values.push_back (city->get_text ()); + changeList[13].field = "Province"; + changeList[13].values.push_back (province->get_text ()); + changeList[14].field = "Country"; + changeList[14].values.push_back (country->get_text ()); + changeList[15].field = "Title"; + changeList[15].values.push_back (title->get_text ()); + changeList[16].field = "DateCreated"; + changeList[16].values.push_back (dateCreated->get_text ()); + changeList[17].field = "TransReference"; + changeList[17].values.push_back (transReference->get_text ()); + + notifyListener (); +} + +void IPTCPanel::applyChangeList () { + + for (int i=0; i<16; i++) + conns[i].block (true); + + captionText->set_text (""); + captionWriter->set_text (""); + headline->set_text (""); + instructions->set_text (""); + keywords->clear_items (); + category->get_entry()->set_text (""); + suppCategories->clear_items (); + author->set_text (""); + authorPos->set_text (""); + credit->set_text (""); + source->set_text (""); + copyright->set_text (""); + city->set_text (""); + province->set_text (""); + country->set_text (""); + title->set_text (""); + dateCreated->set_text (""); + transReference->set_text (""); + keyword->get_entry()->set_text (""); + suppCategory->get_entry()->set_text (""); + + for (int i=0; i0) + captionText->set_text (changeList[i].values[0]); + else if (changeList[i].field == "CaptionWriter" && changeList[i].values.size()>0) + captionWriter->set_text (changeList[i].values[0]); + else if (changeList[i].field == "Headline" && changeList[i].values.size()>0) + headline->set_text (changeList[i].values[0]); + else if (changeList[i].field == "Instructions" && changeList[i].values.size()>0) + instructions->set_text (changeList[i].values[0]); + else if (changeList[i].field == "Keywords") + for (int j=0; jappend_text (changeList[i].values[j]); + else if (changeList[i].field == "Category" && changeList[i].values.size()>0) + category->get_entry()->set_text (changeList[i].values[0]); + else if (changeList[i].field == "SupplementalCategories") + for (int j=0; jappend_text (changeList[i].values[j]); + else if (changeList[i].field == "Author" && changeList[i].values.size()>0) + author->set_text (changeList[i].values[0]); + else if (changeList[i].field == "AuthorsPosition" && changeList[i].values.size()>0) + authorPos->set_text (changeList[i].values[0]); + else if (changeList[i].field == "Credit" && changeList[i].values.size()>0) + credit->set_text (changeList[i].values[0]); + else if (changeList[i].field == "Source" && changeList[i].values.size()>0) + source->set_text (changeList[i].values[0]); + else if (changeList[i].field == "Copyright" && changeList[i].values.size()>0) + copyright->set_text (changeList[i].values[0]); + else if (changeList[i].field == "City" && changeList[i].values.size()>0) + city->set_text (changeList[i].values[0]); + else if (changeList[i].field == "Province" && changeList[i].values.size()>0) + province->set_text (changeList[i].values[0]); + else if (changeList[i].field == "Country" && changeList[i].values.size()>0) + country->set_text (changeList[i].values[0]); + else if (changeList[i].field == "Title" && changeList[i].values.size()>0) + title->set_text (changeList[i].values[0]); + else if (changeList[i].field == "DateCreated" && changeList[i].values.size()>0) + dateCreated->set_text (changeList[i].values[0]); + else if (changeList[i].field == "TransReference" && changeList[i].values.size()>0) + transReference->set_text (changeList[i].values[0]); + + for (int i=0; i<16; i++) + conns[i].block (false); +} + +void IPTCPanel::resetClicked () { + + disableListener (); + changeList = defChangeList; + applyChangeList (); + enableListener (); + notifyListener (); +} + +void IPTCPanel::fileClicked () { + + disableListener (); + changeList = embeddedData; + applyChangeList (); + enableListener (); + notifyListener (); +} + +void IPTCPanel::copyClicked () { + + clipboard.setIPTC (changeList); +} + +void IPTCPanel::pasteClicked () { + + disableListener (); + changeList = clipboard.getIPTC (); + applyChangeList (); + enableListener (); + notifyListener (); +} diff --git a/rtgui/iptcpanel.h b/rtgui/iptcpanel.h new file mode 100755 index 000000000..4b5baec6c --- /dev/null +++ b/rtgui/iptcpanel.h @@ -0,0 +1,91 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _IPTCPANEL_ +#define _IPTCPANEL_ + +#include +#include + +class IPTCPanel : public Gtk::VBox, public ToolPanel { + + private: + std::vector changeList; + std::vector defChangeList; + std::vector embeddedData; + + Gtk::TextView* captionView; + Glib::RefPtr captionText; + Gtk::Entry* captionWriter; + Gtk::Entry* headline; + Gtk::Entry* instructions; + Gtk::ComboBoxEntryText* keyword; + Gtk::ListViewText* keywords; + Gtk::Button* addKW; + Gtk::Button* delKW; + Gtk::ComboBoxEntryText* category; + Gtk::ComboBoxEntryText* suppCategory; + Gtk::ListViewText* suppCategories; + Gtk::Button* addSC; + Gtk::Button* delSC; + + Gtk::Entry* author; + Gtk::Entry* authorPos; + Gtk::Entry* credit; + Gtk::Entry* source; + Gtk::Entry* copyright; + Gtk::Entry* city; + Gtk::Entry* province; + Gtk::Entry* country; + Gtk::Entry* title; + Gtk::Entry* dateCreated; + Gtk::Entry* transReference; + + Gtk::Button* reset; + Gtk::Button* file; + Gtk::Button* copy; + Gtk::Button* paste; + + sigc::connection conns[16]; + + void applyChangeList (); + void updateChangeList (); + + public: + IPTCPanel (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + + void setImageData (const rtengine::ImageMetaData* id); + + void notifyListener (); + + void addKeyWord (); + void delKeyWord (); + void addSuppCategory (); + void delSuppCategory (); + + void resetClicked (); + void fileClicked (); + void copyClicked (); + void pasteClicked (); +}; + +#endif diff --git a/rtgui/lcurve.cc b/rtgui/lcurve.cc new file mode 100755 index 000000000..a0836a562 --- /dev/null +++ b/rtgui/lcurve.cc @@ -0,0 +1,143 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +using namespace rtengine; +using namespace rtengine::procparams; + +LCurve::LCurve () : ToolPanel() { + + Gtk::HBox* abox = Gtk::manage (new Gtk::HBox ()); + abox->set_border_width (2); + + brightness = Gtk::manage (new Adjuster (M("TP_LUMACURVE_BRIGHTNESS"), -2, 2, 0.01, 0)); + hlcompr = Gtk::manage (new Adjuster (M("TP_LUMACURVE_COMPRHIGHLIGHTS"), 0, 100, 1, 0)); + black = Gtk::manage (new Adjuster (M("TP_LUMACURVE_BLACKLEVEL"), 0, 32768, 1, 0)); + shcompr = Gtk::manage (new Adjuster (M("TP_LUMACURVE_COMPRSHADOWS"), 0, 100, 1, 0)); + contrast = Gtk::manage (new Adjuster (M("TP_LUMACURVE_CONTRAST"), -50, 50, 1, 0)); + + pack_start (*brightness); + brightness->show (); + + pack_start (*hlcompr); + hlcompr->show (); + + pack_start (*black); + black->show (); + + pack_start (*shcompr); + shcompr->show (); + + pack_start (*contrast); + contrast->show (); + + Gtk::HSeparator *hsep3 = Gtk::manage (new Gtk::HSeparator()); + hsep3->show (); + pack_start (*hsep3); + + shape = Gtk::manage (new CurveEditor ()); + shape->show (); + shape->setCurveListener (this); + + curvexp = Gtk::manage (new Gtk::Expander (M("TP_LUMACURVE_CURVEEDITOR"))); + curvexp->show (); + curvexp->add (*shape); + + pack_start (*curvexp, Gtk::PACK_SHRINK, 4); + + brightness->setAdjusterListener (this); + hlcompr->setAdjusterListener (this); + black->setAdjusterListener (this); + shcompr->setAdjusterListener (this); + contrast->setAdjusterListener (this); +} + +void LCurve::read (const ProcParams* pp) { + + disableListener (); + + brightness->setValue (pp->lumaCurve.brightness); + black->setValue (pp->lumaCurve.black); + hlcompr->setValue (pp->lumaCurve.hlcompr); + shcompr->setValue (pp->lumaCurve.shcompr); + + contrast->setValue (pp->lumaCurve.contrast); + shape->setCurve (pp->lumaCurve.curve); + + enableListener (); +} + +void LCurve::write (ProcParams* pp) { + + pp->lumaCurve.brightness = brightness->getValue (); + pp->lumaCurve.black = (int)black->getValue (); + pp->lumaCurve.hlcompr = (int)hlcompr->getValue (); + pp->lumaCurve.shcompr = (int)shcompr->getValue (); + pp->lumaCurve.contrast = (int)contrast->getValue (); + pp->lumaCurve.curve = shape->getCurve (); +} + +void LCurve::setDefaults (const ProcParams* defParams) { + + brightness->setDefault (defParams->lumaCurve.brightness); + black->setDefault (defParams->lumaCurve.black); + hlcompr->setDefault (defParams->lumaCurve.hlcompr); + shcompr->setDefault (defParams->lumaCurve.shcompr); + contrast->setDefault (defParams->lumaCurve.contrast); +} + +void LCurve::curveChanged () { + + if (listener) + listener->panelChanged (EvLCurve, M("HISTORY_CUSTOMCURVE")); +} + +void LCurve::adjusterChanged (Adjuster* a, double newval) { + + if (!listener) + return; + + Glib::ustring costr; + if (a==brightness) + costr = Glib::ustring::format (std::setw(3), std::fixed, std::setprecision(2), a->getValue()); + else + costr = Glib::ustring::format ((int)a->getValue()); + + if (a==brightness) + listener->panelChanged (EvLBrightness, costr); + else if (a==black) + listener->panelChanged (EvLBlack, costr); + else if (a==contrast) + listener->panelChanged (EvLContrast, costr); + else if (a==hlcompr) + listener->panelChanged (EvLHLCompr, costr); + else if (a==shcompr) + listener->panelChanged (EvLSHCompr, costr); +} +void LCurve::expandCurve (bool isExpanded) { + + curvexp->set_expanded (isExpanded); +} + +bool LCurve::isCurveExpanded () { + + return curvexp->get_expanded (); +} + diff --git a/rtgui/lcurve.h b/rtgui/lcurve.h new file mode 100755 index 000000000..88aaf0e4c --- /dev/null +++ b/rtgui/lcurve.h @@ -0,0 +1,53 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _LCURVE_H_ +#define _LCURVE_H_ + +#include +#include +#include +#include +#include + +class LCurve : public Gtk::VBox, public AdjusterListener, public ToolPanel, public CurveListener { + + protected: + Adjuster* brightness; + Adjuster* black; + Adjuster* contrast; + Adjuster* hlcompr; + Adjuster* shcompr; + CurveEditor* shape; + Gtk::Expander* curvexp; + + public: + + LCurve (); + + void read (const rtengine::procparams::ProcParams* pp); + void write (rtengine::procparams::ProcParams* pp); + void setDefaults (const rtengine::procparams::ProcParams* defParams); + + void curveChanged (); + void adjusterChanged (Adjuster* a, double newval); + void expandCurve (bool isExpanded); + bool isCurveExpanded (); +}; + +#endif diff --git a/rtgui/lumadenoise.cc b/rtgui/lumadenoise.cc new file mode 100755 index 000000000..e80d1595c --- /dev/null +++ b/rtgui/lumadenoise.cc @@ -0,0 +1,149 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include + +using namespace rtengine; +using namespace rtengine::procparams; + +LumaDenoise::LumaDenoise () : ToolPanel () { + + enabled = Gtk::manage (new Gtk::CheckButton (M("GENERAL_ENABLED"))); + enabled->set_active (false); + enabled->show (); + pack_start (*enabled); + + Gtk::HSeparator *hsep1 = Gtk::manage (new Gtk::HSeparator()); + hsep1->show (); + pack_start (*hsep1); + + enaConn = enabled->signal_toggled().connect( sigc::mem_fun(*this, &LumaDenoise::enabledChanged) ); + + radius = Gtk::manage (new Adjuster (M("TP_LUMADENOISE_RADIUS"), 0.5, 50, 0.1, 1.9)); + edge = Gtk::manage (new Adjuster (M("TP_LUMADENOISE_EDGETOLERANCE"), 10, 30000, 100, 1500)); + radius->setAdjusterListener (this); + edge->setAdjusterListener (this); + radius->show(); + edge->show(); + + pack_start (*radius); + pack_start (*edge); +} + +void LumaDenoise::read (const ProcParams* pp, const ParamsEdited* pedited) { + + disableListener (); + + if (pedited) { + radius->setEditedState (pedited->lumaDenoise.radius ? Edited : UnEdited); + edge->setEditedState (pedited->lumaDenoise.edgetolerance ? Edited : UnEdited); + enabled->set_inconsistent (!pedited->lumaDenoise.enabled); + } + + enaConn.block (true); + enabled->set_active (pp->lumaDenoise.enabled); + enaConn.block (false); + + lastEnabled = pp->lumaDenoise.enabled; + + radius->setValue (pp->lumaDenoise.radius); + edge->setValue (pp->lumaDenoise.edgetolerance); + + enableListener (); +} + +void LumaDenoise::write (ProcParams* pp, ParamsEdited* pedited) { + + pp->lumaDenoise.radius = radius->getValue (); + pp->lumaDenoise.edgetolerance = (int)edge->getValue (); + pp->lumaDenoise.enabled = enabled->get_active(); + + if (pedited) { + pedited->lumaDenoise.radius = radius->getEditedState (); + pedited->lumaDenoise.edgetolerance = edge->getEditedState (); + pedited->lumaDenoise.enabled = !enabled->get_inconsistent(); + } +} + +void LumaDenoise::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { + + radius->setDefault (defParams->lumaDenoise.radius); + edge->setDefault (defParams->lumaDenoise.edgetolerance); + + if (pedited) { + radius->setDefaultEditedState (pedited->lumaDenoise.radius ? Edited : UnEdited); + edge->setDefaultEditedState (pedited->lumaDenoise.edgetolerance ? Edited : UnEdited); + } + else { + radius->setDefaultEditedState (Irrelevant); + edge->setDefaultEditedState (Irrelevant); + } +} + +void LumaDenoise::adjusterChanged (Adjuster* a, double newval) { + + if (listener && enabled->get_active()) { + + if (a==radius) + listener->panelChanged (EvLDNRadius, Glib::ustring::format (std::setw(2), std::fixed, std::setprecision(1), a->getValue())); + else if (a==edge) + listener->panelChanged (EvLDNEdgeTolerance, Glib::ustring::format ((int)a->getValue())); + } +} + +void LumaDenoise::enabledChanged () { + + if (batchMode) { + if (enabled->get_inconsistent()) { + enabled->set_inconsistent (false); + enaConn.block (true); + enabled->set_active (false); + enaConn.block (false); + } + else if (lastEnabled) + enabled->set_inconsistent (true); + + lastEnabled = enabled->get_active (); + } + + if (listener) { + if (enabled->get_active ()) + listener->panelChanged (EvLDNEnabled, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvLDNEnabled, M("GENERAL_DISABLED")); + } +} + +void LumaDenoise::setBatchMode (bool batchMode) { + + ToolPanel::setBatchMode (batchMode); + radius->showEditedCB (); + edge->showEditedCB (); +} + +void LumaDenoise::setAdjusterBehavior (bool bedgetoladd) { + + if (!edgetolAdd && bedgetoladd) + edge->setLimits (-10000, 10000, 100, 0); + else if (edgetolAdd && !bedgetoladd) + edge->setLimits (10, 30000, 100, 1500); + + edgetolAdd = bedgetoladd; +} diff --git a/rtgui/lumadenoise.h b/rtgui/lumadenoise.h new file mode 100755 index 000000000..3f8e84170 --- /dev/null +++ b/rtgui/lumadenoise.h @@ -0,0 +1,51 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _LUMADENOISE_H_ +#define _LUMADENOISE_H_ + +#include +#include +#include + +class LumaDenoise : public Gtk::VBox, public AdjusterListener, public ToolPanel { + + protected: + Adjuster* radius; + Adjuster* edge; + Gtk::CheckButton* enabled; + bool lastEnabled; + sigc::connection enaConn; + bool edgetolAdd; + + public: + + LumaDenoise (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + + void adjusterChanged (Adjuster* a, double newval); + void enabledChanged (); + + void setAdjusterBehavior (bool bedgetoladd); +}; + +#endif diff --git a/rtgui/lwbutton.cc b/rtgui/lwbutton.cc new file mode 100755 index 000000000..a14dec6a7 --- /dev/null +++ b/rtgui/lwbutton.cc @@ -0,0 +1,179 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +LWButton::LWButton (Cairo::RefPtr i, int aCode, void* aData, Alignment ha, Alignment va, Glib::ustring tooltip) + : icon(i), actionCode(aCode), actionData(aData), halign(ha), valign(va), state(Normal), toolTip(tooltip), listener(NULL) { + + w = i->get_width () + 2; + h = i->get_height () + 2; +} + +void LWButton::getSize (int& minw, int& minh) { + + minw = w; + minh = h; +} + +void LWButton::setPosition (int x, int y) { + + xpos = x; + ypos = y; +} + +void LWButton::getPosition (int& x, int& y) { + + x = xpos; + y = ypos; +} + +void LWButton::setIcon (Cairo::RefPtr i) { + + icon = i; + w = i->get_width () + 2; + h = i->get_height () + 2; +} + +Cairo::RefPtr LWButton::getIcon () { + + return icon; +} + +void LWButton::setColors (const Gdk::Color& bg, const Gdk::Color& fg) { + + bgr = bg.get_red_p (); + bgg = bg.get_green_p (); + bgb = bg.get_blue_p (); + fgr = fg.get_red_p (); + fgg = fg.get_green_p (); + fgb = fg.get_blue_p (); +} + +bool LWButton::inside (int x, int y) { + + return x>xpos && xypos && yredrawNeeded (this); + return true; + } + return in; +} + +bool LWButton::pressNotify (int x, int y) { + + bool in = inside (x, y); + State nstate = state; + if (in && (state==Normal || state==Over || state==Pressed_Out)) + nstate = Pressed_In; + else if (!in && state==Pressed_In) + nstate = Normal; + + if (state!=nstate) { + state = nstate; + if (listener) + listener->redrawNeeded (this); + return true; + } + return in; +} + +bool LWButton::releaseNotify (int x, int y) { + + bool in = inside (x, y); + State nstate = state; + bool action = false; + if (in && (state==Pressed_In || state==Pressed_Out)) { + nstate = Over; + action = true; + } + else + nstate = Normal; + + bool ret = action; + if (state!=nstate) { + state = nstate; + if (listener) + listener->redrawNeeded (this); + ret = true; + } + + if (action && listener) + listener->buttonPressed (this, actionCode, actionData); + return ret; +} + +void LWButton::redraw (Cairo::RefPtr context) { + + context->set_line_width (1.0); + context->set_antialias (Cairo::ANTIALIAS_SUBPIXEL); + context->rectangle (xpos+0.5, ypos+0.5, w-1.0, h-1.0); + if (state==Pressed_In) + context->set_source_rgb (fgr, fgg, fgb); + else + context->set_source_rgba (bgr, bgg, bgb, 0); + context->fill_preserve (); + if (state==Over) + context->set_source_rgb (fgr, fgg, fgb); + else + context->set_source_rgba (bgr, bgg, bgb, 0); + context->stroke (); + int dilat = 1; + if (state==Pressed_In) + dilat++; + + context->set_source (icon, xpos+dilat, ypos+dilat); + context->paint (); +} + +void LWButton::getAlignment (Alignment& ha, Alignment& va) { + + ha = halign; + va = valign; +} + +Glib::ustring LWButton::getToolTip (int x, int y) { + + if (inside (x, y)) + return toolTip; + else + return ""; +} + +void LWButton::setToolTip (const Glib::ustring& tooltip) { + + toolTip = tooltip; +} + diff --git a/rtgui/lwbutton.h b/rtgui/lwbutton.h new file mode 100755 index 000000000..0d3e7a61f --- /dev/null +++ b/rtgui/lwbutton.h @@ -0,0 +1,74 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _LWBUTTON_ +#define _LWBUTTON_ + +#include + +class LWButton; +class LWButtonListener { + + public: + virtual void buttonPressed (LWButton* button, int actionCode, void* actionData) {} + virtual void redrawNeeded (LWButton* button) {} +}; + +class LWButton { + + public: + enum Alignment {Left, Right, Top, Bottom, Center}; + enum State { Normal, Over, Pressed_In, Pressed_Out}; + + private: + int xpos, ypos, w, h; + Alignment halign, valign; + Cairo::RefPtr icon; + double bgr, bgg, bgb; + double fgr, fgg, fgb; + State state; + LWButtonListener* listener; + int actionCode; + void* actionData; + Glib::ustring toolTip; + + public: + LWButton (Cairo::RefPtr i, int aCode, void* aData, Alignment ha=Left, Alignment va=Center, Glib::ustring tooltip=""); + + void getSize (int& minw, int& minh); + void getAlignment (Alignment& ha, Alignment& va); + void setPosition (int x, int y); + void getPosition (int& x, int& y); + bool inside (int x, int y); + void setIcon (Cairo::RefPtr i); + Cairo::RefPtr getIcon (); + void setColors (const Gdk::Color& bg, const Gdk::Color& fg); + void setToolTip (const Glib::ustring& tooltip); + + bool motionNotify (int x, int y); + bool pressNotify (int x, int y); + bool releaseNotify (int x, int y); + + Glib::ustring getToolTip (int x, int y); + + void setButtonListener (LWButtonListener* bl) { listener = bl; } + + void redraw (Cairo::RefPtr context); +}; + +#endif diff --git a/rtgui/lwbuttonset.cc b/rtgui/lwbuttonset.cc new file mode 100755 index 000000000..4542b1806 --- /dev/null +++ b/rtgui/lwbuttonset.cc @@ -0,0 +1,169 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +LWButtonSet::LWButtonSet () : aw(0), ah(0) { +} + +LWButtonSet::~LWButtonSet () { + + for (int i=0; igetSize (bw, bh); + w+= bw; + if (bh>h) + h = bh; + } +} + +int LWButtonSet::arrangeButtons (int x, int y, int w, int h) { + + int mw, mh; + getMinimalDimensions (mw, mh); + + if (w<0) + w = mw; + if (h<0) + h = mh; + + int begx = x; + int endx = x+w-1; + for (int i=0; igetSize (bw, bh); + buttons[i]->getAlignment (halign, valign); + if (halign == LWButton::Left) { + bx = begx; + begx += bw; + } + else if (halign == LWButton::Right) { + bx = endx-bw; + endx -= bw; + } + if (valign == LWButton::Top) + by = y; + else if (valign == LWButton::Bottom) + by = y+h-bh-1; + else if (valign == LWButton::Center) + by = y+(h-bh)/2; + buttons[i]->setPosition (bx, by); + } + aw = w; + ah = h; + ax = x; + ay = y; +} + +void LWButtonSet::move (int nx, int ny) { + + for (int i=0; igetPosition (x, y); + buttons[i]->setPosition (x+nx-ax, y+ny-ay); + } + + ax = nx; + ay = ny; +} + +void LWButtonSet::redraw (Cairo::RefPtr context) { + + for (int i=0; iredraw (context); +} + +bool LWButtonSet::motionNotify (int x, int y) { + + bool res = false; + for (int i=0; imotionNotify (x, y); + res = res || handled; + } + + return res; +} + +bool LWButtonSet::pressNotify (int x, int y) { + + bool res = false; + for (int i=0; ipressNotify (x, y); + res = res || handled; + } + return res; +} + +bool LWButtonSet::releaseNotify (int x, int y) { + + bool res = false; + for (int i=0; ireleaseNotify (x, y); + res = res || handled; + } + return res; +} + +bool LWButtonSet::inside (int x, int y) { + + for (int i=0; iinside (x, y)) + return true; + return false; +} + +void LWButtonSet::setButtonListener (LWButtonListener* bl) { + + for (int i=0; isetButtonListener (bl); +} + +void LWButtonSet::getAllocatedDimensions (int& w, int& h) { + + w = aw; + h = ah; +} + +void LWButtonSet::setColors (const Gdk::Color& bg, const Gdk::Color& fg) { + + for (int i=0; isetColors (bg, fg); +} + +Glib::ustring LWButtonSet::getToolTip (int x, int y) { + + for (int i=0; igetToolTip (x, y); + if (ttip!="") + return ttip; + } + return ""; +} diff --git a/rtgui/lwbuttonset.h b/rtgui/lwbuttonset.h new file mode 100755 index 000000000..4e7be5dcb --- /dev/null +++ b/rtgui/lwbuttonset.h @@ -0,0 +1,53 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _LWBUTTONSET_ +#define _LWBUTTONSET_ + +#include +#include +#include + +class LWButtonSet { + + protected: + std::vector buttons; + int aw, ah, ax, ay; + public: + LWButtonSet (); + ~LWButtonSet (); + + void add (LWButton* b); + + void getMinimalDimensions (int& w, int& h); + void getAllocatedDimensions (int& w, int& h); + int arrangeButtons (int x, int y, int w, int h); + void setColors (const Gdk::Color& bg, const Gdk::Color& fg); + bool motionNotify (int x, int y); + bool pressNotify (int x, int y); + bool releaseNotify (int x, int y); + void move (int nx, int ny); + bool inside (int x, int y); + + Glib::ustring getToolTip (int x, int y); + + void setButtonListener (LWButtonListener* bl); + void redraw (Cairo::RefPtr context); +}; + +#endif diff --git a/rtgui/main.cc b/rtgui/main.cc new file mode 100755 index 000000000..13d153e9f --- /dev/null +++ b/rtgui/main.cc @@ -0,0 +1,88 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +// generated 2004/6/3 19:15:32 CEST by gabor@darkstar.(none) +// using glademm V2.5.0 +// +// newer (non customized) versions of this file go to raw.cc_new + +// This file is for your program, I won't touch it again! + +//#include +#include +#include +#include +#include +#include +#include +#include +extern Options options; + +//#ifdef WIN32 +//#include // included for WinMain +//#endif + +Glib::ustring argv0; +Glib::ustring argv1; + +int main(int argc, char **argv) +{ + + std::string argv0_, argv1_; + +#ifndef WIN32 + argv0_ = argv[0]; +#else + char exname[512]; + GetModuleFileName (NULL, exname, 512); + argv0_ = exname; +#endif + int i; + for (i=argv0_.size()-1; (argv0_[i]!='/' && argv0_[i]!='\\') && i>0; i--); + if (argv0_[i]=='/' || argv0_[i]=='\\') + argv0_ = argv0_.substr(0,i); + + if (argc>1) + argv1_ = argv[1]; + else + argv1_ = ""; + + argv0 = Glib::locale_to_utf8 (argv0_); + argv1 = Glib::locale_to_utf8 (argv1_); + + Glib::thread_init(); + gdk_threads_init(); + Gio::init (); + + Options::load (); + + Gtk::RC::add_default_file (argv0+"/themes/"+options.theme); + + Gtk::Main m(&argc, &argv); +// MainWindow *MainWindow = new class MainWindow(); + RTWindow *rtWindow = new class RTWindow(); + gdk_threads_enter (); + m.run(*rtWindow); + gdk_threads_leave (); + delete rtWindow; + return 0; +} + + + + diff --git a/rtgui/mountselectionlistener.h b/rtgui/mountselectionlistener.h new file mode 100755 index 000000000..c1986414d --- /dev/null +++ b/rtgui/mountselectionlistener.h @@ -0,0 +1,30 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _MOUNTSELECTIONLISTENER_ +#define _MOUNTSELECTIONLISTENER_ + +#include + +class MountSelectionListener { + + public: + virtual void mountSelectionChanged (Glib::ustring mountRoot) {} +}; + +#endif diff --git a/rtgui/multilangmgr.cc b/rtgui/multilangmgr.cc new file mode 100755 index 000000000..07bf8c2f1 --- /dev/null +++ b/rtgui/multilangmgr.cc @@ -0,0 +1,97 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include + +MultiLangMgr langMgr; + +Glib::ustring M (std::string key) { return langMgr.getStr (key); } + +bool MultiLangMgr::load (Glib::ustring fname, MultiLangMgr* fb) { + + fallBack = fb; + + FILE *f = g_fopen (fname.c_str(), "rt"); + + if (f==NULL) + return false; + + transTable.clear (); + + char* buffer = new char[2048]; + + while (buffer = fgets (buffer, 2048, f)) { + // find separator + int seppos = 0; + while (buffer[seppos]!=0 && buffer[seppos]!=';') + seppos++; + // no separator found + if (buffer[seppos]==0) + continue; + // cut the last \n and \r characters + int endpos = strlen(buffer)-1; + while (buffer[endpos]=='\n' || buffer[endpos]=='\r') + endpos--; + buffer[endpos+1] = 0; + // replace "\n" to '\n' + int j = 0; + for (int i=0; i::iterator r; + for (r=transTable.begin (); r!=transTable.end(); r++) + fprintf (f, "%s;%s\n", r->first.c_str(), Glib::locale_from_utf8(r->second).c_str()); + + fclose (f); + return true; +} + +Glib::ustring MultiLangMgr::getStr (std::string key) { + + std::map::iterator r = transTable.find (key); + if (r!=transTable.end()) + return r->second; + else if (fallBack) + return fallBack->getStr (key); + else + return ""; +} diff --git a/rtgui/multilangmgr.h b/rtgui/multilangmgr.h new file mode 100755 index 000000000..e22d7fa96 --- /dev/null +++ b/rtgui/multilangmgr.h @@ -0,0 +1,45 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _MULTILANGMGR_ +#define _MULTILANGMGR_ + +#include +#include +#include + +class MultiLangMgr { + + std::map transTable; + MultiLangMgr* fallBack; + + public: + MultiLangMgr () : fallBack (NULL) {} + MultiLangMgr (Glib::ustring fname) : fallBack (NULL) { load (fname); } + + bool load (Glib::ustring fname, MultiLangMgr* fb = NULL); + bool save (Glib::ustring fname); + + Glib::ustring getStr (std::string key); +}; + +extern MultiLangMgr langMgr; + +Glib::ustring M (std::string key); + +#endif diff --git a/rtgui/mycurve.cc b/rtgui/mycurve.cc new file mode 100755 index 000000000..913a398f6 --- /dev/null +++ b/rtgui/mycurve.cc @@ -0,0 +1,467 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +#define RADIUS 3 /* radius of the control points */ +#define MIN_DISTANCE 8 /* min distance between control points */ + +MyCurve::MyCurve () : listener(NULL) { + + cursor_type = Gdk::TOP_LEFT_ARROW; + curve.type = Spline; + height = 0; + grab_point = -1; + + add_events(Gdk::EXPOSURE_MASK | Gdk::POINTER_MOTION_MASK | Gdk::POINTER_MOTION_HINT_MASK | Gdk::ENTER_NOTIFY_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::BUTTON1_MOTION_MASK); + signal_event().connect( sigc::mem_fun(*this, &MyCurve::handleEvents) ); + + curve.x.push_back(0); + curve.y.push_back(0); + curve.x.push_back(1); + curve.y.push_back(1); + curve.type = Spline; +} + +void MyCurve::spline_solve (int n, double x[], double y[], double y2[]) { + + double* u = new double[n-1]; + + y2[0] = u[0] = 0.0; /* set lower boundary condition to "natural" */ + + for (int i = 1; i < n - 1; ++i) + { + double sig = (x[i] - x[i - 1]) / (x[i + 1] - x[i - 1]); + double p = sig * y2[i - 1] + 2.0; + y2[i] = (sig - 1.0) / p; + u[i] = ((y[i + 1] - y[i]) + / (x[i + 1] - x[i]) - (y[i] - y[i - 1]) / (x[i] - x[i - 1])); + u[i] = (6.0 * u[i] / (x[i + 1] - x[i - 1]) - sig * u[i - 1]) / p; + } + + y2[n - 1] = 0.0; + for (int k = n - 2; k >= 0; --k) + y2[k] = y2[k] * y2[k + 1] + u[k]; + + delete [] u; +} + +double MyCurve::spline_eval (int n, double x[], double y[], double y2[], double val) { + + if (val>x[n-1]) + return y[n-1]; + else if (val 1){ + int k = (k_hi + k_lo) / 2; + if (x[k] > val) + k_hi = k; + else + k_lo = k; + } + + double h = x[k_hi] - x[k_lo]; + double a = (x[k_hi] - val) / h; + double b = (val - x[k_lo]) / h; + return a*y[k_lo] + b*y[k_hi] + ((a*a*a - a)*y2[k_lo] + (b*b*b - b)*y2[k_hi]) * (h*h)/6.0; +} + + +std::vector MyCurve::get_vector (int veclen) { + + std::vector vector; + + int num = curve.x.size(); + + /* count active points: */ + double prev =- 1.0; + int active = 0; + int firstact = -1; + for (int i = 0; i < num; ++i) + if (curve.x[i] > prev) { + if (firstact < 0) + firstact = i; + prev = curve.x[i]; + ++active; + } + /* handle degenerate case: */ + if (active < 2) { + double ry; + if (active > 0) + ry = curve.y[firstact]; + else + ry = 0.0; + if (ry < 0.0) ry = 0.0; + if (ry > 1.0) ry = 1.0; + for (int x = 0; x < veclen; ++x) + vector.push_back(ry); + return vector; + } + + if (curve.type==Spline) { + + double* mem = new double [3*active]; + double* xv = mem; + double* yv = mem + active; + double* y2v = mem + 2*active; + + prev = -1.0; + int dst = 0; + for (int i = 0; i < num; ++i) { + if (curve.x[i] > prev) { + prev = curve.x[i]; + xv[dst] = curve.x[i]; + yv[dst] = curve.y[i]; + dst++; + } + } + spline_solve (active, xv, yv, y2v); + + double dx = 1.0 / (veclen - 1); + double rx = 0.0; + for (int x = 0; x < veclen; ++x, rx += dx) { + double ry = spline_eval (active, xv, yv, y2v, rx); + if (ry < 0.0) ry = 0; + if (ry > 1.0) ry = 1.0; + vector.push_back (ry); + } + delete [] mem; + } + else if (curve.type==Linear) { + double dx = 1.0 / (veclen - 1); + double rx = 0; + double ry = 0; + double dy = 0.0; + int i = firstact; + for (int x = 0; x < veclen; ++x, rx += dx) { + if (rx >= curve.x[i]) { + if (rx > curve.x[i]) + ry = 0.0; + dy = 0.0; + int next = i + 1; + while (next < num && curve.x[next] <= curve.x[i]) + ++next; + if (next < num) { + double delta_x = curve.x[next] - curve.x[i]; + dy = (curve.y[next] - curve.y[i]) / delta_x; + dy *= dx; + ry = curve.y[i]; + i = next; + } + } + if (rxcurve.x[num-1]) + vector.push_back (curve.y[num-1]); + else + vector.push_back (ry); + ry += dy; + } + } + return vector; +} + +void MyCurve::interpolate (int width, int height) { + + this->height = height; + point.clear (); + std::vector vector = get_vector (width); + this->height = height; + for (int i = 0; i < width; ++i) { + Gdk::Point p (RADIUS + i, RADIUS + height - (int)((height-1) * vector[i] + 0.5)); + point.push_back (p); + } +} + + +void MyCurve::draw (int width, int height) { + + if (!pixmap) + return; + + if (this->height != height || point.size() != width) + interpolate (width, height); + + Gtk::StateType state = Gtk::STATE_NORMAL; + if (!is_sensitive()) + state = Gtk::STATE_INSENSITIVE; + + Glib::RefPtr style = get_style (); + + Cairo::RefPtr cr = pixmap->create_cairo_context(); + + /* clear the pixmap: */ +// gtk_paint_flat_box (style->gobj(), pixmap->gobj(), GTK_STATE_NORMAL, GTK_SHADOW_NONE, +// NULL, (GtkWidget*)gobj(), "curve_bg", 0, 0, , height + RADIUS * 2); + +// pixmap->draw_rectangle (style->get_bg_gc (state), false, 0, 0, width + RADIUS*2 - 1, height + RADIUS*2 - 1); + + Gdk::Color c = style->get_bg (state); + cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p()); + cr->rectangle (0, 0, width + RADIUS*2, height + RADIUS*2); + cr->fill (); + + /* draw the grid lines: (XXX make more meaningful) */ + cr->set_line_width (1.0); + c = style->get_dark (state); + cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p()); + cr->set_antialias (Cairo::ANTIALIAS_NONE); + for (int i = 0; i < 5; i++) { + + cr->move_to (RADIUS, i * height / 4 + RADIUS); + cr->line_to (width + RADIUS, i * height / 4 + RADIUS); + cr->move_to (i * width / 4 + RADIUS, RADIUS); + cr->line_to (i * width / 4 + RADIUS, height + RADIUS); +// pixmap->draw_line (style->get_dark_gc (state), RADIUS, i * height / 4 + RADIUS, width + RADIUS, i * height / 4 + RADIUS); +// pixmap->draw_line (style->get_dark_gc (state), i * width / 4 + RADIUS, RADIUS, i * width / 4 + RADIUS, height + RADIUS); + } + cr->stroke (); + + cr->set_antialias (Cairo::ANTIALIAS_SUBPIXEL); + cr->set_line_width (1.0); + cr->set_source_rgb (0.0, 0.0, 0.0); + cr->move_to (point[0].get_x(), point[0].get_y()); + for (int i=1; iline_to (point[i].get_x(), point[i].get_y()); + cr->stroke (); + + for (int i = 0; i < curve.x.size(); ++i) { + + double x = ((width-1) * curve.x[i] + 0.5)+RADIUS; // project (curve.x[i], 0, 1, width); + double y = height - ((height-1) * curve.y[i] + 0.5)+RADIUS; // project (curve.y[i], 0, 1, height); + + /* draw a bullet: */ + cr->arc (x, y, RADIUS, 0, 2*M_PI); + cr->fill (); + } + + get_window()->draw_drawable (style->get_fg_gc (state), pixmap, 0, 0, 0, 0, width + RADIUS * 2, height + RADIUS * 2); +} + +bool MyCurve::handleEvents (GdkEvent* event) { + + Gdk::CursorType new_type = cursor_type; + int src, dst; + GdkEventMotion *mevent; + std::vector::iterator itx, ity; + + bool retval = false; + + int width = get_allocation().get_width() - RADIUS * 2; + int height = get_allocation().get_height() - RADIUS * 2; + + if ((width < 0) || (height < 0)) + return false; + + /* get the pointer position */ + int tx, ty; + Gdk::ModifierType gm; + get_window()->get_pointer (tx, ty, gm); + int x = CLAMP ((tx - RADIUS), 0, width-1); + int y = CLAMP ((ty - RADIUS), 0, height-1); + + unsigned int distance = ~0U; + int num = curve.x.size(); + int closest_point = 0; + for (int i = 0; i < num; ++i) { + int cx = (int)((width-1) * curve.x[i] + 0.5); //project (c->ctlpoint[i][0], min_x, c->max_x, width); + if ((unsigned int) abs (x - cx) < distance) { + distance = abs (x - cx); + closest_point = i; + } + } + + switch (event->type) { + case Gdk::CONFIGURE: + if (pixmap) + pixmap.clear (); + /* fall through */ + + case Gdk::EXPOSE: + if (!pixmap) { + pixmap = Gdk::Pixmap::create (get_window(), get_allocation().get_width(), get_allocation().get_height()); + interpolate (width, height); + } + draw (width, height); + + break; + + case Gdk::BUTTON_PRESS: + add_modal_grab (); + new_type = Gdk::PLUS; + switch (curve.type) { + case Linear: + case Spline: + if (distance > MIN_DISTANCE) { + /* insert a new control point */ + if (num > 0) { + int cx = (int)((width-1)*curve.x[closest_point]+0.5); + if (x > cx) + ++closest_point; + } + itx = curve.x.begin(); + ity = curve.y.begin(); + for (int i=0; i= 0.0) { + curve.x[dst] = curve.x[src]; + curve.y[dst] = curve.y[src]; + ++dst; + ++itx; + ++ity; + } + } + if (dst < src) { + curve.x.erase (itx, curve.x.end()); + curve.y.erase (ity, curve.y.end()); + if (curve.x.size() <= 0) { + curve.x.push_back (0); + curve.y.push_back (0); + interpolate (width, height); + draw (width, height); + } + } + new_type = Gdk::FLEUR; + grab_point = -1; + retval = true; + notifyListener (); + break; + + case Gdk::MOTION_NOTIFY: + mevent = (GdkEventMotion *) event; + + switch (curve.type) { + case Linear: + case Spline: + if (grab_point == -1) { + /* if no point is grabbed... */ + if (distance <= MIN_DISTANCE) + new_type = Gdk::FLEUR; + else + new_type = Gdk::PLUS; + } + else { + /* drag the grabbed point */ + new_type = Gdk::FLEUR; + int leftbound = -MIN_DISTANCE; + if (grab_point > 0) + leftbound = (int)((width-1)*curve.x[grab_point-1]+0.5); + + int rightbound = width + RADIUS * 2 + MIN_DISTANCE; + if (grab_point + 1 < num) + rightbound = (int)((width-1)*curve.x[grab_point+1]+0.5); + + if (tx <= leftbound || tx >= rightbound || ty > height + RADIUS * 2 + MIN_DISTANCE || ty < -MIN_DISTANCE) + curve.x[grab_point] = -1.0; + else { + curve.x[grab_point] = (double) x / (width-1); + curve.y[grab_point] = (double) (height-y) / (height-1); + } + interpolate (width, height); + draw (width, height); + notifyListener (); + } + break; + } + + if (new_type != cursor_type) { + cursor_type = new_type; + Gdk::Cursor* cursor = new Gdk::Cursor (get_display(), cursor_type); + get_window ()->set_cursor (*cursor); + delete cursor; + } + + retval = true; + break; + + default: + break; + } + + return retval; + +} + +std::vector MyCurve::getPoints () { + + std::vector result; + if (curve.type==Linear) + result.push_back (-1.0); + else + result.push_back (+1.0); + for (int i=0; i=0) { + result.push_back (curve.x[i]); + result.push_back (curve.y[i]); + } + return result; +} + +void MyCurve::setPoints (const std::vector& p) { + + int ix = 0; + if (p[ix++]>0) + curve.type = Spline; + else + curve.type = Linear; + + curve.x.clear (); + curve.y.clear (); + for (int i=0; icurveChanged (); +} diff --git a/rtgui/mycurve.h b/rtgui/mycurve.h new file mode 100755 index 000000000..13f0d85a0 --- /dev/null +++ b/rtgui/mycurve.h @@ -0,0 +1,69 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _MYCURVE_ +#define _MYCURVE_ + +#include +#include + +class CurveListener { + + public: + virtual void curveChanged () {} +}; + +enum CurveType {Linear, Spline}; + +class CurveDescr { + + public: + CurveType type; + std::vector x, y; +}; + +class MyCurve : public Gtk::DrawingArea { + + CurveListener* listener; + CurveDescr curve; + Gdk::CursorType cursor_type; + Glib::RefPtr pixmap; + int height; + int grab_point; + int last; + std::vector point; + + protected: + void draw (int width, int height); + void interpolate (int width, int height); + std::vector get_vector (int veclen); + double spline_eval (int n, double x[], double y[], double y2[], double val); + void spline_solve (int n, double x[], double y[], double y2[]); + + public: + MyCurve (); + + void setCurveListener (CurveListener* cl) { listener = cl; } + std::vector getPoints (); + void setPoints (const std::vector& p); + void setType (CurveType t); + bool handleEvents (GdkEvent* event); + void notifyListener (); +}; + +#endif diff --git a/rtgui/myicon.o b/rtgui/myicon.o new file mode 100755 index 0000000000000000000000000000000000000000..5f2bced97c9df06b4d35118cd4ee1e3bbe0b2a35 GIT binary patch literal 128280 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 literal 0 HcmV?d00001 diff --git a/rtgui/myicon.rc b/rtgui/myicon.rc new file mode 100755 index 000000000..b986cd1b6 --- /dev/null +++ b/rtgui/myicon.rc @@ -0,0 +1 @@ +1 ICON "RT.ico" diff --git a/rtgui/navigator.cc b/rtgui/navigator.cc new file mode 100755 index 000000000..f6fa53f08 --- /dev/null +++ b/rtgui/navigator.cc @@ -0,0 +1,114 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +Navigator::Navigator () { + + set_label ("Navigator"); + Gtk::VBox* mbox = Gtk::manage (new Gtk::VBox ()); + previewWindow = Gtk::manage (new PreviewWindow ()); + mbox->pack_start (*previewWindow, Gtk::PACK_SHRINK, 2); + position = Gtk::manage (new Gtk::Label ()); + mbox->pack_start (*position, Gtk::PACK_SHRINK, 2); + + R = Gtk::manage (new Gtk::Label ()); + G = Gtk::manage (new Gtk::Label ()); + B = Gtk::manage (new Gtk::Label ()); + H = Gtk::manage (new Gtk::Label ()); + S = Gtk::manage (new Gtk::Label ()); + V = Gtk::manage (new Gtk::Label ()); + + Gtk::Table* table = new Gtk::Table (3, 2); + table->attach (*R, 0, 1, 0, 1, Gtk::EXPAND, Gtk::SHRINK, 0, 0); + table->attach (*G, 0, 1, 1, 2, Gtk::EXPAND, Gtk::SHRINK, 0, 0); + table->attach (*B, 0, 1, 2, 3, Gtk::EXPAND, Gtk::SHRINK, 0, 0); + table->attach (*H, 1, 2, 0, 1, Gtk::EXPAND, Gtk::SHRINK, 0, 0); + table->attach (*S, 1, 2, 1, 2, Gtk::EXPAND, Gtk::SHRINK, 0, 0); + table->attach (*V, 1, 2, 2, 3, Gtk::EXPAND, Gtk::SHRINK, 0, 0); + + mbox->pack_start (*table, Gtk::PACK_SHRINK, 2); + + add (*mbox); + + setInvalid (); + show_all (); +} + +void Navigator::setInvalid () { + + position->set_text ("x = n/a, y = n/a"); + R->set_text ("R = n/a"); + G->set_text ("G = n/a"); + B->set_text ("B = n/a"); + H->set_text ("H = n/a"); + S->set_text ("S = n/a"); + V->set_text ("V = n/a"); +} + +void Navigator::pointerMoved (bool validPos, int x, int y, int r, int g, int b) { + + if (!validPos) + setInvalid (); + else { + position->set_text (Glib::ustring::compose ("x = %1, y = %2", x, y)); + R->set_text (Glib::ustring::compose ("R = %1", r)); + G->set_text (Glib::ustring::compose ("G = %1", g)); + B->set_text (Glib::ustring::compose ("B = %1", b)); + int h, s, v; + rgb2hsv (r, g, b, h, s, v); + H->set_text (Glib::ustring::compose ("H = %1", h)); + S->set_text (Glib::ustring::compose ("S = %1", s)); + V->set_text (Glib::ustring::compose ("V = %1", v)); + } +} + +void Navigator::rgb2hsv (int r, int g, int b, int &h, int &s, int &v) { + + volatile double var_R = r / 255.0; + volatile double var_G = g / 255.0; + volatile double var_B = b / 255.0; + + volatile double var_Min = MIN(MIN(var_R,var_G),var_B); + volatile double var_Max = MAX(MAX(var_R,var_G),var_B); + double del_Max = var_Max - var_Min; + double V = (var_Max + var_Min) / 2; + double H, S; + if (fabs(del_Max)<0.0000001) { + H = 0; + S = 0; + } + else { + if (V < 0.5) S = del_Max / (var_Max + var_Min); + else S = del_Max / (2 - var_Max - var_Min); + + double del_R = ( ( ( var_Max - var_R ) / 6.0 ) + ( del_Max / 2.0 ) ) / del_Max; + double del_G = ( ( ( var_Max - var_G ) / 6.0 ) + ( del_Max / 2.0 ) ) / del_Max; + double del_B = ( ( ( var_Max - var_B ) / 6.0 ) + ( del_Max / 2.0 ) ) / del_Max; + if ( var_R == var_Max ) H = del_B - del_G; + else if ( var_G == var_Max ) H = (1.0 / 3.0) + del_R - del_B; + else if ( var_B == var_Max ) H = (2.0 / 3.0) + del_G - del_R; + + if ( H < 0 ) H += 1; + if ( H > 1 ) H -= 1; + } + + h = (int)(H*255.0); + s = (int)(S*255.0); + v = (int)(V*255.0); +} diff --git a/rtgui/navigator.h b/rtgui/navigator.h new file mode 100755 index 000000000..4e67770bc --- /dev/null +++ b/rtgui/navigator.h @@ -0,0 +1,45 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _NAVIGATOR_ +#define _NAVIGATOR_ + +#include +#include +#include + +class Navigator : public Gtk::Frame, public PointerMotionListener { + + protected: + Gtk::Label* position; + Gtk::Label *R, *G, *B; + Gtk::Label *H, *S, *V; + + void rgb2hsv (int r, int g, int b, int &h, int &s, int &v); + void setInvalid (); + public: + PreviewWindow* previewWindow; + + Navigator (); + + // pointermotionlistener interface + void pointerMoved (bool validPos, int x, int y, int r, int g, int b); + +}; + +#endif diff --git a/rtgui/options.cc b/rtgui/options.cc new file mode 100755 index 000000000..928b59bab --- /dev/null +++ b/rtgui/options.cc @@ -0,0 +1,411 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include +#include +#include + +Options options; +Glib::ustring versionString = "v3.0 alpha 1"; + +Options::Options () { + + setDefaults (); +} + +void Options::setDefaults () { + + firstRun = true; + savesParamsAtExit = true; + saveFormat.format = "jpg"; + saveFormat.jpegQuality = 100; + saveFormat.pngCompression = 6; + saveFormat.pngBits = 8; + saveFormat.tiffBits = 8; + saveFormat.tiffUncompressed = true; + saveFormat.saveParams = false; + savePathTemplate = "\%p1/converted/\%f"; + savePathFolder = ""; + saveUsePathTemplate = true; + defProfRaw = "default"; + defProfImg = "neutral"; + dateFormat = "%y-%m-%d"; + startupDir = 1; + startupPath = ""; + profilePath = "profiles"; + dirBrowserWidth = 200; + dirBrowserHeight = 150; + toolPanelWidth = 250; + browserToolPanelWidth = 250; + historyPanelWidth = 150; + lastScale = 4; + lastCropSize = 1; + fbOnlyRaw = false; + fbShowDateTime = true; + fbShowBasicExif = true; + fbShowHidden = false; + fbArrangement = 0; + multiUser = false; + version = 290; + thumbSize = 80; + showHistory = true; + showFilePanelState = 0; + showInfo = false; + cropDPI = 300; + showClippedHighlights = false; + showClippedShadows = false; + highlightThreshold = 254; + shadowThreshold = 0; + bgcolor = 0; + blinkClipped = true; + language = "english"; + lastSaveAsPath = ""; + theme = ""; + maxThumbnailHeight = 400; + maxCacheEntries = 10000; + thumbnailFormat = FT_Custom16; + thumbInterp = 1; + saveParamsFile = false; + saveParamsCache = true; + paramsLoadLocation = PLL_Cache; + procQueueEnabled = true; + gimpDir = "C:\\Program Files\\GIMP-2.0"; + psDir = "C:\\Program Files\\Adobe\\Adobe Photoshop CS3"; + customEditorProg = "start"; + editorToSendTo = 1; + liveThumbnails = true; + tpOpen.clear (); + crvOpen.clear (); + parseExtensions.clear (); + parseExtensionsEnabled.clear (); + renameUseTemplates = false; + renameTemplates.clear (); + thumbnailZoomRatios.clear (); + thumbnailZoomRatios.push_back (0.2); + thumbnailZoomRatios.push_back (0.3); + thumbnailZoomRatios.push_back (0.45); + thumbnailZoomRatios.push_back (0.6); + thumbnailZoomRatios.push_back (0.8); + thumbnailZoomRatios.push_back (1.0); + overlayedFileNames = true; + + int babehav[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0}; + baBehav = std::vector (babehav, babehav+22); + + rtSettings.dualThreadEnabled = true; + rtSettings.demosaicMethod = "eahd"; + rtSettings.colorCorrectionSteps = 2; + rtSettings.iccDirectory = "/usr/share/color/icc"; + rtSettings.colorimetricIntent = 1; + rtSettings.monitorProfile = ""; + rtSettings.verbose = false; +} + +Options* Options::copyFrom (Options* other) { + + *this = *other; +} + +int Options::readFromFile (Glib::ustring fname) { + + Glib::KeyFile keyFile; + + try { + + if (!keyFile.load_from_file (fname)) + return 1; + + setDefaults (); + +if (keyFile.has_group ("General")) { + Glib::ustring stup; + if (keyFile.has_key ("General", "StartupDirectory") && keyFile.get_string ("General", "StartupDirectory") == "home") + startupDir = STARTUPDIR_HOME; + else if (keyFile.has_key ("General", "StartupDirectory") && keyFile.get_string ("General", "StartupDirectory") == "current") + startupDir = STARTUPDIR_CURRENT; + else if (keyFile.has_key ("General", "StartupDirectory") && keyFile.get_string ("General", "StartupDirectory") == "last") + startupDir = STARTUPDIR_LAST; + else + startupDir = STARTUPDIR_CUSTOM; + + if (keyFile.has_key ("General", "StartupPath")) startupPath = keyFile.get_string ("General", "StartupPath"); + if (keyFile.has_key ("General", "DateFormat")) dateFormat = keyFile.get_string ("General", "DateFormat"); + if (keyFile.has_key ("General", "AdjusterDelay")) Adjuster::delay = keyFile.get_integer ("General", "AdjusterDelay"); + if (keyFile.has_key ("General", "StoreLastProfile")) savesParamsAtExit = keyFile.get_boolean ("General", "StoreLastProfile"); + if (keyFile.has_key ("General", "DualProcSupport")) rtSettings.dualThreadEnabled = keyFile.get_boolean ("General", "DualProcSupport"); + if (keyFile.has_key ("General", "MultiUser")) multiUser = keyFile.get_boolean ("General", "MultiUser"); +// if (keyFile.has_key ("General", "Version")) version = keyFile.get_integer ("General", "Version"); + if (keyFile.has_key ("General", "Language")) language = keyFile.get_string ("General", "Language"); + if (keyFile.has_key ("General", "Theme")) theme = keyFile.get_string ("General", "Theme"); + if (keyFile.has_key ("General", "FirstRun")) firstRun = keyFile.get_boolean ("General", "FirstRun"); +} + +if (keyFile.has_group ("External Editor")) { + if (keyFile.has_key ("External Editor", "EditorKind")) editorToSendTo = keyFile.get_integer ("External Editor", "EditorKind"); + if (keyFile.has_key ("External Editor", "GimpDir")) gimpDir = keyFile.get_string ("External Editor", "GimpDir"); + if (keyFile.has_key ("External Editor", "PhotoshopDir")) psDir = keyFile.get_string ("External Editor", "PhotoshopDir"); + if (keyFile.has_key ("External Editor", "CustomEditor")) customEditorProg = keyFile.get_string ("External Editor", "CustomEditor"); +} + +if (keyFile.has_group ("Output")) { + if (keyFile.has_key ("Output", "Format")) saveFormat.format = keyFile.get_string ("Output", "Format"); + if (keyFile.has_key ("Output", "JpegQuality")) saveFormat.jpegQuality = keyFile.get_integer ("Output", "JpegQuality"); + if (keyFile.has_key ("Output", "PngCompression")) saveFormat.pngCompression = keyFile.get_integer ("Output", "PngCompression"); + if (keyFile.has_key ("Output", "PngBps")) saveFormat.pngBits = keyFile.get_integer ("Output", "PngBps"); + if (keyFile.has_key ("Output", "TiffBps")) saveFormat.tiffBits = keyFile.get_integer ("Output", "TiffBps"); + if (keyFile.has_key ("Output", "SaveProcParams")) saveFormat.saveParams = keyFile.get_boolean ("Output", "SaveProcParams"); + if (keyFile.has_key ("Output", "Path")) savePathTemplate = keyFile.get_string ("Output", "Path"); + if (keyFile.has_key ("Output", "PathTemplate")) savePathTemplate = keyFile.get_string ("Output", "PathTemplate"); + if (keyFile.has_key ("Output", "PathFolder")) savePathFolder = keyFile.get_string ("Output", "PathFolder"); + if (keyFile.has_key ("Output", "UsePathTemplate")) saveUsePathTemplate = keyFile.get_boolean("Output", "UsePathTemplate"); + if (keyFile.has_key ("Output", "LastSaveAsPath")) lastSaveAsPath = keyFile.get_string ("Output", "LastSaveAsPath"); +} + +if (keyFile.has_group ("Profiles")) { + if (keyFile.has_key ("Profiles", "Directory")) profilePath = keyFile.get_string ("Profiles", "Directory"); + if (keyFile.has_key ("Profiles", "RawDefault")) defProfRaw = keyFile.get_string ("Profiles", "RawDefault"); + if (keyFile.has_key ("Profiles", "ImgDefault")) defProfImg = keyFile.get_string ("Profiles", "ImgDefault"); + if (keyFile.has_key ("Profiles", "SaveParamsWithFile")) saveParamsFile = keyFile.get_boolean ("Profiles", "SaveParamsWithFile"); + if (keyFile.has_key ("Profiles", "SaveParamsToCache")) saveParamsCache = keyFile.get_boolean ("Profiles", "SaveParamsToCache"); + if (keyFile.has_key ("Profiles", "LoadParamsFromLocation")) paramsLoadLocation = (PPLoadLocation)keyFile.get_integer ("Profiles", "LoadParamsFromLocation"); +} + +if (keyFile.has_group ("File Browser")) { + if (keyFile.has_key ("File Browser", "ThumbnailSize")) thumbSize = keyFile.get_integer ("File Browser", "ThumbnailSize"); + if (keyFile.has_key ("File Browser", "BrowseOnlyRaw")) fbOnlyRaw = keyFile.get_boolean ("File Browser", "BrowseOnlyRaw"); + if (keyFile.has_key ("File Browser", "BrowserShowsDate")) fbShowDateTime = keyFile.get_boolean ("File Browser", "BrowserShowsDate"); + if (keyFile.has_key ("File Browser", "BrowserShowsExif")) fbShowBasicExif = keyFile.get_boolean ("File Browser", "BrowserShowsExif"); + if (keyFile.has_key ("File Browser", "BrowserShowsHidden")) fbShowHidden = keyFile.get_boolean ("File Browser", "BrowserShowsHidden"); + if (keyFile.has_key ("File Browser", "MaxPreviewHeight")) maxThumbnailHeight = keyFile.get_integer ("File Browser", "MaxPreviewHeight"); + if (keyFile.has_key ("File Browser", "MaxCacheEntries")) maxCacheEntries = keyFile.get_integer ("File Browser", "MaxCacheEntries"); + if (keyFile.has_key ("File Browser", "ThumbnailFormat")) thumbnailFormat = (ThFileType)keyFile.get_integer ("File Browser", "ThumbnailFormat"); + if (keyFile.has_key ("File Browser", "ParseExtensions")) parseExtensions = keyFile.get_string_list ("File Browser", "ParseExtensions"); + if (keyFile.has_key ("File Browser", "ParseExtensionsEnabled")) parseExtensionsEnabled = keyFile.get_integer_list ("File Browser", "ParseExtensionsEnabled"); + if (keyFile.has_key ("File Browser", "ThumbnailArrangement")) fbArrangement = keyFile.get_integer ("File Browser", "ThumbnailArrangement"); + if (keyFile.has_key ("File Browser", "ThumbnailInterpolation")) thumbInterp = keyFile.get_integer ("File Browser", "ThumbnailInterpolation"); + if (keyFile.has_key ("File Browser", "LiveThumbnails")) liveThumbnails = keyFile.get_boolean ("File Browser", "LiveThumbnails"); + if (keyFile.has_key ("File Browser", "FavoriteDirs")) favoriteDirs = keyFile.get_string_list ("File Browser", "FavoriteDirs"); + if (keyFile.has_key ("File Browser", "RenameTemplates")) renameTemplates = keyFile.get_string_list ("File Browser", "RenameTemplates"); + if (keyFile.has_key ("File Browser", "RenameUseTemplates")) renameUseTemplates = keyFile.get_boolean ("File Browser", "RenameUseTemplates"); + if (keyFile.has_key ("File Browser", "ThumbnailZoomRatios"))thumbnailZoomRatios= keyFile.get_double_list ("File Browser", "ThumbnailZoomRatios"); + if (keyFile.has_key ("File Browser", "OverlayedFileNames")) overlayedFileNames = keyFile.get_boolean ("File Browser", "OverlayedFileNames"); +} + +if (keyFile.has_group ("Clipping Indication")) { + if (keyFile.has_key ("Clipping Indication", "HighlightThreshold")) highlightThreshold= keyFile.get_integer ("Clipping Indication", "HighlightThreshold"); + if (keyFile.has_key ("Clipping Indication", "ShadowThreshold")) shadowThreshold = keyFile.get_integer ("Clipping Indication", "ShadowThreshold"); + if (keyFile.has_key ("Clipping Indication", "BlinkClipped")) blinkClipped = keyFile.get_boolean ("Clipping Indication", "BlinkClipped"); +} + +if (keyFile.has_group ("GUI")) { + if (keyFile.has_key ("GUI", "DirBrowserWidth")) dirBrowserWidth = keyFile.get_integer ("GUI", "DirBrowserWidth"); + if (keyFile.has_key ("GUI", "DirBrowserHeight")) dirBrowserHeight = keyFile.get_integer ("GUI", "DirBrowserHeight"); + if (keyFile.has_key ("GUI", "ToolPanelWidth")) toolPanelWidth = keyFile.get_integer ("GUI", "ToolPanelWidth"); + if (keyFile.has_key ("GUI", "BrowserToolPanelWidth"))browserToolPanelWidth = keyFile.get_integer ("GUI", "BrowserToolPanelWidth"); + if (keyFile.has_key ("GUI", "HistoryPanelWidth")) historyPanelWidth = keyFile.get_integer ("GUI", "HistoryPanelWidth"); + if (keyFile.has_key ("GUI", "LastPreviewScale")) lastScale = keyFile.get_integer ("GUI", "LastPreviewScale"); + if (keyFile.has_key ("GUI", "LastCropSize")) lastCropSize = keyFile.get_integer ("GUI", "LastCropSize"); + if (keyFile.has_key ("GUI", "ShowHistory")) showHistory = keyFile.get_boolean ("GUI", "ShowHistory"); + if (keyFile.has_key ("GUI", "ShowFilePanelState")) showFilePanelState= keyFile.get_integer ("GUI", "ShowFilePanelState"); + if (keyFile.has_key ("GUI", "ShowInfo")) showInfo = keyFile.get_boolean ("GUI", "ShowInfo"); + if (keyFile.has_key ("GUI", "ShowClippedHighlights"))showClippedHighlights = keyFile.get_boolean ("GUI", "ShowClippedHighlights"); + if (keyFile.has_key ("GUI", "ShowClippedShadows")) showClippedShadows= keyFile.get_boolean ("GUI", "ShowClippedShadows"); + if (keyFile.has_key ("GUI", "FrameColor")) bgcolor = keyFile.get_integer ("GUI", "FrameColor"); + if (keyFile.has_key ("GUI", "ProcessingQueueEnbled"))procQueueEnabled = keyFile.get_boolean ("GUI", "ProcessingQueueEnbled"); + if (keyFile.has_key ("GUI", "ToolPanelsExpanded")) tpOpen = keyFile.get_integer_list ("GUI", "ToolPanelsExpanded"); + if (keyFile.has_key ("GUI", "CurvePanelsExpanded")) crvOpen = keyFile.get_integer_list ("GUI", "CurvePanelsExpanded"); +} + +if (keyFile.has_group ("Algorithms")) { + if (keyFile.has_key ("Algorithms", "DemosaicMethod")) rtSettings.demosaicMethod = keyFile.get_string ("Algorithms", "DemosaicMethod"); + if (keyFile.has_key ("Algorithms", "ColorCorrection")) rtSettings.colorCorrectionSteps = keyFile.get_integer ("Algorithms", "ColorCorrection"); +} + +if (keyFile.has_group ("Crop Settings")) { + if (keyFile.has_key ("Crop Settings", "DPI")) cropDPI = keyFile.get_integer ("Crop Settings", "DPI"); +} + +if (keyFile.has_group ("Color Management")) { + if (keyFile.has_key ("Color Management", "ICCDirectory")) rtSettings.iccDirectory = keyFile.get_string ("Color Management", "ICCDirectory"); + if (keyFile.has_key ("Color Management", "MonitorProfile")) rtSettings.monitorProfile = keyFile.get_string ("Color Management", "MonitorProfile"); + if (keyFile.has_key ("Color Management", "Intent")) rtSettings.colorimetricIntent = keyFile.get_integer("Color Management", "Intent"); +} + +if (keyFile.has_group ("Batch Processing")) { + if (keyFile.has_key ("Batch Processing", "AdjusterBehavior")) baBehav = keyFile.get_integer_list ("Batch Processing", "AdjusterBehavior"); +} + + return 0; + } + catch (Glib::Error) { + return 1; + } +} + +int Options::saveToFile (Glib::ustring fname) { + + Glib::KeyFile keyFile; + + keyFile.set_boolean ("General", "StoreLastProfile", savesParamsAtExit); + if (startupDir==STARTUPDIR_HOME) + keyFile.set_string ("General", "StartupDirectory", "home"); + else if (startupDir==STARTUPDIR_CURRENT) + keyFile.set_string ("General", "StartupDirectory", "current"); + else if (startupDir==STARTUPDIR_CUSTOM) + keyFile.set_string ("General", "StartupDirectory", "custom"); + else if (startupDir==STARTUPDIR_LAST) + keyFile.set_string ("General", "StartupDirectory", "last"); + keyFile.set_string ("General", "StartupPath", startupPath); + keyFile.set_string ("General", "DateFormat", dateFormat); + keyFile.set_integer ("General", "AdjusterDelay", Adjuster::delay); + keyFile.set_boolean ("General", "DualProcSupport", rtSettings.dualThreadEnabled); + keyFile.set_boolean ("General", "MultiUser", multiUser); + keyFile.set_string ("General", "Language", language); + keyFile.set_string ("General", "Theme", theme); + keyFile.set_integer ("General", "Version", 290); + keyFile.set_boolean ("General", "FirstRun", firstRun); + + keyFile.set_integer ("External Editor", "EditorKind", editorToSendTo); + keyFile.set_string ("External Editor", "GimpDir", gimpDir); + keyFile.set_string ("External Editor", "PhotoshopDir", psDir); + keyFile.set_string ("External Editor", "CustomEditor", customEditorProg); + + + keyFile.set_boolean ("File Browser", "BrowseOnlyRaw", fbOnlyRaw); + keyFile.set_boolean ("File Browser", "BrowserShowsDate", fbShowDateTime); + keyFile.set_boolean ("File Browser", "BrowserShowsExif", fbShowBasicExif); + keyFile.set_boolean ("File Browser", "BrowserShowsHidden", fbShowHidden); + keyFile.set_integer ("File Browser", "ThumbnailSize", thumbSize); + keyFile.set_integer ("File Browser", "MaxPreviewHeight", maxThumbnailHeight); + keyFile.set_integer ("File Browser", "MaxCacheEntries", maxCacheEntries); + keyFile.set_integer ("File Browser", "ThumbnailFormat", (int)thumbnailFormat); + Glib::ArrayHandle pext = parseExtensions; + keyFile.set_string_list ("File Browser", "ParseExtensions", pext); + Glib::ArrayHandle pextena = parseExtensionsEnabled; + keyFile.set_integer_list ("File Browser", "ParseExtensionsEnabled", pextena); + keyFile.set_integer ("File Browser", "ThumbnailArrangement", fbArrangement); + keyFile.set_integer ("File Browser", "ThumbnailInterpolation", thumbInterp); + keyFile.set_boolean ("File Browser", "LiveThumbnails", liveThumbnails); + Glib::ArrayHandle pfav = favoriteDirs; + keyFile.set_string_list ("File Browser", "FavoriteDirs", pfav); + Glib::ArrayHandle pren = renameTemplates; + keyFile.set_string_list ("File Browser", "RenameTemplates", pren); + keyFile.set_boolean ("File Browser", "RenameUseTemplates", renameUseTemplates); + Glib::ArrayHandle ptzoom = thumbnailZoomRatios; + keyFile.set_double_list ("File Browser", "ThumbnailZoomRatios", ptzoom); + keyFile.set_boolean ("File Browser", "OverlayedFileNames", overlayedFileNames); + + keyFile.set_integer ("Clipping Indication", "HighlightThreshold", highlightThreshold); + keyFile.set_integer ("Clipping Indication", "ShadowThreshold", shadowThreshold); + keyFile.set_boolean ("Clipping Indication", "BlinkClipped", blinkClipped); + + keyFile.set_string ("Output", "Format", saveFormat.format); + keyFile.set_integer ("Output", "JpegQuality", saveFormat.jpegQuality); + keyFile.set_integer ("Output", "PngCompression", saveFormat.pngCompression); + keyFile.set_integer ("Output", "PngBps", saveFormat.pngBits); + keyFile.set_integer ("Output", "TiffBps", saveFormat.tiffBits); + keyFile.set_boolean ("Output", "SaveProcParams", saveFormat.saveParams); + keyFile.set_string ("Output", "PathTemplate", savePathTemplate); + keyFile.set_string ("Output", "PathFolder", savePathFolder); + keyFile.set_boolean("Output", "UsePathTemplate", saveUsePathTemplate); + keyFile.set_string ("Output", "LastSaveAsPath", lastSaveAsPath); + + keyFile.set_string ("Profiles", "Directory", profilePath); + keyFile.set_string ("Profiles", "RawDefault", defProfRaw); + keyFile.set_string ("Profiles", "ImgDefault", defProfImg); + keyFile.set_boolean ("Profiles", "SaveParamsWithFile", saveParamsFile); + keyFile.set_boolean ("Profiles", "SaveParamsToCache", saveParamsCache); + keyFile.set_integer ("Profiles", "LoadParamsFromLocation", paramsLoadLocation); + + keyFile.set_integer ("GUI", "DirBrowserWidth", dirBrowserWidth); + keyFile.set_integer ("GUI", "DirBrowserHeight", dirBrowserHeight); + keyFile.set_integer ("GUI", "ToolPanelWidth", toolPanelWidth); + keyFile.set_integer ("GUI", "BrowserToolPanelWidth", browserToolPanelWidth); + keyFile.set_integer ("GUI", "HistoryPanelWidth", historyPanelWidth); + keyFile.set_integer ("GUI", "LastPreviewScale", lastScale); + keyFile.set_integer ("GUI", "LastCropSize", lastCropSize); + keyFile.set_boolean ("GUI", "ShowHistory", showHistory); + keyFile.set_integer ("GUI", "ShowFilePanelState", showFilePanelState); + keyFile.set_boolean ("GUI", "ShowInfo", showInfo); + keyFile.set_boolean ("GUI", "ShowClippedHighlights", showClippedHighlights); + keyFile.set_boolean ("GUI", "ShowClippedShadows", showClippedShadows); + keyFile.set_integer ("GUI", "FrameColor", bgcolor); + keyFile.set_boolean ("GUI", "ProcessingQueueEnbled", procQueueEnabled); + Glib::ArrayHandle tpopen = tpOpen; + keyFile.set_integer_list ("GUI", "ToolPanelsExpanded", tpopen); + Glib::ArrayHandle crvopen = crvOpen; + keyFile.set_integer_list ("GUI", "CurvePanelsExpanded", crvopen); + + keyFile.set_string ("Algorithms", "DemosaicMethod", rtSettings.demosaicMethod); + keyFile.set_integer ("Algorithms", "ColorCorrection", rtSettings.colorCorrectionSteps); + + keyFile.set_integer ("Crop Settings", "DPI", cropDPI); + + keyFile.set_string ("Color Management", "ICCDirectory", rtSettings.iccDirectory); + keyFile.set_string ("Color Management", "MonitorProfile", rtSettings.monitorProfile); + keyFile.set_integer ("Color Management", "Intent", rtSettings.colorimetricIntent); + + Glib::ArrayHandle bab = baBehav; + keyFile.set_integer_list ("Batch Processing", "AdjusterBehavior", bab); + + + FILE *f = g_fopen (fname.c_str(), "wt"); + if (f==NULL) + return 1; + else { + fprintf (f, "%s", keyFile.to_data().c_str()); + fclose (f); + return 0; + } +} + +Glib::ustring Options::rtdir; +Glib::ustring Options::cacheBaseDir; + +void Options::load () { + + rtdir = Glib::ustring(g_get_user_config_dir ())+"/RawTherapeeAlpha"; + options.readFromFile (argv0+"/options"); + cacheBaseDir = argv0 + "/cache"; + if (options.multiUser) { + int r = options.readFromFile (rtdir + "/options"); + if (r && !g_mkdir_with_parents (rtdir.c_str(), 511)) { + Glib::ustring profdir = rtdir + "/profiles"; + g_mkdir_with_parents (profdir.c_str(), 511); + options.saveToFile (rtdir + "/options"); + } + cacheBaseDir = rtdir + "/cache"; + } + if (!langMgr.load (argv0+"/languages/"+options.language, new MultiLangMgr (argv0+"/languages/english-us"))) + langMgr.load (argv0+"/languages/english-us"); + + rtengine::init (&options.rtSettings); +} + +void Options::save () { + + if (options.multiUser==false) { + options.saveToFile (argv0+"/options"); + } + else { + options.saveToFile (rtdir + "/options"); + } +} diff --git a/rtgui/options.h b/rtgui/options.h new file mode 100755 index 000000000..5c1a2f324 --- /dev/null +++ b/rtgui/options.h @@ -0,0 +1,137 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _OPTIONS_ +#define _OPTIONS_ + +#include +#include + +#define STARTUPDIR_CURRENT 0 +#define STARTUPDIR_HOME 1 +#define STARTUPDIR_CUSTOM 2 +#define STARTUPDIR_LAST 3 + +class SaveFormat { + + public: + Glib::ustring format; + int pngBits; + int pngCompression; + int jpegQuality; + int tiffBits; + bool tiffUncompressed; + bool saveParams; +}; + +enum ThFileType {FT_Invalid=-1, FT_None=0, FT_Raw=1, FT_Jpeg=2, FT_Tiff=3, FT_Png=4, FT_Custom=5, FT_Tiff16=6, FT_Png16=7, FT_Custom16=8}; +enum PPLoadLocation {PLL_Cache=0, PLL_Input=1}; + +class Options { + + private: + int getString (const char* src, char* dst); + void error (int line); + + public: + bool firstRun; + bool savesParamsAtExit; + SaveFormat saveFormat; + Glib::ustring savePathTemplate; + Glib::ustring savePathFolder; + bool saveUsePathTemplate; + Glib::ustring defProfRaw; + Glib::ustring defProfImg; + Glib::ustring dateFormat; + int startupDir; + Glib::ustring startupPath; + Glib::ustring profilePath; + Glib::ustring lastSaveAsPath; + int toolPanelWidth; + int browserToolPanelWidth; + int historyPanelWidth; + int dirBrowserWidth; + int dirBrowserHeight; + int lastScale; + int lastCropSize; + bool fbOnlyRaw; + bool fbShowDateTime; + bool fbShowBasicExif; + bool fbShowHidden; + int fbArrangement; + bool multiUser; + static Glib::ustring rtdir; + int version; + int thumbSize; + bool showHistory; + int showFilePanelState; // 0: normal, 1: maximized, 2: normal, 3: hidden + bool showInfo; + int cropDPI; + bool showClippedHighlights; + bool showClippedShadows; + int highlightThreshold; + int shadowThreshold; + bool blinkClipped; + int bgcolor; + Glib::ustring language; + Glib::ustring theme; + static Glib::ustring cacheBaseDir; + bool saveParamsFile; + bool saveParamsCache; + PPLoadLocation paramsLoadLocation; + bool procQueueEnabled; + Glib::ustring gimpDir; + Glib::ustring psDir; + Glib::ustring customEditorProg; + int editorToSendTo; + int maxThumbnailHeight; + int maxCacheEntries; + ThFileType thumbnailFormat; + int thumbInterp; // 0: nearest, 1: bilinear + bool liveThumbnails; + std::vector parseExtensions; + std::vector parseExtensionsEnabled; + std::vector tpOpen; + std::vector crvOpen; + std::vector baBehav; + rtengine::Settings rtSettings; + + std::vector favoriteDirs; + std::vector renameTemplates; + bool renameUseTemplates; + + std::vector thumbnailZoomRatios; + bool overlayedFileNames; + + + Options (); + + Options* copyFrom (Options* other); + void setDefaults (); + int readFromFile (Glib::ustring fname); + int saveToFile (Glib::ustring fname); + static void load (); + static void save (); +}; + +extern Options options; +extern Glib::ustring argv0; +extern Glib::ustring argv1; +extern Glib::ustring versionString; + +#endif diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc new file mode 100755 index 000000000..d23a8045e --- /dev/null +++ b/rtgui/paramsedited.cc @@ -0,0 +1,328 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include + +ParamsEdited::ParamsEdited () { + + set (false); +} + +void ParamsEdited::set (bool v) { + + toneCurve.curve = v; + toneCurve.brightness = v; + toneCurve.black = v; + toneCurve.contrast = v; + toneCurve.shcompr = v; + toneCurve.hlcompr = v; + toneCurve.autoexp = v; + toneCurve.clip = v; + toneCurve.expcomp = v; + lumaCurve.curve = v; + lumaCurve.brightness = v; + lumaCurve.black = v; + lumaCurve.contrast = v; + lumaCurve.shcompr = v; + lumaCurve.hlcompr = v; + sharpening.enabled = v; + sharpening.radius = v; + sharpening.amount = v; + sharpening.threshold = v; + sharpening.edgesonly = v; + sharpening.edges_radius = v; + sharpening.edges_tolerance = v; + sharpening.halocontrol = v; + sharpening.halocontrol_amount= v; + sharpening.method = v; + sharpening.deconvamount = v; + sharpening.deconvradius = v; + sharpening.deconviter = v; + sharpening.deconvdamping = v; + colorBoost.amount = v; + colorBoost.avoidclip = v; + colorBoost.enable_saturationlimiter = v; + colorBoost.saturationlimit = v; + wb.method = v; + wb.green = v; + wb.temperature = v; + colorShift.a = v; + colorShift.b = v; + lumaDenoise.enabled = v; + lumaDenoise.radius = v; + lumaDenoise.edgetolerance = v; + colorDenoise.enabled = v; + colorDenoise.amount = v; + sh.enabled = v; + sh.hq = v; + sh.highlights = v; + sh.htonalwidth = v; + sh.shadows = v; + sh.stonalwidth = v; + sh.localcontrast = v; + sh.radius = v; + crop.enabled = v; + crop.x = v; + crop.y = v; + crop.w = v; + crop.h = v; + crop.fixratio = v; + crop.ratio = v; + crop.orientation = v; + crop.guide = v; + coarse.rotate = v; + coarse.hflip = v; + coarse.vflip = v; + rotate.degree = v; + rotate.fill = v; + distortion.amount = v; + cacorrection.red = v; + cacorrection.blue = v; + vignetting.amount = v; + vignetting.radius = v; + chmixer.red[0] = v; + chmixer.red[1] = v; + chmixer.red[2] = v; + chmixer.green[0] = v; + chmixer.green[1] = v; + chmixer.green[2] = v; + chmixer.blue[0] = v; + chmixer.blue[1] = v; + chmixer.blue[2] = v; + hlrecovery.enabled = v; + hlrecovery.method = v; + resize.scale = v; + resize.method = v; + resize.dataspec = v; + resize.width = v; + resize.height = v; + resize.enabled = v; + icm.input = v; + icm.gammaOnInput = v; + icm.working = v; + icm.output = v; + exif.clear (); + iptc.clear (); +} + +using namespace rtengine; +using namespace rtengine::procparams; + +void ParamsEdited::initFrom (const std::vector& src) { + + set (true); + if (src.size()==0) + return; + + const ProcParams& p = src[0]; + for (int i=1; i + * + * 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 . + */ +#ifndef _PARAMEDITED_H_ +#define _PARAMEDITED_H_ + +#include +#include +#include +#include + +class CurveParamsEdited { + + public: + bool curve; + bool brightness; + bool black; + bool contrast; + bool shcompr; + bool hlcompr; +}; + +class ToneCurveParamsEdited : public CurveParamsEdited { + + public: + bool autoexp; + bool clip; + bool expcomp; +}; + +class SharpeningParamsEdited { + + public: + bool enabled; + bool radius; + bool amount; + bool threshold; + bool edgesonly; + bool edges_radius; + bool edges_tolerance; + bool halocontrol; + bool halocontrol_amount; + + bool method; + bool deconvamount; + bool deconvradius; + bool deconviter; + bool deconvdamping; +}; + +class ColorBoostParamsEdited { + + public: + bool amount; + bool avoidclip; + bool enable_saturationlimiter; + bool saturationlimit; +}; + +class WBParamsEdited { + + public: + bool method; + bool temperature; + bool green; +}; + +class ColorShiftParamsEdited { + + public: + bool a; + bool b; +}; + +class LumaDenoiseParamsEdited { + + public: + bool enabled; + bool radius; + bool edgetolerance; +}; + +class ColorDenoiseParamsEdited { + + public: + bool enabled; + bool amount; +}; + +class SHParamsEdited { + + public: + bool enabled; + bool hq; + bool highlights; + bool htonalwidth; + bool shadows; + bool stonalwidth; + bool localcontrast; + bool radius; +}; + +class CropParamsEdited { + + public: + bool enabled; + bool x; + bool y; + bool w; + bool h; + bool fixratio; + bool ratio; + bool orientation; + bool guide; +}; + +class CoarseTransformParamsEdited { + + public: + bool rotate; + bool hflip; + bool vflip; +}; + +class RotateParamsEdited { + + public: + bool degree; + bool fill; +}; + +class DistortionParamsEdited { + + public: + bool amount; +}; + +class VignettingParamsEdited { + + public: + bool amount; + bool radius; +}; + +class ChannelMixerParamsEdited { + + public: + bool red[3]; + bool green[3]; + bool blue[3]; +}; + +class CACorrParamsEdited { + + public: + bool red; + bool blue; +}; + +class HRecParamsEdited { + + public: + bool enabled; + bool method; +}; + +class ResizeParamsEdited { + + public: + bool scale; + bool method; + bool dataspec; + bool width; + bool height; + bool enabled; +}; + +class ColorManagementParamsEdited { + + public: + bool input; + bool gammaOnInput; + bool working; + bool output; +}; + +class ExifPairEdited { + + public: + Glib::ustring field; + bool value; +}; + +class IPTCPairEdited { + + public: + Glib::ustring field; + bool values; +}; + +class ParamsEdited { + + public: + ToneCurveParamsEdited toneCurve; + CurveParamsEdited lumaCurve; + SharpeningParamsEdited sharpening; + ColorBoostParamsEdited colorBoost; + WBParamsEdited wb; + ColorShiftParamsEdited colorShift; + LumaDenoiseParamsEdited lumaDenoise; + ColorDenoiseParamsEdited colorDenoise; + SHParamsEdited sh; + CropParamsEdited crop; + CoarseTransformParamsEdited coarse; + RotateParamsEdited rotate; + DistortionParamsEdited distortion; + CACorrParamsEdited cacorrection; + VignettingParamsEdited vignetting; + ChannelMixerParamsEdited chmixer; + HRecParamsEdited hlrecovery; + ResizeParamsEdited resize; + ColorManagementParamsEdited icm; + std::vector exif; + std::vector iptc; + + ParamsEdited (); + + void set (bool v); + void initFrom (const std::vector& src); + void combine (rtengine::procparams::ProcParams& toEdit, const rtengine::procparams::ProcParams& mods); + + bool operator== (const ParamsEdited& other); + bool operator!= (const ParamsEdited& other); +}; +#endif diff --git a/rtgui/partialpastedlg.cc b/rtgui/partialpastedlg.cc new file mode 100755 index 000000000..21641b614 --- /dev/null +++ b/rtgui/partialpastedlg.cc @@ -0,0 +1,315 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +PartialPasteDlg::PartialPasteDlg () { + + set_modal (true); + set_title (M("PARTIALPASTE_DIALOGLABEL")); + + basic = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_BASICGROUP"))); + luminance = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_LUMINANCEGROUP"))); + color = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_COLORGROUP"))); + lens = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_LENSGROUP"))); + composition = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_COMPOSITIONGROUP"))); + metaicm = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_METAICMGROUP"))); + + // options in basic: + wb = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_WHITEBALANCE"))); + exposure = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_EXPOSURE"))); + hlrec = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_HLRECOVERY"))); + + // options in luminance: + sharpen = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_SHARPENING"))); + lumaden = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_LUMADENOISE"))); + lumacurve = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_LUMACURVE"))); + sh = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_SHADOWSHIGHLIGHTS"))); + + // options in color: + colormixer = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_COLORMIXER"))); + colorshift = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_COLORSHIFT"))); + colorboost = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_COLORBOOST"))); + colorden = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_COLORDENOISE"))); + + // options in lens: + distortion = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_DISTORTION"))); + cacorr = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_CACORRECTION"))); + vignetting = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_VIGNETTING"))); + + // options in composition: + coarserot = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_COARSETRANS"))); + finerot = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_ROTATION"))); + crop = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_CROP"))); + resize = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_RESIZE"))); + + // options in metaicm: + exifch = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_EXIFCHANGES"))); + iptc = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_IPTCINFO"))); + icm = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_ICMSETTINGS"))); + + Gtk::VBox* vboxes[6]; + Gtk::HSeparator* hseps[6]; + for (int i=0; i<6; i++) { + vboxes[i] = Gtk::manage (new Gtk::VBox ()); + vboxes[i]->set_border_width (16); + hseps[i] = Gtk::manage (new Gtk::HSeparator ()); + } + + vboxes[0]->pack_start (*basic, Gtk::PACK_SHRINK, 2); + vboxes[0]->pack_start (*hseps[0], Gtk::PACK_SHRINK, 2); + vboxes[0]->pack_start (*wb, Gtk::PACK_SHRINK, 2); + vboxes[0]->pack_start (*exposure, Gtk::PACK_SHRINK, 2); + vboxes[0]->pack_start (*hlrec, Gtk::PACK_SHRINK, 2); + + vboxes[1]->pack_start (*luminance, Gtk::PACK_SHRINK, 2); + vboxes[1]->pack_start (*hseps[1], Gtk::PACK_SHRINK, 2); + vboxes[1]->pack_start (*sharpen, Gtk::PACK_SHRINK, 2); + vboxes[1]->pack_start (*lumaden, Gtk::PACK_SHRINK, 2); + vboxes[1]->pack_start (*lumacurve, Gtk::PACK_SHRINK, 2); + vboxes[1]->pack_start (*sh, Gtk::PACK_SHRINK, 2); + + vboxes[2]->pack_start (*color, Gtk::PACK_SHRINK, 2); + vboxes[2]->pack_start (*hseps[2], Gtk::PACK_SHRINK, 2); + vboxes[2]->pack_start (*colormixer, Gtk::PACK_SHRINK, 2); + vboxes[2]->pack_start (*colorshift, Gtk::PACK_SHRINK, 2); + vboxes[2]->pack_start (*colorboost, Gtk::PACK_SHRINK, 2); + vboxes[2]->pack_start (*colorden, Gtk::PACK_SHRINK, 2); + + + vboxes[3]->pack_start (*lens, Gtk::PACK_SHRINK, 2); + vboxes[3]->pack_start (*hseps[3], Gtk::PACK_SHRINK, 2); + vboxes[3]->pack_start (*distortion, Gtk::PACK_SHRINK, 2); + vboxes[3]->pack_start (*cacorr, Gtk::PACK_SHRINK, 2); + vboxes[3]->pack_start (*vignetting, Gtk::PACK_SHRINK, 2); + + vboxes[4]->pack_start (*composition, Gtk::PACK_SHRINK, 2); + vboxes[4]->pack_start (*hseps[4], Gtk::PACK_SHRINK, 2); + vboxes[4]->pack_start (*coarserot, Gtk::PACK_SHRINK, 2); + vboxes[4]->pack_start (*finerot, Gtk::PACK_SHRINK, 2); + vboxes[4]->pack_start (*crop, Gtk::PACK_SHRINK, 2); + vboxes[4]->pack_start (*resize, Gtk::PACK_SHRINK, 2); + + vboxes[5]->pack_start (*metaicm, Gtk::PACK_SHRINK, 2); + vboxes[5]->pack_start (*hseps[5], Gtk::PACK_SHRINK, 2); + vboxes[5]->pack_start (*exifch, Gtk::PACK_SHRINK, 2); + vboxes[5]->pack_start (*iptc, Gtk::PACK_SHRINK, 2); + vboxes[5]->pack_start (*icm, Gtk::PACK_SHRINK, 2); + + Gtk::VBox* vbleft = Gtk::manage (new Gtk::VBox ()); + Gtk::VBox* vbright = Gtk::manage (new Gtk::VBox ()); + + vbleft->set_border_width (16); + vbright->set_border_width (16); + + for (int i=0; i<3; i++) + vbleft->pack_start (*vboxes[i]); + for (int i=3; i<6; i++) + vbright->pack_start (*vboxes[i]); + + Gtk::HBox* hbmain = Gtk::manage (new Gtk::HBox ()); + hbmain->pack_start (*vbleft); + hbmain->pack_start (*(Gtk::manage (new Gtk::VSeparator ()))); + hbmain->pack_start (*vbright); + + get_vbox()->pack_start (*hbmain); + + basicConn = basic->signal_toggled().connect (sigc::mem_fun(*this, &PartialPasteDlg::basicToggled)); + luminanceConn = luminance->signal_toggled().connect (sigc::mem_fun(*this, &PartialPasteDlg::luminanceToggled)); + colorConn = color->signal_toggled().connect (sigc::mem_fun(*this, &PartialPasteDlg::colorToggled)); + lensConn = lens->signal_toggled().connect (sigc::mem_fun(*this, &PartialPasteDlg::lensToggled)); + compositionConn = composition->signal_toggled().connect (sigc::mem_fun(*this, &PartialPasteDlg::compositionToggled)); + metaicmConn = metaicm->signal_toggled().connect (sigc::mem_fun(*this, &PartialPasteDlg::metaicmToggled)); + + wbConn = wb->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true)); + exposureConn = exposure->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true)); + hlrecConn = hlrec->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true)); + + sharpenConn = sharpen->signal_toggled().connect (sigc::bind (sigc::mem_fun(*luminance, &Gtk::CheckButton::set_inconsistent), true)); + lumadenConn = lumaden->signal_toggled().connect (sigc::bind (sigc::mem_fun(*luminance, &Gtk::CheckButton::set_inconsistent), true)); + lumacurveConn = lumacurve->signal_toggled().connect (sigc::bind (sigc::mem_fun(*luminance, &Gtk::CheckButton::set_inconsistent), true)); + shConn = sh->signal_toggled().connect (sigc::bind (sigc::mem_fun(*luminance, &Gtk::CheckButton::set_inconsistent), true)); + + colormixerConn = colormixer->signal_toggled().connect (sigc::bind (sigc::mem_fun(*color, &Gtk::CheckButton::set_inconsistent), true)); + colorshiftConn = colorshift->signal_toggled().connect (sigc::bind (sigc::mem_fun(*color, &Gtk::CheckButton::set_inconsistent), true)); + colorboostConn = colorboost->signal_toggled().connect (sigc::bind (sigc::mem_fun(*color, &Gtk::CheckButton::set_inconsistent), true)); + colordenConn = colorden->signal_toggled().connect (sigc::bind (sigc::mem_fun(*color, &Gtk::CheckButton::set_inconsistent), true)); + + distortionConn = distortion->signal_toggled().connect (sigc::bind (sigc::mem_fun(*lens, &Gtk::CheckButton::set_inconsistent), true)); + cacorrConn = cacorr->signal_toggled().connect (sigc::bind (sigc::mem_fun(*lens, &Gtk::CheckButton::set_inconsistent), true)); + vignettingConn = vignetting->signal_toggled().connect (sigc::bind (sigc::mem_fun(*lens, &Gtk::CheckButton::set_inconsistent), true)); + + coarserotConn = coarserot->signal_toggled().connect (sigc::bind (sigc::mem_fun(*composition, &Gtk::CheckButton::set_inconsistent), true)); + finerotConn = finerot->signal_toggled().connect (sigc::bind (sigc::mem_fun(*composition, &Gtk::CheckButton::set_inconsistent), true)); + cropConn = crop->signal_toggled().connect (sigc::bind (sigc::mem_fun(*composition, &Gtk::CheckButton::set_inconsistent), true)); + resizeConn = resize->signal_toggled().connect (sigc::bind (sigc::mem_fun(*composition, &Gtk::CheckButton::set_inconsistent), true)); + + exifchConn = exifch->signal_toggled().connect (sigc::bind (sigc::mem_fun(*metaicm, &Gtk::CheckButton::set_inconsistent), true)); + iptcConn = iptc->signal_toggled().connect (sigc::bind (sigc::mem_fun(*metaicm, &Gtk::CheckButton::set_inconsistent), true)); + icmConn = icm->signal_toggled().connect (sigc::bind (sigc::mem_fun(*metaicm, &Gtk::CheckButton::set_inconsistent), true)); + + add_button (Gtk::StockID("gtk-ok"), 1); + add_button (Gtk::StockID("gtk-cancel"), 0); + set_response_sensitive (1); + set_default_response (1); + show_all_children (); +} + +void PartialPasteDlg::basicToggled () { + + wbConn.block (true); + exposureConn.block (true); + hlrecConn.block (true); + + basic->set_inconsistent (false); + + wb->set_active (basic->get_active ()); + exposure->set_active (basic->get_active ()); + hlrec->set_active (basic->get_active ()); + + wbConn.block (false); + exposureConn.block (false); + hlrecConn.block (false); +} + +void PartialPasteDlg::luminanceToggled () { + + sharpenConn.block (true); + lumadenConn.block (true); + lumacurveConn.block (true); + shConn.block (true); + + luminance->set_inconsistent (false); + + sharpen->set_active (luminance->get_active ()); + lumaden->set_active (luminance->get_active ()); + lumacurve->set_active (luminance->get_active ()); + sh->set_active (luminance->get_active ()); + + sharpenConn.block (false); + lumadenConn.block (false); + lumacurveConn.block (false); + shConn.block (false); +} + +void PartialPasteDlg::colorToggled () { + + colormixerConn.block (true); + colorshiftConn.block (true); + colorboostConn.block (true); + colordenConn.block (true); + + color->set_inconsistent (false); + + colormixer->set_active (color->get_active ()); + colorshift->set_active (color->get_active ()); + colorboost->set_active (color->get_active ()); + colorden->set_active (color->get_active ()); + + colormixerConn.block (false); + colorshiftConn.block (false); + colorboostConn.block (false); + colordenConn.block (false); +} + +void PartialPasteDlg::lensToggled () { + + distortionConn.block (true); + cacorrConn.block (true); + vignettingConn.block (true); + + lens->set_inconsistent (false); + + distortion->set_active (lens->get_active ()); + cacorr->set_active (lens->get_active ()); + vignetting->set_active (lens->get_active ()); + + distortionConn.block (false); + cacorrConn.block (false); + vignettingConn.block (false); +} + +void PartialPasteDlg::compositionToggled () { + + coarserotConn.block (true); + finerotConn.block (true); + cropConn.block (true); + resizeConn.block (true); + + composition->set_inconsistent (false); + + coarserot->set_active (composition->get_active ()); + finerot->set_active (composition->get_active ()); + crop->set_active (composition->get_active ()); + resize->set_active (composition->get_active ()); + + coarserotConn.block (false); + finerotConn.block (false); + cropConn.block (false); + resizeConn.block (false); +} + +void PartialPasteDlg::metaicmToggled () { + + exifchConn.block (true); + iptcConn.block (true); + icmConn.block (true); + + metaicm->set_inconsistent (false); + + exifch->set_active (metaicm->get_active ()); + iptc->set_active (metaicm->get_active ()); + icm->set_active (metaicm->get_active ()); + + exifchConn.block (false); + iptcConn.block (false); + icmConn.block (false); +} + + +void PartialPasteDlg::applyPaste (rtengine::procparams::ProcParams* dst, const rtengine::procparams::ProcParams* src) { + + if (wb->get_active ()) dst->wb = src->wb; + if (exposure->get_active ()) dst->toneCurve = src->toneCurve; + if (hlrec->get_active ()) dst->hlrecovery = src->hlrecovery; + + if (sharpen->get_active ()) dst->sharpening = src->sharpening; + if (lumaden->get_active ()) dst->lumaDenoise = src->lumaDenoise; + if (lumacurve->get_active ()) dst->lumaCurve = src->lumaCurve; + if (sh->get_active ()) dst->sh = src->sh; + + if (colormixer->get_active ()) dst->chmixer = src->chmixer; + if (colorshift->get_active ()) dst->colorShift = src->colorShift; + if (colorboost->get_active ()) dst->colorBoost = src->colorBoost; + if (colorden->get_active ()) dst->colorDenoise = src->colorDenoise; + + if (distortion->get_active ()) dst->distortion = src->distortion; + if (cacorr->get_active ()) dst->cacorrection = src->cacorrection; + if (vignetting->get_active ()) dst->vignetting = src->vignetting; + + if (coarserot->get_active ()) dst->coarse = src->coarse; + if (finerot->get_active ()) dst->rotate = src->rotate; + if (crop->get_active ()) dst->crop = src->crop; + if (resize->get_active ()) dst->resize = src->resize; + + if (exifch->get_active ()) dst->exif = src->exif; + if (iptc->get_active ()) dst->iptc = src->iptc; + if (icm->get_active ()) dst->icm = src->icm; +} + diff --git a/rtgui/partialpastedlg.h b/rtgui/partialpastedlg.h new file mode 100755 index 000000000..6a42a5033 --- /dev/null +++ b/rtgui/partialpastedlg.h @@ -0,0 +1,92 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _PARTIALPASTEDLG_ +#define _PARTIALPASTEDLG_ + +#include +#include + +class PartialPasteDlg : public Gtk::Dialog { + + public: + // main groups: + Gtk::CheckButton* basic; + Gtk::CheckButton* luminance; + Gtk::CheckButton* color; + Gtk::CheckButton* lens; + Gtk::CheckButton* composition; + Gtk::CheckButton* metaicm; + + // options in basic: + Gtk::CheckButton* wb; + Gtk::CheckButton* exposure; + Gtk::CheckButton* hlrec; + + // options in luminance: + Gtk::CheckButton* sharpen; + Gtk::CheckButton* lumaden; + Gtk::CheckButton* lumacurve; + Gtk::CheckButton* sh; + + // options in color: + Gtk::CheckButton* colormixer; + Gtk::CheckButton* colorshift; + Gtk::CheckButton* colorboost; + Gtk::CheckButton* colorden; + + // options in lens: + Gtk::CheckButton* distortion; + Gtk::CheckButton* cacorr; + Gtk::CheckButton* vignetting; + + // options in composition: + Gtk::CheckButton* coarserot; + Gtk::CheckButton* finerot; + Gtk::CheckButton* crop; + Gtk::CheckButton* resize; + + // options in metaicm: + Gtk::CheckButton* exifch; + Gtk::CheckButton* iptc; + Gtk::CheckButton* icm; + + sigc::connection basicConn, luminanceConn, colorConn, lensConn, compositionConn, metaicmConn; + sigc::connection wbConn, exposureConn, hlrecConn; + sigc::connection sharpenConn, lumadenConn, lumacurveConn, shConn; + sigc::connection colormixerConn, colorshiftConn, colorboostConn, colordenConn; + sigc::connection distortionConn, cacorrConn, vignettingConn; + sigc::connection coarserotConn, finerotConn, cropConn, resizeConn; + sigc::connection exifchConn, iptcConn, icmConn; + + + public: + PartialPasteDlg (); + + void applyPaste (rtengine::procparams::ProcParams* dst, const rtengine::procparams::ProcParams* src); + + void basicToggled (); + void luminanceToggled (); + void colorToggled (); + void lensToggled (); + void compositionToggled (); + void metaicmToggled (); +}; + +#endif + diff --git a/rtgui/placesbrowser.cc b/rtgui/placesbrowser.cc new file mode 100755 index 000000000..b4a69376c --- /dev/null +++ b/rtgui/placesbrowser.cc @@ -0,0 +1,294 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include + +PlacesBrowser::PlacesBrowser () : listener (NULL) { + + scrollw = Gtk::manage (new Gtk::ScrolledWindow ()); + scrollw->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); + pack_start (*scrollw); + + add = Gtk::manage (new Gtk::Button ("Add")); + del = Gtk::manage (new Gtk::Button ("Del")); + add->set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::ADD, Gtk::ICON_SIZE_MENU))); + del->set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::REMOVE, Gtk::ICON_SIZE_MENU))); + Gtk::HBox* buttonBox = Gtk::manage (new Gtk::HBox ()); + buttonBox->pack_start (*add); + buttonBox->pack_start (*del); + + pack_start (*buttonBox, Gtk::PACK_SHRINK, 2); + + treeView = Gtk::manage (new Gtk::TreeView ()); + treeView->unset_flags (Gtk::CAN_FOCUS); + scrollw->add (*treeView); + + placesModel = Gtk::ListStore::create (placesColumns); + treeView->set_model (placesModel); + treeView->set_headers_visible (true); + + Gtk::TreeView::Column *iviewcol = Gtk::manage (new Gtk::TreeView::Column ("Places")); + Gtk::CellRendererPixbuf *iconCR = Gtk::manage (new Gtk::CellRendererPixbuf()); + Gtk::CellRendererText *labelCR = Gtk::manage (new Gtk::CellRendererText()); + iviewcol->pack_start (*iconCR, false); + iviewcol->pack_start (*labelCR, true); + iviewcol->add_attribute (*iconCR, "gicon", 0); + iviewcol->add_attribute (*labelCR, "text", placesColumns.label); + treeView->append_column (*iviewcol); + + treeView->set_row_separator_func (sigc::mem_fun(*this, &PlacesBrowser::rowSeparatorFunc)); + + vm = Gio::VolumeMonitor::get(); + + vm->signal_mount_changed().connect (sigc::mem_fun(*this, &PlacesBrowser::mountChanged)); + vm->signal_mount_added().connect (sigc::mem_fun(*this, &PlacesBrowser::mountChanged)); + vm->signal_mount_removed().connect (sigc::mem_fun(*this, &PlacesBrowser::mountChanged)); + vm->signal_volume_changed().connect (sigc::mem_fun(*this, &PlacesBrowser::volumeChanged)); + vm->signal_volume_added().connect (sigc::mem_fun(*this, &PlacesBrowser::volumeChanged)); + vm->signal_volume_removed().connect (sigc::mem_fun(*this, &PlacesBrowser::volumeChanged)); + vm->signal_drive_connected().connect (sigc::mem_fun(*this, &PlacesBrowser::driveChanged)); + vm->signal_drive_disconnected().connect (sigc::mem_fun(*this, &PlacesBrowser::driveChanged)); + vm->signal_drive_changed().connect (sigc::mem_fun(*this, &PlacesBrowser::driveChanged)); + + treeView->get_selection()->signal_changed().connect(sigc::mem_fun(*this, &PlacesBrowser::selectionChanged)); + add->signal_clicked().connect(sigc::mem_fun(*this, &PlacesBrowser::addPressed)); + del->signal_clicked().connect(sigc::mem_fun(*this, &PlacesBrowser::delPressed)); + + show_all (); +} + +void PlacesBrowser::refreshPlacesList () { + + placesModel->clear (); + + // append home directory + Glib::RefPtr hfile = Gio::File::create_for_path (Glib::get_home_dir ()); + if (hfile) { + Glib::RefPtr info = hfile->query_info (); + if (info) { + Gtk::TreeModel::Row newrow = *(placesModel->append()); + newrow[placesColumns.label] = info->get_display_name (); + newrow[placesColumns.icon] = info->get_icon (); + newrow[placesColumns.root] = hfile->get_parse_name (); + newrow[placesColumns.type] = 4; + newrow[placesColumns.rowSeparator] = false; + } + } + // append pictures directory + hfile = Gio::File::create_for_path (Glib::get_user_special_dir (G_USER_DIRECTORY_PICTURES)); + if (hfile) { + Glib::RefPtr info = hfile->query_info (); + if (info) { + Gtk::TreeModel::Row newrow = *(placesModel->append()); + newrow[placesColumns.label] = info->get_display_name (); + newrow[placesColumns.icon] = info->get_icon (); + newrow[placesColumns.root] = hfile->get_parse_name (); + newrow[placesColumns.type] = 4; + newrow[placesColumns.rowSeparator] = false; + } + } + + if (placesModel->children().size()>0) { + Gtk::TreeModel::Row newrow = *(placesModel->append()); + newrow[placesColumns.rowSeparator] = true; + } + + // scan all drives + std::vector > drives = vm->get_connected_drives (); + for (int j=0; j > volumes = drives[j]->get_volumes (); + if (volumes.size()==0) { + Gtk::TreeModel::Row newrow = *(placesModel->append()); + newrow[placesColumns.label] = drives[j]->get_name (); + newrow[placesColumns.icon] = drives[j]->get_icon (); + newrow[placesColumns.root] = ""; + newrow[placesColumns.type] = 3; + newrow[placesColumns.rowSeparator] = false; + } + for (int i=0; i mount = volumes[i]->get_mount (); + if (mount) { // placesed volumes + Gtk::TreeModel::Row newrow = *(placesModel->append()); + newrow[placesColumns.label] = mount->get_name (); + newrow[placesColumns.icon] = mount->get_icon (); + newrow[placesColumns.root] = mount->get_root ()->get_parse_name (); + newrow[placesColumns.type] = 1; + newrow[placesColumns.rowSeparator] = false; + } + else { // unplacesed volumes + Gtk::TreeModel::Row newrow = *(placesModel->append()); + newrow[placesColumns.label] = volumes[i]->get_name (); + newrow[placesColumns.icon] = volumes[i]->get_icon (); + newrow[placesColumns.root] = ""; + newrow[placesColumns.type] = 2; + newrow[placesColumns.rowSeparator] = false; + } + } + } + + // volumes not belonging to drives + std::vector > volumes = vm->get_volumes (); + for (int i=0; iget_drive ()) { + Glib::RefPtr mount = volumes[i]->get_mount (); + if (mount) { // placesed volumes + Gtk::TreeModel::Row newrow = *(placesModel->append()); + newrow[placesColumns.label] = mount->get_name (); + newrow[placesColumns.icon] = mount->get_icon (); + newrow[placesColumns.root] = mount->get_root ()->get_parse_name (); + newrow[placesColumns.type] = 1; + newrow[placesColumns.rowSeparator] = false; + } + else { // unplacesed volumes + Gtk::TreeModel::Row newrow = *(placesModel->append()); + newrow[placesColumns.label] = volumes[i]->get_name (); + newrow[placesColumns.icon] = volumes[i]->get_icon (); + newrow[placesColumns.root] = ""; + newrow[placesColumns.type] = 2; + newrow[placesColumns.rowSeparator] = false; + } + } + } + // placess not belonging to volumes + std::vector > mounts = vm->get_mounts (); + for (int i=0; iget_volume ()) { + Gtk::TreeModel::Row newrow = *(placesModel->append()); + newrow[placesColumns.label] = mounts[i]->get_name (); + newrow[placesColumns.icon] = mounts[i]->get_icon (); + newrow[placesColumns.root] = mounts[i]->get_root ()->get_parse_name (); + newrow[placesColumns.type] = 1; + newrow[placesColumns.rowSeparator] = false; + } + } + // append favorites + if (placesModel->children().size()>0) { + Gtk::TreeModel::Row newrow = *(placesModel->append()); + newrow[placesColumns.rowSeparator] = true; + } + for (int i=0; i hfile = Gio::File::create_for_path (options.favoriteDirs[i]); + if (hfile) { + Glib::RefPtr info = hfile->query_info (); + if (info) { + Gtk::TreeModel::Row newrow = *(placesModel->append()); + newrow[placesColumns.label] = info->get_display_name (); + newrow[placesColumns.icon] = info->get_icon (); + newrow[placesColumns.root] = hfile->get_parse_name (); + newrow[placesColumns.type] = 5; + newrow[placesColumns.rowSeparator] = false; + } + } + } +} + +bool PlacesBrowser::rowSeparatorFunc (const Glib::RefPtr& model, const Gtk::TreeModel::iterator& iter) { + + return iter->get_value (placesColumns.rowSeparator); +} + +void PlacesBrowser::mountChanged (const Glib::RefPtr& m) { + + gdk_threads_enter (); + refreshPlacesList (); + gdk_threads_leave (); +} + +void PlacesBrowser::volumeChanged (const Glib::RefPtr& m) { + + gdk_threads_enter (); + refreshPlacesList (); + gdk_threads_leave (); +} + +void PlacesBrowser::driveChanged (const Glib::RefPtr& m) { + + gdk_threads_enter (); + refreshPlacesList (); + gdk_threads_leave (); +} + +void PlacesBrowser::selectionChanged () { + + Glib::RefPtr selection = treeView->get_selection(); + Gtk::TreeModel::iterator iter = selection->get_selected(); + if (iter) { + if (iter->get_value (placesColumns.type)==2) { + std::vector > volumes = vm->get_volumes (); + for (int i=0; iget_name () == iter->get_value (placesColumns.label)) { + volumes[i]->mount (); + break; + } + } + else if (iter->get_value (placesColumns.type)==3) { + std::vector > drives = vm->get_connected_drives (); + for (int i=0; iget_name () == iter->get_value (placesColumns.label)) { + drives[i]->poll_for_media (); + break; + } + } + else if (listener) + listener->selectDir (iter->get_value (placesColumns.root)); + } +} + +void PlacesBrowser::dirSelected (const Glib::ustring& dirname, const Glib::ustring& openfile) { + + lastSelectedDir = dirname; +} + +void PlacesBrowser::addPressed () { + + if (lastSelectedDir=="") + return; + + // check if the dirname is already in the list. If yes, return. + for (int i=0; i hfile = Gio::File::create_for_path (lastSelectedDir); + if (hfile) { + Glib::RefPtr info = hfile->query_info (); + if (info) { + options.favoriteDirs.push_back (hfile->get_parse_name ()); + refreshPlacesList (); + } + } +} + +void PlacesBrowser::delPressed () { + + // lookup the selected item in the bookmark + Glib::RefPtr selection = treeView->get_selection(); + Gtk::TreeModel::iterator iter = selection->get_selected(); + + if (iter && iter->get_value (placesColumns.type)==5) { + std::vector::iterator i = std::find (options.favoriteDirs.begin(), options.favoriteDirs.end(), iter->get_value (placesColumns.root)); + if (i != options.favoriteDirs.end()) + options.favoriteDirs.erase (i); + } + + refreshPlacesList (); +} + diff --git a/rtgui/placesbrowser.h b/rtgui/placesbrowser.h new file mode 100755 index 000000000..1a9ef7313 --- /dev/null +++ b/rtgui/placesbrowser.h @@ -0,0 +1,67 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _PLACESBROWSER_ +#define _PLACESBROWSER_ + +#include +#include +#include +#include + +class PlacesBrowser : public Gtk::VBox, public DirSelectionListener { + + class PlacesColumns : public Gtk::TreeModel::ColumnRecord { + public: + Gtk::TreeModelColumn > icon; + Gtk::TreeModelColumn label; + Gtk::TreeModelColumn root; + Gtk::TreeModelColumn type; + Gtk::TreeModelColumn rowSeparator; + PlacesColumns() { add(icon); add(label); add(root); add(type); add(rowSeparator); } + }; + PlacesColumns placesColumns; + Gtk::ScrolledWindow* scrollw; + Gtk::TreeView* treeView; + Glib::RefPtr placesModel; + Glib::RefPtr vm; + DirBrowserRemoteInterface* listener; + Glib::ustring lastSelectedDir; + Gtk::Button* add; + Gtk::Button* del; + + public: + + PlacesBrowser (); + + void setDirBrowserRemoteInterface (DirBrowserRemoteInterface* l) { listener = l; } + void dirSelected (const Glib::ustring& dirname, const Glib::ustring& openfile=""); + + void refreshPlacesList (); + void mountChanged (const Glib::RefPtr& m); + void volumeChanged (const Glib::RefPtr& v); + void driveChanged (const Glib::RefPtr& d); + bool rowSeparatorFunc (const Glib::RefPtr& model, const Gtk::TreeModel::iterator& iter); + void selectionChanged (); + void addPressed (); + void delPressed (); +}; + +#endif + + diff --git a/rtgui/pointermotionlistener.h b/rtgui/pointermotionlistener.h new file mode 100755 index 000000000..0d9230c31 --- /dev/null +++ b/rtgui/pointermotionlistener.h @@ -0,0 +1,28 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _POINTERMOTIONLISTENER_ +#define _POINTERMOTIONLISTENER_ + +class PointerMotionListener { + + public: + virtual void pointerMoved (bool validPos, int x, int y, int r, int g, int b) {} +}; + +#endif diff --git a/rtgui/pparamschangelistener.h b/rtgui/pparamschangelistener.h new file mode 100755 index 000000000..5a34890f2 --- /dev/null +++ b/rtgui/pparamschangelistener.h @@ -0,0 +1,34 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _PPARAMSCHANGELISTENER_ +#define _PPARAMSCHANGELISTENER_ + +#include +#include +#include + +class PParamsChangeListener { + + public: + virtual void procParamsChanged (rtengine::procparams::ProcParams* params, rtengine::ProcEvent ev, Glib::ustring descr, ParamsEdited* paramsEdited=NULL) {} + virtual void clearParamChanges () {} +}; + +#endif + diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc new file mode 100755 index 000000000..b61f80e9b --- /dev/null +++ b/rtgui/preferences.cc @@ -0,0 +1,918 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 "preferences.h" +#include +#include +#include + +extern Options options; +extern Glib::ustring argv0; + +Preferences::Preferences (int initialPage) { + + set_title (M("MAIN_BUTTON_PREFERENCES")); + + moptions.copyFrom (&options); + + set_size_request (650, 550); + set_border_width (4); + + Gtk::VBox* mainvb = get_vbox (); + set_has_separator (false); + + Gtk::Notebook* nb = Gtk::manage (new Gtk::Notebook ()); + mainvb->pack_start (*nb); + + Gtk::HSeparator* hsep1 = Gtk::manage (new Gtk::HSeparator ()); + mainvb->pack_start (*hsep1, Gtk::PACK_SHRINK, 2); + + Gtk::HBox* buttonpanel = Gtk::manage (new Gtk::HBox ()); + mainvb->pack_end (*buttonpanel, Gtk::PACK_SHRINK, 2); + + Gtk::Button* load = Gtk::manage (new Gtk::Button (M("GENERAL_LOAD"))); + Gtk::Button* save = Gtk::manage (new Gtk::Button (M("GENERAL_SAVE"))); + Gtk::Button* about = Gtk::manage (new Gtk::Button (M("GENERAL_ABOUT"))); + Gtk::Button* ok = Gtk::manage (new Gtk::Button (M("GENERAL_OK"))); + Gtk::Button* cancel = Gtk::manage (new Gtk::Button (M("GENERAL_CANCEL"))); + + save->set_image (*Gtk::manage(new Gtk::Image (Gtk::StockID("gtk-save"), Gtk::ICON_SIZE_BUTTON))); + load->set_image (*Gtk::manage(new Gtk::Image (Gtk::StockID("gtk-open"), Gtk::ICON_SIZE_BUTTON))); + about->set_image (*Gtk::manage(new Gtk::Image (argv0+"/images/logoicon16.png"))); + ok->set_image (*Gtk::manage(new Gtk::Image (Gtk::StockID("gtk-ok"), Gtk::ICON_SIZE_BUTTON))); + cancel->set_image (*Gtk::manage(new Gtk::Image (Gtk::StockID("gtk-cancel"), Gtk::ICON_SIZE_BUTTON))); + + + load->signal_clicked().connect( sigc::mem_fun(*this, &Preferences::loadPressed) ); + save->signal_clicked().connect( sigc::mem_fun(*this, &Preferences::savePressed) ); + about->signal_clicked().connect( sigc::mem_fun(*this, &Preferences::aboutPressed) ); + ok->signal_clicked().connect( sigc::mem_fun(*this, &Preferences::okPressed) ); + cancel->signal_clicked().connect( sigc::mem_fun(*this, &Preferences::cancelPressed) ); + + buttonpanel->pack_start (*load, Gtk::PACK_SHRINK, 4); + buttonpanel->pack_start (*save, Gtk::PACK_SHRINK, 4); + buttonpanel->pack_start (*about, Gtk::PACK_SHRINK, 4); + buttonpanel->pack_end (*ok, Gtk::PACK_SHRINK, 4); + buttonpanel->pack_end (*cancel, Gtk::PACK_SHRINK, 4); + + nb->append_page (*getGeneralPanel(), M("PREFERENCES_TAB_GENERAL")); + nb->append_page (*getProcParamsPanel(), M("PREFERENCES_TAB_IMPROC")); + nb->append_page (*getFileBrowserPanel(), M("PREFERENCES_TAB_BROWSER")); + nb->append_page (*getColorManagementPanel(),M("PREFERENCES_TAB_COLORMGR")); + nb->append_page (*getBatchProcPanel(), "Batch Processing"); + nb->set_current_page (initialPage); + + fillPreferences (); + + show_all_children (); + set_modal (true); +} + +Gtk::Widget* Preferences::getBatchProcPanel () { + + Gtk::VBox* mvbpp = Gtk::manage (new Gtk::VBox ()); + + Gtk::ScrolledWindow* behscrollw = Gtk::manage (new Gtk::ScrolledWindow ()); + behscrollw->set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); + Gtk::Frame* behFrame = Gtk::manage (new Gtk::Frame ("Behavior")); + behFrame->add (*behscrollw); + mvbpp->pack_start (*behFrame); +// mvbpp->pack_start (*behFrame, Gtk::PACK_SHRINK, 2); + Gtk::TreeView* behTreeView = Gtk::manage (new Gtk::TreeView ()); + behscrollw->add (*behTreeView); + + behModel = Gtk::TreeStore::create (behavColumns); + behTreeView->set_model (behModel); + + behTreeView->append_column ("Property", behavColumns.label); + behTreeView->append_column_editable ("ADD", behavColumns.badd); + behTreeView->append_column_editable ("SET", behavColumns.bset); + + Gtk::CellRendererToggle* cr_add = static_cast (behTreeView->get_column (1)->get_first_cell_renderer()); + Gtk::CellRendererToggle* cr_set = static_cast (behTreeView->get_column (2)->get_first_cell_renderer()); + + cr_add->set_radio (true); + cr_add->set_property("xalign", 0.0f); + sigc::connection addc = cr_add->signal_toggled().connect (sigc::mem_fun (*this, &Preferences::behAddRadioToggled)); + cr_set->set_radio (true); + cr_set->set_property("xalign", 0.0f); + sigc::connection setc = cr_set->signal_toggled().connect (sigc::mem_fun (*this, &Preferences::behSetRadioToggled)); + + behTreeView->get_column (1)->add_attribute (*cr_add, "visible", behavColumns.visible); + behTreeView->get_column (1)->set_sizing(Gtk::TREE_VIEW_COLUMN_FIXED); + behTreeView->get_column (1)->set_fixed_width (50); + behTreeView->get_column (2)->add_attribute (*cr_set, "visible", behavColumns.visible); + behTreeView->get_column (2)->set_sizing(Gtk::TREE_VIEW_COLUMN_FIXED); + behTreeView->get_column (2)->set_fixed_width (50); + + // fill model + Gtk::TreeModel::iterator mi, ci; + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_EXPOSURE_LABEL")); + appendBehavList (mi, M("TP_EXPOSURE_EXPCOMP"), false); + appendBehavList (mi, M("TP_EXPOSURE_BRIGHTNESS"), false); + appendBehavList (mi, M("TP_EXPOSURE_BLACKLEVEL"), false); + appendBehavList (mi, M("TP_EXPOSURE_CONTRAST"), false); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_SHADOWSHLIGHTS_LABEL")); + appendBehavList (mi, M("TP_SHADOWSHLIGHTS_HIGHLIGHTS"), false); + appendBehavList (mi, M("TP_SHADOWSHLIGHTS_SHADOWS"), false); + appendBehavList (mi, M("TP_SHADOWSHLIGHTS_LOCALCONTR"), false); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_LUMACURVE_LABEL")); + appendBehavList (mi, M("TP_LUMACURVE_BRIGHTNESS"), false); + appendBehavList (mi, M("TP_LUMACURVE_BLACKLEVEL"), false); + appendBehavList (mi, M("TP_LUMACURVE_CONTRAST"), false); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_SHARPENING_LABEL")); + appendBehavList (mi, M("TP_SHARPENING_AMOUNT"), false); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_LUMADENOISE_LABEL")); + appendBehavList (mi, M("TP_LUMADENOISE_EDGETOLERANCE"), true); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_WBALANCE_LABEL")); + appendBehavList (mi, M("TP_WBALANCE_TEMPERATURE"), true); + appendBehavList (mi, M("TP_WBALANCE_GREEN"), true); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_COLORBOOST_LABEL")); + appendBehavList (mi, M("TP_COLORBOOST_AMOUNT"), false); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_COLORSHIFT_LABEL")); + appendBehavList (mi, M("TP_COLORSHIFT_BLUEYELLOW"), false); + appendBehavList (mi, M("TP_COLORSHIFT_GREENMAGENTA"), false); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_ROTATE_LABEL")); + appendBehavList (mi, M("TP_ROTATE_DEGREE"), false); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_DISTORTION_LABEL")); + appendBehavList (mi, M("TP_DISTORTION_AMOUNT"), false); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_CACORRECTION_LABEL")); + appendBehavList (mi, M("TP_CACORRECTION_BLUE"), true); + appendBehavList (mi, M("TP_CACORRECTION_RED"), true); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_VIGNETTING_LABEL")); + appendBehavList (mi, M("TP_VIGNETTING_AMOUNT"), false); + + behTreeView->expand_all (); + + return mvbpp; +} + +void Preferences::appendBehavList (Gtk::TreeModel::iterator& parent, Glib::ustring label, bool set) { + + Gtk::TreeModel::iterator ci = behModel->append (parent->children()); + ci->set_value (behavColumns.label, label); + ci->set_value (behavColumns.visible, true); + ci->set_value (behavColumns.badd, !set); + ci->set_value (behavColumns.bset, set); +} + +void Preferences::behAddRadioToggled (const Glib::ustring& path) { + + Gtk::TreeModel::iterator iter = behModel->get_iter (path); + bool set = iter->get_value (behavColumns.bset); + iter->set_value (behavColumns.bset, false); + iter->set_value (behavColumns.badd, true); +} + +void Preferences::behSetRadioToggled (const Glib::ustring& path) { + + Gtk::TreeModel::iterator iter = behModel->get_iter (path); + bool add = iter->get_value (behavColumns.badd); + iter->set_value (behavColumns.bset, true); + iter->set_value (behavColumns.badd, false); +} + +Gtk::Widget* Preferences::getProcParamsPanel () { + + Gtk::VBox* mvbpp = Gtk::manage (new Gtk::VBox ()); + + Gtk::Frame* fpp = Gtk::manage (new Gtk::Frame (M("PREFERENCES_IMPROCPARAMS"))); + Gtk::Label* drlab = Gtk::manage (new Gtk::Label (M("PREFERENCES_FORRAW")+":")); + rprofiles = Gtk::manage (new Gtk::ComboBoxText ()); + Gtk::Label* drimg = Gtk::manage (new Gtk::Label (M("PREFERENCES_FORIMAGE")+":")); + iprofiles = Gtk::manage (new Gtk::ComboBoxText ()); + Gtk::Table* defpt = Gtk::manage (new Gtk::Table (2, 2)); + defpt->attach (*drlab, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + defpt->attach (*rprofiles, 1, 2, 0, 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + defpt->attach (*drimg, 0, 1, 1, 2, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + defpt->attach (*iprofiles, 1, 2, 1, 2, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + fpp->add (*defpt); + + mvbpp->pack_start (*fpp, Gtk::PACK_SHRINK, 4); + + Gtk::Frame* fdp = Gtk::manage (new Gtk::Frame (M("PREFERENCES_PROFILEHANDLING"))); + Gtk::VBox* vbdp = Gtk::manage (new Gtk::VBox ()); + saveParamsFile = Gtk::manage (new Gtk::CheckButton (M("PREFERENCES_PROFILESAVEINPUT"))); + vbdp->pack_start (*saveParamsFile, Gtk::PACK_SHRINK, 4); + saveParamsCache = Gtk::manage (new Gtk::CheckButton (M("PREFERENCES_PROFILESAVECACHE"))); + vbdp->pack_start (*saveParamsCache, Gtk::PACK_SHRINK, 4); + Gtk::Label* lplab = Gtk::manage (new Gtk::Label (M("PREFERENCES_PROFILELOADPR")+":")); + loadParamsPreference = Gtk::manage (new Gtk::ComboBoxText ()); + loadParamsPreference->append_text (M("PREFERENCES_PROFILEPRCACHE")); + loadParamsPreference->append_text (M("PREFERENCES_PROFILEPRFILE")); + Gtk::HBox* hb41 = Gtk::manage (new Gtk::HBox ()); + hb41->pack_start (*lplab, Gtk::PACK_SHRINK, 4); + hb41->pack_start (*loadParamsPreference); + vbdp->pack_start (*hb41, Gtk::PACK_SHRINK, 4); + fdp->add (*vbdp); + mvbpp->pack_start (*fdp, Gtk::PACK_SHRINK, 4); + + Gtk::Frame* fdem = Gtk::manage (new Gtk::Frame (M("PREFERENCES_DEMOSAICINGALGO"))); + Gtk::VBox* fdb = Gtk::manage (new Gtk::VBox ()); + fdb->set_border_width (4); + fdem->add (*fdb); + Gtk::Label* dmlab = Gtk::manage (new Gtk::Label (M("PREFERENCES_DMETHOD")+":")); + dmethod = Gtk::manage (new Gtk::ComboBoxText ()); + Gtk::HBox* hb11 = Gtk::manage (new Gtk::HBox ()); + hb11->pack_start (*dmlab, Gtk::PACK_SHRINK, 4); + hb11->pack_start (*dmethod); + dmethod->append_text ("EAHD"); + dmethod->append_text ("HPHD"); + dmethod->append_text ("VNG-4"); + Gtk::Label* cclab = Gtk::manage (new Gtk::Label (M("PREFERENCES_FALSECOLOR")+":")); + ccSteps = Gtk::manage (new Gtk::SpinButton ()); + ccSteps->set_digits (0); + ccSteps->set_increments (1, 2); + ccSteps->set_range (0, 5); + Gtk::HBox* hb12 = Gtk::manage (new Gtk::HBox ()); + hb12->pack_start (*cclab, Gtk::PACK_SHRINK, 4); + hb12->pack_start (*ccSteps); + fdb->pack_start (*hb11, Gtk::PACK_SHRINK, 4); + fdb->pack_start (*hb12, Gtk::PACK_SHRINK, 4); + mvbpp->pack_start (*fdem, Gtk::PACK_SHRINK, 4); + mvbpp->set_border_width (4); + // drlab->set_size_request (drimg->get_width(), -1); + + std::vector pnames; + if (options.multiUser) + parseDir (Options::rtdir + "/" + options.profilePath, pnames, ".pp2"); + parseDir (argv0 + "/" + options.profilePath, pnames, ".pp2"); + for (int i=0; iappend_text (pnames[i]); + iprofiles->append_text (pnames[i]); + } + + dmconn = dmethod->signal_changed().connect( sigc::mem_fun(*this, &Preferences::dmethodChanged) ); + + return mvbpp; +} + +Gtk::Widget* Preferences::getColorManagementPanel () { + + Gtk::VBox* mvbcm = Gtk::manage (new Gtk::VBox ()); + mvbcm->set_border_width (4); + + Gtk::Label* intlab = Gtk::manage (new Gtk::Label (M("PREFERENCES_CMETRICINTENT")+":")); + intent = Gtk::manage (new Gtk::ComboBoxText ()); + intent->append_text (M("PREFERENCES_INTENT_PERCEPTUAL")); + intent->append_text (M("PREFERENCES_INTENT_RELATIVE")); + intent->append_text (M("PREFERENCES_INTENT_SATURATION")); + intent->append_text (M("PREFERENCES_INTENT_ABSOLUTE")); + + iccDir = Gtk::manage (new Gtk::FileChooserButton (M("PREFERENCES_ICCDIR"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); + Gtk::Label* pdlabel = Gtk::manage (new Gtk::Label (M("PREFERENCES_ICCDIR")+":")); + + monProfile = Gtk::manage (new Gtk::FileChooserButton (M("PREFERENCES_MONITORICC"), Gtk::FILE_CHOOSER_ACTION_OPEN)); + Gtk::Label* mplabel = Gtk::manage (new Gtk::Label (M("PREFERENCES_MONITORICC")+":")); + + Gtk::Table* colt = Gtk::manage (new Gtk::Table (3, 2)); + colt->attach (*intlab, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + colt->attach (*intent, 1, 2, 0, 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + colt->attach (*pdlabel, 0, 1, 1, 2, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + colt->attach (*iccDir, 1, 2, 1, 2, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + colt->attach (*mplabel, 0, 1, 2, 3, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + colt->attach (*monProfile, 1, 2, 2, 3, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + + mvbcm->pack_start (*colt, Gtk::PACK_SHRINK, 4); + + return mvbcm; +} + +Gtk::Widget* Preferences::getGeneralPanel () { + + Gtk::VBox* mvbsd = new Gtk::VBox (); + + Gtk::Frame* flang = new Gtk::Frame (M("PREFERENCES_DEFAULTLANG")); + Gtk::HBox* hblang = new Gtk::HBox (); + hblang->set_border_width (4); + Gtk::Label* langlab = new Gtk::Label (M("PREFERENCES_SELECTLANG")+":"); + languages = new Gtk::ComboBoxText (); + + std::vector langs; + parseDir (argv0 + "/languages", langs, ""); + for (int i=0; iappend_text (langs[i]); + + Gtk::Label* langw = new Gtk::Label (Glib::ustring("(") + M("PREFERENCES_APPLNEXTSTARTUP") + ")"); + hblang->pack_start (*langlab, Gtk::PACK_SHRINK, 4); + hblang->pack_start (*languages); + hblang->pack_end (*langw, Gtk::PACK_SHRINK, 4); + flang->add (*hblang); + mvbsd->pack_start (*flang, Gtk::PACK_SHRINK, 4); + + Gtk::Frame* ftheme = new Gtk::Frame (M("PREFERENCES_DEFAULTTHEME")); + Gtk::HBox* hbtheme = new Gtk::HBox (); + hbtheme->set_border_width (4); + Gtk::Label* themelab = new Gtk::Label (M("PREFERENCES_SELECTTHEME")+":"); + theme = new Gtk::ComboBoxText (); + + theme->append_text (Glib::ustring("(")+M("PREFERENCES_GTKTHEME")+")"); + theme->set_active (0); + std::vector themes; + parseDir (argv0 + "/themes", themes, ""); + for (int i=0; iappend_text (themes[i]); + + hbtheme->pack_start (*themelab, Gtk::PACK_SHRINK, 4); + hbtheme->pack_start (*theme); + ftheme->add (*hbtheme); + mvbsd->pack_start (*ftheme, Gtk::PACK_SHRINK, 4); + +//----- + + Gtk::Frame* frl = new Gtk::Frame (M("PREFERENCES_CLIPPINGIND")); + blinkClipped = new Gtk::CheckButton (M("PREFERENCES_BLINKCLIPPED")); + Gtk::VBox* vbrl = new Gtk::VBox (); + vbrl->set_border_width (4); + vbrl->pack_start (*blinkClipped, Gtk::PACK_SHRINK, 4); + + Gtk::HBox* vbhl = new Gtk::HBox (); + Gtk::Label* hll = new Gtk::Label (M("PREFERENCES_HLTHRESHOLD")+": "); + hlThresh = new Gtk::SpinButton (); + hlThresh->set_digits (0); + hlThresh->set_increments (1, 10); + hlThresh->set_range (0, 255); + vbhl->pack_start (*hll, Gtk::PACK_SHRINK, 8); + vbhl->pack_start (*hlThresh, Gtk::PACK_SHRINK, 8); + + vbrl->pack_start (*vbhl, Gtk::PACK_SHRINK, 4); + + Gtk::HBox* vbsh = new Gtk::HBox (); + Gtk::Label* shl = new Gtk::Label (M("PREFERENCES_SHTHRESHOLD")+": "); + shThresh = new Gtk::SpinButton (); + shThresh->show (); + shThresh->set_digits (0); + shThresh->set_increments (1, 10); + shThresh->set_range (0, 255); + vbsh->pack_start (*shl, Gtk::PACK_SHRINK, 8); + vbsh->pack_start (*shThresh, Gtk::PACK_SHRINK, 8); + vbrl->pack_start (*vbsh, Gtk::PACK_SHRINK, 4); + + frl->add (*vbrl); + mvbsd->pack_start (*frl, Gtk::PACK_SHRINK, 4); + +//----- + Gtk::Frame* fdf = new Gtk::Frame (M("PREFERENCES_DATEFORMAT")); + + Gtk::HBox* hb6 = new Gtk::HBox (); + Gtk::VBox* dfvb = new Gtk::VBox (); + Gtk::Label* dflab = new Gtk::Label (M("PREFERENCES_DATEFORMAT")+":"); + hb6->pack_start (*dflab, Gtk::PACK_SHRINK,4); + dateformat = new Gtk::Entry (); + dateformat->set_tooltip_markup (M("PREFERENCES_DATEFORMATHINT")); + dflab->set_tooltip_markup (M("PREFERENCES_DATEFORMATHINT")); + hb6->pack_start (*dateformat); + dfvb->pack_start (*hb6, Gtk::PACK_SHRINK, 4); + fdf->add (*dfvb); + dfvb->set_border_width (4); + + mvbsd->pack_start (*fdf, Gtk::PACK_SHRINK, 4); + + //----- + Gtk::Frame* fdg = new Gtk::Frame (M("PREFERENCES_EXTERNALEDITOR")); + Gtk::VBox* dgvb = new Gtk::VBox (); + + Gtk::HBox* hb7c = new Gtk::HBox (); + edOther = new Gtk::RadioButton (M("PREFERENCES_EDITORCMDLINE")+":"); + hb7c->pack_start (*edOther, Gtk::PACK_SHRINK,4); + editorToSendTo = new Gtk::Entry (); + hb7c->pack_start (*editorToSendTo); + Gtk::RadioButton::Group ge = edOther->get_group(); + +#ifndef _WIN32 + Gtk::HBox* hb7 = new Gtk::HBox (); + edGimp = new Gtk::RadioButton ("GIMP"); + hb7->pack_start (*edGimp, Gtk::PACK_SHRINK,4); + dgvb->pack_start (*hb7, Gtk::PACK_SHRINK, 4); + edGimp->set_group (ge); +#else + Gtk::HBox* hb7 = new Gtk::HBox (); + edGimp = new Gtk::RadioButton (M("PREFERENCES_GIMPPATH")+":"); + hb7->pack_start (*edGimp, Gtk::PACK_SHRINK,4); + gimpDir = new Gtk::FileChooserButton (M("PREFERENCES_GIMPPATH"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER); + hb7->pack_start (*gimpDir); + dgvb->pack_start (*hb7, Gtk::PACK_SHRINK, 4); + edGimp->set_group (ge); + + Gtk::HBox* hb7b = new Gtk::HBox (); + edPS = new Gtk::RadioButton (M("PREFERENCES_PSPATH")+":"); + hb7b->pack_start (*edPS, Gtk::PACK_SHRINK,4); + psDir = new Gtk::FileChooserButton (M("PREFERENCES_PSPATH"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER); + hb7b->pack_start (*psDir); + dgvb->pack_start (*hb7b, Gtk::PACK_SHRINK, 4); + edPS->set_group (ge); +#endif + + dgvb->pack_start (*hb7c, Gtk::PACK_SHRINK, 4); + dgvb->set_border_width (4); + fdg->add (*dgvb); + mvbsd->pack_start (*fdg, Gtk::PACK_SHRINK, 4); + + mvbsd->set_border_width (4); + + tconn = theme->signal_changed().connect( sigc::mem_fun(*this, &Preferences::themeChanged) ); + + return mvbsd; +} + +Gtk::Widget* Preferences::getFileBrowserPanel () { + + Gtk::VBox* mvbfb = new Gtk::VBox (); + mvbfb->set_border_width (4); + + Gtk::Frame* fsd = new Gtk::Frame (M("PREFERENCES_STARTUPIMDIR")); + + sdcurrent = new Gtk::RadioButton (M("PREFERENCES_DIRSOFTWARE")); + sdlast = new Gtk::RadioButton (M("PREFERENCES_DIRLAST")); + sdhome = new Gtk::RadioButton (M("PREFERENCES_DIRHOME")); + sdother = new Gtk::RadioButton (M("PREFERENCES_DIROTHER")+": "); + startupdir = new Gtk::Entry (); + + Gtk::Button* sdselect = new Gtk::Button (""); + sdselect->set_image (*(new Gtk::Image (Gtk::StockID("gtk-open"), Gtk::ICON_SIZE_BUTTON))); + + Gtk::RadioButton::Group opts = sdcurrent->get_group(); + sdlast->set_group (opts); + sdhome->set_group (opts); + sdother->set_group (opts); + + Gtk::VBox* vbsd = new Gtk::VBox (); + vbsd->pack_start (*sdcurrent, Gtk::PACK_SHRINK,0); + vbsd->pack_start (*sdlast, Gtk::PACK_SHRINK,0); + vbsd->pack_start (*sdhome, Gtk::PACK_SHRINK,0); + Gtk::HBox* otherbox = new Gtk::HBox (); + otherbox->pack_start (*sdother, Gtk::PACK_SHRINK); + otherbox->pack_start (*startupdir); + otherbox->pack_end (*sdselect, Gtk::PACK_SHRINK, 4); + vbsd->pack_start (*otherbox, Gtk::PACK_SHRINK, 0); + vbsd->set_border_width (4); + + fsd->add (*vbsd); + mvbfb->pack_start (*fsd, Gtk::PACK_SHRINK, 4); + + sdselect->signal_clicked().connect( sigc::mem_fun(*this, &Preferences::selectStartupDir) ); + +//--- + + + Gtk::Frame* fro = new Gtk::Frame (M("PREFERENCES_FBROWSEROPTS")); + showDateTime = new Gtk::CheckButton (M("PREFERENCES_SHOWDATETIME")); + showBasicExif = new Gtk::CheckButton (M("PREFERENCES_SHOWBASICEXIF")); + Gtk::VBox* vbro = new Gtk::VBox (); + overlayedFileNames = new Gtk::CheckButton ("Overlay filenames on thumbnails"); + vbro->set_border_width (4); + vbro->pack_start (*showDateTime, Gtk::PACK_SHRINK, 0); + vbro->pack_start (*showBasicExif, Gtk::PACK_SHRINK, 0); + vbro->pack_start (*overlayedFileNames, Gtk::PACK_SHRINK, 4); + + fro->add (*vbro); + + Gtk::Frame* fre = new Gtk::Frame (M("PREFERENCES_PARSEDEXT")); + Gtk::VBox* vbre = new Gtk::VBox (); + vbre->set_border_width (4); + Gtk::HBox* hb0 = new Gtk::HBox (); + Gtk::Label* elab = new Gtk::Label (M("PREFERENCES_PARSEDEXTADD")+":"); + hb0->pack_start (*elab, Gtk::PACK_SHRINK, 4); + extension = new Gtk::Entry (); + hb0->pack_start (*extension); + addExt = new Gtk::Button (); + delExt = new Gtk::Button (); + addExt->set_tooltip_text (M("PREFERENCES_PARSEDEXTADDHINT")); + delExt->set_tooltip_text (M("PREFERENCES_PARSEDEXTDELHINT")); + Gtk::Image* addExtImg = new Gtk::Image (argv0+"/images/list-add12.png"); + Gtk::Image* delExtImg = new Gtk::Image (argv0+"/images/list-remove12r.png"); + addExt->add (*addExtImg); + delExt->add (*delExtImg); + hb0->pack_end (*delExt, Gtk::PACK_SHRINK, 4); + hb0->pack_end (*addExt, Gtk::PACK_SHRINK, 4); + extensions = new Gtk::TreeView (); + Gtk::ScrolledWindow* hscrollw = new Gtk::ScrolledWindow (); + hscrollw->set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS); + hscrollw->add (*extensions); + extensionModel = Gtk::ListStore::create (extensionColumns); + extensions->set_model (extensionModel); + extensions->append_column_editable("Enabled", extensionColumns.enabled); + extensions->append_column("Extension", extensionColumns.ext); + extensions->set_headers_visible (false); + vbre->pack_start (*hscrollw); + vbre->pack_start (*hb0, Gtk::PACK_SHRINK, 0); + + fre->add (*vbre); + + Gtk::Frame* frc = new Gtk::Frame (M("PREFERENCES_CACHEOPTS")); + Gtk::VBox* vbc = new Gtk::VBox (); + frc->add (*vbc); + vbc->set_border_width (4); + + Gtk::Label* cflab = new Gtk::Label (M("PREFERENCES_CACHETHUMBFORM")+":"); + cformat = new Gtk::ComboBoxText (); + cformat->append_text (M("PREFERENCES_CACHEFORMAT1")); + cformat->append_text (M("PREFERENCES_CACHEFORMAT2")); + cformat->append_text (M("PREFERENCES_CACHEFORMAT1")+", 16 bit"); + Gtk::HBox* hb2 = new Gtk::HBox (); + hb2->pack_start (*cflab, Gtk::PACK_SHRINK, 4); + hb2->pack_start (*cformat); + vbc->pack_start (*hb2, Gtk::PACK_SHRINK, 0); + + Gtk::HBox* hb3 = new Gtk::HBox (); + Gtk::Label* chlab = new Gtk::Label (M("PREFERENCES_CACHETHUMBHEIGHT")+":"); + maxThumbSize = new Gtk::SpinButton (); + hb3->pack_start (*chlab, Gtk::PACK_SHRINK, 8); + hb3->pack_start (*maxThumbSize, Gtk::PACK_SHRINK, 8); + + maxThumbSize->set_digits (0); + maxThumbSize->set_increments (1, 10); + maxThumbSize->set_range (40, 400); + vbc->pack_start (*hb3, Gtk::PACK_SHRINK, 0); + + Gtk::HBox* hb4 = new Gtk::HBox (); + Gtk::Label* celab = new Gtk::Label (M("PREFERENCES_CACHEMAXENTRIES")+":"); + maxCacheEntries = new Gtk::SpinButton (); + hb4->pack_start (*celab, Gtk::PACK_SHRINK, 8); + hb4->pack_start (*maxCacheEntries, Gtk::PACK_SHRINK, 8); + + maxCacheEntries->set_digits (0); + maxCacheEntries->set_increments (1, 10); + maxCacheEntries->set_range (10, 100000); + vbc->pack_start (*hb4, Gtk::PACK_SHRINK, 0); + + Gtk::HBox* hb5 = new Gtk::HBox (); + clearThumbnails = new Gtk::Button (M("PREFERENCES_CACHECLEARTHUMBS")); + clearProfiles = new Gtk::Button (M("PREFERENCES_CACHECLEARPROFILES")); + clearAll = new Gtk::Button (M("PREFERENCES_CACHECLEARALL")); + hb5->pack_start (*clearThumbnails, Gtk::PACK_SHRINK, 8); + hb5->pack_start (*clearProfiles, Gtk::PACK_SHRINK, 8); + hb5->pack_start (*clearAll, Gtk::PACK_SHRINK, 8); + vbc->pack_start (*hb5, Gtk::PACK_SHRINK, 0); + + Gtk::HBox* hb6 = new Gtk::HBox (); + Gtk::VBox* vb6 = new Gtk::VBox (); + + vb6->pack_start (*fro); + vb6->pack_end (*frc); + hb6->pack_start (*vb6); + hb6->pack_start (*fre); + + mvbfb->pack_start (*hb6, Gtk::PACK_SHRINK, 4); + +// mvbfb->pack_start (*fro, Gtk::PACK_SHRINK, 4); +// mvbfb->pack_start (*fre); +// mvbfb->pack_start (*frc, Gtk::PACK_SHRINK, 4); + + addExt->signal_clicked().connect( sigc::mem_fun(*this, &Preferences::addExtPressed) ); + delExt->signal_clicked().connect( sigc::mem_fun(*this, &Preferences::delExtPressed) ); + extension->signal_activate().connect( sigc::mem_fun(*this, &Preferences::addExtPressed) ); + clearThumbnails->signal_clicked().connect( sigc::mem_fun(*this, &Preferences::clearThumbImagesPressed) ); + clearProfiles->signal_clicked().connect( sigc::mem_fun(*this, &Preferences::clearProfilesPressed) ); + clearAll->signal_clicked().connect( sigc::mem_fun(*this, &Preferences::clearAllPressed) ); + + return mvbfb; +} + +void Preferences::parseDir (Glib::ustring dirname, std::vector& items, Glib::ustring ext) { + + // process directory + Glib::Dir* dir = NULL; + try { + dir = new Glib::Dir (dirname); + } + catch (const Glib::FileError& fe) { + return; + } + dirname = dirname + "/"; + for (Glib::DirIterator i = dir->begin(); i!=dir->end(); ++i) { + Glib::ustring fname = dirname + *i; + Glib::ustring sname = *i; + // ignore directories + if (!Glib::file_test (fname, Glib::FILE_TEST_IS_DIR) && sname.size() >= ext.size() && sname.substr (sname.size()-ext.size(), ext.size()).casefold() == ext) + items.push_back (sname.substr(0,sname.size()-ext.size())); + } + delete dir; +} + +void Preferences::storePreferences () { + + moptions.defProfRaw = rprofiles->get_active_text(); + moptions.defProfImg = iprofiles->get_active_text(); + moptions.dateFormat = dateformat->get_text(); + moptions.fbShowDateTime = showDateTime->get_active (); + moptions.fbShowBasicExif = showBasicExif->get_active (); + moptions.blinkClipped = blinkClipped->get_active (); + moptions.highlightThreshold = (int)hlThresh->get_value (); + moptions.shadowThreshold = (int)shThresh->get_value (); + moptions.language = languages->get_active_text (); + moptions.theme = theme->get_active_text (); +#ifdef _WIN32 + moptions.gimpDir = gimpDir->get_filename (); + moptions.psDir = psDir->get_filename (); +#endif + moptions.customEditorProg = editorToSendTo->get_text (); + if (edGimp->get_active ()) + moptions.editorToSendTo = 1; +#ifdef _WIN32 + else if (edPS->get_active ()) + moptions.editorToSendTo = 2; +#endif + else if (edOther->get_active ()) + moptions.editorToSendTo = 3; + + + moptions.rtSettings.colorCorrectionSteps= (int)ccSteps->get_value (); + moptions.rtSettings.monitorProfile = monProfile->get_filename (); + moptions.rtSettings.iccDirectory = iccDir->get_filename (); + moptions.rtSettings.colorimetricIntent = intent->get_active_row_number (); + if (dmethod->get_active_row_number()==0) + moptions.rtSettings.demosaicMethod = "eahd"; + else if (dmethod->get_active_row_number()==1) + moptions.rtSettings.demosaicMethod = "hphd"; + else if (dmethod->get_active_row_number()==2) + moptions.rtSettings.demosaicMethod = "vng4"; + + if (sdcurrent->get_active ()) + moptions.startupDir = STARTUPDIR_CURRENT; + else if (sdhome->get_active ()) + moptions.startupDir = STARTUPDIR_HOME; + else if (sdlast->get_active ()) + moptions.startupDir = STARTUPDIR_LAST; + else if (sdother->get_active ()) { + moptions.startupDir = STARTUPDIR_CUSTOM; + moptions.startupPath = startupdir->get_text(); + } + + moptions.parseExtensions.clear (); + moptions.parseExtensionsEnabled.clear (); + Gtk::TreeNodeChildren c = extensionModel->children (); + for (int i=0; iget_active_row_number() == 0) + moptions.thumbnailFormat = FT_Custom; + else if (cformat->get_active_row_number() == 1) + moptions.thumbnailFormat = FT_Jpeg; + else if (cformat->get_active_row_number() == 2) + moptions.thumbnailFormat = FT_Custom16; + + moptions.maxThumbnailHeight = (int)maxThumbSize->get_value (); + moptions.maxCacheEntries = (int)maxCacheEntries->get_value (); + moptions.overlayedFileNames = overlayedFileNames->get_active (); + + moptions.saveParamsFile = saveParamsFile->get_active (); + moptions.saveParamsCache = saveParamsCache->get_active (); + moptions.paramsLoadLocation = (PPLoadLocation)loadParamsPreference->get_active_row_number (); + + int i = 0; + moptions.baBehav.clear (); + for (Gtk::TreeIter sections=behModel->children().begin(); sections!=behModel->children().end(); sections++) + for (Gtk::TreeIter adjs=sections->children().begin(); adjs!=sections->children().end(); adjs++) + moptions.baBehav.push_back (adjs->get_value (behavColumns.badd)); +} + +void Preferences::fillPreferences () { + + dmconn.block (true); + tconn.block (true); + + rprofiles->set_active_text (moptions.defProfRaw); + iprofiles->set_active_text (moptions.defProfImg); + dateformat->set_text (moptions.dateFormat); + ccSteps->set_value (moptions.rtSettings.colorCorrectionSteps); + if (Glib::file_test (moptions.rtSettings.monitorProfile, Glib::FILE_TEST_EXISTS)) + monProfile->set_filename (moptions.rtSettings.monitorProfile); + if (Glib::file_test (moptions.rtSettings.iccDirectory, Glib::FILE_TEST_IS_DIR)) + iccDir->set_filename (moptions.rtSettings.iccDirectory); + intent->set_active (moptions.rtSettings.colorimetricIntent); + languages->set_active_text (moptions.language); + theme->set_active_text (moptions.theme); + showDateTime->set_active (moptions.fbShowDateTime); + showBasicExif->set_active (moptions.fbShowBasicExif); + blinkClipped->set_active (moptions.blinkClipped); + hlThresh->set_value (moptions.highlightThreshold); + shThresh->set_value (moptions.shadowThreshold); + + edGimp->set_active (moptions.editorToSendTo==1); + edOther->set_active (moptions.editorToSendTo==3); +#ifdef _WIN32 + edPS->set_active (moptions.editorToSendTo==2); + if (Glib::file_test (moptions.gimpDir, Glib::FILE_TEST_IS_DIR)) + gimpDir->set_filename (moptions.gimpDir); + if (Glib::file_test (moptions.psDir, Glib::FILE_TEST_IS_DIR)) + psDir->set_filename (moptions.psDir); +#endif + editorToSendTo->set_text (moptions.customEditorProg); + + if (moptions.rtSettings.demosaicMethod=="eahd") + dmethod->set_active (0); + else if (moptions.rtSettings.demosaicMethod=="hphd") + dmethod->set_active (1); + else if (moptions.rtSettings.demosaicMethod=="vng4") + dmethod->set_active (2); + + if (moptions.startupDir==STARTUPDIR_CURRENT) + sdcurrent->set_active (); + else if (moptions.startupDir==STARTUPDIR_LAST) + sdlast->set_active (); + else if (moptions.startupDir==STARTUPDIR_HOME) + sdhome->set_active (); + else if (moptions.startupDir==STARTUPDIR_CUSTOM) { + sdother->set_active (); + startupdir->set_text (moptions.startupPath); + } + + extensionModel->clear (); + for (int i=0; iappend()); + row[extensionColumns.enabled] = moptions.parseExtensionsEnabled[i]; + row[extensionColumns.ext] = moptions.parseExtensions[i]; + } + + if (moptions.thumbnailFormat == FT_Custom) + cformat->set_active (0); + else if (moptions.thumbnailFormat == FT_Jpeg) + cformat->set_active (1); + else if (moptions.thumbnailFormat == FT_Custom16) + cformat->set_active (2); + + maxThumbSize->set_value (moptions.maxThumbnailHeight); + maxCacheEntries->set_value (moptions.maxCacheEntries); + overlayedFileNames->set_active (moptions.overlayedFileNames); + + saveParamsFile->set_active (moptions.saveParamsFile); + saveParamsCache->set_active (moptions.saveParamsCache); + loadParamsPreference->set_active (moptions.paramsLoadLocation); + + addc.block (true); + setc.block (true); + int i = 0; + for (Gtk::TreeIter sections=behModel->children().begin(); sections!=behModel->children().end(); sections++) + for (Gtk::TreeIter adjs=sections->children().begin(); adjs!=sections->children().end(); adjs++) + if (moptions.baBehav.size()>i) { + adjs->set_value (behavColumns.badd, moptions.baBehav[i]==1); + adjs->set_value (behavColumns.bset, moptions.baBehav[i++]!=1); + } + addc.block (false); + setc.block (false); + + dmconn.block (false); + tconn.block (false); +} + +void Preferences::loadPressed () { + + moptions.copyFrom (&options); + fillPreferences (); +} + +void Preferences::savePressed () { + + storePreferences (); + options.copyFrom (&moptions); + Options::save (); +} + +void Preferences::okPressed () { + + storePreferences (); + options.copyFrom (&moptions); + hide (); +} + +void Preferences::cancelPressed () { + + hide (); +} + +void Preferences::selectStartupDir () { + + Gtk::FileChooserDialog dialog(M("PREFERENCES_DIRSELECTDLG"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER); +// dialog.set_transient_for(*this); + + //Add response buttons the the dialog: + dialog.add_button(Gtk::StockID("gtk-cancel"), Gtk::RESPONSE_CANCEL); + dialog.add_button(Gtk::StockID("gtk-open"), Gtk::RESPONSE_OK); + + int result = dialog.run(); + + if (result==Gtk::RESPONSE_OK) + startupdir->set_text (dialog.get_filename()); +} + +void Preferences::dmethodChanged () { + + if (dmethod->get_active_row_number()==0) + ccSteps->set_value (2); + else if (dmethod->get_active_row_number()==1) + ccSteps->set_value (1); + else if (dmethod->get_active_row_number()==2) + ccSteps->set_value (2); +} + +void Preferences::aboutPressed () { + + Splash* splash = new Splash (-1); + splash->set_transient_for (*this); + splash->set_modal (true); + splash->show (); +} +void Preferences::themeChanged () { + + std::vector files; + files.push_back (argv0+"/themes/"+theme->get_active_text ()); + Gtk::RC::set_default_files (files); + Gtk::RC::reparse_all (Gtk::Settings::get_default()); + GdkEventClient event = { GDK_CLIENT_EVENT, NULL, TRUE, gdk_atom_intern("_GTK_READ_RCFILES", FALSE), 8 }; + gdk_event_send_clientmessage_toall ((GdkEvent*)&event); +} + +void Preferences::addExtPressed () { + + Gtk::TreeNodeChildren c = extensionModel->children (); + for (int i=0; iget_text ()) + return; + + Gtk::TreeRow row = *(extensionModel->append()); + + row[extensionColumns.enabled] = true; + row[extensionColumns.ext] = extension->get_text (); +} + +void Preferences::delExtPressed () { + + extensionModel->erase (extensions->get_selection()->get_selected ()); +} + +void Preferences::clearProfilesPressed () { + + Gtk::MessageDialog md (*this, M("PREFERENCES_CLEARDLG_LINE1"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_NONE, true); + md.set_secondary_text (M("PREFERENCES_CLEARDLG_LINE2")); + md.set_title (M("PREFERENCES_CLEARDLG_TITLE")); + md.show_all (); + while (gtk_events_pending ()) gtk_main_iteration (); + cacheMgr.clearProfiles (); + md.hide (); +} + +void Preferences::clearThumbImagesPressed () { + + Gtk::MessageDialog md (*this, M("PREFERENCES_CLEARDLG_LINE1"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_NONE, true); + md.set_secondary_text (M("PREFERENCES_CLEARDLG_LINE2")); + md.set_title (M("PREFERENCES_CLEARDLG_TITLE")); + md.show_all (); + while (gtk_events_pending ()) gtk_main_iteration (); + cacheMgr.clearThumbImages (); + md.hide (); +} + +void Preferences::clearAllPressed () { + + Gtk::MessageDialog md (*this, M("PREFERENCES_CLEARDLG_LINE1"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_NONE, true); + md.set_secondary_text (M("PREFERENCES_CLEARDLG_LINE2")); + md.set_title (M("PREFERENCES_CLEARDLG_TITLE")); + md.show_all (); + while (gtk_events_pending ()) gtk_main_iteration (); + cacheMgr.clearAll (); + md.hide (); +} + diff --git a/rtgui/preferences.h b/rtgui/preferences.h new file mode 100755 index 000000000..f27b1fcd5 --- /dev/null +++ b/rtgui/preferences.h @@ -0,0 +1,141 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef __PREFERENCES_H__ +#define __PREFERENCES_H__ + +#include +#include +#include +#include + +class Preferences : public Gtk::Dialog { + + class ExtensionColumns : public Gtk::TreeModel::ColumnRecord { + public: + Gtk::TreeModelColumn enabled; + Gtk::TreeModelColumn ext; + ExtensionColumns() { add(enabled); add(ext); } + }; + ExtensionColumns extensionColumns; + Glib::RefPtr extensionModel; + + + class BehavColumns : public Gtk::TreeModel::ColumnRecord { + public: + Gtk::TreeModelColumn label; + Gtk::TreeModelColumn badd; + Gtk::TreeModelColumn bset; + Gtk::TreeModelColumn visible; + BehavColumns() { add(label); add(badd); add(bset); add(visible);} + }; + Glib::RefPtr behModel; + BehavColumns behavColumns; + + + protected: + Gtk::ComboBoxText* rprofiles; + Gtk::ComboBoxText* iprofiles; + Gtk::ComboBoxText* dmethod; + Gtk::ComboBoxText* languages; + Gtk::Entry* dateformat; + Gtk::Entry* startupdir; + Gtk::RadioButton* sdcurrent; + Gtk::RadioButton* sdlast; + Gtk::RadioButton* sdhome; + Gtk::RadioButton* sdother; + Gtk::FileChooserButton* gimpDir; + Gtk::FileChooserButton* psDir; + Gtk::Entry* editorToSendTo; + Gtk::RadioButton* edGimp; + Gtk::RadioButton* edPS; + Gtk::RadioButton* edOther; + + + Gtk::CheckButton* showDateTime; + Gtk::CheckButton* showBasicExif; + + Gtk::SpinButton* ccSteps; + Gtk::FileChooserButton* iccDir; + Gtk::FileChooserButton* monProfile; + + Gtk::CheckButton* blinkClipped; + Gtk::SpinButton* hlThresh; + Gtk::SpinButton* shThresh; + + Gtk::ComboBoxText* intent; + + Gtk::ComboBoxText* theme; + + Gtk::ComboBoxText* cformat; + Gtk::SpinButton* maxThumbSize; + Gtk::SpinButton* maxCacheEntries; + Gtk::Button* clearThumbnails; + Gtk::Button* clearProfiles; + Gtk::Button* clearAll; + Gtk::Entry* extension; + Gtk::TreeView* extensions; + Gtk::Button* addExt; + Gtk::Button* delExt; + Gtk::CheckButton* overlayedFileNames; + + Gtk::CheckButton* saveParamsFile; + Gtk::CheckButton* saveParamsCache; + Gtk::ComboBoxText* loadParamsPreference; + + Options moptions; + sigc::connection dmconn, tconn, addc, setc; + + void fillPreferences (); + void storePreferences (); + void parseDir (Glib::ustring dirname, std::vector& items, Glib::ustring ext); + void dmethodChanged (); + + void themeChanged (); + + void appendBehavList (Gtk::TreeModel::iterator& parent, Glib::ustring label, bool set); + + Gtk::Widget* getProcParamsPanel (); + Gtk::Widget* getColorManagementPanel (); + Gtk::Widget* getFileBrowserPanel (); + Gtk::Widget* getGeneralPanel (); + Gtk::Widget* getBatchProcPanel (); + + public: + Preferences (int initialPage=0); + + void savePressed (); + void loadPressed (); + void okPressed (); + void cancelPressed (); + void aboutPressed (); + + void selectStartupDir (); + void addExtPressed (); + void delExtPressed (); + + void clearProfilesPressed (); + void clearThumbImagesPressed (); + void clearAllPressed (); + void behAddRadioToggled (const Glib::ustring& path); + void behSetRadioToggled (const Glib::ustring& path); +// void selectICCProfileDir (); +// void selectMonitorProfile (); +}; + +#endif diff --git a/rtgui/previewhandler.cc b/rtgui/previewhandler.cc new file mode 100755 index 000000000..421ebac9c --- /dev/null +++ b/rtgui/previewhandler.cc @@ -0,0 +1,234 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include + +using namespace rtengine; +using namespace rtengine::procparams; + +PreviewHandler::PreviewHandler () : image(NULL) { + + pih = new PreviewHandlerIdleHelper; + pih->phandler = this; + pih->destroyed = false; + pih->pending = 0; +}; + +PreviewHandler::~PreviewHandler () { + + if (pih->pending) + pih->destroyed = true; + else + delete pih; +}; + +//----------------previewimagelistener functions-------------------- + +struct iaimgpar { + IImage8* image; + PreviewHandlerIdleHelper* pih; + double scale; + CropParams cp; +}; + +int iasetimage (void* data) { + + gdk_threads_enter (); + + iaimgpar* iap = (iaimgpar*)data; + PreviewHandlerIdleHelper* pih = iap->pih; + + if (pih->destroyed) { + if (pih->pending == 1) + delete pih; + else + pih->pending--; + delete iap; + gdk_threads_leave (); + return 0; + } + + if (pih->phandler->image) { + IImage8* temp = pih->phandler->image; + temp->getMutex().lock (); + pih->phandler->image = iap->image; + temp->getMutex().unlock (); + } + else + pih->phandler->image = iap->image; + pih->phandler->cropParams = iap->cp; + pih->phandler->previewScale = iap->scale; + pih->pending--; + delete iap; + + gdk_threads_leave (); + + return 0; +} + +void PreviewHandler::setImage (rtengine::IImage8* i, double scale, rtengine::procparams::CropParams cp) { + + pih->pending++; + + iaimgpar* iap = new iaimgpar; + iap->image = i; + iap->pih = pih; + iap->scale = scale; + iap->cp = cp; + + g_idle_add (iasetimage, iap); +} + +int iadelimage (void* data) { + + gdk_threads_enter (); + + iaimgpar* iap = (iaimgpar*)data; + PreviewHandlerIdleHelper* pih = iap->pih; + + if (pih->destroyed) { + if (pih->pending == 1) + delete pih; + else + pih->pending--; + delete iap; + gdk_threads_leave (); + return 0; + } + + if (pih->phandler->image) { + IImage8* temp = pih->phandler->image; + temp->getMutex().lock (); + pih->phandler->image = NULL; + temp->getMutex().unlock (); + } + iap->image->free (); + pih->phandler->previewImgMutex.lock (); + pih->phandler->previewImg.clear (); + pih->phandler->previewImgMutex.unlock (); + + pih->pending--; + delete iap; + + gdk_threads_leave (); + + return 0; +} + +void PreviewHandler::delImage (IImage8* i) { + + pih->pending++; + + iaimgpar* iap = new iaimgpar; + iap->image = i; + iap->pih = pih; + + g_idle_add (iadelimage, iap); +} + +int imready (void* data) { + + gdk_threads_enter (); + + iaimgpar* iap = (iaimgpar*)data; + PreviewHandlerIdleHelper* pih = iap->pih; + + if (pih->destroyed) { + if (pih->pending == 1) + delete pih; + else + pih->pending--; + delete iap; + gdk_threads_leave (); + return 0; + } + + pih->phandler->previewImgMutex.lock (); + pih->phandler->previewImg = Gdk::Pixbuf::create_from_data (pih->phandler->image->getData(), Gdk::COLORSPACE_RGB, false, 8, pih->phandler->image->getWidth(), pih->phandler->image->getHeight(), 3*pih->phandler->image->getWidth()); + pih->phandler->previewImgMutex.unlock (); + pih->phandler->cropParams = iap->cp; + pih->phandler->previewImageChanged (); + pih->pending--; + delete iap; + + gdk_threads_leave (); + + return 0; +} + +void PreviewHandler::imageReady (CropParams cp) { + + pih->pending++; + iaimgpar* iap = new iaimgpar; + iap->pih = pih; + iap->cp = cp; + g_idle_add (imready, iap); +} + +Glib::RefPtr PreviewHandler::getRoughImage (int x, int y, int w, int h, double zoom) { + + Glib::RefPtr resPixbuf; + previewImgMutex.lock (); + if (previewImg) { + double totalZoom = zoom*previewScale; + if (w>previewImg->get_width()*totalZoom) + w = image->getWidth()*totalZoom; + if (h>previewImg->get_height()*totalZoom) + h = image->getHeight()*totalZoom; + int ix = x*zoom; + int iy = y*zoom; + if (ix<0) + ix = 0; + if (iy<0) + iy = 0; + if ((ix+w)/totalZoom>previewImg->get_width()) + ix = previewImg->get_width()*totalZoom - w; + if ((iy+h)/totalZoom>previewImg->get_height()) + iy = previewImg->get_height()*totalZoom - h; + + resPixbuf = Gdk::Pixbuf::create (Gdk::COLORSPACE_RGB, false, 8, w, h); + previewImg->scale (resPixbuf, 0, 0, w, h, -ix, -iy, totalZoom, totalZoom, Gdk::INTERP_NEAREST); + } + previewImgMutex.unlock (); + return resPixbuf; +} + +Glib::RefPtr PreviewHandler::getRoughImage (int desiredW, int desiredH, double& zoom_) { + + Glib::RefPtr resPixbuf; + previewImgMutex.lock (); + if (previewImg) { + double zoom1 = (double)desiredW / previewImg->get_width(); + double zoom2 = (double)desiredH / previewImg->get_height(); + double zoom = zoom1getWidth()*zoom, image->getHeight()*zoom); + previewImg->scale (resPixbuf, 0, 0, previewImg->get_width()*zoom, previewImg->get_height()*zoom, 0, 0, zoom, zoom, Gdk::INTERP_NEAREST); + zoom_ = zoom / previewScale; + } + previewImgMutex.unlock (); + return resPixbuf; +} + +void PreviewHandler::previewImageChanged () { + + for (std::list::iterator i=listeners.begin(); i!=listeners.end(); i++) + (*i)->previewImageChanged (); +} diff --git a/rtgui/previewhandler.h b/rtgui/previewhandler.h new file mode 100755 index 000000000..677ad5d3f --- /dev/null +++ b/rtgui/previewhandler.h @@ -0,0 +1,76 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _PREVIEWHANDLER_ +#define _PREVIEWHANDLER_ + +#include +#include +#include + +class PreviewListener { + + public: + virtual void previewImageChanged () {} +}; + +class PreviewHandler; +struct PreviewHandlerIdleHelper { + PreviewHandler* phandler; + bool destroyed; + int pending; +}; + +class PreviewHandler : public rtengine::PreviewImageListener { + + friend int iasetimage (void* data); + friend int iadelimage (void* data); + friend int imready (void* data); + + protected: + rtengine::IImage8* image; + rtengine::procparams::CropParams cropParams; + double previewScale; + PreviewHandlerIdleHelper* pih; + std::list listeners; + Glib::Mutex previewImgMutex; + Glib::RefPtr previewImg; + + + public: + + PreviewHandler (); + ~PreviewHandler (); + + void addPreviewImageListener (PreviewListener* l) { listeners.push_back (l); } + + // previewimagelistener + void setImage (rtengine::IImage8* img, double scale, rtengine::procparams::CropParams cp); + void delImage (rtengine::IImage8* img); + void imageReady (rtengine::procparams::CropParams cp); + + // this function is called when a new preview image arrives from rtengine + void previewImageChanged (); + + // with this function it is possible to ask for a rough approximation of a (possibly zoomed) crop of the image + Glib::RefPtr getRoughImage (int x, int y, int w, int h, double zoom); + Glib::RefPtr getRoughImage (int desiredW, int desiredH, double& zoom); + rtengine::procparams::CropParams getCropParams () { return cropParams; } +}; + +#endif diff --git a/rtgui/previewwindow.cc b/rtgui/previewwindow.cc new file mode 100755 index 000000000..9c3d647dd --- /dev/null +++ b/rtgui/previewwindow.cc @@ -0,0 +1,212 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include + +PreviewWindow::PreviewWindow () : previewHandler(NULL), mainCropWin(NULL), isMoving(false) { + + rconn = signal_size_allocate().connect( sigc::mem_fun(*this, &PreviewWindow::on_resized) ); +} + +PreviewWindow::~PreviewWindow () { + + delete cCropMoving; +#ifndef WIN32 + delete cNormal; +#endif +} + +void PreviewWindow::on_realize () { + + Gtk::DrawingArea::on_realize (); + add_events(Gdk::EXPOSURE_MASK | Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::SCROLL_MASK); + cCropMoving = new Gdk::Cursor (Gdk::FLEUR); +#ifdef _WIN32 + cNormal = new Gdk::Cursor (Gdk::LAST_CURSOR); +#else + cNormal = new Gdk::Cursor (Gdk::ARROW); +#endif +} + +void PreviewWindow::getObservedFrameArea (int& x, int& y, int& w, int& h) { + + if (mainCropWin) { + int cropX, cropY, cropW, cropH; + mainCropWin->getCropRectangle (cropX, cropY, cropW, cropH); + // translate it to screen coordinates + x = imgX + cropX*zoom; + y = imgY + cropY*zoom; + w = cropW * zoom; + h = cropH * zoom; + } +} + +void PreviewWindow::updatePreviewImage () { + + int W = get_width(), H = get_height(); + backBuffer = Gdk::Pixmap::create (get_window(), W, H, -1); + backBuffer->draw_rectangle (get_style()->get_base_gc(Gtk::STATE_NORMAL), true, 0, 0, W, H); + if (previewHandler) { + Glib::RefPtr resPixbuf = previewHandler->getRoughImage (W, H, zoom); + if (resPixbuf) { + imgW = resPixbuf->get_width(); + imgH = resPixbuf->get_height(); + imgX = (W-imgW)/2; + imgY = (H-imgH)/2; + backBuffer->draw_pixbuf (get_style()->get_base_gc(Gtk::STATE_NORMAL), resPixbuf, 0, 0, imgX, imgY, -1, -1, Gdk::RGB_DITHER_NONE, 0, 0); + Cairo::RefPtr cr = backBuffer->create_cairo_context(); + if (previewHandler->getCropParams().enabled) + drawCrop (cr, imgX, imgY, imgW, imgH, 0, 0, zoom, previewHandler->getCropParams()); + } + } +} + +void PreviewWindow::setPreviewHandler (PreviewHandler* ph) { + + previewHandler = ph; + previewHandler->addPreviewImageListener (this); +} + +void PreviewWindow::on_resized (Gtk::Allocation& req) { + + updatePreviewImage (); + queue_draw (); +} + +bool PreviewWindow::on_expose_event (GdkEventExpose* event) { + + if (backBuffer) { + Glib::RefPtr window = get_window(); + + int bufferW, bufferH; + backBuffer->get_size (bufferW, bufferH); + + if (!mainCropWin) { + mainCropWin = imageArea->getMainCropWindow (); + if (mainCropWin) + mainCropWin->addCropWindowListener (this); + } + + if (get_width()!=bufferW && get_height()!=bufferH) + updatePreviewImage (); + + window->draw_drawable (get_style()->get_base_gc(Gtk::STATE_NORMAL), backBuffer, 0, 0, 0, 0, -1, -1); + + if (mainCropWin) { + Cairo::RefPtr cr = get_window()->create_cairo_context(); + int x, y, w, h; + getObservedFrameArea (x, y, w, h); + cr->set_source_rgb (1.0, 1.0, 1.0); + cr->set_line_width (3); + cr->rectangle (x-1.5, y-1.5, w+2, h+2); + cr->stroke (); + cr->set_source_rgb (1.0, 0.0, 0.0); + cr->set_line_width (1); + cr->rectangle (x-1.5, y-1.5, w+2, h+2); + cr->stroke (); + } + } + return true; +} + +void PreviewWindow::previewImageChanged () { + + updatePreviewImage (); + queue_draw (); +} + +void PreviewWindow::setImageArea (ImageArea* ia) { + + imageArea = ia; + mainCropWin = ia->getMainCropWindow (); + if (mainCropWin) + mainCropWin->addCropWindowListener (this); +} + +void PreviewWindow::cropPositionChanged (CropWindow* w) { + + queue_draw (); +} + +void PreviewWindow::cropWindowSizeChanged (CropWindow* w) { + + queue_draw (); +} + +void PreviewWindow::cropZoomChanged (CropWindow* w) { + + queue_draw (); +} + +bool PreviewWindow::on_motion_notify_event (GdkEventMotion* event) { + + if (!mainCropWin) + return true; + + int x, y, w, h; + getObservedFrameArea (x, y, w, h); + bool inside = event->x > x-6 && event->x < x+w-1+6 && event->y > y-6 && event->y < y+h-1+6; + bool moreInside = event->x > x+6 && event->x < x+w-1-6 && event->y > y+6 && event->y < y+h-1-6; + + if (isMoving) + mainCropWin->remoteMove ((event->x - press_x)/zoom, (event->y - press_y)/zoom); + else if (inside && !moreInside) + get_window()->set_cursor (*cCropMoving); + else + get_window()->set_cursor (*cNormal); + +} + +bool PreviewWindow::on_button_press_event (GdkEventButton* event) { + + if (!mainCropWin) + return true; + + int x, y, w, h; + getObservedFrameArea (x, y, w, h); + bool inside = event->x > x-6 && event->x < x+w-1+6 && event->y > y-6 && event->y < y+h-1+6; + bool moreInside = event->x > x+6 && event->x < x+w-1-6 && event->y > y+6 && event->y < y+h-1-6; + + if (!isMoving) { + isMoving = true; + if (!inside || moreInside) { + mainCropWin->remoteMove ((event->x - (x+w/2))/zoom, (event->y - (y+h/2))/zoom); + press_x = x+w/2; + press_y = y+h/2; + } + else { + press_x = event->x; + press_y = event->y; + } + get_window()->set_cursor (*cCropMoving); + } +} + +bool PreviewWindow::on_button_release_event (GdkEventButton* event) { + + if (!mainCropWin) + return true; + + if (isMoving) { + isMoving = false; + get_window()->set_cursor (*cNormal); + mainCropWin->remoteMoveReady (); + } +} diff --git a/rtgui/previewwindow.h b/rtgui/previewwindow.h new file mode 100755 index 000000000..c3fcdb8d0 --- /dev/null +++ b/rtgui/previewwindow.h @@ -0,0 +1,68 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _PREVIEWWINDOW_ +#define _PREVIEWWINDOW_ + +#include +#include +#include + +class PreviewWindow : public Gtk::DrawingArea, public PreviewListener, public CropWindowListener { + + private: + Glib::RefPtr backBuffer; + int oldwidth, oldheight; + PreviewHandler* previewHandler; + sigc::connection rconn; + CropWindow* mainCropWin; + ImageArea* imageArea; + int imgX, imgY, imgW, imgH; + double zoom; + Gdk::Cursor* cCropMoving; + Gdk::Cursor* cNormal; + int press_x, press_y; + bool isMoving; + + void updatePreviewImage (); + void getObservedFrameArea (int& x, int& y, int& w, int& h); + + public: + PreviewWindow (); + ~PreviewWindow (); + + void setPreviewHandler (PreviewHandler* ph); + void setImageArea (ImageArea* ia); + + void on_realize (); + void on_resized (Gtk::Allocation& req); + bool on_expose_event (GdkEventExpose* event); + bool on_motion_notify_event (GdkEventMotion* event); + bool on_button_press_event (GdkEventButton* event); + bool on_button_release_event(GdkEventButton* event); + + // PreviewListener interface + void previewImageChanged (); + + // CropWindowListener interface + void cropPositionChanged (CropWindow* w); + void cropWindowSizeChanged (CropWindow* w); + void cropZoomChanged (CropWindow* w); +}; + +#endif diff --git a/rtgui/procparamchangers.h b/rtgui/procparamchangers.h new file mode 100755 index 000000000..6de1c5e21 --- /dev/null +++ b/rtgui/procparamchangers.h @@ -0,0 +1,24 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#define UNKNOWN -1 +#define FILEBROWSER 1 +#define EDITOR 2 +#define BATCHEDITOR 3 +#define CACHEMGR 4 +#define SAFETYUPDATE 5 diff --git a/rtgui/procthread.h b/rtgui/procthread.h new file mode 100755 index 000000000..f992899b4 --- /dev/null +++ b/rtgui/procthread.h @@ -0,0 +1,78 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _PROCTHREAD_ +#define _PROCTHREAD_ + +#include + +template +class ProcessingThread { + + protected: + bool tostop; + bool stopped; + std::list jqueue; + Glib::Thread* thread; + bool fifo; + + public: + ProcessingThread () : tostop(false), stopped(true), fifo(true) {} + void init () { tostop = false; stopped = true; } + void add (T de) { jqueue.push_back (de); } + void removejobs () { while (!jqueue.empty()) jqueue.pop_front (); } + void stop () { if (stopped) { tostop = true; return; } gdk_threads_leave(); tostop = true; Glib::Thread::self()->yield(); if (!stopped) thread->join (); gdk_threads_enter();} + + virtual void start () {} + virtual void process (T& e) {} + virtual void processCustomOrder () {} + virtual void end () {} + + void process () { + if (stopped) + #undef THREAD_PRIORITY_NORMAL + thread = Glib::Thread::create(sigc::mem_fun(*this, &ProcessingThread::process_), (unsigned long int)0, true, true, Glib::THREAD_PRIORITY_NORMAL); + } + void process_ () { + stopped = false; + tostop = false; + + start (); // jqueue.sort (); + + + while (!tostop && !jqueue.empty ()) { + if (fifo) { + T current = jqueue.front (); + jqueue.pop_front (); + process (current); + } + else + processCustomOrder (); + } + stopped = true; + end (); + } + + bool runs () { return !stopped; } + + void terminate () { stop (); removejobs (); } + + int numOfJobs () { return jqueue.size(); } +}; + +#endif diff --git a/rtgui/profilechangelistener.h b/rtgui/profilechangelistener.h new file mode 100755 index 000000000..a57ad4d88 --- /dev/null +++ b/rtgui/profilechangelistener.h @@ -0,0 +1,33 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _PROFILECHANGELISTENER_ +#define _PROFILECHANGELISTENER_ + +#include +#include + +class ProfileChangeListener { + + public: + virtual void profileChange (const rtengine::procparams::ProcParams* nparams, rtengine::ProcEvent event, const Glib::ustring& descr, const ParamsEdited* paramsEdited=NULL) {} + virtual void setDefaults (rtengine::procparams::ProcParams* defparams) {} +}; + +#endif + diff --git a/rtgui/profilepanel.cc b/rtgui/profilepanel.cc new file mode 100755 index 000000000..5849f885d --- /dev/null +++ b/rtgui/profilepanel.cc @@ -0,0 +1,385 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include +#include + +using namespace rtengine; +using namespace rtengine::procparams; + +extern Glib::ustring argv0; + +ProfilePanel::ProfilePanel () { + + tpc = NULL; + + profiles = Gtk::manage (new Gtk::ComboBoxText ()); + Gtk::HBox* hbox = Gtk::manage (new Gtk::HBox ()); + hbox->show (); +// pack_start (*profiles, Gtk::PACK_SHRINK, 4); + + pack_start (*hbox, Gtk::PACK_SHRINK, 4); + + save = Gtk::manage (new Gtk::Button ()); + save->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-save"), Gtk::ICON_SIZE_BUTTON))); + load = Gtk::manage (new Gtk::Button ()); + load->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-open"), Gtk::ICON_SIZE_BUTTON))); + copy = Gtk::manage (new Gtk::Button ()); + copy->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-copy"), Gtk::ICON_SIZE_BUTTON))); + paste = Gtk::manage (new Gtk::Button ()); + paste->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-paste"), Gtk::ICON_SIZE_BUTTON))); + + hbox->pack_start (*profiles); + hbox->pack_start (*load, Gtk::PACK_SHRINK, 1); + hbox->pack_start (*save, Gtk::PACK_SHRINK, 1); + hbox->pack_start (*copy, Gtk::PACK_SHRINK, 1); + hbox->pack_start (*paste, Gtk::PACK_SHRINK, 1); + + load->signal_clicked().connect( sigc::mem_fun(*this, &ProfilePanel::load_clicked) ); + save->signal_clicked().connect( sigc::mem_fun(*this, &ProfilePanel::save_clicked) ); + copy->signal_clicked().connect( sigc::mem_fun(*this, &ProfilePanel::copy_clicked) ); + paste->signal_clicked().connect( sigc::mem_fun(*this, &ProfilePanel::paste_clicked) ); + + custom = NULL; + lastphoto = NULL; + lastsaved = NULL; + dontupdate = false; + + refreshProfileList (); + + profiles->set_active (0); + old = profiles->get_active_text(); + changeconn = profiles->signal_changed().connect( sigc::mem_fun(*this, &ProfilePanel::selection_changed) ); + + save->set_tooltip_text (M("PROFILEPANEL_TOOLTIPSAVE")); + load->set_tooltip_text (M("PROFILEPANEL_TOOLTIPLOAD")); + copy->set_tooltip_text (M("PROFILEPANEL_TOOLTIPCOPY")); + paste->set_tooltip_text (M("PROFILEPANEL_TOOLTIPPASTE")); + + show_all_children (); +} + +ProfilePanel::~ProfilePanel () { + + delete custom; + delete lastsaved; + delete lastphoto; +} + +void ProfilePanel::refreshProfileList () { + + Glib::ustring oldsel = profiles->get_active_text (); + changeconn.block (true); + + // clear items + profiles->clear_items (); + pparams.clear (); + + // re-parse profile directories (deletes old ones) + profileStore.parseProfiles (); + pparams = profileStore.getProfileNames (); + for (int i=0; iappend_text (pparams[i]); + + if (custom) + profiles->append_text (Glib::ustring("(") + M("PROFILEPANEL_PCUSTOM") + ")"); + if (lastsaved) + profiles->append_text (Glib::ustring("(") + M("PROFILEPANEL_PLASTSAVED") + ")"); + if (lastphoto) + profiles->append_text (Glib::ustring("(") + M("PROFILEPANEL_PLASTPHOTO") + ")"); + + profiles->set_active_text (oldsel); + changeconn.block (false); +} + +void ProfilePanel::save_clicked () { + + Gtk::FileChooserDialog dialog(M("PROFILEPANEL_SAVEDLGLABEL"), Gtk::FILE_CHOOSER_ACTION_SAVE); + if (options.multiUser) + dialog.set_current_folder (Options::rtdir + "/" + options.profilePath); + else + dialog.set_current_folder (argv0 + "/" + options.profilePath); + + //Add response buttons the the dialog: + dialog.add_button(Gtk::StockID("gtk-cancel"), Gtk::RESPONSE_CANCEL); + dialog.add_button(Gtk::StockID("gtk-save"), Gtk::RESPONSE_OK); + + //Add filters, so that only certain file types can be selected: + + Gtk::FileFilter filter_pp; + filter_pp.set_name(M("PROFILEPANEL_FILEDLGFILTERPP")); + filter_pp.add_pattern("*.pp2"); + dialog.add_filter(filter_pp); + + Gtk::FileFilter filter_any; + filter_any.set_name(M("PROFILEPANEL_FILEDLGFILTERANY")); + filter_any.add_pattern("*"); + dialog.add_filter(filter_any); + +// dialog.set_do_overwrite_confirmation (true); + + savedialog = &dialog; + + int result = dialog.run(); + + if (result==Gtk::RESPONSE_OK) { + + std::string fname = dialog.get_filename(); + + bool hasext = true; + int dotpos = fname.find_last_of ('.'); + if (dotpos==Glib::ustring::npos) + hasext = false; + int dirpos1 = fname.find_last_of ('/'); + if (dirpos1!=Glib::ustring::npos && dirpos1>dotpos) + hasext = false; + int dirpos2 = fname.find_last_of ('\\'); + if (dirpos2!=Glib::ustring::npos && dirpos2>dotpos) + hasext = false; + + if (!hasext) + fname = fname + ".pp2"; + + if (Glib::file_test (fname, Glib::FILE_TEST_EXISTS)) { + Glib::ustring msg_ = Glib::ustring("") + fname + ": " + M("MAIN_MSG_ALREADYEXISTS") + "\n" + M("MAIN_MSG_QOVERWRITE") + ""; + Gtk::MessageDialog msgd (msg_, true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true); + int response = msgd.run (); + if (response==Gtk::RESPONSE_NO) + return; + } + + ProcParams* toSave = NULL; + if (profiles->get_active_text() == Glib::ustring("(") + M("PROFILEPANEL_PCUSTOM") + ")") + toSave = custom; + else if (profiles->get_active_text() == Glib::ustring("(") + M("PROFILEPANEL_PLASTSAVED") + ")") + toSave = lastsaved; + else if (profiles->get_active_text() == Glib::ustring("(") + M("PROFILEPANEL_PLASTPHOTO") + ")") + toSave = lastphoto; + else + toSave = profileStore.getProfile (profiles->get_active_text()); + + if (toSave) { + toSave->save (fname); + refreshProfileList (); + } + } +} + +void ProfilePanel::copy_clicked () { + + ProcParams* toSave = NULL; + if (profiles->get_active_text() == Glib::ustring("(") + M("PROFILEPANEL_PCUSTOM") + ")") + toSave = custom; + else if (profiles->get_active_text() == Glib::ustring("(") + M("PROFILEPANEL_PLASTSAVED") + ")") + toSave = lastsaved; + else if (profiles->get_active_text() == Glib::ustring("(") + M("PROFILEPANEL_PLASTPHOTO") + ")") + toSave = lastphoto; + else + toSave = profileStore.getProfile (profiles->get_active_text()); + + if (toSave) + clipboard.setProcParams (*toSave); +} + +void ProfilePanel::load_clicked () { + + Gtk::FileChooserDialog dialog(M("PROFILEPANEL_LOADDLGLABEL"), Gtk::FILE_CHOOSER_ACTION_OPEN); + if (options.multiUser) + dialog.set_current_folder (Options::rtdir + "/" + options.profilePath); + else + dialog.set_current_folder (argv0 + "/" + options.profilePath); + + //Add response buttons the the dialog: + dialog.add_button(Gtk::StockID("gtk-cancel"), Gtk::RESPONSE_CANCEL); + dialog.add_button(Gtk::StockID("gtk-open"), Gtk::RESPONSE_OK); + + //Add filters, so that only certain file types can be selected: + + Gtk::FileFilter filter_pp; + filter_pp.set_name(M("PROFILEPANEL_FILEDLGFILTERPP")); + filter_pp.add_pattern("*.pp2"); + dialog.add_filter(filter_pp); + + Gtk::FileFilter filter_any; + filter_any.set_name(M("PROFILEPANEL_FILEDLGFILTERANY")); + filter_any.add_pattern("*"); + dialog.add_filter(filter_any); + + int result = dialog.run(); + + if (result==Gtk::RESPONSE_OK) { + if (!custom) { + custom = new ProcParams (); + profiles->append_text (Glib::ustring("(") + M("PROFILEPANEL_PCUSTOM") + ")"); + } + custom->load (dialog.get_filename()); + profiles->set_active_text (Glib::ustring("(") + M("PROFILEPANEL_PCUSTOM") + ")"); + old = profiles->get_active_text(); + changeTo (custom, M("PROFILEPANEL_PFILE")); + } +} + +void ProfilePanel::paste_clicked () { + + if (!clipboard.hasProcParams()) + return; + + if (!custom) { + custom = new ProcParams (); + profiles->append_text (Glib::ustring("(") + M("PROFILEPANEL_PCUSTOM") + ")"); + } + *custom = clipboard.getProcParams (); + profiles->set_active_text (Glib::ustring("(") + M("PROFILEPANEL_PCUSTOM") + ")"); + old = profiles->get_active_text(); + changeTo (custom, M("HISTORY_FROMCLIPBOARD")); +} + +void ProfilePanel::changeTo (ProcParams* newpp, Glib::ustring profname) { + + if (!newpp) + return; + + // Keep transformation parameters while changing the profile + +/* int cropx = working->crop_x; + int cropy = working->crop_y; + int cropw = working->crop_w; + int croph = working->crop_h; + bool crope = working->crop_enabled; + int rotcor = working->rotate_coarse; + double rotfine = working->rotate_fine; + double lenscorr = working->lens_distortion; + bool hflip = working->horizontal_flip; + bool vflip = working->vertical_flip; + + working->copy (newpp); + + working->crop_x = cropx; + working->crop_y = cropy; + working->crop_w = cropw; + working->crop_h = croph; + working->crop_enabled = crope; + working->rotate_coarse = rotcor; + working->rotate_fine = rotfine; + working->lens_distortion = lenscorr; + working->horizontal_flip = hflip; + working->vertical_flip = vflip; +*/ + if (tpc) + tpc->profileChange (newpp, EvProfileChanged, profname); +} + +void ProfilePanel::selection_changed () { + + if (profiles->get_active_text() == Glib::ustring("(") + M("PROFILEPANEL_PCUSTOM") + ")") { + if (!dontupdate) + changeTo (custom, Glib::ustring("(") + M("PROFILEPANEL_PCUSTOM") + ")"); + } + else if (profiles->get_active_text() == Glib::ustring("(") + M("PROFILEPANEL_PLASTSAVED") + ")") + changeTo (lastsaved, Glib::ustring("(") + M("PROFILEPANEL_PLASTSAVED") + ")"); + else if (profiles->get_active_text() == Glib::ustring("(") + M("PROFILEPANEL_PLASTPHOTO") + ")") + changeTo (lastphoto, Glib::ustring("(") + M("PROFILEPANEL_PLASTPHOTO") + ")"); + else { + ProcParams* s = profileStore.getProfile (profiles->get_active_text()); + if (s) + changeTo (s, profiles->get_active_text()); + } + old = profiles->get_active_text (); + dontupdate = false; +} + +void ProfilePanel::procParamsChanged (rtengine::procparams::ProcParams* p, rtengine::ProcEvent ev, Glib::ustring descr, ParamsEdited* paramsEdited) { + + // to prevent recursion filter out the events caused by the profilepanel + if (ev==EvProfileChanged || ev==EvPhotoLoaded) + return; + + if (profiles->get_active_text() != Glib::ustring("(") + M("PROFILEPANEL_PCUSTOM") + ")") { + dontupdate = true; + if (!custom) { + custom = new ProcParams (); + profiles->append_text (Glib::ustring("(") + M("PROFILEPANEL_PCUSTOM") + ")"); + } + *custom = *p; + profiles->set_active_text (Glib::ustring("(") + M("PROFILEPANEL_PCUSTOM") + ")"); + old = profiles->get_active_text(); + } + else + *custom = *p; +} + +void ProfilePanel::initProfile (const Glib::ustring& profname, ProcParams* lastSaved, ProcParams* lastPhoto) { + + changeconn.block (true); + + profiles->clear_items (); + pparams.clear (); + + pparams = profileStore.getProfileNames (); + for (int i=0; iappend_text (pparams[i]); + + delete custom; + custom = NULL; + delete lastsaved; + lastsaved = lastSaved; + delete lastphoto; + lastphoto = lastPhoto; + + Glib::ustring defline = profname; + ProcParams* defprofile = profileStore.getProfile (profname); + + if (lastphoto) + profiles->append_text (Glib::ustring("(") + M("PROFILEPANEL_PLASTPHOTO") + ")"); + + if (lastsaved) { + defline = Glib::ustring("(") + M("PROFILEPANEL_PLASTSAVED") + ")"; + defprofile = lastsaved; + profiles->append_text (Glib::ustring("(") + M("PROFILEPANEL_PLASTSAVED") + ")"); + } + + if (tpc) { + if (lastsaved) + tpc->setDefaults (lastsaved); + else + tpc->setDefaults (profileStore.getProfile (profname)); + } + if (defprofile) { + old = defline; + profiles->set_active_text (defline); + changeconn.block (false); + if (tpc) + tpc->profileChange (defprofile, EvPhotoLoaded, defline); + } + else { + // select first valid profile + old = ""; + profiles->set_active (0); + ProcParams* s = profileStore.getProfile (profiles->get_active_text()); + if (!s) + s = new ProcParams (); + changeconn.block (false); + if (tpc) + tpc->profileChange (s, EvPhotoLoaded, profiles->get_active_text()); + } +} + + diff --git a/rtgui/profilepanel.h b/rtgui/profilepanel.h new file mode 100755 index 000000000..2009aad8b --- /dev/null +++ b/rtgui/profilepanel.h @@ -0,0 +1,70 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _PROFILEPANEL_ +#define _PROFILEPANEL_ + +#include +#include +#include +#include +#include + +class ProfilePanel : public Gtk::VBox, public PParamsChangeListener { + + protected: + + Gtk::Button* save; + Gtk::Button* load; + Gtk::Button* copy; + Gtk::Button* paste; + Gtk::ComboBoxText* profiles; + std::vector pparams; + rtengine::procparams::ProcParams* custom; + rtengine::procparams::ProcParams* lastsaved; + rtengine::procparams::ProcParams* lastphoto; + Glib::ustring old; + ProfileChangeListener* tpc; + bool dontupdate; + sigc::connection changeconn; + Gtk::FileChooserDialog* savedialog; + + void changeTo (rtengine::procparams::ProcParams* newpp, Glib::ustring profname); + void refreshProfileList (); + + public: + + ProfilePanel (); + virtual ~ProfilePanel (); + + void setProfileChangeListener (ProfileChangeListener* ppl) { tpc = ppl; } + + void initProfile (const Glib::ustring& profname, rtengine::procparams::ProcParams* lastSaved, rtengine::procparams::ProcParams* lastPhoto); + + // PParamsChangeListener interface + void procParamsChanged (rtengine::procparams::ProcParams* params, rtengine::ProcEvent ev, Glib::ustring descr, ParamsEdited* paramsEdited=NULL); + + // gui callbacks + void save_clicked (); + void load_clicked (); + void copy_clicked (); + void paste_clicked (); + void selection_changed (); +}; + +#endif diff --git a/rtgui/profilestore.cc b/rtgui/profilestore.cc new file mode 100755 index 000000000..81ab27b3b --- /dev/null +++ b/rtgui/profilestore.cc @@ -0,0 +1,105 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +ProfileStore profileStore; + +using namespace rtengine; +using namespace rtengine::procparams; + +extern Glib::ustring argv0; + +void ProfileStore::parseProfiles () { + + // clear loaded profiles + for (std::map::iterator i = pparams.begin(); i!=pparams.end(); i++) + delete i->second; + pparams.clear (); + + if (options.multiUser) { + Glib::ustring userPD = options.rtdir + "/" + options.profilePath; + if (!Glib::file_test (userPD, Glib::FILE_TEST_IS_DIR)) + g_mkdir_with_parents (userPD.c_str(), 511); + parseDir (userPD); + } + parseDir (argv0 + "/" + options.profilePath); +} + +void ProfileStore::parseDir (const Glib::ustring& pdir) { + + // reload the available profiles from the profile dir + if (pdir!="") { + // process directory + Glib::ustring dirname = pdir; + Glib::Dir* dir = NULL; + try { + dir = new Glib::Dir (dirname); + } + catch (const Glib::FileError& fe) { + return; + } + dirname = dirname + "/"; + for (Glib::DirIterator i = dir->begin(); i!=dir->end(); ++i) { + Glib::ustring fname = dirname + *i; + Glib::ustring sname = *i; + // ignore directories + if (!Glib::file_test (fname, Glib::FILE_TEST_IS_DIR)) { + int lastdot = sname.find_last_of ('.'); + if (lastdot!=Glib::ustring::npos && lastdot<=sname.size()-4 && !sname.casefold().compare (lastdot, 4, ".pp2")) { + printf ("processing file %s...\n", fname.c_str()); + Glib::ustring name = sname.substr(0,lastdot); + if (pparams.find(name)!=pparams.end()) { + delete pparams[name]; + pparams.erase (pparams.find(name)); + } + ProcParams* pp = new ProcParams (); + int res = pp->load (fname); + if (!res && pp->version>=220) + pparams[name] = pp; + else + delete pp; + } + } + } + delete dir; + } +} + +rtengine::procparams::ProcParams* ProfileStore::getProfile (const Glib::ustring& profname) { + + return pparams[profname]; +} + +std::vector ProfileStore::getProfileNames () { + + std::vector ret; + for (std::map::iterator i = pparams.begin(); i!=pparams.end(); i++) + ret.push_back (i->first); + return ret; +} + +rtengine::procparams::ProcParams* ProfileStore::getDefaultProcParams (bool isRaw) { + + if (!isRaw) + return getProfile (options.defProfImg); + else + return getProfile (options.defProfRaw); +} + diff --git a/rtgui/profilestore.h b/rtgui/profilestore.h new file mode 100755 index 000000000..d54b90498 --- /dev/null +++ b/rtgui/profilestore.h @@ -0,0 +1,42 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _PROFILESTORE_ +#define _PROFILESTORE_ + +#include +#include +#include +#include + +class ProfileStore { + + std::map pparams; + void parseDir (const Glib::ustring& pdir); + + public: + + void parseProfiles (); + rtengine::procparams::ProcParams* getProfile (const Glib::ustring& profname); + std::vector getProfileNames (); + rtengine::procparams::ProcParams* getDefaultProcParams (bool isRaw); +}; + +extern ProfileStore profileStore; + +#endif diff --git a/rtgui/progressdialog.cc b/rtgui/progressdialog.cc new file mode 100755 index 000000000..cc9df4c6b --- /dev/null +++ b/rtgui/progressdialog.cc @@ -0,0 +1,56 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +template +ProgressDialog::ProgressDialog (const sigc::slot0& slot) { + + set_deletable (false); + operation.connect (slot); +} + +template +void ProgressDialog::start () { + + T ret = operation.emit (); +} + +template +void ProgressDialog::finish () { + + gtk_threads_enter (); + hide (); + gtk_threads_leave (); +} + +template +void ProgressDialog::setProgress (double p) { +} + +template +void ProgressDialog::setProgressStr (Glib::ustring str) { +} + +template +void ProgressDialog::setProgressState (int state) { +} + +template +void ProgressDialog::error (Glib::ustring descr) { +} diff --git a/rtgui/progressdialog.h b/rtgui/progressdialog.h new file mode 100755 index 000000000..4539ee357 --- /dev/null +++ b/rtgui/progressdialog.h @@ -0,0 +1,126 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _PROGRESSDIALOG_ +#define _PROGRESSDIALOG_ + +#include +#include +#include + +class PLDBridge : public rtengine::ProgressListener { + + Gtk::Dialog* dialog; + Gtk::Label* label; + Gtk::ProgressBar* progBar; + + public: + PLDBridge (Gtk::Dialog* d, Gtk::Label* l, Gtk::ProgressBar* pb) + : dialog(d), label(l), progBar(pb) {} + + // progresslistener interface + void setProgress (double p) { + gdk_threads_enter (); + progBar->set_fraction (p); + gdk_threads_leave (); + } + void setProgressStr (Glib::ustring str) { + gdk_threads_enter (); + Glib::ustring progrstr; + if (str=="Decoding...") + progrstr = M("PROGRESSBAR_DECODING"); + else if (str=="Ready.") + progrstr = M("PROGRESSBAR_READY"); + else if (str=="Demosaicing...") + progrstr = M("PROGRESSBAR_DEMOSAICING"); + else if (str=="Loading...") + progrstr = M("PROGRESSBAR_LOADING"); + else if (str=="Loading PNG file...") + progrstr = M("PROGRESSBAR_LOADPNG"); + else if (str=="Loading JPEG file...") + progrstr = M("PROGRESSBAR_LOADJPEG"); + else if (str=="Loading TIFF file...") + progrstr = M("PROGRESSBAR_LOADTIFF"); + else if (str=="Saving PNG file...") + progrstr = M("PROGRESSBAR_SAVEPNG"); + else if (str=="Saving JPEG file...") + progrstr = M("PROGRESSBAR_SAVEJPEG"); + else if (str=="Saving TIFF file...") + progrstr = M("PROGRESSBAR_SAVETIFF"); + else if (str=="Processing...") + progrstr = M("PROGRESSBAR_PROCESSING"); + else + progrstr = str; + + label->set_text (progrstr); + gdk_threads_leave (); + } + void setProgressState (int state) {} + void error (Glib::ustring descr) {} +}; + +template +class ProgressDialog : public Gtk::Dialog { + + sigc::signal0 operation; + T* retval; + Gtk::Label prLabel; + Gtk::ProgressBar prProgBar; + + PLDBridge* pldBridge; + + + void workingThread () { + *retval = operation.emit (); + gdk_threads_enter (); + response (1); + gdk_threads_leave (); + } + + public: + + ProgressDialog (Glib::ustring label) : Gtk::Dialog (label, true) { + pldBridge = new PLDBridge (this, &prLabel, &prProgBar); + get_vbox()->pack_start (prLabel, Gtk::PACK_SHRINK, 4); + get_vbox()->pack_start (prProgBar, Gtk::PACK_SHRINK, 4); + set_size_request (300, -1); + show_all_children (); + } + + ~ProgressDialog () { + delete pldBridge; + } + + rtengine::ProgressListener* getProgressListener () { return pldBridge; } + + void setFunc (const sigc::slot0& slot, T* rv) { + retval = rv; + operation.connect (slot); + } + + void start () { + Glib::Thread *thread = Glib::Thread::create(sigc::mem_fun(*this, &ProgressDialog::workingThread), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + int x = run (); + if (x<0) { + gdk_threads_leave (); + thread->join (); + gdk_threads_enter (); + } + } +}; +#endif diff --git a/rtgui/quickzoomlistener.h b/rtgui/quickzoomlistener.h new file mode 100755 index 000000000..958e05302 --- /dev/null +++ b/rtgui/quickzoomlistener.h @@ -0,0 +1,34 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _QZLISTENER_ +#define _QZLISTENER_ + +class QuickZoomListener { + + public: + + virtual void increaseZoom () {} + virtual void decreaseZoom () {} + virtual void quickZoom () {} + virtual void increaseCropZoom () {} + virtual void decreaseCropZoom () {} + virtual void quickCropZoom () {} +}; + +#endif diff --git a/rtgui/recentbrowser.cc b/rtgui/recentbrowser.cc new file mode 100755 index 000000000..e694d5e7a --- /dev/null +++ b/rtgui/recentbrowser.cc @@ -0,0 +1,52 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +RecentBrowser::RecentBrowser () : listener (NULL) { + + recentDirs = Gtk::manage (new Gtk::ComboBoxText ()); + + Gtk::Frame* frame = Gtk::manage (new Gtk::Frame ("Recent Folders")); + frame->add (*recentDirs); + + pack_start (*frame, Gtk::PACK_SHRINK, 4); + + conn = recentDirs->signal_changed().connect(sigc::mem_fun(*this, &RecentBrowser::selectionChanged)); + + show_all (); +} + +void RecentBrowser::selectionChanged () { + + Glib::ustring sel = recentDirs->get_active_text (); + if (sel!="" && listener) + listener->selectDir (sel); +} + +void RecentBrowser::dirSelected (const Glib::ustring& dirname, const Glib::ustring& openfile) { + + conn.block (true); + + recentDirs->remove_text (dirname); + recentDirs->prepend_text (dirname); + recentDirs->set_active_text (dirname); + + conn.block (false); +} + diff --git a/rtgui/recentbrowser.cc.old b/rtgui/recentbrowser.cc.old new file mode 100755 index 000000000..42ab1c19b --- /dev/null +++ b/rtgui/recentbrowser.cc.old @@ -0,0 +1,59 @@ +#include + +RecentBrowser::RecentBrowser () : listener (NULL) { + + scrollw = Gtk::manage (new Gtk::ScrolledWindow ()); + scrollw->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); + + Gtk::Frame* frame = Gtk::manage (new Gtk::Frame ("Recent Folders")); + frame->add (*scrollw); + + pack_start (*frame); + + treeView = Gtk::manage (new Gtk::TreeView ()); + scrollw->add (*treeView); + + recentModel = Gtk::ListStore::create (recentColumns); + treeView->set_model (recentModel); + treeView->set_headers_visible (false); + + Gtk::CellRendererText *crt = Gtk::manage (new Gtk::CellRendererText()); + Gtk::TreeView::Column *col = Gtk::manage (new Gtk::TreeView::Column ("")); + col->pack_start (*crt, true); + col->add_attribute (crt->property_text (), recentColumns.dir); + col->set_sizing (Gtk::TREE_VIEW_COLUMN_FIXED); + crt->set_property ("xalign", 1.0); + + treeView->append_column (*col); + treeView->set_tooltip_column (0); + + treeView->get_selection()->signal_changed().connect(sigc::mem_fun(*this, &RecentBrowser::selectionChanged)); + + show_all (); +} + +void RecentBrowser::selectionChanged () { + + Glib::RefPtr selection = treeView->get_selection(); + Gtk::TreeModel::iterator iter = selection->get_selected(); + if (iter && listener) + listener->selectDir (iter->get_value (recentColumns.dir)); +} + +void RecentBrowser::dirSelected (const Glib::ustring& dirname, const Glib::ustring& openfile) { + + // check if the dirname is already in the list. If yes, remove it. + Gtk::TreeModel::iterator iter = recentModel->children ().begin(); + while (iter != recentModel->children().end()) { + if (iter->get_value (recentColumns.dir) == dirname) { + recentModel->erase (iter); + break; + } + iter++; + } + + // append dirname to the top of the list + iter = recentModel->prepend (); + iter->set_value (recentColumns.dir, dirname); +} + diff --git a/rtgui/recentbrowser.h b/rtgui/recentbrowser.h new file mode 100755 index 000000000..26280bc4e --- /dev/null +++ b/rtgui/recentbrowser.h @@ -0,0 +1,44 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _RECENTBROWSER_ +#define _RECENTBROWSER_ + +#include +#include +#include + +class RecentBrowser : public Gtk::VBox, public DirSelectionListener { + + Gtk::ComboBoxText* recentDirs; + sigc::connection conn; + DirBrowserRemoteInterface* listener; + + public: + + RecentBrowser (); + + void setDirBrowserRemoteInterface (DirBrowserRemoteInterface* l) { listener = l; } + + void selectionChanged (); + void dirSelected (const Glib::ustring& dirname, const Glib::ustring& openfile=""); +}; + +#endif + + diff --git a/rtgui/recentbrowser.h.old b/rtgui/recentbrowser.h.old new file mode 100755 index 000000000..f797ec13f --- /dev/null +++ b/rtgui/recentbrowser.h.old @@ -0,0 +1,33 @@ +#ifndef _RECENTBROWSER_ +#define _RECENTBROWSER_ + +#include +#include +#include + +class RecentBrowser : public Gtk::VBox, public DirSelectionListener { + + class RecentColumns : public Gtk::TreeModel::ColumnRecord { + public: + Gtk::TreeModelColumn dir; + RecentColumns() { add(dir); } + }; + RecentColumns recentColumns; + Gtk::ScrolledWindow* scrollw; + Gtk::TreeView* treeView; + Glib::RefPtr recentModel; + DirBrowserRemoteInterface* listener; + + public: + + RecentBrowser (); + + void setDirBrowserRemoteInterface (DirBrowserRemoteInterface* l) { listener = l; } + + void selectionChanged (); + void dirSelected (const Glib::ustring& dirname, const Glib::ustring& openfile=""); +}; + +#endif + + diff --git a/rtgui/recentselectionlistener.h b/rtgui/recentselectionlistener.h new file mode 100755 index 000000000..c1e865bd1 --- /dev/null +++ b/rtgui/recentselectionlistener.h @@ -0,0 +1,30 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _RECENTSELECTIONLISTENER_ +#define _RECENTSELECTIONLISTENER_ + +#include + +class RecentSelectionListener { + + public: + virtual void recentSelected (Glib::ustring recentdir) {} +}; + +#endif diff --git a/rtgui/renamedlg.cc b/rtgui/renamedlg.cc new file mode 100755 index 000000000..34d34ebb3 --- /dev/null +++ b/rtgui/renamedlg.cc @@ -0,0 +1,215 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include + +RenameDialog::RenameDialog (Gtk::Window* parent) + : Gtk::Dialog (M("FILEBROWSER_RENAMEDLGLABEL"), *parent, true, true), imageData(NULL), p(parent) { + + Gtk::Table* names = Gtk::manage (new Gtk::Table (2, 2)); + Gtk::Label* onlab = Gtk::manage (new Gtk::Label ("Current name:")); + Gtk::Label* nnlab = Gtk::manage (new Gtk::Label ("New name:")); + oldName = Gtk::manage (new Gtk::Label ("alma")); + newName = Gtk::manage (new Gtk::Entry ()); + + names->attach (*onlab, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + names->attach (*oldName, 1, 2, 0, 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + names->attach (*nnlab, 0, 1, 1, 2, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + names->attach (*newName, 1, 2, 1, 2, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + + get_vbox()->pack_start (*names, Gtk::PACK_SHRINK, 4); + + Gtk::HBox* tbox = Gtk::manage (new Gtk::HBox()); + useTmpl = Gtk::manage (new Gtk::CheckButton ("Use template:")); + templates = Gtk::manage (new Gtk::ComboBox ()); + templateModel = Gtk::ListStore::create (templateColumns); + templates->set_model (templateModel); + templates->pack_start (templateColumns.tmplName); + + tbox->pack_start (*useTmpl, Gtk::PACK_SHRINK, 4); + tbox->pack_start (*templates); + + get_vbox()->pack_start (*tbox, Gtk::PACK_SHRINK, 4); + + add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK); + add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + all = add_button ("All", RESPONSE_ALL); + + newName->set_activates_default (true); + set_default_response (Gtk::RESPONSE_OK); + + fillTemplateList (); + + templates->set_row_separator_func (sigc::mem_fun(*this, &RenameDialog::rowSeparatorFunc)); + templates->signal_changed().connect(sigc::mem_fun(*this, &RenameDialog::tmplSelectionChanged)); + useTmpl->signal_toggled().connect( sigc::mem_fun(*this, &RenameDialog::useTemplToggled) ); + + useTmpl->set_active (options.renameUseTemplates); + + show_all_children (); +} + +void RenameDialog::initName (const Glib::ustring& iname, const CacheImageData* cid) { + + imageData = cid; + oldName->set_text (iname); + newName->set_text (iname); + if (useTmpl->get_active () && isTemplSelected ()) + newName->set_text (applyTemplate (iname, cid, getActiveTemplate())); + newName->select_region (0, newName->get_text().size()); +} + +Glib::ustring RenameDialog::getNewName () { + + return newName->get_text (); +} + +void RenameDialog::fillTemplateList () { + + templateModel->clear (); + + for (int i=0; iappend (); + iter->set_value (templateColumns.tmplName, options.renameTemplates[i]); + iter->set_value (templateColumns.rowSeparator, false); + } + // append separator and the manage... item + Gtk::TreeModel::iterator iter = templateModel->append (); + iter->set_value (templateColumns.tmplName, Glib::ustring("")); + iter->set_value (templateColumns.rowSeparator, true); + iter = templateModel->append (); + iter->set_value (templateColumns.tmplName, Glib::ustring("Add/Del templates...")); + iter->set_value (templateColumns.rowSeparator, false); +} + +bool RenameDialog::rowSeparatorFunc (const Glib::RefPtr& model, const Gtk::TreeModel::iterator& iter) { + + return iter->get_value (templateColumns.rowSeparator); +} + +void RenameDialog::useTemplToggled () { + + templates->set_sensitive (useTmpl->get_active ()); + if (useTmpl->get_active () && isTemplSelected ()) { + all->set_sensitive (true); + newName->set_text (applyTemplate (oldName->get_text(), imageData, getActiveTemplate())); + } + else + all->set_sensitive (false); + newName->select_region (0, newName->get_text().size()); +} + +bool RenameDialog::isTemplSelected () { + + Gtk::TreeModel::iterator iter = templates->get_active(); + return iter && iter->get_value (templateColumns.tmplName)!="Add/Del templates..."; +} + +Glib::ustring RenameDialog::getActiveTemplate () { + + Gtk::TreeModel::iterator iter = templates->get_active(); + if (iter && iter->get_value (templateColumns.tmplName)!="Add/Del templates...") + return iter->get_value (templateColumns.tmplName); + else + return ""; +} + +void RenameDialog::tmplSelectionChanged () { + + Gtk::TreeModel::iterator iter = templates->get_active(); + if (iter && iter->get_value (templateColumns.tmplName)=="Add/Del templates...") { + RenameTemplateEditor* rte = new RenameTemplateEditor (p); + if (rte->run()==Gtk::RESPONSE_OK) { + fillTemplateList (); + } + delete rte; + // show add/del template dialog + } + else + useTemplToggled (); +} + +RenameTemplateEditor::RenameTemplateEditor (Gtk::Window* parent) + : Gtk::Dialog ("Edit rename templates", *parent, true, true) { + + list = Gtk::manage (new Gtk::ListViewText (1, false, Gtk::SELECTION_MULTIPLE)); + list->set_headers_visible (false); + get_vbox ()->pack_start (*list); + + Gtk::HBox* hb = Gtk::manage (new Gtk::HBox ()); + templ = Gtk::manage (new Gtk::Entry ()); + Gtk::Button* add = Gtk::manage (new Gtk::Button ()); + Gtk::Button* del = Gtk::manage (new Gtk::Button ()); + add->add (*Gtk::manage (new Gtk::Image (argv0+"/images/list-add12.png"))); + del->add (*Gtk::manage (new Gtk::Image (argv0+"/images/list-remove12r.png"))); + hb->pack_start (*templ); + hb->pack_start (*add, Gtk::PACK_SHRINK, 2); + hb->pack_start (*del, Gtk::PACK_SHRINK, 2); + + get_vbox ()->pack_start (*hb, Gtk::PACK_SHRINK, 4); + + add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK); + + refreshTemplateList (); + + add->signal_pressed().connect( sigc::mem_fun(*this, &RenameTemplateEditor::addPressed) ); + del->signal_pressed().connect( sigc::mem_fun(*this, &RenameTemplateEditor::delPressed) ); + + show_all_children (); + + set_size_request (-1, 250); +} + +void RenameTemplateEditor::refreshTemplateList () { + + list->clear_items (); + + for (int i=0; iappend_text (options.renameTemplates[i]); +} + +void RenameTemplateEditor::addPressed () { + + if (templ->get_text()!="") { + options.renameTemplates.push_back (templ->get_text ()); + refreshTemplateList (); + templ->set_text(""); + } +} + +void RenameTemplateEditor::delPressed () { + + std::vector sel = list->get_selected (); + for (int i=0; iget_text (sel[i]); + std::vector::iterator f = std::find (options.renameTemplates.begin(), options.renameTemplates.end(), toDel); + if (f!=options.renameTemplates.end()) + options.renameTemplates.erase (f); + } + refreshTemplateList (); +} + +Glib::ustring RenameDialog::applyTemplate (const Glib::ustring& oName, const CacheImageData* cid, const Glib::ustring& templ) { + + return Glib::ustring ("szeva"); + +} + + diff --git a/rtgui/renamedlg.h b/rtgui/renamedlg.h new file mode 100755 index 000000000..e1cef34d9 --- /dev/null +++ b/rtgui/renamedlg.h @@ -0,0 +1,83 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _RENAMEDLG_ +#define _RENAMEDLG_ + +#include +#include + +#define RESPONSE_ALL 100 + +class RenameDialog : public Gtk::Dialog { + + protected: + + class TemplateColumns : public Gtk::TreeModel::ColumnRecord { + public: + Gtk::TreeModelColumn tmplName; + Gtk::TreeModelColumn rowSeparator; + TemplateColumns() { add(tmplName); add(rowSeparator); } + }; + TemplateColumns templateColumns; + Glib::RefPtr templateModel; + + Gtk::Window* p; + Gtk::Label* oldName; + Gtk::Entry* newName; + Gtk::CheckButton* useTmpl; + Gtk::ComboBox* templates; + Gtk::Button* all; + const CacheImageData* imageData; + + void fillTemplateList (); + + public: + RenameDialog (Gtk::Window* parent); + + void initName (const Glib::ustring& iname, const CacheImageData* cid); + Glib::ustring getNewName (); + + bool rowSeparatorFunc (const Glib::RefPtr& model, const Gtk::TreeModel::iterator& iter); + void tmplSelectionChanged (); + void useTemplToggled (); + + bool isTemplSelected (); + Glib::ustring getActiveTemplate (); + + static Glib::ustring applyTemplate (const Glib::ustring& oName, const CacheImageData* cid, const Glib::ustring& templ); +}; + +class RenameTemplateEditor : public Gtk::Dialog { + + protected: + Gtk::ListViewText* list; + Gtk::Entry* templ; + + void refreshTemplateList (); + public: + RenameTemplateEditor (Gtk::Window* parent); + + Glib::ustring getSelectedTemplate (); + + void addPressed (); + void delPressed (); +}; + +#endif + diff --git a/rtgui/resize.cc b/rtgui/resize.cc new file mode 100755 index 000000000..0ae776dbb --- /dev/null +++ b/rtgui/resize.cc @@ -0,0 +1,346 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include + +using namespace rtengine; +using namespace rtengine::procparams; + +Resize::Resize () : maxw(100000), maxh(100000) { + + enabled = Gtk::manage (new Gtk::CheckButton (M("GENERAL_ENABLED"))); + pack_start(*enabled); + pack_start(*Gtk::manage (new Gtk::HSeparator()), Gtk::PACK_SHRINK, 2); + + Gtk::Table* combos = Gtk::manage (new Gtk::Table (2, 2)); + + method = Gtk::manage (new Gtk::ComboBoxText ()); + method->append_text (M("TP_RESIZE_NEAREST")); + method->append_text (M("TP_RESIZE_BILINEAR")); + method->append_text (M("TP_RESIZE_BICUBIC")); + method->append_text (M("TP_RESIZE_BICUBICSF")); + method->append_text (M("TP_RESIZE_BICUBICSH")); + method->set_active (0); + + combos->attach (*Gtk::manage (new Gtk::Label (M("TP_RESIZE_METHOD"))), 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + combos->attach (*method, 1, 2, 0, 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + + spec = Gtk::manage (new Gtk::ComboBoxText ()); + spec->append_text ("Scale"); + spec->append_text ("Width"); + spec->append_text ("Height"); + method->set_active (0); + + combos->attach (*Gtk::manage (new Gtk::Label ("Specify:")), 0, 1, 1, 2, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + combos->attach (*spec, 1, 2, 1, 2, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + + pack_start (*combos, Gtk::PACK_SHRINK, 4); + + scale = new Adjuster (M("TP_RESIZE_SCALE"), 0.2, 4, 0.01, 1); + scale->setAdjusterListener (this); + + pack_start (*scale, Gtk::PACK_SHRINK, 4); + + sizeBox = Gtk::manage (new Gtk::VBox ()); + + Gtk::HBox* sbox = Gtk::manage (new Gtk::HBox ()); + Gtk::HBox* wbox = Gtk::manage (new Gtk::HBox ()); + Gtk::HBox* hbox = Gtk::manage (new Gtk::HBox ()); + w = Gtk::manage (new Gtk::SpinButton ()); + h = Gtk::manage (new Gtk::SpinButton ()); + wbox->pack_start (*Gtk::manage (new Gtk::Label (M("TP_RESIZE_W"))), Gtk::PACK_SHRINK, 4); + wbox->pack_start (*w); + hbox->pack_start (*Gtk::manage (new Gtk::Label (M("TP_RESIZE_H"))), Gtk::PACK_SHRINK, 4); + hbox->pack_start (*h); + sbox->pack_start (*wbox); + sbox->pack_start (*hbox); + + sizeBox->pack_start (*sbox, Gtk::PACK_SHRINK, 4); + sizeBox->show_all (); + sizeBox->reference (); + + w->set_digits (0); + w->set_increments (1,100); + w->set_value (800); + w->set_range (32, 4*maxw); + + h->set_digits (0); + h->set_increments (1,100); + h->set_value (600); + h->set_range (32, 4*maxh); + + wconn = w->signal_value_changed().connect ( sigc::mem_fun(*this, &Resize::entryWChanged), true); + hconn = h->signal_value_changed().connect ( sigc::mem_fun(*this, &Resize::entryHChanged), true); + method->signal_changed().connect ( sigc::mem_fun(*this, &Resize::methodChanged) ); + spec->signal_changed().connect ( sigc::mem_fun(*this, &Resize::specChanged) ); + enaConn = enabled->signal_toggled().connect ( sigc::mem_fun(*this, &Resize::enabledToggled) ); + + show_all(); +} + +Resize::~Resize () { + + delete scale; + delete sizeBox; +} + +void Resize::read (const ProcParams* pp, const ParamsEdited* pedited) { + + disableListener (); + wconn.block (true); + hconn.block (true); + + scale->setValue (pp->resize.scale); + w->set_value (pp->resize.width); + h->set_value (pp->resize.height); + enabled->set_active (pp->resize.enabled); + spec->set_active (pp->resize.dataspec); + + method->set_active (2); + if (pp->resize.method == "Nearest") + method->set_active (0); + else if (pp->resize.method == "Bilinear") + method->set_active (1); + else if (pp->resize.method == "Bicubic") + method->set_active (2); + else if (pp->resize.method == "Bicubic (Softer)") + method->set_active (3); + else if (pp->resize.method == "Bicubic (Sharper)") + method->set_active (4); + + wDirty = false; + hDirty = false; + + if (pedited) { + wDirty = pedited->resize.width; + hDirty = pedited->resize.height; + scale->setEditedState (pedited->resize.scale ? Edited : UnEdited); + if (!pedited->resize.method) + method->set_active (5); + if (!pedited->resize.dataspec) + spec->set_active (3); + enabled->set_inconsistent (!pedited->resize.enabled); + } + + lastEnabled = pp->resize.enabled; + + wconn.block (false); + hconn.block (false); + enableListener (); +} + +void Resize::write (ProcParams* pp, ParamsEdited* pedited) { + + pp->resize.scale = scale->getValue (); + pp->resize.method = "Bicubic"; + if (method->get_active_row_number() == 0) + pp->resize.method = "Nearest"; + else if (method->get_active_row_number() == 1) + pp->resize.method = "Bilinear"; + else if (method->get_active_row_number() == 2) + pp->resize.method = "Bicubic"; + else if (method->get_active_row_number() == 3) + pp->resize.method = "Bicubic (Softer)"; + else if (method->get_active_row_number() == 4) + pp->resize.method = "Bicubic (Sharper)"; + + pp->resize.dataspec = spec->get_active_row_number(); + pp->resize.width = round (w->get_value ()); + pp->resize.height = round(h->get_value ()); + pp->resize.enabled = enabled->get_active (); + + if (pedited) { + pedited->resize.enabled = !enabled->get_inconsistent(); + pedited->resize.dataspec = spec->get_active_row_number() != 3; + pedited->resize.method = method->get_active_row_number() != 5; + if (pedited->resize.dataspec) { + pedited->resize.scale = scale->getEditedState (); + pedited->resize.width = wDirty; + pedited->resize.height = hDirty; + } + else { + pedited->resize.scale = false; + pedited->resize.width = false; + pedited->resize.height = false; + } + } +} + +void Resize::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { + + scale->setDefault (defParams->resize.scale); + + if (pedited) + scale->setDefaultEditedState (pedited->resize.scale ? Edited : UnEdited); + else + scale->setDefaultEditedState (Irrelevant); +} + +void Resize::adjusterChanged (Adjuster* a, double newval) { + + if (!batchMode) { + wconn.block (true); + hconn.block (true); + h->set_value (maxh * a->getValue ()); + w->set_value (maxw * a->getValue ()); + wconn.block (false); + hconn.block (false); + } + + if (listener && (enabled->get_active () || batchMode)) + listener->panelChanged (EvResizeScale, Glib::ustring::format (std::setw(5), std::fixed, std::setprecision(4), scale->getValue())); +} + +void Resize::methodChanged () { + + if (listener && (enabled->get_active () || batchMode)) + listener->panelChanged (EvResizeMethod, method->get_active_text()); +} + +struct setrdimparams { + Resize* resize; + int mw; + int mh; + int ow; + int oh; +}; + +int setrdim (void* data) { + + gdk_threads_enter (); + setrdimparams* params = (setrdimparams*)data; + params->resize->setDimensions (params->mw, params->mh, params->ow, params->oh); + delete params; + gdk_threads_leave (); + return 0; +} + +void Resize::sizeChanged (int mw, int mh, int ow, int oh) { + + setrdimparams* params = new setrdimparams; + params->mw = mw; + params->mh = mh; + params->ow = ow; + params->oh = oh; + params->resize = this; + g_idle_add (setrdim, params); +} + +void Resize::setDimensions (int mw, int mh, int ow, int oh) { + + maxw = ow; + maxh = oh; + + wconn.block (true); + hconn.block (true); + + w->set_range (32, 4*maxw); + h->set_range (32, 4*maxh); + + wconn.block (false); + hconn.block (false); +} + +void Resize::entryWChanged () { + + wDirty = true; + + if (!batchMode && listener) { + hconn.block (true); + h->set_value (w->get_value () * maxh / maxw); + hconn.block (false); + scale->setValue (w->get_value () / maxw); + } + + if (listener && (enabled->get_active () || batchMode)) + listener->panelChanged (EvResizeWidth, Glib::ustring::format ((int)w->get_value())); + + +} + +void Resize::entryHChanged () { + + hDirty = true; + + if (!batchMode && listener) { + wconn.block (true); + w->set_value (h->get_value () * maxw / maxh); + wconn.block (false); + scale->setValue (h->get_value () / maxh); + } + + if (listener && (enabled->get_active () || batchMode)) + listener->panelChanged (EvResizeHeight, Glib::ustring::format ((int)h->get_value())); +} + +void Resize::specChanged () { + + removeIfThere (this, scale, false); + removeIfThere (this, sizeBox, false); + + if (spec->get_active_row_number() == 0) { + pack_start (*scale, Gtk::PACK_SHRINK, 4); + scale->sliderChanged (); + } + else if (spec->get_active_row_number() == 1) { + pack_start (*sizeBox, Gtk::PACK_SHRINK, 4); + w->set_sensitive (true); + h->set_sensitive (false); + entryWChanged (); + } + else if (spec->get_active_row_number() == 2) { + pack_start (*sizeBox, Gtk::PACK_SHRINK, 4); + h->set_sensitive (true); + w->set_sensitive (false); + entryHChanged (); + } +} + +void Resize::setBatchMode (bool batchMode) { + + method->append_text ("(Unchanged)"); + spec->append_text ("(Unchanged)"); + ToolPanel::setBatchMode (batchMode); + scale->showEditedCB (); +} + +void Resize::enabledToggled () { + + if (batchMode) { + if (enabled->get_inconsistent()) { + enabled->set_inconsistent (false); + enaConn.block (true); + enabled->set_active (false); + enaConn.block (false); + } + else if (lastEnabled) + enabled->set_inconsistent (true); + + lastEnabled = enabled->get_active (); + } + + if (listener) { + if (enabled->get_active ()) + listener->panelChanged (EvResizeEnabled, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvResizeEnabled, M("GENERAL_DISABLED")); + } +} + diff --git a/rtgui/resize.h b/rtgui/resize.h new file mode 100755 index 000000000..5f9a3f2b6 --- /dev/null +++ b/rtgui/resize.h @@ -0,0 +1,60 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _RESIZE_H_ +#define _RESIZE_H_ + +#include +#include +#include + +class Resize : public Gtk::VBox, public AdjusterListener, public ToolPanel, public rtengine::SizeListener { + + protected: + Gtk::CheckButton* enabled; + Adjuster* scale; + Gtk::VBox* sizeBox; + Gtk::ComboBoxText* method; + Gtk::ComboBoxText* spec; + Gtk::SpinButton* w; + Gtk::SpinButton* h; + int maxw, maxh; + sigc::connection wconn, hconn, enaConn; + bool wDirty, hDirty, lastEnabled; + + public: + + Resize (); + ~Resize (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + + void adjusterChanged (Adjuster* a, double newval); + void entryWChanged (); + void entryHChanged (); + void methodChanged (); + void specChanged (); + void sizeChanged (int w, int h, int ow, int oh); + void setDimensions (int w, int h, int ow, int oh); + void enabledToggled (); +}; + +#endif diff --git a/rtgui/rotate.cc b/rtgui/rotate.cc new file mode 100755 index 000000000..f0411f7e2 --- /dev/null +++ b/rtgui/rotate.cc @@ -0,0 +1,157 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include + +extern Glib::ustring argv0; + +using namespace rtengine; +using namespace rtengine::procparams; + +Rotate::Rotate () : ToolPanel (), degAdd(false) { + + rlistener = NULL; + + degree = Gtk::manage (new Adjuster (M("TP_ROTATE_DEGREE"), -45, 45, 0.01, 0)); + degree->setAdjusterListener (this); + pack_start (*degree); + + fill = Gtk::manage (new Gtk::CheckButton (M("TP_ROTATE_FILL"))); + pack_start (*fill); + + selectStraight = Gtk::manage (new Gtk::Button (M("TP_ROTATE_SELECTLINE"))); + Gtk::Image* selimg = Gtk::manage (new Gtk::Image (argv0+"/images/straighten16.png")); + selectStraight->set_image (*selimg); + pack_start (*selectStraight, Gtk::PACK_SHRINK, 2); + + autoCrop = Gtk::manage (new Gtk::Button (M("TP_ROTATE_AUTOCROP"))); + pack_start (*autoCrop, Gtk::PACK_SHRINK, 2); + + selectStraight->signal_pressed().connect( sigc::mem_fun(*this, &Rotate::selectStraightPressed) ); + autoCrop->signal_pressed().connect( sigc::mem_fun(*this, &Rotate::autoCropPressed) ); + fillConn = fill->signal_toggled().connect( sigc::mem_fun(*this, &Rotate::fillPressed) ); + + fill->set_active (true); + show_all (); +} + +void Rotate::read (const ProcParams* pp, const ParamsEdited* pedited) { + + disableListener (); + + if (pedited) { + degree->setEditedState (pedited->rotate.degree ? Edited : UnEdited); + fill->set_inconsistent (!pedited->rotate.fill); + } + + degree->setValue (pp->rotate.degree); + fillConn.block (true); + fill->set_active (pp->rotate.fill); + fillConn.block (false); + + lastFill = pp->rotate.fill; + + enableListener (); +} + +void Rotate::write (ProcParams* pp, ParamsEdited* pedited) { + + pp->rotate.degree = degree->getValue (); + pp->rotate.fill = fill->get_active (); + + if (pedited) { + pedited->rotate.degree = degree->getEditedState (); + pedited->rotate.fill = !fill->get_inconsistent(); + } +} + +void Rotate::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { + + degree->setDefault (defParams->rotate.degree); + + if (pedited) + degree->setDefaultEditedState (pedited->rotate.degree ? Edited : UnEdited); + else + degree->setDefaultEditedState (Irrelevant); +} + +void Rotate::adjusterChanged (Adjuster* a, double newval) { + + if (listener) + listener->panelChanged (EvROTDegree, Glib::ustring::format (std::setw(3), std::fixed, std::setprecision(2), degree->getValue())); +} + +void Rotate::straighten (double deg) { + + degree->setValue (degree->getValue()+deg); + degree->setEditedState (Edited); + if (listener) + listener->panelChanged (EvROTDegree, Glib::ustring::format (std::setw(3), std::fixed, std::setprecision(2), degree->getValue())); +} + +void Rotate::selectStraightPressed () { + + if (rlistener) + rlistener->straightenRequested (); +} + +void Rotate::autoCropPressed () { + + if (rlistener) + rlistener->autoCropRequested (); +} + +void Rotate::fillPressed () { + + if (batchMode) { + if (fill->get_inconsistent()) { + fill->set_inconsistent (false); + fillConn.block (true); + fill->set_active (false); + fillConn.block (false); + } + else if (lastFill) + fill->set_inconsistent (true); + + lastFill = fill->get_active (); + } + + if (listener) { + if (fill->get_active()) + listener->panelChanged (EvROTDegree, M("TP_ROTATE_FILL")+' '+M("GENERAL_ENABLED")); + else + listener->panelChanged (EvROTFill, M("TP_ROTATE_FILL")+' '+M("GENERAL_DISABLED")); + } +} + +void Rotate::setBatchMode (bool batchMode) { + + ToolPanel::setBatchMode (batchMode); + degree->showEditedCB (); + removeIfThere (this, autoCrop); +} + +void Rotate::setAdjusterBehavior (bool brotadd) { + + if (!degAdd && brotadd || degAdd && !brotadd) + degree->setLimits (-45, 45, 0.01, 0); + + degAdd = brotadd; +} diff --git a/rtgui/rotate.h b/rtgui/rotate.h new file mode 100755 index 000000000..17019fcb2 --- /dev/null +++ b/rtgui/rotate.h @@ -0,0 +1,64 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _ROTATE_H_ +#define _ROTATE_H_ + +#include +#include +#include + +class RotateListener { + + public: + virtual void straightenRequested () {} + virtual void autoCropRequested () {} +}; + +class Rotate : public Gtk::VBox, public AdjusterListener, public ToolPanel { + + protected: + Adjuster* degree; + Gtk::Button* selectStraight; + Gtk::Button* autoCrop; + RotateListener* rlistener; + Gtk::CheckButton* fill; + bool degAdd; + bool lastFill; + sigc::connection fillConn; + + public: + + Rotate (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + + void straighten (double deg); + + void adjusterChanged (Adjuster* a, double newval); + void setAdjusterBehavior (bool brotadd); + void selectStraightPressed (); + void fillPressed (); + void autoCropPressed (); + void setRotateListener (RotateListener* l) { rlistener = l; } +}; + +#endif diff --git a/rtgui/rtwindow.cc b/rtgui/rtwindow.cc new file mode 100755 index 000000000..105976157 --- /dev/null +++ b/rtgui/rtwindow.cc @@ -0,0 +1,225 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include + +RTWindow::RTWindow () { + + cacheMgr.init (); + + try { + set_default_icon_from_file (argv0+"/images/logoicon16.png"); + } + catch (Glib::FileError) {} + set_title("Raw Therapee "+versionString); + property_allow_shrink() = true; + set_size_request (1000,600); +// maximize (); + set_modal(false); + set_resizable(true); + property_destroy_with_parent().set_value(false); + + mainNB = Gtk::manage (new Gtk::Notebook ()); + mainNB->set_scrollable (true); + + fpanel = new FilePanel (); + fpanel->setParent (this); + + // decorate tab + Gtk::HBox* hbf = Gtk::manage (new Gtk::HBox ()); + hbf->pack_start (*Gtk::manage (new Gtk::Image (Gtk::Stock::DIRECTORY, Gtk::ICON_SIZE_MENU))); + hbf->pack_start (*Gtk::manage (new Gtk::Label ("File Browser"))); + hbf->set_spacing (2); + hbf->show_all (); + mainNB->append_page (*fpanel, *hbf); + + bpanel = new BatchQueuePanel (); + bpanel->setParent (this); + + // decorate tab + Gtk::HBox* hbb = Gtk::manage (new Gtk::HBox ()); + hbb->pack_start (*Gtk::manage (new Gtk::Image (Gtk::Stock::EXECUTE, Gtk::ICON_SIZE_MENU))); + hbb->pack_start (*Gtk::manage (new Gtk::Label ("Batch Queue"))); + hbb->set_spacing (2); + hbb->show_all (); + mainNB->append_page (*bpanel, *hbb); + + signal_key_press_event().connect( sigc::mem_fun(*this, &RTWindow::keyPressed) ); + + Gtk::VBox* mainBox = Gtk::manage (new Gtk::VBox ()); + mainBox->pack_start (*mainNB); + Gtk::HBox* bottomBox = Gtk::manage (new Gtk::HBox ()); + mainBox->pack_start (*bottomBox, Gtk::PACK_SHRINK, 1); + Gtk::LinkButton* rtWeb = Gtk::manage (new Gtk::LinkButton ("http://rawtherapee.com")); + bottomBox->pack_start (*rtWeb, Gtk::PACK_SHRINK, 1); + Gtk::Button* preferences = Gtk::manage (new Gtk::Button (M("MAIN_BUTTON_PREFERENCES"))); + preferences->set_image (*Gtk::manage(new Gtk::Image (Gtk::StockID("gtk-preferences"), Gtk::ICON_SIZE_BUTTON))); + preferences->set_relief (Gtk::RELIEF_NONE); + preferences->signal_clicked().connect( sigc::mem_fun(*this, &RTWindow::showPreferences) ); + Gtk::Button* exit = Gtk::manage (new Gtk::Button ("Exit")); + exit->set_image (*Gtk::manage(new Gtk::Image (Gtk::StockID("gtk-quit"), Gtk::ICON_SIZE_BUTTON))); + exit->set_relief (Gtk::RELIEF_NONE); + exit->signal_clicked().connect( sigc::mem_fun(*this, &RTWindow::onExit) ); + bottomBox->pack_start (*rtWeb, Gtk::PACK_SHRINK, 1); + bottomBox->pack_end (*exit, Gtk::PACK_SHRINK, 1); + bottomBox->pack_end (*preferences, Gtk::PACK_SHRINK, 8); + Glib::RefPtr style = Gtk::RcStyle::create (); + style->set_xthickness (0); + style->set_ythickness (0); + rtWeb->modify_style (style); + preferences->modify_style (style); + exit->modify_style (style); + + add (*mainBox); + show_all (); +} + +void RTWindow::on_realize () { + + Gtk::Window::on_realize (); + + cursorManager.init (get_window()); +} + +void RTWindow::addEditorPanel (EditorPanel* ep) { + + ep->setParent (this); + + // construct closeable tab for the image + Gtk::HBox* hb = Gtk::manage (new Gtk::HBox ()); + hb->pack_start (*Gtk::manage (new Gtk::Image (Gtk::Stock::FILE, Gtk::ICON_SIZE_MENU))); + hb->pack_start (*Gtk::manage (new Gtk::Label (ep->getShortName ()))); + Gtk::Button* closeb = Gtk::manage (new Gtk::Button ()); + closeb->set_image (*Gtk::manage(new Gtk::Image (Gtk::Stock::CLOSE, Gtk::ICON_SIZE_MENU))); + closeb->set_relief (Gtk::RELIEF_NONE); + closeb->set_focus_on_click (false); + // make the button as small as possible + Glib::RefPtr style = Gtk::RcStyle::create (); + style->set_xthickness (0); + style->set_ythickness (0); + + closeb->modify_style (style); + closeb->signal_clicked().connect( sigc::bind (sigc::mem_fun(*this, &RTWindow::remEditorPanel) , ep)); + hb->pack_end (*closeb); + hb->set_spacing (2); + hb->show_all (); + mainNB->append_page (*ep, *hb); + mainNB->set_current_page (mainNB->page_num (*ep)); + mainNB->set_tab_reorderable (*ep, true); + + epanels[ep->getFileName()] = ep; + filesEdited.insert (ep->getFileName ()); + fpanel->refreshEditedState (filesEdited); +} + +void RTWindow::remEditorPanel (EditorPanel* ep) { + + if (ep->beforeClosing ()) { + ep->saveOptions (); + epanels.erase (ep->getFileName()); + filesEdited.erase (ep->getFileName ()); + fpanel->refreshEditedState (filesEdited); + + mainNB->remove_page (*ep); + } + // TODO: ask what to do: close & apply, close & apply selection, close & revert, cancel +} + +bool RTWindow::keyPressed (GdkEventKey* event) { + + if (mainNB->get_nth_page (mainNB->get_current_page()) == fpanel) { + } +// else if (mainNB->get_nth_page (mainNB->get_current_page()) == bqpanel) { +// } + else { + EditorPanel* ep = (EditorPanel*)mainNB->get_nth_page (mainNB->get_current_page()); + return ep->handleShortcutKey (event); + } + return false; +} + +void RTWindow::imageDeveloped (Glib::ustring fname) { + +// fpanel->refreshThumbnail (fname); +} + +void RTWindow::addBatchQueueJob (BatchQueueEntry* bqe, bool head) { + + bpanel->addBatchQueueJob (bqe, head); + fpanel->queue_draw (); +} + +void RTWindow::onExit () { + + on_delete_event (NULL); +} + +bool RTWindow::on_delete_event(GdkEventAny* event) { + + fpanel->saveOptions (); + bpanel->saveOptions (); + +/* if (fileBrowser->getFileCatalog()->getBatchQueue()->hasJobs()) { + Gtk::MessageDialog msgd (M("MAIN_MSG_EXITJOBSINQUEUEQUEST"), false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO, true); + msgd.set_secondary_text (M("MAIN_MSG_EXITJOBSINQUEUEINFO")); + int response = msgd.run (); + if (response==Gtk::RESPONSE_NO) + return true; + } + + editCoord->close (); + + if (options.startupDir==STARTUPDIR_LAST && fileBrowser->lastSelectedDir ()!="") + options.startupPath = fileBrowser->lastSelectedDir (); + fileBrowser->close (); + cacheMgr.closeCache (); + + options.lastScale = editorPanel->zoomBar->getScale (); + options.lastCropSize = editorPanel->zoomBar->getCropSize (); + if (options.showFilePanelState==0 || options.showFilePanelState==2) + options.fileBrowserHeight = fileBrowser->get_height (); + options.historyPanelWidth = ppaned->get_position (); + options.toolPanelWidth = vboxright->get_width();//hpaned->get_width() - hpaned->get_position (); + options.showHistory = editorPanel->hidehp->get_active (); + options.showInfo = editorPanel->info->get_active (); + options.showClippedHighlights = editorPanel->indclippedh->get_active (); + options.showClippedShadows = editorPanel->indclippeds->get_active (); + options.bgcolor = editorPanel->iarea->imageArea->getBGColor (); + options.lastSaveAsPath = saveAsDialog->getDirectory (); + options.procQueueEnabled = fileBrowser->getFileCatalog()->getBatchQueue()->isEnabled(); + options.fbArrangement = fileBrowser->getFileCatalog()->getArrangement (); + options.firstRun = false; +*/ + Options::save (); + hide(); + return true; +} + +void RTWindow::showPreferences () { + + Preferences *pref = new Preferences (); + pref->run (); + delete pref; + + fpanel->optionsChanged (); +} + + diff --git a/rtgui/rtwindow.h b/rtgui/rtwindow.h new file mode 100755 index 000000000..4bf7c8adb --- /dev/null +++ b/rtgui/rtwindow.h @@ -0,0 +1,54 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _RTWINDOW_ +#define _RTWINDOW_ + +#include +#include +#include +#include +#include + +class RTWindow : public Gtk::Window { + + private: + Gtk::Notebook* mainNB; + FilePanel* fpanel; + BatchQueuePanel* bpanel; + std::set filesEdited; + std::map epanels; + + public: + RTWindow (); + + void addEditorPanel (EditorPanel* ep); + void remEditorPanel (EditorPanel* ep); + + void addBatchQueueJob (BatchQueueEntry* bqe, bool head=false); + + bool keyPressed (GdkEventKey* event); + bool on_delete_event(GdkEventAny* event); + + void imageDeveloped (Glib::ustring fname); // called by the batchqueue when it finishes an image + void showPreferences (); + void onExit (); + void on_realize (); +}; + +#endif diff --git a/rtgui/saveasdlg.cc b/rtgui/saveasdlg.cc new file mode 100755 index 000000000..088eef363 --- /dev/null +++ b/rtgui/saveasdlg.cc @@ -0,0 +1,141 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 "saveasdlg.h" +#include + +extern Options options; +SaveAsDialog::SaveAsDialog (Glib::ustring initialDir) { + + Gtk::VBox* vbox = get_vbox (); + + fchooser = new Gtk::FileChooserWidget (Gtk::FILE_CHOOSER_ACTION_SAVE); + fchooser->set_current_folder (initialDir); + + filter_jpg.set_name(M("SAVEDLG_JPGFILTER")); + filter_jpg.add_pattern("*.jpg"); + + filter_tif.set_name(M("SAVEDLG_JPGFILTER")); + filter_tif.add_pattern("*.tif"); + + filter_png.set_name(M("SAVEDLG_JPGFILTER")); + filter_png.add_pattern("*.png"); + + vbox->pack_start (*fchooser); + + Gtk::HSeparator* hsep1 = new Gtk::HSeparator (); + vbox->pack_start (*hsep1, Gtk::PACK_SHRINK, 2); + +// Output Options +// ~~~~~~~~~~~~~~ + formatOpts = new SaveFormatPanel (); + formatOpts->init (options.saveFormat); + formatOpts->setListener (this); + + vbox->pack_start (*formatOpts, Gtk::PACK_SHRINK, 4); + + Gtk::HSeparator* hsep2 = new Gtk::HSeparator (); + vbox->pack_start (*hsep2, Gtk::PACK_SHRINK, 2); + +// queue/immediate +// ~~~~~~~~~~~~~ + immediately = new Gtk::RadioButton (M("SAVEDLG_SAVEIMMEDIATELY")); + putToQueueHead = new Gtk::RadioButton (M("SAVEDLG_PUTTOQUEUEHEAD")); + putToQueueTail = new Gtk::RadioButton (M("SAVEDLG_PUTTOQUEUETAIL")); + vbox->pack_start (*immediately, Gtk::PACK_SHRINK, 4); + vbox->pack_start (*putToQueueHead, Gtk::PACK_SHRINK, 4); + vbox->pack_start (*putToQueueTail, Gtk::PACK_SHRINK, 4); + immediately->set_active (true); + Gtk::RadioButton::Group g = immediately->get_group(); + putToQueueHead->set_group (g); + putToQueueTail->set_group (g); + +// buttons +// ~~~~~~ + Gtk::Button* ok = new Gtk::Button (M("GENERAL_OK")); + Gtk::Button* cancel = new Gtk::Button (M("GENERAL_CANCEL")); + + ok->set_image (*(new Gtk::Image (Gtk::StockID("gtk-ok"), Gtk::ICON_SIZE_BUTTON))); + cancel->set_image (*(new Gtk::Image (Gtk::StockID("gtk-cancel"), Gtk::ICON_SIZE_BUTTON))); + + ok->signal_clicked().connect( sigc::mem_fun(*this, &SaveAsDialog::okPressed) ); + cancel->signal_clicked().connect( sigc::mem_fun(*this, &SaveAsDialog::cancelPressed) ); + + get_action_area()->pack_end (*ok, Gtk::PACK_SHRINK, 4); + get_action_area()->pack_end (*cancel, Gtk::PACK_SHRINK, 4); + + set_border_width (4); + show_all_children (); +} + +bool SaveAsDialog::getImmediately () { + + return immediately->get_active (); +} + +bool SaveAsDialog::getToHeadOfQueue () { + + return putToQueueHead->get_active (); +} + +bool SaveAsDialog::getToTailOfQueue () { + + return putToQueueTail->get_active (); +} + +Glib::ustring SaveAsDialog::getFileName () { + + return fname; +} + +Glib::ustring SaveAsDialog::getDirectory () { + + return fchooser->get_current_folder (); +} + +SaveFormat SaveAsDialog::getFormat () { + + return formatOpts->getFormat (); +} + +void SaveAsDialog::okPressed () { + + fname = fchooser->get_filename(); + hide (); +} + +void SaveAsDialog::cancelPressed () { + + fname = ""; + hide (); +} + +void SaveAsDialog::formatChanged (Glib::ustring f) { + + if (f=="jpg") + fchooser->set_filter (filter_jpg); + else if (f=="png") + fchooser->set_filter (filter_png); + else if (f=="tif") + fchooser->set_filter (filter_tif); +} + +void SaveAsDialog::setInitialFileName (Glib::ustring fname) { + + fchooser->set_current_name(fname); +} diff --git a/rtgui/saveasdlg.h b/rtgui/saveasdlg.h new file mode 100755 index 000000000..f038bc62a --- /dev/null +++ b/rtgui/saveasdlg.h @@ -0,0 +1,58 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _SAVEASDLG_ +#define _SAVEASDLG_ + +#include +#include +#include +#include + +class SaveAsDialog : public Gtk::Dialog, public FormatChangeListener { + + protected: + Gtk::FileChooserWidget* fchooser; + SaveFormatPanel* formatOpts; + Glib::ustring fname; + Gtk::FileFilter filter_jpg; + Gtk::FileFilter filter_tif; + Gtk::FileFilter filter_png; + Gtk::RadioButton* immediately; + Gtk::RadioButton* putToQueueHead; + Gtk::RadioButton* putToQueueTail; + + public: + SaveAsDialog (Glib::ustring initialDir); + + Glib::ustring getFileName (); + Glib::ustring getDirectory (); + SaveFormat getFormat (); + bool getImmediately (); + bool getToHeadOfQueue (); + bool getToTailOfQueue (); + + void setInitialFileName (Glib::ustring iname); + + void okPressed (); + void cancelPressed (); + void formatChanged (Glib::ustring f); +}; + + +#endif diff --git a/rtgui/saveformatpanel.cc b/rtgui/saveformatpanel.cc new file mode 100755 index 000000000..3c2b0d699 --- /dev/null +++ b/rtgui/saveformatpanel.cc @@ -0,0 +1,132 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include + +SaveFormatPanel::SaveFormatPanel () : listener (NULL) { + + jpegqual = new Adjuster (M("SAVEDLG_JPEGQUAL"), 0, 100, 1, 100); + jpegqual->setAdjusterListener (this); + jpegqual->show (); + pngcompr = new Adjuster (M("SAVEDLG_PNGCOMPR"), 0, 6, 1, 6); + pngcompr->setAdjusterListener (this); + pngcompr->show (); + + Gtk::HBox* hb1 = Gtk::manage (new Gtk::HBox ()); + Gtk::Label* flab = Gtk::manage (new Gtk::Label (M("SAVEDLG_FILEFORMAT")+":")); + hb1->pack_start (*flab, Gtk::PACK_SHRINK,4); + format = Gtk::manage (new Gtk::ComboBoxText ()); + format->append_text ("JPEG (8 bit)"); + format->append_text ("TIFF (8 bit)"); + format->append_text ("TIFF (16 bit)"); + format->append_text ("PNG (8 bit)"); + format->append_text ("PNG (16 bit)"); + format->set_active (0); + oformat = 0; + format->signal_changed().connect( sigc::mem_fun(*this, &SaveFormatPanel::formatChanged) ); + hb1->pack_start (*format); + pack_start (*hb1, Gtk::PACK_SHRINK, 4); + + formatopts = Gtk::manage (new Gtk::VBox ()); + formatopts->pack_start (*jpegqual, Gtk::PACK_SHRINK, 4); + pack_start (*formatopts, Gtk::PACK_SHRINK, 4); + + savespp = Gtk::manage (new Gtk::CheckButton (M("SAVEDLG_SAVESPP"))); + pack_start (*savespp, Gtk::PACK_SHRINK, 4); + + show_all (); + set_border_width (4); + + fstr[0] = "jpg"; + fstr[1] = "tif"; + fstr[2] = "tif"; + fstr[3] = "png"; + fstr[4] = "png"; +} + +void SaveFormatPanel::init (SaveFormat &sf) { + + FormatChangeListener* tmp = listener; + listener = NULL; + + if (sf.format=="jpg") + format->set_active (0); + else if (sf.format=="png" && sf.pngBits==16) + format->set_active (4); + else if (sf.format=="png" && sf.pngBits==8) + format->set_active (3); + else if (sf.format=="tif" && sf.tiffBits==16) + format->set_active (2); + else if (sf.format=="tif" && sf.tiffBits==8) + format->set_active (1); + + pngcompr->setValue (sf.pngCompression); + jpegqual->setValue (sf.jpegQuality); + savespp->set_active (sf.saveParams); + listener = tmp; +} + +SaveFormat SaveFormatPanel::getFormat () { + + SaveFormat sf; + + int sel = format->get_active_row_number(); + sf.format = fstr[sel]; + if (sel==4) + sf.pngBits = 16; + else + sf.pngBits = 8; + if (sel==2) + sf.tiffBits = 16; + else + sf.tiffBits = 8; + sf.pngCompression = (int) pngcompr->getValue (); + sf.jpegQuality = (int) jpegqual->getValue (); + sf.saveParams = savespp->get_active (); + return sf; +} + +void SaveFormatPanel::formatChanged () { + + if (oformat==0) + removeIfThere (formatopts, jpegqual); + else if (oformat==3 || oformat==4) + removeIfThere (formatopts, pngcompr); + + int act = format->get_active_row_number(); + if (act<0 || act>4) + return; + + Glib::ustring fr = fstr[act]; + if (fr=="jpg") + formatopts->pack_start (*jpegqual, Gtk::PACK_SHRINK,4); + else if (fr=="png") + formatopts->pack_start (*pngcompr, Gtk::PACK_SHRINK,4); + + oformat = act; + + if (listener) + listener->formatChanged (fr); +} + +void SaveFormatPanel::adjusterChanged (Adjuster* a, double newval) { + + formatChanged (); +} diff --git a/rtgui/saveformatpanel.h b/rtgui/saveformatpanel.h new file mode 100755 index 000000000..2add74c45 --- /dev/null +++ b/rtgui/saveformatpanel.h @@ -0,0 +1,58 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef __SAVEFORMATPANEL_H__ +#define __SAVEFORMATPANEL_H__ + +#include +#include +#include + +class FormatChangeListener { + + public: + virtual void formatChanged (Glib::ustring f) {} + +}; + +class SaveFormatPanel : public Gtk::VBox, public AdjusterListener { + + protected: + Adjuster* jpegqual; + Adjuster* pngcompr; + Gtk::ComboBoxText* format; + Gtk::VBox* formatopts; + int oformat; + FormatChangeListener* listener; + Glib::ustring fstr[5]; + Gtk::CheckButton* savespp; + + + public: + + SaveFormatPanel (); + void setListener (FormatChangeListener* l) { listener = l; } + + void init (SaveFormat& sf); + SaveFormat getFormat (); + + void formatChanged (); + void adjusterChanged (Adjuster* a, double newval); +}; + +#endif diff --git a/rtgui/shadowshighlights.cc b/rtgui/shadowshighlights.cc new file mode 100755 index 000000000..bb1700453 --- /dev/null +++ b/rtgui/shadowshighlights.cc @@ -0,0 +1,254 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +using namespace rtengine; +using namespace rtengine::procparams; + +ShadowsHighlights::ShadowsHighlights () : ToolPanel() { + + enabled = Gtk::manage (new Gtk::CheckButton (M("GENERAL_ENABLED"))); + enabled->set_active (false); + pack_start (*enabled); + enaConn = enabled->signal_toggled().connect( sigc::mem_fun(*this, &ShadowsHighlights::enabledChanged) ); + + pack_start (*Gtk::manage (new Gtk::HSeparator())); + + hq = Gtk::manage (new Gtk::CheckButton ("High Quality")); + hq->set_active (false); + pack_start (*hq); + hqConn = hq->signal_toggled().connect( sigc::mem_fun(*this, &ShadowsHighlights::hqChanged) ); + + pack_start (*Gtk::manage (new Gtk::HSeparator())); + highlights = Gtk::manage (new Adjuster (M("TP_SHADOWSHLIGHTS_HIGHLIGHTS"), 0, 100, 1, 0)); + h_tonalwidth = Gtk::manage (new Adjuster (M("TP_SHADOWSHLIGHTS_HLTONALW"), 10, 100, 1, 80)); + pack_start (*highlights); + pack_start (*h_tonalwidth); + + pack_start (*Gtk::manage (new Gtk::HSeparator())); + + shadows = Gtk::manage (new Adjuster (M("TP_SHADOWSHLIGHTS_SHADOWS"), 0, 100, 1, 0)); + s_tonalwidth = Gtk::manage (new Adjuster (M("TP_SHADOWSHLIGHTS_SHTONALW"), 10, 100, 1, 80)); + pack_start (*shadows); + pack_start (*s_tonalwidth); + + pack_start (*Gtk::manage (new Gtk::HSeparator())); + + lcontrast = Gtk::manage (new Adjuster (M("TP_SHADOWSHLIGHTS_LOCALCONTR"), 0, 100, 1, 0)); + pack_start (*lcontrast); + + pack_start (*Gtk::manage (new Gtk::HSeparator())); + + radius = Gtk::manage (new Adjuster (M("TP_SHADOWSHLIGHTS_RADIUS"), 5, 100, 1, 30)); + pack_start (*radius); + + radius->setAdjusterListener (this); + highlights->setAdjusterListener (this); + h_tonalwidth->setAdjusterListener (this); + shadows->setAdjusterListener (this); + s_tonalwidth->setAdjusterListener (this); + lcontrast->setAdjusterListener (this); + + show_all_children (); +} + +void ShadowsHighlights::read (const ProcParams* pp, const ParamsEdited* pedited) { + + disableListener (); + + if (pedited) { + radius->setEditedState (pedited->sh.radius ? Edited : UnEdited); + lcontrast->setEditedState (pedited->sh.localcontrast ? Edited : UnEdited); + highlights->setEditedState (pedited->sh.highlights ? Edited : UnEdited); + h_tonalwidth->setEditedState (pedited->sh.htonalwidth ? Edited : UnEdited); + shadows->setEditedState (pedited->sh.shadows ? Edited : UnEdited); + s_tonalwidth->setEditedState (pedited->sh.stonalwidth ? Edited : UnEdited); + enabled->set_inconsistent (!pedited->sh.enabled); + hq->set_inconsistent (!pedited->sh.hq); + } + + enaConn.block (true); + enabled->set_active (pp->sh.enabled); + enaConn.block (false); + hqConn.block (true); + hq->set_active (pp->sh.hq); + hqConn.block (false); + + lastEnabled = pp->sh.enabled; + lastHQ = pp->sh.hq; + + radius->setValue (pp->sh.radius); + lcontrast->setValue (pp->sh.localcontrast); + highlights->setValue (pp->sh.highlights); + h_tonalwidth->setValue (pp->sh.htonalwidth); + shadows->setValue (pp->sh.shadows); + s_tonalwidth->setValue (pp->sh.stonalwidth); + + enableListener (); +} + +void ShadowsHighlights::write (ProcParams* pp, ParamsEdited* pedited) { + + pp->sh.radius = (int)radius->getValue (); + pp->sh.localcontrast = (int)lcontrast->getValue (); + pp->sh.highlights = (int)highlights->getValue (); + pp->sh.htonalwidth = (int)h_tonalwidth->getValue (); + pp->sh.shadows = (int)shadows->getValue (); + pp->sh.stonalwidth = (int)s_tonalwidth->getValue (); + pp->sh.enabled = enabled->get_active(); + pp->sh.hq = hq->get_active(); + + if (pedited) { + pedited->sh.radius = radius->getEditedState (); + pedited->sh.localcontrast = lcontrast->getEditedState (); + pedited->sh.highlights = highlights->getEditedState (); + pedited->sh.htonalwidth = h_tonalwidth->getEditedState (); + pedited->sh.shadows = shadows->getEditedState (); + pedited->sh.stonalwidth = s_tonalwidth->getEditedState (); + pedited->sh.enabled = !enabled->get_inconsistent(); + pedited->sh.hq = !hq->get_inconsistent(); + } +} + +void ShadowsHighlights::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { + + radius->setDefault (defParams->sh.radius); + lcontrast->setDefault (defParams->sh.localcontrast); + highlights->setDefault (defParams->sh.highlights); + h_tonalwidth->setDefault (defParams->sh.htonalwidth); + shadows->setDefault (defParams->sh.shadows); + s_tonalwidth->setDefault (defParams->sh.stonalwidth); + + if (pedited) { + radius->setDefaultEditedState (pedited->sh.radius ? Edited : UnEdited); + lcontrast->setDefaultEditedState (pedited->sh.localcontrast ? Edited : UnEdited); + highlights->setDefaultEditedState (pedited->sh.highlights ? Edited : UnEdited); + h_tonalwidth->setDefaultEditedState (pedited->sh.htonalwidth ? Edited : UnEdited); + shadows->setDefaultEditedState (pedited->sh.shadows ? Edited : UnEdited); + s_tonalwidth->setDefaultEditedState (pedited->sh.stonalwidth ? Edited : UnEdited); + } + else { + radius->setDefaultEditedState (Irrelevant); + lcontrast->setDefaultEditedState (Irrelevant); + highlights->setDefaultEditedState (Irrelevant); + h_tonalwidth->setDefaultEditedState (Irrelevant); + shadows->setDefaultEditedState (Irrelevant); + s_tonalwidth->setDefaultEditedState (Irrelevant); + } +} + +void ShadowsHighlights::adjusterChanged (Adjuster* a, double newval) { + + if (listener && enabled->get_active()) { + + Glib::ustring costr = Glib::ustring::format ((int)a->getValue()); + + if (a==highlights) + listener->panelChanged (EvSHHighlights, costr); + else if (a==h_tonalwidth) + listener->panelChanged (EvSHHLTonalW, costr); + else if (a==shadows) + listener->panelChanged (EvSHShadows, costr); + else if (a==s_tonalwidth) + listener->panelChanged (EvSHSHTonalW, costr); + else if (a==radius) + listener->panelChanged (EvSHRadius, costr); + else if (a==lcontrast) + listener->panelChanged (EvSHLContrast, costr); + } +} + +void ShadowsHighlights::enabledChanged () { + + if (batchMode) { + if (enabled->get_inconsistent()) { + enabled->set_inconsistent (false); + enaConn.block (true); + enabled->set_active (false); + enaConn.block (false); + } + else if (lastEnabled) + enabled->set_inconsistent (true); + + lastEnabled = enabled->get_active (); + } + + if (listener) { + if (enabled->get_active()) + listener->panelChanged (EvSHEnabled, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvSHEnabled, M("GENERAL_DISABLED")); + } +} + +void ShadowsHighlights::hqChanged () { + + if (batchMode) { + if (hq->get_inconsistent()) { + hq->set_inconsistent (false); + hqConn.block (true); + hq->set_active (false); + hqConn.block (false); + } + else if (lastHQ) + hq->set_inconsistent (true); + + lastHQ = hq->get_active (); + } + + if (listener) { + if (hq->get_active()) + listener->panelChanged (EvSHHighQuality, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvSHHighQuality, M("GENERAL_DISABLED")); + } +} + +void ShadowsHighlights::setBatchMode (bool batchMode) { + + ToolPanel::setBatchMode (batchMode); + radius->showEditedCB (); + lcontrast->showEditedCB (); + highlights->showEditedCB (); + h_tonalwidth->showEditedCB (); + shadows->showEditedCB (); + s_tonalwidth->showEditedCB (); +} + +void ShadowsHighlights::setAdjusterBehavior (bool hadd, bool sadd, bool lcadd) { + + if (!hAdd && hadd) + highlights->setLimits (-100, 100, 1, 0); + else if (hAdd && !hadd) + highlights->setLimits (0, 100, 1, 0); + + if (!sAdd && sadd) + shadows->setLimits (-100, 100, 1, 0); + else if (sAdd && !sadd) + shadows->setLimits (0, 100, 1, 0); + + if (!lcAdd && lcadd) + lcontrast->setLimits (-100, 100, 1, 0); + else if (lcAdd && !lcadd) + lcontrast->setLimits (0, 100, 1, 0); + + hAdd = hadd; + sAdd = sadd; + lcAdd = lcadd; +} diff --git a/rtgui/shadowshighlights.h b/rtgui/shadowshighlights.h new file mode 100755 index 000000000..c65ebea05 --- /dev/null +++ b/rtgui/shadowshighlights.h @@ -0,0 +1,57 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _SHADOWSHIGHLIGHTS_H_ +#define _SHADOWSHIGHLIGHTS_H_ + +#include +#include +#include + +class ShadowsHighlights : public Gtk::VBox, public AdjusterListener, public ToolPanel { + + protected: + Adjuster* highlights; + Adjuster* h_tonalwidth; + Adjuster* shadows; + Adjuster* s_tonalwidth; + Adjuster* lcontrast; + Adjuster* radius; + Gtk::CheckButton* enabled; + Gtk::CheckButton* hq; + bool hAdd, sAdd, lcAdd; + bool lastEnabled, lastHQ; + sigc::connection enaConn, hqConn; + + public: + + ShadowsHighlights (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + + void adjusterChanged (Adjuster* a, double newval); + void enabledChanged (); + void hqChanged (); + + void setAdjusterBehavior (bool hadd, bool sadd, bool lcadd); +}; + +#endif diff --git a/rtgui/sharpening.cc b/rtgui/sharpening.cc new file mode 100755 index 000000000..805d9efaf --- /dev/null +++ b/rtgui/sharpening.cc @@ -0,0 +1,461 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include + +using namespace rtengine; +using namespace rtengine::procparams; + +Sharpening::Sharpening () : ToolPanel () { + + enabled = Gtk::manage (new Gtk::CheckButton (M("GENERAL_ENABLED"))); + enabled->set_active (true); + pack_start(*enabled); + enabled->show (); + Gtk::HSeparator *hsep6aa = Gtk::manage (new Gtk::HSeparator()); + pack_start(*hsep6aa, Gtk::PACK_SHRINK, 2); + hsep6aa->show (); + + Gtk::HBox* hb = Gtk::manage (new Gtk::HBox ()); + hb->set_border_width (4); + hb->show (); + Gtk::Label* ml = Gtk::manage (new Gtk::Label (M("TP_SHARPENING_METHOD")+":")); + ml->show (); + method = Gtk::manage (new Gtk::ComboBoxText ()); + method->append_text (M("TP_SHARPENING_USM")); + method->append_text (M("TP_SHARPENING_RLD")); + method->show (); + hb->pack_start(*ml, Gtk::PACK_SHRINK, 4); + hb->pack_start(*method); + pack_start (*hb); + + rld = new Gtk::VBox (); + dradius = Gtk::manage (new Adjuster (M("TP_SHARPENING_EDRADIUS"), 0.5, 2.5, 0.01, 0.75)); + damount = Gtk::manage (new Adjuster (M("TP_SHARPENING_RLD_AMOUNT"), 0.0, 100, 1, 75)); + ddamping = Gtk::manage (new Adjuster (M("TP_SHARPENING_RLD_DAMPING"), 0, 100, 1, 20)); + diter = Gtk::manage (new Adjuster (M("TP_SHARPENING_RLD_ITERATIONS"), 5, 100, 1, 30)); + rld->pack_start (*dradius); + rld->pack_start (*damount); + rld->pack_start (*ddamping); + rld->pack_start (*diter); + dradius->show (); + damount->show (); + ddamping->show (); + diter->show (); + rld->show (); + + usm = new Gtk::VBox (); + usm->show (); + + + Gtk::HSeparator *hsep6a = Gtk::manage (new Gtk::HSeparator()); + amount = Gtk::manage (new Adjuster (M("TP_SHARPENING_AMOUNT"), 1, 1000, 1, 150)); + radius = Gtk::manage (new Adjuster (M("TP_SHARPENING_RADIUS"), 0.3, 3, 0.01, 0.8)); + threshold = Gtk::manage (new Adjuster (M("TP_SHARPENING_THRESHOLD"), 0, 16384, 1024, 1)); + pack_start(*hsep6a, Gtk::PACK_SHRINK, 2); + + pack_start (*usm); + + usm->pack_start(*radius); + usm->pack_start(*amount); + usm->pack_start(*threshold); + hsep6a->show (); + radius->show (); + amount->show (); + threshold->show (); + + Gtk::HSeparator *hsep6 = Gtk::manage (new Gtk::HSeparator()); + edgesonly = Gtk::manage (new Gtk::CheckButton (M("TP_SHARPENING_ONLYEDGES"))); + edgesonly->set_active (false); + edgebox = new Gtk::VBox (); + eradius = Gtk::manage (new Adjuster (M("TP_SHARPENING_EDRADIUS"), 0.5, 2.5, 0.1, 1.9)); + etolerance = Gtk::manage (new Adjuster (M("TP_SHARPENING_EDTOLERANCE"), 10, 10000, 100, 1000)); + usm->pack_start(*hsep6, Gtk::PACK_SHRINK, 2); + usm->pack_start(*edgesonly); + edgebox->pack_start(*eradius); + edgebox->pack_start(*etolerance); + edgebox->show (); + edgebin = Gtk::manage (new Gtk::VBox ()); + usm->pack_start (*edgebin); + edgebin->show (); + hsep6->show(); + edgesonly->show(); + eradius->show(); + etolerance->show(); + + Gtk::HSeparator *hsep6b = Gtk::manage (new Gtk::HSeparator()); + halocontrol = Gtk::manage (new Gtk::CheckButton (M("TP_SHARPENING_HALOCONTROL"))); + halocontrol->set_active (false); + hcbox = new Gtk::VBox (); + hcamount = Gtk::manage (new Adjuster (M("TP_SHARPENING_HCAMOUNT"), 1, 100, 1, 75)); + usm->pack_start(*hsep6b, Gtk::PACK_SHRINK, 2); + usm->pack_start(*halocontrol); + hcbox->pack_start(*hcamount); + hcbox->show (); + hcbin = Gtk::manage (new Gtk::VBox ()); + usm->pack_start (*hcbin); + hcbin->show (); + hsep6b->show (); + halocontrol->show (); + hcamount->show (); + + dradius->setAdjusterListener (this); + damount->setAdjusterListener (this); + ddamping->setAdjusterListener (this); + diter->setAdjusterListener (this); + radius->setAdjusterListener (this); + amount->setAdjusterListener (this); + threshold->setAdjusterListener (this); + eradius->setAdjusterListener (this); + etolerance->setAdjusterListener (this); + hcamount->setAdjusterListener (this); + + edgebox->reference (); + hcbox->reference (); + usm->reference (); + rld->reference (); + + enaConn = enabled->signal_toggled().connect( sigc::mem_fun(*this, &Sharpening::enabled_toggled) ); + eonlyConn = edgesonly->signal_toggled().connect( sigc::mem_fun(*this, &Sharpening::edgesonly_toggled) ); + hcConn = halocontrol->signal_toggled().connect( sigc::mem_fun(*this, &Sharpening::halocontrol_toggled) ); + method->signal_changed().connect( sigc::mem_fun(*this, &Sharpening::method_changed) ); +} + +Sharpening::~Sharpening () { + + delete usm; + delete rld; + delete edgebox; + delete hcbox; +} + + +void Sharpening::read (const ProcParams* pp, const ParamsEdited* pedited) { + + disableListener (); + + if (pedited) { + amount->setEditedState (pedited->sharpening.amount ? Edited : UnEdited); + radius->setEditedState (pedited->sharpening.radius ? Edited : UnEdited); + threshold->setEditedState (pedited->sharpening.threshold ? Edited : UnEdited); + eradius->setEditedState (pedited->sharpening.edges_radius ? Edited : UnEdited); + etolerance->setEditedState (pedited->sharpening.edges_tolerance ? Edited : UnEdited); + hcamount->setEditedState (pedited->sharpening.halocontrol_amount ? Edited : UnEdited); + damount->setEditedState (pedited->sharpening.deconvamount ? Edited : UnEdited); + dradius->setEditedState (pedited->sharpening.deconvradius ? Edited : UnEdited); + diter->setEditedState (pedited->sharpening.deconviter ? Edited : UnEdited); + ddamping->setEditedState (pedited->sharpening.deconvdamping ? Edited : UnEdited); + + enabled->set_inconsistent (!pedited->sharpening.enabled); + halocontrol->set_inconsistent (!pedited->sharpening.halocontrol); + edgesonly->set_inconsistent (!pedited->sharpening.edgesonly); + } + + enaConn.block (true); + enabled->set_active (pp->sharpening.enabled); + enaConn.block (false); + lastEnabled = pp->sharpening.enabled; + + eonlyConn.block (true); + edgesonly->set_active (pp->sharpening.edgesonly); + eonlyConn.block (false); + lastEdgesOnly = pp->sharpening.edgesonly; + + hcConn.block (true); + halocontrol->set_active (pp->sharpening.halocontrol); + hcConn.block (false); + lastHaloControl = pp->sharpening.halocontrol; + + amount->setValue (pp->sharpening.amount); + radius->setValue (pp->sharpening.radius); + threshold->setValue (pp->sharpening.threshold); + eradius->setValue (pp->sharpening.edges_radius); + etolerance->setValue (pp->sharpening.edges_tolerance); + hcamount->setValue (pp->sharpening.halocontrol_amount); + + dradius->setValue (pp->sharpening.deconvradius); + damount->setValue (pp->sharpening.deconvamount); + diter->setValue (pp->sharpening.deconviter); + ddamping->setValue (pp->sharpening.deconvdamping); + + if (!batchMode) { + removeIfThere (edgebin, edgebox, false); + if (edgesonly->get_active ()) + edgebin->pack_start (*edgebox); + + removeIfThere (hcbin, hcbox, false); + if (halocontrol->get_active ()) + hcbin->pack_start (*hcbox); + + } + if (pedited && !pedited->sharpening.method) + method->set_active (2); + else if (pp->sharpening.method=="usm") + method->set_active (0); + else if (pp->sharpening.method=="rld") + method->set_active (1); + + enableListener (); +} + +void Sharpening::write (ProcParams* pp, ParamsEdited* pedited) { + + pp->sharpening.amount = (int)amount->getValue(); + pp->sharpening.enabled = enabled->get_active (); + pp->sharpening.radius = radius->getValue (); + pp->sharpening.threshold = (int)threshold->getValue (); + pp->sharpening.edgesonly = edgesonly->get_active (); + pp->sharpening.edges_radius = eradius->getValue (); + pp->sharpening.edges_tolerance = (int)etolerance->getValue (); + pp->sharpening.halocontrol = halocontrol->get_active (); + pp->sharpening.halocontrol_amount = (int)hcamount->getValue (); + pp->sharpening.deconvradius = dradius->getValue (); + pp->sharpening.deconviter = (int)diter->getValue (); + pp->sharpening.deconvamount = (int)damount->getValue (); + pp->sharpening.deconvdamping = (int)ddamping->getValue (); + + if (method->get_active_row_number()==0) + pp->sharpening.method = "usm"; + else if (method->get_active_row_number()==1) + pp->sharpening.method = "rld"; + + if (pedited) { + pedited->sharpening.amount = amount->getEditedState (); + pedited->sharpening.radius = radius->getEditedState (); + pedited->sharpening.threshold = threshold->getEditedState (); + pedited->sharpening.edges_radius = eradius->getEditedState (); + pedited->sharpening.edges_tolerance = etolerance->getEditedState (); + pedited->sharpening.halocontrol_amount = hcamount->getEditedState (); + pedited->sharpening.deconvamount = damount->getEditedState (); + pedited->sharpening.deconvradius = dradius->getEditedState (); + pedited->sharpening.deconviter = diter->getEditedState (); + pedited->sharpening.deconvdamping = ddamping->getEditedState (); + pedited->sharpening.method = method->get_active_row_number()!=2; + pedited->sharpening.halocontrol = !halocontrol->get_inconsistent(); + pedited->sharpening.edgesonly = !edgesonly->get_inconsistent(); + pedited->sharpening.enabled = !enabled->get_inconsistent(); + } +} + +void Sharpening::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { + + amount->setDefault (defParams->sharpening.amount); + radius->setDefault (defParams->sharpening.radius); + threshold->setDefault (defParams->sharpening.threshold); + eradius->setDefault (defParams->sharpening.edges_radius); + etolerance->setDefault (defParams->sharpening.edges_tolerance); + hcamount->setDefault (defParams->sharpening.halocontrol_amount); + damount->setDefault (defParams->sharpening.deconvamount); + dradius->setDefault (defParams->sharpening.deconvradius); + diter->setDefault (defParams->sharpening.deconviter); + ddamping->setDefault (defParams->sharpening.deconvdamping); + + if (pedited) { + amount->setDefaultEditedState (pedited->sharpening.amount ? Edited : UnEdited); + radius->setDefaultEditedState (pedited->sharpening.radius ? Edited : UnEdited); + threshold->setDefaultEditedState (pedited->sharpening.threshold ? Edited : UnEdited); + eradius->setDefaultEditedState (pedited->sharpening.edges_radius ? Edited : UnEdited); + etolerance->setDefaultEditedState (pedited->sharpening.edges_tolerance ? Edited : UnEdited); + hcamount->setDefaultEditedState (pedited->sharpening.halocontrol_amount ? Edited : UnEdited); + damount->setDefaultEditedState (pedited->sharpening.deconvamount ? Edited : UnEdited); + dradius->setDefaultEditedState (pedited->sharpening.deconvradius ? Edited : UnEdited); + diter->setDefaultEditedState (pedited->sharpening.deconviter ? Edited : UnEdited); + ddamping->setDefaultEditedState (pedited->sharpening.deconvdamping ? Edited : UnEdited); + } + else { + amount->setDefaultEditedState (Irrelevant); + radius->setDefaultEditedState (Irrelevant); + threshold->setDefaultEditedState (Irrelevant); + eradius->setDefaultEditedState (Irrelevant); + etolerance->setDefaultEditedState (Irrelevant); + hcamount->setDefaultEditedState (Irrelevant); + damount->setDefaultEditedState (Irrelevant); + dradius->setDefaultEditedState (Irrelevant); + diter->setDefaultEditedState (Irrelevant); + ddamping->setDefaultEditedState (Irrelevant); + } +} + +void Sharpening::adjusterChanged (Adjuster* a, double newval) { + + if (listener && enabled->get_active()) { + + Glib::ustring costr; + if (a==radius || a==dradius) + costr = Glib::ustring::format (std::setw(3), std::fixed, std::setprecision(2), a->getValue()); + else if (a==eradius) + costr = Glib::ustring::format (std::setw(2), std::fixed, std::setprecision(1), a->getValue()); + else + costr = Glib::ustring::format ((int)a->getValue()); + + if (a==amount) + listener->panelChanged (EvShrAmount, costr); + else if (a==radius) + listener->panelChanged (EvShrRadius, costr); + else if (a==threshold) + listener->panelChanged (EvShrThresh, costr); + else if (a==eradius) + listener->panelChanged (EvShrEdgeRadius, costr); + else if (a==etolerance) + listener->panelChanged (EvShrEdgeTolerance, costr); + else if (a==hcamount) + listener->panelChanged (EvShrHaloAmount, costr); + else if (a==dradius) + listener->panelChanged (EvShrDRadius, costr); + else if (a==damount) + listener->panelChanged (EvShrDAmount, costr); + else if (a==ddamping) + listener->panelChanged (EvShrDDamping, costr); + else if (a==diter) + listener->panelChanged (EvShrDIterations, costr); + } +} + +void Sharpening::enabled_toggled () { + + if (batchMode) { + if (enabled->get_inconsistent()) { + enabled->set_inconsistent (false); + enaConn.block (true); + enabled->set_active (false); + enaConn.block (false); + } + else if (lastEnabled) + enabled->set_inconsistent (true); + + lastEnabled = enabled->get_active (); + } + + if (listener) { + if (enabled->get_active ()) + listener->panelChanged (EvShrEnabled, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvShrEnabled, M("GENERAL_DISABLED")); + } +} + +void Sharpening::edgesonly_toggled () { + + if (batchMode) { + if (edgesonly->get_inconsistent()) { + edgesonly->set_inconsistent (false); + eonlyConn.block (true); + edgesonly->set_active (false); + eonlyConn.block (false); + } + else if (lastEdgesOnly) + edgesonly->set_inconsistent (true); + + lastEdgesOnly = edgesonly->get_active (); + } + + if (!batchMode) { + removeIfThere (edgebin, edgebox, false); + if (edgesonly->get_active ()) + edgebin->pack_start (*edgebox); + } + + if (listener && enabled->get_active()) { + if (edgesonly->get_active ()) + listener->panelChanged (EvShrEdgeOnly, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvShrEdgeOnly, M("GENERAL_DISABLED")); + } +} + +void Sharpening::halocontrol_toggled () { + + if (batchMode) { + if (halocontrol->get_inconsistent()) { + halocontrol->set_inconsistent (false); + hcConn.block (true); + halocontrol->set_active (false); + hcConn.block (false); + } + else if (lastHaloControl) + halocontrol->set_inconsistent (true); + + lastHaloControl = halocontrol->get_active (); + } + + if (!batchMode) { + removeIfThere (hcbin, hcbox, false); + if (halocontrol->get_active ()) + hcbin->pack_start (*hcbox); + } + + if (listener && enabled->get_active()) { + if (halocontrol->get_active ()) + listener->panelChanged (EvShrHaloControl, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvShrHaloControl, M("GENERAL_DISABLED")); + } +} + +void Sharpening::method_changed () { + + removeIfThere (this, usm, false); + removeIfThere (this, rld, false); + + if (method->get_active_row_number()==0) + pack_start (*usm); + else if (method->get_active_row_number()==1) + pack_start (*rld); + + if (listener && enabled->get_active ()) + listener->panelChanged (EvShrMethod, method->get_active_text ()); + +} + +void Sharpening::setBatchMode (bool batchMode) { + + ToolPanel::setBatchMode (batchMode); + + removeIfThere (hcbin, hcbox, false); + hcbin->pack_start (*hcbox); + removeIfThere (edgebin, edgebox, false); + edgebin->pack_start (*edgebox); + + radius->showEditedCB (); + amount->showEditedCB (); + threshold->showEditedCB (); + eradius->showEditedCB (); + etolerance->showEditedCB (); + hcamount->showEditedCB (); + dradius->showEditedCB (); + damount->showEditedCB (); + ddamping->showEditedCB (); + diter->showEditedCB (); + method->append_text ("(Unchanged)"); +} + +void Sharpening::setAdjusterBehavior (bool bamountadd) { + + if (!amountAdd && bamountadd) { + amount->setLimits (-100, 100, 1, 0); + damount->setLimits (-100, 100, 1, 0); + } + else if (amountAdd && !bamountadd) { + amount->setLimits (1, 1000, 1, 150); + damount->setLimits (0, 100, 1, 75); + } + amountAdd = bamountadd; +} diff --git a/rtgui/sharpening.h b/rtgui/sharpening.h new file mode 100755 index 000000000..cb3ad2a43 --- /dev/null +++ b/rtgui/sharpening.h @@ -0,0 +1,79 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _SHARPENING_H_ +#define _SHARPENING_H_ + +#include +#include +#include + +class Sharpening : public Gtk::VBox, public AdjusterListener, public ToolPanel { + + protected: + Gtk::ComboBoxText* method; + Adjuster* dradius; + Adjuster* damount; + Adjuster* ddamping; + Adjuster* diter; + Gtk::VBox* usm; + Gtk::VBox* rld; + + Adjuster* radius; + Adjuster* amount; + Adjuster* threshold; + Adjuster* eradius; + Adjuster* etolerance; + Adjuster* hcamount; + Gtk::VBox* edgebin; + Gtk::VBox* hcbin; + Gtk::VBox* edgebox; + Gtk::VBox* hcbox; + Gtk::CheckButton* enabled; + bool lastEnabled; + sigc::connection enaConn; + Gtk::CheckButton* edgesonly; + bool lastEdgesOnly; + sigc::connection eonlyConn; + Gtk::CheckButton* halocontrol; + bool lastHaloControl; + sigc::connection hcConn; + bool amountAdd; + + + + public: + + Sharpening (); + virtual ~Sharpening (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + + void adjusterChanged (Adjuster* a, double newval); + void enabled_toggled (); + void edgesonly_toggled (); + void halocontrol_toggled (); + void method_changed (); + + void setAdjusterBehavior (bool bamountadd); +}; + +#endif diff --git a/rtgui/splash.cc b/rtgui/splash.cc new file mode 100755 index 000000000..300bb27b1 --- /dev/null +++ b/rtgui/splash.cc @@ -0,0 +1,97 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +extern Glib::ustring argv0; +extern Glib::ustring versionString; + +SplashImage::SplashImage () { + + pixbuf = Gdk::Pixbuf::create_from_file (argv0+"/images/splash.png"); + set_size_request (pixbuf->get_width(), pixbuf->get_height()); +} + +void SplashImage::on_realize () { + + Gtk::DrawingArea::on_realize(); + add_events(Gdk::EXPOSURE_MASK); + + gc_ = Gdk::GC::create (get_window()); + Glib::RefPtr colormap = get_default_colormap(); + Gdk::Color fontc = Gdk::Color ("white"); + colormap->alloc_color (fontc); + gc_->set_foreground (fontc); + +} + +bool SplashImage::on_expose_event (GdkEventExpose* event) { + + Glib::RefPtr window = get_window(); + pixbuf->render_to_drawable (window, gc_, 0, 0, 0, 0, pixbuf->get_width(), pixbuf->get_height(), Gdk::RGB_DITHER_NONE, 0, 0); + + Cairo::FontOptions cfo; + cfo.set_antialias (Cairo::ANTIALIAS_SUBPIXEL); + Glib::RefPtr context = get_pango_context () ; + context->set_cairo_font_options (cfo); + Pango::FontDescription fontd = context->get_font_description (); + fontd.set_weight (Pango::WEIGHT_SEMIBOLD); + fontd.set_size (12*Pango::SCALE); + context->set_font_description (fontd); + + version = create_pango_layout (versionString); + int w, h; + version->get_pixel_size (w, h); + window->draw_layout(gc_, pixbuf->get_width() - w - 28, 44-h, version); + + return true; +} + +Splash::Splash (int maxtime) { + + set_title (M("GENERAL_ABOUT")); + + splashImage = new SplashImage (); +// add (*splashImage); + get_vbox()->pack_start (*splashImage); + set_has_separator (false); + splashImage->show (); + + if (maxtime>0) + Glib::signal_timeout().connect (sigc::mem_fun(*this, &Splash::on_timer), maxtime); + set_position (Gtk::WIN_POS_CENTER); + if (maxtime>0) + set_decorated (false); + add_events(Gdk::BUTTON_RELEASE_MASK); + set_resizable (false); + + set_keep_above (true); +} + +bool Splash::on_timer () { + + hide (); + return false; +} + +bool Splash::on_button_release_event (GdkEventButton* event) { + + hide (); + return true; +} diff --git a/rtgui/splash.h b/rtgui/splash.h new file mode 100755 index 000000000..b8c1b38af --- /dev/null +++ b/rtgui/splash.h @@ -0,0 +1,50 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef __SPLASH__ +#define __SPLASH__ + +#include + +class SplashImage : public Gtk::DrawingArea { + + private: + Glib::RefPtr gc_; + Glib::RefPtr pixbuf; + Glib::RefPtr version; + + public: + SplashImage (); + void on_realize (); + bool on_expose_event (GdkEventExpose* event); +}; + +//class Splash : public Gtk::Window { +class Splash : public Gtk::Dialog { + + private: + SplashImage* splashImage; + + public: + Splash (int maxtime); + + bool on_timer (); + virtual bool on_button_release_event (GdkEventButton* event); +}; + +#endif diff --git a/rtgui/thumbbrowserbase.cc b/rtgui/thumbbrowserbase.cc new file mode 100755 index 000000000..4bf43c556 --- /dev/null +++ b/rtgui/thumbbrowserbase.cc @@ -0,0 +1,545 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include +#include + +ThumbBrowserBase::ThumbBrowserBase () + : previewHeight(options.thumbSize), lastClicked(NULL) { + + inW = -1; inH = -1; + + Gtk::HBox* hb1 = new Gtk::HBox (); + Gtk::HBox* hb2 = new Gtk::HBox (); + Gtk::Frame* frame = new Gtk::Frame (); + frame->add (internal); + frame->set_shadow_type (Gtk::SHADOW_IN ); + hb1->pack_start (*frame); + hb1->pack_end (vscroll, Gtk::PACK_SHRINK, 0); + + pack_start (*hb1); + + Gtk::HBox* tmp = new Gtk::HBox (); + hb2->pack_start (hscroll); + Gtk::Requisition vcr = vscroll.size_request (); + tmp->set_size_request (vcr.width, vcr.width); + hb2->pack_end (*tmp, Gtk::PACK_SHRINK, 0); + + pack_start (*hb2,Gtk::PACK_SHRINK, 0); + + internal.setParent (this); + + show_all (); + + hscroll.set_update_policy (Gtk::UPDATE_CONTINUOUS); + vscroll.set_update_policy (Gtk::UPDATE_CONTINUOUS); + + vscroll.signal_value_changed().connect( sigc::mem_fun(*this, &ThumbBrowserBase::scrollChanged) ); + hscroll.signal_value_changed().connect( sigc::mem_fun(*this, &ThumbBrowserBase::scrollChanged) ); + + internal.signal_size_allocate().connect( sigc::mem_fun(*this, &ThumbBrowserBase::internalAreaResized) ); + signal_style_changed().connect( sigc::mem_fun(*this, &ThumbBrowserBase::styleChanged) ); +} + +void ThumbBrowserBase::scrollChanged () { + + for (int i=0; isetOffset ((int)(hscroll.get_value()), (int)(vscroll.get_value())); + + internal.setPosition ((int)(hscroll.get_value()), (int)(vscroll.get_value())); + + if (!internal.isDirty()) { + internal.setDirty (); + internal.queue_draw (); +// gdk_window_process_updates (get_window()->gobj(), true); + } +} + +void ThumbBrowserBase::scroll (int direction) { + + if (arrangement==TB_Vertical) + vscroll.set_value (vscroll.get_value() + (direction==GDK_SCROLL_DOWN ? +1 : -1) * vscroll.get_adjustment()->get_step_increment()); + else + hscroll.set_value (hscroll.get_value() + (direction==GDK_SCROLL_DOWN ? +1 : -1) * hscroll.get_adjustment()->get_step_increment()); +} + +void ThumbBrowserBase::resizeThumbnailArea (int w, int h) { + + inW = w; + inH = h; + + if (hscroll.get_value() + internal.get_width() > inW) + hscroll.set_value (inW - internal.get_width()); + if (vscroll.get_value() + internal.get_height() > inH) + vscroll.set_value (inH - internal.get_height()); + + configScrollBars (); +} + +void ThumbBrowserBase::internalAreaResized (Gtk::Allocation& req) { + + if (inW>0 && inH>0) { + configScrollBars (); + redraw (); + } +} + +void ThumbBrowserBase::configScrollBars () { + + if (inW>0 && inH>0) { + + int iw = internal.get_width (); + int ih = internal.get_height (); + + hscroll.get_adjustment()->set_upper (inW); + vscroll.get_adjustment()->set_upper (inH); + hscroll.get_adjustment()->set_lower (0); + vscroll.get_adjustment()->set_lower (0); + hscroll.get_adjustment()->set_step_increment (32); + vscroll.get_adjustment()->set_step_increment (32); + hscroll.get_adjustment()->set_page_increment (iw); + vscroll.get_adjustment()->set_page_increment (ih); + hscroll.get_adjustment()->set_page_size (iw); + vscroll.get_adjustment()->set_page_size (ih); + } +} + +void ThumbBrowserBase::arrangeFiles () { + + int N = fd.size (); + // apply filter + for (int i=0; ifiltered = !checkFilter (fd[i]); + + int rowHeight = 0; + // compute size of the items + for (int i=0; ifiltered && fd[i]->getMinimalHeight() > rowHeight) + rowHeight = fd[i]->getMinimalHeight (); + + if (arrangement==TB_Horizontal) { + + int numOfRows = 1; + if (rowHeight>0) { + numOfRows = (internal.get_height()+rowHeight/2)/rowHeight; + if (numOfRows<1) + numOfRows = 1; + } + + int ct = 0; + int currx = 0; int curry = 0; + while (ctgetMinimalWidth() > maxw) + maxw = fd[ct+i]->getMinimalWidth (); + + // arrange items in the column + curry = 0; + for (int i=0; ctfiltered) + fd[ct++]->drawable = false; + if (ctsetPosition (currx, curry, maxw, rowHeight); + fd[ct]->drawable = true; + curry += rowHeight; + } + } + currx += maxw; + } + resizeThumbnailArea (currx, numOfRows*rowHeight); + } + else { + int availWidth = internal.get_width(); + // initial number of columns + int numOfCols = 0; + int currColNum = 0; + int colsWidth = 0; + for (int i=0; ifiltered && colsWidth + fd[i]->getMinimalWidth() <= availWidth) { + colsWidth += fd[numOfCols]->getMinimalWidth (); + numOfCols++; + } + if (numOfCols<1) + numOfCols = 1; + std::vector colWidths; + for (; numOfCols>0; numOfCols--) { + // compute column widths + colWidths.resize (numOfCols); + for (int i=0; ifiltered && fd[i]->getMinimalWidth() > colWidths[j%numOfCols]) + colWidths[j%numOfCols] = fd[i]->getMinimalWidth (); + if (!fd[i]->filtered) + j++; + } + // if not wider than the space available, arrange it and we are ready + colsWidth = 0; + for (int i=0; ifiltered) + fd[ct++]->drawable = false; + if (ctsetPosition (currx, curry, colWidths[i%numOfCols], rowHeight); + fd[ct]->drawable = true; + currx += colWidths[i%numOfCols]; + } + } + if (currx>0) // there were thumbnails placed in the row + curry += rowHeight; + } + resizeThumbnailArea (colsWidth, curry); + } +} + + +void ThumbBrowserBase::Internal::on_realize() +{ + Cairo::FontOptions cfo; + cfo.set_antialias (Cairo::ANTIALIAS_SUBPIXEL); + get_pango_context()->set_cairo_font_options (cfo); + + Gtk::DrawingArea::on_realize(); + Glib::RefPtr window = get_window(); + set_flags (Gtk::CAN_FOCUS); + add_events(Gdk::EXPOSURE_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::POINTER_MOTION_MASK | Gdk::SCROLL_MASK | Gdk::KEY_PRESS_MASK); + gc_ = Gdk::GC::create(window); + set_has_tooltip (true); + signal_query_tooltip().connect( sigc::mem_fun(*this, &ThumbBrowserBase::Internal::on_query_tooltip) ); +} + +bool ThumbBrowserBase::Internal::on_query_tooltip (int x, int y, bool keyboard_tooltip, const Glib::RefPtr& tooltip) { + + Glib::ustring ttip = ""; + for (int i=0; ifd.size(); i++) + if (parent->fd[i]->drawable && parent->fd[i]->inside (x, y)) { + ttip = parent->fd[i]->getToolTip (x, y); + break; + } + if (ttip!="") { + tooltip->set_text (ttip); + return true; + } + else + return false; +} + +void ThumbBrowserBase::styleChanged (const Glib::RefPtr& style) { + + refreshThumbImages (); +} + +ThumbBrowserBase::Internal::Internal () : parent(NULL), ofsX(0), ofsY(0), dirty(true) { +} + +void ThumbBrowserBase::Internal::setParent (ThumbBrowserBase* p) { + + parent = p; +} + +void ThumbBrowserBase::Internal::setPosition (int x, int y) { + + ofsX = x; + ofsY = y; +} + +bool ThumbBrowserBase::Internal::on_key_press_event (GdkEventKey* event) { + + return parent->keyPressed (event); +} + +bool ThumbBrowserBase::Internal::on_button_press_event (GdkEventButton* event) { + + grab_focus (); + + parent->eventTime = event->time; + + parent->buttonPressed ((int)event->x, (int)event->y, event->button, event->type, event->state, 0, 0, get_width(), get_height()); + Glib::RefPtr window = get_window(); + + GdkRectangle rect; + rect.x = 0; + rect.y = 0; + window->get_size (rect.width, rect.height); + + gdk_window_invalidate_rect (window->gobj(), &rect, true); + gdk_window_process_updates (window->gobj(), true); + return true; +} + +void ThumbBrowserBase::buttonPressed (int x, int y, int button, GdkEventType type, int state, int clx, int cly, int clw, int clh) { + + ThumbBrowserEntryBase* fileDescr = NULL; + bool handled = false; + for (int i=0; idrawable) { + if (fd[i]->inside (x, y) && fd[i]->insideWindow (clx, cly, clw, clh)) + fileDescr = fd[i]; + bool b = fd[i]->pressNotify (button, type, state, x, y); + handled = handled || b; + } + + if (handled || (fileDescr && fileDescr->processing)) + return; + + if (selected.size()==1 && type==GDK_2BUTTON_PRESS && button==1) + doubleClicked (selected[0]); + else if (button==1 && type==GDK_BUTTON_PRESS) { + if (fileDescr && state & GDK_SHIFT_MASK) { + if (selected.size()==0) { + selected.push_back (fileDescr); + fileDescr->selected = true; + lastClicked = fileDescr; + selectionChanged (); + } + else { + // find the start and the end of the selection interval + int startx = fd.size()-1; + if (lastClicked) { + for (; startx>=0; startx--) + if (fd[startx]==lastClicked) + break; + } + else { + for (; startx>=0; startx--) + if (fd[startx]==selected[0]) + break; + } + int endx = 0; + for (; endxselected = false; + selected.clear (); + // select thumbnails in the interval + for (int i=startx; i<=endx; i++) { + if (!fd[i]->filtered) { + fd[i]->selected = true; + selected.push_back (fd[i]); + } + } + selectionChanged (); + } + } + else if (fileDescr && state & GDK_CONTROL_MASK) { + std::vector::iterator i = std::find (selected.begin(), selected.end(), fileDescr); + if (i!=selected.end()) { + (*i)->selected = false; + selected.erase (i); + } + else { + selected.push_back (fileDescr); + fileDescr->selected = true; + } + lastClicked = fileDescr; + selectionChanged (); + } + else { + for (int i=0; iselected = false; + selected.clear (); + if (fileDescr) { + selected.push_back (fileDescr); + fileDescr->selected = true; + } + lastClicked = fileDescr; + selectionChanged (); + } + } + else if (fileDescr && button==3 && type==GDK_BUTTON_PRESS) { + if (!fileDescr->selected) { + for (int i=0; iselected = false; + selected.clear (); + fileDescr->selected = true; + selected.push_back (fileDescr); + lastClicked = fileDescr; + selectionChanged (); + } + rightClicked (fileDescr); + } +} + +bool ThumbBrowserBase::Internal::on_expose_event(GdkEventExpose* event) { + + dirty = false; + + Glib::RefPtr window = get_window(); + + int w = get_width(); + int h = get_height(); + + window->clear(); + // draw thumbnails + Glib::RefPtr context = get_pango_context (); + context->set_font_description (get_style()->get_font()); + for (int i=0; ifd.size(); i++) { + if (!parent->fd[i]->drawable || !parent->fd[i]->insideWindow (0, 0, w, h)) + parent->fd[i]->updatepriority = false; + else { + parent->fd[i]->updatepriority = true; + parent->fd[i]->draw (); + } + } + + return true; +} + +bool ThumbBrowserBase::Internal::on_button_release_event (GdkEventButton* event) { + + int w = get_width(); + int h = get_height(); + + for (int i=0; ifd.size(); i++) + if (parent->fd[i]->drawable && parent->fd[i]->insideWindow (0, 0, w, h)) + parent->fd[i]->releaseNotify (event->button, event->type, event->state, (int)event->x, (int)event->y); + return true; +} + +bool ThumbBrowserBase::Internal::on_motion_notify_event (GdkEventMotion* event) { + + int w = get_width(); + int h = get_height(); + + for (int i=0; ifd.size(); i++) + if (parent->fd[i]->drawable && parent->fd[i]->insideWindow (0, 0, w, h)) + parent->fd[i]->motionNotify ((int)event->x, (int)event->y); + return true; +} + +bool ThumbBrowserBase::Internal::on_scroll_event (GdkEventScroll* event) { + + parent->scroll (event->direction); + return true; +} + + +void ThumbBrowserBase::redraw () { + + arrangeFiles (); + queue_draw (); +} + +void ThumbBrowserBase::zoomChanged (bool zoomIn) { + + int newHeight; + int i=0; + if (zoomIn) + for (i=0; i options.thumbSize) + break; + } + else + for (i=options.thumbnailZoomRatios.size()-1; i>=0; i--) { + newHeight = (int)(options.thumbnailZoomRatios[i] * options.maxThumbnailHeight); + if (newHeight < options.thumbSize) + break; + } + previewHeight = options.thumbSize = newHeight; + for (int i=0; iresize (previewHeight); + redraw (); +#ifdef _WIN32 + gdk_window_process_updates (get_window()->gobj(), true); +#endif +} +void ThumbBrowserBase::refreshThumbImages () { + + for (int i=0; irefreshThumbnailImage (); + + redraw (); +} + +void ThumbBrowserBase::refreshEditedState (const std::set& efiles) { + + editedFiles = efiles; + for (int i=0; iframed = editedFiles.find (fd[i]->filename)!=editedFiles.end(); + queue_draw (); +} + +void ThumbBrowserBase::setArrangement (Arrangement a) { + + arrangement = a; + redraw (); +} + +void ThumbBrowserBase::initEntry (ThumbBrowserEntryBase* entry) { + + entry->setOffset ((int)(hscroll.get_value()), (int)(vscroll.get_value())); +} +void ThumbBrowserBase::getScrollPosition (double& h, double& v) { + + h = hscroll.get_value (); + v = vscroll.get_value (); +} + +void ThumbBrowserBase::setScrollPosition (double h, double v) { + + hscroll.set_value (h>hscroll.get_adjustment()->get_upper() ? hscroll.get_adjustment()->get_upper() : h); + vscroll.set_value (v>vscroll.get_adjustment()->get_upper() ? vscroll.get_adjustment()->get_upper() : v); +} + +/*void PreviewImgUpdater::processCustomOrder () { + + // find first filtered entry, if any + std::list::iterator i; + for (i=jqueue.begin (); i!=jqueue.end(); i++) + if (!(*i)->filtered) + break; + if (i==jqueue.end()) + i = jqueue.begin(); + + ThumbBrowserEntryBase* current = *i; + jqueue.erase (i); + + current->updateImg (); + if (parent) { + gdk_threads_enter (); + parent->queue_draw (); + if (parent->get_window()) + gdk_window_process_updates (parent->get_window()->gobj(), true); + gdk_threads_leave (); + } +} +*/ + diff --git a/rtgui/thumbbrowserbase.h b/rtgui/thumbbrowserbase.h new file mode 100755 index 000000000..efc1eea2a --- /dev/null +++ b/rtgui/thumbbrowserbase.h @@ -0,0 +1,118 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _THUMBNAILBROWSERBASE_ +#define _THUMBNAILBROWSERBASE_ + +#include +#include +#include + +class ThumbBrowserBase : public Gtk::VBox { + + class Internal : public Gtk::DrawingArea { + + Glib::RefPtr gc_; + int ofsX, ofsY; + ThumbBrowserBase* parent; + bool dirty; + public: + Internal (); + void setParent (ThumbBrowserBase* p); + void on_realize(); + bool on_expose_event(GdkEventExpose* event); + bool on_button_press_event (GdkEventButton* event); + bool on_button_release_event (GdkEventButton* event); + bool on_motion_notify_event (GdkEventMotion* event); + bool on_scroll_event (GdkEventScroll* event); + bool on_key_press_event (GdkEventKey* event); + bool on_query_tooltip (int x, int y, bool keyboard_tooltip, const Glib::RefPtr& tooltip); + void setPosition (int x, int y); + + void setDirty () { dirty = true; } + bool isDirty () { return dirty; } + }; + + protected: + + Internal internal; + Gtk::HScrollbar hscroll; + Gtk::VScrollbar vscroll; + + int inW, inH; + + void resizeThumbnailArea (int w, int h); + void internalAreaResized (Gtk::Allocation& req); + void buttonPressed (int x, int y, int button, GdkEventType type, int state, int clx, int cly, int clw, int clh); + + public: + + enum Arrangement {TB_Horizontal, TB_Vertical}; + void configScrollBars (); + void scrollChanged (); + void scroll (int direction); + + protected: + + int eventTime; + + std::vector fd; + std::vector selected; + ThumbBrowserEntryBase* lastClicked; + + int previewHeight; + + Arrangement arrangement; + + std::set editedFiles; + + void arrangeFiles (); + void zoomChanged (bool zoomIn); + + public: + + ThumbBrowserBase (); + + void zoomIn () { zoomChanged (true); } + void zoomOut () { zoomChanged (false); } + + const std::vector& getEntries () { return fd; } + void styleChanged (const Glib::RefPtr& style); + void redraw (); // arrange files and draw area + void refreshThumbImages (); // refresh thumbnail sizes, re-generate thumbnail images, arrange and draw + void refreshEditedState (const std::set& efiles); + + void initEntry (ThumbBrowserEntryBase* entry); + + void getScrollPosition (double& h, double& v); + void setScrollPosition (double h, double v); + + void setArrangement (Arrangement a); + virtual bool checkFilter (ThumbBrowserEntryBase* entry) { return true; } + virtual void rightClicked (ThumbBrowserEntryBase* entry) {} + virtual void doubleClicked (ThumbBrowserEntryBase* entry) {} + virtual bool keyPressed (GdkEventKey* event) {} + virtual void selectionChanged () {} + + virtual void redrawNeeded (ThumbBrowserEntryBase* entry) {} + virtual void thumbRearrangementNeeded () {} + + Gtk::Widget* getDrawingArea () { return &internal; } +}; + +#endif diff --git a/rtgui/thumbbrowserbase_old.cc b/rtgui/thumbbrowserbase_old.cc new file mode 100755 index 000000000..58e755897 --- /dev/null +++ b/rtgui/thumbbrowserbase_old.cc @@ -0,0 +1,360 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include + +ThumbBrowserBase::ThumbBrowserBase () + : previewHeight(options.thumbSize), lastClicked(NULL) { + + signal_style_changed().connect( sigc::mem_fun(*this, &ThumbBrowserBase::styleChanged) ); +} + +void ThumbBrowserBase::arrangeFiles () { + + int N = fd.size (); + // apply filter + for (int i=0; ifiltered = !checkFilter (fd[i]); + + int rowHeight = 0; + // compute size of the items + for (int i=0; ifiltered && fd[i]->getMinimalHeight() > rowHeight) + rowHeight = fd[i]->getMinimalHeight (); + + if (arrangement==TB_Horizontal) { + + int numOfRows = 1; + if (get_parent () && rowHeight>0) { + Gtk::Allocation alloc = get_parent ()->get_allocation (); + numOfRows = (alloc.get_height()+rowHeight/2)/rowHeight; + if (numOfRows<1) + numOfRows = 1; + } + + int ct = 0; + int currx = 0; int curry = 0; + while (ctgetMinimalWidth() > maxw) + maxw = fd[ct+i]->getMinimalWidth (); + + // arrange items in the column + curry = 0; + for (int i=0; ctfiltered) + fd[ct++]->drawable = false; + if (ctsetPosition (currx, curry, maxw, rowHeight); + fd[ct]->drawable = true; + curry += rowHeight; + } + } + currx += maxw; + } + set_size_request (currx, numOfRows*rowHeight); + } + else { + int availWidth = 0; + if (get_parent ()) { + Gtk::Allocation alloc = get_parent ()->get_allocation (); + availWidth = alloc.get_width(); + } + + // initial number of columns + int numOfCols = 0; + int currColNum = 0; + int colsWidth = 0; + for (int i=0; ifiltered && colsWidth + fd[i]->getMinimalWidth() <= availWidth) { + colsWidth += fd[numOfCols]->getMinimalWidth (); + numOfCols++; + } + if (numOfCols<1) + numOfCols = 1; + std::vector colWidths; + for (; numOfCols>0; numOfCols--) { + // compute column widths + colWidths.resize (numOfCols); + for (int i=0; ifiltered && fd[i]->getMinimalWidth() > colWidths[j%numOfCols]) + colWidths[j%numOfCols] = fd[i]->getMinimalWidth (); + if (!fd[i]->filtered) + j++; + } + // if not wider than the space available, arrange it and we are ready + colsWidth = 0; + for (int i=0; ifiltered) + fd[ct++]->drawable = false; + if (ctsetPosition (currx, curry, colWidths[i%numOfCols], rowHeight); + fd[ct]->drawable = true; + currx += colWidths[i%numOfCols]; + } + } + curry += rowHeight; + } + set_size_request (colsWidth, curry); + } +} + + +void ThumbBrowserBase::on_realize() +{ + Cairo::FontOptions cfo; + cfo.set_antialias (Cairo::ANTIALIAS_SUBPIXEL); + get_pango_context()->set_cairo_font_options (cfo); + + add_events(Gdk::LEAVE_NOTIFY_MASK); + Gtk::DrawingArea::on_realize(); + Glib::RefPtr window = get_window(); + add_events(Gdk::EXPOSURE_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::POINTER_MOTION_MASK); + + gc_ = Gdk::GC::create(window); +} + +void ThumbBrowserBase::styleChanged (const Glib::RefPtr& style) { + + refreshAll (); +} + +bool ThumbBrowserBase::on_expose_event(GdkEventExpose* event) { + + Gtk::Viewport* vp = (Gtk::Viewport*) get_parent (); + Gtk::ScrolledWindow* sw = (Gtk::ScrolledWindow*) vp->get_parent (); + + int px = (int)(sw->get_hscrollbar()->get_value ()); + int py = (int)(sw->get_vscrollbar()->get_value ()); + int pw = vp->get_width (); + int ph = vp->get_height (); + Glib::RefPtr window = get_window(); + + window->clear(); + // draw thumbnails + Glib::RefPtr context = get_pango_context (); + context->set_font_description (get_style()->get_font()); + for (int i=0; idrawable || !fd[i]->insideWindow (px, py, pw, ph)) + continue; + fd[i]->draw (this); + } + return true; +} + +bool ThumbBrowserBase::on_button_press_event (GdkEventButton* event) { + + Gtk::Viewport* vp = (Gtk::Viewport*) get_parent (); + Gtk::ScrolledWindow* sw = (Gtk::ScrolledWindow*) vp->get_parent (); + + int px = (int)(sw->get_hscrollbar()->get_value ()); + int py = (int)(sw->get_vscrollbar()->get_value ()); + int pw = vp->get_width (); + int ph = vp->get_height (); + + ThumbBrowserEntryBase* fileDescr = NULL; + bool handled = false; + for (int i=0; idrawable && fd[i]->insideWindow (px, py, pw, ph)) { + if (fd[i]->inside ((int)event->x, (int)event->y)) + fileDescr = fd[i]; + bool b = fd[i]->pressNotify (this, (int)event->x, (int)event->y); + handled = handled || b; + } + if (handled || (fileDescr && fileDescr->processing)) + return true; + + if (selected.size()==1 && event->type==GDK_2BUTTON_PRESS && event->button==1) + doubleClicked (selected[0]); + else if (event->button==1 && event->type==GDK_BUTTON_PRESS) { + if (fileDescr && event->state & GDK_SHIFT_MASK) { + if (selected.size()==0) { + selected.push_back (fileDescr); + fileDescr->selected = true; + lastClicked = fileDescr; + } + else { + // find the start and the end of the selection interval + int startx = fd.size()-1; + if (lastClicked) { + for (; startx>=0; startx--) + if (fd[startx]==lastClicked) + break; + } + else { + for (; startx>=0; startx--) + if (fd[startx]==selected[0]) + break; + } + int endx = 0; + for (; endxselected = false; + selected.clear (); + // select thumbnails in the interval + for (int i=startx; i<=endx; i++) { + fd[i]->selected = true; + selected.push_back (fd[i]); + } + } + } + else if (fileDescr && event->state & GDK_CONTROL_MASK) { + std::vector::iterator i = std::find (selected.begin(), selected.end(), fileDescr); + if (i!=selected.end()) { + (*i)->selected = false; + selected.erase (i); + } + else { + selected.push_back (fileDescr); + fileDescr->selected = true; + } + lastClicked = fileDescr; + } + else { + for (int i=0; iselected = false; + selected.clear (); + if (fileDescr) { + selected.push_back (fileDescr); + fileDescr->selected = true; + } + lastClicked = fileDescr; + } + } + else if (fileDescr && event->button==3 && event->type==GDK_BUTTON_PRESS) { + if (!fileDescr->selected) { + for (int i=0; iselected = false; + selected.clear (); + fileDescr->selected = true; + selected.push_back (fileDescr); + lastClicked = fileDescr; + } + rightClicked (fileDescr); + } + Glib::RefPtr window = get_window(); + + GdkRectangle rect; + rect.x = 0; + rect.y = 0; + window->get_size (rect.width, rect.height); + + gdk_window_invalidate_rect (window->gobj(), &rect, true); + gdk_window_process_updates (window->gobj(), true); + + return true; +} + +bool ThumbBrowserBase::on_button_release_event (GdkEventButton* event) { + + Gtk::Viewport* vp = (Gtk::Viewport*) get_parent (); + Gtk::ScrolledWindow* sw = (Gtk::ScrolledWindow*) vp->get_parent (); + + int px = (int)(sw->get_hscrollbar()->get_value ()); + int py = (int)(sw->get_vscrollbar()->get_value ()); + int pw = vp->get_width (); + int ph = vp->get_height (); + + for (int i=0; idrawable && fd[i]->insideWindow (px, py, pw, ph)) + fd[i]->releaseNotify (this, (int)event->x, (int)event->y); + return true; +} + +bool ThumbBrowserBase::on_motion_notify_event (GdkEventMotion* event) { + + Gtk::Viewport* vp = (Gtk::Viewport*) get_parent (); + Gtk::ScrolledWindow* sw = (Gtk::ScrolledWindow*) vp->get_parent (); + + int px = (int)(sw->get_hscrollbar()->get_value ()); + int py = (int)(sw->get_vscrollbar()->get_value ()); + int pw = vp->get_width (); + int ph = vp->get_height (); + + for (int i=0; idrawable && fd[i]->insideWindow (px, py, pw, ph)) + fd[i]->motionNotify (this, (int)event->x, (int)event->y); + return true; +} + +void ThumbBrowserBase::resized (Gtk::Allocation& req) { + arrangeFiles (); +} + +void ThumbBrowserBase::redraw () { + + arrangeFiles (); + queue_draw (); +} + +void ThumbBrowserBase::setPreviewHeight (int h) { + + previewHeight = h; + for (int i=0; iinitSizes (this, previewHeight); + arrangeFiles (); +} + +void ThumbBrowserBase::refreshAll () { + + for (int i=0; iforceHeight (options.thumbSize); + fd[i]->updateImg (); + fd[i]->initSizes (this, options.thumbSize); + } + redraw (); +} + +void ThumbBrowserBase::setOpenedFileName (const Glib::ustring& fname) { + + fileInEditor = fname; + for (int i=0; iframed = fd[i]->filename==fileInEditor; +} + +void ThumbBrowserBase::setArrangement (Arrangement a) { + + arrangement = a; + redraw (); +} diff --git a/rtgui/thumbbrowserbase_old.h b/rtgui/thumbbrowserbase_old.h new file mode 100755 index 000000000..d594be85d --- /dev/null +++ b/rtgui/thumbbrowserbase_old.h @@ -0,0 +1,71 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _THUMBNAILBROWSERBASE_ +#define _THUMBNAILBROWSERBASE_ + +#include +#include + +class ThumbBrowserBase : public Gtk::DrawingArea { + + public: + + enum Arrangement {TB_Horizontal, TB_Vertical}; + + protected: + + Glib::RefPtr gc_; + + std::vector fd; + std::vector selected; + ThumbBrowserEntryBase* lastClicked; + + int previewHeight; + + Glib::ustring fileInEditor; + Arrangement arrangement; + + void arrangeFiles (); + + public: + + ThumbBrowserBase (); + + void setPreviewHeight (int h); + const std::vector& getEntries () { return fd; } + void styleChanged (const Glib::RefPtr& style); + void redraw (); // arrange files and draw area + void refreshAll (); // refresh thumbnail sizes, re-generate thumbnail images, arrange and draw + void resized (Gtk::Allocation& req); + void setOpenedFileName (const Glib::ustring& fname); + + virtual void on_realize(); + virtual bool on_expose_event(GdkEventExpose* event); + virtual bool on_button_press_event (GdkEventButton* event); + virtual bool on_button_release_event (GdkEventButton* event); + virtual bool on_motion_notify_event (GdkEventMotion* event); + + void setArrangement (Arrangement a); + virtual bool checkFilter (ThumbBrowserEntryBase* entry) { return true; } + virtual void rightClicked (ThumbBrowserEntryBase* entry) {} + virtual void doubleClicked (ThumbBrowserEntryBase* entry) {} + +}; + +#endif diff --git a/rtgui/thumbbrowserentry.cc b/rtgui/thumbbrowserentry.cc new file mode 100755 index 000000000..79531775b --- /dev/null +++ b/rtgui/thumbbrowserentry.cc @@ -0,0 +1,63 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +FileBrowserEntry::FileBrowserEntry (Thumbnail* thm, const Glib::ustring& fname) + : ThumbBrowserEntryBase (fname), thumbnail(thm) { + + previewOwner = false; + italicstyle = thumbnail->getType() != FT_Raw; + datetimeline = thumbnail->getDateTimeString (); + exifline = thumbnail->getExifString (); +} + +void ThumbBrowserEntry::obtainThumbnailImage () { + + preview = thumbnail ? (guint8*) thumbnail->getThumbnailImage (prew, preh) : NULL; +} + +void ThumbBrowserEntry::obtainThumbnailSize () { + + if (thumbnail) + thumbnail->getThumbnailSize (prew, preh); +} +Glib::RefPtr ThumbBrowserEntry::editedIcon; +Glib::RefPtr ThumbBrowserEntry::recentlySavedIcon; +Glib::RefPtr ThumbBrowserEntry::enqueuedIcon; +std::vector > ThumbBrowserEntry::getIconsOnImageArea () { + + std::vector > ret; + + if (!thumbnail) + return ret; + + if (thumbnail->hasProcParams() && editedIcon) + ret.push_back (editedIcon); + if (thumbnail->isRecentlySaved() && recentlySavedIcon) + ret.push_back (recentlySavedIcon); + if (thumbnail->isEnqueued () && enqueuedIcon) + ret.push_back (enqueuedIcon); + + return ret; +} + +ThumbnailButtonSet* ThumbBrowserEntry::getThumbButtonSet () { + + return (ThumbnailButtonSet*)buttonSet; +} diff --git a/rtgui/thumbbrowserentrybase.cc b/rtgui/thumbbrowserentrybase.cc new file mode 100755 index 000000000..8e89dfaa7 --- /dev/null +++ b/rtgui/thumbbrowserentrybase.cc @@ -0,0 +1,406 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include + +ThumbBrowserEntryBase::ThumbBrowserEntryBase (const Glib::ustring& fname) + : filename(fname), selected(false), drawable(false),framed(false), processing(false), + italicstyle(false), preview(NULL), exifline(""), datetimeline(""), + buttonSet(NULL), updatepriority(false), redrawRequests(0), + parent(NULL), exp_width(0), exp_height(0) { + + shortname = Glib::path_get_basename (fname); + dispname = shortname; + + upperMargin = 6; + borderWidth = 1; + sideMargin = 8; + lowerMargin = 8; + textGap = 6; + + ofsX = ofsY = 0; +} + +ThumbBrowserEntryBase::~ThumbBrowserEntryBase () { + + delete [] preview; + delete buttonSet; +} + +void ThumbBrowserEntryBase::addButtonSet (LWButtonSet* bs) { + + buttonSet = bs; +} + +void ThumbBrowserEntryBase::updateBackBuffer () { + + if (!parent) + return; + + Gtk::Widget* w = parent->getDrawingArea (); + + backBuffer = Gdk::Pixmap::create (w->get_window(), exp_width, exp_height); + + bbSelected = selected; + bbFramed = framed; + bbPreview = preview; + + Glib::RefPtr gc_ = Gdk::GC::create (backBuffer); + + Gdk::Color textn = w->get_style()->get_text(Gtk::STATE_NORMAL); + Gdk::Color texts = w->get_style()->get_text(Gtk::STATE_SELECTED); + Gdk::Color bgn = w->get_style()->get_bg(Gtk::STATE_NORMAL); + Gdk::Color bgs = w->get_style()->get_bg(Gtk::STATE_SELECTED); + + // clear area, draw frames and background + gc_->set_foreground (bgn); + gc_->set_background (bgn); + backBuffer->draw_rectangle (gc_, true, 0, 0, exp_width, exp_height); + Cairo::RefPtr cr = backBuffer->create_cairo_context(); + drawFrame (cr, bgs, bgn); + + // calculate height of button set + int bsHeight = 0; + if (buttonSet) { + int tmp; + buttonSet->getAllocatedDimensions (tmp, bsHeight); + } + + // draw preview frame + backBuffer->draw_rectangle (gc_, false, (exp_width-prew)/2, upperMargin+bsHeight, prew+1, preh+1); + // draw thumbnail image + if (preview) { + prex = borderWidth + (exp_width-prew)/2; + prey = upperMargin+bsHeight+borderWidth; + backBuffer->draw_rgb_image (gc_, prex, prey, prew, preh, Gdk::RGB_DITHER_NONE, preview, prew*3); + } + + customBackBufferUpdate (cr); + + // draw icons onto the thumbnail area + bbIcons = getIconsOnImageArea (); + + int infow, infoh; + getTextSizes (infow, infoh); + + int iofs_x = 4, iofs_y = 4; + int igap = 2; + int istartx = prex; + int istarty = prey; + + if (options.overlayedFileNames) { + cr->begin_new_path (); + cr->rectangle (istartx, istarty, prew, fnlabh+dtlabh+exlabh+2*iofs_y); + if ((texts.get_red_p()+texts.get_green_p()+texts.get_blue_p())/3 > 0.5) + cr->set_source_rgba (0, 0, 0, 0.5); + else + cr->set_source_rgba (1, 1, 1, 0.5); + cr->fill (); + } + + istartx += iofs_x; + istarty += iofs_y; + + if (bbIcons.size()>0) { + int iwidth = igap; + int iheight = 0; + for (int i=0; iget_width() + igap; + if (bbIcons[i]->get_height() > iheight) + iheight = bbIcons[i]->get_height(); + } + iheight += 2*igap; + if (!options.overlayedFileNames) { + cr->begin_new_path (); + cr->rectangle (istartx-igap, istarty-igap, iwidth, iheight); + cr->set_source_rgba (0, 0, 0, 0.75); + cr->fill (); + } + for (int i=0; idraw_pixbuf (gc_, bbIcons[i], 0, 0, istartx, istarty, bbIcons[i]->get_width(), bbIcons[i]->get_height(), Gdk::RGB_DITHER_NONE, 0, 0); + istartx += bbIcons[i]->get_width() + igap; + } + } + + int textposx_fn, textposx_ex, textposx_dt, textposy, textw; + if (!options.overlayedFileNames) { + textposx_fn = exp_width/2 - fnlabw/2; + if (textposx_fn<0) textposx_fn = 0; + textposx_ex = exp_width/2 - exlabw/2; + if (textposx_ex<0) textposx_ex = 0; + textposx_dt = exp_width/2 - dtlabw/2; + if (textposx_dt<0) textposx_dt = 0; + textposy = upperMargin + bsHeight + 2*borderWidth + preh + borderWidth + textGap; + textw = exp_width - 2*textGap; + gc_->set_foreground (selected ? texts : textn); + } + else { + textposx_fn = istartx; + textposx_ex = istartx; + textposx_dt = istartx; + textposy = istarty; + textw = prew - (istartx - prex); + gc_->set_foreground (texts); + } + + // draw file name + Glib::RefPtr context = w->get_pango_context () ; + Pango::FontDescription fontd = context->get_font_description (); + fontd.set_weight (Pango::WEIGHT_BOLD); + if (italicstyle) + fontd.set_style (Pango::STYLE_ITALIC); + else + fontd.set_style (Pango::STYLE_NORMAL); + + context->set_font_description (fontd); + Glib::RefPtr fn = w->create_pango_layout (dispname); + fn->set_width (textw*Pango::SCALE); + fn->set_ellipsize (Pango::ELLIPSIZE_MIDDLE); + backBuffer->draw_layout(gc_, textposx_fn, textposy, fn); + + fontd.set_weight (Pango::WEIGHT_NORMAL); + fontd.set_style (Pango::STYLE_NORMAL); + context->set_font_description (fontd); + + // draw date/time label + int tpos = fnlabh; + if (options.fbShowDateTime && datetimeline!="") { + fn = w->create_pango_layout (datetimeline); + fn->set_width (textw*Pango::SCALE); + fn->set_ellipsize (Pango::ELLIPSIZE_MIDDLE); + backBuffer->draw_layout(gc_, textposx_dt, textposy + tpos, fn); + tpos += dtlabh; + } + // draw basic exif info + if (options.fbShowBasicExif && exifline!="") { + fn = w->create_pango_layout (exifline); + fn->set_width (textw*Pango::SCALE); + fn->set_ellipsize (Pango::ELLIPSIZE_MIDDLE); + backBuffer->draw_layout (gc_, textposx_ex, textposy + tpos, fn); + tpos += exlabh; + } +} + +void ThumbBrowserEntryBase::getTextSizes (int& infow, int& infoh) { + + if (!parent) + return; + + Gtk::Widget* w = parent->getDrawingArea (); + + // calculate dimensions of the text based fields + dispname = shortname; + + Glib::RefPtr context = w->get_pango_context () ; + context->set_font_description (w->get_style()->get_font()); + + // filename: + Pango::FontDescription fontd = context->get_font_description (); + fontd.set_weight (Pango::WEIGHT_BOLD); + context->set_font_description (fontd); + Glib::RefPtr fn = w->create_pango_layout(shortname); + fn->get_pixel_size (fnlabw, fnlabh); + + // datetime + fontd.set_weight (Pango::WEIGHT_NORMAL); + context->set_font_description (fontd); + fn = w->create_pango_layout (datetimeline); + fn->get_pixel_size (dtlabw, dtlabh); + + // basic exif data + fn = w->create_pango_layout (exifline); + fn->get_pixel_size (exlabw, exlabh); + + // calculate cummulated height of all info fields + infoh = fnlabh; + infow = 0; + // add date/tile size: + if (options.fbShowDateTime) { + infoh += dtlabh; + if (dtlabw + 2*sideMargin > infow) + infow = dtlabw + 2*sideMargin; + } + if (options.fbShowBasicExif) { + infoh += exlabh; + if (exlabw + 2*sideMargin > infow) + infow = exlabw + 2*sideMargin; + } +} + +void ThumbBrowserEntryBase::resize (int h) { + + delete [] preview; + preview = NULL; + height = h; + + // dimensions of the button set + int bsw=0, bsh=0; + if (buttonSet) + buttonSet->getMinimalDimensions (bsw, bsh); + + // calculate the height remaining for the thumbnail image + preh = height - upperMargin - 2*borderWidth - lowerMargin - bsh; + int infow, infoh; + if (!options.overlayedFileNames) { + // dimensions of the info text + getTextSizes (infow, infoh); + preh -= infoh + textGap; + } + + calcThumbnailSize (); + width = prew + 2*sideMargin + 2*borderWidth; + if (!options.overlayedFileNames) { + width = prew + 2*sideMargin + 2*borderWidth; + if (width cr, const Gdk::Color& bg, const Gdk::Color& fg) { + + int radius = 8; + if (selected || framed) { + cr->set_antialias (Cairo::ANTIALIAS_SUBPIXEL); + cr->move_to (radius, 0); + cr->arc (exp_width-1-radius, radius, radius, -M_PI/2, 0); + cr->arc (exp_width-1-radius, exp_height-1-radius, radius, 0, M_PI/2); + cr->arc (radius, exp_height-1-radius, radius, M_PI/2, M_PI); + cr->arc (radius, radius, radius, M_PI, -M_PI/2); + cr->close_path (); + if (selected) { + cr->set_source_rgb (bg.get_red_p(), bg.get_green_p(), bg.get_blue_p()); + cr->fill_preserve (); + } + cr->set_source_rgb (bg.get_red_p()*2/3, bg.get_green_p()*2/3, bg.get_blue_p()*2/3); + cr->set_line_width (1.0); + cr->stroke (); + + } + + if (framed) { + cr->set_antialias (Cairo::ANTIALIAS_SUBPIXEL); + cr->move_to (+2+0.5+radius, +2+0.5); + cr->arc (-2+0.5+exp_width-1-radius, +2+0.5+radius, radius, -M_PI/2, 0); + cr->arc (-2+0.5+exp_width-1-radius, -2+0.5+exp_height-1-radius, radius, 0, M_PI/2); + cr->arc (+2+0.5+radius, -2+exp_height-1-radius, radius, M_PI/2, M_PI); + cr->arc (+2+0.5+radius, +2+radius, radius, M_PI, -M_PI/2); + cr->close_path (); + cr->set_source_rgb (fg.get_red_p(), fg.get_green_p(), fg.get_blue_p()); + cr->set_line_width (2.0); + cr->stroke (); + } +} + +void ThumbBrowserEntryBase::draw () { + + if (!drawable) + return; + + int bbWidth, bbHeight; + if (backBuffer) + backBuffer->get_size (bbWidth, bbHeight); + + + if (!backBuffer || selected!=bbSelected || framed!=bbFramed || preview!=bbPreview + || exp_width!=bbWidth || exp_height!=bbHeight || getIconsOnImageArea ()!=bbIcons) + updateBackBuffer (); + + if (!parent) + return; + + Gtk::Widget* w = parent->getDrawingArea (); + + Glib::RefPtr gc_ = Gdk::GC::create (w->get_window()); + + Gdk::Color textn = w->get_style()->get_text(Gtk::STATE_NORMAL); + Gdk::Color texts = w->get_style()->get_text(Gtk::STATE_SELECTED); + Gdk::Color bgn = w->get_style()->get_bg(Gtk::STATE_NORMAL); + Gdk::Color bgs = w->get_style()->get_bg(Gtk::STATE_SELECTED); + + w->get_window()->draw_drawable (gc_, backBuffer, 0, 0, startx + ofsX, starty + ofsY); + + // check icon set changes!!! + +// drawProgressBar (window, gc_, selected ? texts : textn, selected ? bgs : bgn, ofsX+startx, exp_width, ofsY+starty + upperMargin+bsHeight+borderWidth+preh+borderWidth+textGap+tpos, fnlabh); + + // redraw button set above the thumbnail + if (buttonSet) { + buttonSet->setColors (selected ? bgs : bgn, selected ? bgn : bgs); + buttonSet->redraw (w->get_window()->create_cairo_context()); + } +} + +void ThumbBrowserEntryBase::setPosition (int x, int y, int w, int h) { + + exp_width = w; + exp_height = h; + startx = x; + starty = y; + + if (buttonSet) + buttonSet->arrangeButtons (ofsX+x+sideMargin, ofsY+y+upperMargin, w-2*sideMargin, -1); +} + +void ThumbBrowserEntryBase::setOffset (int x, int y) { + + ofsX = -x; + ofsY = -y; + + if (buttonSet) + buttonSet->move (ofsX+startx+sideMargin, ofsY+starty+upperMargin); +} + +bool ThumbBrowserEntryBase::inside (int x, int y) { + + return x>ofsX+startx && xofsY+starty && yx+w || ofsX+startx+exp_widthy+h || ofsY+starty+exp_heightmotionNotify (x, y) : false; +} + +bool ThumbBrowserEntryBase::pressNotify (int button, int type, int bstate, int x, int y) { + + return buttonSet ? buttonSet->pressNotify (x, y) : false; +} + +bool ThumbBrowserEntryBase::releaseNotify (int button, int type, int bstate, int x, int y) { + + return buttonSet ? buttonSet->releaseNotify (x, y) : false; +} +Glib::ustring ThumbBrowserEntryBase::getToolTip (int x, int y) { + + return buttonSet ? buttonSet->getToolTip (x, y) : ""; +} + + diff --git a/rtgui/thumbbrowserentrybase.h b/rtgui/thumbbrowserentrybase.h new file mode 100755 index 000000000..c69737db0 --- /dev/null +++ b/rtgui/thumbbrowserentrybase.h @@ -0,0 +1,125 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _THUMBNAILBROWSERENTRYBASE_ +#define _THUMBNAILBROWSERENTRYBASE_ + +#include +#include + +class ThumbBrowserBase; +class ThumbBrowserEntryBase { + +protected: + int fnlabw, fnlabh; // dimensions of the filename label + int dtlabw, dtlabh; // dimensions of the date/time label + int exlabw, exlabh; // dimensions of the exif label + int prew; // width of the thumbnail + int preh; // height of the thumbnail + int prex; + int prey; + + int upperMargin; + int borderWidth; + int textGap; + int sideMargin; + int lowerMargin; + + guint8* preview; + + Glib::ustring dispname; + + LWButtonSet* buttonSet; + + int width; // minimal width + int height; // minimal height +// set by arrangeFiles() of thumbbrowser + int exp_width; // arranged width + int exp_height; // arranged height + int startx; // x coord. in the widget + int starty; // y coord. in the widget + + int ofsX, ofsY; // offset due to the scrolling of the parent + + int redrawRequests; + + ThumbBrowserBase* parent; + + Glib::RefPtr backBuffer; + bool bbSelected, bbFramed; + guint8* bbPreview; + std::vector > bbIcons; + + void drawFrame (Cairo::RefPtr cr, const Gdk::Color& bg, const Gdk::Color& fg); + void getTextSizes (int& w, int& h); + + virtual void customBackBufferUpdate (Cairo::RefPtr c) {} + + public: + +// thumbnail preview properties: + Glib::ustring filename; + Glib::ustring shortname; + Glib::ustring exifline; + Glib::ustring datetimeline; + +// misc attributes + bool selected; + bool drawable; + bool filtered; + bool framed; + bool processing; + bool italicstyle; + bool edited; + bool recentlysaved; + bool updatepriority; + + ThumbBrowserEntryBase (const Glib::ustring& fname); + virtual ~ThumbBrowserEntryBase (); + + void setParent (ThumbBrowserBase* l) { parent = l; } + + void updateBackBuffer (); + void resize (int h); + virtual void draw (); + + void addButtonSet (LWButtonSet* bs); + int getMinimalHeight () { return height; } + int getMinimalWidth () { return width; } + bool inside (int x, int y); + bool insideWindow (int x, int y, int w, int h); + void setPosition (int x, int y, int w, int h); + void setOffset (int x, int y); + + bool operator< (ThumbBrowserEntryBase& other) { return shortname.casefold()>other.shortname.casefold(); } + + virtual void refreshThumbnailImage () {} + virtual void calcThumbnailSize () {} + + virtual void drawProgressBar (Glib::RefPtr win, Glib::RefPtr gc, const Gdk::Color& foregr, const Gdk::Color& backgr, int x, int w, int y, int h) {} + + virtual std::vector > getIconsOnImageArea () { std::vector > r; return r; } + virtual void getIconSize (int& w, int& h) { w=0; h=0; } + + virtual bool motionNotify (int x, int y); + virtual bool pressNotify (int button, int type, int bstate, int x, int y); + virtual bool releaseNotify (int button, int type, int bstate, int x, int y); + Glib::ustring getToolTip (int x, int y); +}; + +#endif diff --git a/rtgui/thumbimageupdater.cc b/rtgui/thumbimageupdater.cc new file mode 100755 index 000000000..2dfaf066c --- /dev/null +++ b/rtgui/thumbimageupdater.cc @@ -0,0 +1,166 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +ThumbImageUpdater thumbImageUpdater; + +ThumbImageUpdater::ThumbImageUpdater () + : tostop(false), stopped(true), qMutex(NULL), startMutex(NULL) { + +} + +void ThumbImageUpdater::add (Thumbnail* t, const rtengine::procparams::ProcParams& params, int height, bool* priority, ThumbImageUpdateListener* l) { + + if (!qMutex) + qMutex = new Glib::Mutex (); + if (!startMutex) + startMutex = new Glib::Mutex (); + + qMutex->lock (); + // look up if an older version is in the queue + std::list::iterator i; + for (i=jqueue.begin(); i!=jqueue.end(); i++) + if (i->thumbnail==t && i->listener==l) { + i->pparams = params; + i->height = height; + i->priority = priority; + break; + } + // not found, create and append new job + if (i==jqueue.end ()) { + Job j; + j.thumbnail = t; + j.pparams = params; + j.height = height; + j.listener = l; + j.priority = priority; + jqueue.push_back (j); + } + qMutex->unlock (); +} + +void ThumbImageUpdater::process () { + + if (stopped) { + #undef THREAD_PRIORITY_NORMAL + stopped = false; + thread = Glib::Thread::create(sigc::mem_fun(*this, &ThumbImageUpdater::process_), (unsigned long int)0, true, true, Glib::THREAD_PRIORITY_NORMAL); + } +} + +void ThumbImageUpdater::process_ () { + + stopped = false; + tostop = false; + + #define threadNum 4 // IF LCMS GETS THREAD SAFETY WE CAN ENABLE MORE THREADS + Glib::Thread **threadPool = new Glib::Thread* [threadNum]; + + while (!tostop && !jqueue.empty ()) { + + qMutex->lock (); + int threads = 0; + for (; threads::iterator i; + for (i=jqueue.begin (); i!=jqueue.end(); i++) + if (*(i->priority)) + break; + if (i==jqueue.end()) + i = jqueue.begin(); + Job current = *i; + jqueue.erase (i); + if (current.listener) + threadPool[threads] = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &ThumbImageUpdater::processJob), current), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); + else + threadPool[threads] = NULL; + } + qMutex->unlock (); + + for (int j=0; jjoin (); + } + stopped = true; +} + +void ThumbImageUpdater::processJob (Job current) { + + if (current.listener) { + double scale = 1.0; + rtengine::IImage8* img = current.thumbnail->processThumbImage (current.pparams, current.height, scale); + if (img) + current.listener->updateImage (img, scale, current.pparams.crop); + } + +} + +void ThumbImageUpdater::stop () { + + if (stopped) { + tostop = true; + return; } + + gdk_threads_leave(); + tostop = true; + Glib::Thread::self()->yield(); + if (!stopped) + thread->join (); + gdk_threads_enter(); +} + +void ThumbImageUpdater::removeJobs () { + + if (!qMutex) + return; + + qMutex->lock (); + while (!jqueue.empty()) + jqueue.pop_front (); + qMutex->unlock (); +} + +void ThumbImageUpdater::removeJobs (ThumbImageUpdateListener* listener) { + + if (!qMutex) + return; + + qMutex->lock (); + bool ready = false; + while (!ready) { + ready = true; + std::list::iterator i; + for (i=jqueue.begin(); i!=jqueue.end(); i++) + if (i->listener == listener) { + jqueue.erase (i); + ready = false; + break; + } + } + qMutex->unlock (); +} + +void ThumbImageUpdater::terminate () { + + stop (); + removeJobs (); +} + + diff --git a/rtgui/thumbimageupdater.h b/rtgui/thumbimageupdater.h new file mode 100755 index 000000000..91c0d6956 --- /dev/null +++ b/rtgui/thumbimageupdater.h @@ -0,0 +1,66 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _THUMBIMAGEUPDATER_ +#define _THUMBIMAGEUPDATER_ + +#include +#include +#include + +class ThumbImageUpdateListener { + + public: + virtual void updateImage (rtengine::IImage8* img, double scale, rtengine::procparams::CropParams cropParams) {} +}; + +class ThumbImageUpdater { + + struct Job { + Thumbnail* thumbnail; + rtengine::procparams::ProcParams pparams; + int height; + bool* priority; + ThumbImageUpdateListener* listener; + }; + + protected: + bool tostop; + bool stopped; + std::list jqueue; + Glib::Thread* thread; + Glib::Mutex* qMutex; + Glib::Mutex* startMutex; + + public: + ThumbImageUpdater (); + + void add (Thumbnail* t, const rtengine::procparams::ProcParams& params, int height, bool* priority, ThumbImageUpdateListener* l); + void process (); + void stop (); + void removeJobs (); + void removeJobs (ThumbImageUpdateListener* listener); + void terminate (); + + void process_ (); + void processJob (Job current); +}; + +extern ThumbImageUpdater thumbImageUpdater; + +#endif diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc new file mode 100755 index 000000000..f39cae764 --- /dev/null +++ b/rtgui/thumbnail.cc @@ -0,0 +1,447 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace rtengine::procparams; + +Thumbnail::Thumbnail (CacheManager* cm, const Glib::ustring& fname, CacheImageData* cf) + : cachemgr(cm), cfs(*cf), pparamsValid(false), fname(fname), + lastImg(NULL), ref(1), enqueueNumber(0), tpp(NULL), needsReProcessing(true) { + + mutex = new Glib::Mutex (); + cfs.load (getCacheFileName ("data")+".txt"); + loadProcParams (); + loadThumbnail (); + generateExifDateTimeStrings (); +} + +Thumbnail::Thumbnail (CacheManager* cm, const Glib::ustring& fname, const std::string& md5) + : cachemgr(cm), pparamsValid(false), lastImg(NULL), fname(fname), + ref(1), enqueueNumber(0), tpp(NULL), needsReProcessing(true) { + + mutex = new Glib::Mutex (); + + cfs.md5 = md5; + generateThumbnailImage (); + loadProcParams (); + cfs.recentlySaved = false; +} + +void Thumbnail::generateThumbnailImage (bool internal) { + + if (!internal) + mutex->lock (); + +// delete everything loaded into memory + delete tpp; + tpp = NULL; + delete [] lastImg; + lastImg = NULL; + tw = -1; + th = options.maxThumbnailHeight; + +// generate thumbnail image + + Glib::ustring ext = getExtension (fname); + if (ext=="") + return; + cfs.supported = false; + cfs.exifValid = false; + cfs.timeValid = false; + + delete tpp; + tpp = NULL; + if (ext.lowercase()=="jpg" || ext.lowercase()=="png" || ext.lowercase()=="tif" || ext.lowercase()=="tiff") + tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, 1); + if (tpp) { + if (ext.lowercase()=="jpg") { + cfs.format = FT_Jpeg; + infoFromImage (fname); + } + else if (ext.lowercase()=="png") + cfs.format = FT_Png; + else if (ext.lowercase()=="tif" || ext.lowercase()=="tiff") { + cfs.format = FT_Tiff; + infoFromImage (fname); + } + } + else { + rtengine::RawMetaDataLocation ri; + tpp = rtengine::Thumbnail::loadFromRaw (fname, ri, tw, th, 1); + if (tpp) { + cfs.format = FT_Raw; + infoFromImage (fname, &ri); + } + } + if (tpp) { + // save thumbnail image to cache + saveThumbnail (); + cfs.supported = true; + } + needsReProcessing = true; + + cfs.save (getCacheFileName ("data")+".txt"); + + generateExifDateTimeStrings (); + + if (!internal) + mutex->unlock (); +} + +bool Thumbnail::isSupported () { + + return cfs.supported; +} + +const ProcParams& Thumbnail::getProcParams () { + + if (pparamsValid) + return pparams; + else { + rtengine::procparams::ProcParams* pp = profileStore.getDefaultProcParams (getType()==FT_Raw); + if (pp->wb.method=="Camera") { + double ct; + getCamWB (ct, pp->wb.green); + pp->wb.temperature = ct; + } + else if (pp->wb.method=="Auto") { + double ct; + getAutoWB (ct, pp->wb.green); + pp->wb.temperature = ct; + } + if (pp) + return *pp; + } + return pparams; // there is no valid pp to return, but we have to return something +} + +void Thumbnail::loadProcParams () { + + pparamsValid = false; + if (options.paramsLoadLocation==PLL_Input) { + // try to load it from pp2 file next to the image file + int ppres = pparams.load (fname + ".pp2"); + pparamsValid = !ppres && pparams.version>=220; + if (!pparamsValid) + pparamsValid = !pparams.load (getCacheFileName ("profiles")+".pp2"); + } + else { + // try to load it from cache + pparamsValid = !pparams.load (getCacheFileName ("profiles")+".pp2"); + // if no success, load it from pp2 file next to the image file + if (!pparamsValid) { + int ppres = pparams.load (fname + ".pp2"); + pparamsValid = !ppres && pparams.version>=220; + } + } +} + +void Thumbnail::clearProcParams (int whoClearedIt) { + + cfs.recentlySaved = false; + pparamsValid = false; + needsReProcessing = true; + // remove pp2 file from cache + Glib::ustring fname_ = getCacheFileName ("profiles")+".pp2"; + if (Glib::file_test (fname_, Glib::FILE_TEST_EXISTS)) + ::g_remove (fname_.c_str()); + // remove pp2 file located next to the file +// fname_ = removeExtension(fname) + ".pp2"; + fname_ = fname + ".pp2"; + if (Glib::file_test (fname_, Glib::FILE_TEST_EXISTS)) + ::g_remove (fname_.c_str()); + fname_ = removeExtension(fname) + ".pp2"; + if (Glib::file_test (fname_, Glib::FILE_TEST_EXISTS)) + ::g_remove (fname_.c_str()); + + for (int i=0; iprocParamsChanged (this, whoClearedIt); +} + +bool Thumbnail::hasProcParams () { + + return pparamsValid; +} + +void Thumbnail::setProcParams (const ProcParams& pp, int whoChangedIt, bool updateCacheNow) { + + if (pparams!=pp) + cfs.recentlySaved = false; + + pparams = pp; + pparamsValid = true; + needsReProcessing = true; + if (updateCacheNow) + updateCache (); + + for (int i=0; iprocParamsChanged (this, whoChangedIt); +} + +bool Thumbnail::isRecentlySaved () { + + return cfs.recentlySaved; +} + +void Thumbnail::imageDeveloped () { + + cfs.recentlySaved = true; + cfs.save (getCacheFileName ("data")+".txt"); + pparams.save (getCacheFileName ("profiles")+".pp2"); +} + +void Thumbnail::imageEnqueued () { + + enqueueNumber++; +} + +void Thumbnail::imageRemovedFromQueue () { + + enqueueNumber--; +} + +bool Thumbnail::isEnqueued () { + + return enqueueNumber > 0; +} + +void Thumbnail::increaseRef () { ref++; } +void Thumbnail::decreaseRef () { ref--; if (!ref) cachemgr->closeThumbnail (this); } + +void Thumbnail::getThumbnailSize (int &w, int &h) { + + if (tpp) + w = tpp->getImageWidth (getProcParams(), h); + else + w = tw * h / th; +} + +rtengine::IImage8* Thumbnail::processThumbImage (const rtengine::procparams::ProcParams& pparams, int h, double& scale) { + + mutex->lock (); + + if (!tpp) + return NULL; + + rtengine::IImage8* res = tpp->processImage (pparams, h, rtengine::TI_Bilinear, scale); + + mutex->unlock (); + return res; +} + +void Thumbnail::generateExifDateTimeStrings () { + + exifString = ""; + dateTimeString = ""; + + if (!cfs.exifValid) + return; + + exifString = Glib::ustring::compose ("f/%1 %2s %3%4", Glib::ustring(rtengine::ImageData::apertureToString(cfs.fnumber)), Glib::ustring(rtengine::ImageData::shutterToString(cfs.shutter)), M("QINFO_ISO"), cfs.iso); + + std::string dateFormat = options.dateFormat; + std::ostringstream ostr; + bool spec = false; + for (int i=0; ihasExif()) { + cfs.shutter = idata->getShutterSpeed (); + cfs.fnumber = idata->getFNumber (); + cfs.focalLen = idata->getFocalLen (); + cfs.iso = idata->getISOSpeed (); + cfs.year = 1900 + idata->getDateTime().tm_year; + cfs.month = idata->getDateTime().tm_mon + 1; + cfs.day = idata->getDateTime().tm_mday; + cfs.hour = idata->getDateTime().tm_hour; + cfs.min = idata->getDateTime().tm_min; + cfs.sec = idata->getDateTime().tm_sec; + cfs.timeValid = true; + cfs.exifValid = true; + cfs.lens = idata->getLens(); + cfs.camera = idata->getMake() + " " + idata->getModel(); + } + else { + cfs.lens = "Unknown"; + cfs.camera = "Unknown"; + } + delete idata; +} + +void Thumbnail::loadThumbnail (bool internal, bool firstTrial) { + + if (!internal) + mutex->lock (); + + needsReProcessing = true; + delete tpp; + tpp = new rtengine::Thumbnail (); + tpp->isRaw = (cfs.format == (int) FT_Raw); + + // load supplementary data + bool succ = tpp->readData (getCacheFileName ("data")+".txt"); + + // thumbnail image + succ = succ && tpp->readImage (getCacheFileName ("images")); + + if (!succ && firstTrial) { + generateThumbnailImage (true); + if (cfs.supported && firstTrial) + loadThumbnail (true, false); + } + else if (!succ) { + delete tpp; + tpp = NULL; + } + else { + // load aehistogram + tpp->readAEHistogram (getCacheFileName ("aehistograms")); + + // load embedded profile + tpp->readEmbProfile (getCacheFileName ("embprofiles")+".icc"); + + tpp->init (); + + } + if (!internal) + mutex->unlock (); +} + +void Thumbnail::saveThumbnail () { + + if (!tpp) + return; + + ::g_remove ((getCacheFileName ("images")+".cust").c_str()); + ::g_remove ((getCacheFileName ("images")+".cust16").c_str()); + ::g_remove ((getCacheFileName ("images")+".jpg").c_str()); + + // save thumbnail image + if (options.thumbnailFormat == FT_Custom) + tpp->writeImage (getCacheFileName ("images")+".cust", 1); + else if (options.thumbnailFormat == FT_Custom16) + tpp->writeImage (getCacheFileName ("images")+".cust16", 2); + else if (options.thumbnailFormat == FT_Jpeg) + tpp->writeImage (getCacheFileName ("images")+".jpg", 3); + + // save aehistogram + tpp->writeAEHistogram (getCacheFileName ("aehistograms")); + + // save embedded profile + tpp->writeEmbProfile (getCacheFileName ("embprofiles")+".icc"); + + // save supplementary data + tpp->writeData (getCacheFileName ("data")+".txt"); +} + +void Thumbnail::updateCache () { + + if (pparamsValid) { + if (options.saveParamsCache) + pparams.save (getCacheFileName ("profiles")+".pp2"); + if (options.saveParamsFile) +// pparams.save (removeExtension(fname) + ".pp2"); + pparams.save (fname + ".pp2"); + } + cfs.save (getCacheFileName ("data")+".txt"); +} + +Thumbnail::~Thumbnail () { + + delete [] lastImg; + delete tpp; +} + +Glib::ustring Thumbnail::getCacheFileName (Glib::ustring subdir) { + + return cachemgr->getCacheFileName (subdir, fname, cfs.md5); +} + +void Thumbnail::setFileName (const Glib::ustring fn) { + + fname = fn; + cfs.md5 = cachemgr->getMD5 (fname); +} + +void Thumbnail::addThumbnailListener (ThumbnailListener* tnl) { + + listeners.push_back (tnl); +} + +void Thumbnail::removeThumbnailListener (ThumbnailListener* tnl) { + + std::vector::iterator f = std::find (listeners.begin(), listeners.end(), tnl); + if (f!=listeners.end()) + listeners.erase (f); +} + diff --git a/rtgui/thumbnail.h b/rtgui/thumbnail.h new file mode 100755 index 000000000..389e8e872 --- /dev/null +++ b/rtgui/thumbnail.h @@ -0,0 +1,130 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _THUMBNAIL_ +#define _THUMBNAIL_ + +#include +#include +#include +#include +#include +#include +#include +#include + +class CacheManager; +class Thumbnail { + + Glib::Mutex* mutex; + + Glib::ustring fname; // file name corresponding to the thumbnail + CacheImageData cfs; // cache entry corresponding to the thumbnail + CacheManager* cachemgr; // parent + int ref; // variable for reference counting + int enqueueNumber; // the number of instances in the batch queue corresponding to this thumbnail + + // if the thumbnail is in processed mode, this class holds its data: + rtengine::Thumbnail* tpp; + int tw, th; // dimensions of timgdata (it stores tpp->width and tpp->height in processed mode for simplicity) +// double scale; // portion of the sizes of the processed thumbnail image and the full scale image + + rtengine::procparams::ProcParams pparams; + bool pparamsValid; + bool pparamsSet; + bool needsReProcessing; + + // these are the data of the result image of the last getthumbnailimage call (for caching purposes) + unsigned char* lastImg; + int lastW; + int lastH; + + // exif & date/time strings + Glib::ustring exifString; + Glib::ustring dateTimeString; + + // vector of listeners + std::vector listeners; + + void infoFromImage (const Glib::ustring& fname, rtengine::RawMetaDataLocation* rml=NULL); + void loadThumbnail (bool internal=false, bool firstTrial=true); + void saveThumbnail (); + void generateExifDateTimeStrings (); + + Glib::ustring getCacheFileName (Glib::ustring subdir); + + public: + Thumbnail (CacheManager* cm, const Glib::ustring& fname, CacheImageData* cf); + Thumbnail (CacheManager* cm, const Glib::ustring& fname, const std::string& md5); + ~Thumbnail (); + + bool hasProcParams (); + const rtengine::procparams::ProcParams& getProcParams (); + void setProcParams (const rtengine::procparams::ProcParams& pp, int whoChangedIt=-1, bool updateCacheNow=true); + void clearProcParams (int whoClearedIt=-1); + void loadProcParams (); + + bool isRecentlySaved (); + void imageDeveloped (); + void imageEnqueued (); + void imageRemovedFromQueue (); + bool isEnqueued (); + +// unsigned char* getThumbnailImage (int &w, int &h, int fixwh=1); // fixwh = 0: fix w and calculate h, =1: fix h and calculate w + rtengine::IImage8* processThumbImage (const rtengine::procparams::ProcParams& pparams, int h, double& scale); + void processThumbImage2 (const rtengine::procparams::ProcParams& pparams, int h, rtengine::IImage8*& img, double& scale) { img = processThumbImage(pparams, h, scale); } + void getThumbnailSize (int &w, int &h); + void getFinalSize (const rtengine::procparams::ProcParams& pparams, int& w, int& h) { if (tpp) tpp->getFinalSize (pparams, w, h); } + + void generateThumbnailImage (bool internal=false); + + const Glib::ustring& getExifString (); + const Glib::ustring& getDateTimeString (); + void getCamWB (double& temp, double& green) { if (tpp) tpp->getCamWB (temp, green); } + void getAutoWB (double& temp, double& green) { if (tpp) tpp->getAutoWB (temp, green); } + void getSpotWB (int x, int y, int rect, double& temp, double& green) { if (tpp) tpp->getSpotWB (getProcParams(), x, y, rect, temp, green); } + void applyAutoExp (rtengine::procparams::ProcParams& pparams) { if (tpp) tpp->applyAutoExp (pparams); } + + ThFileType getType (); + Glib::ustring getFileName () { return fname; } + void setFileName (const Glib::ustring fn); + + bool isSupported (); + + const CacheImageData* getCacheImageData() { return &cfs; } + std::string getMD5 () { return cfs.md5; } + + int getRank () { return cfs.rank; } + void setRank (int rank) { cfs.rank = rank; } + + int getStage () { return cfs.inTrash; } + void setStage (int stage) { cfs.inTrash = stage; } + + void addThumbnailListener (ThumbnailListener* tnl); + void removeThumbnailListener (ThumbnailListener* tnl); + + void increaseRef (); + void decreaseRef (); + + void updateCache (); + void reSaveThumbnail () { mutex->lock (); saveThumbnail(); mutex->unlock(); } +}; + + +#endif + diff --git a/rtgui/thumbnail_old.cc b/rtgui/thumbnail_old.cc new file mode 100755 index 000000000..d3735785d --- /dev/null +++ b/rtgui/thumbnail_old.cc @@ -0,0 +1,1080 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +extern "C" { +#include +extern jmp_buf jpeg_jmp_buf; +extern GLOBAL(struct jpeg_error_mgr *) +my_jpeg_std_error (struct jpeg_error_mgr * err); +extern GLOBAL(void) +my_jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile); +} +#include +#include + +using namespace rtengine::procparams; +using namespace rtengine; + +Thumbnail::Thumbnail (CacheManager* cm, const Glib::ustring& fname, CacheFileStruct* cf, int fpos) + : cachemgr(cm), cfs(cf), tImgData(NULL), tw(-1), th(-1), pparamsValid(false), filePos(fpos), fname(fname), + lastImg(NULL), ref(1), enqueueNumber(0), tpp(NULL), needsReProcessing(true) { + + mutex = new Glib::Mutex (); + + loadProcParams (); + if (options.liveThumbnails!=cfs->thumbProcessed) { + cfs->thumbProcessed = options.liveThumbnails; + generateThumbnailImage (false); + } + if (!tImgData || !tpp) + loadThumbnail (options.thumbCacheMemPolicy==MP_Memory); +} + +Thumbnail::Thumbnail (CacheManager* cm, const Glib::ustring& fname, const std::string& md5, CacheFileStruct* cf, int fpos) + : cachemgr(cm), cfs(cf), pparamsValid(false), filePos(fpos), lastImg(NULL), tImgData(NULL), fname(fname), + ref(1), enqueueNumber(0), tpp(NULL), needsReProcessing(true) { + + mutex = new Glib::Mutex (); + + memcpy (cfs->MD5, md5.c_str(), 32); + cfs->ppformat = 0; + cfs->preinterp = 0; + cfs->accessed = -1; + cfs->rank = 0; + cfs->stage = 0; + cfs->thumbnail = FT_Invalid; + cfs->recentlySaved = false; + cfs->thumbProcessed = options.liveThumbnails; + + generateThumbnailImage (false); +} + +void Thumbnail::generateThumbnailImage (bool useLock) { + + mutex->lock (); + + if (cfs->thumbProcessed) + generateProcessedThumbnailImage (useLock); + else + generatePreviewThumbnailImage (useLock); + + mutex->unlock (); +} + +void Thumbnail::generatePreviewThumbnailImage (bool useLock) { + +// delete everything loaded into memory + delete tpp; + tpp = NULL; + delete [] lastImg; + lastImg = NULL; + tw = -1; + th = options.maxThumbnailHeight; + delete [] tImgData; + tImgData = NULL; + +// generate thumbnail image + int lastdot = fname.find_last_of ('.'); + if (lastdot==Glib::ustring::npos) + return; + + cfs->thumbnail = (int) options.thumbnailFormat; + Glib::ustring ext = fname.substr (lastdot); + cfs->supported = false; + cfs->exifValid = 0; + cfs->timeValid = 0; + if (ext.lowercase()==".jpg") { + // try to load it as jpeg + int thumbW, thumbH; + int res = loadJPEGThumbnail (0, tImgData, tw, th); + if (!res) { + cfs->format = (int) FT_Jpeg; + infoFromImage (fname); + cfs->supported = true; + } + else { + // try to let it load by dcraw + rtengine::RawMetaDataLocation ri; + res = getRawFileBasicInfo (fname, ri, cfs->rotate, thumbW, thumbH, cfs->thumbOffset, cfs->thumbImgType); + if (!res) { + cfs->format = (int) FT_Raw; + infoFromImage (fname, &ri); + cfs->supported = true; + if (cfs->thumbImgType == 1) + loadJPEGThumbnail (cfs->thumbOffset, tImgData, tw, th, cfs->rotate); + else if (cfs->thumbImgType == 2) + loadPPMThumbnail (cfs->thumbOffset, thumbW, thumbH, tImgData, tw, th, cfs->rotate); + else { + cfs->thumbnail = (int) FT_None; + tw = th * thumbW / thumbH; + } + + } + } + } + else if (ext.lowercase()==".tif" || ext.lowercase()==".tiff") { + // try to detect it as raw file first + int thumbW, thumbH; + rtengine::RawMetaDataLocation ri; + if (!getRawFileBasicInfo (fname, ri, cfs->rotate, thumbW, thumbH, cfs->thumbOffset, cfs->thumbImgType)) { + cfs->format = (int) FT_Raw; + infoFromImage (fname, &ri); + cfs->supported = true; + if (cfs->thumbImgType == 1) + loadJPEGThumbnail (cfs->thumbOffset, tImgData, tw, th, cfs->rotate); + else if (cfs->thumbImgType == 2) + loadPPMThumbnail (cfs->thumbOffset, thumbW, thumbH, tImgData, tw, th, cfs->rotate); + else { + cfs->thumbnail = (int) FT_None; + tw = th * thumbW / thumbH; + } + } + else if (!loadTIFFThumbnail (tImgData, tw, th)) { + cfs->format = (int) FT_Tiff; + infoFromImage (fname); + cfs->supported = true; + } + } + else if (ext.lowercase()==".png") { + int res = loadPNGThumbnail (tImgData, tw, th); + if (!res) { + cfs->format = (int) FT_Png; + cfs->supported = true; + } + } + else { + int thumbW, thumbH; + rtengine::RawMetaDataLocation ri; + if (!getRawFileBasicInfo (fname, ri, cfs->rotate, thumbW, thumbH, cfs->thumbOffset, cfs->thumbImgType)) { + cfs->format = (int) FT_Raw; + infoFromImage (fname, &ri); + cfs->supported = true; + if (cfs->thumbImgType == 1) + loadJPEGThumbnail (cfs->thumbOffset, tImgData, tw, th, cfs->rotate); + else if (cfs->thumbImgType == 2) + loadPPMThumbnail (cfs->thumbOffset, thumbW, thumbH, tImgData, tw, th, cfs->rotate); + else { + cfs->thumbnail = (int) FT_None; + tw = th * thumbW / thumbH; + } + } + } + + cfs->thumbProcessed = 0; +// save thumbnail image to cache + if (cfs->supported) { + saveThumbnail (); + if (options.thumbCacheMemPolicy==MP_Memory) { + delete [] tImgData; + tImgData = NULL; + } + } + updateCache (true, true, useLock); +} + +void Thumbnail::generateProcessedThumbnailImage (bool useLock) { + +// delete everything loaded into memory + delete tpp; + tpp = NULL; + delete [] lastImg; + lastImg = NULL; + tw = -1; + th = options.maxThumbnailHeight; + delete [] tImgData; + tImgData = NULL; + +// generate thumbnail image + int lastdot = fname.find_last_of ('.'); + if (lastdot==Glib::ustring::npos) + return; + + cfs->thumbnail = (int) options.thumbnailFormat; + Glib::ustring ext = fname.substr (lastdot); + cfs->supported = false; + cfs->exifValid = 0; + cfs->timeValid = 0; + + delete tpp; + tpp = NULL; + if (ext.lowercase()==".jpg" || ext.lowercase()==".tif" || ext.lowercase()==".tiff" || ext.lowercase()==".png") + tpp = ThumbnailProcessingParameters::loadFromImage (fname, tw, th, 1); + + if (tpp) { + if (ext.lowercase()==".jpg") { + cfs->format = (int) FT_Jpeg; + infoFromImage (fname); + } + else if (ext.lowercase()==".tif" || ext.lowercase()==".tiff") { + cfs->format = (int) FT_Tiff; + infoFromImage (fname); + } + else if (ext.lowercase()==".png") + cfs->format = (int) FT_Png; + } + else { + rtengine::RawMetaDataLocation ri; + tpp = ThumbnailProcessingParameters::loadFromRaw (fname, ri, tw, th, 1); + if (tpp) { + cfs->format = (int) FT_Raw; + infoFromImage (fname, &ri); + } + } + if (tpp) { + cfs->supported = true; + cfs->camwbRed = tpp->camwbRed; + cfs->camwbGreen = tpp->camwbGreen; + cfs->camwbBlue = tpp->camwbBlue; + cfs->autowbTemp = tpp->autowbTemp; + cfs->autowbGreen = tpp->autowbGreen; + cfs->aeHistCompression = tpp->aeHistCompression; + cfs->embProfileLength = tpp->embProfileLength; + cfs->redMultiplier = tpp->redMultiplier; + cfs->greenMultiplier = tpp->greenMultiplier; + cfs->blueMultiplier = tpp->blueMultiplier; + cfs->scale = tpp->scale; + cfs->defGain = tpp->defGain; + cfs->scaleForSave = tpp->scaleForSave; + cfs->gammaCorrected = tpp->gammaCorrected; + memcpy (cfs->colorMatrix, tpp->colorMatrix, sizeof (cfs->colorMatrix)); +/* IImage8* res = tpp->processImage (getProcParams ()); + tw = res->getWidth (); + th = res->getHeight (); + tImgData = new unsigned char [tw*th*3]; + memcpy (tImgData, res->getData (), tw*th*3); + res->free ();*/ + } + + cfs->thumbProcessed = 1; +// save thumbnail image to cache + if (cfs->supported) { + saveThumbnail (); + if (options.thumbCacheMemPolicy==MP_Memory) { + delete tpp; + tpp = NULL; +// delete [] tImgData; +// tImgData = NULL; + } + } + + updateCache (true, true, useLock); + needsReProcessing = true; +} + +bool Thumbnail::isSupported () { + + return cfs->supported; +} + +const ProcParams& Thumbnail::getProcParams () { + + if (pparamsValid) + return pparams; + else { + rtengine::procparams::ProcParams* pp = profileStore.getDefaultProcParams (getType()==FT_Raw); + if (pp) + return *pp; + } + return pparams; // there is no valid pp to return, but we have to return something +} + +void Thumbnail::loadProcParams () { + + pparamsValid = false; + if (options.paramsLoadLocation==PLL_Input) { + // try to load it from pp2 file next to the image file + int ppres = pparams.load (removeExtension(fname) + ".pp2"); + pparamsValid = !ppres && pparams.version>=220; + // if no success, load it from the cache + if (!pparamsValid) + pparamsValid = !pparams.load (getCacheFileName ("profiles")+".pp2"); + } + else { + // try to load it from cache + pparamsValid = !pparams.load (getCacheFileName ("profiles")+".pp2"); + // if no success, load it from pp2 file next to the image file + if (!pparamsValid) { + int ppres = pparams.load (removeExtension(fname) + ".pp2"); + pparamsValid = !ppres && pparams.version>=220; + } + } +} + +void Thumbnail::clearProcParams () { + + cfs->recentlySaved = false; + cfs->ppformat = 0; + pparamsValid = false; + needsReProcessing = true; + // remove pp2 file from cache + Glib::ustring fname_ = getCacheFileName ("profiles")+".pp2"; + if (Glib::file_test (fname_, Glib::FILE_TEST_EXISTS)) + ::g_remove (fname_.c_str()); + // remove pp2 file located next to the file + fname_ = removeExtension(fname) + ".pp2"; + if (Glib::file_test (fname_, Glib::FILE_TEST_EXISTS)) + ::g_remove (fname_.c_str()); +} + +bool Thumbnail::hasProcParams () { + + return pparamsValid; +} + +void Thumbnail::setProcParams (const ProcParams& pp, bool updateCacheNow) { + + if (pparams!=pp) + cfs->recentlySaved = false; + + pparams = pp; + pparamsValid = true; + needsReProcessing = true; + if (updateCacheNow) + pparams.save (getCacheFileName ("profiles")+".pp2"); +} + +bool Thumbnail::isRecentlySaved () { + + return cfs->recentlySaved; +} + +void Thumbnail::imageDeveloped () { + + cfs->recentlySaved = true; + updateCache (false, false); +} + +void Thumbnail::imageEnqueued () { + + enqueueNumber++; +} + +void Thumbnail::imageRemovedFromQueue () { + + enqueueNumber--; +} + +bool Thumbnail::isEnqueued () { + + return enqueueNumber > 0; +} + +void Thumbnail::increaseRef () { ref++; } +void Thumbnail::decreaseRef () { ref--; if (!ref) cachemgr->closeThumbnail (this); } + +void Thumbnail::getThumbnailSize (int &w, int &h, int fixwh) { // fixwh = 0: fix w and calculate h, =1: fix h and calculate w + + mutex->lock (); + + if (fixwh==1) + w = tw * h / th; + else if (fixwh==0) + h = th * w / tw; + + mutex->unlock (); +} + +unsigned char* Thumbnail::getThumbnailImage (int &w, int &h, int fixwh) { // fixwh = 0: fix w and calculate h, =1: fix h and calculate w + + getThumbnailSize (w, h, fixwh); + + mutex->lock (); + + // if the result of last query fits the needs, we just have to return it + if (lastImg && lastW==w && lastH==h && !(cfs->thumbProcessed && needsReProcessing)) { + mutex->unlock (); + return lastImg; + } + else + delete [] lastImg; + + if (!cfs->thumbProcessed) { + // if thumbnail not loaed yet, load it + if (!tImgData) { + loadThumbnail (); + if (!tImgData) { + if (fixwh==1) + w = tw * h / th; + else if (fixwh==0) + h = th * w / tw; + mutex->unlock (); + return NULL; + } + } + lastW = w; + lastH = h; + lastImg = new unsigned char [lastW*lastH*3]; + thumbInterp (tImgData, tw, th, lastImg, w, h); + } + else { + if (!tpp) + loadThumbnail (); + IImage8* res = tpp->processImage (getProcParams (), h, TI_Bilinear); + lastW = w = res->getWidth (); + lastH = h = res->getHeight (); + lastImg = new unsigned char [lastW*lastH*3]; + memcpy (lastImg, res->getData(), lastW*lastH*3); + res->free (); + needsReProcessing = false; + } + + // if we have to spare with memory, delete full res thumb image from memory + if (options.thumbCacheMemPolicy==MP_Memory) { + delete [] tImgData; + delete tpp; + tpp = NULL; + tImgData = NULL; + } + + mutex->unlock (); + return lastImg; +} + +Glib::ustring Thumbnail::getExifString () { + + if (!cfs->exifValid) + return ""; + + std::ostringstream s; + s << "f/" << ImageData::apertureToString(cfs->fnumber) << " "; + s << ImageData::shutterToString(cfs->shutter) << "s "; + s << "ISO" << cfs->iso; + + return s.str(); +} + +Glib::ustring Thumbnail::getDateTimeString () { + + if (!cfs->timeValid) + return ""; + std::string dateFormat = options.dateFormat; + std::ostringstream ostr; + bool spec = false; + for (int i=0; iyear; + spec = false; + } + else if (spec && dateFormat[i]=='m') { + ostr << (int)cfs->month; + spec = false; + } + else if (spec && dateFormat[i]=='d') { + ostr << (int)cfs->day; + spec = false; + } + else if (dateFormat[i]=='%') + spec = true; + else { + ostr << (char)dateFormat[i]; + spec = false; + } + ostr << " " << (int)cfs->hour << ":" << (int)cfs->min << ":" << (int)cfs->sec; + return ostr.str (); +} + +ThFileType Thumbnail::getType () { + + return (ThFileType) cfs->format; +} + +void Thumbnail::infoFromImage (const Glib::ustring& fname, rtengine::RawMetaDataLocation* rml) { + + ImageMetaData* idata = ImageMetaData::fromFile (fname, rml); + if (!idata) + return; + cfs->timeValid = false; + cfs->exifValid = false; + if (idata->hasExif()) { + cfs->shutter = idata->getShutterSpeed (); + cfs->fnumber = idata->getFNumber (); + cfs->focalLen = idata->getFocalLen (); + cfs->iso = idata->getISOSpeed (); + cfs->year = 1900 + idata->getDateTime().tm_year; + cfs->month = idata->getDateTime().tm_mon + 1; + cfs->day = idata->getDateTime().tm_mday; + cfs->hour = idata->getDateTime().tm_hour; + cfs->min = idata->getDateTime().tm_min; + cfs->sec = idata->getDateTime().tm_sec; + cfs->timeValid = true; + cfs->exifValid = true; + cfs->lens = idata->getLens(); + cfs->camera = idata->getMake() + " " + idata->getModel(); + } + delete idata; +} + +void Thumbnail::loadThumbnail (bool sizeOnly) { + + mutex->lock (); + + delete tImgData; + delete tpp; + tImgData = NULL; + tpp = NULL; + needsReProcessing = true; + + if (cfs->thumbnail == FT_None) + return; + + unsigned char* data = NULL; + Glib::ustring fname = getCacheFileName ("images"); + int imgType = 0; + if (Glib::file_test (fname+".cust", Glib::FILE_TEST_EXISTS)) + imgType = 1; + else if (Glib::file_test (fname+".jpg", Glib::FILE_TEST_EXISTS)) + imgType = 2; + + + FILE* f = g_fopen (fname.c_str(), "rb"); + if (!f || !imgType) { + if (f) + fclose(f); + mutex->unlock (); + generateThumbnailImage (); + if (cfs->supported) + loadThumbnail (sizeOnly); + else + return; + } + else if (imgType==1) { + fread (&tw, 1, sizeof (int), f); + fread (&th, 1, sizeof (int), f); + if (!sizeOnly) { + data = new unsigned char [tw*th*3]; + fread (data, tw*th, 3, f); + } + fclose (f); + } + else if (imgType==2) { + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + if (!setjmp(jpeg_jmp_buf)) { + cinfo.err = my_jpeg_std_error (&jerr); + jpeg_create_decompress (&cinfo); + my_jpeg_stdio_src (&cinfo,f); + jpeg_read_header (&cinfo, TRUE); + tw = cinfo.image_width; + th = cinfo.image_height; + if (!sizeOnly) { + cinfo.dct_method = JDCT_FASTEST; + cinfo.do_fancy_upsampling = 1; + jpeg_start_decompress(&cinfo); + data = new unsigned char [tw*th*3]; + while (cinfo.output_scanline < cinfo.output_height) { + unsigned char* row = data + cinfo.output_scanline*tw*3; + jpeg_read_scanlines (&cinfo, &row, 1); + } + jpeg_finish_decompress (&cinfo); + } + jpeg_destroy_decompress (&cinfo); + fclose (f); + } + else { + fclose (f); + mutex->unlock (); + return; + } + } + if (!cfs->thumbProcessed) { + tImgData = data; + } + else if (!sizeOnly) { + tpp = new ThumbnailProcessingParameters (); + tpp->data = data; + tpp->width = tw; + tpp->height = th; + tpp->camwbRed = cfs->camwbRed; + tpp->camwbGreen = cfs->camwbGreen; + tpp->camwbBlue = cfs->camwbBlue; + tpp->autowbTemp = cfs->autowbTemp; + tpp->autowbGreen = cfs->autowbGreen; + tpp->aeHistCompression = cfs->aeHistCompression; + FILE* f = fopen (getCacheFileName ("aehistograms").c_str(), "rb"); + if (!f) + tpp->aeHistogram = NULL; + else { + tpp->aeHistogram = new int[65536>>tpp->aeHistCompression]; + fread (tpp->aeHistogram, 1, (65536>>tpp->aeHistCompression)*sizeof(int), f); + fclose (f); + } + tpp->embProfileLength = cfs->embProfileLength; + Glib::ustring pfName = getCacheFileName ("embprofiles")+".icc"; + f = fopen (pfName.c_str(), "rb"); + if (!f) { + tpp->embProfileData = NULL; + tpp->embProfile = NULL; + } + else { + tpp->embProfileData = new unsigned char[tpp->embProfileLength]; + fread (tpp->embProfileData, 1, tpp->embProfileLength, f); + fclose (f); + tpp->embProfile = cmsOpenProfileFromMem (tpp->embProfileData, tpp->embProfileLength); + } + tpp->redMultiplier = cfs->redMultiplier; + tpp->greenMultiplier = cfs->greenMultiplier; + tpp->blueMultiplier = cfs->blueMultiplier; + tpp->scale = cfs->scale; + tpp->defGain = cfs->defGain; + tpp->scaleForSave = cfs->scaleForSave; + tpp->gammaCorrected = cfs->gammaCorrected; + tpp->isRaw = (cfs->format == (int) FT_Raw); + memcpy (tpp->colorMatrix, cfs->colorMatrix, sizeof (tpp->colorMatrix)); + tpp->init (); + } + mutex->unlock (); +} + +void Thumbnail::saveThumbnail () { + + if (!tImgData && !tpp) + return; + + unsigned char* data = tImgData; + int w = tw, h = th; + + if (cfs->thumbProcessed && tpp) { + data = tpp->data; + w = tpp->width; + h = tpp->height; + } + + if (data) { + if (cfs->thumbnail == FT_Custom) { + Glib::ustring fname = getCacheFileName ("images")+".cust"; + FILE* f = g_fopen (fname.c_str(), "wb"); + if (!f) + return; + fwrite (&w, 1, sizeof (int), f); + fwrite (&h, 1, sizeof (int), f); + fwrite (data, w*h, 3, f); + fclose (f); + } + else if (cfs->thumbnail == FT_Jpeg) { + Glib::ustring fname = getCacheFileName ("images")+".jpg"; + FILE* f = g_fopen (fname.c_str(), "wb"); + if (!f) + return; + jpeg_compress_struct cinfo; + jpeg_error_mgr jerr; + cinfo.err = jpeg_std_error (&jerr); + jpeg_create_compress (&cinfo); + jpeg_stdio_dest (&cinfo, f); + cinfo.image_width = w; + cinfo.image_height = h; + cinfo.in_color_space = JCS_RGB; + cinfo.input_components = 3; + jpeg_set_defaults (&cinfo); + cinfo.write_JFIF_header = FALSE; + jpeg_set_quality (&cinfo, 85, true); + jpeg_start_compress(&cinfo, TRUE); + int rowlen = w*3; + while (cinfo.next_scanline < cinfo.image_height) { + unsigned char* row = data + cinfo.next_scanline*w*3; + if (jpeg_write_scanlines (&cinfo, &row, 1) < 1) { + jpeg_finish_compress (&cinfo); + jpeg_destroy_compress (&cinfo); + fclose (f); + return; + } + } + jpeg_finish_compress (&cinfo); + jpeg_destroy_compress (&cinfo); + fclose (f); + } + } + + if (tpp) { + // save aehistogram + if (tpp->aeHistogram) { + FILE* f = fopen (getCacheFileName ("aehistograms").c_str(), "wb"); + if (f) { + fwrite (tpp->aeHistogram, 1, (65536>>tpp->aeHistCompression)*sizeof(int), f); + fclose (f); + } + } + // save embedded profile + if (tpp->embProfileLength) { + Glib::ustring pfName = getCacheFileName ("embprofiles")+".icc"; + FILE* f = fopen (pfName.c_str(), "wb"); + if (f) { + fwrite (tpp->embProfileData, 1, tpp->embProfileLength, f); + fclose (f); + } + } + } +} + +void Thumbnail::updateCache (bool savePparams, bool saveThumbImg, bool useLock) { + + if (filePos>=0) { + + if (pparamsValid) + cfs->ppformat = 1; + else + cfs->ppformat = 0; + + if (pparamsValid && savePparams) { + if (options.saveParamsCache) + pparams.save (getCacheFileName ("profiles")); + if (options.saveParamsFile) + pparams.save (removeExtension(fname) + ".pp2"); + } + + cachemgr->saveThumbnail (this, useLock); + } +} + +Thumbnail::~Thumbnail () { + + delete [] lastImg; + delete [] tImgData; +} + +Glib::ustring Thumbnail::getCacheFileName (Glib::ustring subdir) { + + Glib::ustring cfn = cachemgr->getBaseDir() + "/" + subdir + "/"; + for (int i=0; i<32; i++) + cfn += cfs->MD5[i]; + return cfn; +} + +int Thumbnail::loadJPEGThumbnail (int offset, unsigned char* &data, int &width, int &height, int degree, int fixwh) { + + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + + data = NULL; + + FILE* f = g_fopen (fname.c_str(), "rb"); + + if (!f) + return 2; + fseek (f, offset, SEEK_SET); + + if (!setjmp(jpeg_jmp_buf)) { + + cinfo.err = my_jpeg_std_error (&jerr); + jpeg_create_decompress (&cinfo); + my_jpeg_stdio_src (&cinfo,f); + jpeg_read_header (&cinfo, TRUE); + cinfo.dct_method = JDCT_FASTEST; + cinfo.scale_num = 1; + + if (fixwh==1) { + if (degree==0 || degree==180) + width = height * cinfo.image_width / cinfo.image_height; + else + width = height * cinfo.image_height / cinfo.image_width; + } + else { + if (degree==0 || degree==180) + height = width * cinfo.image_height / cinfo.image_width; + else + height = width * cinfo.image_width / cinfo.image_height; + } + + if (cinfo.image_width > 8*width && cinfo.image_height > 8*height ) + cinfo.scale_denom = 8; + else if (cinfo.image_width > 4*width && cinfo.image_height > 4*height ) + cinfo.scale_denom = 4; + else if (cinfo.image_width > 2*width && cinfo.image_height > 2*height ) + cinfo.scale_denom = 2; + else + cinfo.scale_denom = 1; + + cinfo.do_fancy_upsampling = 1; + jpeg_start_decompress(&cinfo); + unsigned char* fullData = new unsigned char [3*cinfo.output_height*cinfo.output_width]; + unsigned char* row = fullData; + for (int i=0; iio_ptr); + if (check != length) + png_error(png_ptr, "Read Error"); +} + +int Thumbnail::loadPNGThumbnail (unsigned char* &data, int &width, int &height, int fixwh) { + + + data = NULL; + + FILE *file=g_fopen(fname.c_str(),"rb"); + if (!file) return 2; + + //reading PNG header + unsigned char header[8]; + fread(header,1,8,file); + if (!png_check_sig(header,8)) { + fclose(file); + return 3; + } + //initializing main structures + png_structp png= png_create_read_struct(PNG_LIBPNG_VER_STRING,0,0,0); + if (!png) { + fclose(file); + return 4; + } + png_infop info= png_create_info_struct(png); + png_infop end_info = png_create_info_struct(png); + if (!end_info || !info) { + png_destroy_read_struct(&png,&info,&end_info); + fclose(file); + return 5; + } + + if (setjmp(png_jmpbuf(png))) { + png_destroy_read_struct(&png,&info,&end_info); + fclose(file); + return 3; + } + + //set up png read + png_set_read_fn(png, file, png_read_data); + png_set_sig_bytes(png,8); + + png_read_info(png,info); + + //retrieving image information + unsigned long fwidth, fheight; + int bit_depth,color_type,interlace_type,compression_type,filter_method; + png_get_IHDR(png,info,&fwidth,&fheight,&bit_depth,&color_type,&interlace_type, + &compression_type, &filter_method); + + //converting to 32bpp format + if (color_type==PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png); + + if (color_type==PNG_COLOR_TYPE_GRAY || color_type==PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(png); + + if (png_get_valid(png,info,PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png); + + if (interlace_type!=PNG_INTERLACE_NONE) { + fclose (file); + return 6; + } + + if (color_type & PNG_COLOR_MASK_ALPHA) + png_set_strip_alpha(png); + + if (bit_depth==16) + png_set_strip_16(png); + + //setting gamma + double gamma; + if (png_get_gAMA(png,info,&gamma)) + png_set_gamma(png, 2.0, gamma); + else + png_set_gamma(png, 1.0, 1.0); + + //updating png info struct + png_read_update_info(png,info); + png_get_IHDR(png,info,&fwidth,&fheight,&bit_depth,&color_type,&interlace_type, + &compression_type, &filter_method); + + if (color_type & PNG_COLOR_MASK_ALPHA) + png_set_strip_alpha(png); + if (bit_depth==16) + png_set_strip_16(png); + + png_read_update_info(png,info); + png_get_IHDR(png,info,&fwidth,&fheight,&bit_depth,&color_type,&interlace_type, + &compression_type, &filter_method); + + png_timep time; + cfs->timeValid = png_get_tIME (png, info, &time); + cfs->exifValid = 0; + cfs->year = time->year; + cfs->month = time->month; + cfs->day = time->day; + cfs->hour = time->hour; + cfs->min = time->minute; + cfs->sec = time->second; + + if (fixwh==1) + width = height * fwidth / fheight; + else + height = width * fheight / fwidth; + + unsigned char* fullData = new unsigned char [3*fheight*fwidth]; + unsigned char* row = fullData; + for (int i=0; i> 8; + } + TIFFClose(in); + delete [] linebuffer; + } + else if (bitspersample == 8) { + for (int i=0; i + * + * 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 . + */ +#ifndef _THUMBNAIL_ +#define _THUMBNAIL_ + +#include +#include +#include +#include +#include +#include + +class CacheManager; +class Thumbnail { + + Glib::Mutex* mutex; + + Glib::ustring fname; // file name corresponding to the thumbnail + CacheImageData* cfs; // cache entry corresponding to the thumbnail + CacheManager* cachemgr; // parent + int ref; // variable for reference counting + int enqueueNumber; // the number of instances in the batch queue corresponding to this thumbnail + + // if the thumbnail is in non-processed mode, these fields hold the thumbnail image: + unsigned char* tImgData; + int tw, th; // dimensions of timgdata (it stores tpp->width and tpp->height in processed mode for simplicity) + + // if the thumbnail is in processed mode, this class holds its data: + rtengine::ThumbnailProcessingParameters* tpp; + + rtengine::procparams::ProcParams pparams; + bool pparamsValid; + bool pparamsSet; + bool needsReProcessing; + + // these are the data of the result image of the last getthumbnailimage call (for caching purposes) + unsigned char* lastImg; + int lastW; + int lastH; + + void infoFromImage (const Glib::ustring& fname, rtengine::RawMetaDataLocation* rml=NULL); + void loadThumbnail (bool sizeOnly=false); + void saveThumbnail (); + void generateProcessedThumbnailImage (bool useLock=true); + void generatePreviewThumbnailImage (bool useLock=true); + + + Glib::ustring getCacheFileName (Glib::ustring subdir); + + public: + Thumbnail (CacheManager* cm, const Glib::ustring& fname, CacheImageData* cf); + Thumbnail (CacheManager* cm, const Glib::ustring& fname, const std::string& md5); + ~Thumbnail (); + + bool hasProcParams (); + const rtengine::procparams::ProcParams& getProcParams (); + void setProcParams (const rtengine::procparams::ProcParams& pp, bool updateCacheNow=true); + void clearProcParams (); + void loadProcParams (); + + bool isRecentlySaved (); + void imageDeveloped (); + void imageEnqueued (); + void imageRemovedFromQueue (); + bool isEnqueued (); + + unsigned char* getThumbnailImage (int &w, int &h, int fixwh=1); // fixwh = 0: fix w and calculate h, =1: fix h and calculate w + void getThumbnailSize (int &w, int &h, int fixwh=1); // fixwh = 0: fix w and calculate h, =1: fix h and calculate w + void generateThumbnailImage (bool useLock=true); + + Glib::ustring getExifString (); + Glib::ustring getDateTimeString (); + + ThFileType getType (); + Glib::ustring getFileName () { return fname; } + void setFileName (const Glib::ustring fn) { fname = fn; } + + bool isSupported (); + + void saveToCache (FILE* f, bool full); + + void setFilePos (int fp) { filePos = fp; } + int getFilePos () { return filePos; } + + int getRank () { return cfs->rank; } + void setRank (int rank) { cfs->rank = rank; } + int getStage () { return cfs->stage; } + void setStage (int stage) { cfs->stage = stage; } + + void increaseRef (); + void decreaseRef (); + + void updateCache (bool pparams=true, bool thumbImg=true, bool useLock=true); + + const CacheFileStruct* getCacheFileStruct () const { return cfs; } + + int loadJPEGThumbnail (int offset, unsigned char* &data, int &width, int &height, int degree=0, int fixwh=1); + int loadPPMThumbnail (int offset, int iw, int ih, unsigned char* &data, int &width, int &height, int degree=0, int fixwh=1); + int loadPNGThumbnail (unsigned char* &data, int &width, int &height, int fixwh=1); + int loadTIFFThumbnail (unsigned char* &data, int &width, int &height, int fixwh=1); +}; + + +#endif + diff --git a/rtgui/thumbnailbrowser.h b/rtgui/thumbnailbrowser.h new file mode 100755 index 000000000..9f0731cf4 --- /dev/null +++ b/rtgui/thumbnailbrowser.h @@ -0,0 +1,95 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _THUMBNAILBROWSER_ +#define _THUMBNAILBROWSER_ + +#include +#include +#include + +class ThumbBrowserEntry { + +public: +// set by arrangeFiles(): + int width; // minimal width + int height; // minimal height + int exp_width; // ararnged width + int startx; // x coord. in the widget + int starty; // y coord. in the widget +// thumbnail preview properties: + int prew; // width of the thumbnail + int preh; // height of the thumbnail + guint8* preview; +// file and directory attributes: + Glib::ustring filename; + Glib::ustring shortname; + Glib::ustring dirname; +// the associated thumbnail instance: + Thumbnail* thumbnail; + + ThumbBrowserEntry (Thumbnail* thm, Glib::ustring fname, Glib::ustring sname, Glib::ustring dname, int h) + : thumbnail(thm), filename(fname), shortname(sname), dirname(dname), preh(h) { + preview = thumbnail ? (guint8*) thumbnail->getThumbnailImage (prew, preh) : NULL; + } + + bool operator< (FileDescr& other) { + return shortname>other.shortname; + } +}; + +class ThumbBrowser : public Gtk::DrawingArea { + + protected: + int dx, dy, w, h; + + Glib::RefPtr gc_; + Gdk::Color black; + Gdk::Color white; + Gdk::Color blue; + Gdk::Color bluew; + + std::vector fd; + std::vector selected; + + int rowHeight; + int numOfRows; + + ThumbBrowserListener* tbl; + + void arrangeFiles (int rows); + + public: + + ThumbBrowser (); + + void addEntry (ThumbBrowserEntry* entry); + void setThumbBrowserListener (ThumbBrowserListener* l) { tbl = l; } + + virtual void on_realize(); + virtual bool on_expose_event(GdkEventExpose* event); + virtual bool on_button_press_event (GdkEventButton* event); + virtual bool on_button_release_event (GdkEventButton* event); + virtual void previewReady (FileDescr* fdn); + + void resized (Gtk::Allocation& req); + void redraw (); + void styleChanged (const Glib::RefPtr& style); +}; + +#endif diff --git a/rtgui/thumbnaillistener.h b/rtgui/thumbnaillistener.h new file mode 100755 index 000000000..49a4eace9 --- /dev/null +++ b/rtgui/thumbnaillistener.h @@ -0,0 +1,34 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _THUMBNAILLISTENER_ +#define _THUMBNAILLISTENER_ + +#include + +class Thumbnail; +class ThumbnailListener { + + public: + + virtual void procParamsChanged (Thumbnail* thm, int whoChangedIt) {} + +}; + +#endif + diff --git a/rtgui/tonecurve.cc b/rtgui/tonecurve.cc new file mode 100755 index 000000000..b56c0c332 --- /dev/null +++ b/rtgui/tonecurve.cc @@ -0,0 +1,363 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include +#include + +using namespace rtengine; +using namespace rtengine::procparams; + +ToneCurve::ToneCurve () : ToolPanel(), expAdd(false), blackAdd(false), brAdd(false), contrAdd(false) { + +//----------- Auto Levels ---------------------------------- + abox = Gtk::manage (new Gtk::HBox ()); + abox->set_border_width (2); + + autolevels = Gtk::manage (new Gtk::ToggleButton (M("TP_EXPOSURE_AUTOLEVELS"))); + autoconn = autolevels->signal_toggled().connect( sigc::mem_fun(*this, &ToneCurve::autolevels_toggled) ); + + sclip = Gtk::manage (new Gtk::SpinButton ()); + sclip->set_range (0.0, 0.9999); + sclip->set_increments (0.0001, 0.01); + sclip->set_value (0.002); + sclip->set_digits (4); + sclip->signal_value_changed().connect( sigc::mem_fun(*this, &ToneCurve::clip_changed) ); + + abox->pack_start (*autolevels); + abox->pack_end (*sclip); + abox->pack_end (*Gtk::manage (new Gtk::Label (M("TP_EXPOSURE_CLIP")))); + pack_start (*abox); + + pack_start (*Gtk::manage (new Gtk::HSeparator())); + +//----------- Exposure Compensation ------------------------ + expcomp = new Adjuster (M("TP_EXPOSURE_EXPCOMP"), -5, 5, 0.01, 0); + pack_start (*expcomp); + hlcompr = Gtk::manage (new Adjuster (M("TP_EXPOSURE_COMPRHIGHLIGHTS"), 0, 150, 1, 0)); + pack_start (*hlcompr); + +//----------- Black Level ---------------------------------- + black = Gtk::manage (new Adjuster (M("TP_EXPOSURE_BLACKLEVEL"), 0, 32768, 1, 0)); + pack_start (*black); + shcompr = Gtk::manage (new Adjuster (M("TP_EXPOSURE_COMPRSHADOWS"), 0, 150, 1, 0)); + pack_start (*shcompr); + + pack_start (*Gtk::manage (new Gtk::HSeparator())); + +//---------Brightness / Contrast ------------------------- + brightness = Gtk::manage (new Adjuster (M("TP_EXPOSURE_BRIGHTNESS"), -100, 100, 1, 0)); + pack_start (*brightness); + contrast = Gtk::manage (new Adjuster (M("TP_EXPOSURE_CONTRAST"), -100, 100, 1, 0)); + pack_start (*contrast); + +/* +//----------- Curve ------------------------------ + pack_start (*Gtk::manage (new Gtk::HSeparator())); + + shape = Gtk::manage (new CurveEditor ()); + shape->setCurveListener (this); + curvexp = Gtk::manage (new Gtk::Expander (M("TP_EXPOSURE_CURVEEDITOR"))); + curvexp->add (*shape); + + pack_start (*curvexp, Gtk::PACK_SHRINK, 4); +*/ +// --------- Set Up Listeners ------------- + expcomp->setAdjusterListener (this); + brightness->setAdjusterListener (this); + black->setAdjusterListener (this); + hlcompr->setAdjusterListener (this); + shcompr->setAdjusterListener (this); + contrast->setAdjusterListener (this); +} + +ToneCurve::~ToneCurve () { + + delete expcomp; +} + +void ToneCurve::read (const ProcParams* pp, const ParamsEdited* pedited) { + + disableListener (); + + if (pedited) { + expcomp->setEditedState (pedited->toneCurve.expcomp ? Edited : UnEdited); + black->setEditedState (pedited->toneCurve.black ? Edited : UnEdited); + hlcompr->setEditedState (pedited->toneCurve.hlcompr ? Edited : UnEdited); + shcompr->setEditedState (pedited->toneCurve.shcompr ? Edited : UnEdited); + brightness->setEditedState (pedited->toneCurve.brightness ? Edited : UnEdited); + contrast->setEditedState (pedited->toneCurve.contrast ? Edited : UnEdited); + autolevels->set_inconsistent (!pedited->toneCurve.autoexp); + clipDirty = pedited->toneCurve.clip; + } + + autoconn.block (true); + autolevels->set_active (pp->toneCurve.autoexp); + autoconn.block (false); + lastAuto = pp->toneCurve.autoexp; + sclip->set_value (pp->toneCurve.clip); + + expcomp->setValue (pp->toneCurve.expcomp); + black->setValue (pp->toneCurve.black); + hlcompr->setValue (pp->toneCurve.hlcompr); + shcompr->setValue (pp->toneCurve.shcompr); + brightness->setValue (pp->toneCurve.brightness); + contrast->setValue (pp->toneCurve.contrast); +// shape->setCurve (pp->toneCurve.curve); + + enableListener (); +} + +void ToneCurve::write (ProcParams* pp, ParamsEdited* pedited) { + + pp->toneCurve.autoexp = autolevels->get_active(); + pp->toneCurve.clip = sclip->get_value (); + pp->toneCurve.expcomp = expcomp->getValue (); + pp->toneCurve.black = (int)black->getValue (); + pp->toneCurve.hlcompr = (int)hlcompr->getValue (); + pp->toneCurve.shcompr = (int)shcompr->getValue (); + pp->toneCurve.brightness = (int)brightness->getValue (); + pp->toneCurve.contrast = (int)contrast->getValue (); +// pp->toneCurve.curve = shape->getCurve (); + + if (pedited) { + pedited->toneCurve.expcomp = expcomp->getEditedState (); + pedited->toneCurve.black = black->getEditedState (); + pedited->toneCurve.hlcompr = hlcompr->getEditedState (); + pedited->toneCurve.shcompr = shcompr->getEditedState (); + pedited->toneCurve.brightness = brightness->getEditedState (); + pedited->toneCurve.contrast = contrast->getEditedState (); + pedited->toneCurve.autoexp = !autolevels->get_inconsistent(); + pedited->toneCurve.clip = clipDirty; + } +} + +void ToneCurve::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { + + expcomp->setDefault (defParams->toneCurve.expcomp); + brightness->setDefault (defParams->toneCurve.brightness); + black->setDefault (defParams->toneCurve.black); + hlcompr->setDefault (defParams->toneCurve.hlcompr); + shcompr->setDefault (defParams->toneCurve.shcompr); + contrast->setDefault (defParams->toneCurve.contrast); + + if (pedited) { + expcomp->setDefaultEditedState (pedited->toneCurve.expcomp ? Edited : UnEdited); + black->setDefaultEditedState (pedited->toneCurve.black ? Edited : UnEdited); + hlcompr->setDefaultEditedState (pedited->toneCurve.hlcompr ? Edited : UnEdited); + shcompr->setDefaultEditedState (pedited->toneCurve.shcompr ? Edited : UnEdited); + brightness->setDefaultEditedState (pedited->toneCurve.brightness ? Edited : UnEdited); + contrast->setDefaultEditedState (pedited->toneCurve.contrast ? Edited : UnEdited); + } + else { + expcomp->setDefaultEditedState (Irrelevant); + black->setDefaultEditedState (Irrelevant); + hlcompr->setDefaultEditedState (Irrelevant); + shcompr->setDefaultEditedState (Irrelevant); + brightness->setDefaultEditedState (Irrelevant); + contrast->setDefaultEditedState (Irrelevant); + } +} + +/*void ToneCurve::curveChanged () { + + if (listener) { + listener->panelChanged (EvToneCurve, M("HISTORY_CUSTOMCURVE")); + } +} +*/ +void ToneCurve::adjusterChanged (Adjuster* a, double newval) { + + if (autolevels->get_active() && (a==expcomp || a==black || a==hlcompr || a==shcompr)) { + autolevels->set_active (false); + autolevels->set_inconsistent (false); + } + + if (!listener) + return; + + Glib::ustring costr; + if (a==expcomp) + costr = Glib::ustring::format (std::setw(3), std::fixed, std::setprecision(2), a->getValue()); + else + costr = Glib::ustring::format ((int)a->getValue()); + + if (a==expcomp) + listener->panelChanged (EvExpComp, costr); + else if (a==brightness) + listener->panelChanged (EvBrightness, costr); + else if (a==black) + listener->panelChanged (EvBlack, costr); + else if (a==contrast) + listener->panelChanged (EvContrast, costr); + else if (a==hlcompr) + listener->panelChanged (EvHLCompr, costr); + else if (a==shcompr) + listener->panelChanged (EvSHCompr, costr); +} + +void ToneCurve::autolevels_toggled () { + + if (batchMode) { + if (autolevels->get_inconsistent()) { + autolevels->set_inconsistent (false); + autoconn.block (true); + autolevels->set_active (false); + autoconn.block (false); + } + else if (lastAuto) + autolevels->set_inconsistent (true); + + lastAuto = autolevels->get_active (); + } + + if (!batchMode && autolevels->get_active() && listener) { + listener->panelChanged (EvAutoExp, M("GENERAL_ENABLED")); + waitForAutoExp (); + } + + if (batchMode) { + expcomp->setEditedState (UnEdited); + black->setEditedState (UnEdited); + if (expAdd) + expcomp->setValue (0); + if (blackAdd) + black->setValue (0); + listener->panelChanged (EvAutoExp, M("GENERAL_ENABLED")); + } +} + +void ToneCurve::clip_changed () { + + clipDirty = true; + if (autolevels->get_active() && listener) + Glib::signal_idle().connect (sigc::mem_fun(*this, &ToneCurve::clip_changed_)); +} + +bool ToneCurve::clip_changed_ () { + + if (listener) { + listener->panelChanged (EvClip, Glib::ustring::format (std::setprecision(5), sclip->get_value())); + if (!batchMode) + waitForAutoExp (); + } + return false; +} + +void ToneCurve::waitForAutoExp () { + + sclip->set_sensitive (false); + expcomp->setEnabled (false); + brightness->setEnabled (false); + black->setEnabled (false); + hlcompr->setEnabled (false); + shcompr->setEnabled (false); + contrast->setEnabled (false); +// shape->set_sensitive (false); +} + +int aexpcomputed (void* data) { + + gdk_threads_enter(); + ((ToneCurve*)data)->autoExpComputed_ (); + gdk_threads_leave(); + return 0; +} + +void ToneCurve::autoExpChanged (double br, int bl) { + + nextBl = bl; + nextBr = br; + g_idle_add (aexpcomputed, this); + + +// Glib::signal_idle().connect (sigc::mem_fun(*this, &ToneCurve::autoExpComputed_)); +} + +void ToneCurve::enableAll () { + + sclip->set_sensitive (true); + expcomp->setEnabled (true); + brightness->setEnabled (true); + black->setEnabled (true); + hlcompr->setEnabled (true); + shcompr->setEnabled (true); + contrast->setEnabled (true); +// shape->set_sensitive (true); +} + +bool ToneCurve::autoExpComputed_ () { + + disableListener (); + enableAll (); + expcomp->setValue (nextBr); + black->setValue (nextBl); + enableListener (); + + return false; +} + +/* +void ToneCurve::expandCurve (bool isExpanded) { + + curvexp->set_expanded (isExpanded); +} + +bool ToneCurve::isCurveExpanded () { + + return curvexp->get_expanded (); +} +*/ + +void ToneCurve::setBatchMode (bool batchMode) { + + removeIfThere (abox, autolevels, false); + autolevels = Gtk::manage (new Gtk::CheckButton (M("TP_EXPOSURE_AUTOLEVELS"))); + autoconn = autolevels->signal_toggled().connect( sigc::mem_fun(*this, &ToneCurve::autolevels_toggled) ); + abox->pack_start (*autolevels); + + ToolPanel::setBatchMode (batchMode); + expcomp->showEditedCB (); + black->showEditedCB (); + hlcompr->showEditedCB (); + shcompr->showEditedCB (); + brightness->showEditedCB (); + contrast->showEditedCB (); +} + +void ToneCurve::setAdjusterBehavior (bool expadd, bool bradd, bool blackadd, bool contradd) { + + if (!expAdd && expadd || expAdd && !expadd) + expcomp->setLimits (-5, 5, 0.01, 0); + if (!blackAdd && blackadd) + black->setLimits (0, 16384, 1, 0); + else if (blackAdd && !blackadd) + black->setLimits (0, 32768, 1, 0); + if (!brAdd && bradd || brAdd && !bradd) + brightness->setLimits (-100, 100, 0.01, 0); + if (!contrAdd && contradd || contrAdd && !contradd) + contrast->setLimits (-100, 100, 0.01, 0); + + expAdd = expadd; + blackAdd = blackadd; + brAdd = bradd; + contrAdd = contradd; +} + diff --git a/rtgui/tonecurve.h b/rtgui/tonecurve.h new file mode 100755 index 000000000..822964f00 --- /dev/null +++ b/rtgui/tonecurve.h @@ -0,0 +1,71 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _TONECURVE_H_ +#define _TONECURVE_H_ + +#include +#include +#include +//#include +//#include + +class ToneCurve : public Gtk::VBox, public AdjusterListener, public ToolPanel, public rtengine::AutoExpListener/*, public CurveListener */{ + + protected: + Gtk::HBox* abox; + Gtk::ToggleButton* autolevels; + Gtk::SpinButton* sclip; + Adjuster* expcomp; + Adjuster* brightness; + Adjuster* black; + Adjuster* hlcompr; + Adjuster* shcompr; + Adjuster* contrast; + bool expAdd, blackAdd, brAdd, contrAdd, clipDirty, lastAuto; + sigc::connection autoconn; +// CurveEditor* shape; +// Gtk::Expander* curvexp; + double nextBr; + int nextBl; + + public: + + ToneCurve (); + virtual ~ToneCurve (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + void setAdjusterBehavior (bool expadd, bool bradd, bool blackadd, bool contradd); + + void adjusterChanged (Adjuster* a, double newval); + void autolevels_toggled (); + void clip_changed (); + bool clip_changed_ (); + void waitForAutoExp (); + void autoExpChanged (double br, int bl); + bool autoExpComputed_ (); + void enableAll (); +/* void curveChanged (); + void expandCurve (bool isExpanded); + bool isCurveExpanded ();*/ +}; + +#endif diff --git a/rtgui/toolbar.cc b/rtgui/toolbar.cc new file mode 100755 index 000000000..2c8ccc2c8 --- /dev/null +++ b/rtgui/toolbar.cc @@ -0,0 +1,195 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 "toolbar.h" +#include + +extern Glib::ustring argv0; + +ToolBar::ToolBar () : listener (NULL) { + + handTool = Gtk::manage (new Gtk::ToggleButton ()); + Gtk::Image* handimg = Gtk::manage (new Gtk::Image (argv0+"/images/openhand22.png")); + handTool->add (*handimg); + handimg->show (); + handTool->set_relief(Gtk::RELIEF_NONE); + handTool->show (); + + pack_start (*handTool); + + wbTool = Gtk::manage (new Gtk::ToggleButton ()); + Gtk::Image* wbimg = Gtk::manage (new Gtk::Image (argv0+"/images/wbpicker22.png")); + wbTool->add (*wbimg); + wbimg->show (); + wbTool->set_relief(Gtk::RELIEF_NONE); + wbTool->show (); + + pack_start (*wbTool); + + cropTool = Gtk::manage (new Gtk::ToggleButton ()); + Gtk::Image* cropimg = Gtk::manage (new Gtk::Image (argv0+"/images/crop22.png")); + cropTool->add (*cropimg); + cropimg->show (); + cropTool->set_relief(Gtk::RELIEF_NONE); + cropTool->show (); + + pack_start (*cropTool); + + straTool = Gtk::manage (new Gtk::ToggleButton ()); + Gtk::Image* straimg = Gtk::manage (new Gtk::Image (argv0+"/images/straighten22.png")); + straTool->add (*straimg); + straimg->show (); + straTool->set_relief(Gtk::RELIEF_NONE); + straTool->show (); + + pack_start (*straTool); + + + handTool->set_active (true); + current = TMHand; + + handConn = handTool->signal_toggled().connect( sigc::mem_fun(*this, &ToolBar::hand_pressed)); + wbConn = wbTool->signal_toggled().connect( sigc::mem_fun(*this, &ToolBar::wb_pressed)); + cropConn = cropTool->signal_toggled().connect( sigc::mem_fun(*this, &ToolBar::crop_pressed)); + straConn = straTool->signal_toggled().connect( sigc::mem_fun(*this, &ToolBar::stra_pressed)); + + handTool->set_tooltip_text (M("TOOLBAR_TOOLTIP_HAND")); + wbTool->set_tooltip_text (M("TOOLBAR_TOOLTIP_WB")); + cropTool->set_tooltip_text (M("TOOLBAR_TOOLTIP_CROP")); + straTool->set_tooltip_text (M("TOOLBAR_TOOLTIP_STRAIGHTEN")); +} + +// +// Selects the desired tool without notifying the listener +// +void ToolBar::setTool (ToolMode tool) { + + handConn.block (true); + cropConn.block (true); + wbConn.block (true); + straConn.block (true); + + handTool->set_active (false); + wbTool->set_active (false); + cropTool->set_active (false); + straTool->set_active (false); + + if (tool==TMHand) + handTool->set_active (true); + else if (tool==TMSpotWB) + wbTool->set_active (true); + else if (tool==TMCropSelect) + cropTool->set_active (true); + else if (tool==TMStraighten) + straTool->set_active (true); + + current = tool; + + handConn.block (false); + cropConn.block (false); + wbConn.block (false); + straConn.block (false); +} + +void ToolBar::hand_pressed () { + + handConn.block (true); + cropConn.block (true); + wbConn.block (true); + straConn.block (true); + if (current!=TMHand) { + wbTool->set_active (false); + cropTool->set_active (false); + straTool->set_active (false); + current = TMHand; + } + handTool->set_active (true); + handConn.block (false); + cropConn.block (false); + wbConn.block (false); + straConn.block (false); + + if (listener) + listener->toolSelected (TMHand); +} + +void ToolBar::wb_pressed () { + + handConn.block (true); + cropConn.block (true); + wbConn.block (true); + straConn.block (true); + if (current!=TMSpotWB) { + handTool->set_active (false); + cropTool->set_active (false); + straTool->set_active (false); + current = TMSpotWB; + } + wbTool->set_active (true); + handConn.block (false); + cropConn.block (false); + wbConn.block (false); + straConn.block (false); + + if (listener) + listener->toolSelected (TMSpotWB); +} + +void ToolBar::crop_pressed () { + + handConn.block (true); + cropConn.block (true); + wbConn.block (true); + straConn.block (true); + if (current!=TMCropSelect) { + handTool->set_active (false); + wbTool->set_active (false); + straTool->set_active (false); + current = TMCropSelect; + } + cropTool->set_active (true); + handConn.block (false); + cropConn.block (false); + wbConn.block (false); + straConn.block (false); + + if (listener) + listener->toolSelected (TMCropSelect); +} + +void ToolBar::stra_pressed () { + + handConn.block (true); + cropConn.block (true); + wbConn.block (true); + straConn.block (true); + if (current!=TMStraighten) { + handTool->set_active (false); + wbTool->set_active (false); + cropTool->set_active (false); + current = TMStraighten; + } + straTool->set_active (true); + handConn.block (false); + cropConn.block (false); + wbConn.block (false); + straConn.block (false); + + if (listener) + listener->toolSelected (TMStraighten); +} diff --git a/rtgui/toolbar.h b/rtgui/toolbar.h new file mode 100755 index 000000000..a98287222 --- /dev/null +++ b/rtgui/toolbar.h @@ -0,0 +1,60 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef __TOOLBAR_H__ +#define __TOOLBAR_H__ + +#include +#include + +class ToolBarListener { + + public: + virtual void toolSelected (ToolMode tool) {} + +}; + +class ToolBar : public Gtk::HBox { + + protected: + Gtk::ToggleButton* handTool; + Gtk::ToggleButton* wbTool; + Gtk::ToggleButton* cropTool; + Gtk::ToggleButton* straTool; + ToolBarListener* listener; + ToolMode current; + sigc::connection handConn; + sigc::connection wbConn; + sigc::connection cropConn; + sigc::connection straConn; + + public: + ToolBar (); + + void setTool (ToolMode tool); + ToolMode getTool () { return current; } + + void setToolBarListener (ToolBarListener* tpl) { listener = tpl; } + + void hand_pressed (); + void wb_pressed (); + void crop_pressed (); + void stra_pressed (); +}; + +#endif diff --git a/rtgui/toolenum.h b/rtgui/toolenum.h new file mode 100755 index 000000000..082084851 --- /dev/null +++ b/rtgui/toolenum.h @@ -0,0 +1,24 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _TOOLENUM_ +#define _TOOLENUM_ + +enum ToolMode {TMHand=0, TMSpotWB=1, TMCropSelect=2, TMStraighten=3}; + +#endif diff --git a/rtgui/toolpanel.h b/rtgui/toolpanel.h new file mode 100755 index 000000000..f4fadb8b2 --- /dev/null +++ b/rtgui/toolpanel.h @@ -0,0 +1,58 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef __TOOLPANEL__ +#define __TOOLPANEL__ + +#include +#include +#include +#include +#include + +class ToolPanelListener { + + public: + + virtual void panelChanged (rtengine::ProcEvent event, const Glib::ustring& descr) {} +}; + +class ToolPanel { + + protected: + ToolPanelListener* listener; + ToolPanelListener* tmp; + bool batchMode; + + public: + + ToolPanel () : listener(NULL), tmp(NULL), batchMode(false) {} + + void setListener (ToolPanelListener* tpl) { listener = tpl; } + virtual void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL) {} + virtual void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL) {} + virtual void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL) {} + + void disableListener () { if (tmp==NULL) tmp = listener; listener = NULL; } + void enableListener () { if (tmp!=NULL) listener = tmp; tmp = NULL; } + + virtual void setBatchMode (bool batchMode) { this->batchMode = batchMode; } + +}; + +#endif diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc new file mode 100755 index 000000000..6b9db38b0 --- /dev/null +++ b/rtgui/toolpanelcoord.cc @@ -0,0 +1,355 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include +#include + +using namespace rtengine::procparams; + +ToolPanelCoordinator::ToolPanelCoordinator () : ipc(NULL) { + + exposurePanel = Gtk::manage (new Gtk::VBox ()); + detailsPanel = Gtk::manage (new Gtk::VBox ()); + colorPanel = Gtk::manage (new Gtk::VBox ()); + transformPanel = Gtk::manage (new Gtk::VBox ()); + + coarse = Gtk::manage (new CoarsePanel ()); + curve = Gtk::manage (new ToneCurve ()); + shadowshighlights = Gtk::manage (new ShadowsHighlights ()); + lumadenoise = Gtk::manage (new LumaDenoise ()); + colordenoise = Gtk::manage (new ColorDenoise ()); + sharpening = Gtk::manage (new Sharpening ()); +// lcurve = Gtk::manage (new LCurve ()); + colorboost = Gtk::manage (new ColorBoost ()); + colorshift = Gtk::manage (new ColorShift ()); + distortion = Gtk::manage (new Distortion ()); + rotate = Gtk::manage (new Rotate ()); + whitebalance = Gtk::manage (new WhiteBalance ()); + vignetting = Gtk::manage (new Vignetting ()); + cacorrection = Gtk::manage (new CACorrection ()); + hlrecovery = Gtk::manage (new HLRecovery ()); + chmixer = Gtk::manage (new ChMixer ()); + resize = Gtk::manage (new Resize ()); + crop = Gtk::manage (new Crop ()); + icm = Gtk::manage (new ICMPanel ()); + exifpanel = Gtk::manage (new ExifPanel ()); + iptcpanel = Gtk::manage (new IPTCPanel ()); + + addPanel (colorPanel, whitebalance, M("TP_WBALANCE_LABEL")); toolPanels.push_back (whitebalance); + addPanel (exposurePanel, curve, M("TP_EXPOSURE_LABEL")); toolPanels.push_back (curve); + addPanel (exposurePanel, hlrecovery, M("TP_HLREC_LABEL")); toolPanels.push_back (hlrecovery); + addPanel (colorPanel, chmixer, M("TP_CHMIXER_LABEL")); toolPanels.push_back (chmixer); + addPanel (exposurePanel, shadowshighlights, M("TP_SHADOWSHLIGHTS_LABEL")); toolPanels.push_back (shadowshighlights); + addPanel (detailsPanel, sharpening, M("TP_SHARPENING_LABEL")); toolPanels.push_back (sharpening); + addPanel (colorPanel, colorboost, M("TP_COLORBOOST_LABEL")); toolPanels.push_back (colorboost); + addPanel (colorPanel, colorshift, M("TP_COLORSHIFT_LABEL")); toolPanels.push_back (colorshift); +/* addPanel (exposurePanel, lcurve, M("TP_LUMACURVE_LABEL")); toolPanels.push_back (lcurve);*/ + addPanel (detailsPanel, lumadenoise, M("TP_LUMADENOISE_LABEL")); toolPanels.push_back (lumadenoise); + addPanel (detailsPanel, colordenoise, M("TP_COLORDENOISE_LABEL")); toolPanels.push_back (colordenoise); + addPanel (transformPanel, crop, M("TP_CROP_LABEL")); toolPanels.push_back (crop); + addPanel (transformPanel, rotate, M("TP_ROTATE_LABEL")); toolPanels.push_back (rotate); + addPanel (transformPanel, distortion, M("TP_DISTORTION_LABEL")); toolPanels.push_back (distortion); + addPanel (transformPanel, cacorrection, M("TP_CACORRECTION_LABEL")); toolPanels.push_back (cacorrection); + addPanel (transformPanel, vignetting, M("TP_VIGNETTING_LABEL")); toolPanels.push_back (vignetting); + addPanel (transformPanel, resize, M("TP_RESIZE_LABEL")); toolPanels.push_back (resize); + addPanel (colorPanel, icm, M("TP_ICM_LABEL")); toolPanels.push_back (icm); + + toolPanels.push_back (coarse); + toolPanels.push_back (exifpanel); + toolPanels.push_back (iptcpanel); + + metadataPanel = Gtk::manage (new Gtk::Notebook ()); + toolPanelNotebook = new Gtk::Notebook (); + + metadataPanel->append_page (*exifpanel, M("MAIN_TAB_EXIF")); + metadataPanel->append_page (*iptcpanel, M("MAIN_TAB_IPTC")); + + Gtk::ScrolledWindow* exposurePanelSW = Gtk::manage (new Gtk::ScrolledWindow ()); + Gtk::ScrolledWindow* detailsPanelSW = Gtk::manage (new Gtk::ScrolledWindow ()); + Gtk::ScrolledWindow* colorPanelSW = Gtk::manage (new Gtk::ScrolledWindow ()); + Gtk::ScrolledWindow* transformPanelSW = Gtk::manage (new Gtk::ScrolledWindow ()); + exposurePanelSW->set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); + detailsPanelSW->set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); + colorPanelSW->set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); + transformPanelSW->set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); + + exposurePanelSW->add (*exposurePanel); + detailsPanelSW->add (*detailsPanel); + colorPanelSW->add (*colorPanel); + transformPanelSW->add (*transformPanel); + + toolPanelNotebook->append_page (*exposurePanelSW, M("MAIN_TAB_EXPOSURE")); + toolPanelNotebook->append_page (*detailsPanelSW, M("MAIN_TAB_DETAIL")); + toolPanelNotebook->append_page (*colorPanelSW, M("MAIN_TAB_COLOR")); + toolPanelNotebook->append_page (*transformPanelSW, M("MAIN_TAB_TRANSFORM")); + toolPanelNotebook->append_page (*metadataPanel, M("MAIN_TAB_METADATA")); + toolPanelNotebook->set_current_page (0); + + toolPanelNotebook->set_scrollable (); + toolPanelNotebook->show_all (); + + for (int i=0; isetListener (this); + + whitebalance->setWBProvider (this); + whitebalance->setSpotWBListener (this); + rotate->setRotateListener (this); + crop->setCropPanelListener (this); + icm->setICMPanelListener (this); + + toolBar = new ToolBar (); +} + +void ToolPanelCoordinator::addPanel (Gtk::Box* where, Gtk::Container* panel, Glib::ustring label) { + + Gtk::HSeparator *hsep = Gtk::manage (new Gtk::HSeparator()); + where->pack_start(*hsep, Gtk::PACK_SHRINK, 0); + hsep->show(); + +// Gtk::Expander* exp = new Gtk::Expander (); +// exp->set_label_widget (*(new ILabel (Glib::ustring("") + label + ""))); + Gtk::Expander* exp = Gtk::manage (new Gtk::Expander (Glib::ustring("") + label + "")); + exp->set_border_width (4); + exp->set_use_markup (true); + expList.push_back (exp); + + Gtk::Frame* pframe = Gtk::manage (new Gtk::Frame ()); + + pframe->set_name ("ToolPanel"); + + pframe->add (*panel); + panel->show (); + + exp->add (*pframe); + pframe->set_shadow_type (Gtk::SHADOW_ETCHED_IN); + pframe->show (); + exp->show (); + + where->pack_start(*exp, false, false); +} + +ToolPanelCoordinator::~ToolPanelCoordinator () { + + closeImage (); + + delete toolPanelNotebook; + delete toolBar; +} + +void ToolPanelCoordinator::panelChanged (rtengine::ProcEvent event, const Glib::ustring& descr) { + + if (!ipc) return; + + ProcParams* params = ipc->getParamsForUpdate (event); + for (int i=0; iwrite (params); + + // some transformations make the crop change for convinience + if (event==rtengine::EvResizeScale) { + crop->resizeScaleChanged (params->resize.scale); + crop->write (params); + } + else if (event==rtengine::EvCTHFlip) { + crop->hFlipCrop (); + crop->write (params); + } + else if (event==rtengine::EvCTVFlip) { + crop->vFlipCrop (); + crop->write (params); + } + else if (event==rtengine::EvCTRotate) { + crop->rotateCrop (params->coarse.rotate); + crop->write (params); + } + + ipc->paramsUpdateReady (); + + hasChanged = true; + + for (int i=0; iprocParamsChanged (params, event, descr); +} + +void ToolPanelCoordinator::profileChange (const ProcParams *nparams, rtengine::ProcEvent event, const Glib::ustring& descr, const ParamsEdited* paramsEdited) { + + if (!ipc) return; + ProcParams* params = ipc->getParamsForUpdate (event); + *params = *nparams; + for (int i=0; iread (nparams); + + ipc->paramsUpdateReady (); + + hasChanged = event != rtengine::EvProfileChangeNotification; + + for (int i=0; iprocParamsChanged (params, event, descr); +} + +void ToolPanelCoordinator::setDefaults (ProcParams* defparams) { + + if (defparams) + for (int i=0; isetDefaults (defparams); +} + +CropGUIListener* ToolPanelCoordinator::getCropGUIListener () { + + return crop; +} + +void ToolPanelCoordinator::initImage (rtengine::StagedImageProcessor* ipc_, bool raw) { + + ipc = ipc_; + curve->disableListener (); + curve->enableAll (); + curve->enableListener (); + + + exifpanel->setImageData (ipc->getInitialImage()->getMetaData()); + iptcpanel->setImageData (ipc->getInitialImage()->getMetaData()); + + if (ipc) { + ipc->setAutoExpListener (curve); + ipc->setSizeListener (crop); + ipc->setSizeListener (resize); + } + + icm->setRaw (raw); + hlrecovery->setRaw (raw); + hasChanged = true; +} + + +void ToolPanelCoordinator::closeImage () { + + if (ipc) { + ipc->stopProcessing (); + ipc = NULL; + } +} + +void ToolPanelCoordinator::readOptions () { + + crop->readOptions (); +/* for (int i=0; iset_expanded (options.tpOpen[i]); + + if (options.crvOpen.size()>1) { + curve->expandCurve (options.crvOpen[0]); + lcurve->expandCurve (options.crvOpen[1]); + }*/ +} + +void ToolPanelCoordinator::writeOptions () { + + crop->writeOptions (); +/* options.tpOpen.clear (); + for (int i=0; iget_expanded ()); + + options.crvOpen.clear (); + options.crvOpen.push_back (curve->isCurveExpanded()); + options.crvOpen.push_back (lcurve->isCurveExpanded());*/ +} + + +void ToolPanelCoordinator::cropSelectionReady () { + + toolBar->setTool (TMHand); + + if (!ipc) + return; +} + +void ToolPanelCoordinator::rotateSelectionReady (double rotate_deg, Thumbnail* thm) { + + toolBar->setTool (TMHand); + + if (!ipc) + return; + + if (rotate_deg!=0.0) + rotate->straighten (rotate_deg); +} + +void ToolPanelCoordinator::spotWBselected (int x, int y, Thumbnail* thm) { + + if (!ipc) + return; + +// toolBar->setTool (TOOL_HAND); + if (x>0 && y>0) { + double temp; + double green; + ipc->getSpotWB (x, y, whitebalance->getSize (), temp, green); + whitebalance->setWB (temp, green); + } +} + +void ToolPanelCoordinator::autoCropRequested () { + + if (!ipc) + return; + + int x1, y1, x2, y2, w, h; + ipc->getAutoCrop (crop->getRatio(), x1, y1, w, h); + x2 = x1 + w - 1; + y2 = y1 + h - 1; + crop->cropInit (x1, y1, w, h); + crop->cropResized (x1, y1, x2, y2); + crop->cropManipReady (); +} + +void ToolPanelCoordinator::straightenRequested () { + + if (!ipc) + return; + + toolBar->setTool (TMStraighten); +} + +void ToolPanelCoordinator::spotWBRequested (int size) { + + if (!ipc) + return; + + toolBar->setTool (TMSpotWB); +} + +void ToolPanelCoordinator::cropSelectRequested () { + + if (!ipc) + return; + + toolBar->setTool (TMCropSelect); +} + +void ToolPanelCoordinator::saveInputICCReference (Glib::ustring fname) { + + if (ipc) + ipc->saveInputICCReference (fname); +} + +int ToolPanelCoordinator::getSpotWBRectSize () { + + return whitebalance->getSize (); +} diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h new file mode 100755 index 000000000..778ea4945 --- /dev/null +++ b/rtgui/toolpanelcoord.h @@ -0,0 +1,161 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef __TOOLPANELCCORD__ +#define __TOOLPANELCCORD__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class ImageEditorCoordinator; + +class ToolPanelCoordinator : public ToolPanelListener, + public ProfileChangeListener, + public WBProvider, + public RotateListener , + public SpotWBListener, + public CropPanelListener, + public ICMPanelListener, + public ImageAreaToolListener { + + protected: + + WhiteBalance* whitebalance; + Vignetting* vignetting; + Rotate* rotate; + Distortion* distortion; + CACorrection* cacorrection; + ColorShift* colorshift; + HLRecovery* hlrecovery; + ChMixer* chmixer; + ColorBoost* colorboost; + Resize* resize; + ICMPanel* icm; + Crop* crop; + ToneCurve* curve; + ShadowsHighlights* shadowshighlights; + LumaDenoise* lumadenoise; + ColorDenoise* colordenoise; + Sharpening* sharpening; +// LCurve* lcurve; + + std::vector paramcListeners; + + rtengine::StagedImageProcessor* ipc; + + std::vector toolPanels; + Gtk::VBox* exposurePanel; + Gtk::VBox* detailsPanel; + Gtk::VBox* colorPanel; + Gtk::VBox* transformPanel; + Gtk::Notebook* metadataPanel; + ExifPanel* exifpanel; + IPTCPanel* iptcpanel; + ToolBar* toolBar; + + std::vector expList; + + bool hasChanged; + + void addPanel (Gtk::Box* where, Gtk::Container* panel, Glib::ustring label); + + public: + + CoarsePanel* coarse; + Gtk::Notebook* toolPanelNotebook; + + ToolPanelCoordinator (); + ~ToolPanelCoordinator (); + + bool getChangedState () { return hasChanged; } + + // multiple listeners can be added that are notified on changes (typical: profile panel and the history) + void addPParamsChangeListener (PParamsChangeListener* pp) { paramcListeners.push_back (pp); } + + // toolpanellistener interface + void panelChanged (rtengine::ProcEvent event, const Glib::ustring& descr); + + // profilechangelistener interface + void profileChange (const rtengine::procparams::ProcParams* nparams, rtengine::ProcEvent event, const Glib::ustring& descr, const ParamsEdited* paramsEdited=NULL); + void setDefaults (rtengine::procparams::ProcParams* defparams); + + // to support the GUI: + CropGUIListener* getCropGUIListener (); // through the CropGUIListener the editor area can notify the "crop" ToolPanel when the crop selection changes + + // init the toolpanelcoordinator with an image & close it + void initImage (rtengine::StagedImageProcessor* ipc_, bool israw); + void closeImage (); + + // read/write the "expanded" state of the expanders & read/write the crop panel settings (ratio, guide type, etc.) + void readOptions (); + void writeOptions (); + + // wbprovider interface + void getAutoWB (double& temp, double& green) { if (ipc) ipc->getAutoWB (temp, green); } + void getCamWB (double& temp, double& green) { if (ipc) ipc->getCamWB (temp, green); } + + // rotatelistener interface + void straightenRequested (); + void autoCropRequested (); + + // spotwblistener interface + void spotWBRequested (int size); + + // croppanellistener interface + void cropSelectRequested (); + + // icmpanellistener interface + void saveInputICCReference (Glib::ustring fname); + + // imageareatoollistener interface + void spotWBselected (int x, int y, Thumbnail* thm=NULL); + void cropSelectionReady (); + void rotateSelectionReady (double rotate_deg, Thumbnail* thm=NULL); + ToolBar* getToolBar () { return toolBar; } + int getSpotWBRectSize (); + CropGUIListener* startCropEditing (Thumbnail* thm=NULL) { return crop; } +}; + +#endif diff --git a/rtgui/utils.cc b/rtgui/utils.cc new file mode 100755 index 000000000..06d67aa2f --- /dev/null +++ b/rtgui/utils.cc @@ -0,0 +1,39 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +void removeIfThere (Gtk::Container* cont, Gtk::Widget* w) { + + Glib::ListHandle list = cont->get_children (); + Glib::ListHandle::iterator i = list.begin (); + for (; i!=list.end() && *i!=w; i++); + if (i!=list.end()) { + w->reference (); + cont->remove (*w); + } +} + +void thumbInterp (const unsigned char* src, int sw, int sh, unsigned char* dst, int dw, int dh) { + + if (options.thumbInterp==0) + rtengine::nearestInterp (src, sw, sh, dst, dw, dh); + else if (options.thumbInterp==1) + rtengine::bilinearInterp (src, sw, sh, dst, dw, dh); +} diff --git a/rtgui/utils.h b/rtgui/utils.h new file mode 100755 index 000000000..dfcc299f0 --- /dev/null +++ b/rtgui/utils.h @@ -0,0 +1,27 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef __UTILS_ +#define __UTILS_ + +#include + +void removeIfThere (Gtk::Container* cont, Gtk::Widget* w); +void thumbInterp (const unsigned char* src, int sw, int sh, unsigned char* dst, int dw, int dh); + +#endif diff --git a/rtgui/vignetting.cc b/rtgui/vignetting.cc new file mode 100755 index 000000000..1d35bc9e5 --- /dev/null +++ b/rtgui/vignetting.cc @@ -0,0 +1,90 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +using namespace rtengine; +using namespace rtengine::procparams; + +Vignetting::Vignetting () : vigAdd(false) { + + amount = Gtk::manage (new Adjuster (M("TP_VIGNETTING_AMOUNT"), -100, 100, 1, 0)); + amount->setAdjusterListener (this); + + radius = Gtk::manage (new Adjuster (M("TP_VIGNETTING_RADIUS"), 0, 100, 1, 50)); + radius->setAdjusterListener (this); + + pack_start (*amount); + pack_start (*radius); + + show_all(); +} + +void Vignetting::read (const ProcParams* pp, const ParamsEdited* pedited) { + + disableListener (); + + if (pedited) + amount->setEditedState (pedited->vignetting.amount ? Edited : UnEdited); + + amount->setValue (pp->vignetting.amount); + radius->setValue (pp->vignetting.radius); + + enableListener (); +} + +void Vignetting::write (ProcParams* pp, ParamsEdited* pedited) { + + pp->vignetting.amount = (int)amount->getValue (); + pp->vignetting.radius = (int)radius->getValue (); + + if (pedited) + pedited->vignetting.amount = amount->getEditedState (); +} + +void Vignetting::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { + + amount->setDefault (defParams->vignetting.amount); + radius->setDefault (defParams->vignetting.radius); + + if (pedited) + amount->setDefaultEditedState (pedited->vignetting.amount ? Edited : UnEdited); + else + amount->setDefaultEditedState (Irrelevant); +} + +void Vignetting::adjusterChanged (Adjuster* a, double newval) { + + if (listener) + listener->panelChanged (EvVignetting, Glib::ustring::compose ("%1=%3\n%2=%4", M("TP_VIGNETTING_AMOUNT"), M("TP_VIGNETTING_RADIUS"), (int)amount->getValue(), (int)radius->getValue())); +} + +void Vignetting::setAdjusterBehavior (bool bvadd) { + + if (!vigAdd && bvadd || vigAdd && !bvadd) + amount->setLimits (-100, 100, 1, 0); + + vigAdd = bvadd; +} + +void Vignetting::setBatchMode (bool batchMode) { + + ToolPanel::setBatchMode (batchMode); + amount->showEditedCB (); +} diff --git a/rtgui/vignetting.h b/rtgui/vignetting.h new file mode 100755 index 000000000..ff65e9584 --- /dev/null +++ b/rtgui/vignetting.h @@ -0,0 +1,46 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _VIGNETTING_H_ +#define _VIGNETTING_H_ + +#include +#include +#include + +class Vignetting : public Gtk::VBox, public AdjusterListener, public ToolPanel { + + protected: + Adjuster* amount; + Adjuster* radius; + bool vigAdd; + + public: + + Vignetting (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + + void adjusterChanged (Adjuster* a, double newval); + void setAdjusterBehavior (bool bvadd); +}; + +#endif diff --git a/rtgui/wbprovider.h b/rtgui/wbprovider.h new file mode 100755 index 000000000..f5f70ba9d --- /dev/null +++ b/rtgui/wbprovider.h @@ -0,0 +1,31 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _WBPROVIDER_ +#define _WBPROVIDER_ + + +class WBProvider { + + public: + virtual void getAutoWB (double& temp, double& green) {} + virtual void getCamWB (double& temp, double& green) {} + virtual void spotWBRequested (int size) {} +}; + +#endif diff --git a/rtgui/whitebalance.cc b/rtgui/whitebalance.cc new file mode 100755 index 000000000..0d84c0707 --- /dev/null +++ b/rtgui/whitebalance.cc @@ -0,0 +1,297 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +#define MINTEMP 1200 +#define MAXTEMP 12000 +#define MINGREEN 0.02 +#define MAXGREEN 5.0 + +extern Glib::ustring argv0; + +using namespace rtengine; +using namespace rtengine::procparams; + +WhiteBalance::WhiteBalance () : ToolPanel(), wbp(NULL), wblistener(NULL), tempAdd(false), greenAdd (false) { + + Gtk::HBox* hbox = Gtk::manage (new Gtk::HBox ()); + hbox->show (); + Gtk::Label* lab = Gtk::manage (new Gtk::Label (M("TP_WBALANCE_METHOD"))); + lab->show (); + method = Gtk::manage (new Gtk::ComboBoxText ()); + method->show (); + method->append_text (M("TP_WBALANCE_CAMERA")); + method->append_text (M("TP_WBALANCE_AUTO")); + method->append_text (M("TP_WBALANCE_CUSTOM")); + method->set_active (0); + hbox->pack_start (*lab, Gtk::PACK_SHRINK, 4); + hbox->pack_start (*method); + pack_start (*hbox, Gtk::PACK_SHRINK, 4); + opt = 0; + + Gtk::HBox* spotbox = Gtk::manage (new Gtk::HBox ()); + spotbox->show (); + + spotbutton = Gtk::manage (new Gtk::Button (M("TP_WBALANCE_SPOTWB"))); + Gtk::Image* spotimg = Gtk::manage (new Gtk::Image (argv0+"/images/wbpicker16.png")); + spotimg->show (); + spotbutton->set_image (*spotimg); + spotbutton->show (); + + spotbox->pack_start (*spotbutton); + + Gtk::Label* slab = Gtk::manage (new Gtk::Label (M("TP_WBALANCE_SIZE"))); + slab->show (); + + spotsize = Gtk::manage (new Gtk::ComboBoxText ()); + spotsize->show (); + spotsize->append_text ("2"); + spotsize->append_text ("4"); + spotsize->append_text ("8"); + spotsize->append_text ("16"); + spotsize->append_text ("32"); + spotsize->set_active (2); + + spotbox->pack_end (*spotsize, Gtk::PACK_SHRINK, 4); + spotbox->pack_end (*slab, Gtk::PACK_SHRINK, 4); + + pack_start (*spotbox, Gtk::PACK_SHRINK, 4); + + temp = Gtk::manage (new Adjuster (M("TP_WBALANCE_TEMPERATURE"), MINTEMP, MAXTEMP, 1, 4750)); + green = Gtk::manage (new Adjuster (M("TP_WBALANCE_GREEN"), MINGREEN, MAXGREEN, 0.001, 1.2)); + temp->show (); + green->show (); + + pack_start (*temp); + pack_start (*green); + + temp->setAdjusterListener (this); + green->setAdjusterListener (this); + + spotbutton->signal_pressed().connect( sigc::mem_fun(*this, &WhiteBalance::spotPressed) ); + methconn = method->signal_changed().connect( sigc::mem_fun(*this, &WhiteBalance::optChanged) ); + spotsize->signal_changed().connect( sigc::mem_fun(*this, &WhiteBalance::spotSizeChanged) ); +} + +void WhiteBalance::adjusterChanged (Adjuster* a, double newval) { + + if (method->get_active_row_number()!=2) { + disableListener (); + method->set_active (2); + enableListener (); + } + + if (listener) { + if (a==temp) + listener->panelChanged (EvWBTemp, Glib::ustring::format ((int)a->getValue())); + else if (a==green) + listener->panelChanged (EvWBGreen, Glib::ustring::format (std::setw(4), std::fixed, std::setprecision(3), a->getValue())); + } +} + +void WhiteBalance::optChanged () { + + if (opt!=method->get_active_row_number()) { + opt = method->get_active_row_number(); + Glib::ustring meth = M("TP_WBALANCE_CUSTOM"); + if (opt==0 && wbp) { + double ctemp; double cgreen; + wbp->getCamWB (ctemp, cgreen); + temp->setValue (tempAdd ? 0.0 : (int)ctemp); + green->setValue (greenAdd ? 0.0 : cgreen); + meth = M("TP_WBALANCE_CAMERA"); + if (batchMode) { + temp->setEditedState (UnEdited); + green->setEditedState (UnEdited); + } + } + else if (opt==1 && wbp) { + double ctemp; double cgreen; + wbp->getAutoWB (ctemp, cgreen); + temp->setValue (tempAdd ? 0.0 : (int)ctemp); + green->setValue (greenAdd ? 0.0 : cgreen); + meth = M("TP_WBALANCE_AUTO"); + if (batchMode) { + temp->setEditedState (UnEdited); + green->setEditedState (UnEdited); + } + } + else if (opt==3) { + meth = "(Unchanged)"; + temp->setEditedState (UnEdited); + green->setEditedState (UnEdited); + } + if (listener) + listener->panelChanged (EvWBMethod, meth); + } +} + +void WhiteBalance::spotPressed () { + + if (wblistener) + wblistener->spotWBRequested (getSize()); +} + +void WhiteBalance::spotSizeChanged () { + + if (wblistener) + wblistener->spotWBRequested (getSize()); +} + +void WhiteBalance::read (const ProcParams* pp, const ParamsEdited* pedited) { + + disableListener (); + methconn.block (true); + + if (pedited) { + temp->setEditedState (UnEdited); + green->setEditedState (UnEdited); + } + + if (pedited && !pedited->wb.method) { + method->set_active (3); + opt = 3; + } + else { + if (pp->wb.method == "Camera") { + method->set_active (0); + if (wbp) { + double ctemp; double cgreen; + wbp->getCamWB (ctemp, cgreen); + temp->setValue (tempAdd ? 0.0 : (int)ctemp); + green->setValue (greenAdd ? 0.0 : cgreen); + } + opt = 0; + } + else if (pp->wb.method == "Auto") { + method->set_active (1); + if (wbp) { + double ctemp; double cgreen; + wbp->getAutoWB (ctemp, cgreen); + temp->setValue (tempAdd ? 0.0 : (int)ctemp); + green->setValue (greenAdd ? 0.0 : cgreen); + } + opt = 1; + } + else if (pp->wb.method == "Custom") { + method->set_active (2); + temp->setValue (pp->wb.temperature); + green->setValue (pp->wb.green); + opt = 2; + if (pedited) { + temp->setEditedState (pedited->wb.temperature ? Edited : UnEdited); + green->setEditedState (pedited->wb.green ? Edited : UnEdited); + } + } + } + methconn.block (false); + enableListener (); +} + +void WhiteBalance::write (ProcParams* pp, ParamsEdited* pedited) { + + if (pedited) { + pedited->wb.temperature = temp->getEditedState (); + pedited->wb.green = green->getEditedState (); + pedited->wb.method = method->get_active_row_number()!=3; + } + + if (method->get_active_row_number()==0) + pp->wb.method = "Camera"; + else if (method->get_active_row_number()==1) + pp->wb.method = "Auto"; + else if (method->get_active_row_number()>=2) + pp->wb.method = "Custom"; + + pp->wb.temperature = (int)temp->getValue (); + pp->wb.green = green->getValue (); + +} + +void WhiteBalance::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { + + if (wbp && defParams->wb.method == "Camera") { + double ctemp; double cgreen; + wbp->getCamWB (ctemp, cgreen); + temp->setDefault (tempAdd ? 0 : (int)ctemp); + green->setDefault (greenAdd ? 0 : cgreen); + } + else if (wbp && defParams->wb.method == "Auto") { + double ctemp; double cgreen; + wbp->getAutoWB (ctemp, cgreen); + temp->setDefault (tempAdd ? 0 : (int)ctemp); + green->setDefault (greenAdd ? 0 : cgreen); + } + else if (defParams->wb.method == "Custom") { + temp->setDefault (defParams->wb.temperature); + green->setDefault (defParams->wb.green); + } + if (pedited) { + temp->setDefaultEditedState (pedited->wb.temperature ? Edited : UnEdited); + green->setDefaultEditedState (pedited->wb.green ? Edited : UnEdited); + } + else { + temp->setDefaultEditedState (Irrelevant); + green->setDefaultEditedState (Irrelevant); + } +} + +void WhiteBalance::setBatchMode (bool batchMode) { + + ToolPanel::setBatchMode (batchMode); + temp->showEditedCB (); + green->showEditedCB (); + method->append_text ("(Unchanged)"); +} + +int WhiteBalance::getSize () { + + return atoi(spotsize->get_active_text().c_str()); +} + +void WhiteBalance::setWB (int vtemp, double vgreen) { + + disableListener (); + temp->setValue (vtemp); + green->setValue (vgreen); + method->set_active (2); + temp->setEditedState (Edited); + green->setEditedState (Edited); + enableListener (); + + if (listener) + listener->panelChanged (EvWBTemp, Glib::ustring::compose("%1, %2", (int)temp->getValue(), Glib::ustring::format (std::setw(4), std::fixed, std::setprecision(3), green->getValue()))); +} + void WhiteBalance::setAdjusterBehavior (bool btempadd, bool bgreenadd) { + + if (!tempAdd && btempadd) + temp->setLimits (-4000, +4000, 1, 0); + else if (tempAdd && !btempadd) + temp->setLimits (MINTEMP, MAXTEMP, 1, 4750); + + if (!greenAdd && bgreenadd) + green->setLimits (-1.0, +1.0, 0.001, 0); + else if (greenAdd && bgreenadd) + green->setLimits (MINGREEN, MAXGREEN, 0.001, 1.2); + + tempAdd = btempadd; + greenAdd = bgreenadd; +} + diff --git a/rtgui/whitebalance.h b/rtgui/whitebalance.h new file mode 100755 index 000000000..89e6b97d8 --- /dev/null +++ b/rtgui/whitebalance.h @@ -0,0 +1,71 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _WB_H_ +#define _WB_H_ + +#include +#include +#include +#include + +class SpotWBListener { + + public: + virtual void spotWBRequested (int size) {} +}; + +class WhiteBalance : public Gtk::VBox, public AdjusterListener, public ToolPanel { + + protected: + Gtk::ComboBoxText* method; + Gtk::ComboBoxText* spotsize; + Adjuster* temp; + Adjuster* green; + Gtk::Button* spotbutton; + int opt; + double nextTemp; + double nextGreen; + WBProvider *wbp; + SpotWBListener* wblistener; + sigc::connection methconn; + bool tempAdd, greenAdd; + + public: + + WhiteBalance (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + + + void optChanged (); + void spotPressed (); + void spotSizeChanged (); + void adjusterChanged (Adjuster* a, double newval); + int getSize (); + void setWBProvider (WBProvider* p) { wbp = p; } + void setSpotWBListener (SpotWBListener* l) { wblistener = l; } + void setWB (int temp, double green); + + void setAdjusterBehavior (bool btempadd, bool bgreenadd); +}; + +#endif diff --git a/rtgui/windirmonitor.cc b/rtgui/windirmonitor.cc new file mode 100755 index 000000000..b5284a02a --- /dev/null +++ b/rtgui/windirmonitor.cc @@ -0,0 +1,80 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 + +static void CALLBACK current_directory_monitor_callback (DWORD error, DWORD nBytes, LPOVERLAPPED lpOverlapped) { + +// printf ("hivas: %d %d %d\n", error, nBytes, lpOverlapped); + + WinDirMonitor::MonitorData* monData = (WinDirMonitor::MonitorData*)lpOverlapped; + if (!nBytes) { + delete monData; + return; + } + + if (monData->listener) + monData->listener->winDirChanged (); + + ReadDirectoryChangesW (monData->hDirectory, + monData->file_notify_buffer, + monData->buffer_allocated_bytes, + FALSE, + FILE_NOTIFY_CHANGE_FILE_NAME | + FILE_NOTIFY_CHANGE_DIR_NAME | + FILE_NOTIFY_CHANGE_ATTRIBUTES | + FILE_NOTIFY_CHANGE_SIZE, + &monData->buffer_filled_bytes, + &monData->overlapped, + current_directory_monitor_callback); +} + +WinDirMonitor::WinDirMonitor (Glib::ustring dirName, WinDirChangeListener* listener) : monData(NULL) { + + wchar_t* wdirname = (wchar_t*)g_utf8_to_utf16 (dirName.raw().c_str(), -1, NULL, NULL, NULL); + HANDLE hDirectory = CreateFileW (wdirname, FILE_LIST_DIRECTORY,FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL); + g_free (wdirname); + + if (hDirectory != INVALID_HANDLE_VALUE) { + + monData = new MonitorData (); + monData->listener = listener; + monData->buffer_allocated_bytes = 32768; + monData->file_notify_buffer = new char [monData->buffer_allocated_bytes]; + monData->hDirectory = hDirectory; + +// printf ("mondata=%d\n", monData); + ReadDirectoryChangesW (monData->hDirectory, + monData->file_notify_buffer, + monData->buffer_allocated_bytes, + FALSE, + FILE_NOTIFY_CHANGE_FILE_NAME | + FILE_NOTIFY_CHANGE_DIR_NAME | + FILE_NOTIFY_CHANGE_ATTRIBUTES | + FILE_NOTIFY_CHANGE_SIZE, + &monData->buffer_filled_bytes, + &monData->overlapped, + current_directory_monitor_callback); + } +} + +WinDirMonitor::~WinDirMonitor () { + + if (monData && monData->hDirectory != INVALID_HANDLE_VALUE) + CloseHandle (monData->hDirectory); +} diff --git a/rtgui/windirmonitor.h b/rtgui/windirmonitor.h new file mode 100755 index 000000000..10f4b39f2 --- /dev/null +++ b/rtgui/windirmonitor.h @@ -0,0 +1,53 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _WINDIRMONITOR_ +#define _WINDIRMONITOR_ + +#include +#include + +class WinDirChangeListener { + + public: + virtual void winDirChanged () {} +}; + +class WinDirMonitor : public Glib::Object { + + public: + struct MonitorData { + OVERLAPPED overlapped; + DWORD buffer_allocated_bytes; + char *file_notify_buffer; + DWORD buffer_filled_bytes; + HANDLE hDirectory; + WinDirChangeListener* listener; + int bigyo; + }; + + private: + MonitorData* monData; + + public: + WinDirMonitor (Glib::ustring dirName, WinDirChangeListener* listener); + ~WinDirMonitor (); +}; + +#endif + diff --git a/rtgui/zoompanel.cc b/rtgui/zoompanel.cc new file mode 100755 index 000000000..b8dda6b29 --- /dev/null +++ b/rtgui/zoompanel.cc @@ -0,0 +1,121 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 +#include + +ZoomPanel::ZoomPanel (ImageArea* iarea) : iarea(iarea) { + + set_border_width (0); + + Gtk::Label* label = Gtk::manage (new Gtk::Label (Glib::ustring("") + "Zoom" + ": ")); + label->set_use_markup (true); + + pack_start (*label, Gtk::PACK_SHRINK, 4); + + Gtk::Image* imageOut = Gtk::manage (new Gtk::Image (Gtk::StockID ("gtk-zoom-out"), Gtk::ICON_SIZE_SMALL_TOOLBAR)); + imageOut->set_padding(0,0); + Gtk::Image* imageIn = Gtk::manage (new Gtk::Image (Gtk::StockID ("gtk-zoom-in"), Gtk::ICON_SIZE_SMALL_TOOLBAR)); + imageIn->set_padding(0,0); + Gtk::Image* image11 =Gtk::manage ( new Gtk::Image (Gtk::StockID ("gtk-zoom-100"), Gtk::ICON_SIZE_SMALL_TOOLBAR)); + image11->set_padding(0,0); + Gtk::Image* imageFit = Gtk::manage (new Gtk::Image (Gtk::StockID ("gtk-zoom-fit"), Gtk::ICON_SIZE_SMALL_TOOLBAR)); + imageFit->set_padding(0,0); + + zoomOut = Gtk::manage (new Gtk::Button()); + zoomOut->add (*imageOut); + zoomOut->set_relief(Gtk::RELIEF_NONE); + zoomIn = Gtk::manage (new Gtk::Button()); + zoomIn->add (*imageIn); + zoomIn->set_relief(Gtk::RELIEF_NONE); + zoomFit = Gtk::manage (new Gtk::Button()); + zoomFit->add (*imageFit); + zoomFit->set_relief(Gtk::RELIEF_NONE); + zoom11 = Gtk::manage (new Gtk::Button()); + zoom11->add (*image11); + zoom11->set_relief(Gtk::RELIEF_NONE); + + pack_start (*zoomOut, Gtk::PACK_SHRINK, 0); + pack_start (*zoomIn, Gtk::PACK_SHRINK, 0); + pack_start (*zoomFit, Gtk::PACK_SHRINK, 0); + pack_start (*zoom11, Gtk::PACK_SHRINK, 0); + + zoomLabel = Gtk::manage (new Gtk::Label ()); + pack_start (*zoomLabel, Gtk::PACK_SHRINK, 4); + + Gtk::Image* imageCrop = Gtk::manage (new Gtk::Image (Gtk::StockID ("gtk-add"), Gtk::ICON_SIZE_SMALL_TOOLBAR)); + imageCrop->set_padding(0,0); + newCrop = Gtk::manage (new Gtk::Button()); + newCrop->add (*imageCrop); + newCrop->set_relief(Gtk::RELIEF_NONE); + pack_start (*newCrop, Gtk::PACK_SHRINK, 4); + + show_all_children (); + + zoomIn->signal_clicked().connect ( sigc::mem_fun(*this, &ZoomPanel::zoomInClicked) ); + zoomOut->signal_clicked().connect( sigc::mem_fun(*this, &ZoomPanel::zoomOutClicked) ); + zoomFit->signal_clicked().connect( sigc::mem_fun(*this, &ZoomPanel::zoomFitClicked) ); + zoom11->signal_clicked().connect ( sigc::mem_fun(*this, &ZoomPanel::zoom11Clicked) ); + newCrop->signal_clicked().connect ( sigc::mem_fun(*this, &ZoomPanel::newCropClicked) ); + + zoomIn->set_tooltip_text ("Zoom In"); + zoomOut->set_tooltip_text ("Zoom Out"); + zoom11->set_tooltip_text ("Zoom to 100%"); + zoomFit->set_tooltip_text ("Fit to screen"); + newCrop->set_tooltip_text ("Add new crop window"); + + zoomLabel->set_text ("(100%)"); +} + +void ZoomPanel::zoomInClicked () { + + if (iarea->mainCropWindow) + iarea->mainCropWindow->zoomIn (); +} + +void ZoomPanel::zoomOutClicked () { + + if (iarea->mainCropWindow) + iarea->mainCropWindow->zoomOut (); +} + +void ZoomPanel::zoomFitClicked () { + + if (iarea->mainCropWindow) + iarea->mainCropWindow->zoomFit (); +} + +void ZoomPanel::zoom11Clicked () { + + if (iarea->mainCropWindow) + iarea->mainCropWindow->zoom11 (); +} + +void ZoomPanel::refreshZoomLabel () { + + if (iarea->mainCropWindow) { + int z = (int)(iarea->mainCropWindow->getZoom () * 100); + zoomLabel->set_text (Glib::ustring::compose("%1%%", z)); + } +} + +void ZoomPanel::newCropClicked () { + + iarea->addCropWindow (); +} diff --git a/rtgui/zoompanel.h b/rtgui/zoompanel.h new file mode 100755 index 000000000..2733c0a71 --- /dev/null +++ b/rtgui/zoompanel.h @@ -0,0 +1,50 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 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 . + */ +#ifndef _ZOOMPANEL_ +#define _ZOOMPANEL_ + +#include + +class ImageArea; +class ZoomPanel : public Gtk::HBox { + + protected: + + Gtk::Button* zoomOut; + Gtk::Button* zoomIn; + Gtk::Button* zoomFit; + Gtk::Button* zoom11; + Gtk::Button* newCrop; + Gtk::Label* zoomLabel; + ImageArea* iarea; + + public: + + ZoomPanel (ImageArea* iarea); + + void zoomInClicked (); + void zoomOutClicked (); + void zoomFitClicked (); + void zoom11Clicked (); + void newCropClicked (); + void refreshZoomLabel (); +}; + +#endif + diff --git a/rtinstaller.nsi b/rtinstaller.nsi new file mode 100755 index 000000000..8a7227ed9 --- /dev/null +++ b/rtinstaller.nsi @@ -0,0 +1,135 @@ +;NSIS Modern User Interface +;Start Menu Folder Selection Example Script +;Written by Joost Verburg + +;-------------------------------- +;Include Modern UI + + !include "MUI2.nsh" + +;-------------------------------- +;General + SetCompressor /SOLID lzma + + ;Name and file + Name "Raw Therapee 3.0 alpha 1" + OutFile "rawtherapee30a1.exe" + + ;Default installation folder + InstallDir "$PROGRAMFILES\Raw Therapee 3.0 A1" + + ;Get installation folder from registry if available + InstallDirRegKey HKCU "Software\Raw Therapee 3.0 A1" "" + + ;Request application privileges for Windows Vista + RequestExecutionLevel admin + +;-------------------------------- +;Variables + + Var StartMenuFolder + +;-------------------------------- +;Interface Settings + + !define MUI_ABORTWARNING + +;-------------------------------- +;Pages + +# !insertmacro MUI_PAGE_LICENSE "${NSISDIR}\Docs\Modern UI\License.txt" + !insertmacro MUI_PAGE_COMPONENTS + !insertmacro MUI_PAGE_DIRECTORY + + ;Start Menu Folder Page Configuration + !define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKCU" + !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\Raw Therapee 3.0 A1" + !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder" + !define MUI_STARTMENUPAGE_DEFAULTFOLDER "Raw Therapee" + + !insertmacro MUI_PAGE_STARTMENU Application $StartMenuFolder + + !insertmacro MUI_PAGE_INSTFILES + + !insertmacro MUI_UNPAGE_CONFIRM + !insertmacro MUI_UNPAGE_INSTFILES + +;-------------------------------- +;Languages + + !insertmacro MUI_LANGUAGE "English" + +;-------------------------------- +;Installer Sections + +;First possible component +Section "Binaries" Component1 + SectionIn 1 RO + SetOutPath "$INSTDIR" + + ;ADD YOUR OWN FILES HERE... + AddSize 34553 + File /r /x rtinstaller.nsi *.* + + ;Store installation folder + WriteRegStr HKCU "Software\Raw Therapee" "" $INSTDIR + + ;Create uninstaller + WriteUninstaller "$INSTDIR\Uninstall.exe" + + !insertmacro MUI_STARTMENU_WRITE_BEGIN Application + ;Create shortcuts + CreateDirectory "$SMPROGRAMS\$StartMenuFolder" + CreateShortCut "$SMPROGRAMS\$StartMenuFolder\Raw Therapee.lnk" "$INSTDIR\rt.exe" + CreateShortCut "$SMPROGRAMS\$StartMenuFolder\Uninstall.lnk" "$INSTDIR\Uninstall.exe" + !insertmacro MUI_STARTMENU_WRITE_END +SectionEnd + +Section "Desktop Shortcut" Component2 + ;Create Shortcut + CreateShortCut "$DESKTOP\Raw Therapee.lnk" "$INSTDIR\rt.exe" +SectionEnd + +Section "Quicklaunch Shortcut" Component3 + ;Create Shortcut + CreateShortCut "$QUICKLAUNCH\Raw Therapee.lnk" "$INSTDIR\rt.exe" +SectionEnd +;-------------------------------- +;Descriptions + + ;Language strings + LangString DESC_Component1 ${LANG_ENGLISH} "Raw Therapee Binaries" + LangString DESC_Component2 ${LANG_ENGLISH} "Create Raw Therapee shortcut on desktop" + LangString DESC_Component3 ${LANG_ENGLISH} "Create Raw Therapee shortcut on quicklaunch bar" + + ;Assign language strings to sections + !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN + !insertmacro MUI_DESCRIPTION_TEXT ${Component1} $(DESC_Component1) + !insertmacro MUI_DESCRIPTION_TEXT ${Component2} $(DESC_Component2) + !insertmacro MUI_DESCRIPTION_TEXT ${Component3} $(DESC_Component3) + !insertmacro MUI_FUNCTION_DESCRIPTION_END + +;-------------------------------- +;Uninstaller Section + +Section "Uninstall" + + ;ADD YOUR OWN FILES HERE... + + Delete "$INSTDIR\Uninstall.exe" + + RMDir "$INSTDIR" + + !insertmacro MUI_STARTMENU_GETFOLDER Application $StartMenuFolder + + Delete "$SMPROGRAMS\$StartMenuFolder\Raw Therapee.lnk" + Delete "$SMPROGRAMS\$StartMenuFolder\Uninstall.lnk" + Delete "$DESKTOP\Raw Therapee.lnk" + Delete "$QUICKLAUNCH\Raw Therapee.lnk" + RMDir /r "$INSTDIR" + RMDir "$SMPROGRAMS\$StartMenuFolder" + + DeleteRegKey HKCU "Software\Raw Therapee 3.0 A1" + + +SectionEnd \ No newline at end of file diff --git a/rtstart b/rtstart new file mode 100755 index 000000000..2bc895444 --- /dev/null +++ b/rtstart @@ -0,0 +1,4 @@ +#!/bin/bash + +export LD_LIBRARY_PATH=`dirname "$0"` +`dirname "$0"`/rt \ No newline at end of file diff --git a/tools/createicon.exe b/tools/createicon.exe new file mode 100755 index 0000000000000000000000000000000000000000..0c192be2d73d7a136ec020121b596a0222e1ad27 GIT binary patch literal 315654 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

    IS>|1lH@#SaC3tlFPy9IBt@jPg*e!BHxt4 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 + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/tools/processing.png b/tools/processing.png new file mode 100755 index 0000000000000000000000000000000000000000..33e8c4ed780407e450d486f045173913a2cc48b9 GIT binary patch literal 865 zcmV-n1D^beP)M*xX`tB!(C-jD{GeL~cwpjHvO# zEXE6s+!~|81qlpf28m>J9gu--2gOj#T-mZ_VB53WkJI&>{=G0WUX}u5T^D01VQULn)nv3=Zw* z`Fws4A%sp}4qX7?t7$MjJ-x;_y=$yjuy@}JQhR$F0N|NtchJ7wL8+{lE5bBGH4OrR z0CzSx<_YK)XI⁢N02srC2m3_74uo+x^>EeM18W$ZN;vUzh$f5JHf#u`&7iUERwT zNqYR~_=j?9s|$Kr$F-~1J!--N=;08P5t28N!^~!TS z-Q1?y+Pq$`H5ly0^|>3^)Yyp4&71MWlUt==UoUgHTnqrh;o0(1a``*P`2jjHG4X&g zx==9;box4(v(Aa4UPL;RhN?b-P-q4#sT2SpaVLRjBqmxOZI&fj+5-TLO5z^pQj^=` zw#c%Kxw-54_s;XFDFJonSMJ^NyhlLP@qsKnNTZi5tx~}7sk3WON`Nh+xCbw&uTs?qW06>k3 z@z?otQ>9!k2a82Ui>pOf6y-~g$8DpOBDt6}e4W0s|7riX00sdF0LI4mc-16Z3~KyY zEEZesb~|=-b*cZ~MJAK27!~t#%IL9Lqodhub`t@bIcK;X|J~3u4FHf#-V@2iWL34> zC5uHGt_5!_akZ$IMrUWPo-j@GVk(si?Cj~b$09ME5OP}x(Xy7!kEl-Np$7n95`Zn6 r&dH3jI~S&YQ9#J|1bFjd%^Ud#4ct3n5&tpY00000NkvXXu0mjf`dFzl literal 0 HcmV?d00001 diff --git a/tools/processingb.png b/tools/processingb.png new file mode 100755 index 0000000000000000000000000000000000000000..d34293483862ca9e209313b8a0b8288d414a029d GIT binary patch literal 860 zcmV-i1Ec(jP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iOP= z4<8q`c59jd000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}0008FNklaZW=|D>j1nE~oyf9GET(Ys z)Cp>?*D^OZM^e%XUNyH82m}ynYOkp!2V6_uZ1| zF@PY7qFQ~qlET6Qtg`iwP`P`0dGe@^mrX4RSrH{kLNXZ8Xf=!szb6m~05CD}8Sl6k zi^W3D#+<*xrin(QSA9MoX0sW0PcMq1V6)rkZ0}@naG2TIS?=DsMW>vTFQ mDlZ}#CHngZc=X^g|EnM3Wd}%?c5dAO00006nP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iOP= z4<0ZHXYa58000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}0008BNklHydu_5BTwVKT}z9DBl03B_e zq_0j}e1-Y>d8(=}Ff}!W!Ds}awWS^BfRo~qA~LfwFc^(AKWj!20`>1?S(d49sAY0; zg0tsNV=^TY4u|RP>SllW0bX^#24MY$Y$}c(!Qptj;DKk*&6B1_Bqy2i&Cbx%+lNpD zhYlY^l9u!E!DHNRHzlRTY|PEU<#f^VycMf;H7dW~FK*nb!=9JR%*+guBw;WZxOw9? z`2}0a$h7_CQPY#B#2VwMtT;+kbaXVav9ZXqj5XB?Krk3&`r9;meKg%&uduALkdUx~ z;h_;ip%9W3hr{6nK(jJ2{z@bg!E7<3)oK}VI2rW3!)i_8(Zk0CgCX257ung_+`rdI zI26X^@=$gDA_jv2Rb4}k*jBV~sz@Y4TT44dg(dX8>A{|tix7gk+Ir^Z{N&m5IDP62 zilU&=Xco?>U8beIwS$fJ9AaW(FeRCI@v@UOwsh2LHJ?6y!j@qpJ9c2r$f06-I zilT@+_imAznnL`F_`hG;;UpRP zj?oXJONLFY*X!9;wwu15ew2BE$2~|W6vE^3@O5gMu`grn-nD1R0e^%^mSyfY-o-cT iW9`~?Y%krx|L_CD@+3P)D>h{S0000$r4k8~~{e#(+{O z(PFeEVAsywQTbpn*)#k(IIAE~gnvL67kiP!*I8>ZgRBb9CgQmJ|R`a2U(p5rfl zK&OpOZ+E-`ao0iI@*pFFeI0;Qp|rwZ{>ZtrXQ)*6VT{4^Jc1zjH)dvMxOuxu)EFR< zvJFV2LMe?&*68ma;Qqr0{0e_kES4C*QzZxj(ln*qQ${vx*p@|-X5F%~Cn%K6Hf-Bw zWqAerzmm@o`C00huV)69WU^?S3^U&e-phkSs1KF{6i zIE_Y~dc95*E#kT^y}iB2^}=-rUDRsL47TUUWq`-R_AeePeFn983;%`|9-mf*vpiY7 Z^#}Fz@0W@8dK~}&002ovPDHLkV1h@q2>}2A literal 0 HcmV?d00001 diff --git a/tools/savedb.png b/tools/savedb.png new file mode 100755 index 0000000000000000000000000000000000000000..1d5e809c00e4e60dd62fa9b091fb7ae0fa9888e9 GIT binary patch literal 676 zcmV;V0$crwP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iOP= z4;>!_CX>@2HM@dakSAh-}00061Nkl4KY#X)GHgHtDU z?V=z)aEaBSiVyT&l9DE=-rU^taJV&zPy#t{I2;b2&+mKA`59AZujy3&6t|w;V3=`p zX_a>MBX%l3%k?Ygx$tFuD8a9*OFUfD*kIr~7CYP9LkUu@1sK=>T5C>gjgW#`tvV1K z8yzE^&hTQh0+0x#JUG>$lo}{dTK~5u0+nn`(KghWb( z?)+wE<^+$|*YJOS$MeRyv$BfkdBkx{AzwhWTUe&i6`0)w2Y+c<7R^Qzt9+SOYmZzm zM-)Z)zE8bgPaw-AjzwRBjzma>3#8L&45RmiQ4~?FRtbWjTf{UBIPx#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iOP= z4;~K42J#yK000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}0006CNklA$x*(S~Hhp7^4rCN|oilALOxfSXnD2OO14le!$1;IsI1s5qeI0zOB zibGwj9pm62t>O}^P!&}4UXqZusovb&^Wku75}^co;BYt`p6C6Y^B&{M&1br>yvD7? zDRwh%OwKSdp2vQ*vc|Pb6P*4!w=2P~%ac5qTg28HT*u<`>guipU9N@JU;}8aIiWQ| z3d-eDN3gHAk5nqn>xCk)Es%2iRD)8gqd;l>-^e}XKVnWG+Kj{ zf^wzv74{D9!*N`MY)>E+FW!9P)bSyP4vYd|>;P*(Db35}9|);hf> zWJ}Nx5-AnB@tcv6Lp+*$jQ{gHp4ZQv=@~rFBaUOTd$Ndn4a+o|0<)Q5yO)+_vAMB{ zmA^=>woWFKA&Me=-=|uwCXi(k$D%DkLn5TY1yZRLhS7S$D2gbRN(4dBEMgi4jaao3 zZ2hTYTM6WO9@)Vx^3y!My#rLMReawk2!iG(Gl1w{f~#l7cwYF(=#iv->2#XAx2LJs zL&7kmT(00a4!K+oArff7>!!9l}I#d7v002ovPDHLkV1lzUD6{|o literal 0 HcmV?d00001 diff --git a/tools/tail.png b/tools/tail.png new file mode 100755 index 0000000000000000000000000000000000000000..a40e937505db58efab7ef7b4737e07955128cfd7 GIT binary patch literal 608 zcmV-m0-ybfP)rULO3E?mcnF^wTV`2&A5C!Ta=FGk0ow;+r7Sp6N&b)9IAMZI2=RKcHK8a)A8sQ?Hloh{+ zS@f-Q)AtJtRO!-~^;v5j0}zoFRowuvzK$7e)bHAdt=4K!YaQ$8k8yKg5Uq8rCICQb zi8eH;$yyMAfP_kY^#G!jKRWO{da}7;svZQu9LapVZ6>-CJ(!h_fgcGSW9aI`$m17x zrrL+?`0Rtir$YcUNTRQ|hqlIRC^0HhIQ|YsP&3$fH}dq==v4c#69-)h0BEvWSWb@< zG{T4y1Q0_Z0-_Wrf~UE0c_{Mi^`ptWS2zr?b2iDX8NybCP#}zD9KkXIh$xEW`OXr} zk@K{jy%3#UoF!-H@hop2;N}W=Hl%eLrG6uZpj4?uDVn2a*i3IQpPbJEN1cqzUa+ta zNdB0krLhYULCS+7XnfMS6kgV1BKb1wY7Tg7hv4Ffp4 zF7Doe2sNd(T1ia>P7H?K)tw literal 0 HcmV?d00001 diff --git a/tools/tailb.png b/tools/tailb.png new file mode 100755 index 0000000000000000000000000000000000000000..e22ba7f147c3afa56f9200abbb7f1d5986f3cd13 GIT binary patch literal 659 zcmV;E0&M+>P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iOP= z4_CX>@2HM@dakSAh-}0005*NklCPJ(lp|weEo6JW#nQ<|Z7-x$3!r{O@+~@M%bB+K$e@SW3wO9DL z7%DL^X^>0@=d~q45hVrvqdMLDBveYKeU1%gxN`m)$+W)(0O&A;<70_P2!Jk$-)}`r zMB~=QDTc;(Z3zL0?H|zS9nm6fbjG{5e(o*}{|3({S6KTJ{*zemh{n*#VKUp#qNE*U zd248f&(+}xJb#?$w<}=)Kw3Y<$I1+GEr}>W08t8&An%MH;PUC4xb7W1>S2Is)yS7$ zlGMA2>q&IYK-UaJ6b&3cGfz)vA4mH7c{Be4%XDyKZVTYpo46*d_{%6Ih!RvYL@9bw z8Ge+Pcsn->3aqMwV{Enn`O<3+?l^^r1fhcL<59L3acer+xhK4OWOH;hhFP_7wgpyV zAEp{`VS&Qeh4wb0F?jeAp54Jr{wcYK7L`xU39LHQyP6h?(+!H#jrI=eaOQD><<%1J z3t4gxY*ve{7MdG2j`N3wXnDLVWXavLLpxzsZ5-<#0LS#1y>GMr&5x|tU8`v|VjD$4 tYPYan3ST}kp_AGZjP}NNKN|2q`UUPAv;O68f&c&j002ovPDHLkV1lYC7!?2j literal 0 HcmV?d00001 diff --git a/tools/tailw.png b/tools/tailw.png new file mode 100755 index 0000000000000000000000000000000000000000..cfadaf6b555e87b006bf85d4cced55ff51c4c558 GIT binary patch literal 689 zcmV;i0#5yjP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iOP= z4=A000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}0006ENklLe8S!hBReGsGzTO&xisOX|Dyb&aZHLc1pvCS zz~zCkqXa+|s{mFOD2ht=kr+3hpIA`>;CeKEo7ix)9Jnf|^i*;7U@teG9p^$z9|2!e z`McO~lyGZ=#+su@p_IU^^$W#qbLv1h*Ppi2)7oDy09daE8UHbaNAV)0KmbBYgedkp zPk{D)9b6rZI199FhIr~FUUe-V)r+dQQ582rND3Gv7{OoJ%=WE8-i*8;s~MOsb4g(6 zc}xwG_8d|QgcQid5>nz{)5!PKEb+D3&aC8;g|w1v8`a zc5;yOE%)eo7(z?y7^`zdLC2n3+<6sc^6O~n8Kugh9jCGM3O-B^aWT|S{f4~&WYPw? zs>Kx|!A>H<&XVC=LFeS%TIS|wn3#P>Z`%X5)$RVnwFMo+_-h5HSeD7e+^!zvg8>{P`1^<)Z X!H2_N#5Z>K00000NkvXXu0mjf9i}i5 literal 0 HcmV?d00001 diff --git a/tools/trash.png b/tools/trash.png new file mode 100755 index 0000000000000000000000000000000000000000..c185c78e42b531040c42b88b8a0ec6543031d265 GIT binary patch literal 810 zcmV+_1J(SAP)1w!KZDNz_Gw&_CM0z_h$MBR2mz5;fJ6|i5LeJeHmz8&U_tKz5G%x@a0OgI z7i=g}QK=Ax66{!^aR@Xv>2ZRGRh?dMl*G~RNfdt;j*~Cy)oP972=5lmd~(GcDe-Y`B6lMU6Lb0M zqIh#{jY6ToU^t*$+T_mNZ)hAGDox5b2)du^YW#ksQi*kdk&vGjiwo;3%U6sjiYS*V zeE7jfC{iXTr-4jn47a%eQ6a<(|EkMN0P({ zDF}xHf^L^#7^0Li0OYYC?XtRkS-T+MO0b5YTKk34(wi2Gxh~Hk*T!4i3g?%Ib^H zjGfeHUODS27r8i0wKhI3xp6G<;s@w zJP+G;F-?>6=jYH3o%zB%`TSYt3k4oke^pY`H%_?Id*Xig+P!bT`?9|OB)fdIXkWT8 zuTM=rgB04)g!L!mo!#Bx!Qo*i?)9!oDgRYsxqaY2w>1dYcD8q3wjArVBpENG6hg{U o9EV?zPx#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iOP= z4-X!OXu)p)000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}0007~NklWLFsLov#%;B*Z5ts3@`J<=0wz(&<;4a5 zXh=GnEk@7*6h&dpU1#Hq&qoSd}>~`Pq<1a68Diu^k;rQr?!O1)F zJVya?x3$6dPrl>f=6#Z6Mt5hIgZ&;kl9iQJmY46)?%d_&uUoX54g4_T=bv71a@e0c zs4m^+;pSJA%Vi89aLNvAjWxV;j||mNEZ+kt2Vc>ZltEf?5a_!8|A0l_D2f0uuU;z@3INpWwd?x+1DM4z-8cI< zjzh6n!Y~Y6w}GzfG}oKdYIU0HO?v&KPmW0go&!W-KroroKRjZVrU)UZRw@YH;Gf}$ zcPFR(@p_xR{T_!0d)F-}AD^?Ts#tcJTeeMYsg5oRkmn>x%y>9t5=BhH04e3QgMR_7 WY%SwjIq35M0000Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iOP= z4-Yt0Wkiwy000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}0008vNkl+x;NHEz=NUoP#LvY9am=7-OQ*7rr;qHxd*4 zCrpS&5`z$9qQn>&Fmx-hZi9`r>lH)0yS8`Njyqp;1Bv*&e?H&m$&+s=2!eoJnY9|< z|8SXaFI@sak|g|RKCO0}v*^ z0({cxep0C<`9hB0|CnbeJ3!m@I5M2$vrj+i0j5v9$$N8WiAJNyl0>uF;?c%B=9Wp- zG)bpZjE#@6U)zW0dHBB1cbBhnUPPaoM9!FJG1_m-rO->;Q0-NPB-EN0a zIE3ps*i9S9b@4n8fG|Kf9LCzVsXeJ7D++ymQFL9$Fk%!61%`$Wp-3`M>vc9CmkELZ zK@b3X31(;BqO`g~KA$7-1GcRO+g1bHwyD?aSeAut+q9Z3wEY?jcZ-~yefz}kiwNjpw=SRg@)(z~5nPw7`w|1q{P@QDIO0=@j|=2(eh4txAQz78g-fm6cKn zNtQ89lm7k`;obiK0SKaqs;cO^j_>=FD;1*AJ{t8pnx^484v|RY-+6pxZ*Adv9WGw@is8eDUj_iUuFK6^w^>|TV&Tub6z@HNARwR5F?sA5M<*tjo|;5e c)#nNR0n!FBUGJtfmH+?%07*qoM6N<$f^W8ucK`qY literal 0 HcmV?d00001 diff --git a/tools/undelete.png b/tools/undelete.png new file mode 100755 index 0000000000000000000000000000000000000000..17f7c62f0226a2d4f63559df363c29bef53e7cfe GIT binary patch literal 914 zcmV;D18w|?P)0w_;De~BsH2;1PHDUTu+8H7lcq_Uq)G10&%L=nzO2;)=ka_TI7eW5gv%4NJdO)M zB9Z7;w7?62_TcM&)fWl`1A=8)=!W4~W^1Emx6a$H{n^@NaP|8f2)lr{$B)We`NBKx zp^iz%aeada2ZSfa$B4zcQGGHC3rqZRX@-q-##0s9tmw7R^+Nt-nY+s53-1o>Pfk8O zJfupp%x_nI=iIsXY1A8}Qc2>yaSja)V%xS5*%$V^u6J^7ZZW(EkRL>n zZ2?TnWNRynCNqY@kk1saY=T8NU1}yI zSh{63tCgrUq2T+=hvnvR#n^PU*rFZ^7)!|vj6}907*qoM6N<$g86#Ji~s-t literal 0 HcmV?d00001 diff --git a/tools/undeleteb.png b/tools/undeleteb.png new file mode 100755 index 0000000000000000000000000000000000000000..3119ed6f6ccd333ccc8ee09be1747d7d5d57098a GIT binary patch literal 935 zcmV;Y16cftP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iOP= z4_CX>@2HM@dakSAh-}00095Nklu9~4^JF0Cz#Eh5ncg^jFh1%Dlk9=w}9Zq~$$$tE7WdeC_H zV!Rs9>cNX^Ok5Y%)o5W^C{jWe3N5A3pEE<-DKq0?1J%zT@XC{Xo<{%<|2e6ujD#bM zrBe94J_ZAWbWIaY)6g}Ylgbf|S{1X~1wfnwLI`4sB&mrBY};Y_$`r3JE-*S8Lv>4X zxlMlkZHdBu5mmY<>=iiJecT7)$uTkuuP}f0MO;$y`~3&x^V^&nr%X*fOCp&dm42GP zvTH=bAuP-0?%gHidGtv15_2zHVJI+!R8_8Bnpr4>ot5Gbh;@7iuJ8hcHI>u=S zUDv7C>ol7!bWKAybi7_48=HALoi;AuQ-EloN#^-OZr-}i+QTB%(w{UdE4bZ0hC<_* zW{+k|qgX1lzPZIgsZ2h%{^ScYlY(~^R6e@>24iC*9F`gwhDohvaObByxm_Rmqj6MK zMK~6d&!ky>w8_Rw7MYn#}y6RwmGbvu)R~FTs~qa zzxDq$UQ}8LrqVu)-Y|h+lvkhI!!H{Ee7~Ha-Y_sU4a>3s_!l0HO?nP4^5y^l002ov JPDHLkV1mdVmUI9B literal 0 HcmV?d00001 diff --git a/tools/undeletew.png b/tools/undeletew.png new file mode 100755 index 0000000000000000000000000000000000000000..2bf13763dcb0bec495f66139d1886e4b5bb82f97 GIT binary patch literal 975 zcmV;=12FuFP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iOP= z4_CX>@2HM@dakSAh-}0009jNkl1wU?985Kn`ZXV>?TdO3AUv+F-6Hf*k%9-1=0*{f zdLsxTw8eNpEuvLZY-%x*B3ffajcu(7Zfa?h7?Vx*ls(Mu?9PlAC0Tv{fam+ZhxZe< zZQJ}OtH~r^o*m`m)2FE#6;z)}*)S*;iv;`u9z65_2k(o~7>NKN)&Ztza&q_`J|7uD z*GufVeJ2Bby)-n0QJgZ<(=&Yg-9_dX7V)WG`uqBM{@G`0fVYmHU}EwII@)&QkY#?H zm?R#brC2DkYu8Siwl>kyx}9I9t`H1p2qB?q!5U!To&&`0?ZdD6krjnhD#hH*d6LN_ zi9~`>C`4QP9yZl&qFgFr+cqO-$B@@=FO|#adI_yn!$FCyP3?5`b5ebmi0S?*0S}xDubH6h+eiT*p5DrHO1cHP@TWD=*!R2(5NoSa!UqA>! z)ii4x+#ic^`PcKP`67~H>u z+_jf@_|YET9iHH~@uR49VM5LO@oVi=DpfL>EX#=`3yW7N6ia-1>cd+SfBybG&VBM6 zk3G>%bF-g+7BdtI2B}nmv9IGy-|!M&j-n_E!Zz7)TPrj1>x`fO3i-n5F(xm(!I7tX z2?l)tL>lWiiq+QM#A~mPAruQk1X)>05Q&7D{c8>Y86ja?g2g4BRK~)zEF?+bkOcLc zodg4J9y;8`2Os^3?%9W77gzQW zS;4d{gb=kJboW0(&N0B-CoduiLG17s?7nM=(KDB+R7_-9M%(No8jW(}<^th{E%}FqA7pkfP@Gng;SYs(jlVJb=002ovPDHLkV1jp;xOM;l literal 0 HcmV?d00001 diff --git a/tools/vertical.svg b/tools/vertical.svg new file mode 100755 index 000000000..c8bdaf573 --- /dev/null +++ b/tools/vertical.svg @@ -0,0 +1,201 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/winclude/cderror.h b/winclude/cderror.h new file mode 100755 index 000000000..70435e161 --- /dev/null +++ b/winclude/cderror.h @@ -0,0 +1,132 @@ +/* + * cderror.h + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the error and message codes for the cjpeg/djpeg + * applications. These strings are not needed as part of the JPEG library + * proper. + * Edit this file to add new codes, or to translate the message strings to + * some other language. + */ + +/* + * To define the enum list of message codes, include this file without + * defining macro JMESSAGE. To create a message string table, include it + * again with a suitable JMESSAGE definition (see jerror.c for an example). + */ +#ifndef JMESSAGE +#ifndef CDERROR_H +#define CDERROR_H +/* First time through, define the enum list */ +#define JMAKE_ENUM_LIST +#else +/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */ +#define JMESSAGE(code,string) +#endif /* CDERROR_H */ +#endif /* JMESSAGE */ + +#ifdef JMAKE_ENUM_LIST + +typedef enum { + +#define JMESSAGE(code,string) code , + +#endif /* JMAKE_ENUM_LIST */ + +JMESSAGE(JMSG_FIRSTADDONCODE=1000, NULL) /* Must be first entry! */ + +#ifdef BMP_SUPPORTED +JMESSAGE(JERR_BMP_BADCMAP, "Unsupported BMP colormap format") +JMESSAGE(JERR_BMP_BADDEPTH, "Only 8- and 24-bit BMP files are supported") +JMESSAGE(JERR_BMP_BADHEADER, "Invalid BMP file: bad header length") +JMESSAGE(JERR_BMP_BADPLANES, "Invalid BMP file: biPlanes not equal to 1") +JMESSAGE(JERR_BMP_COLORSPACE, "BMP output must be grayscale or RGB") +JMESSAGE(JERR_BMP_COMPRESSED, "Sorry, compressed BMPs not yet supported") +JMESSAGE(JERR_BMP_NOT, "Not a BMP file - does not start with BM") +JMESSAGE(JTRC_BMP, "%ux%u 24-bit BMP image") +JMESSAGE(JTRC_BMP_MAPPED, "%ux%u 8-bit colormapped BMP image") +JMESSAGE(JTRC_BMP_OS2, "%ux%u 24-bit OS2 BMP image") +JMESSAGE(JTRC_BMP_OS2_MAPPED, "%ux%u 8-bit colormapped OS2 BMP image") +#endif /* BMP_SUPPORTED */ + +#ifdef GIF_SUPPORTED +JMESSAGE(JERR_GIF_BUG, "GIF output got confused") +JMESSAGE(JERR_GIF_CODESIZE, "Bogus GIF codesize %d") +JMESSAGE(JERR_GIF_COLORSPACE, "GIF output must be grayscale or RGB") +JMESSAGE(JERR_GIF_IMAGENOTFOUND, "Too few images in GIF file") +JMESSAGE(JERR_GIF_NOT, "Not a GIF file") +JMESSAGE(JTRC_GIF, "%ux%ux%d GIF image") +JMESSAGE(JTRC_GIF_BADVERSION, + "Warning: unexpected GIF version number '%c%c%c'") +JMESSAGE(JTRC_GIF_EXTENSION, "Ignoring GIF extension block of type 0x%02x") +JMESSAGE(JTRC_GIF_NONSQUARE, "Caution: nonsquare pixels in input") +JMESSAGE(JWRN_GIF_BADDATA, "Corrupt data in GIF file") +JMESSAGE(JWRN_GIF_CHAR, "Bogus char 0x%02x in GIF file, ignoring") +JMESSAGE(JWRN_GIF_ENDCODE, "Premature end of GIF image") +JMESSAGE(JWRN_GIF_NOMOREDATA, "Ran out of GIF bits") +#endif /* GIF_SUPPORTED */ + +#ifdef PPM_SUPPORTED +JMESSAGE(JERR_PPM_COLORSPACE, "PPM output must be grayscale or RGB") +JMESSAGE(JERR_PPM_NONNUMERIC, "Nonnumeric data in PPM file") +JMESSAGE(JERR_PPM_NOT, "Not a PPM/PGM file") +JMESSAGE(JTRC_PGM, "%ux%u PGM image") +JMESSAGE(JTRC_PGM_TEXT, "%ux%u text PGM image") +JMESSAGE(JTRC_PPM, "%ux%u PPM image") +JMESSAGE(JTRC_PPM_TEXT, "%ux%u text PPM image") +#endif /* PPM_SUPPORTED */ + +#ifdef RLE_SUPPORTED +JMESSAGE(JERR_RLE_BADERROR, "Bogus error code from RLE library") +JMESSAGE(JERR_RLE_COLORSPACE, "RLE output must be grayscale or RGB") +JMESSAGE(JERR_RLE_DIMENSIONS, "Image dimensions (%ux%u) too large for RLE") +JMESSAGE(JERR_RLE_EMPTY, "Empty RLE file") +JMESSAGE(JERR_RLE_EOF, "Premature EOF in RLE header") +JMESSAGE(JERR_RLE_MEM, "Insufficient memory for RLE header") +JMESSAGE(JERR_RLE_NOT, "Not an RLE file") +JMESSAGE(JERR_RLE_TOOMANYCHANNELS, "Cannot handle %d output channels for RLE") +JMESSAGE(JERR_RLE_UNSUPPORTED, "Cannot handle this RLE setup") +JMESSAGE(JTRC_RLE, "%ux%u full-color RLE file") +JMESSAGE(JTRC_RLE_FULLMAP, "%ux%u full-color RLE file with map of length %d") +JMESSAGE(JTRC_RLE_GRAY, "%ux%u grayscale RLE file") +JMESSAGE(JTRC_RLE_MAPGRAY, "%ux%u grayscale RLE file with map of length %d") +JMESSAGE(JTRC_RLE_MAPPED, "%ux%u colormapped RLE file with map of length %d") +#endif /* RLE_SUPPORTED */ + +#ifdef TARGA_SUPPORTED +JMESSAGE(JERR_TGA_BADCMAP, "Unsupported Targa colormap format") +JMESSAGE(JERR_TGA_BADPARMS, "Invalid or unsupported Targa file") +JMESSAGE(JERR_TGA_COLORSPACE, "Targa output must be grayscale or RGB") +JMESSAGE(JTRC_TGA, "%ux%u RGB Targa image") +JMESSAGE(JTRC_TGA_GRAY, "%ux%u grayscale Targa image") +JMESSAGE(JTRC_TGA_MAPPED, "%ux%u colormapped Targa image") +#else +JMESSAGE(JERR_TGA_NOTCOMP, "Targa support was not compiled") +#endif /* TARGA_SUPPORTED */ + +JMESSAGE(JERR_BAD_CMAP_FILE, + "Color map file is invalid or of unsupported format") +JMESSAGE(JERR_TOO_MANY_COLORS, + "Output file format cannot handle %d colormap entries") +JMESSAGE(JERR_UNGETC_FAILED, "ungetc failed") +#ifdef TARGA_SUPPORTED +JMESSAGE(JERR_UNKNOWN_FORMAT, + "Unrecognized input file format --- perhaps you need -targa") +#else +JMESSAGE(JERR_UNKNOWN_FORMAT, "Unrecognized input file format") +#endif +JMESSAGE(JERR_UNSUPPORTED_FORMAT, "Unsupported output file format") + +#ifdef JMAKE_ENUM_LIST + + JMSG_LASTADDONCODE +} ADDON_MESSAGE_CODE; + +#undef JMAKE_ENUM_LIST +#endif /* JMAKE_ENUM_LIST */ + +/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */ +#undef JMESSAGE diff --git a/winclude/cdjpeg.h b/winclude/cdjpeg.h new file mode 100755 index 000000000..de83cfb1a --- /dev/null +++ b/winclude/cdjpeg.h @@ -0,0 +1,184 @@ +/* + * cdjpeg.h + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains common declarations for the sample applications + * cjpeg and djpeg. It is NOT used by the core JPEG library. + */ + +#define JPEG_CJPEG_DJPEG /* define proper options in jconfig.h */ +#define JPEG_INTERNAL_OPTIONS /* cjpeg.c,djpeg.c need to see xxx_SUPPORTED */ +#include "jinclude.h" +#include "jpeglib.h" +#include "jerror.h" /* get library error codes too */ +#include "cderror.h" /* get application-specific error codes */ + + +/* + * Object interface for cjpeg's source file decoding modules + */ + +typedef struct cjpeg_source_struct * cjpeg_source_ptr; + +struct cjpeg_source_struct { + JMETHOD(void, start_input, (j_compress_ptr cinfo, + cjpeg_source_ptr sinfo)); + JMETHOD(JDIMENSION, get_pixel_rows, (j_compress_ptr cinfo, + cjpeg_source_ptr sinfo)); + JMETHOD(void, finish_input, (j_compress_ptr cinfo, + cjpeg_source_ptr sinfo)); + + FILE *input_file; + + JSAMPARRAY buffer; + JDIMENSION buffer_height; +}; + + +/* + * Object interface for djpeg's output file encoding modules + */ + +typedef struct djpeg_dest_struct * djpeg_dest_ptr; + +struct djpeg_dest_struct { + /* start_output is called after jpeg_start_decompress finishes. + * The color map will be ready at this time, if one is needed. + */ + JMETHOD(void, start_output, (j_decompress_ptr cinfo, + djpeg_dest_ptr dinfo)); + /* Emit the specified number of pixel rows from the buffer. */ + JMETHOD(void, put_pixel_rows, (j_decompress_ptr cinfo, + djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied)); + /* Finish up at the end of the image. */ + JMETHOD(void, finish_output, (j_decompress_ptr cinfo, + djpeg_dest_ptr dinfo)); + + /* Target file spec; filled in by djpeg.c after object is created. */ + FILE * output_file; + + /* Output pixel-row buffer. Created by module init or start_output. + * Width is cinfo->output_width * cinfo->output_components; + * height is buffer_height. + */ + JSAMPARRAY buffer; + JDIMENSION buffer_height; +}; + + +/* + * cjpeg/djpeg may need to perform extra passes to convert to or from + * the source/destination file format. The JPEG library does not know + * about these passes, but we'd like them to be counted by the progress + * monitor. We use an expanded progress monitor object to hold the + * additional pass count. + */ + +struct cdjpeg_progress_mgr { + struct jpeg_progress_mgr pub; /* fields known to JPEG library */ + int completed_extra_passes; /* extra passes completed */ + int total_extra_passes; /* total extra */ + /* last printed percentage stored here to avoid multiple printouts */ + int percent_done; +}; + +typedef struct cdjpeg_progress_mgr * cd_progress_ptr; + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jinit_read_bmp jIRdBMP +#define jinit_write_bmp jIWrBMP +#define jinit_read_gif jIRdGIF +#define jinit_write_gif jIWrGIF +#define jinit_read_ppm jIRdPPM +#define jinit_write_ppm jIWrPPM +#define jinit_read_rle jIRdRLE +#define jinit_write_rle jIWrRLE +#define jinit_read_targa jIRdTarga +#define jinit_write_targa jIWrTarga +#define read_quant_tables RdQTables +#define read_scan_script RdScnScript +#define set_quant_slots SetQSlots +#define set_sample_factors SetSFacts +#define read_color_map RdCMap +#define enable_signal_catcher EnSigCatcher +#define start_progress_monitor StProgMon +#define end_progress_monitor EnProgMon +#define read_stdin RdStdin +#define write_stdout WrStdout +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + +/* Module selection routines for I/O modules. */ + +EXTERN(cjpeg_source_ptr) jinit_read_bmp JPP((j_compress_ptr cinfo)); +EXTERN(djpeg_dest_ptr) jinit_write_bmp JPP((j_decompress_ptr cinfo, + jboolean is_os2)); +EXTERN(cjpeg_source_ptr) jinit_read_gif JPP((j_compress_ptr cinfo)); +EXTERN(djpeg_dest_ptr) jinit_write_gif JPP((j_decompress_ptr cinfo)); +EXTERN(cjpeg_source_ptr) jinit_read_ppm JPP((j_compress_ptr cinfo)); +EXTERN(djpeg_dest_ptr) jinit_write_ppm JPP((j_decompress_ptr cinfo)); +EXTERN(cjpeg_source_ptr) jinit_read_rle JPP((j_compress_ptr cinfo)); +EXTERN(djpeg_dest_ptr) jinit_write_rle JPP((j_decompress_ptr cinfo)); +EXTERN(cjpeg_source_ptr) jinit_read_targa JPP((j_compress_ptr cinfo)); +EXTERN(djpeg_dest_ptr) jinit_write_targa JPP((j_decompress_ptr cinfo)); + +/* cjpeg support routines (in rdswitch.c) */ + +EXTERN(jboolean) read_quant_tables JPP((j_compress_ptr cinfo, char * filename, + int scale_factor, jboolean force_baseline)); +EXTERN(jboolean) read_scan_script JPP((j_compress_ptr cinfo, char * filename)); +EXTERN(jboolean) set_quant_slots JPP((j_compress_ptr cinfo, char *arg)); +EXTERN(jboolean) set_sample_factors JPP((j_compress_ptr cinfo, char *arg)); + +/* djpeg support routines (in rdcolmap.c) */ + +EXTERN(void) read_color_map JPP((j_decompress_ptr cinfo, FILE * infile)); + +/* common support routines (in cdjpeg.c) */ + +EXTERN(void) enable_signal_catcher JPP((j_common_ptr cinfo)); +EXTERN(void) start_progress_monitor JPP((j_common_ptr cinfo, + cd_progress_ptr progress)); +EXTERN(void) end_progress_monitor JPP((j_common_ptr cinfo)); +EXTERN(jboolean) keymatch JPP((char * arg, const char * keyword, int minchars)); +EXTERN(FILE *) read_stdin JPP((void)); +EXTERN(FILE *) write_stdout JPP((void)); + +/* miscellaneous useful macros */ + +#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */ +#define READ_BINARY "r" +#define WRITE_BINARY "w" +#else +#ifdef VMS /* VMS is very nonstandard */ +#define READ_BINARY "rb", "ctx=stm" +#define WRITE_BINARY "wb", "ctx=stm" +#else /* standard ANSI-compliant case */ +#define READ_BINARY "rb" +#define WRITE_BINARY "wb" +#endif +#endif + +#ifndef EXIT_FAILURE /* define exit() codes if not provided */ +#define EXIT_FAILURE 1 +#endif +#ifndef EXIT_SUCCESS +#ifdef VMS +#define EXIT_SUCCESS 1 /* VMS is very nonstandard */ +#else +#define EXIT_SUCCESS 0 +#endif +#endif +#ifndef EXIT_WARNING +#ifdef VMS +#define EXIT_WARNING 1 /* VMS is very nonstandard */ +#else +#define EXIT_WARNING 2 +#endif +#endif diff --git a/winclude/common.h b/winclude/common.h new file mode 100755 index 000000000..bd5545904 --- /dev/null +++ b/winclude/common.h @@ -0,0 +1,49 @@ +#ifndef _COMMON_ +#define _COMMON_ + +#define ISRED(image,row,col) \ + ((image->filters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3)==0) +#define ISGREEN(image,row,col) \ + ((image->filters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3)==1) +#define ISBLUE(image,row,col) \ + ((image->filters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3)==2) + + +#define CMAXVAL 65535 + +#include + +struct RawImage { + + int width; + int height; + + unsigned filters; + + double red_multiplier; + double green_multiplier; + double blue_multiplier; + + double camwb_red; + double camwb_green; + double camwb_blue; + + int blackpoint; + int rgb_max; + int rotate_deg; + int fuji_width; + + struct tm* time; + float iso_speed, aperture, focal_len, shutter; + char *make, *model; + + int exifbase, exiflocation, exiforder; + + unsigned short** data; // holds pixel values, data[i][j] corresponds to the ith row and jth column + + float coeff[3][4]; + float icoeff[3][4]; + +}; + +#endif diff --git a/winclude/deflate.h b/winclude/deflate.h new file mode 100755 index 000000000..c5958df63 --- /dev/null +++ b/winclude/deflate.h @@ -0,0 +1,318 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2002 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef _DEFLATE_H +#define _DEFLATE_H + +#include "zutil.h" + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + int pending; /* nb of bytes in the pending buffer */ + int noheader; /* suppress zlib header and adler32 */ + Byte data_type; /* UNKNOWN, BINARY or ASCII */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + + /* in trees.c */ +void _tr_init OF((deflate_state *s)); +int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_align OF((deflate_state *s)); +void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch _length_code[]; + extern uch _dist_code[]; +#else + extern const uch _length_code[]; + extern const uch _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif diff --git a/winclude/icc34.h b/winclude/icc34.h new file mode 100755 index 000000000..deca76d02 --- /dev/null +++ b/winclude/icc34.h @@ -0,0 +1,1027 @@ +/* Header file guard bands */ +#ifndef ICC_H +#define ICC_H + +#define PACKAGE_NAME 1 + + +/***************************************************************** + Copyright (c) 1994-1996 SunSoft, Inc. + + Rights Reserved + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without restrict- +ion, including without limitation the rights to use, copy, modify, +merge, publish distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON- +INFRINGEMENT. IN NO EVENT SHALL SUNSOFT, INC. OR ITS PARENT +COMPANY BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of SunSoft, Inc. +shall not be used in advertising or otherwise to promote the +sale, use or other dealings in this Software without written +authorization from SunSoft Inc. +******************************************************************/ + +/* + * This version of the header file corresponds to the profile + * specification version 3.4. + * + * All header file entries are pre-fixed with "ic" to help + * avoid name space collisions. Signatures are pre-fixed with + * icSig. + * + * The structures defined in this header file were created to + * represent a description of an ICC profile on disk. Rather + * than use pointers a technique is used where a single byte array + * was placed at the end of each structure. This allows us in "C" + * to extend the structure by allocating more data than is needed + * to account for variable length structures. + * + * This also ensures that data following is allocated + * contiguously and makes it easier to write and read data from + * the file. + * + * For example to allocate space for a 256 count length UCR + * and BG array, and fill the allocated data. Note strlen + 1 + * to remember NULL terminator. + * + icUcrBgCurve *ucrCurve, *bgCurve; + int ucr_nbytes, bg_nbytes, string_bytes; + icUcrBg *ucrBgWrite; + char ucr_string[100], *ucr_char; + + strcpy(ucr_string, "Example ucrBG curves"); + ucr_nbytes = sizeof(icUInt32Number) + + (UCR_CURVE_SIZE * sizeof(icUInt16Number)); + bg_nbytes = sizeof(icUInt32Number) + + (BG_CURVE_SIZE * sizeof(icUInt16Number)); + string_bytes = strlen(ucr_string) + 1; + + ucrBgWrite = (icUcrBg *)malloc( + (ucr_nbytes + bg_nbytes + string_bytes)); + + ucrCurve = (icUcrBgCurve *)ucrBgWrite->data; + ucrCurve->count = UCR_CURVE_SIZE; + for (i=0; icount; i++) + ucrCurve->curve[i] = (icUInt16Number)i; + + bgCurve = (icUcrBgCurve *)((char *)ucrCurve + ucr_nbytes); + bgCurve->count = BG_CURVE_SIZE; + for (i=0; icount; i++) + bgCurve->curve[i] = 255 - (icUInt16Number)i; + + ucr_char = (char *)((char *)bgCurve + bg_nbytes); + memcpy(ucr_char, ucr_string, string_bytes); + * + */ + +/* + * Many of the structures contain variable length arrays. This + * is represented by the use of the convention. + * + * type data[icAny]; + */ + +/*------------------------------------------------------------------------*/ +/* + * Defines used in the specification + */ +#define icMagicNumber 0x61637370L /* 'acsp' */ +#define icVersionNumber 0x02100000L /* 2.1.0, BCD */ + +/* Screening Encodings */ +#define icPrtrDefaultScreensFalse 0x00000000L /* Bit pos 0 */ +#define icPrtrDefaultScreensTrue 0x00000001L /* Bit pos 0 */ +#define icLinesPerInch 0x00000002L /* Bit pos 1 */ +#define icLinesPerCm 0x00000000L /* Bit pos 1 */ + +/* + * Device attributes, currently defined values correspond + * to the low 4 bytes of the 8 byte attribute quantity, see + * the header for their location. + */ +#define icReflective 0x00000000L /* Bit pos 0 */ +#define icTransparency 0x00000001L /* Bit pos 0 */ +#define icGlossy 0x00000000L /* Bit pos 1 */ +#define icMatte 0x00000002L /* Bit pos 1 */ + +/* + * Profile header flags, the low 16 bits are reserved for consortium + * use. + */ +#define icEmbeddedProfileFalse 0x00000000L /* Bit pos 0 */ +#define icEmbeddedProfileTrue 0x00000001L /* Bit pos 0 */ +#define icUseAnywhere 0x00000000L /* Bit pos 1 */ +#define icUseWithEmbeddedDataOnly 0x00000002L /* Bit pos 1 */ + +/* Ascii or Binary data */ +#define icAsciiData 0x00000000L +#define icBinaryData 0x00000001L + +/* + * Define used to indicate that this is a variable length array + */ +#define icAny 1 + + +/*------------------------------------------------------------------------*/ +/* + * Use this area to translate platform definitions of long + * etc into icXXX form. The rest of the header uses the icXXX + * typedefs. Signatures are 4 byte quantities. + * + */ + + +#ifdef PACKAGE_NAME +/* + June 9, 2003, Adapted for use with configure by Bob Friesenhahn + Added the stupid check for autoconf by Marti Maria. + PACKAGE_NAME is defined if autoconf is being used +*/ + +typedef unsigned char icUInt8Number; +typedef unsigned short icUInt16Number; +typedef unsigned int icUInt32Number; +typedef unsigned int icUInt64Number[2]; + +typedef char icInt8Number; +typedef short icInt16Number; +typedef int icInt32Number; +typedef int icInt64Number[2]; + +#else + +/* + *Apr-17-2002: Modified by Marti Maria in order to provide wider portability. + */ + +#if defined (__digital__) && defined (__unix__) + +/* Tru64 */ + +#include + +typedef uint8_t icUInt8Number; +typedef uint16_t icUInt16Number; +typedef uint32_t icUInt32Number; +typedef uint32_t icUInt64Number[2]; + +typedef int8_t icInt8Number; +typedef int16_t icInt16Number; +typedef int32_t icInt32Number; +typedef int32_t icInt64Number[2]; + +#else +#ifdef __sgi +#include "sgidefs.h" + + +/* + * Number definitions + */ + +/* Unsigned integer numbers */ +typedef unsigned char icUInt8Number; +typedef unsigned short icUInt16Number; +typedef __uint32_t icUInt32Number; +typedef __uint32_t icUInt64Number[2]; + +/* Signed numbers */ +typedef char icInt8Number; +typedef short icInt16Number; +typedef __int32_t icInt32Number; +typedef __int32_t icInt64Number[2]; + + +#else +#if defined(__GNUC__) || defined(__unix__) || defined(__unix) + +#include + +#if defined(__sun) || defined(__hpux) || defined (__MINGW) || defined(__MINGW32__) + +typedef uint8_t icUInt8Number; +typedef uint16_t icUInt16Number; +typedef uint32_t icUInt32Number; +typedef uint32_t icUInt64Number[2]; + +#else + +/* Unsigned integer numbers */ +typedef u_int8_t icUInt8Number; +typedef u_int16_t icUInt16Number; +typedef u_int32_t icUInt32Number; +typedef u_int32_t icUInt64Number[2]; + +#endif + + +/* Signed numbers */ +typedef int8_t icInt8Number; +typedef int16_t icInt16Number; +typedef int32_t icInt32Number; +typedef int32_t icInt64Number[2]; + + +#else /* default definitions */ + +/* + * Number definitions + */ + +/* Unsigned integer numbers */ +typedef unsigned char icUInt8Number; +typedef unsigned short icUInt16Number; +typedef unsigned long icUInt32Number; +typedef unsigned long icUInt64Number[2]; + +/* Signed numbers */ +typedef char icInt8Number; +typedef short icInt16Number; +typedef long icInt32Number; +typedef long icInt64Number[2]; + + +#endif /* default defs */ +#endif +#endif +#endif + +/* Base types */ + +typedef icInt32Number icSignature; +typedef icInt32Number icS15Fixed16Number; +typedef icUInt32Number icU16Fixed16Number; + + +/*------------------------------------------------------------------------*/ +/* public tags and sizes */ +typedef enum { + icSigAToB0Tag = 0x41324230L, /* 'A2B0' */ + icSigAToB1Tag = 0x41324231L, /* 'A2B1' */ + icSigAToB2Tag = 0x41324232L, /* 'A2B2' */ + icSigBlueColorantTag = 0x6258595AL, /* 'bXYZ' */ + icSigBlueTRCTag = 0x62545243L, /* 'bTRC' */ + icSigBToA0Tag = 0x42324130L, /* 'B2A0' */ + icSigBToA1Tag = 0x42324131L, /* 'B2A1' */ + icSigBToA2Tag = 0x42324132L, /* 'B2A2' */ + icSigCalibrationDateTimeTag = 0x63616C74L, /* 'calt' */ + icSigCharTargetTag = 0x74617267L, /* 'targ' */ + icSigCopyrightTag = 0x63707274L, /* 'cprt' */ + icSigCrdInfoTag = 0x63726469L, /* 'crdi' */ + icSigDeviceMfgDescTag = 0x646D6E64L, /* 'dmnd' */ + icSigDeviceModelDescTag = 0x646D6464L, /* 'dmdd' */ + icSigGamutTag = 0x67616D74L, /* 'gamt ' */ + icSigGrayTRCTag = 0x6b545243L, /* 'kTRC' */ + icSigGreenColorantTag = 0x6758595AL, /* 'gXYZ' */ + icSigGreenTRCTag = 0x67545243L, /* 'gTRC' */ + icSigLuminanceTag = 0x6C756d69L, /* 'lumi' */ + icSigMeasurementTag = 0x6D656173L, /* 'meas' */ + icSigMediaBlackPointTag = 0x626B7074L, /* 'bkpt' */ + icSigMediaWhitePointTag = 0x77747074L, /* 'wtpt' */ + icSigNamedColorTag = 0x6E636f6CL, /* 'ncol' + * OBSOLETE, use ncl2 */ + icSigNamedColor2Tag = 0x6E636C32L, /* 'ncl2' */ + icSigPreview0Tag = 0x70726530L, /* 'pre0' */ + icSigPreview1Tag = 0x70726531L, /* 'pre1' */ + icSigPreview2Tag = 0x70726532L, /* 'pre2' */ + icSigProfileDescriptionTag = 0x64657363L, /* 'desc' */ + icSigProfileSequenceDescTag = 0x70736571L, /* 'pseq' */ + icSigPs2CRD0Tag = 0x70736430L, /* 'psd0' */ + icSigPs2CRD1Tag = 0x70736431L, /* 'psd1' */ + icSigPs2CRD2Tag = 0x70736432L, /* 'psd2' */ + icSigPs2CRD3Tag = 0x70736433L, /* 'psd3' */ + icSigPs2CSATag = 0x70733273L, /* 'ps2s' */ + icSigPs2RenderingIntentTag = 0x70733269L, /* 'ps2i' */ + icSigRedColorantTag = 0x7258595AL, /* 'rXYZ' */ + icSigRedTRCTag = 0x72545243L, /* 'rTRC' */ + icSigScreeningDescTag = 0x73637264L, /* 'scrd' */ + icSigScreeningTag = 0x7363726EL, /* 'scrn' */ + icSigTechnologyTag = 0x74656368L, /* 'tech' */ + icSigUcrBgTag = 0x62666420L, /* 'bfd ' */ + icSigViewingCondDescTag = 0x76756564L, /* 'vued' */ + icSigViewingConditionsTag = 0x76696577L, /* 'view' */ + icMaxEnumTag = 0xFFFFFFFFL +} icTagSignature; + +/* technology signature descriptions */ +typedef enum { + icSigDigitalCamera = 0x6463616DL, /* 'dcam' */ + icSigFilmScanner = 0x6673636EL, /* 'fscn' */ + icSigReflectiveScanner = 0x7273636EL, /* 'rscn' */ + icSigInkJetPrinter = 0x696A6574L, /* 'ijet' */ + icSigThermalWaxPrinter = 0x74776178L, /* 'twax' */ + icSigElectrophotographicPrinter = 0x6570686FL, /* 'epho' */ + icSigElectrostaticPrinter = 0x65737461L, /* 'esta' */ + icSigDyeSublimationPrinter = 0x64737562L, /* 'dsub' */ + icSigPhotographicPaperPrinter = 0x7270686FL, /* 'rpho' */ + icSigFilmWriter = 0x6670726EL, /* 'fprn' */ + icSigVideoMonitor = 0x7669646DL, /* 'vidm' */ + icSigVideoCamera = 0x76696463L, /* 'vidc' */ + icSigProjectionTelevision = 0x706A7476L, /* 'pjtv' */ + icSigCRTDisplay = 0x43525420L, /* 'CRT ' */ + icSigPMDisplay = 0x504D4420L, /* 'PMD ' */ + icSigAMDisplay = 0x414D4420L, /* 'AMD ' */ + icSigPhotoCD = 0x4B504344L, /* 'KPCD' */ + icSigPhotoImageSetter = 0x696D6773L, /* 'imgs' */ + icSigGravure = 0x67726176L, /* 'grav' */ + icSigOffsetLithography = 0x6F666673L, /* 'offs' */ + icSigSilkscreen = 0x73696C6BL, /* 'silk' */ + icSigFlexography = 0x666C6578L, /* 'flex' */ + icMaxEnumTechnology = 0xFFFFFFFFL +} icTechnologySignature; + +/* type signatures */ +typedef enum { + icSigCurveType = 0x63757276L, /* 'curv' */ + icSigDataType = 0x64617461L, /* 'data' */ + icSigDateTimeType = 0x6474696DL, /* 'dtim' */ + icSigLut16Type = 0x6d667432L, /* 'mft2' */ + icSigLut8Type = 0x6d667431L, /* 'mft1' */ + icSigMeasurementType = 0x6D656173L, /* 'meas' */ + icSigNamedColorType = 0x6E636f6CL, /* 'ncol' + * OBSOLETE, use ncl2 */ + icSigProfileSequenceDescType = 0x70736571L, /* 'pseq' */ + icSigS15Fixed16ArrayType = 0x73663332L, /* 'sf32' */ + icSigScreeningType = 0x7363726EL, /* 'scrn' */ + icSigSignatureType = 0x73696720L, /* 'sig ' */ + icSigTextType = 0x74657874L, /* 'text' */ + icSigTextDescriptionType = 0x64657363L, /* 'desc' */ + icSigU16Fixed16ArrayType = 0x75663332L, /* 'uf32' */ + icSigUcrBgType = 0x62666420L, /* 'bfd ' */ + icSigUInt16ArrayType = 0x75693136L, /* 'ui16' */ + icSigUInt32ArrayType = 0x75693332L, /* 'ui32' */ + icSigUInt64ArrayType = 0x75693634L, /* 'ui64' */ + icSigUInt8ArrayType = 0x75693038L, /* 'ui08' */ + icSigViewingConditionsType = 0x76696577L, /* 'view' */ + icSigXYZType = 0x58595A20L, /* 'XYZ ' */ + icSigXYZArrayType = 0x58595A20L, /* 'XYZ ' */ + icSigNamedColor2Type = 0x6E636C32L, /* 'ncl2' */ + icSigCrdInfoType = 0x63726469L, /* 'crdi' */ + icMaxEnumType = 0xFFFFFFFFL +} icTagTypeSignature; + +/* + * Color Space Signatures + * Note that only icSigXYZData and icSigLabData are valid + * Profile Connection Spaces (PCSs) + */ +typedef enum { + icSigXYZData = 0x58595A20L, /* 'XYZ ' */ + icSigLabData = 0x4C616220L, /* 'Lab ' */ + icSigLuvData = 0x4C757620L, /* 'Luv ' */ + icSigYCbCrData = 0x59436272L, /* 'YCbr' */ + icSigYxyData = 0x59787920L, /* 'Yxy ' */ + icSigRgbData = 0x52474220L, /* 'RGB ' */ + icSigGrayData = 0x47524159L, /* 'GRAY' */ + icSigHsvData = 0x48535620L, /* 'HSV ' */ + icSigHlsData = 0x484C5320L, /* 'HLS ' */ + icSigCmykData = 0x434D594BL, /* 'CMYK' */ + icSigCmyData = 0x434D5920L, /* 'CMY ' */ + icSig2colorData = 0x32434C52L, /* '2CLR' */ + icSig3colorData = 0x33434C52L, /* '3CLR' */ + icSig4colorData = 0x34434C52L, /* '4CLR' */ + icSig5colorData = 0x35434C52L, /* '5CLR' */ + icSig6colorData = 0x36434C52L, /* '6CLR' */ + icSig7colorData = 0x37434C52L, /* '7CLR' */ + icSig8colorData = 0x38434C52L, /* '8CLR' */ + icSig9colorData = 0x39434C52L, /* '9CLR' */ + icSig10colorData = 0x41434C52L, /* 'ACLR' */ + icSig11colorData = 0x42434C52L, /* 'BCLR' */ + icSig12colorData = 0x43434C52L, /* 'CCLR' */ + icSig13colorData = 0x44434C52L, /* 'DCLR' */ + icSig14colorData = 0x45434C52L, /* 'ECLR' */ + icSig15colorData = 0x46434C52L, /* 'FCLR' */ + icMaxEnumData = 0xFFFFFFFFL +} icColorSpaceSignature; + +/* profileClass enumerations */ +typedef enum { + icSigInputClass = 0x73636E72L, /* 'scnr' */ + icSigDisplayClass = 0x6D6E7472L, /* 'mntr' */ + icSigOutputClass = 0x70727472L, /* 'prtr' */ + icSigLinkClass = 0x6C696E6BL, /* 'link' */ + icSigAbstractClass = 0x61627374L, /* 'abst' */ + icSigColorSpaceClass = 0x73706163L, /* 'spac' */ + icSigNamedColorClass = 0x6e6d636cL, /* 'nmcl' */ + icMaxEnumClass = 0xFFFFFFFFL +} icProfileClassSignature; + +/* Platform Signatures */ +typedef enum { + icSigMacintosh = 0x4150504CL, /* 'APPL' */ + icSigMicrosoft = 0x4D534654L, /* 'MSFT' */ + icSigSolaris = 0x53554E57L, /* 'SUNW' */ + icSigSGI = 0x53474920L, /* 'SGI ' */ + icSigTaligent = 0x54474E54L, /* 'TGNT' */ + icMaxEnumPlatform = 0xFFFFFFFFL +} icPlatformSignature; + +/*------------------------------------------------------------------------*/ +/* + * Other enums + */ + +/* Measurement Flare, used in the measurmentType tag */ +typedef enum { + icFlare0 = 0x00000000L, /* 0% flare */ + icFlare100 = 0x00000001L, /* 100% flare */ + icMaxFlare = 0xFFFFFFFFL +} icMeasurementFlare; + +/* Measurement Geometry, used in the measurmentType tag */ +typedef enum { + icGeometryUnknown = 0x00000000L, /* Unknown */ + icGeometry045or450 = 0x00000001L, /* 0/45, 45/0 */ + icGeometry0dord0 = 0x00000002L, /* 0/d or d/0 */ + icMaxGeometry = 0xFFFFFFFFL +} icMeasurementGeometry; + +/* Rendering Intents, used in the profile header */ +typedef enum { + icPerceptual = 0, + icRelativeColorimetric = 1, + icSaturation = 2, + icAbsoluteColorimetric = 3, + icMaxEnumIntent = 0xFFFFFFFFL +} icRenderingIntent; + +/* Different Spot Shapes currently defined, used for screeningType */ +typedef enum { + icSpotShapeUnknown = 0, + icSpotShapePrinterDefault = 1, + icSpotShapeRound = 2, + icSpotShapeDiamond = 3, + icSpotShapeEllipse = 4, + icSpotShapeLine = 5, + icSpotShapeSquare = 6, + icSpotShapeCross = 7, + icMaxEnumSpot = 0xFFFFFFFFL +} icSpotShape; + +/* Standard Observer, used in the measurmentType tag */ +typedef enum { + icStdObsUnknown = 0x00000000L, /* Unknown */ + icStdObs1931TwoDegrees = 0x00000001L, /* 2 deg */ + icStdObs1964TenDegrees = 0x00000002L, /* 10 deg */ + icMaxStdObs = 0xFFFFFFFFL +} icStandardObserver; + +/* Pre-defined illuminants, used in measurement and viewing conditions type */ +typedef enum { + icIlluminantUnknown = 0x00000000L, + icIlluminantD50 = 0x00000001L, + icIlluminantD65 = 0x00000002L, + icIlluminantD93 = 0x00000003L, + icIlluminantF2 = 0x00000004L, + icIlluminantD55 = 0x00000005L, + icIlluminantA = 0x00000006L, + icIlluminantEquiPowerE = 0x00000007L, + icIlluminantF8 = 0x00000008L, + icMaxEnumIluminant = 0xFFFFFFFFL +} icIlluminant; + + +/*------------------------------------------------------------------------*/ +/* + * Arrays of numbers + */ + +/* Int8 Array */ +typedef struct { + icInt8Number data[icAny]; /* Variable array of values */ +} icInt8Array; + +/* UInt8 Array */ +typedef struct { + icUInt8Number data[icAny]; /* Variable array of values */ +} icUInt8Array; + +/* uInt16 Array */ +typedef struct { + icUInt16Number data[icAny]; /* Variable array of values */ +} icUInt16Array; + +/* Int16 Array */ +typedef struct { + icInt16Number data[icAny]; /* Variable array of values */ +} icInt16Array; + +/* uInt32 Array */ +typedef struct { + icUInt32Number data[icAny]; /* Variable array of values */ +} icUInt32Array; + +/* Int32 Array */ +typedef struct { + icInt32Number data[icAny]; /* Variable array of values */ +} icInt32Array; + +/* UInt64 Array */ +typedef struct { + icUInt64Number data[icAny]; /* Variable array of values */ +} icUInt64Array; + +/* Int64 Array */ +typedef struct { + icInt64Number data[icAny]; /* Variable array of values */ +} icInt64Array; + +/* u16Fixed16 Array */ +typedef struct { + icU16Fixed16Number data[icAny]; /* Variable array of values */ +} icU16Fixed16Array; + +/* s15Fixed16 Array */ +typedef struct { + icS15Fixed16Number data[icAny]; /* Variable array of values */ +} icS15Fixed16Array; + +/* The base date time number */ +typedef struct { + icUInt16Number year; + icUInt16Number month; + icUInt16Number day; + icUInt16Number hours; + icUInt16Number minutes; + icUInt16Number seconds; +} icDateTimeNumber; + +/* XYZ Number */ +typedef struct { + icS15Fixed16Number X; + icS15Fixed16Number Y; + icS15Fixed16Number Z; +} icXYZNumber; + +/* XYZ Array */ +typedef struct { + icXYZNumber data[icAny]; /* Variable array of XYZ numbers */ +} icXYZArray; + +/* Curve */ +typedef struct { + icUInt32Number count; /* Number of entries */ + icUInt16Number data[icAny]; /* The actual table data, real + * number is determined by count + * Interpretation depends on how + * data is used with a given tag + */ +} icCurve; + +/* Data */ +typedef struct { + icUInt32Number dataFlag; /* 0 = ascii, 1 = binary */ + icInt8Number data[icAny]; /* Data, size from tag */ +} icData; + +/* lut16 */ +typedef struct { + icUInt8Number inputChan; /* Number of input channels */ + icUInt8Number outputChan; /* Number of output channels */ + icUInt8Number clutPoints; /* Number of grid points */ + icInt8Number pad; /* Padding for byte alignment */ + icS15Fixed16Number e00; /* e00 in the 3 * 3 */ + icS15Fixed16Number e01; /* e01 in the 3 * 3 */ + icS15Fixed16Number e02; /* e02 in the 3 * 3 */ + icS15Fixed16Number e10; /* e10 in the 3 * 3 */ + icS15Fixed16Number e11; /* e11 in the 3 * 3 */ + icS15Fixed16Number e12; /* e12 in the 3 * 3 */ + icS15Fixed16Number e20; /* e20 in the 3 * 3 */ + icS15Fixed16Number e21; /* e21 in the 3 * 3 */ + icS15Fixed16Number e22; /* e22 in the 3 * 3 */ + icUInt16Number inputEnt; /* Num of in-table entries */ + icUInt16Number outputEnt; /* Num of out-table entries */ + icUInt16Number data[icAny]; /* Data follows see spec */ +/* + * Data that follows is of this form + * + * icUInt16Number inputTable[inputChan][icAny]; * The in-table + * icUInt16Number clutTable[icAny]; * The clut + * icUInt16Number outputTable[outputChan][icAny]; * The out-table + */ +} icLut16; + +/* lut8, input & output tables are always 256 bytes in length */ +typedef struct { + icUInt8Number inputChan; /* Num of input channels */ + icUInt8Number outputChan; /* Num of output channels */ + icUInt8Number clutPoints; /* Num of grid points */ + icInt8Number pad; + icS15Fixed16Number e00; /* e00 in the 3 * 3 */ + icS15Fixed16Number e01; /* e01 in the 3 * 3 */ + icS15Fixed16Number e02; /* e02 in the 3 * 3 */ + icS15Fixed16Number e10; /* e10 in the 3 * 3 */ + icS15Fixed16Number e11; /* e11 in the 3 * 3 */ + icS15Fixed16Number e12; /* e12 in the 3 * 3 */ + icS15Fixed16Number e20; /* e20 in the 3 * 3 */ + icS15Fixed16Number e21; /* e21 in the 3 * 3 */ + icS15Fixed16Number e22; /* e22 in the 3 * 3 */ + icUInt8Number data[icAny]; /* Data follows see spec */ +/* + * Data that follows is of this form + * + * icUInt8Number inputTable[inputChan][256]; * The in-table + * icUInt8Number clutTable[icAny]; * The clut + * icUInt8Number outputTable[outputChan][256]; * The out-table + */ +} icLut8; + +/* Measurement Data */ +typedef struct { + icStandardObserver stdObserver; /* Standard observer */ + icXYZNumber backing; /* XYZ for backing */ + icMeasurementGeometry geometry; /* Meas. geometry */ + icMeasurementFlare flare; /* Measurement flare */ + icIlluminant illuminant; /* Illuminant */ +} icMeasurement; + +/* Named color */ + +/* + * icNamedColor2 takes the place of icNamedColor + */ +typedef struct { + icUInt32Number vendorFlag; /* Bottom 16 bits for IC use */ + icUInt32Number count; /* Count of named colors */ + icUInt32Number nDeviceCoords; /* Num of device coordinates */ + icInt8Number prefix[32]; /* Prefix for each color name */ + icInt8Number suffix[32]; /* Suffix for each color name */ + icInt8Number data[icAny]; /* Named color data follows */ +/* + * Data that follows is of this form + * + * icInt8Number root1[32]; * Root name for 1st color + * icUInt16Number pcsCoords1[icAny]; * PCS coords of 1st color + * icUInt16Number deviceCoords1[icAny]; * Dev coords of 1st color + * icInt8Number root2[32]; * Root name for 2nd color + * icUInt16Number pcsCoords2[icAny]; * PCS coords of 2nd color + * icUInt16Number deviceCoords2[icAny]; * Dev coords of 2nd color + * : + * : + * Repeat for name and PCS and device color coordinates up to (count-1) + * + * NOTES: + * PCS and device space can be determined from the header. + * + * PCS coordinates are icUInt16 numbers and are described in Annex A of + * the ICC spec. Only 16 bit L*a*b* and XYZ are allowed. The number of + * coordinates is consistent with the headers PCS. + * + * Device coordinates are icUInt16 numbers where 0x0000 represents + * the minimum value and 0xFFFF represents the maximum value. + * If the nDeviceCoords value is 0 this field is not given. + */ +} icNamedColor2; + +/* Profile sequence structure */ +typedef struct { + icSignature deviceMfg; /* Dev Manufacturer */ + icSignature deviceModel; /* Dev Model */ + icUInt64Number attributes; /* Dev attributes */ + icTechnologySignature technology; /* Technology sig */ + icInt8Number data[icAny]; /* Desc text follows */ +/* + * Data that follows is of this form, this is an icInt8Number + * to avoid problems with a compiler generating bad code as + * these arrays are variable in length. + * + * icTextDescription deviceMfgDesc; * Manufacturer text + * icTextDescription modelDesc; * Model text + */ +} icDescStruct; + +/* Profile sequence description */ +typedef struct { + icUInt32Number count; /* Number of descriptions */ + icUInt8Number data[icAny]; /* Array of desc structs */ +} icProfileSequenceDesc; + +/* textDescription */ +typedef struct { + icUInt32Number count; /* Description length */ + icInt8Number data[icAny]; /* Descriptions follow */ +/* + * Data that follows is of this form + * + * icInt8Number desc[count] * NULL terminated ascii string + * icUInt32Number ucLangCode; * UniCode language code + * icUInt32Number ucCount; * UniCode description length + * icInt16Number ucDesc[ucCount];* The UniCode description + * icUInt16Number scCode; * ScriptCode code + * icUInt8Number scCount; * ScriptCode count + * icInt8Number scDesc[67]; * ScriptCode Description + */ +} icTextDescription; + +/* Screening Data */ +typedef struct { + icS15Fixed16Number frequency; /* Frequency */ + icS15Fixed16Number angle; /* Screen angle */ + icSpotShape spotShape; /* Spot Shape encodings below */ +} icScreeningData; + +typedef struct { + icUInt32Number screeningFlag; /* Screening flag */ + icUInt32Number channels; /* Number of channels */ + icScreeningData data[icAny]; /* Array of screening data */ +} icScreening; + +/* Text Data */ +typedef struct { + icInt8Number data[icAny]; /* Variable array of chars */ +} icText; + +/* Structure describing either a UCR or BG curve */ +typedef struct { + icUInt32Number count; /* Curve length */ + icUInt16Number curve[icAny]; /* The array of curve values */ +} icUcrBgCurve; + +/* Under color removal, black generation */ +typedef struct { + icInt8Number data[icAny]; /* The Ucr BG data */ +/* + * Data that follows is of this form, this is a icInt8Number + * to avoid problems with a compiler generating bad code as + * these arrays are variable in length. + * + * icUcrBgCurve ucr; * Ucr curve + * icUcrBgCurve bg; * Bg curve + * icInt8Number string; * UcrBg description + */ +} icUcrBg; + +/* viewingConditionsType */ +typedef struct { + icXYZNumber illuminant; /* In candelas per sq. meter */ + icXYZNumber surround; /* In candelas per sq. meter */ + icIlluminant stdIluminant; /* See icIlluminant defines */ +} icViewingCondition; + +/* CrdInfo type */ +typedef struct { + icUInt32Number count; /* Char count includes NULL */ + icInt8Number desc[icAny]; /* Null terminated string */ +} icCrdInfo; + +/*------------------------------------------------------------------------*/ +/* + * Tag Type definitions + */ + +/* + * Many of the structures contain variable length arrays. This + * is represented by the use of the convention. + * + * type data[icAny]; + */ + +/* The base part of each tag */ +typedef struct { + icTagTypeSignature sig; /* Signature */ + icInt8Number reserved[4]; /* Reserved, set to 0 */ +} icTagBase; + +/* curveType */ +typedef struct { + icTagBase base; /* Signature, "curv" */ + icCurve curve; /* The curve data */ +} icCurveType; + +/* dataType */ +typedef struct { + icTagBase base; /* Signature, "data" */ + icData data; /* The data structure */ +} icDataType; + +/* dateTimeType */ +typedef struct { + icTagBase base; /* Signature, "dtim" */ + icDateTimeNumber date; /* The date */ +} icDateTimeType; + +/* lut16Type */ +typedef struct { + icTagBase base; /* Signature, "mft2" */ + icLut16 lut; /* Lut16 data */ +} icLut16Type; + +/* lut8Type, input & output tables are always 256 bytes in length */ +typedef struct { + icTagBase base; /* Signature, "mft1" */ + icLut8 lut; /* Lut8 data */ +} icLut8Type; + +/* Measurement Type */ +typedef struct { + icTagBase base; /* Signature, "meas" */ + icMeasurement measurement; /* Measurement data */ +} icMeasurementType; + +/* Named color type */ +/* icNamedColor2Type, replaces icNamedColorType */ +typedef struct { + icTagBase base; /* Signature, "ncl2" */ + icNamedColor2 ncolor; /* Named color data */ +} icNamedColor2Type; + +/* Profile sequence description type */ +typedef struct { + icTagBase base; /* Signature, "pseq" */ + icProfileSequenceDesc desc; /* The seq description */ +} icProfileSequenceDescType; + +/* textDescriptionType */ +typedef struct { + icTagBase base; /* Signature, "desc" */ + icTextDescription desc; /* The description */ +} icTextDescriptionType; + +/* s15Fixed16Type */ +typedef struct { + icTagBase base; /* Signature, "sf32" */ + icS15Fixed16Array data; /* Array of values */ +} icS15Fixed16ArrayType; + +typedef struct { + icTagBase base; /* Signature, "scrn" */ + icScreening screen; /* Screening structure */ +} icScreeningType; + +/* sigType */ +typedef struct { + icTagBase base; /* Signature, "sig" */ + icSignature signature; /* The signature data */ +} icSignatureType; + +/* textType */ +typedef struct { + icTagBase base; /* Signature, "text" */ + icText data; /* Variable array of chars */ +} icTextType; + +/* u16Fixed16Type */ +typedef struct { + icTagBase base; /* Signature, "uf32" */ + icU16Fixed16Array data; /* Variable array of values */ +} icU16Fixed16ArrayType; + +/* Under color removal, black generation type */ +typedef struct { + icTagBase base; /* Signature, "bfd " */ + icUcrBg data; /* ucrBg structure */ +} icUcrBgType; + +/* uInt16Type */ +typedef struct { + icTagBase base; /* Signature, "ui16" */ + icUInt16Array data; /* Variable array of values */ +} icUInt16ArrayType; + +/* uInt32Type */ +typedef struct { + icTagBase base; /* Signature, "ui32" */ + icUInt32Array data; /* Variable array of values */ +} icUInt32ArrayType; + +/* uInt64Type */ +typedef struct { + icTagBase base; /* Signature, "ui64" */ + icUInt64Array data; /* Variable array of values */ +} icUInt64ArrayType; + +/* uInt8Type */ +typedef struct { + icTagBase base; /* Signature, "ui08" */ + icUInt8Array data; /* Variable array of values */ +} icUInt8ArrayType; + +/* viewingConditionsType */ +typedef struct { + icTagBase base; /* Signature, "view" */ + icViewingCondition view; /* Viewing conditions */ +} icViewingConditionType; + +/* XYZ Type */ +typedef struct { + icTagBase base; /* Signature, "XYZ" */ + icXYZArray data; /* Variable array of XYZ nums */ +} icXYZType; + +/* CRDInfoType where [0] is the CRD product name count and string and + * [1] -[5] are the rendering intents 0-4 counts and strings + */ +typedef struct { + icTagBase base; /* Signature, "crdi" */ + icCrdInfo info; /* 5 sets of counts & strings */ +}icCrdInfoType; + /* icCrdInfo productName; PS product count/string */ + /* icCrdInfo CRDName0; CRD name for intent 0 */ + /* icCrdInfo CRDName1; CRD name for intent 1 */ + /* icCrdInfo CRDName2; CRD name for intent 2 */ + /* icCrdInfo CRDName3; CRD name for intent 3 */ + +/*------------------------------------------------------------------------*/ + +/* + * Lists of tags, tags, profile header and profile structure + */ + +/* A tag */ +typedef struct { + icTagSignature sig; /* The tag signature */ + icUInt32Number offset; /* Start of tag relative to + * start of header, Spec + * Clause 5 */ + icUInt32Number size; /* Size in bytes */ +} icTag; + +/* A Structure that may be used independently for a list of tags */ +typedef struct { + icUInt32Number count; /* Num tags in the profile */ + icTag tags[icAny]; /* Variable array of tags */ +} icTagList; + +/* The Profile header */ +typedef struct { + icUInt32Number size; /* Prof size in bytes */ + icSignature cmmId; /* CMM for profile */ + icUInt32Number version; /* Format version */ + icProfileClassSignature deviceClass; /* Type of profile */ + icColorSpaceSignature colorSpace; /* Clr space of data */ + icColorSpaceSignature pcs; /* PCS, XYZ or Lab */ + icDateTimeNumber date; /* Creation Date */ + icSignature magic; /* icMagicNumber */ + icPlatformSignature platform; /* Primary Platform */ + icUInt32Number flags; /* Various bits */ + icSignature manufacturer; /* Dev manufacturer */ + icUInt32Number model; /* Dev model number */ + icUInt64Number attributes; /* Device attributes */ + icUInt32Number renderingIntent;/* Rendering intent */ + icXYZNumber illuminant; /* Profile illuminant */ + icSignature creator; /* Profile creator */ + icInt8Number reserved[44]; /* Reserved */ +} icHeader; + +/* + * A profile, + * we can't use icTagList here because its not at the end of the structure + */ +typedef struct { + icHeader header; /* The header */ + icUInt32Number count; /* Num tags in the profile */ + icInt8Number data[icAny]; /* The tagTable and tagData */ +/* + * Data that follows is of the form + * + * icTag tagTable[icAny]; * The tag table + * icInt8Number tagData[icAny]; * The tag data + */ +} icProfile; + +/*------------------------------------------------------------------------*/ +/* Obsolete entries */ + +/* icNamedColor was replaced with icNamedColor2 */ +typedef struct { + icUInt32Number vendorFlag; /* Bottom 16 bits for IC use */ + icUInt32Number count; /* Count of named colors */ + icInt8Number data[icAny]; /* Named color data follows */ +/* + * Data that follows is of this form + * + * icInt8Number prefix[icAny]; * Prefix + * icInt8Number suffix[icAny]; * Suffix + * icInt8Number root1[icAny]; * Root name + * icInt8Number coords1[icAny]; * Color coordinates + * icInt8Number root2[icAny]; * Root name + * icInt8Number coords2[icAny]; * Color coordinates + * : + * : + * Repeat for root name and color coordinates up to (count-1) + */ +} icNamedColor; + +/* icNamedColorType was replaced by icNamedColor2Type */ +typedef struct { + icTagBase base; /* Signature, "ncol" */ + icNamedColor ncolor; /* Named color data */ +} icNamedColorType; + +#endif /* ICC_H */ diff --git a/winclude/infblock.h b/winclude/infblock.h new file mode 100755 index 000000000..4cf0fa969 --- /dev/null +++ b/winclude/infblock.h @@ -0,0 +1,39 @@ +/* infblock.h -- header to use infblock.c + * Copyright (C) 1995-2002 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_blocks_state; +typedef struct inflate_blocks_state FAR inflate_blocks_statef; + +extern inflate_blocks_statef * inflate_blocks_new OF(( + z_streamp z, + check_func c, /* check function */ + uInt w)); /* window size */ + +extern int inflate_blocks OF(( + inflate_blocks_statef *, + z_streamp , + int)); /* initial return code */ + +extern void inflate_blocks_reset OF(( + inflate_blocks_statef *, + z_streamp , + uLongf *)); /* check value on output */ + +extern int inflate_blocks_free OF(( + inflate_blocks_statef *, + z_streamp)); + +extern void inflate_set_dictionary OF(( + inflate_blocks_statef *s, + const Bytef *d, /* dictionary */ + uInt n)); /* dictionary length */ + +extern int inflate_blocks_sync_point OF(( + inflate_blocks_statef *s)); diff --git a/winclude/infcodes.h b/winclude/infcodes.h new file mode 100755 index 000000000..531d41927 --- /dev/null +++ b/winclude/infcodes.h @@ -0,0 +1,27 @@ +/* infcodes.h -- header to use infcodes.c + * Copyright (C) 1995-2002 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_codes_state; +typedef struct inflate_codes_state FAR inflate_codes_statef; + +extern inflate_codes_statef *inflate_codes_new OF(( + uInt, uInt, + inflate_huft *, inflate_huft *, + z_streamp )); + +extern int inflate_codes OF(( + inflate_blocks_statef *, + z_streamp , + int)); + +extern void inflate_codes_free OF(( + inflate_codes_statef *, + z_streamp )); + diff --git a/winclude/inffast.h b/winclude/inffast.h new file mode 100755 index 000000000..ac643b329 --- /dev/null +++ b/winclude/inffast.h @@ -0,0 +1,17 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2002 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +extern int inflate_fast OF(( + uInt, + uInt, + inflate_huft *, + inflate_huft *, + inflate_blocks_statef *, + z_streamp )); diff --git a/winclude/inffixed.h b/winclude/inffixed.h new file mode 100755 index 000000000..e997507c3 --- /dev/null +++ b/winclude/inffixed.h @@ -0,0 +1,151 @@ +/* inffixed.h -- table for decoding fixed codes + * Generated automatically by the maketree.c program + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +local uInt fixed_bl = 9; +local uInt fixed_bd = 5; +local inflate_huft fixed_tl[] = { + {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, + {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192}, + {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160}, + {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224}, + {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144}, + {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208}, + {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176}, + {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240}, + {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, + {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200}, + {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168}, + {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232}, + {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152}, + {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216}, + {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184}, + {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248}, + {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, + {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196}, + {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164}, + {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228}, + {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148}, + {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212}, + {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180}, + {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244}, + {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204}, + {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172}, + {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236}, + {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156}, + {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220}, + {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188}, + {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252}, + {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, + {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194}, + {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162}, + {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226}, + {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146}, + {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210}, + {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178}, + {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242}, + {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, + {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202}, + {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170}, + {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234}, + {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154}, + {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218}, + {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186}, + {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250}, + {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, + {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198}, + {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166}, + {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230}, + {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150}, + {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214}, + {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182}, + {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246}, + {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206}, + {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174}, + {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238}, + {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158}, + {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222}, + {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190}, + {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254}, + {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, + {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193}, + {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161}, + {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225}, + {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145}, + {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209}, + {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177}, + {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241}, + {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, + {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201}, + {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169}, + {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233}, + {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153}, + {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217}, + {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185}, + {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249}, + {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, + {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197}, + {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165}, + {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229}, + {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149}, + {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213}, + {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181}, + {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245}, + {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205}, + {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173}, + {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237}, + {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157}, + {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221}, + {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189}, + {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253}, + {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, + {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195}, + {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163}, + {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227}, + {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147}, + {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211}, + {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179}, + {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243}, + {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, + {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203}, + {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171}, + {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235}, + {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155}, + {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219}, + {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187}, + {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251}, + {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, + {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199}, + {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167}, + {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231}, + {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151}, + {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215}, + {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183}, + {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247}, + {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207}, + {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175}, + {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239}, + {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159}, + {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223}, + {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191}, + {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255} + }; +local inflate_huft fixed_td[] = { + {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097}, + {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385}, + {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193}, + {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577}, + {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145}, + {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577}, + {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289}, + {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577} + }; diff --git a/winclude/inftrees.h b/winclude/inftrees.h new file mode 100755 index 000000000..affbb3b21 --- /dev/null +++ b/winclude/inftrees.h @@ -0,0 +1,58 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2002 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Huffman code lookup table entry--this entry is four bytes for machines + that have 16-bit pointers (e.g. PC's in the small or medium model). */ + +typedef struct inflate_huft_s FAR inflate_huft; + +struct inflate_huft_s { + union { + struct { + Byte Exop; /* number of extra bits or operation */ + Byte Bits; /* number of bits in this code or subcode */ + } what; + uInt pad; /* pad structure to a power of 2 (4 bytes for */ + } word; /* 16-bit, 8 bytes for 32-bit int's) */ + uInt base; /* literal, length base, distance base, + or table offset */ +}; + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1004 huft structures (850 for length/literals + and 154 for distances, the latter actually the result of an + exhaustive search). The actual maximum is not known, but the + value below is more than safe. */ +#define MANY 1440 + +extern int inflate_trees_bits OF(( + uIntf *, /* 19 code lengths */ + uIntf *, /* bits tree desired/actual depth */ + inflate_huft * FAR *, /* bits tree result */ + inflate_huft *, /* space for trees */ + z_streamp)); /* for messages */ + +extern int inflate_trees_dynamic OF(( + uInt, /* number of literal/length codes */ + uInt, /* number of distance codes */ + uIntf *, /* that many (total) code lengths */ + uIntf *, /* literal desired/actual bit depth */ + uIntf *, /* distance desired/actual bit depth */ + inflate_huft * FAR *, /* literal/length tree result */ + inflate_huft * FAR *, /* distance tree result */ + inflate_huft *, /* space for trees */ + z_streamp)); /* for messages */ + +extern int inflate_trees_fixed OF(( + uIntf *, /* literal desired/actual bit depth */ + uIntf *, /* distance desired/actual bit depth */ + inflate_huft * FAR *, /* literal/length tree result */ + inflate_huft * FAR *, /* distance tree result */ + z_streamp)); /* for memory allocation */ diff --git a/winclude/infutil.h b/winclude/infutil.h new file mode 100755 index 000000000..0c0ace366 --- /dev/null +++ b/winclude/infutil.h @@ -0,0 +1,98 @@ +/* infutil.h -- types and macros common to blocks and codes + * Copyright (C) 1995-2002 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +#ifndef _INFUTIL_H +#define _INFUTIL_H + +typedef enum { + TYPE, /* get type bits (3, including end bit) */ + LENS, /* get lengths for stored */ + STORED, /* processing stored block */ + TABLE, /* get table lengths */ + BTREE, /* get bit lengths tree for a dynamic block */ + DTREE, /* get length, distance trees for a dynamic block */ + CODES, /* processing fixed or dynamic block */ + DRY, /* output remaining window bytes */ + DONE, /* finished last block, done */ + BAD} /* got a data error--stuck here */ +inflate_block_mode; + +/* inflate blocks semi-private state */ +struct inflate_blocks_state { + + /* mode */ + inflate_block_mode mode; /* current inflate_block mode */ + + /* mode dependent information */ + union { + uInt left; /* if STORED, bytes left to copy */ + struct { + uInt table; /* table lengths (14 bits) */ + uInt index; /* index into blens (or border) */ + uIntf *blens; /* bit lengths of codes */ + uInt bb; /* bit length tree depth */ + inflate_huft *tb; /* bit length decoding tree */ + } trees; /* if DTREE, decoding info for trees */ + struct { + inflate_codes_statef + *codes; + } decode; /* if CODES, current state */ + } sub; /* submode */ + uInt last; /* true if this block is the last block */ + + /* mode independent information */ + uInt bitk; /* bits in bit buffer */ + uLong bitb; /* bit buffer */ + inflate_huft *hufts; /* single malloc for tree space */ + Bytef *window; /* sliding window */ + Bytef *end; /* one byte after sliding window */ + Bytef *read; /* window read pointer */ + Bytef *write; /* window write pointer */ + check_func checkfn; /* check function */ + uLong check; /* check on output */ + +}; + + +/* defines for inflate input/output */ +/* update pointers and return */ +#define UPDBITS {s->bitb=b;s->bitk=k;} +#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;} +#define UPDOUT {s->write=q;} +#define UPDATE {UPDBITS UPDIN UPDOUT} +#define LEAVE {UPDATE return inflate_flush(s,z,r);} +/* get bytes and bits */ +#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} +#define NEEDBYTE {if(n)r=Z_OK;else LEAVE} +#define NEXTBYTE (n--,*p++) +#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<>=(j);k-=(j);} +/* output bytes */ +#define WAVAIL (uInt)(qread?s->read-q-1:s->end-q) +#define LOADOUT {q=s->write;m=(uInt)WAVAIL;} +#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}} +#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} +#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;} +#define OUTBYTE(a) {*q++=(Byte)(a);m--;} +/* load local pointers */ +#define LOAD {LOADIN LOADOUT} + +/* masks for lower bits (size given to avoid silly warnings with Visual C++) */ +extern uInt inflate_mask[17]; + +/* copy as much as possible from the sliding window to the output area */ +extern int inflate_flush OF(( + inflate_blocks_statef *, + z_streamp , + int)); + +struct internal_state {int dummy;}; /* for buggy compilers */ + +#endif diff --git a/winclude/jchuff.h b/winclude/jchuff.h new file mode 100755 index 000000000..a914f45d7 --- /dev/null +++ b/winclude/jchuff.h @@ -0,0 +1,47 @@ +/* + * jchuff.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains declarations for Huffman entropy encoding routines + * that are shared between the sequential encoder (jchuff.c) and the + * progressive encoder (jcphuff.c). No other modules need to see these. + */ + +/* The legal range of a DCT coefficient is + * -1024 .. +1023 for 8-bit data; + * -16384 .. +16383 for 12-bit data. + * Hence the magnitude should always fit in 10 or 14 bits respectively. + */ + +#if BITS_IN_JSAMPLE == 8 +#define MAX_COEF_BITS 10 +#else +#define MAX_COEF_BITS 14 +#endif + +/* Derived data constructed for each Huffman table */ + +typedef struct { + unsigned int ehufco[256]; /* code for each symbol */ + char ehufsi[256]; /* length of code for each symbol */ + /* If no code has been allocated for a symbol S, ehufsi[S] contains 0 */ +} c_derived_tbl; + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_make_c_derived_tbl jMkCDerived +#define jpeg_gen_optimal_table jGenOptTbl +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + +/* Expand a Huffman table definition into the derived format */ +EXTERN(void) jpeg_make_c_derived_tbl + JPP((j_compress_ptr cinfo, jboolean isDC, int tblno, + c_derived_tbl ** pdtbl)); + +/* Generate an optimal table definition given the specified counts */ +EXTERN(void) jpeg_gen_optimal_table + JPP((j_compress_ptr cinfo, JHUFF_TBL * htbl, long freq[])); diff --git a/winclude/jconfig.h b/winclude/jconfig.h new file mode 100755 index 000000000..9594ec56b --- /dev/null +++ b/winclude/jconfig.h @@ -0,0 +1,45 @@ +/* jconfig.h. Generated automatically by configure. */ +/* jconfig.cfg --- source file edited by configure script */ +/* see jconfig.doc for explanations */ + +#define HAVE_PROTOTYPES +#define HAVE_UNSIGNED_CHAR +#define HAVE_UNSIGNED_SHORT +#undef void +#undef const +#undef CHAR_IS_UNSIGNED +#define HAVE_STDDEF_H +#define HAVE_STDLIB_H +#undef NEED_BSD_STRINGS +#undef NEED_SYS_TYPES_H +#undef NEED_FAR_POINTERS +#undef NEED_SHORT_EXTERNAL_NAMES +/* Define this if you get warnings about undefined structures. */ +#undef INCOMPLETE_TYPES_BROKEN + +#ifdef JPEG_INTERNALS + +#undef RIGHT_SHIFT_IS_UNSIGNED +#define INLINE __inline__ +/* These are for configuring the JPEG memory manager. */ +#undef DEFAULT_MAX_MEM +#undef NO_MKTEMP + +#endif /* JPEG_INTERNALS */ + +#ifdef JPEG_CJPEG_DJPEG + +#define BMP_SUPPORTED /* BMP image file format */ +#define GIF_SUPPORTED /* GIF image file format */ +#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */ +#undef RLE_SUPPORTED /* Utah RLE image file format */ +#define TARGA_SUPPORTED /* Targa image file format */ + +#undef TWO_FILE_COMMANDLINE +#undef NEED_SIGNAL_CATCHER +#undef DONT_USE_B_MODE + +/* Define this if you want percent-done progress reports from cjpeg/djpeg. */ +#undef PROGRESS_REPORT + +#endif /* JPEG_CJPEG_DJPEG */ diff --git a/winclude/jdatasrc.c b/winclude/jdatasrc.c new file mode 100755 index 000000000..bfbd9e802 --- /dev/null +++ b/winclude/jdatasrc.c @@ -0,0 +1,408 @@ +/* + * jdatasrc.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains decompression data source routines for the case of + * reading JPEG data from a file (or any stdio stream). While these routines + * are sufficient for most applications, some will want to use a different + * source manager. + * IMPORTANT: we assume that fread() will correctly transcribe an array of + * JOCTETs from 8-bit-wide elements on external storage. If char is wider + * than 8 bits on your machine, you may need to do some tweaking. + */ + +/* this is not a core library module, so it doesn't define JPEG_INTERNALS */ +//#include "jinclude.h" +#include +#include +#include + +#define JFREAD(file,buf,sizeofbuf) \ + ((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) +#define JFWRITE(file,buf,sizeofbuf) \ + ((size_t) fwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) + + + + +/* Expanded data source object for stdio input */ + +typedef struct { + struct jpeg_source_mgr pub; /* public fields */ + + FILE * infile; /* source stream */ + JOCTET * buffer; /* start of buffer */ + jboolean start_of_file; /* have we gotten any data yet? */ +} my_source_mgr; + +typedef my_source_mgr * my_src_ptr; + +#define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */ + + +/* + * Initialize source --- called by jpeg_read_header + * before any data is actually read. + */ + +METHODDEF(void) +my_init_source (j_decompress_ptr cinfo) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + /* We reset the empty-input-file flag for each image, + * but we don't clear the input buffer. + * This is correct behavior for reading a series of images from one source. + */ + src->start_of_file = TRUE; +} + + +/* + * Fill the input buffer --- called whenever buffer is emptied. + * + * In typical applications, this should read fresh data into the buffer + * (ignoring the current state of next_input_byte & bytes_in_buffer), + * reset the pointer & count to the start of the buffer, and return TRUE + * indicating that the buffer has been reloaded. It is not necessary to + * fill the buffer entirely, only to obtain at least one more byte. + * + * There is no such thing as an EOF return. If the end of the file has been + * reached, the routine has a choice of ERREXIT() or inserting fake data into + * the buffer. In most cases, generating a warning message and inserting a + * fake EOI marker is the best course of action --- this will allow the + * decompressor to output however much of the image is there. However, + * the resulting error message is misleading if the real problem is an empty + * input file, so we handle that case specially. + * + * In applications that need to be able to suspend compression due to input + * not being available yet, a FALSE return indicates that no more data can be + * obtained right now, but more may be forthcoming later. In this situation, + * the decompressor will return to its caller (with an indication of the + * number of scanlines it has read, if any). The application should resume + * decompression after it has loaded more data into the input buffer. Note + * that there are substantial restrictions on the use of suspension --- see + * the documentation. + * + * When suspending, the decompressor will back up to a convenient restart point + * (typically the start of the current MCU). next_input_byte & bytes_in_buffer + * indicate where the restart point will be if the current call returns FALSE. + * Data beyond this point must be rescanned after resumption, so move it to + * the front of the buffer rather than discarding it. + */ + +METHODDEF(jboolean) +my_fill_input_buffer (j_decompress_ptr cinfo) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + size_t nbytes; + + nbytes = JFREAD(src->infile, src->buffer, INPUT_BUF_SIZE); + + if (nbytes <= 0) { + if (src->start_of_file) /* Treat empty input file as fatal error */ + ERREXIT(cinfo, JERR_INPUT_EMPTY); + WARNMS(cinfo, JWRN_JPEG_EOF); + /* Insert a fake EOI marker */ + src->buffer[0] = (JOCTET) 0xFF; + src->buffer[1] = (JOCTET) JPEG_EOI; + nbytes = 2; + } + + if (src->start_of_file) + src->buffer[0] = (JOCTET) 0xFF; + + src->pub.next_input_byte = src->buffer; + src->pub.bytes_in_buffer = nbytes; + src->start_of_file = FALSE; + + return TRUE; +} + + +/* + * Skip data --- used to skip over a potentially large amount of + * uninteresting data (such as an APPn marker). + * + * Writers of suspendable-input applications must note that skip_input_data + * is not granted the right to give a suspension return. If the skip extends + * beyond the data currently in the buffer, the buffer can be marked empty so + * that the next read will cause a fill_input_buffer call that can suspend. + * Arranging for additional bytes to be discarded before reloading the input + * buffer is the application writer's problem. + */ + +METHODDEF(void) +my_skip_input_data (j_decompress_ptr cinfo, long num_bytes) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + /* Just a dumb implementation for now. Could use fseek() except + * it doesn't work on pipes. Not clear that being smart is worth + * any trouble anyway --- large skips are infrequent. + */ + if (num_bytes > 0) { + while (num_bytes > (long) src->pub.bytes_in_buffer) { + num_bytes -= (long) src->pub.bytes_in_buffer; + (void) my_fill_input_buffer(cinfo); + /* note we assume that fill_input_buffer will never return FALSE, + * so suspension need not be handled. + */ + } + src->pub.next_input_byte += (size_t) num_bytes; + src->pub.bytes_in_buffer -= (size_t) num_bytes; + } +} + + +/* + * An additional method that can be provided by data source modules is the + * resync_to_restart method for error recovery in the presence of RST markers. + * For the moment, this source module just uses the default resync method + * provided by the JPEG library. That method assumes that no backtracking + * is possible. + */ + + +/* + * Terminate source --- called by jpeg_finish_decompress + * after all data has been read. Often a no-op. + * + * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding + * application must deal with any cleanup that should happen even + * for error exit. + */ + +METHODDEF(void) +my_term_source (j_decompress_ptr cinfo) +{ + /* no work necessary here */ +} + + +/* + * Prepare for input from a stdio stream. + * The caller must have already opened the stream, and is responsible + * for closing it after finishing decompression. + */ + +GLOBAL(void) +my_jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile) +{ + my_src_ptr src; + + /* The source object and input buffer are made permanent so that a series + * of JPEG images can be read from the same file by calling jpeg_stdio_src + * only before the first one. (If we discarded the buffer at the end of + * one image, we'd likely lose the start of the next one.) + * This makes it unsafe to use this manager and a different source + * manager serially with the same JPEG object. Caveat programmer. + */ + if (cinfo->src == NULL) { /* first time for this JPEG object? */ + cinfo->src = (struct jpeg_source_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + sizeof(my_source_mgr)); + src = (my_src_ptr) cinfo->src; + src->buffer = (JOCTET *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + INPUT_BUF_SIZE * sizeof(JOCTET)); + } + + src = (my_src_ptr) cinfo->src; + src->pub.init_source = my_init_source; + src->pub.fill_input_buffer = my_fill_input_buffer; + src->pub.skip_input_data = my_skip_input_data; + src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ + src->pub.term_source = my_term_source; + src->infile = infile; + src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ + src->pub.next_input_byte = NULL; /* until buffer loaded */ +} + +jmp_buf jpeg_jmp_buf; + +METHODDEF(void) +my_error_exit (j_common_ptr cinfo) +{ + /* Always display the message */ + (*cinfo->err->output_message) (cinfo); + + /* Let the memory manager delete any temp files before we die */ + jpeg_destroy(cinfo); + + longjmp (jpeg_jmp_buf, 1); +} + + +//const char * const jpeg_std_message_table[] = { +//#include "jerror.h" +// NULL +//}; +extern const char * const jpeg_std_message_table[]; + + +/* + * Actual output of an error or trace message. + * Applications may override this method to send JPEG messages somewhere + * other than stderr. + * + * On Windows, printing to stderr is generally completely useless, + * so we provide optional code to produce an error-dialog popup. + * Most Windows applications will still prefer to override this routine, + * but if they don't, it'll do something at least marginally useful. + * + * NOTE: to use the library in an environment that doesn't support the + * C stdio library, you may have to delete the call to fprintf() entirely, + * not just not use this routine. + */ + +METHODDEF(void) +output_message (j_common_ptr cinfo) +{ + char buffer[JMSG_LENGTH_MAX]; + + /* Create the message */ + (*cinfo->err->format_message) (cinfo, buffer); + +#ifdef USE_WINDOWS_MESSAGEBOX + /* Display it in a message dialog box */ + MessageBox(GetActiveWindow(), buffer, "JPEG Library Error", + MB_OK | MB_ICONERROR); +#else + /* Send it to stderr, adding a newline */ + fprintf(stderr, "%s\n", buffer); +#endif +} + + +/* + * Decide whether to emit a trace or warning message. + * msg_level is one of: + * -1: recoverable corrupt-data warning, may want to abort. + * 0: important advisory messages (always display to user). + * 1: first level of tracing detail. + * 2,3,...: successively more detailed tracing messages. + * An application might override this method if it wanted to abort on warnings + * or change the policy about which messages to display. + */ + +METHODDEF(void) +emit_message (j_common_ptr cinfo, int msg_level) +{ + struct jpeg_error_mgr * err = cinfo->err; + + if (msg_level < 0) { + /* It's a warning message. Since corrupt files may generate many warnings, + * the policy implemented here is to show only the first warning, + * unless trace_level >= 3. + */ + if (err->num_warnings == 0 || err->trace_level >= 3) + (*err->output_message) (cinfo); + /* Always count warnings in num_warnings. */ + err->num_warnings++; + } else { + /* It's a trace message. Show it if trace_level >= msg_level. */ + if (err->trace_level >= msg_level) + (*err->output_message) (cinfo); + } +} + + +/* + * Format a message string for the most recent JPEG error or message. + * The message is stored into buffer, which should be at least JMSG_LENGTH_MAX + * characters. Note that no '\n' character is added to the string. + * Few applications should need to override this method. + */ + +METHODDEF(void) +format_message (j_common_ptr cinfo, char * buffer) +{ + struct jpeg_error_mgr * err = cinfo->err; + int msg_code = err->msg_code; + const char * msgtext = NULL; + const char * msgptr; + char ch; + jboolean isstring; + + /* Look up message string in proper table */ + if (msg_code > 0 && msg_code <= err->last_jpeg_message) { + msgtext = err->jpeg_message_table[msg_code]; + } else if (err->addon_message_table != NULL && + msg_code >= err->first_addon_message && + msg_code <= err->last_addon_message) { + msgtext = err->addon_message_table[msg_code - err->first_addon_message]; + } + + /* Defend against bogus message number */ + if (msgtext == NULL) { + err->msg_parm.i[0] = msg_code; + msgtext = err->jpeg_message_table[0]; + } + + /* Check for string parameter, as indicated by %s in the message text */ + isstring = FALSE; + msgptr = msgtext; + while ((ch = *msgptr++) != '\0') { + if (ch == '%') { + if (*msgptr == 's') isstring = TRUE; + break; + } + } + + /* Format the message into the passed buffer */ + if (isstring) + sprintf(buffer, msgtext, err->msg_parm.s); + else + sprintf(buffer, msgtext, + err->msg_parm.i[0], err->msg_parm.i[1], + err->msg_parm.i[2], err->msg_parm.i[3], + err->msg_parm.i[4], err->msg_parm.i[5], + err->msg_parm.i[6], err->msg_parm.i[7]); +} + + +/* + * Reset error state variables at start of a new image. + * This is called during compression startup to reset trace/error + * processing to default state, without losing any application-specific + * method pointers. An application might possibly want to override + * this method if it has additional error processing state. + */ + +METHODDEF(void) +reset_error_mgr (j_common_ptr cinfo) +{ + cinfo->err->num_warnings = 0; + /* trace_level is not reset since it is an application-supplied parameter */ + cinfo->err->msg_code = 0; /* may be useful as a flag for "no error" */ +} + + +GLOBAL(struct jpeg_error_mgr *) +my_jpeg_std_error (struct jpeg_error_mgr * err) +{ + + err->error_exit = my_error_exit; + err->emit_message = emit_message; + err->output_message = output_message; + err->format_message = format_message; + err->reset_error_mgr = reset_error_mgr; + + err->trace_level = 0; /* default = no tracing */ + err->num_warnings = 0; /* no warnings emitted yet */ + err->msg_code = 0; /* may be useful as a flag for "no error" */ + + /* Initialize message table pointers */ + err->jpeg_message_table = jpeg_std_message_table; + err->last_jpeg_message = (int) JMSG_LASTMSGCODE - 1; + + err->addon_message_table = NULL; + err->first_addon_message = 0; /* for safety */ + err->last_addon_message = 0; + + return err; +} diff --git a/winclude/jdct.h b/winclude/jdct.h new file mode 100755 index 000000000..04192a266 --- /dev/null +++ b/winclude/jdct.h @@ -0,0 +1,176 @@ +/* + * jdct.h + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This include file contains common declarations for the forward and + * inverse DCT modules. These declarations are private to the DCT managers + * (jcdctmgr.c, jddctmgr.c) and the individual DCT algorithms. + * The individual DCT algorithms are kept in separate files to ease + * machine-dependent tuning (e.g., assembly coding). + */ + + +/* + * A forward DCT routine is given a pointer to a work area of type DCTELEM[]; + * the DCT is to be performed in-place in that buffer. Type DCTELEM is int + * for 8-bit samples, INT32 for 12-bit samples. (NOTE: Floating-point DCT + * implementations use an array of type FAST_FLOAT, instead.) + * The DCT inputs are expected to be signed (range +-CENTERJSAMPLE). + * The DCT outputs are returned scaled up by a factor of 8; they therefore + * have a range of +-8K for 8-bit data, +-128K for 12-bit data. This + * convention improves accuracy in integer implementations and saves some + * work in floating-point ones. + * Quantization of the output coefficients is done by jcdctmgr.c. + */ + +#if BITS_IN_JSAMPLE == 8 +typedef int DCTELEM; /* 16 or 32 bits is fine */ +#else +typedef INT32 DCTELEM; /* must have 32 bits */ +#endif + +typedef JMETHOD(void, forward_DCT_method_ptr, (DCTELEM * data)); +typedef JMETHOD(void, float_DCT_method_ptr, (FAST_FLOAT * data)); + + +/* + * An inverse DCT routine is given a pointer to the input JBLOCK and a pointer + * to an output sample array. The routine must dequantize the input data as + * well as perform the IDCT; for dequantization, it uses the multiplier table + * pointed to by compptr->dct_table. The output data is to be placed into the + * sample array starting at a specified column. (Any row offset needed will + * be applied to the array pointer before it is passed to the IDCT code.) + * Note that the number of samples emitted by the IDCT routine is + * DCT_scaled_size * DCT_scaled_size. + */ + +/* typedef inverse_DCT_method_ptr is declared in jpegint.h */ + +/* + * Each IDCT routine has its own ideas about the best dct_table element type. + */ + +typedef MULTIPLIER ISLOW_MULT_TYPE; /* short or int, whichever is faster */ +#if BITS_IN_JSAMPLE == 8 +typedef MULTIPLIER IFAST_MULT_TYPE; /* 16 bits is OK, use short if faster */ +#define IFAST_SCALE_BITS 2 /* fractional bits in scale factors */ +#else +typedef INT32 IFAST_MULT_TYPE; /* need 32 bits for scaled quantizers */ +#define IFAST_SCALE_BITS 13 /* fractional bits in scale factors */ +#endif +typedef FAST_FLOAT FLOAT_MULT_TYPE; /* preferred floating type */ + + +/* + * Each IDCT routine is responsible for range-limiting its results and + * converting them to unsigned form (0..MAXJSAMPLE). The raw outputs could + * be quite far out of range if the input data is corrupt, so a bulletproof + * range-limiting step is required. We use a mask-and-table-lookup method + * to do the combined operations quickly. See the comments with + * prepare_range_limit_table (in jdmaster.c) for more info. + */ + +#define IDCT_range_limit(cinfo) ((cinfo)->sample_range_limit + CENTERJSAMPLE) + +#define RANGE_MASK (MAXJSAMPLE * 4 + 3) /* 2 bits wider than legal samples */ + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_fdct_islow jFDislow +#define jpeg_fdct_ifast jFDifast +#define jpeg_fdct_float jFDfloat +#define jpeg_idct_islow jRDislow +#define jpeg_idct_ifast jRDifast +#define jpeg_idct_float jRDfloat +#define jpeg_idct_4x4 jRD4x4 +#define jpeg_idct_2x2 jRD2x2 +#define jpeg_idct_1x1 jRD1x1 +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + +/* Extern declarations for the forward and inverse DCT routines. */ + +EXTERN(void) jpeg_fdct_islow JPP((DCTELEM * data)); +EXTERN(void) jpeg_fdct_ifast JPP((DCTELEM * data)); +EXTERN(void) jpeg_fdct_float JPP((FAST_FLOAT * data)); + +EXTERN(void) jpeg_idct_islow + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_ifast + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_float + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_4x4 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_2x2 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_1x1 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); + + +/* + * Macros for handling fixed-point arithmetic; these are used by many + * but not all of the DCT/IDCT modules. + * + * All values are expected to be of type INT32. + * Fractional constants are scaled left by CONST_BITS bits. + * CONST_BITS is defined within each module using these macros, + * and may differ from one module to the next. + */ + +#define ONE ((INT32) 1) +#define CONST_SCALE (ONE << CONST_BITS) + +/* Convert a positive real constant to an integer scaled by CONST_SCALE. + * Caution: some C compilers fail to reduce "FIX(constant)" at compile time, + * thus causing a lot of useless floating-point operations at run time. + */ + +#define FIX(x) ((INT32) ((x) * CONST_SCALE + 0.5)) + +/* Descale and correctly round an INT32 value that's scaled by N bits. + * We assume RIGHT_SHIFT rounds towards minus infinity, so adding + * the fudge factor is correct for either sign of X. + */ + +#define DESCALE(x,n) RIGHT_SHIFT((x) + (ONE << ((n)-1)), n) + +/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. + * This macro is used only when the two inputs will actually be no more than + * 16 bits wide, so that a 16x16->32 bit multiply can be used instead of a + * full 32x32 multiply. This provides a useful speedup on many machines. + * Unfortunately there is no way to specify a 16x16->32 multiply portably + * in C, but some C compilers will do the right thing if you provide the + * correct combination of casts. + */ + +#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */ +#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT16) (const))) +#endif +#ifdef SHORTxLCONST_32 /* known to work with Microsoft C 6.0 */ +#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT32) (const))) +#endif + +#ifndef MULTIPLY16C16 /* default definition */ +#define MULTIPLY16C16(var,const) ((var) * (const)) +#endif + +/* Same except both inputs are variables. */ + +#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */ +#define MULTIPLY16V16(var1,var2) (((INT16) (var1)) * ((INT16) (var2))) +#endif + +#ifndef MULTIPLY16V16 /* default definition */ +#define MULTIPLY16V16(var1,var2) ((var1) * (var2)) +#endif diff --git a/winclude/jdhuff.h b/winclude/jdhuff.h new file mode 100755 index 000000000..82199ca40 --- /dev/null +++ b/winclude/jdhuff.h @@ -0,0 +1,201 @@ +/* + * jdhuff.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains declarations for Huffman entropy decoding routines + * that are shared between the sequential decoder (jdhuff.c) and the + * progressive decoder (jdphuff.c). No other modules need to see these. + */ + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_make_d_derived_tbl jMkDDerived +#define jpeg_fill_bit_buffer jFilBitBuf +#define jpeg_huff_decode jHufDecode +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Derived data constructed for each Huffman table */ + +#define HUFF_LOOKAHEAD 8 /* # of bits of lookahead */ + +typedef struct { + /* Basic tables: (element [0] of each array is unused) */ + INT32 maxcode[18]; /* largest code of length k (-1 if none) */ + /* (maxcode[17] is a sentinel to ensure jpeg_huff_decode terminates) */ + INT32 valoffset[17]; /* huffval[] offset for codes of length k */ + /* valoffset[k] = huffval[] index of 1st symbol of code length k, less + * the smallest code of length k; so given a code of length k, the + * corresponding symbol is huffval[code + valoffset[k]] + */ + + /* Link to public Huffman table (needed only in jpeg_huff_decode) */ + JHUFF_TBL *pub; + + /* Lookahead tables: indexed by the next HUFF_LOOKAHEAD bits of + * the input data stream. If the next Huffman code is no more + * than HUFF_LOOKAHEAD bits long, we can obtain its length and + * the corresponding symbol directly from these tables. + */ + int look_nbits[1< 32 bits on your machine, and shifting/masking longs is + * reasonably fast, making bit_buf_type be long and setting BIT_BUF_SIZE + * appropriately should be a win. Unfortunately we can't define the size + * with something like #define BIT_BUF_SIZE (sizeof(bit_buf_type)*8) + * because not all machines measure sizeof in 8-bit bytes. + */ + +typedef struct { /* Bitreading state saved across MCUs */ + bit_buf_type get_buffer; /* current bit-extraction buffer */ + int bits_left; /* # of unused bits in it */ +} bitread_perm_state; + +typedef struct { /* Bitreading working state within an MCU */ + /* Current data source location */ + /* We need a copy, rather than munging the original, in case of suspension */ + const JOCTET * next_input_byte; /* => next byte to read from source */ + size_t bytes_in_buffer; /* # of bytes remaining in source buffer */ + /* Bit input buffer --- note these values are kept in register variables, + * not in this struct, inside the inner loops. + */ + bit_buf_type get_buffer; /* current bit-extraction buffer */ + int bits_left; /* # of unused bits in it */ + /* Pointer needed by jpeg_fill_bit_buffer. */ + j_decompress_ptr cinfo; /* back link to decompress master record */ +} bitread_working_state; + +/* Macros to declare and load/save bitread local variables. */ +#define BITREAD_STATE_VARS \ + register bit_buf_type get_buffer; \ + register int bits_left; \ + bitread_working_state br_state + +#define BITREAD_LOAD_STATE(cinfop,permstate) \ + br_state.cinfo = cinfop; \ + br_state.next_input_byte = cinfop->src->next_input_byte; \ + br_state.bytes_in_buffer = cinfop->src->bytes_in_buffer; \ + get_buffer = permstate.get_buffer; \ + bits_left = permstate.bits_left; + +#define BITREAD_SAVE_STATE(cinfop,permstate) \ + cinfop->src->next_input_byte = br_state.next_input_byte; \ + cinfop->src->bytes_in_buffer = br_state.bytes_in_buffer; \ + permstate.get_buffer = get_buffer; \ + permstate.bits_left = bits_left + +/* + * These macros provide the in-line portion of bit fetching. + * Use CHECK_BIT_BUFFER to ensure there are N bits in get_buffer + * before using GET_BITS, PEEK_BITS, or DROP_BITS. + * The variables get_buffer and bits_left are assumed to be locals, + * but the state struct might not be (jpeg_huff_decode needs this). + * CHECK_BIT_BUFFER(state,n,action); + * Ensure there are N bits in get_buffer; if suspend, take action. + * val = GET_BITS(n); + * Fetch next N bits. + * val = PEEK_BITS(n); + * Fetch next N bits without removing them from the buffer. + * DROP_BITS(n); + * Discard next N bits. + * The value N should be a simple variable, not an expression, because it + * is evaluated multiple times. + */ + +#define CHECK_BIT_BUFFER(state,nbits,action) \ + { if (bits_left < (nbits)) { \ + if (! jpeg_fill_bit_buffer(&(state),get_buffer,bits_left,nbits)) \ + { action; } \ + get_buffer = (state).get_buffer; bits_left = (state).bits_left; } } + +#define GET_BITS(nbits) \ + (((int) (get_buffer >> (bits_left -= (nbits)))) & ((1<<(nbits))-1)) + +#define PEEK_BITS(nbits) \ + (((int) (get_buffer >> (bits_left - (nbits)))) & ((1<<(nbits))-1)) + +#define DROP_BITS(nbits) \ + (bits_left -= (nbits)) + +/* Load up the bit buffer to a depth of at least nbits */ +EXTERN(jboolean) jpeg_fill_bit_buffer + JPP((bitread_working_state * state, register bit_buf_type get_buffer, + register int bits_left, int nbits)); + + +/* + * Code for extracting next Huffman-coded symbol from input bit stream. + * Again, this is time-critical and we make the main paths be macros. + * + * We use a lookahead table to process codes of up to HUFF_LOOKAHEAD bits + * without looping. Usually, more than 95% of the Huffman codes will be 8 + * or fewer bits long. The few overlength codes are handled with a loop, + * which need not be inline code. + * + * Notes about the HUFF_DECODE macro: + * 1. Near the end of the data segment, we may fail to get enough bits + * for a lookahead. In that case, we do it the hard way. + * 2. If the lookahead table contains no entry, the next code must be + * more than HUFF_LOOKAHEAD bits long. + * 3. jpeg_huff_decode returns -1 if forced to suspend. + */ + +#define HUFF_DECODE(result,state,htbl,failaction,slowlabel) \ +{ register int nb, look; \ + if (bits_left < HUFF_LOOKAHEAD) { \ + if (! jpeg_fill_bit_buffer(&state,get_buffer,bits_left, 0)) {failaction;} \ + get_buffer = state.get_buffer; bits_left = state.bits_left; \ + if (bits_left < HUFF_LOOKAHEAD) { \ + nb = 1; goto slowlabel; \ + } \ + } \ + look = PEEK_BITS(HUFF_LOOKAHEAD); \ + if ((nb = htbl->look_nbits[look]) != 0) { \ + DROP_BITS(nb); \ + result = htbl->look_sym[look]; \ + } else { \ + nb = HUFF_LOOKAHEAD+1; \ +slowlabel: \ + if ((result=jpeg_huff_decode(&state,get_buffer,bits_left,htbl,nb)) < 0) \ + { failaction; } \ + get_buffer = state.get_buffer; bits_left = state.bits_left; \ + } \ +} + +/* Out-of-line case for Huffman code fetching */ +EXTERN(int) jpeg_huff_decode + JPP((bitread_working_state * state, register bit_buf_type get_buffer, + register int bits_left, d_derived_tbl * htbl, int min_bits)); diff --git a/winclude/jerror.h b/winclude/jerror.h new file mode 100755 index 000000000..fc2fffeac --- /dev/null +++ b/winclude/jerror.h @@ -0,0 +1,291 @@ +/* + * jerror.h + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the error and message codes for the JPEG library. + * Edit this file to add new codes, or to translate the message strings to + * some other language. + * A set of error-reporting macros are defined too. Some applications using + * the JPEG library may wish to include this file to get the error codes + * and/or the macros. + */ + +/* + * To define the enum list of message codes, include this file without + * defining macro JMESSAGE. To create a message string table, include it + * again with a suitable JMESSAGE definition (see jerror.c for an example). + */ +#ifndef JMESSAGE +#ifndef JERROR_H +/* First time through, define the enum list */ +#define JMAKE_ENUM_LIST +#else +/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */ +#define JMESSAGE(code,string) +#endif /* JERROR_H */ +#endif /* JMESSAGE */ + +#ifdef JMAKE_ENUM_LIST + +typedef enum { + +#define JMESSAGE(code,string) code , + +#endif /* JMAKE_ENUM_LIST */ + +JMESSAGE(JMSG_NOMESSAGE, "Bogus message code %d") /* Must be first entry! */ + +/* For maintenance convenience, list is alphabetical by message code name */ +JMESSAGE(JERR_ARITH_NOTIMPL, + "Sorry, there are legal restrictions on arithmetic coding") +JMESSAGE(JERR_BAD_ALIGN_TYPE, "ALIGN_TYPE is wrong, please fix") +JMESSAGE(JERR_BAD_ALLOC_CHUNK, "MAX_ALLOC_CHUNK is wrong, please fix") +JMESSAGE(JERR_BAD_BUFFER_MODE, "Bogus buffer control mode") +JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS") +JMESSAGE(JERR_BAD_DCT_COEF, "DCT coefficient out of range") +JMESSAGE(JERR_BAD_DCTSIZE, "IDCT output block size %d not supported") +JMESSAGE(JERR_BAD_HUFF_TABLE, "Bogus Huffman table definition") +JMESSAGE(JERR_BAD_IN_COLORSPACE, "Bogus input colorspace") +JMESSAGE(JERR_BAD_J_COLORSPACE, "Bogus JPEG colorspace") +JMESSAGE(JERR_BAD_LENGTH, "Bogus marker length") +JMESSAGE(JERR_BAD_LIB_VERSION, + "Wrong JPEG library version: library is %d, caller expects %d") +JMESSAGE(JERR_BAD_MCU_SIZE, "Sampling factors too large for interleaved scan") +JMESSAGE(JERR_BAD_POOL_ID, "Invalid memory pool code %d") +JMESSAGE(JERR_BAD_PRECISION, "Unsupported JPEG data precision %d") +JMESSAGE(JERR_BAD_PROGRESSION, + "Invalid progressive parameters Ss=%d Se=%d Ah=%d Al=%d") +JMESSAGE(JERR_BAD_PROG_SCRIPT, + "Invalid progressive parameters at scan script entry %d") +JMESSAGE(JERR_BAD_SAMPLING, "Bogus sampling factors") +JMESSAGE(JERR_BAD_SCAN_SCRIPT, "Invalid scan script at entry %d") +JMESSAGE(JERR_BAD_STATE, "Improper call to JPEG library in state %d") +JMESSAGE(JERR_BAD_STRUCT_SIZE, + "JPEG parameter struct mismatch: library thinks size is %u, caller expects %u") +JMESSAGE(JERR_BAD_VIRTUAL_ACCESS, "Bogus virtual array access") +JMESSAGE(JERR_BUFFER_SIZE, "Buffer passed to JPEG library is too small") +JMESSAGE(JERR_CANT_SUSPEND, "Suspension not allowed here") +JMESSAGE(JERR_CCIR601_NOTIMPL, "CCIR601 sampling not implemented yet") +JMESSAGE(JERR_COMPONENT_COUNT, "Too many color components: %d, max %d") +JMESSAGE(JERR_CONVERSION_NOTIMPL, "Unsupported color conversion request") +JMESSAGE(JERR_DAC_INDEX, "Bogus DAC index %d") +JMESSAGE(JERR_DAC_VALUE, "Bogus DAC value 0x%x") +JMESSAGE(JERR_DHT_INDEX, "Bogus DHT index %d") +JMESSAGE(JERR_DQT_INDEX, "Bogus DQT index %d") +JMESSAGE(JERR_EMPTY_IMAGE, "Empty JPEG image (DNL not supported)") +JMESSAGE(JERR_EMS_READ, "Read from EMS failed") +JMESSAGE(JERR_EMS_WRITE, "Write to EMS failed") +JMESSAGE(JERR_EOI_EXPECTED, "Didn't expect more than one scan") +JMESSAGE(JERR_FILE_READ, "Input file read error") +JMESSAGE(JERR_FILE_WRITE, "Output file write error --- out of disk space?") +JMESSAGE(JERR_FRACT_SAMPLE_NOTIMPL, "Fractional sampling not implemented yet") +JMESSAGE(JERR_HUFF_CLEN_OVERFLOW, "Huffman code size table overflow") +JMESSAGE(JERR_HUFF_MISSING_CODE, "Missing Huffman code table entry") +JMESSAGE(JERR_IMAGE_TOO_BIG, "Maximum supported image dimension is %u pixels") +JMESSAGE(JERR_INPUT_EMPTY, "Empty input file") +JMESSAGE(JERR_INPUT_EOF, "Premature end of input file") +JMESSAGE(JERR_MISMATCHED_QUANT_TABLE, + "Cannot transcode due to multiple use of quantization table %d") +JMESSAGE(JERR_MISSING_DATA, "Scan script does not transmit all data") +JMESSAGE(JERR_MODE_CHANGE, "Invalid color quantization mode change") +JMESSAGE(JERR_NOTIMPL, "Not implemented yet") +JMESSAGE(JERR_NOT_COMPILED, "Requested feature was omitted at compile time") +JMESSAGE(JERR_NO_BACKING_STORE, "Backing store not supported") +JMESSAGE(JERR_NO_HUFF_TABLE, "Huffman table 0x%02x was not defined") +JMESSAGE(JERR_NO_IMAGE, "JPEG datastream contains no image") +JMESSAGE(JERR_NO_QUANT_TABLE, "Quantization table 0x%02x was not defined") +JMESSAGE(JERR_NO_SOI, "Not a JPEG file: starts with 0x%02x 0x%02x") +JMESSAGE(JERR_OUT_OF_MEMORY, "Insufficient memory (case %d)") +JMESSAGE(JERR_QUANT_COMPONENTS, + "Cannot quantize more than %d color components") +JMESSAGE(JERR_QUANT_FEW_COLORS, "Cannot quantize to fewer than %d colors") +JMESSAGE(JERR_QUANT_MANY_COLORS, "Cannot quantize to more than %d colors") +JMESSAGE(JERR_SOF_DUPLICATE, "Invalid JPEG file structure: two SOF markers") +JMESSAGE(JERR_SOF_NO_SOS, "Invalid JPEG file structure: missing SOS marker") +JMESSAGE(JERR_SOF_UNSUPPORTED, "Unsupported JPEG process: SOF type 0x%02x") +JMESSAGE(JERR_SOI_DUPLICATE, "Invalid JPEG file structure: two SOI markers") +JMESSAGE(JERR_SOS_NO_SOF, "Invalid JPEG file structure: SOS before SOF") +JMESSAGE(JERR_TFILE_CREATE, "Failed to create temporary file %s") +JMESSAGE(JERR_TFILE_READ, "Read failed on temporary file") +JMESSAGE(JERR_TFILE_SEEK, "Seek failed on temporary file") +JMESSAGE(JERR_TFILE_WRITE, + "Write failed on temporary file --- out of disk space?") +JMESSAGE(JERR_TOO_LITTLE_DATA, "Application transferred too few scanlines") +JMESSAGE(JERR_UNKNOWN_MARKER, "Unsupported marker type 0x%02x") +JMESSAGE(JERR_VIRTUAL_BUG, "Virtual array controller messed up") +JMESSAGE(JERR_WIDTH_OVERFLOW, "Image too wide for this implementation") +JMESSAGE(JERR_XMS_READ, "Read from XMS failed") +JMESSAGE(JERR_XMS_WRITE, "Write to XMS failed") +JMESSAGE(JMSG_COPYRIGHT, JCOPYRIGHT) +JMESSAGE(JMSG_VERSION, JVERSION) +JMESSAGE(JTRC_16BIT_TABLES, + "Caution: quantization tables are too coarse for baseline JPEG") +JMESSAGE(JTRC_ADOBE, + "Adobe APP14 marker: version %d, flags 0x%04x 0x%04x, transform %d") +JMESSAGE(JTRC_APP0, "Unknown APP0 marker (not JFIF), length %u") +JMESSAGE(JTRC_APP14, "Unknown APP14 marker (not Adobe), length %u") +JMESSAGE(JTRC_DAC, "Define Arithmetic Table 0x%02x: 0x%02x") +JMESSAGE(JTRC_DHT, "Define Huffman Table 0x%02x") +JMESSAGE(JTRC_DQT, "Define Quantization Table %d precision %d") +JMESSAGE(JTRC_DRI, "Define Restart Interval %u") +JMESSAGE(JTRC_EMS_CLOSE, "Freed EMS handle %u") +JMESSAGE(JTRC_EMS_OPEN, "Obtained EMS handle %u") +JMESSAGE(JTRC_EOI, "End Of Image") +JMESSAGE(JTRC_HUFFBITS, " %3d %3d %3d %3d %3d %3d %3d %3d") +JMESSAGE(JTRC_JFIF, "JFIF APP0 marker: version %d.%02d, density %dx%d %d") +JMESSAGE(JTRC_JFIF_BADTHUMBNAILSIZE, + "Warning: thumbnail image size does not match data length %u") +JMESSAGE(JTRC_JFIF_EXTENSION, + "JFIF extension marker: type 0x%02x, length %u") +JMESSAGE(JTRC_JFIF_THUMBNAIL, " with %d x %d thumbnail image") +JMESSAGE(JTRC_MISC_MARKER, "Miscellaneous marker 0x%02x, length %u") +JMESSAGE(JTRC_PARMLESS_MARKER, "Unexpected marker 0x%02x") +JMESSAGE(JTRC_QUANTVALS, " %4u %4u %4u %4u %4u %4u %4u %4u") +JMESSAGE(JTRC_QUANT_3_NCOLORS, "Quantizing to %d = %d*%d*%d colors") +JMESSAGE(JTRC_QUANT_NCOLORS, "Quantizing to %d colors") +JMESSAGE(JTRC_QUANT_SELECTED, "Selected %d colors for quantization") +JMESSAGE(JTRC_RECOVERY_ACTION, "At marker 0x%02x, recovery action %d") +JMESSAGE(JTRC_RST, "RST%d") +JMESSAGE(JTRC_SMOOTH_NOTIMPL, + "Smoothing not supported with nonstandard sampling ratios") +JMESSAGE(JTRC_SOF, "Start Of Frame 0x%02x: width=%u, height=%u, components=%d") +JMESSAGE(JTRC_SOF_COMPONENT, " Component %d: %dhx%dv q=%d") +JMESSAGE(JTRC_SOI, "Start of Image") +JMESSAGE(JTRC_SOS, "Start Of Scan: %d components") +JMESSAGE(JTRC_SOS_COMPONENT, " Component %d: dc=%d ac=%d") +JMESSAGE(JTRC_SOS_PARAMS, " Ss=%d, Se=%d, Ah=%d, Al=%d") +JMESSAGE(JTRC_TFILE_CLOSE, "Closed temporary file %s") +JMESSAGE(JTRC_TFILE_OPEN, "Opened temporary file %s") +JMESSAGE(JTRC_THUMB_JPEG, + "JFIF extension marker: JPEG-compressed thumbnail image, length %u") +JMESSAGE(JTRC_THUMB_PALETTE, + "JFIF extension marker: palette thumbnail image, length %u") +JMESSAGE(JTRC_THUMB_RGB, + "JFIF extension marker: RGB thumbnail image, length %u") +JMESSAGE(JTRC_UNKNOWN_IDS, + "Unrecognized component IDs %d %d %d, assuming YCbCr") +JMESSAGE(JTRC_XMS_CLOSE, "Freed XMS handle %u") +JMESSAGE(JTRC_XMS_OPEN, "Obtained XMS handle %u") +JMESSAGE(JWRN_ADOBE_XFORM, "Unknown Adobe color transform code %d") +JMESSAGE(JWRN_BOGUS_PROGRESSION, + "Inconsistent progression sequence for component %d coefficient %d") +JMESSAGE(JWRN_EXTRANEOUS_DATA, + "Corrupt JPEG data: %u extraneous bytes before marker 0x%02x") +JMESSAGE(JWRN_HIT_MARKER, "Corrupt JPEG data: premature end of data segment") +JMESSAGE(JWRN_HUFF_BAD_CODE, "Corrupt JPEG data: bad Huffman code") +JMESSAGE(JWRN_JFIF_MAJOR, "Warning: unknown JFIF revision number %d.%02d") +JMESSAGE(JWRN_JPEG_EOF, "Premature end of JPEG file") +JMESSAGE(JWRN_MUST_RESYNC, + "Corrupt JPEG data: found marker 0x%02x instead of RST%d") +JMESSAGE(JWRN_NOT_SEQUENTIAL, "Invalid SOS parameters for sequential JPEG") +JMESSAGE(JWRN_TOO_MUCH_DATA, "Application transferred too many scanlines") + +#ifdef JMAKE_ENUM_LIST + + JMSG_LASTMSGCODE +} J_MESSAGE_CODE; + +#undef JMAKE_ENUM_LIST +#endif /* JMAKE_ENUM_LIST */ + +/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */ +#undef JMESSAGE + + +#ifndef JERROR_H +#define JERROR_H + +/* Macros to simplify using the error and trace message stuff */ +/* The first parameter is either type of cinfo pointer */ + +/* Fatal errors (print message and exit) */ +#define ERREXIT(cinfo,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT1(cinfo,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT2(cinfo,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT3(cinfo,code,p1,p2,p3) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (cinfo)->err->msg_parm.i[2] = (p3), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT4(cinfo,code,p1,p2,p3,p4) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (cinfo)->err->msg_parm.i[2] = (p3), \ + (cinfo)->err->msg_parm.i[3] = (p4), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXITS(cinfo,code,str) \ + ((cinfo)->err->msg_code = (code), \ + strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) + +#define MAKESTMT(stuff) do { stuff } while (0) + +/* Nonfatal errors (we can keep going, but the data is probably corrupt) */ +#define WARNMS(cinfo,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) +#define WARNMS1(cinfo,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) +#define WARNMS2(cinfo,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) + +/* Informational/debugging messages */ +#define TRACEMS(cinfo,lvl,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS1(cinfo,lvl,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS2(cinfo,lvl,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS3(cinfo,lvl,code,p1,p2,p3) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS4(cinfo,lvl,code,p1,p2,p3,p4) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS5(cinfo,lvl,code,p1,p2,p3,p4,p5) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + _mp[4] = (p5); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS8(cinfo,lvl,code,p1,p2,p3,p4,p5,p6,p7,p8) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + _mp[4] = (p5); _mp[5] = (p6); _mp[6] = (p7); _mp[7] = (p8); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMSS(cinfo,lvl,code,str) \ + ((cinfo)->err->msg_code = (code), \ + strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) + +#endif /* JERROR_H */ diff --git a/winclude/jinclude.h b/winclude/jinclude.h new file mode 100755 index 000000000..0a4f15146 --- /dev/null +++ b/winclude/jinclude.h @@ -0,0 +1,91 @@ +/* + * jinclude.h + * + * Copyright (C) 1991-1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file exists to provide a single place to fix any problems with + * including the wrong system include files. (Common problems are taken + * care of by the standard jconfig symbols, but on really weird systems + * you may have to edit this file.) + * + * NOTE: this file is NOT intended to be included by applications using the + * JPEG library. Most applications need only include jpeglib.h. + */ + + +/* Include auto-config file to find out which system include files we need. */ + +#include "jconfig.h" /* auto configuration options */ +#define JCONFIG_INCLUDED /* so that jpeglib.h doesn't do it again */ + +/* + * We need the NULL macro and size_t typedef. + * On an ANSI-conforming system it is sufficient to include . + * Otherwise, we get them from or ; we may have to + * pull in as well. + * Note that the core JPEG library does not require ; + * only the default error handler and data source/destination modules do. + * But we must pull it in because of the references to FILE in jpeglib.h. + * You can remove those references if you want to compile without . + */ + +#ifdef HAVE_STDDEF_H +#include +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef NEED_SYS_TYPES_H +#include +#endif + +#include + +/* + * We need memory copying and zeroing functions, plus strncpy(). + * ANSI and System V implementations declare these in . + * BSD doesn't have the mem() functions, but it does have bcopy()/bzero(). + * Some systems may declare memset and memcpy in . + * + * NOTE: we assume the size parameters to these functions are of type size_t. + * Change the casts in these macros if not! + */ + +#ifdef NEED_BSD_STRINGS + +#include +#define MEMZERO(target,size) bzero((void *)(target), (size_t)(size)) +#define MEMCOPY(dest,src,size) bcopy((const void *)(src), (void *)(dest), (size_t)(size)) + +#else /* not BSD, assume ANSI/SysV string lib */ + +#include +#define MEMZERO(target,size) memset((void *)(target), 0, (size_t)(size)) +#define MEMCOPY(dest,src,size) memcpy((void *)(dest), (const void *)(src), (size_t)(size)) + +#endif + +/* + * In ANSI C, and indeed any rational implementation, size_t is also the + * type returned by sizeof(). However, it seems there are some irrational + * implementations out there, in which sizeof() returns an int even though + * size_t is defined as long or unsigned long. To ensure consistent results + * we always use this SIZEOF() macro in place of using sizeof() directly. + */ + +#define SIZEOF(object) ((size_t) sizeof(object)) + +/* + * The modules that use fread() and fwrite() always invoke them through + * these macros. On some systems you may need to twiddle the argument casts. + * CAUTION: argument order is different from underlying functions! + */ + +#define JFREAD(file,buf,sizeofbuf) \ + ((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) +#define JFWRITE(file,buf,sizeofbuf) \ + ((size_t) fwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) diff --git a/winclude/jmemsys.h b/winclude/jmemsys.h new file mode 100755 index 000000000..6c3c6d348 --- /dev/null +++ b/winclude/jmemsys.h @@ -0,0 +1,198 @@ +/* + * jmemsys.h + * + * Copyright (C) 1992-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This include file defines the interface between the system-independent + * and system-dependent portions of the JPEG memory manager. No other + * modules need include it. (The system-independent portion is jmemmgr.c; + * there are several different versions of the system-dependent portion.) + * + * This file works as-is for the system-dependent memory managers supplied + * in the IJG distribution. You may need to modify it if you write a + * custom memory manager. If system-dependent changes are needed in + * this file, the best method is to #ifdef them based on a configuration + * symbol supplied in jconfig.h, as we have done with USE_MSDOS_MEMMGR + * and USE_MAC_MEMMGR. + */ + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_get_small jGetSmall +#define jpeg_free_small jFreeSmall +#define jpeg_get_large jGetLarge +#define jpeg_free_large jFreeLarge +#define jpeg_mem_available jMemAvail +#define jpeg_open_backing_store jOpenBackStore +#define jpeg_mem_init jMemInit +#define jpeg_mem_term jMemTerm +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* + * These two functions are used to allocate and release small chunks of + * memory. (Typically the total amount requested through jpeg_get_small is + * no more than 20K or so; this will be requested in chunks of a few K each.) + * Behavior should be the same as for the standard library functions malloc + * and free; in particular, jpeg_get_small must return NULL on failure. + * On most systems, these ARE malloc and free. jpeg_free_small is passed the + * size of the object being freed, just in case it's needed. + * On an 80x86 machine using small-data memory model, these manage near heap. + */ + +EXTERN(void *) jpeg_get_small JPP((j_common_ptr cinfo, size_t sizeofobject)); +EXTERN(void) jpeg_free_small JPP((j_common_ptr cinfo, void * object, + size_t sizeofobject)); + +/* + * These two functions are used to allocate and release large chunks of + * memory (up to the total free space designated by jpeg_mem_available). + * The interface is the same as above, except that on an 80x86 machine, + * far pointers are used. On most other machines these are identical to + * the jpeg_get/free_small routines; but we keep them separate anyway, + * in case a different allocation strategy is desirable for large chunks. + */ + +EXTERN(void FAR *) jpeg_get_large JPP((j_common_ptr cinfo, + size_t sizeofobject)); +EXTERN(void) jpeg_free_large JPP((j_common_ptr cinfo, void FAR * object, + size_t sizeofobject)); + +/* + * The macro MAX_ALLOC_CHUNK designates the maximum number of bytes that may + * be requested in a single call to jpeg_get_large (and jpeg_get_small for that + * matter, but that case should never come into play). This macro is needed + * to model the 64Kb-segment-size limit of far addressing on 80x86 machines. + * On those machines, we expect that jconfig.h will provide a proper value. + * On machines with 32-bit flat address spaces, any large constant may be used. + * + * NB: jmemmgr.c expects that MAX_ALLOC_CHUNK will be representable as type + * size_t and will be a multiple of sizeof(align_type). + */ + +#ifndef MAX_ALLOC_CHUNK /* may be overridden in jconfig.h */ +#define MAX_ALLOC_CHUNK 1000000000L +#endif + +/* + * This routine computes the total space still available for allocation by + * jpeg_get_large. If more space than this is needed, backing store will be + * used. NOTE: any memory already allocated must not be counted. + * + * There is a minimum space requirement, corresponding to the minimum + * feasible buffer sizes; jmemmgr.c will request that much space even if + * jpeg_mem_available returns zero. The maximum space needed, enough to hold + * all working storage in memory, is also passed in case it is useful. + * Finally, the total space already allocated is passed. If no better + * method is available, cinfo->mem->max_memory_to_use - already_allocated + * is often a suitable calculation. + * + * It is OK for jpeg_mem_available to underestimate the space available + * (that'll just lead to more backing-store access than is really necessary). + * However, an overestimate will lead to failure. Hence it's wise to subtract + * a slop factor from the true available space. 5% should be enough. + * + * On machines with lots of virtual memory, any large constant may be returned. + * Conversely, zero may be returned to always use the minimum amount of memory. + */ + +EXTERN(long) jpeg_mem_available JPP((j_common_ptr cinfo, + long min_bytes_needed, + long max_bytes_needed, + long already_allocated)); + + +/* + * This structure holds whatever state is needed to access a single + * backing-store object. The read/write/close method pointers are called + * by jmemmgr.c to manipulate the backing-store object; all other fields + * are private to the system-dependent backing store routines. + */ + +#define TEMP_NAME_LENGTH 64 /* max length of a temporary file's name */ + + +#ifdef USE_MSDOS_MEMMGR /* DOS-specific junk */ + +typedef unsigned short XMSH; /* type of extended-memory handles */ +typedef unsigned short EMSH; /* type of expanded-memory handles */ + +typedef union { + short file_handle; /* DOS file handle if it's a temp file */ + XMSH xms_handle; /* handle if it's a chunk of XMS */ + EMSH ems_handle; /* handle if it's a chunk of EMS */ +} handle_union; + +#endif /* USE_MSDOS_MEMMGR */ + +#ifdef USE_MAC_MEMMGR /* Mac-specific junk */ +#include +#endif /* USE_MAC_MEMMGR */ + + +typedef struct backing_store_struct * backing_store_ptr; + +typedef struct backing_store_struct { + /* Methods for reading/writing/closing this backing-store object */ + JMETHOD(void, read_backing_store, (j_common_ptr cinfo, + backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count)); + JMETHOD(void, write_backing_store, (j_common_ptr cinfo, + backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count)); + JMETHOD(void, close_backing_store, (j_common_ptr cinfo, + backing_store_ptr info)); + + /* Private fields for system-dependent backing-store management */ +#ifdef USE_MSDOS_MEMMGR + /* For the MS-DOS manager (jmemdos.c), we need: */ + handle_union handle; /* reference to backing-store storage object */ + char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */ +#else +#ifdef USE_MAC_MEMMGR + /* For the Mac manager (jmemmac.c), we need: */ + short temp_file; /* file reference number to temp file */ + FSSpec tempSpec; /* the FSSpec for the temp file */ + char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */ +#else + /* For a typical implementation with temp files, we need: */ + FILE * temp_file; /* stdio reference to temp file */ + char temp_name[TEMP_NAME_LENGTH]; /* name of temp file */ +#endif +#endif +} backing_store_info; + + +/* + * Initial opening of a backing-store object. This must fill in the + * read/write/close pointers in the object. The read/write routines + * may take an error exit if the specified maximum file size is exceeded. + * (If jpeg_mem_available always returns a large value, this routine can + * just take an error exit.) + */ + +EXTERN(void) jpeg_open_backing_store JPP((j_common_ptr cinfo, + backing_store_ptr info, + long total_bytes_needed)); + + +/* + * These routines take care of any system-dependent initialization and + * cleanup required. jpeg_mem_init will be called before anything is + * allocated (and, therefore, nothing in cinfo is of use except the error + * manager pointer). It should return a suitable default value for + * max_memory_to_use; this may subsequently be overridden by the surrounding + * application. (Note that max_memory_to_use is only important if + * jpeg_mem_available chooses to consult it ... no one else will.) + * jpeg_mem_term may assume that all requested memory has been freed and that + * all opened backing-store objects have been closed. + */ + +EXTERN(long) jpeg_mem_init JPP((j_common_ptr cinfo)); +EXTERN(void) jpeg_mem_term JPP((j_common_ptr cinfo)); diff --git a/winclude/jmorecfg.h b/winclude/jmorecfg.h new file mode 100755 index 000000000..c00e644a3 --- /dev/null +++ b/winclude/jmorecfg.h @@ -0,0 +1,363 @@ +/* + * jmorecfg.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains additional configuration options that customize the + * JPEG software for special applications or support machine-dependent + * optimizations. Most users will not need to touch this file. + */ + + +/* + * Define BITS_IN_JSAMPLE as either + * 8 for 8-bit sample values (the usual setting) + * 12 for 12-bit sample values + * Only 8 and 12 are legal data precisions for lossy JPEG according to the + * JPEG standard, and the IJG code does not support anything else! + * We do not support run-time selection of data precision, sorry. + */ + +#define BITS_IN_JSAMPLE 8 /* use 8 or 12 */ + + +/* + * Maximum number of components (color channels) allowed in JPEG image. + * To meet the letter of the JPEG spec, set this to 255. However, darn + * few applications need more than 4 channels (maybe 5 for CMYK + alpha + * mask). We recommend 10 as a reasonable compromise; use 4 if you are + * really short on memory. (Each allowed component costs a hundred or so + * bytes of storage, whether actually used in an image or not.) + */ + +#define MAX_COMPONENTS 10 /* maximum number of image components */ + + +/* + * Basic data types. + * You may need to change these if you have a machine with unusual data + * type sizes; for example, "char" not 8 bits, "short" not 16 bits, + * or "long" not 32 bits. We don't care whether "int" is 16 or 32 bits, + * but it had better be at least 16. + */ + +/* Representation of a single sample (pixel element value). + * We frequently allocate large arrays of these, so it's important to keep + * them small. But if you have memory to burn and access to char or short + * arrays is very slow on your hardware, you might want to change these. + */ + +#if BITS_IN_JSAMPLE == 8 +/* JSAMPLE should be the smallest type that will hold the values 0..255. + * You can use a signed char by having GETJSAMPLE mask it with 0xFF. + */ + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#else /* not HAVE_UNSIGNED_CHAR */ + +typedef char JSAMPLE; +#ifdef CHAR_IS_UNSIGNED +#define GETJSAMPLE(value) ((int) (value)) +#else +#define GETJSAMPLE(value) ((int) (value) & 0xFF) +#endif /* CHAR_IS_UNSIGNED */ + +#endif /* HAVE_UNSIGNED_CHAR */ + +#define MAXJSAMPLE 255 +#define CENTERJSAMPLE 128 + +#endif /* BITS_IN_JSAMPLE == 8 */ + + +#if BITS_IN_JSAMPLE == 12 +/* JSAMPLE should be the smallest type that will hold the values 0..4095. + * On nearly all machines "short" will do nicely. + */ + +typedef short JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#define MAXJSAMPLE 4095 +#define CENTERJSAMPLE 2048 + +#endif /* BITS_IN_JSAMPLE == 12 */ + + +/* Representation of a DCT frequency coefficient. + * This should be a signed value of at least 16 bits; "short" is usually OK. + * Again, we allocate large arrays of these, but you can change to int + * if you have memory to burn and "short" is really slow. + */ + +typedef short JCOEF; + + +/* Compressed datastreams are represented as arrays of JOCTET. + * These must be EXACTLY 8 bits wide, at least once they are written to + * external storage. Note that when using the stdio data source/destination + * managers, this is also the data type passed to fread/fwrite. + */ + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char JOCTET; +#define GETJOCTET(value) (value) + +#else /* not HAVE_UNSIGNED_CHAR */ + +typedef char JOCTET; +#ifdef CHAR_IS_UNSIGNED +#define GETJOCTET(value) (value) +#else +#define GETJOCTET(value) ((value) & 0xFF) +#endif /* CHAR_IS_UNSIGNED */ + +#endif /* HAVE_UNSIGNED_CHAR */ + + +/* These typedefs are used for various table entries and so forth. + * They must be at least as wide as specified; but making them too big + * won't cost a huge amount of memory, so we don't provide special + * extraction code like we did for JSAMPLE. (In other words, these + * typedefs live at a different point on the speed/space tradeoff curve.) + */ + +/* UINT8 must hold at least the values 0..255. */ + +#ifdef HAVE_UNSIGNED_CHAR +typedef unsigned char UINT8; +#else /* not HAVE_UNSIGNED_CHAR */ +#ifdef CHAR_IS_UNSIGNED +typedef char UINT8; +#else /* not CHAR_IS_UNSIGNED */ +typedef short UINT8; +#endif /* CHAR_IS_UNSIGNED */ +#endif /* HAVE_UNSIGNED_CHAR */ + +/* UINT16 must hold at least the values 0..65535. */ + +#ifdef HAVE_UNSIGNED_SHORT +typedef unsigned short UINT16; +#else /* not HAVE_UNSIGNED_SHORT */ +typedef unsigned int UINT16; +#endif /* HAVE_UNSIGNED_SHORT */ + +/* INT16 must hold at least the values -32768..32767. */ + +#ifndef XMD_H /* X11/xmd.h correctly defines INT16 */ +typedef short INT16; +#endif + +/* INT32 must hold at least signed 32-bit values. */ + +//#ifndef XMD_H /* X11/xmd.h correctly defines INT32 */ +//typedef long INT32; +//#endif + +/* Datatype used for image dimensions. The JPEG standard only supports + * images up to 64K*64K due to 16-bit fields in SOF markers. Therefore + * "unsigned int" is sufficient on all machines. However, if you need to + * handle larger images and you don't mind deviating from the spec, you + * can change this datatype. + */ + +typedef unsigned int JDIMENSION; + +#define JPEG_MAX_DIMENSION 65500L /* a tad under 64K to prevent overflows */ + + +/* These macros are used in all function definitions and extern declarations. + * You could modify them if you need to change function linkage conventions; + * in particular, you'll need to do that to make the library a Windows DLL. + * Another application is to make all functions global for use with debuggers + * or code profilers that require it. + */ + +/* a function called through method pointers: */ +#define METHODDEF(type) static type +/* a function used only in its module: */ +#define LOCAL(type) static type +/* a function referenced thru EXTERNs: */ +#define GLOBAL(type) type +/* a reference to a GLOBAL function: */ +#define EXTERN(type) extern type + + +/* This macro is used to declare a "method", that is, a function pointer. + * We want to supply prototype parameters if the compiler can cope. + * Note that the arglist parameter must be parenthesized! + * Again, you can customize this if you need special linkage keywords. + */ + +#ifdef HAVE_PROTOTYPES +#define JMETHOD(type,methodname,arglist) type (*methodname) arglist +#else +#define JMETHOD(type,methodname,arglist) type (*methodname) () +#endif + + +/* Here is the pseudo-keyword for declaring pointers that must be "far" + * on 80x86 machines. Most of the specialized coding for 80x86 is handled + * by just saying "FAR *" where such a pointer is needed. In a few places + * explicit coding is needed; see uses of the NEED_FAR_POINTERS symbol. + */ + +#ifdef NEED_FAR_POINTERS +#define FAR far +#else +#define FAR +#endif + + +/* + * On a few systems, type jboolean and/or its values FALSE, TRUE may appear + * in standard header files. Or you may have conflicts with application- + * specific header files that you want to include together with these files. + * Defining HAVE_jboolean before including jpeglib.h should make it work. + */ + +#ifndef HAVE_jboolean +typedef int jboolean; +#endif +#ifndef FALSE /* in case these macros already exist */ +#define FALSE 0 /* values of jboolean */ +#endif +#ifndef TRUE +#define TRUE 1 +#endif + + +/* + * The remaining options affect code selection within the JPEG library, + * but they don't need to be visible to most applications using the library. + * To minimize application namespace pollution, the symbols won't be + * defined unless JPEG_INTERNALS or JPEG_INTERNAL_OPTIONS has been defined. + */ + +#ifdef JPEG_INTERNALS +#define JPEG_INTERNAL_OPTIONS +#endif + +#ifdef JPEG_INTERNAL_OPTIONS + + +/* + * These defines indicate whether to include various optional functions. + * Undefining some of these symbols will produce a smaller but less capable + * library. Note that you can leave certain source files out of the + * compilation/linking process if you've #undef'd the corresponding symbols. + * (You may HAVE to do that if your compiler doesn't like null source files.) + */ + +/* Arithmetic coding is unsupported for legal reasons. Complaints to IBM. */ + +/* Capability options common to encoder and decoder: */ + +#define DCT_ISLOW_SUPPORTED /* slow but accurate integer algorithm */ +#define DCT_IFAST_SUPPORTED /* faster, less accurate integer method */ +#define DCT_FLOAT_SUPPORTED /* floating-point: accurate, fast on fast HW */ + +/* Encoder capability options: */ + +#undef C_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ +#define C_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define C_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ +#define ENTROPY_OPT_SUPPORTED /* Optimization of entropy coding parms? */ +/* Note: if you selected 12-bit data precision, it is dangerous to turn off + * ENTROPY_OPT_SUPPORTED. The standard Huffman tables are only good for 8-bit + * precision, so jchuff.c normally uses entropy optimization to compute + * usable tables for higher precision. If you don't want to do optimization, + * you'll have to supply different default Huffman tables. + * The exact same statements apply for progressive JPEG: the default tables + * don't work for progressive mode. (This may get fixed, however.) + */ +#define INPUT_SMOOTHING_SUPPORTED /* Input image smoothing option? */ + +/* Decoder capability options: */ + +#undef D_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ +#define D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ +#define SAVE_MARKERS_SUPPORTED /* jpeg_save_markers() needed? */ +#define BLOCK_SMOOTHING_SUPPORTED /* Block smoothing? (Progressive only) */ +#define IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? */ +#undef UPSAMPLE_SCALING_SUPPORTED /* Output rescaling at upsample stage? */ +#define UPSAMPLE_MERGING_SUPPORTED /* Fast path for sloppy upsampling? */ +#define QUANT_1PASS_SUPPORTED /* 1-pass color quantization? */ +#define QUANT_2PASS_SUPPORTED /* 2-pass color quantization? */ + +/* more capability options later, no doubt */ + + +/* + * Ordering of RGB data in scanlines passed to or from the application. + * If your application wants to deal with data in the order B,G,R, just + * change these macros. You can also deal with formats such as R,G,B,X + * (one extra byte per pixel) by changing RGB_PIXELSIZE. Note that changing + * the offsets will also change the order in which colormap data is organized. + * RESTRICTIONS: + * 1. The sample applications cjpeg,djpeg do NOT support modified RGB formats. + * 2. These macros only affect RGB<=>YCbCr color conversion, so they are not + * useful if you are using JPEG color spaces other than YCbCr or grayscale. + * 3. The color quantizer modules will not behave desirably if RGB_PIXELSIZE + * is not 3 (they don't understand about dummy color components!). So you + * can't use color quantization if you change that value. + */ + +#define RGB_RED 0 /* Offset of Red in an RGB scanline element */ +#define RGB_GREEN 1 /* Offset of Green */ +#define RGB_BLUE 2 /* Offset of Blue */ +#define RGB_PIXELSIZE 3 /* JSAMPLEs per RGB scanline element */ + + +/* Definitions for speed-related optimizations. */ + + +/* If your compiler supports inline functions, define INLINE + * as the inline keyword; otherwise define it as empty. + */ + +#ifndef INLINE +#ifdef __GNUC__ /* for instance, GNU C knows about inline */ +#define INLINE __inline__ +#endif +#ifndef INLINE +#define INLINE /* default is to define it as empty */ +#endif +#endif + + +/* On some machines (notably 68000 series) "int" is 32 bits, but multiplying + * two 16-bit shorts is faster than multiplying two ints. Define MULTIPLIER + * as short on such a machine. MULTIPLIER must be at least 16 bits wide. + */ + +#ifndef MULTIPLIER +#define MULTIPLIER int /* type for fastest integer multiply */ +#endif + + +/* FAST_FLOAT should be either float or double, whichever is done faster + * by your compiler. (Note that this type is only used in the floating point + * DCT routines, so it only matters if you've defined DCT_FLOAT_SUPPORTED.) + * Typically, float is faster in ANSI C compilers, while double is faster in + * pre-ANSI compilers (because they insist on converting to double anyway). + * The code below therefore chooses float if we have ANSI-style prototypes. + */ + +#ifndef FAST_FLOAT +#ifdef HAVE_PROTOTYPES +#define FAST_FLOAT float +#else +#define FAST_FLOAT double +#endif +#endif + +#endif /* JPEG_INTERNAL_OPTIONS */ diff --git a/winclude/jpegint.h b/winclude/jpegint.h new file mode 100755 index 000000000..4f37410e2 --- /dev/null +++ b/winclude/jpegint.h @@ -0,0 +1,392 @@ +/* + * jpegint.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file provides common declarations for the various JPEG modules. + * These declarations are considered internal to the JPEG library; most + * applications using the library shouldn't need to include this file. + */ + + +/* Declarations for both compression & decompression */ + +typedef enum { /* Operating modes for buffer controllers */ + JBUF_PASS_THRU, /* Plain stripwise operation */ + /* Remaining modes require a full-image buffer to have been created */ + JBUF_SAVE_SOURCE, /* Run source subobject only, save output */ + JBUF_CRANK_DEST, /* Run dest subobject only, using saved data */ + JBUF_SAVE_AND_PASS /* Run both subobjects, save output */ +} J_BUF_MODE; + +/* Values of global_state field (jdapi.c has some dependencies on ordering!) */ +#define CSTATE_START 100 /* after create_compress */ +#define CSTATE_SCANNING 101 /* start_compress done, write_scanlines OK */ +#define CSTATE_RAW_OK 102 /* start_compress done, write_raw_data OK */ +#define CSTATE_WRCOEFS 103 /* jpeg_write_coefficients done */ +#define DSTATE_START 200 /* after create_decompress */ +#define DSTATE_INHEADER 201 /* reading header markers, no SOS yet */ +#define DSTATE_READY 202 /* found SOS, ready for start_decompress */ +#define DSTATE_PRELOAD 203 /* reading multiscan file in start_decompress*/ +#define DSTATE_PRESCAN 204 /* performing dummy pass for 2-pass quant */ +#define DSTATE_SCANNING 205 /* start_decompress done, read_scanlines OK */ +#define DSTATE_RAW_OK 206 /* start_decompress done, read_raw_data OK */ +#define DSTATE_BUFIMAGE 207 /* expecting jpeg_start_output */ +#define DSTATE_BUFPOST 208 /* looking for SOS/EOI in jpeg_finish_output */ +#define DSTATE_RDCOEFS 209 /* reading file in jpeg_read_coefficients */ +#define DSTATE_STOPPING 210 /* looking for EOI in jpeg_finish_decompress */ + + +/* Declarations for compression modules */ + +/* Master control module */ +struct jpeg_comp_master { + JMETHOD(void, prepare_for_pass, (j_compress_ptr cinfo)); + JMETHOD(void, pass_startup, (j_compress_ptr cinfo)); + JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); + + /* State variables made visible to other modules */ + jboolean call_pass_startup; /* True if pass_startup must be called */ + jboolean is_last_pass; /* True during last pass */ +}; + +/* Main buffer control (downsampled-data buffer) */ +struct jpeg_c_main_controller { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, process_data, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail)); +}; + +/* Compression preprocessing (downsampling input buffer control) */ +struct jpeg_c_prep_controller { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, pre_process_data, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, + JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail, + JSAMPIMAGE output_buf, + JDIMENSION *out_row_group_ctr, + JDIMENSION out_row_groups_avail)); +}; + +/* Coefficient buffer control */ +struct jpeg_c_coef_controller { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(jboolean, compress_data, (j_compress_ptr cinfo, + JSAMPIMAGE input_buf)); +}; + +/* Colorspace conversion */ +struct jpeg_color_converter { + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + JMETHOD(void, color_convert, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +}; + +/* Downsampling */ +struct jpeg_downsampler { + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + JMETHOD(void, downsample, (j_compress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_index, + JSAMPIMAGE output_buf, + JDIMENSION out_row_group_index)); + + jboolean need_context_rows; /* TRUE if need rows above & below */ +}; + +/* Forward DCT (also controls coefficient quantization) */ +struct jpeg_forward_dct { + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + /* perhaps this should be an array??? */ + JMETHOD(void, forward_DCT, (j_compress_ptr cinfo, + jpeg_component_info * compptr, + JSAMPARRAY sample_data, JBLOCKROW coef_blocks, + JDIMENSION start_row, JDIMENSION start_col, + JDIMENSION num_blocks)); +}; + +/* Entropy encoding */ +struct jpeg_entropy_encoder { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, jboolean gather_statistics)); + JMETHOD(jboolean, encode_mcu, (j_compress_ptr cinfo, JBLOCKROW *MCU_data)); + JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); +}; + +/* Marker writing */ +struct jpeg_marker_writer { + JMETHOD(void, write_file_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_frame_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_scan_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_file_trailer, (j_compress_ptr cinfo)); + JMETHOD(void, write_tables_only, (j_compress_ptr cinfo)); + /* These routines are exported to allow insertion of extra markers */ + /* Probably only COM and APPn markers should be written this way */ + JMETHOD(void, write_marker_header, (j_compress_ptr cinfo, int marker, + unsigned int datalen)); + JMETHOD(void, write_marker_byte, (j_compress_ptr cinfo, int val)); +}; + + +/* Declarations for decompression modules */ + +/* Master control module */ +struct jpeg_decomp_master { + JMETHOD(void, prepare_for_output_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, finish_output_pass, (j_decompress_ptr cinfo)); + + /* State variables made visible to other modules */ + jboolean is_dummy_pass; /* True during 1st pass for 2-pass quant */ +}; + +/* Input control module */ +struct jpeg_input_controller { + JMETHOD(int, consume_input, (j_decompress_ptr cinfo)); + JMETHOD(void, reset_input_controller, (j_decompress_ptr cinfo)); + JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, finish_input_pass, (j_decompress_ptr cinfo)); + + /* State variables made visible to other modules */ + jboolean has_multiple_scans; /* True if file has multiple scans */ + jboolean eoi_reached; /* True when EOI has been consumed */ +}; + +/* Main buffer control (downsampled-data buffer) */ +struct jpeg_d_main_controller { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, process_data, (j_decompress_ptr cinfo, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +}; + +/* Coefficient buffer control */ +struct jpeg_d_coef_controller { + JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); + JMETHOD(int, consume_data, (j_decompress_ptr cinfo)); + JMETHOD(void, start_output_pass, (j_decompress_ptr cinfo)); + JMETHOD(int, decompress_data, (j_decompress_ptr cinfo, + JSAMPIMAGE output_buf)); + /* Pointer to array of coefficient virtual arrays, or NULL if none */ + jvirt_barray_ptr *coef_arrays; +}; + +/* Decompression postprocessing (color quantization buffer control) */ +struct jpeg_d_post_controller { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, post_process_data, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, + JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +}; + +/* Marker reading & parsing */ +struct jpeg_marker_reader { + JMETHOD(void, reset_marker_reader, (j_decompress_ptr cinfo)); + /* Read markers until SOS or EOI. + * Returns same codes as are defined for jpeg_consume_input: + * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. + */ + JMETHOD(int, read_markers, (j_decompress_ptr cinfo)); + /* Read a restart marker --- exported for use by entropy decoder only */ + jpeg_marker_parser_method read_restart_marker; + + /* State of marker reader --- nominally internal, but applications + * supplying COM or APPn handlers might like to know the state. + */ + jboolean saw_SOI; /* found SOI? */ + jboolean saw_SOF; /* found SOF? */ + int next_restart_num; /* next restart number expected (0-7) */ + unsigned int discarded_bytes; /* # of bytes skipped looking for a marker */ +}; + +/* Entropy decoding */ +struct jpeg_entropy_decoder { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + JMETHOD(jboolean, decode_mcu, (j_decompress_ptr cinfo, + JBLOCKROW *MCU_data)); + + /* This is here to share code between baseline and progressive decoders; */ + /* other modules probably should not use it */ + jboolean insufficient_data; /* set TRUE after emitting warning */ +}; + +/* Inverse DCT (also performs dequantization) */ +typedef JMETHOD(void, inverse_DCT_method_ptr, + (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col)); + +struct jpeg_inverse_dct { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + /* It is useful to allow each component to have a separate IDCT method. */ + inverse_DCT_method_ptr inverse_DCT[MAX_COMPONENTS]; +}; + +/* Upsampling (note that upsampler must also call color converter) */ +struct jpeg_upsampler { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, upsample, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, + JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); + + jboolean need_context_rows; /* TRUE if need rows above & below */ +}; + +/* Colorspace conversion */ +struct jpeg_color_deconverter { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, color_convert, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows)); +}; + +/* Color quantization or color precision reduction */ +struct jpeg_color_quantizer { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, jboolean is_pre_scan)); + JMETHOD(void, color_quantize, (j_decompress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPARRAY output_buf, + int num_rows)); + JMETHOD(void, finish_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, new_color_map, (j_decompress_ptr cinfo)); +}; + + +/* Miscellaneous useful macros */ + +#undef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#undef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + + +/* We assume that right shift corresponds to signed division by 2 with + * rounding towards minus infinity. This is correct for typical "arithmetic + * shift" instructions that shift in copies of the sign bit. But some + * C compilers implement >> with an unsigned shift. For these machines you + * must define RIGHT_SHIFT_IS_UNSIGNED. + * RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity. + * It is only applied with constant shift counts. SHIFT_TEMPS must be + * included in the variables of any routine using RIGHT_SHIFT. + */ + +#ifdef RIGHT_SHIFT_IS_UNSIGNED +#define SHIFT_TEMPS INT32 shift_temp; +#define RIGHT_SHIFT(x,shft) \ + ((shift_temp = (x)) < 0 ? \ + (shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \ + (shift_temp >> (shft))) +#else +#define SHIFT_TEMPS +#define RIGHT_SHIFT(x,shft) ((x) >> (shft)) +#endif + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jinit_compress_master jICompress +#define jinit_c_master_control jICMaster +#define jinit_c_main_controller jICMainC +#define jinit_c_prep_controller jICPrepC +#define jinit_c_coef_controller jICCoefC +#define jinit_color_converter jICColor +#define jinit_downsampler jIDownsampler +#define jinit_forward_dct jIFDCT +#define jinit_huff_encoder jIHEncoder +#define jinit_phuff_encoder jIPHEncoder +#define jinit_marker_writer jIMWriter +#define jinit_master_decompress jIDMaster +#define jinit_d_main_controller jIDMainC +#define jinit_d_coef_controller jIDCoefC +#define jinit_d_post_controller jIDPostC +#define jinit_input_controller jIInCtlr +#define jinit_marker_reader jIMReader +#define jinit_huff_decoder jIHDecoder +#define jinit_phuff_decoder jIPHDecoder +#define jinit_inverse_dct jIIDCT +#define jinit_upsampler jIUpsampler +#define jinit_color_deconverter jIDColor +#define jinit_1pass_quantizer jI1Quant +#define jinit_2pass_quantizer jI2Quant +#define jinit_merged_upsampler jIMUpsampler +#define jinit_memory_mgr jIMemMgr +#define jdiv_round_up jDivRound +#define jround_up jRound +#define jcopy_sample_rows jCopySamples +#define jcopy_block_row jCopyBlocks +#define jzero_far jZeroFar +#define jpeg_zigzag_order jZIGTable +#define jpeg_natural_order jZAGTable +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Compression module initialization routines */ +EXTERN(void) jinit_compress_master JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_c_master_control JPP((j_compress_ptr cinfo, + jboolean transcode_only)); +EXTERN(void) jinit_c_main_controller JPP((j_compress_ptr cinfo, + jboolean need_full_buffer)); +EXTERN(void) jinit_c_prep_controller JPP((j_compress_ptr cinfo, + jboolean need_full_buffer)); +EXTERN(void) jinit_c_coef_controller JPP((j_compress_ptr cinfo, + jboolean need_full_buffer)); +EXTERN(void) jinit_color_converter JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_downsampler JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_forward_dct JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_huff_encoder JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_phuff_encoder JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_marker_writer JPP((j_compress_ptr cinfo)); +/* Decompression module initialization routines */ +EXTERN(void) jinit_master_decompress JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_d_main_controller JPP((j_decompress_ptr cinfo, + jboolean need_full_buffer)); +EXTERN(void) jinit_d_coef_controller JPP((j_decompress_ptr cinfo, + jboolean need_full_buffer)); +EXTERN(void) jinit_d_post_controller JPP((j_decompress_ptr cinfo, + jboolean need_full_buffer)); +EXTERN(void) jinit_input_controller JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_marker_reader JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_huff_decoder JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_phuff_decoder JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_inverse_dct JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_upsampler JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_color_deconverter JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_1pass_quantizer JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_2pass_quantizer JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_merged_upsampler JPP((j_decompress_ptr cinfo)); +/* Memory manager initialization */ +EXTERN(void) jinit_memory_mgr JPP((j_common_ptr cinfo)); + +/* Utility routines in jutils.c */ +EXTERN(long) jdiv_round_up JPP((long a, long b)); +EXTERN(long) jround_up JPP((long a, long b)); +EXTERN(void) jcopy_sample_rows JPP((JSAMPARRAY input_array, int source_row, + JSAMPARRAY output_array, int dest_row, + int num_rows, JDIMENSION num_cols)); +EXTERN(void) jcopy_block_row JPP((JBLOCKROW input_row, JBLOCKROW output_row, + JDIMENSION num_blocks)); +EXTERN(void) jzero_far JPP((void FAR * target, size_t bytestozero)); +/* Constant tables in jutils.c */ +#if 0 /* This table is not actually needed in v6a */ +extern const int jpeg_zigzag_order[]; /* natural coef order to zigzag order */ +#endif +extern const int jpeg_natural_order[]; /* zigzag coef order to natural order */ + +/* Suppress undefined-structure complaints if necessary. */ + +#ifdef INCOMPLETE_TYPES_BROKEN +#ifndef AM_MEMORY_MANAGER /* only jmemmgr.c defines these */ +struct jvirt_sarray_control { long dummy; }; +struct jvirt_barray_control { long dummy; }; +#endif +#endif /* INCOMPLETE_TYPES_BROKEN */ diff --git a/winclude/jpeglib.h b/winclude/jpeglib.h new file mode 100755 index 000000000..9a06b5d07 --- /dev/null +++ b/winclude/jpeglib.h @@ -0,0 +1,1096 @@ +/* + * jpeglib.h + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the application interface for the JPEG library. + * Most applications using the library need only include this file, + * and perhaps jerror.h if they want to know the exact error codes. + */ + +#ifndef JPEGLIB_H +#define JPEGLIB_H + +/* + * First we include the configuration files that record how this + * installation of the JPEG library is set up. jconfig.h can be + * generated automatically for many systems. jmorecfg.h contains + * manual configuration options that most people need not worry about. + */ + +#ifndef JCONFIG_INCLUDED /* in case jinclude.h already did */ +#include "jconfig.h" /* widely used configuration options */ +#endif +#include "jmorecfg.h" /* seldom changed options */ + + +/* Version ID for the JPEG library. + * Might be useful for tests like "#if JPEG_LIB_VERSION >= 60". + */ + +#define JPEG_LIB_VERSION 62 /* Version 6b */ + + +/* Various constants determining the sizes of things. + * All of these are specified by the JPEG standard, so don't change them + * if you want to be compatible. + */ + +#define DCTSIZE 8 /* The basic DCT block is 8x8 samples */ +#define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */ +#define NUM_QUANT_TBLS 4 /* Quantization tables are numbered 0..3 */ +#define NUM_HUFF_TBLS 4 /* Huffman tables are numbered 0..3 */ +#define NUM_ARITH_TBLS 16 /* Arith-coding tables are numbered 0..15 */ +#define MAX_COMPS_IN_SCAN 4 /* JPEG limit on # of components in one scan */ +#define MAX_SAMP_FACTOR 4 /* JPEG limit on sampling factors */ +/* Unfortunately, some bozo at Adobe saw no reason to be bound by the standard; + * the PostScript DCT filter can emit files with many more than 10 blocks/MCU. + * If you happen to run across such a file, you can up D_MAX_BLOCKS_IN_MCU + * to handle it. We even let you do this from the jconfig.h file. However, + * we strongly discourage changing C_MAX_BLOCKS_IN_MCU; just because Adobe + * sometimes emits noncompliant files doesn't mean you should too. + */ +#define C_MAX_BLOCKS_IN_MCU 10 /* compressor's limit on blocks per MCU */ +#ifndef D_MAX_BLOCKS_IN_MCU +#define D_MAX_BLOCKS_IN_MCU 10 /* decompressor's limit on blocks per MCU */ +#endif + + +/* Data structures for images (arrays of samples and of DCT coefficients). + * On 80x86 machines, the image arrays are too big for near pointers, + * but the pointer arrays can fit in near memory. + */ + +typedef JSAMPLE FAR *JSAMPROW; /* ptr to one image row of pixel samples. */ +typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */ +typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */ + +typedef JCOEF JBLOCK[DCTSIZE2]; /* one block of coefficients */ +typedef JBLOCK FAR *JBLOCKROW; /* pointer to one row of coefficient blocks */ +typedef JBLOCKROW *JBLOCKARRAY; /* a 2-D array of coefficient blocks */ +typedef JBLOCKARRAY *JBLOCKIMAGE; /* a 3-D array of coefficient blocks */ + +typedef JCOEF FAR *JCOEFPTR; /* useful in a couple of places */ + + +/* Types for JPEG compression parameters and working tables. */ + + +/* DCT coefficient quantization tables. */ + +typedef struct { + /* This array gives the coefficient quantizers in natural array order + * (not the zigzag order in which they are stored in a JPEG DQT marker). + * CAUTION: IJG versions prior to v6a kept this array in zigzag order. + */ + UINT16 quantval[DCTSIZE2]; /* quantization step for each coefficient */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + jboolean sent_table; /* TRUE when table has been output */ +} JQUANT_TBL; + + +/* Huffman coding tables. */ + +typedef struct { + /* These two fields directly represent the contents of a JPEG DHT marker */ + UINT8 bits[17]; /* bits[k] = # of symbols with codes of */ + /* length k bits; bits[0] is unused */ + UINT8 huffval[256]; /* The symbols, in order of incr code length */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + jboolean sent_table; /* TRUE when table has been output */ +} JHUFF_TBL; + + +/* Basic info about one component (color channel). */ + +typedef struct { + /* These values are fixed over the whole image. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOF marker. */ + int component_id; /* identifier for this component (0..255) */ + int component_index; /* its index in SOF or cinfo->comp_info[] */ + int h_samp_factor; /* horizontal sampling factor (1..4) */ + int v_samp_factor; /* vertical sampling factor (1..4) */ + int quant_tbl_no; /* quantization table selector (0..3) */ + /* These values may vary between scans. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOS marker. */ + /* The decompressor output side may not use these variables. */ + int dc_tbl_no; /* DC entropy table selector (0..3) */ + int ac_tbl_no; /* AC entropy table selector (0..3) */ + + /* Remaining fields should be treated as private by applications. */ + + /* These values are computed during compression or decompression startup: */ + /* Component's size in DCT blocks. + * Any dummy blocks added to complete an MCU are not counted; therefore + * these values do not depend on whether a scan is interleaved or not. + */ + JDIMENSION width_in_blocks; + JDIMENSION height_in_blocks; + /* Size of a DCT block in samples. Always DCTSIZE for compression. + * For decompression this is the size of the output from one DCT block, + * reflecting any scaling we choose to apply during the IDCT step. + * Values of 1,2,4,8 are likely to be supported. Note that different + * components may receive different IDCT scalings. + */ + int DCT_scaled_size; + /* The downsampled dimensions are the component's actual, unpadded number + * of samples at the main buffer (preprocessing/compression interface), thus + * downsampled_width = ceil(image_width * Hi/Hmax) + * and similarly for height. For decompression, IDCT scaling is included, so + * downsampled_width = ceil(image_width * Hi/Hmax * DCT_scaled_size/DCTSIZE) + */ + JDIMENSION downsampled_width; /* actual width in samples */ + JDIMENSION downsampled_height; /* actual height in samples */ + /* This flag is used only for decompression. In cases where some of the + * components will be ignored (eg grayscale output from YCbCr image), + * we can skip most computations for the unused components. + */ + jboolean component_needed; /* do we need the value of this component? */ + + /* These values are computed before starting a scan of the component. */ + /* The decompressor output side may not use these variables. */ + int MCU_width; /* number of blocks per MCU, horizontally */ + int MCU_height; /* number of blocks per MCU, vertically */ + int MCU_blocks; /* MCU_width * MCU_height */ + int MCU_sample_width; /* MCU width in samples, MCU_width*DCT_scaled_size */ + int last_col_width; /* # of non-dummy blocks across in last MCU */ + int last_row_height; /* # of non-dummy blocks down in last MCU */ + + /* Saved quantization table for component; NULL if none yet saved. + * See jdinput.c comments about the need for this information. + * This field is currently used only for decompression. + */ + JQUANT_TBL * quant_table; + + /* Private per-component storage for DCT or IDCT subsystem. */ + void * dct_table; +} jpeg_component_info; + + +/* The script for encoding a multiple-scan file is an array of these: */ + +typedef struct { + int comps_in_scan; /* number of components encoded in this scan */ + int component_index[MAX_COMPS_IN_SCAN]; /* their SOF/comp_info[] indexes */ + int Ss, Se; /* progressive JPEG spectral selection parms */ + int Ah, Al; /* progressive JPEG successive approx. parms */ +} jpeg_scan_info; + +/* The decompressor can save APPn and COM markers in a list of these: */ + +typedef struct jpeg_marker_struct FAR * jpeg_saved_marker_ptr; + +struct jpeg_marker_struct { + jpeg_saved_marker_ptr next; /* next in list, or NULL */ + UINT8 marker; /* marker code: JPEG_COM, or JPEG_APP0+n */ + unsigned int original_length; /* # bytes of data in the file */ + unsigned int data_length; /* # bytes of data saved at data[] */ + JOCTET FAR * data; /* the data contained in the marker */ + /* the marker length word is not counted in data_length or original_length */ +}; + +/* Known color spaces. */ + +typedef enum { + JCS_UNKNOWN, /* error/unspecified */ + JCS_GRAYSCALE, /* monochrome */ + JCS_RGB, /* red/green/blue */ + JCS_YCbCr, /* Y/Cb/Cr (also known as YUV) */ + JCS_CMYK, /* C/M/Y/K */ + JCS_YCCK /* Y/Cb/Cr/K */ +} J_COLOR_SPACE; + +/* DCT/IDCT algorithm options. */ + +typedef enum { + JDCT_ISLOW, /* slow but accurate integer algorithm */ + JDCT_IFAST, /* faster, less accurate integer method */ + JDCT_FLOAT /* floating-point: accurate, fast on fast HW */ +} J_DCT_METHOD; + +#ifndef JDCT_DEFAULT /* may be overridden in jconfig.h */ +#define JDCT_DEFAULT JDCT_ISLOW +#endif +#ifndef JDCT_FASTEST /* may be overridden in jconfig.h */ +#define JDCT_FASTEST JDCT_IFAST +#endif + +/* Dithering options for decompression. */ + +typedef enum { + JDITHER_NONE, /* no dithering */ + JDITHER_ORDERED, /* simple ordered dither */ + JDITHER_FS /* Floyd-Steinberg error diffusion dither */ +} J_DITHER_MODE; + + +/* Common fields between JPEG compression and decompression master structs. */ + +#define jpeg_common_fields \ + struct jpeg_error_mgr * err; /* Error handler module */\ + struct jpeg_memory_mgr * mem; /* Memory manager module */\ + struct jpeg_progress_mgr * progress; /* Progress monitor, or NULL if none */\ + void * client_data; /* Available for use by application */\ + jboolean is_decompressor; /* So common code can tell which is which */\ + int global_state /* For checking call sequence validity */ + +/* Routines that are to be used by both halves of the library are declared + * to receive a pointer to this structure. There are no actual instances of + * jpeg_common_struct, only of jpeg_compress_struct and jpeg_decompress_struct. + */ +struct jpeg_common_struct { + jpeg_common_fields; /* Fields common to both master struct types */ + /* Additional fields follow in an actual jpeg_compress_struct or + * jpeg_decompress_struct. All three structs must agree on these + * initial fields! (This would be a lot cleaner in C++.) + */ +}; + +typedef struct jpeg_common_struct * j_common_ptr; +typedef struct jpeg_compress_struct * j_compress_ptr; +typedef struct jpeg_decompress_struct * j_decompress_ptr; + + +/* Master record for a compression instance */ + +struct jpeg_compress_struct { + jpeg_common_fields; /* Fields shared with jpeg_decompress_struct */ + + /* Destination for compressed data */ + struct jpeg_destination_mgr * dest; + + /* Description of source image --- these fields must be filled in by + * outer application before starting compression. in_color_space must + * be correct before you can even call jpeg_set_defaults(). + */ + + JDIMENSION image_width; /* input image width */ + JDIMENSION image_height; /* input image height */ + int input_components; /* # of color components in input image */ + J_COLOR_SPACE in_color_space; /* colorspace of input image */ + + double input_gamma; /* image gamma of input image */ + + /* Compression parameters --- these fields must be set before calling + * jpeg_start_compress(). We recommend calling jpeg_set_defaults() to + * initialize everything to reasonable defaults, then changing anything + * the application specifically wants to change. That way you won't get + * burnt when new parameters are added. Also note that there are several + * helper routines to simplify changing parameters. + */ + + int data_precision; /* bits of precision in image data */ + + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + int num_scans; /* # of entries in scan_info array */ + const jpeg_scan_info * scan_info; /* script for multi-scan file, or NULL */ + /* The default value of scan_info is NULL, which causes a single-scan + * sequential JPEG file to be emitted. To create a multi-scan file, + * set num_scans and scan_info to point to an array of scan definitions. + */ + + jboolean raw_data_in; /* TRUE=caller supplies downsampled data */ + jboolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + jboolean optimize_coding; /* TRUE=optimize entropy encoding parms */ + jboolean CCIR601_sampling; /* TRUE=first samples are cosited */ + int smoothing_factor; /* 1..100, or 0 for no input smoothing */ + J_DCT_METHOD dct_method; /* DCT algorithm selector */ + + /* The restart interval can be specified in absolute MCUs by setting + * restart_interval, or in MCU rows by setting restart_in_rows + * (in which case the correct restart_interval will be figured + * for each scan). + */ + unsigned int restart_interval; /* MCUs per restart, or 0 for no restart */ + int restart_in_rows; /* if > 0, MCU rows per restart interval */ + + /* Parameters controlling emission of special markers. */ + + jboolean write_JFIF_header; /* should a JFIF marker be written? */ + UINT8 JFIF_major_version; /* What to write for the JFIF version number */ + UINT8 JFIF_minor_version; + /* These three values are not used by the JPEG code, merely copied */ + /* into the JFIF APP0 marker. density_unit can be 0 for unknown, */ + /* 1 for dots/inch, or 2 for dots/cm. Note that the pixel aspect */ + /* ratio is defined by X_density/Y_density even when density_unit=0. */ + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + jboolean write_Adobe_marker; /* should an Adobe marker be written? */ + + /* State variable: index of next scanline to be written to + * jpeg_write_scanlines(). Application may use this to control its + * processing loop, e.g., "while (next_scanline < image_height)". + */ + + JDIMENSION next_scanline; /* 0 .. image_height-1 */ + + /* Remaining fields are known throughout compressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during compression startup + */ + jboolean progressive_mode; /* TRUE if scan script uses progressive mode */ + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + + JDIMENSION total_iMCU_rows; /* # of iMCU rows to be input to coef ctlr */ + /* The coefficient controller receives data in units of MCU rows as defined + * for fully interleaved scans (whether the JPEG file is interleaved or not). + * There are v_samp_factor * DCTSIZE sample rows of each component in an + * "iMCU" (interleaved MCU) row. + */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int blocks_in_MCU; /* # of DCT blocks per MCU */ + int MCU_membership[C_MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ + + /* + * Links to compression subobjects (methods and private variables of modules) + */ + struct jpeg_comp_master * master; + struct jpeg_c_main_controller * main; + struct jpeg_c_prep_controller * prep; + struct jpeg_c_coef_controller * coef; + struct jpeg_marker_writer * marker; + struct jpeg_color_converter * cconvert; + struct jpeg_downsampler * downsample; + struct jpeg_forward_dct * fdct; + struct jpeg_entropy_encoder * entropy; + jpeg_scan_info * script_space; /* workspace for jpeg_simple_progression */ + int script_space_size; +}; + + +/* Master record for a decompression instance */ + +struct jpeg_decompress_struct { + jpeg_common_fields; /* Fields shared with jpeg_compress_struct */ + + /* Source of compressed data */ + struct jpeg_source_mgr * src; + + /* Basic description of image --- filled in by jpeg_read_header(). */ + /* Application may inspect these values to decide how to process image. */ + + JDIMENSION image_width; /* nominal image width (from SOF marker) */ + JDIMENSION image_height; /* nominal image height */ + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + /* Decompression processing parameters --- these fields must be set before + * calling jpeg_start_decompress(). Note that jpeg_read_header() initializes + * them to default values. + */ + + J_COLOR_SPACE out_color_space; /* colorspace for output */ + + unsigned int scale_num, scale_denom; /* fraction by which to scale image */ + + double output_gamma; /* image gamma wanted in output */ + + jboolean buffered_image; /* TRUE=multiple output passes */ + jboolean raw_data_out; /* TRUE=downsampled data wanted */ + + J_DCT_METHOD dct_method; /* IDCT algorithm selector */ + jboolean do_fancy_upsampling; /* TRUE=apply fancy upsampling */ + jboolean do_block_smoothing; /* TRUE=apply interblock smoothing */ + + jboolean quantize_colors; /* TRUE=colormapped output wanted */ + /* the following are ignored if not quantize_colors: */ + J_DITHER_MODE dither_mode; /* type of color dithering to use */ + jboolean two_pass_quantize; /* TRUE=use two-pass color quantization */ + int desired_number_of_colors; /* max # colors to use in created colormap */ + /* these are significant only in buffered-image mode: */ + jboolean enable_1pass_quant; /* enable future use of 1-pass quantizer */ + jboolean enable_external_quant;/* enable future use of external colormap */ + jboolean enable_2pass_quant; /* enable future use of 2-pass quantizer */ + + /* Description of actual output image that will be returned to application. + * These fields are computed by jpeg_start_decompress(). + * You can also use jpeg_calc_output_dimensions() to determine these values + * in advance of calling jpeg_start_decompress(). + */ + + JDIMENSION output_width; /* scaled image width */ + JDIMENSION output_height; /* scaled image height */ + int out_color_components; /* # of color components in out_color_space */ + int output_components; /* # of color components returned */ + /* output_components is 1 (a colormap index) when quantizing colors; + * otherwise it equals out_color_components. + */ + int rec_outbuf_height; /* min recommended height of scanline buffer */ + /* If the buffer passed to jpeg_read_scanlines() is less than this many rows + * high, space and time will be wasted due to unnecessary data copying. + * Usually rec_outbuf_height will be 1 or 2, at most 4. + */ + + /* When quantizing colors, the output colormap is described by these fields. + * The application can supply a colormap by setting colormap non-NULL before + * calling jpeg_start_decompress; otherwise a colormap is created during + * jpeg_start_decompress or jpeg_start_output. + * The map has out_color_components rows and actual_number_of_colors columns. + */ + int actual_number_of_colors; /* number of entries in use */ + JSAMPARRAY colormap; /* The color map as a 2-D pixel array */ + + /* State variables: these variables indicate the progress of decompression. + * The application may examine these but must not modify them. + */ + + /* Row index of next scanline to be read from jpeg_read_scanlines(). + * Application may use this to control its processing loop, e.g., + * "while (output_scanline < output_height)". + */ + JDIMENSION output_scanline; /* 0 .. output_height-1 */ + + /* Current input scan number and number of iMCU rows completed in scan. + * These indicate the progress of the decompressor input side. + */ + int input_scan_number; /* Number of SOS markers seen so far */ + JDIMENSION input_iMCU_row; /* Number of iMCU rows completed */ + + /* The "output scan number" is the notional scan being displayed by the + * output side. The decompressor will not allow output scan/row number + * to get ahead of input scan/row, but it can fall arbitrarily far behind. + */ + int output_scan_number; /* Nominal scan number being displayed */ + JDIMENSION output_iMCU_row; /* Number of iMCU rows read */ + + /* Current progression status. coef_bits[c][i] indicates the precision + * with which component c's DCT coefficient i (in zigzag order) is known. + * It is -1 when no data has yet been received, otherwise it is the point + * transform (shift) value for the most recent scan of the coefficient + * (thus, 0 at completion of the progression). + * This pointer is NULL when reading a non-progressive file. + */ + int (*coef_bits)[DCTSIZE2]; /* -1 or current Al value for each coef */ + + /* Internal JPEG parameters --- the application usually need not look at + * these fields. Note that the decompressor output side may not use + * any parameters that can change between scans. + */ + + /* Quantization and Huffman tables are carried forward across input + * datastreams when processing abbreviated JPEG datastreams. + */ + + JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + /* These parameters are never carried across datastreams, since they + * are given in SOF/SOS markers or defined to be reset by SOI. + */ + + int data_precision; /* bits of precision in image data */ + + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + jboolean progressive_mode; /* TRUE if SOFn specifies progressive mode */ + jboolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + unsigned int restart_interval; /* MCUs per restart interval, or 0 for no restart */ + + /* These fields record data obtained from optional markers recognized by + * the JPEG library. + */ + jboolean saw_JFIF_marker; /* TRUE iff a JFIF APP0 marker was found */ + /* Data copied from JFIF marker; only valid if saw_JFIF_marker is TRUE: */ + UINT8 JFIF_major_version; /* JFIF version number */ + UINT8 JFIF_minor_version; + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + jboolean saw_Adobe_marker; /* TRUE iff an Adobe APP14 marker was found */ + UINT8 Adobe_transform; /* Color transform code from Adobe marker */ + + jboolean CCIR601_sampling; /* TRUE=first samples are cosited */ + + /* Aside from the specific data retained from APPn markers known to the + * library, the uninterpreted contents of any or all APPn and COM markers + * can be saved in a list for examination by the application. + */ + jpeg_saved_marker_ptr marker_list; /* Head of list of saved markers */ + + /* Remaining fields are known throughout decompressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during decompression startup + */ + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + + int min_DCT_scaled_size; /* smallest DCT_scaled_size of any component */ + + JDIMENSION total_iMCU_rows; /* # of iMCU rows in image */ + /* The coefficient controller's input and output progress is measured in + * units of "iMCU" (interleaved MCU) rows. These are the same as MCU rows + * in fully interleaved JPEG scans, but are used whether the scan is + * interleaved or not. We define an iMCU row as v_samp_factor DCT block + * rows of each component. Therefore, the IDCT output contains + * v_samp_factor*DCT_scaled_size sample rows of a component per iMCU row. + */ + + JSAMPLE * sample_range_limit; /* table for fast range-limiting */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + * Note that the decompressor output side must not use these fields. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int blocks_in_MCU; /* # of DCT blocks per MCU */ + int MCU_membership[D_MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ + + /* This field is shared between entropy decoder and marker parser. + * It is either zero or the code of a JPEG marker that has been + * read from the data source, but has not yet been processed. + */ + int unread_marker; + + /* + * Links to decompression subobjects (methods, private variables of modules) + */ + struct jpeg_decomp_master * master; + struct jpeg_d_main_controller * main; + struct jpeg_d_coef_controller * coef; + struct jpeg_d_post_controller * post; + struct jpeg_input_controller * inputctl; + struct jpeg_marker_reader * marker; + struct jpeg_entropy_decoder * entropy; + struct jpeg_inverse_dct * idct; + struct jpeg_upsampler * upsample; + struct jpeg_color_deconverter * cconvert; + struct jpeg_color_quantizer * cquantize; +}; + + +/* "Object" declarations for JPEG modules that may be supplied or called + * directly by the surrounding application. + * As with all objects in the JPEG library, these structs only define the + * publicly visible methods and state variables of a module. Additional + * private fields may exist after the public ones. + */ + + +/* Error handler object */ + +struct jpeg_error_mgr { + /* Error exit handler: does not return to caller */ + JMETHOD(void, error_exit, (j_common_ptr cinfo)); + /* Conditionally emit a trace or warning message */ + JMETHOD(void, emit_message, (j_common_ptr cinfo, int msg_level)); + /* Routine that actually outputs a trace or error message */ + JMETHOD(void, output_message, (j_common_ptr cinfo)); + /* Format a message string for the most recent JPEG error or message */ + JMETHOD(void, format_message, (j_common_ptr cinfo, char * buffer)); +#define JMSG_LENGTH_MAX 200 /* recommended size of format_message buffer */ + /* Reset error state variables at start of a new image */ + JMETHOD(void, reset_error_mgr, (j_common_ptr cinfo)); + + /* The message ID code and any parameters are saved here. + * A message can have one string parameter or up to 8 int parameters. + */ + int msg_code; +#define JMSG_STR_PARM_MAX 80 + union { + int i[8]; + char s[JMSG_STR_PARM_MAX]; + } msg_parm; + + /* Standard state variables for error facility */ + + int trace_level; /* max msg_level that will be displayed */ + + /* For recoverable corrupt-data errors, we emit a warning message, + * but keep going unless emit_message chooses to abort. emit_message + * should count warnings in num_warnings. The surrounding application + * can check for bad data by seeing if num_warnings is nonzero at the + * end of processing. + */ + long num_warnings; /* number of corrupt-data warnings */ + + /* These fields point to the table(s) of error message strings. + * An application can change the table pointer to switch to a different + * message list (typically, to change the language in which errors are + * reported). Some applications may wish to add additional error codes + * that will be handled by the JPEG library error mechanism; the second + * table pointer is used for this purpose. + * + * First table includes all errors generated by JPEG library itself. + * Error code 0 is reserved for a "no such error string" message. + */ + const char * const * jpeg_message_table; /* Library errors */ + int last_jpeg_message; /* Table contains strings 0..last_jpeg_message */ + /* Second table can be added by application (see cjpeg/djpeg for example). + * It contains strings numbered first_addon_message..last_addon_message. + */ + const char * const * addon_message_table; /* Non-library errors */ + int first_addon_message; /* code for first string in addon table */ + int last_addon_message; /* code for last string in addon table */ +}; + + +/* Progress monitor object */ + +struct jpeg_progress_mgr { + JMETHOD(void, progress_monitor, (j_common_ptr cinfo)); + + long pass_counter; /* work units completed in this pass */ + long pass_limit; /* total number of work units in this pass */ + int completed_passes; /* passes completed so far */ + int total_passes; /* total number of passes expected */ +}; + + +/* Data destination object for compression */ + +struct jpeg_destination_mgr { + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + + JMETHOD(void, init_destination, (j_compress_ptr cinfo)); + JMETHOD(jboolean, empty_output_buffer, (j_compress_ptr cinfo)); + JMETHOD(void, term_destination, (j_compress_ptr cinfo)); +}; + + +/* Data source object for decompression */ + +struct jpeg_source_mgr { + const JOCTET * next_input_byte; /* => next byte to read from buffer */ + size_t bytes_in_buffer; /* # of bytes remaining in buffer */ + + JMETHOD(void, init_source, (j_decompress_ptr cinfo)); + JMETHOD(jboolean, fill_input_buffer, (j_decompress_ptr cinfo)); + JMETHOD(void, skip_input_data, (j_decompress_ptr cinfo, long num_bytes)); + JMETHOD(jboolean, resync_to_restart, (j_decompress_ptr cinfo, int desired)); + JMETHOD(void, term_source, (j_decompress_ptr cinfo)); +}; + + +/* Memory manager object. + * Allocates "small" objects (a few K total), "large" objects (tens of K), + * and "really big" objects (virtual arrays with backing store if needed). + * The memory manager does not allow individual objects to be freed; rather, + * each created object is assigned to a pool, and whole pools can be freed + * at once. This is faster and more convenient than remembering exactly what + * to free, especially where malloc()/free() are not too speedy. + * NB: alloc routines never return NULL. They exit to error_exit if not + * successful. + */ + +#define JPOOL_PERMANENT 0 /* lasts until master record is destroyed */ +#define JPOOL_IMAGE 1 /* lasts until done with image/datastream */ +#define JPOOL_NUMPOOLS 2 + +typedef struct jvirt_sarray_control * jvirt_sarray_ptr; +typedef struct jvirt_barray_control * jvirt_barray_ptr; + + +struct jpeg_memory_mgr { + /* Method pointers */ + JMETHOD(void *, alloc_small, (j_common_ptr cinfo, int pool_id, + size_t sizeofobject)); + JMETHOD(void FAR *, alloc_large, (j_common_ptr cinfo, int pool_id, + size_t sizeofobject)); + JMETHOD(JSAMPARRAY, alloc_sarray, (j_common_ptr cinfo, int pool_id, + JDIMENSION samplesperrow, + JDIMENSION numrows)); + JMETHOD(JBLOCKARRAY, alloc_barray, (j_common_ptr cinfo, int pool_id, + JDIMENSION blocksperrow, + JDIMENSION numrows)); + JMETHOD(jvirt_sarray_ptr, request_virt_sarray, (j_common_ptr cinfo, + int pool_id, + jboolean pre_zero, + JDIMENSION samplesperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + JMETHOD(jvirt_barray_ptr, request_virt_barray, (j_common_ptr cinfo, + int pool_id, + jboolean pre_zero, + JDIMENSION blocksperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + JMETHOD(void, realize_virt_arrays, (j_common_ptr cinfo)); + JMETHOD(JSAMPARRAY, access_virt_sarray, (j_common_ptr cinfo, + jvirt_sarray_ptr ptr, + JDIMENSION start_row, + JDIMENSION num_rows, + jboolean writable)); + JMETHOD(JBLOCKARRAY, access_virt_barray, (j_common_ptr cinfo, + jvirt_barray_ptr ptr, + JDIMENSION start_row, + JDIMENSION num_rows, + jboolean writable)); + JMETHOD(void, free_pool, (j_common_ptr cinfo, int pool_id)); + JMETHOD(void, self_destruct, (j_common_ptr cinfo)); + + /* Limit on memory allocation for this JPEG object. (Note that this is + * merely advisory, not a guaranteed maximum; it only affects the space + * used for virtual-array buffers.) May be changed by outer application + * after creating the JPEG object. + */ + long max_memory_to_use; + + /* Maximum allocation request accepted by alloc_large. */ + long max_alloc_chunk; +}; + + +/* Routine signature for application-supplied marker processing methods. + * Need not pass marker code since it is stored in cinfo->unread_marker. + */ +typedef JMETHOD(jboolean, jpeg_marker_parser_method, (j_decompress_ptr cinfo)); + + +/* Declarations for routines called by application. + * The JPP macro hides prototype parameters from compilers that can't cope. + * Note JPP requires double parentheses. + */ + +#ifdef HAVE_PROTOTYPES +#define JPP(arglist) arglist +#else +#define JPP(arglist) () +#endif + + +/* Short forms of external names for systems with brain-damaged linkers. + * We shorten external names to be unique in the first six letters, which + * is good enough for all known systems. + * (If your compiler itself needs names to be unique in less than 15 + * characters, you are out of luck. Get a better compiler.) + */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_std_error jStdError +#define jpeg_CreateCompress jCreaCompress +#define jpeg_CreateDecompress jCreaDecompress +#define jpeg_destroy_compress jDestCompress +#define jpeg_destroy_decompress jDestDecompress +#define jpeg_stdio_dest jStdDest +#define jpeg_stdio_src jStdSrc +#define jpeg_set_defaults jSetDefaults +#define jpeg_set_colorspace jSetColorspace +#define jpeg_default_colorspace jDefColorspace +#define jpeg_set_quality jSetQuality +#define jpeg_set_linear_quality jSetLQuality +#define jpeg_add_quant_table jAddQuantTable +#define jpeg_quality_scaling jQualityScaling +#define jpeg_simple_progression jSimProgress +#define jpeg_suppress_tables jSuppressTables +#define jpeg_alloc_quant_table jAlcQTable +#define jpeg_alloc_huff_table jAlcHTable +#define jpeg_start_compress jStrtCompress +#define jpeg_write_scanlines jWrtScanlines +#define jpeg_finish_compress jFinCompress +#define jpeg_write_raw_data jWrtRawData +#define jpeg_write_marker jWrtMarker +#define jpeg_write_m_header jWrtMHeader +#define jpeg_write_m_byte jWrtMByte +#define jpeg_write_tables jWrtTables +#define jpeg_read_header jReadHeader +#define jpeg_start_decompress jStrtDecompress +#define jpeg_read_scanlines jReadScanlines +#define jpeg_finish_decompress jFinDecompress +#define jpeg_read_raw_data jReadRawData +#define jpeg_has_multiple_scans jHasMultScn +#define jpeg_start_output jStrtOutput +#define jpeg_finish_output jFinOutput +#define jpeg_input_complete jInComplete +#define jpeg_new_colormap jNewCMap +#define jpeg_consume_input jConsumeInput +#define jpeg_calc_output_dimensions jCalcDimensions +#define jpeg_save_markers jSaveMarkers +#define jpeg_set_marker_processor jSetMarker +#define jpeg_read_coefficients jReadCoefs +#define jpeg_write_coefficients jWrtCoefs +#define jpeg_copy_critical_parameters jCopyCrit +#define jpeg_abort_compress jAbrtCompress +#define jpeg_abort_decompress jAbrtDecompress +#define jpeg_abort jAbort +#define jpeg_destroy jDestroy +#define jpeg_resync_to_restart jResyncRestart +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Default error-management setup */ +EXTERN(struct jpeg_error_mgr *) jpeg_std_error + JPP((struct jpeg_error_mgr * err)); + +/* Initialization of JPEG compression objects. + * jpeg_create_compress() and jpeg_create_decompress() are the exported + * names that applications should call. These expand to calls on + * jpeg_CreateCompress and jpeg_CreateDecompress with additional information + * passed for version mismatch checking. + * NB: you must set up the error-manager BEFORE calling jpeg_create_xxx. + */ +#define jpeg_create_compress(cinfo) \ + jpeg_CreateCompress((cinfo), JPEG_LIB_VERSION, \ + (size_t) sizeof(struct jpeg_compress_struct)) +#define jpeg_create_decompress(cinfo) \ + jpeg_CreateDecompress((cinfo), JPEG_LIB_VERSION, \ + (size_t) sizeof(struct jpeg_decompress_struct)) +EXTERN(void) jpeg_CreateCompress JPP((j_compress_ptr cinfo, + int version, size_t structsize)); +EXTERN(void) jpeg_CreateDecompress JPP((j_decompress_ptr cinfo, + int version, size_t structsize)); +/* Destruction of JPEG compression objects */ +EXTERN(void) jpeg_destroy_compress JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_destroy_decompress JPP((j_decompress_ptr cinfo)); + +/* Standard data source and destination managers: stdio streams. */ +/* Caller is responsible for opening the file before and closing after. */ +EXTERN(void) jpeg_stdio_dest JPP((j_compress_ptr cinfo, FILE * outfile)); +EXTERN(void) jpeg_stdio_src JPP((j_decompress_ptr cinfo, FILE * infile)); + +/* Default parameter setup for compression */ +EXTERN(void) jpeg_set_defaults JPP((j_compress_ptr cinfo)); +/* Compression parameter setup aids */ +EXTERN(void) jpeg_set_colorspace JPP((j_compress_ptr cinfo, + J_COLOR_SPACE colorspace)); +EXTERN(void) jpeg_default_colorspace JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_set_quality JPP((j_compress_ptr cinfo, int quality, + jboolean force_baseline)); +EXTERN(void) jpeg_set_linear_quality JPP((j_compress_ptr cinfo, + int scale_factor, + jboolean force_baseline)); +EXTERN(void) jpeg_add_quant_table JPP((j_compress_ptr cinfo, int which_tbl, + const unsigned int *basic_table, + int scale_factor, + jboolean force_baseline)); +EXTERN(int) jpeg_quality_scaling JPP((int quality)); +EXTERN(void) jpeg_simple_progression JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_suppress_tables JPP((j_compress_ptr cinfo, + jboolean suppress)); +EXTERN(JQUANT_TBL *) jpeg_alloc_quant_table JPP((j_common_ptr cinfo)); +EXTERN(JHUFF_TBL *) jpeg_alloc_huff_table JPP((j_common_ptr cinfo)); + +/* Main entry points for compression */ +EXTERN(void) jpeg_start_compress JPP((j_compress_ptr cinfo, + jboolean write_all_tables)); +EXTERN(JDIMENSION) jpeg_write_scanlines JPP((j_compress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION num_lines)); +EXTERN(void) jpeg_finish_compress JPP((j_compress_ptr cinfo)); + +/* Replaces jpeg_write_scanlines when writing raw downsampled data. */ +EXTERN(JDIMENSION) jpeg_write_raw_data JPP((j_compress_ptr cinfo, + JSAMPIMAGE data, + JDIMENSION num_lines)); + +/* Write a special marker. See libjpeg.doc concerning safe usage. */ +EXTERN(void) jpeg_write_marker + JPP((j_compress_ptr cinfo, int marker, + const JOCTET * dataptr, unsigned int datalen)); +/* Same, but piecemeal. */ +EXTERN(void) jpeg_write_m_header + JPP((j_compress_ptr cinfo, int marker, unsigned int datalen)); +EXTERN(void) jpeg_write_m_byte + JPP((j_compress_ptr cinfo, int val)); + +/* Alternate compression function: just write an abbreviated table file */ +EXTERN(void) jpeg_write_tables JPP((j_compress_ptr cinfo)); + +/* Decompression startup: read start of JPEG datastream to see what's there */ +EXTERN(int) jpeg_read_header JPP((j_decompress_ptr cinfo, + jboolean require_image)); +/* Return value is one of: */ +#define JPEG_SUSPENDED 0 /* Suspended due to lack of input data */ +#define JPEG_HEADER_OK 1 /* Found valid image datastream */ +#define JPEG_HEADER_TABLES_ONLY 2 /* Found valid table-specs-only datastream */ +/* If you pass require_image = TRUE (normal case), you need not check for + * a TABLES_ONLY return code; an abbreviated file will cause an error exit. + * JPEG_SUSPENDED is only possible if you use a data source module that can + * give a suspension return (the stdio source module doesn't). + */ + +/* Main entry points for decompression */ +EXTERN(jboolean) jpeg_start_decompress JPP((j_decompress_ptr cinfo)); +EXTERN(JDIMENSION) jpeg_read_scanlines JPP((j_decompress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION max_lines)); +EXTERN(jboolean) jpeg_finish_decompress JPP((j_decompress_ptr cinfo)); + +/* Replaces jpeg_read_scanlines when reading raw downsampled data. */ +EXTERN(JDIMENSION) jpeg_read_raw_data JPP((j_decompress_ptr cinfo, + JSAMPIMAGE data, + JDIMENSION max_lines)); + +/* Additional entry points for buffered-image mode. */ +EXTERN(jboolean) jpeg_has_multiple_scans JPP((j_decompress_ptr cinfo)); +EXTERN(jboolean) jpeg_start_output JPP((j_decompress_ptr cinfo, + int scan_number)); +EXTERN(jboolean) jpeg_finish_output JPP((j_decompress_ptr cinfo)); +EXTERN(jboolean) jpeg_input_complete JPP((j_decompress_ptr cinfo)); +EXTERN(void) jpeg_new_colormap JPP((j_decompress_ptr cinfo)); +EXTERN(int) jpeg_consume_input JPP((j_decompress_ptr cinfo)); +/* Return value is one of: */ +/* #define JPEG_SUSPENDED 0 Suspended due to lack of input data */ +#define JPEG_REACHED_SOS 1 /* Reached start of new scan */ +#define JPEG_REACHED_EOI 2 /* Reached end of image */ +#define JPEG_ROW_COMPLETED 3 /* Completed one iMCU row */ +#define JPEG_SCAN_COMPLETED 4 /* Completed last iMCU row of a scan */ + +/* Precalculate output dimensions for current decompression parameters. */ +EXTERN(void) jpeg_calc_output_dimensions JPP((j_decompress_ptr cinfo)); + +/* Control saving of COM and APPn markers into marker_list. */ +EXTERN(void) jpeg_save_markers + JPP((j_decompress_ptr cinfo, int marker_code, + unsigned int length_limit)); + +/* Install a special processing method for COM or APPn markers. */ +EXTERN(void) jpeg_set_marker_processor + JPP((j_decompress_ptr cinfo, int marker_code, + jpeg_marker_parser_method routine)); + +/* Read or write raw DCT coefficients --- useful for lossless transcoding. */ +EXTERN(jvirt_barray_ptr *) jpeg_read_coefficients JPP((j_decompress_ptr cinfo)); +EXTERN(void) jpeg_write_coefficients JPP((j_compress_ptr cinfo, + jvirt_barray_ptr * coef_arrays)); +EXTERN(void) jpeg_copy_critical_parameters JPP((j_decompress_ptr srcinfo, + j_compress_ptr dstinfo)); + +/* If you choose to abort compression or decompression before completing + * jpeg_finish_(de)compress, then you need to clean up to release memory, + * temporary files, etc. You can just call jpeg_destroy_(de)compress + * if you're done with the JPEG object, but if you want to clean it up and + * reuse it, call this: + */ +EXTERN(void) jpeg_abort_compress JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_abort_decompress JPP((j_decompress_ptr cinfo)); + +/* Generic versions of jpeg_abort and jpeg_destroy that work on either + * flavor of JPEG object. These may be more convenient in some places. + */ +EXTERN(void) jpeg_abort JPP((j_common_ptr cinfo)); +EXTERN(void) jpeg_destroy JPP((j_common_ptr cinfo)); + +/* Default restart-marker-resync procedure for use by data source modules */ +EXTERN(jboolean) jpeg_resync_to_restart JPP((j_decompress_ptr cinfo, + int desired)); + + +/* These marker codes are exported since applications and data source modules + * are likely to want to use them. + */ + +#define JPEG_RST0 0xD0 /* RST0 marker code */ +#define JPEG_EOI 0xD9 /* EOI marker code */ +#define JPEG_APP0 0xE0 /* APP0 marker code */ +#define JPEG_COM 0xFE /* COM marker code */ + + +/* If we have a brain-damaged compiler that emits warnings (or worse, errors) + * for structure definitions that are never filled in, keep it quiet by + * supplying dummy definitions for the various substructures. + */ + +#ifdef INCOMPLETE_TYPES_BROKEN +#ifndef JPEG_INTERNALS /* will be defined in jpegint.h */ +struct jvirt_sarray_control { long dummy; }; +struct jvirt_barray_control { long dummy; }; +struct jpeg_comp_master { long dummy; }; +struct jpeg_c_main_controller { long dummy; }; +struct jpeg_c_prep_controller { long dummy; }; +struct jpeg_c_coef_controller { long dummy; }; +struct jpeg_marker_writer { long dummy; }; +struct jpeg_color_converter { long dummy; }; +struct jpeg_downsampler { long dummy; }; +struct jpeg_forward_dct { long dummy; }; +struct jpeg_entropy_encoder { long dummy; }; +struct jpeg_decomp_master { long dummy; }; +struct jpeg_d_main_controller { long dummy; }; +struct jpeg_d_coef_controller { long dummy; }; +struct jpeg_d_post_controller { long dummy; }; +struct jpeg_input_controller { long dummy; }; +struct jpeg_marker_reader { long dummy; }; +struct jpeg_entropy_decoder { long dummy; }; +struct jpeg_inverse_dct { long dummy; }; +struct jpeg_upsampler { long dummy; }; +struct jpeg_color_deconverter { long dummy; }; +struct jpeg_color_quantizer { long dummy; }; +#endif /* JPEG_INTERNALS */ +#endif /* INCOMPLETE_TYPES_BROKEN */ + + +/* + * The JPEG library modules define JPEG_INTERNALS before including this file. + * The internal structure declarations are read only when that is true. + * Applications using the library should not include jpegint.h, but may wish + * to include jerror.h. + */ + +#ifdef JPEG_INTERNALS +#include "jpegint.h" /* fetch private declarations */ +#include "jerror.h" /* fetch error codes too */ +#endif + +#endif /* JPEGLIB_H */ diff --git a/winclude/jversion.h b/winclude/jversion.h new file mode 100755 index 000000000..6472c58d3 --- /dev/null +++ b/winclude/jversion.h @@ -0,0 +1,14 @@ +/* + * jversion.h + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains software version identification. + */ + + +#define JVERSION "6b 27-Mar-1998" + +#define JCOPYRIGHT "Copyright (C) 1998, Thomas G. Lane" diff --git a/winclude/lcms.h b/winclude/lcms.h new file mode 100755 index 000000000..c90a2b496 --- /dev/null +++ b/winclude/lcms.h @@ -0,0 +1,2052 @@ +// +// Little cms +// Copyright (C) 1998-2006 Marti Maria +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +// Version 1.16 + +#ifndef __cms_H + +// ********** Configuration toggles **************************************** + +// Optimization mode. +// +// Note that USE_ASSEMBLER Is fastest by far, but it is limited to Pentium. +// USE_FLOAT are the generic floating-point routines. USE_C should work on +// virtually any machine. + +//#define USE_FLOAT 1 +// #define USE_C 1 +#define USE_ASSEMBLER 1 + +// Define this if you are using this package as a DLL (windows only) + +// #define LCMS_DLL 1 +// #define LCMS_DLL_BUILD 1 + +// Uncomment if you are trying the engine in a non-windows environment +// like linux, SGI, VAX, FreeBSD, BeOS, etc. +#define NON_WINDOWS 1 + +// Uncomment this one if you are using big endian machines (only meaningful +// when NON_WINDOWS is used) +// #define USE_BIG_ENDIAN 1 + +// Uncomment this one if your compiler/machine does support the +// "long long" type This will speedup fixed point math. (USE_C only) +#define USE_INT64 1 + +// Some machines does not have a reliable 'swab' function. Usually +// leave commented unless the testbed diagnoses the contrary. +// #define USE_CUSTOM_SWAB 1 + +// Uncomment this if your compiler supports inline +#define USE_INLINE 1 + +// Uncomment this if your compiler doesn't work with fast floor function +// #define USE_DEFAULT_FLOOR_CONVERSION 1 + +// Uncomment this line on multithreading environments +// #define USE_PTHREADS 1 + +// Uncomment this line if you want lcms to use the black point tag in profile, +// if commented, lcms will compute the black point by its own. +// It is safer to leve it commented out +// #define HONOR_BLACK_POINT_TAG 1 + +// ********** End of configuration toggles ****************************** + +#define LCMS_VERSION 116 + +// Microsoft VisualC++ + +// Deal with Microsoft's attempt at deprecating C standard runtime functions + +#ifdef _MSC_VER +# undef NON_WINDOWS +# if (_MSC_VER >= 1400) +# define _CRT_SECURE_NO_DEPRECATE 1 +# endif +#endif + +// Borland C + +#ifdef __BORLANDC__ +# undef NON_WINDOWS +#endif + + +#include +#include +#include +#include +#include +#include + +// Metroworks CodeWarrior +#ifdef __MWERKS__ +# define unlink remove +# if WIN32 +# define USE_CUSTOM_SWAB 1 +# undef NON_WINDOWS +# else +# define NON_WINDOWS 1 +# endif +#endif + + +// Here comes the Non-Windows settings + +#ifdef NON_WINDOWS + +// Non windows environments. Also avoid indentation on includes. + +#ifdef USE_PTHREADS +# include +typedef pthread_rwlock_t LCMS_RWLOCK_T; +# define LCMS_CREATE_LOCK(x) pthread_rwlock_init((x), NULL) +# define LCMS_FREE_LOCK(x) pthread_rwlock_destroy((x)) +# define LCMS_READ_LOCK(x) pthread_rwlock_rdlock((x)) +# define LCMS_WRITE_LOCK(x) pthread_rwlock_wrlock((x)) +# define LCMS_UNLOCK(x) pthread_rwlock_unlock((x)) +#endif + +#undef LCMS_DLL + +#ifdef USE_ASSEMBLER +# undef USE_ASSEMBLER +# define USE_C 1 +#endif + +#ifdef _HOST_BIG_ENDIAN +# define USE_BIG_ENDIAN 1 +#endif + +#if defined(__sgi__) || defined(__sgi) || defined(__powerpc__) || defined(sparc) || defined(__ppc__) +# define USE_BIG_ENDIAN 1 +#endif + +#if TARGET_CPU_PPC +# define USE_BIG_ENDIAN 1 +#endif + +#if macintosh +# ifndef __LITTLE_ENDIAN__ +# define USE_BIG_ENDIAN 1 +# endif +#endif + +#if __BIG_ENDIAN__ +# define USE_BIG_ENDIAN 1 +#endif + +#ifdef WORDS_BIGENDIAN +# define USE_BIG_ENDIAN 1 +#endif + +#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) +# include +# define USE_INT64 1 +# define LCMSSLONGLONG int64_t +# define LCMSULONGLONG u_int64_t +#endif + +#ifdef USE_INT64 +# ifndef LCMSULONGLONG +# define LCMSULONGLONG unsigned long long +# define LCMSSLONGLONG long long +# endif +#endif + +#if !defined(__INTEGRITY) +# include +#endif + +#include + +#if defined(__GNUC__) || defined(__FreeBSD__) +# include +#endif + +#ifndef LCMS_WIN_TYPES_ALREADY_DEFINED + +typedef unsigned char BYTE, *LPBYTE; +typedef unsigned short WORD, *LPWORD; +typedef unsigned long DWORD, *LPDWORD; +typedef int BOOL; +typedef char *LPSTR; +typedef void *LPVOID; +typedef void* LCMSHANDLE; + + +#define ZeroMemory(p,l) memset((p),0,(l)) +#define CopyMemory(d,s,l) memcpy((d),(s),(l)) +#define FAR + +#ifndef stricmp +# define stricmp strcasecmp +#endif + + +#ifndef FALSE +# define FALSE 0 +#endif +#ifndef TRUE +# define TRUE 1 +#endif + +#define LOWORD(l) ((WORD)(l)) +#define HIWORD(l) ((WORD)((DWORD)(l) >> 16)) + +#ifndef MAX_PATH +# define MAX_PATH (256) +#endif + +#define cdecl +#endif + +// The specification for "inline" is section 6.7.4 of the C99 standard (ISO/IEC 9899:1999). + +#define LCMS_INLINE static inline + +#else + +// Win32 stuff + +#ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif + +#include + +typedef HANDLE LCMSHANDLE; + + +#ifdef USE_INT64 +# ifndef LCMSULONGLONG +# define LCMSULONGLONG unsigned __int64 +# define LCMSSLONGLONG __int64 +# endif +#endif + +// This works for both VC & BorlandC +#define LCMS_INLINE __inline + +#ifdef USE_PTHREADS +typedef CRITICAL_SECTION LCMS_RWLOCK_T; +# define LCMS_CREATE_LOCK(x) InitializeCriticalSection((x)) +# define LCMS_FREE_LOCK(x) DeleteCriticalSection((x)) +# define LCMS_READ_LOCK(x) EnterCriticalSection((x)) +# define LCMS_WRITE_LOCK(x) EnterCriticalSection((x)) +# define LCMS_UNLOCK(x) LeaveCriticalSection((x)) +#endif + +#endif + +#ifndef USE_PTHREADS +typedef int LCMS_RWLOCK_T; +# define LCMS_CREATE_LOCK(x) +# define LCMS_FREE_LOCK(x) +# define LCMS_READ_LOCK(x) +# define LCMS_WRITE_LOCK(x) +# define LCMS_UNLOCK(x) +#endif + + +#include "icc34.h" // ICC header file + + +// Some tag & type additions + +#define lcmsSignature ((icSignature) 0x6c636d73L) + +#define icSigLuvKData ((icColorSpaceSignature) 0x4C75764BL) // 'LuvK' + +#define icSigHexachromeData ((icColorSpaceSignature) 0x4d434836L) // MCH6 +#define icSigHeptachromeData ((icColorSpaceSignature) 0x4d434837L) // MCH7 +#define icSigOctachromeData ((icColorSpaceSignature) 0x4d434838L) // MCH8 + +#define icSigMCH5Data ((icColorSpaceSignature) 0x4d434835L) // MCH5 +#define icSigMCH6Data ((icColorSpaceSignature) 0x4d434836L) // MCH6 +#define icSigMCH7Data ((icColorSpaceSignature) 0x4d434837L) // MCH7 +#define icSigMCH8Data ((icColorSpaceSignature) 0x4d434838L) // MCH8 +#define icSigMCH9Data ((icColorSpaceSignature) 0x4d434839L) // MCH9 +#define icSigMCHAData ((icColorSpaceSignature) 0x4d434841L) // MCHA +#define icSigMCHBData ((icColorSpaceSignature) 0x4d434842L) // MCHB +#define icSigMCHCData ((icColorSpaceSignature) 0x4d434843L) // MCHC +#define icSigMCHDData ((icColorSpaceSignature) 0x4d434844L) // MCHD +#define icSigMCHEData ((icColorSpaceSignature) 0x4d434845L) // MCHE +#define icSigMCHFData ((icColorSpaceSignature) 0x4d434846L) // MCHF + +#define icSigCAM97JABData ((icColorSpaceSignature) 0x4A616231L) // 'Jab1' H. Zeng +#define icSigCAM02JABData ((icColorSpaceSignature) 0x4A616232L) // 'Jab2' H. Zeng +#define icSigCAM02JCHData ((icColorSpaceSignature) 0x4A636A32L) // 'Jch2' H. Zeng + +#define icSigChromaticityTag ((icTagSignature) 0x6368726dL) // As per Addendum 2 to Spec. ICC.1:1998-09 +#define icSigChromaticAdaptationTag ((icTagSignature) 0x63686164L) // 'chad' +#define icSigColorantTableTag ((icTagSignature) 0x636c7274L) // 'clrt' +#define icSigColorantTableOutTag ((icTagSignature) 0x636c6f74L) // 'clot' +#define icSigHPGamutDescTag ((icTagSignature) 0x676D7441L) // 'gmtA' H. Zeng + + +#define icSigParametricCurveType ((icTagTypeSignature) 0x70617261L) // parametric (ICC 4.0) +#define icSigMultiLocalizedUnicodeType ((icTagTypeSignature) 0x6D6C7563L) +#define icSigS15Fixed16ArrayType ((icTagTypeSignature) 0x73663332L) +#define icSigChromaticityType ((icTagTypeSignature) 0x6368726dL) +#define icSiglutAtoBType ((icTagTypeSignature) 0x6d414220L) // mAB +#define icSiglutBtoAType ((icTagTypeSignature) 0x6d424120L) // mBA +#define icSigColorantTableType ((icTagTypeSignature) 0x636c7274L) // clrt +#define icSigHPGamutDescType ((icTagTypeSignature) 0x676D7441L) // gmtA H. Zeng + + +typedef struct { + icUInt8Number gridPoints[16]; // Number of grid points in each dimension. + icUInt8Number prec; // Precision of data elements in bytes. + icUInt8Number pad1; + icUInt8Number pad2; + icUInt8Number pad3; + /*icUInt8Number data[icAny]; Data follows see spec for size */ +} icCLutStruct; + +// icLutAtoB +typedef struct { + icUInt8Number inputChan; // Number of input channels + icUInt8Number outputChan; // Number of output channels + icUInt8Number pad1; + icUInt8Number pad2; + icUInt32Number offsetB; // Offset to first "B" curve + icUInt32Number offsetMat; // Offset to matrix + icUInt32Number offsetM; // Offset to first "M" curve + icUInt32Number offsetC; // Offset to CLUT + icUInt32Number offsetA; // Offset to first "A" curve + /*icUInt8Number data[icAny]; Data follows see spec for size */ +} icLutAtoB; + +// icLutBtoA +typedef struct { + icUInt8Number inputChan; // Number of input channels + icUInt8Number outputChan; // Number of output channels + icUInt8Number pad1; + icUInt8Number pad2; + icUInt32Number offsetB; // Offset to first "B" curve + icUInt32Number offsetMat; // Offset to matrix + icUInt32Number offsetM; // Offset to first "M" curve + icUInt32Number offsetC; // Offset to CLUT + icUInt32Number offsetA; // Offset to first "A" curve + /*icUInt8Number data[icAny]; Data follows see spec for size */ +} icLutBtoA; + + + + + +#ifdef __cplusplus +extern "C" { +#endif + +// Calling convention + +#ifdef NON_WINDOWS +# define LCMSEXPORT +# define LCMSAPI +#else +# ifdef LCMS_DLL +# ifdef __BORLANDC__ +# define LCMSEXPORT __stdcall _export +# define LCMSAPI +# else + // VC++ +# define LCMSEXPORT _stdcall +# ifdef LCMS_DLL_BUILD +# define LCMSAPI __declspec(dllexport) +# else +# define LCMSAPI __declspec(dllimport) +# endif +# endif +# else +# define LCMSEXPORT cdecl +# define LCMSAPI +# endif +#endif + +#ifdef USE_ASSEMBLER +#ifdef __BORLANDC__ + +# define ASM asm +# define RET(v) return(v) +#else + // VC++ +# define ASM __asm +# define RET(v) return +#endif +#endif + +#ifdef _MSC_VER +#ifndef stricmp +# define stricmp _stricmp +#endif +#ifndef unlink +# define unlink _unlink +#endif +#ifndef swab +# define swab _swab +#endif +#ifndef itoa +# define itoa _itoa +#endif +#ifndef filelength +# define filelength _filelength +#endif +#ifndef fileno +# define fileno _fileno +#endif +#ifndef strupr +# define strupr _strupr +#endif +#ifndef hypot +# define hypot _hypot +#endif +#endif + + +#ifndef M_PI +# define M_PI 3.14159265358979323846 +#endif + +#ifndef LOGE +# define LOGE 0.4342944819 +#endif + +// ********** Little cms API *************************************************** + +typedef LCMSHANDLE cmsHPROFILE; // Opaque typedefs to hide internals +typedef LCMSHANDLE cmsHTRANSFORM; + +#define MAXCHANNELS 16 // Maximum number of channels + +// Format of pixel is defined by one DWORD, using bit fields as follows +// +// TTTTT U Y F P X S EEE CCCC BBB +// +// T: Pixeltype +// F: Flavor 0=MinIsBlack(Chocolate) 1=MinIsWhite(Vanilla) +// P: Planar? 0=Chunky, 1=Planar +// X: swap 16 bps endianess? +// S: Do swap? ie, BGR, KYMC +// E: Extra samples +// C: Channels (Samples per pixel) +// B: Bytes per sample +// Y: Swap first - changes ABGR to BGRA and KCMY to CMYK + + +#define COLORSPACE_SH(s) ((s) << 16) +#define SWAPFIRST_SH(s) ((s) << 14) +#define FLAVOR_SH(s) ((s) << 13) +#define PLANAR_SH(p) ((p) << 12) +#define ENDIAN16_SH(e) ((e) << 11) +#define DOSWAP_SH(e) ((e) << 10) +#define EXTRA_SH(e) ((e) << 7) +#define CHANNELS_SH(c) ((c) << 3) +#define BYTES_SH(b) (b) + +// Pixel types + +#define PT_ANY 0 // Don't check colorspace + // 1 & 2 are reserved +#define PT_GRAY 3 +#define PT_RGB 4 +#define PT_CMY 5 +#define PT_CMYK 6 +#define PT_YCbCr 7 +#define PT_YUV 8 // Lu'v' +#define PT_XYZ 9 +#define PT_Lab 10 +#define PT_YUVK 11 // Lu'v'K +#define PT_HSV 12 +#define PT_HLS 13 +#define PT_Yxy 14 +#define PT_HiFi 15 +#define PT_HiFi7 16 +#define PT_HiFi8 17 +#define PT_HiFi9 18 +#define PT_HiFi10 19 +#define PT_HiFi11 20 +#define PT_HiFi12 21 +#define PT_HiFi13 22 +#define PT_HiFi14 23 +#define PT_HiFi15 24 + +#define NOCOLORSPACECHECK(x) ((x) & 0xFFFF) + +// Some (not all!) representations + +#ifndef TYPE_RGB_8 // TYPE_RGB_8 is a very common identifier, so don't include ours + // if user has it already defined. + +#define TYPE_GRAY_8 (COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(1)) +#define TYPE_GRAY_8_REV (COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(1)|FLAVOR_SH(1)) +#define TYPE_GRAY_16 (COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(2)) +#define TYPE_GRAY_16_REV (COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(2)|FLAVOR_SH(1)) +#define TYPE_GRAY_16_SE (COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(2)|ENDIAN16_SH(1)) +#define TYPE_GRAYA_8 (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(1)) +#define TYPE_GRAYA_16 (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(2)) +#define TYPE_GRAYA_16_SE (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(2)|ENDIAN16_SH(1)) +#define TYPE_GRAYA_8_PLANAR (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(1)|PLANAR_SH(1)) +#define TYPE_GRAYA_16_PLANAR (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(2)|PLANAR_SH(1)) + +#define TYPE_RGB_8 (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(1)) +#define TYPE_RGB_8_PLANAR (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1)) +#define TYPE_BGR_8 (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)) +#define TYPE_BGR_8_PLANAR (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|PLANAR_SH(1)) +#define TYPE_RGB_16 (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_RGB_16_PLANAR (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1)) +#define TYPE_RGB_16_SE (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)) +#define TYPE_BGR_16 (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)) +#define TYPE_BGR_16_PLANAR (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|PLANAR_SH(1)) +#define TYPE_BGR_16_SE (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1)) + +#define TYPE_RGBA_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)) +#define TYPE_RGBA_8_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1)) +#define TYPE_RGBA_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_RGBA_16_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1)) +#define TYPE_RGBA_16_SE (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)) + +#define TYPE_ARGB_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|SWAPFIRST_SH(1)) +#define TYPE_ARGB_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|SWAPFIRST_SH(1)) + +#define TYPE_ABGR_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)) +#define TYPE_ABGR_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)) +#define TYPE_ABGR_16_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|PLANAR_SH(1)) +#define TYPE_ABGR_16_SE (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1)) + +#define TYPE_BGRA_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1)) +#define TYPE_BGRA_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|SWAPFIRST_SH(1)) +#define TYPE_BGRA_16_SE (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)|SWAPFIRST_SH(1)) + +#define TYPE_CMY_8 (COLORSPACE_SH(PT_CMY)|CHANNELS_SH(3)|BYTES_SH(1)) +#define TYPE_CMY_8_PLANAR (COLORSPACE_SH(PT_CMY)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1)) +#define TYPE_CMY_16 (COLORSPACE_SH(PT_CMY)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_CMY_16_PLANAR (COLORSPACE_SH(PT_CMY)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1)) +#define TYPE_CMY_16_SE (COLORSPACE_SH(PT_CMY)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)) + +#define TYPE_CMYK_8 (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(1)) +#define TYPE_CMYKA_8 (COLORSPACE_SH(PT_CMYK)|EXTRA_SH(1)|CHANNELS_SH(4)|BYTES_SH(1)) +#define TYPE_CMYK_8_REV (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1)) +#define TYPE_YUVK_8 TYPE_CMYK_8_REV +#define TYPE_CMYK_8_PLANAR (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(1)|PLANAR_SH(1)) +#define TYPE_CMYK_16 (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)) +#define TYPE_CMYK_16_REV (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|FLAVOR_SH(1)) +#define TYPE_YUVK_16 TYPE_CMYK_16_REV +#define TYPE_CMYK_16_PLANAR (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|PLANAR_SH(1)) +#define TYPE_CMYK_16_SE (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|ENDIAN16_SH(1)) + +#define TYPE_KYMC_8 (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)) +#define TYPE_KYMC_16 (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1)) +#define TYPE_KYMC_16_SE (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1)) + +#define TYPE_KCMY_8 (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(1)|SWAPFIRST_SH(1)) +#define TYPE_KCMY_8_REV (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1)|SWAPFIRST_SH(1)) +#define TYPE_KCMY_16 (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|SWAPFIRST_SH(1)) +#define TYPE_KCMY_16_REV (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|FLAVOR_SH(1)|SWAPFIRST_SH(1)) +#define TYPE_KCMY_16_SE (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|ENDIAN16_SH(1)|SWAPFIRST_SH(1)) + + +// HiFi separations, Thanks to Steven Greaves for providing the code, +// the colorspace is not checked +#define TYPE_CMYK5_8 (CHANNELS_SH(5)|BYTES_SH(1)) +#define TYPE_CMYK5_16 (CHANNELS_SH(5)|BYTES_SH(2)) +#define TYPE_CMYK5_16_SE (CHANNELS_SH(5)|BYTES_SH(2)|ENDIAN16_SH(1)) +#define TYPE_KYMC5_8 (CHANNELS_SH(5)|BYTES_SH(1)|DOSWAP_SH(1)) +#define TYPE_KYMC5_16 (CHANNELS_SH(5)|BYTES_SH(2)|DOSWAP_SH(1)) +#define TYPE_KYMC5_16_SE (CHANNELS_SH(5)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1)) + +#define TYPE_CMYKcm_8 (CHANNELS_SH(6)|BYTES_SH(1)) +#define TYPE_CMYKcm_8_PLANAR (CHANNELS_SH(6)|BYTES_SH(1)|PLANAR_SH(1)) +#define TYPE_CMYKcm_16 (CHANNELS_SH(6)|BYTES_SH(2)) +#define TYPE_CMYKcm_16_PLANAR (CHANNELS_SH(6)|BYTES_SH(2)|PLANAR_SH(1)) +#define TYPE_CMYKcm_16_SE (CHANNELS_SH(6)|BYTES_SH(2)|ENDIAN16_SH(1)) + +// Separations with more than 6 channels aren't very standarized, +// Except most start with CMYK and add other colors, so I just used +// then total number of channels after CMYK i.e CMYK8_8 + +#define TYPE_CMYK7_8 (CHANNELS_SH(7)|BYTES_SH(1)) +#define TYPE_CMYK7_16 (CHANNELS_SH(7)|BYTES_SH(2)) +#define TYPE_CMYK7_16_SE (CHANNELS_SH(7)|BYTES_SH(2)|ENDIAN16_SH(1)) +#define TYPE_KYMC7_8 (CHANNELS_SH(7)|BYTES_SH(1)|DOSWAP_SH(1)) +#define TYPE_KYMC7_16 (CHANNELS_SH(7)|BYTES_SH(2)|DOSWAP_SH(1)) +#define TYPE_KYMC7_16_SE (CHANNELS_SH(7)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1)) +#define TYPE_CMYK8_8 (CHANNELS_SH(8)|BYTES_SH(1)) +#define TYPE_CMYK8_16 (CHANNELS_SH(8)|BYTES_SH(2)) +#define TYPE_CMYK8_16_SE (CHANNELS_SH(8)|BYTES_SH(2)|ENDIAN16_SH(1)) +#define TYPE_KYMC8_8 (CHANNELS_SH(8)|BYTES_SH(1)|DOSWAP_SH(1)) +#define TYPE_KYMC8_16 (CHANNELS_SH(8)|BYTES_SH(2)|DOSWAP_SH(1)) +#define TYPE_KYMC8_16_SE (CHANNELS_SH(8)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1)) +#define TYPE_CMYK9_8 (CHANNELS_SH(9)|BYTES_SH(1)) +#define TYPE_CMYK9_16 (CHANNELS_SH(9)|BYTES_SH(2)) +#define TYPE_CMYK9_16_SE (CHANNELS_SH(9)|BYTES_SH(2)|ENDIAN16_SH(1)) +#define TYPE_KYMC9_8 (CHANNELS_SH(9)|BYTES_SH(1)|DOSWAP_SH(1)) +#define TYPE_KYMC9_16 (CHANNELS_SH(9)|BYTES_SH(2)|DOSWAP_SH(1)) +#define TYPE_KYMC9_16_SE (CHANNELS_SH(9)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1)) +#define TYPE_CMYK10_8 (CHANNELS_SH(10)|BYTES_SH(1)) +#define TYPE_CMYK10_16 (CHANNELS_SH(10)|BYTES_SH(2)) +#define TYPE_CMYK10_16_SE (CHANNELS_SH(10)|BYTES_SH(2)|ENDIAN16_SH(1)) +#define TYPE_KYMC10_8 (CHANNELS_SH(10)|BYTES_SH(1)|DOSWAP_SH(1)) +#define TYPE_KYMC10_16 (CHANNELS_SH(10)|BYTES_SH(2)|DOSWAP_SH(1)) +#define TYPE_KYMC10_16_SE (CHANNELS_SH(10)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1)) +#define TYPE_CMYK11_8 (CHANNELS_SH(11)|BYTES_SH(1)) +#define TYPE_CMYK11_16 (CHANNELS_SH(11)|BYTES_SH(2)) +#define TYPE_CMYK11_16_SE (CHANNELS_SH(11)|BYTES_SH(2)|ENDIAN16_SH(1)) +#define TYPE_KYMC11_8 (CHANNELS_SH(11)|BYTES_SH(1)|DOSWAP_SH(1)) +#define TYPE_KYMC11_16 (CHANNELS_SH(11)|BYTES_SH(2)|DOSWAP_SH(1)) +#define TYPE_KYMC11_16_SE (CHANNELS_SH(11)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1)) +#define TYPE_CMYK12_8 (CHANNELS_SH(12)|BYTES_SH(1)) +#define TYPE_CMYK12_16 (CHANNELS_SH(12)|BYTES_SH(2)) +#define TYPE_CMYK12_16_SE (CHANNELS_SH(12)|BYTES_SH(2)|ENDIAN16_SH(1)) +#define TYPE_KYMC12_8 (CHANNELS_SH(12)|BYTES_SH(1)|DOSWAP_SH(1)) +#define TYPE_KYMC12_16 (CHANNELS_SH(12)|BYTES_SH(2)|DOSWAP_SH(1)) +#define TYPE_KYMC12_16_SE (CHANNELS_SH(12)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1)) + +// Colorimetric + +#define TYPE_XYZ_16 (COLORSPACE_SH(PT_XYZ)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_Lab_8 (COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(1)) +#define TYPE_ALab_8 (COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|DOSWAP_SH(1)) +#define TYPE_Lab_16 (COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_Yxy_16 (COLORSPACE_SH(PT_Yxy)|CHANNELS_SH(3)|BYTES_SH(2)) + +// YCbCr + +#define TYPE_YCbCr_8 (COLORSPACE_SH(PT_YCbCr)|CHANNELS_SH(3)|BYTES_SH(1)) +#define TYPE_YCbCr_8_PLANAR (COLORSPACE_SH(PT_YCbCr)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1)) +#define TYPE_YCbCr_16 (COLORSPACE_SH(PT_YCbCr)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_YCbCr_16_PLANAR (COLORSPACE_SH(PT_YCbCr)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1)) +#define TYPE_YCbCr_16_SE (COLORSPACE_SH(PT_YCbCr)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)) + +// YUV + +#define TYPE_YUV_8 (COLORSPACE_SH(PT_YUV)|CHANNELS_SH(3)|BYTES_SH(1)) +#define TYPE_YUV_8_PLANAR (COLORSPACE_SH(PT_YUV)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1)) +#define TYPE_YUV_16 (COLORSPACE_SH(PT_YUV)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_YUV_16_PLANAR (COLORSPACE_SH(PT_YUV)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1)) +#define TYPE_YUV_16_SE (COLORSPACE_SH(PT_YUV)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)) + +// HLS + +#define TYPE_HLS_8 (COLORSPACE_SH(PT_HLS)|CHANNELS_SH(3)|BYTES_SH(1)) +#define TYPE_HLS_8_PLANAR (COLORSPACE_SH(PT_HLS)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1)) +#define TYPE_HLS_16 (COLORSPACE_SH(PT_HLS)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_HLS_16_PLANAR (COLORSPACE_SH(PT_HLS)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1)) +#define TYPE_HLS_16_SE (COLORSPACE_SH(PT_HLS)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)) + + +// HSV + +#define TYPE_HSV_8 (COLORSPACE_SH(PT_HSV)|CHANNELS_SH(3)|BYTES_SH(1)) +#define TYPE_HSV_8_PLANAR (COLORSPACE_SH(PT_HSV)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1)) +#define TYPE_HSV_16 (COLORSPACE_SH(PT_HSV)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_HSV_16_PLANAR (COLORSPACE_SH(PT_HSV)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1)) +#define TYPE_HSV_16_SE (COLORSPACE_SH(PT_HSV)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)) + +// Named color index. Only 16 bits allowed (don't check colorspace) + +#define TYPE_NAMED_COLOR_INDEX (CHANNELS_SH(1)|BYTES_SH(2)) + +// Double values. Painful slow, but sometimes helpful. NOTE THAT 'BYTES' FIELD IS SET TO ZERO! + +#define TYPE_XYZ_DBL (COLORSPACE_SH(PT_XYZ)|CHANNELS_SH(3)|BYTES_SH(0)) +#define TYPE_Lab_DBL (COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(0)) +#define TYPE_GRAY_DBL (COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(0)) +#define TYPE_RGB_DBL (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(0)) +#define TYPE_CMYK_DBL (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(0)) + +#endif + + +// Gamma table parameters + +typedef struct { + + unsigned int Crc32; // Has my table been touched? + + // Keep initial parameters for further serialization + + int Type; + double Params[10]; + + } LCMSGAMMAPARAMS, FAR* LPLCMSGAMMAPARAMS; + +// Gamma tables. + +typedef struct { + + LCMSGAMMAPARAMS Seed; // Parameters used for table creation + + // Table-based representation follows + + int nEntries; + WORD GammaTable[1]; + + } GAMMATABLE; + +typedef GAMMATABLE FAR* LPGAMMATABLE; + +// Sampled curves (1D) +typedef struct { + + int nItems; + double* Values; + + } SAMPLEDCURVE; + +typedef SAMPLEDCURVE FAR* LPSAMPLEDCURVE; + +// Vectors +typedef struct { // Float Vector + + double n[3]; + + } VEC3; + +typedef VEC3 FAR* LPVEC3; + + +typedef struct { // Matrix + + VEC3 v[3]; + + } MAT3; + +typedef MAT3 FAR* LPMAT3; + +// Colorspace values +typedef struct { + + double X; + double Y; + double Z; + + } cmsCIEXYZ; + +typedef cmsCIEXYZ FAR* LPcmsCIEXYZ; + +typedef struct { + + double x; + double y; + double Y; + + } cmsCIExyY; + +typedef cmsCIExyY FAR* LPcmsCIExyY; + +typedef struct { + + double L; + double a; + double b; + + } cmsCIELab; + +typedef cmsCIELab FAR* LPcmsCIELab; + +typedef struct { + + double L; + double C; + double h; + + } cmsCIELCh; + +typedef cmsCIELCh FAR* LPcmsCIELCh; + +typedef struct { + + double J; + double C; + double h; + + } cmsJCh; + +typedef cmsJCh FAR* LPcmsJCh; + +// Primaries +typedef struct { + + cmsCIEXYZ Red; + cmsCIEXYZ Green; + cmsCIEXYZ Blue; + + } cmsCIEXYZTRIPLE; + +typedef cmsCIEXYZTRIPLE FAR* LPcmsCIEXYZTRIPLE; + + +typedef struct { + + cmsCIExyY Red; + cmsCIExyY Green; + cmsCIExyY Blue; + + } cmsCIExyYTRIPLE; + +typedef cmsCIExyYTRIPLE FAR* LPcmsCIExyYTRIPLE; + + + +// Following ICC spec + +#define D50X (0.9642) +#define D50Y (1.0) +#define D50Z (0.8249) + +#define PERCEPTUAL_BLACK_X (0.00336) +#define PERCEPTUAL_BLACK_Y (0.0034731) +#define PERCEPTUAL_BLACK_Z (0.00287) + +// Does return pointers to constant structs + +LCMSAPI LPcmsCIEXYZ LCMSEXPORT cmsD50_XYZ(void); +LCMSAPI LPcmsCIExyY LCMSEXPORT cmsD50_xyY(void); + + +// Input/Output + +LCMSAPI cmsHPROFILE LCMSEXPORT cmsOpenProfileFromFile(const char *ICCProfile, const char *sAccess); +LCMSAPI cmsHPROFILE LCMSEXPORT cmsOpenProfileFromMem(LPVOID MemPtr, DWORD dwSize); +LCMSAPI BOOL LCMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile); + +// Predefined run-time profiles + +LCMSAPI cmsHPROFILE LCMSEXPORT cmsCreateRGBProfile(LPcmsCIExyY WhitePoint, + LPcmsCIExyYTRIPLE Primaries, + LPGAMMATABLE TransferFunction[3]); + +LCMSAPI cmsHPROFILE LCMSEXPORT cmsCreateGrayProfile(LPcmsCIExyY WhitePoint, + LPGAMMATABLE TransferFunction); + +LCMSAPI cmsHPROFILE LCMSEXPORT cmsCreateLinearizationDeviceLink(icColorSpaceSignature ColorSpace, + LPGAMMATABLE TransferFunctions[]); + +LCMSAPI cmsHPROFILE LCMSEXPORT cmsCreateInkLimitingDeviceLink(icColorSpaceSignature ColorSpace, + double Limit); + + +LCMSAPI cmsHPROFILE LCMSEXPORT cmsCreateLabProfile(LPcmsCIExyY WhitePoint); +LCMSAPI cmsHPROFILE LCMSEXPORT cmsCreateLab4Profile(LPcmsCIExyY WhitePoint); + +LCMSAPI cmsHPROFILE LCMSEXPORT cmsCreateXYZProfile(void); +LCMSAPI cmsHPROFILE LCMSEXPORT cmsCreate_sRGBProfile(void); + + + +LCMSAPI cmsHPROFILE LCMSEXPORT cmsCreateBCHSWabstractProfile(int nLUTPoints, + double Bright, + double Contrast, + double Hue, + double Saturation, + int TempSrc, + int TempDest); + +LCMSAPI cmsHPROFILE LCMSEXPORT cmsCreateNULLProfile(void); + + +// Colorimetric space conversions + +LCMSAPI void LCMSEXPORT cmsXYZ2xyY(LPcmsCIExyY Dest, const cmsCIEXYZ* Source); +LCMSAPI void LCMSEXPORT cmsxyY2XYZ(LPcmsCIEXYZ Dest, const cmsCIExyY* Source); +LCMSAPI void LCMSEXPORT cmsXYZ2Lab(LPcmsCIEXYZ WhitePoint, LPcmsCIELab Lab, const cmsCIEXYZ* xyz); +LCMSAPI void LCMSEXPORT cmsLab2XYZ(LPcmsCIEXYZ WhitePoint, LPcmsCIEXYZ xyz, const cmsCIELab* Lab); +LCMSAPI void LCMSEXPORT cmsLab2LCh(LPcmsCIELCh LCh, const cmsCIELab* Lab); +LCMSAPI void LCMSEXPORT cmsLCh2Lab(LPcmsCIELab Lab, const cmsCIELCh* LCh); + + +// CIELab handling + +LCMSAPI double LCMSEXPORT cmsDeltaE(LPcmsCIELab Lab1, LPcmsCIELab Lab2); +LCMSAPI double LCMSEXPORT cmsCIE94DeltaE(LPcmsCIELab Lab1, LPcmsCIELab Lab2); +LCMSAPI double LCMSEXPORT cmsBFDdeltaE(LPcmsCIELab Lab1, LPcmsCIELab Lab2); +LCMSAPI double LCMSEXPORT cmsCMCdeltaE(LPcmsCIELab Lab1, LPcmsCIELab Lab2); +LCMSAPI double LCMSEXPORT cmsCIE2000DeltaE(LPcmsCIELab Lab1, LPcmsCIELab Lab2, double Kl, double Kc, double Kh); + +LCMSAPI void LCMSEXPORT cmsClampLab(LPcmsCIELab Lab, double amax, double amin, double bmax, double bmin); + +LCMSAPI BOOL LCMSEXPORT cmsWhitePointFromTemp(int TempK, LPcmsCIExyY WhitePoint); + +LCMSAPI BOOL LCMSEXPORT cmsAdaptToIlluminant(LPcmsCIEXYZ Result, + LPcmsCIEXYZ SourceWhitePt, + LPcmsCIEXYZ Illuminant, + LPcmsCIEXYZ Value); + +LCMSAPI BOOL LCMSEXPORT cmsBuildRGB2XYZtransferMatrix(LPMAT3 r, + LPcmsCIExyY WhitePoint, + LPcmsCIExyYTRIPLE Primaries); + +// Viewing conditions + +#define AVG_SURROUND_4 0 +#define AVG_SURROUND 1 +#define DIM_SURROUND 2 +#define DARK_SURROUND 3 +#define CUTSHEET_SURROUND 4 + +#define D_CALCULATE (-1) +#define D_CALCULATE_DISCOUNT (-2) + +typedef struct { + + cmsCIEXYZ whitePoint; + double Yb; + double La; + int surround; + double D_value; + + } cmsViewingConditions; + +typedef cmsViewingConditions FAR* LPcmsViewingConditions; + +// CIECAM97s + +LCMSAPI LCMSHANDLE LCMSEXPORT cmsCIECAM97sInit(LPcmsViewingConditions pVC2); +LCMSAPI void LCMSEXPORT cmsCIECAM97sDone(LCMSHANDLE hModel); +LCMSAPI void LCMSEXPORT cmsCIECAM97sForward(LCMSHANDLE hModel, LPcmsCIEXYZ pIn, LPcmsJCh pOut); +LCMSAPI void LCMSEXPORT cmsCIECAM97sReverse(LCMSHANDLE hModel, LPcmsJCh pIn, LPcmsCIEXYZ pOut); + + +// CIECAM02 + +LCMSAPI LCMSHANDLE LCMSEXPORT cmsCIECAM02Init(LPcmsViewingConditions pVC); +LCMSAPI void LCMSEXPORT cmsCIECAM02Done(LCMSHANDLE hModel); +LCMSAPI void LCMSEXPORT cmsCIECAM02Forward(LCMSHANDLE hModel, LPcmsCIEXYZ pIn, LPcmsJCh pOut); +LCMSAPI void LCMSEXPORT cmsCIECAM02Reverse(LCMSHANDLE hModel, LPcmsJCh pIn, LPcmsCIEXYZ pOut); + + +// Gamma + +LCMSAPI LPGAMMATABLE LCMSEXPORT cmsBuildGamma(int nEntries, double Gamma); +LCMSAPI LPGAMMATABLE LCMSEXPORT cmsBuildParametricGamma(int nEntries, int Type, double Params[]); +LCMSAPI LPGAMMATABLE LCMSEXPORT cmsAllocGamma(int nEntries); +LCMSAPI void LCMSEXPORT cmsFreeGamma(LPGAMMATABLE Gamma); +LCMSAPI void LCMSEXPORT cmsFreeGammaTriple(LPGAMMATABLE Gamma[3]); +LCMSAPI LPGAMMATABLE LCMSEXPORT cmsDupGamma(LPGAMMATABLE Src); +LCMSAPI LPGAMMATABLE LCMSEXPORT cmsReverseGamma(int nResultSamples, LPGAMMATABLE InGamma); +LCMSAPI LPGAMMATABLE LCMSEXPORT cmsJoinGamma(LPGAMMATABLE InGamma, LPGAMMATABLE OutGamma); +LCMSAPI LPGAMMATABLE LCMSEXPORT cmsJoinGammaEx(LPGAMMATABLE InGamma, LPGAMMATABLE OutGamma, int nPoints); +LCMSAPI BOOL LCMSEXPORT cmsSmoothGamma(LPGAMMATABLE Tab, double lambda); +LCMSAPI double LCMSEXPORT cmsEstimateGamma(LPGAMMATABLE t); +LCMSAPI double LCMSEXPORT cmsEstimateGammaEx(LPWORD Table, int nEntries, double Thereshold); +LCMSAPI LPGAMMATABLE LCMSEXPORT cmsReadICCGamma(cmsHPROFILE hProfile, icTagSignature sig); +LCMSAPI LPGAMMATABLE LCMSEXPORT cmsReadICCGammaReversed(cmsHPROFILE hProfile, icTagSignature sig); + +// Access to Profile data. + +LCMSAPI BOOL LCMSEXPORT cmsTakeMediaWhitePoint(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile); +LCMSAPI BOOL LCMSEXPORT cmsTakeMediaBlackPoint(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile); +LCMSAPI BOOL LCMSEXPORT cmsTakeIluminant(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile); +LCMSAPI BOOL LCMSEXPORT cmsTakeColorants(LPcmsCIEXYZTRIPLE Dest, cmsHPROFILE hProfile); +LCMSAPI DWORD LCMSEXPORT cmsTakeHeaderFlags(cmsHPROFILE hProfile); +LCMSAPI DWORD LCMSEXPORT cmsTakeHeaderAttributes(cmsHPROFILE hProfile); + +LCMSAPI void LCMSEXPORT cmsSetLanguage(int LanguageCode, int CountryCode); +LCMSAPI const char* LCMSEXPORT cmsTakeProductName(cmsHPROFILE hProfile); +LCMSAPI const char* LCMSEXPORT cmsTakeProductDesc(cmsHPROFILE hProfile); +LCMSAPI const char* LCMSEXPORT cmsTakeProductInfo(cmsHPROFILE hProfile); +LCMSAPI const char* LCMSEXPORT cmsTakeManufacturer(cmsHPROFILE hProfile); +LCMSAPI const char* LCMSEXPORT cmsTakeModel(cmsHPROFILE hProfile); +LCMSAPI const char* LCMSEXPORT cmsTakeCopyright(cmsHPROFILE hProfile); +LCMSAPI const BYTE* LCMSEXPORT cmsTakeProfileID(cmsHPROFILE hProfile); + +LCMSAPI BOOL LCMSEXPORT cmsTakeCreationDateTime(struct tm *Dest, cmsHPROFILE hProfile); +LCMSAPI BOOL LCMSEXPORT cmsTakeCalibrationDateTime(struct tm *Dest, cmsHPROFILE hProfile); + +LCMSAPI BOOL LCMSEXPORT cmsIsTag(cmsHPROFILE hProfile, icTagSignature sig); +LCMSAPI int LCMSEXPORT cmsTakeRenderingIntent(cmsHPROFILE hProfile); + +LCMSAPI BOOL LCMSEXPORT cmsTakeCharTargetData(cmsHPROFILE hProfile, char** Data, size_t* len); + +LCMSAPI int LCMSEXPORT cmsReadICCTextEx(cmsHPROFILE hProfile, icTagSignature sig, char *Text, size_t size); +LCMSAPI int LCMSEXPORT cmsReadICCText(cmsHPROFILE hProfile, icTagSignature sig, char *Text); + + +#define LCMS_DESC_MAX 512 + +typedef struct { + + icSignature deviceMfg; + icSignature deviceModel; + icUInt32Number attributes[2]; + icTechnologySignature technology; + + char Manufacturer[LCMS_DESC_MAX]; + char Model[LCMS_DESC_MAX]; + + } cmsPSEQDESC, FAR *LPcmsPSEQDESC; + +typedef struct { + + int n; + cmsPSEQDESC seq[1]; + + } cmsSEQ, FAR *LPcmsSEQ; + + +LCMSAPI LPcmsSEQ LCMSEXPORT cmsReadProfileSequenceDescription(cmsHPROFILE hProfile); +LCMSAPI void LCMSEXPORT cmsFreeProfileSequenceDescription(LPcmsSEQ pseq); + + +// Extended gamut tag -- an HP extension + +#define LCMSGAMUTMETHOD_SEGMENTMAXIMA 0 +#define LCMSGAMUTMETHOD_CONVEXHULL 1 +#define LCMSGAMUTMETHOD_ALPHASHAPE 2 + + +#define LCMSGAMUT_PHYSICAL 0 +#define LCMSGAMUT_HP1 1 +#define LCMSGAMUT_HP2 2 + +typedef struct { + + icColorSpaceSignature CoordSig; // Gamut coordinates signature + icUInt16Number Method; // Method used to generate gamut + icUInt16Number Usage; // Gamut usage or intent + + char Description[LCMS_DESC_MAX]; // Textual description + + cmsViewingConditions Vc; // The viewing conditions + + icUInt32Number Count; // Number of entries + double Data[1]; // The current data + + } cmsGAMUTEX, FAR* LPcmsGAMUTEX; + + +LCMSAPI LPcmsGAMUTEX LCMSEXPORT cmsReadExtendedGamut(cmsHPROFILE hProfile, int index); +LCMSAPI void LCMSEXPORT cmsFreeExtendedGamut(LPcmsGAMUTEX gex); + + + + +// Translate form/to our notation to ICC +LCMSAPI icColorSpaceSignature LCMSEXPORT _cmsICCcolorSpace(int OurNotation); +LCMSAPI int LCMSEXPORT _cmsLCMScolorSpace(icColorSpaceSignature ProfileSpace); +LCMSAPI int LCMSEXPORT _cmsChannelsOf(icColorSpaceSignature ColorSpace); +LCMSAPI BOOL LCMSEXPORT _cmsIsMatrixShaper(cmsHPROFILE hProfile); + +#define LCMS_USED_AS_INPUT 0 +#define LCMS_USED_AS_OUTPUT 1 +#define LCMS_USED_AS_PROOF 2 + +LCMSAPI BOOL LCMSEXPORT cmsIsIntentSupported(cmsHPROFILE hProfile, int Intent, int UsedDirection); + +LCMSAPI icColorSpaceSignature LCMSEXPORT cmsGetPCS(cmsHPROFILE hProfile); +LCMSAPI icColorSpaceSignature LCMSEXPORT cmsGetColorSpace(cmsHPROFILE hProfile); +LCMSAPI icProfileClassSignature LCMSEXPORT cmsGetDeviceClass(cmsHPROFILE hProfile); +LCMSAPI DWORD LCMSEXPORT cmsGetProfileICCversion(cmsHPROFILE hProfile); +LCMSAPI void LCMSEXPORT cmsSetProfileICCversion(cmsHPROFILE hProfile, DWORD Version); +LCMSAPI icInt32Number LCMSEXPORT cmsGetTagCount(cmsHPROFILE hProfile); +LCMSAPI icTagSignature LCMSEXPORT cmsGetTagSignature(cmsHPROFILE hProfile, icInt32Number n); + + +LCMSAPI void LCMSEXPORT cmsSetDeviceClass(cmsHPROFILE hProfile, icProfileClassSignature sig); +LCMSAPI void LCMSEXPORT cmsSetColorSpace(cmsHPROFILE hProfile, icColorSpaceSignature sig); +LCMSAPI void LCMSEXPORT cmsSetPCS(cmsHPROFILE hProfile, icColorSpaceSignature pcs); +LCMSAPI void LCMSEXPORT cmsSetRenderingIntent(cmsHPROFILE hProfile, int RenderingIntent); +LCMSAPI void LCMSEXPORT cmsSetHeaderFlags(cmsHPROFILE hProfile, DWORD Flags); +LCMSAPI void LCMSEXPORT cmsSetHeaderAttributes(cmsHPROFILE hProfile, DWORD Flags); +LCMSAPI void LCMSEXPORT cmsSetProfileID(cmsHPROFILE hProfile, LPBYTE ProfileID); + +// Intents + +#define INTENT_PERCEPTUAL 0 +#define INTENT_RELATIVE_COLORIMETRIC 1 +#define INTENT_SATURATION 2 +#define INTENT_ABSOLUTE_COLORIMETRIC 3 + +// Flags + +#define cmsFLAGS_MATRIXINPUT 0x0001 +#define cmsFLAGS_MATRIXOUTPUT 0x0002 +#define cmsFLAGS_MATRIXONLY (cmsFLAGS_MATRIXINPUT|cmsFLAGS_MATRIXOUTPUT) + +#define cmsFLAGS_NOWHITEONWHITEFIXUP 0x0004 // Don't hot fix scum dot +#define cmsFLAGS_NOPRELINEARIZATION 0x0010 // Don't create prelinearization tables + // on precalculated transforms (internal use) + +#define cmsFLAGS_GUESSDEVICECLASS 0x0020 // Guess device class (for transform2devicelink) + +#define cmsFLAGS_NOTCACHE 0x0040 // Inhibit 1-pixel cache + +#define cmsFLAGS_NOTPRECALC 0x0100 +#define cmsFLAGS_NULLTRANSFORM 0x0200 // Don't transform anyway +#define cmsFLAGS_HIGHRESPRECALC 0x0400 // Use more memory to give better accurancy +#define cmsFLAGS_LOWRESPRECALC 0x0800 // Use less memory to minimize resouces + + +#define cmsFLAGS_WHITEBLACKCOMPENSATION 0x2000 +#define cmsFLAGS_BLACKPOINTCOMPENSATION cmsFLAGS_WHITEBLACKCOMPENSATION + +// Proofing flags + +#define cmsFLAGS_GAMUTCHECK 0x1000 // Out of Gamut alarm +#define cmsFLAGS_SOFTPROOFING 0x4000 // Do softproofing + +// Black preservation + +#define cmsFLAGS_PRESERVEBLACK 0x8000 + +// CRD special + +#define cmsFLAGS_NODEFAULTRESOURCEDEF 0x00010000 + +// Gridpoints + +#define cmsFLAGS_GRIDPOINTS(n) (((n) & 0xFF) << 16) + + +// Transforms + +LCMSAPI cmsHTRANSFORM LCMSEXPORT cmsCreateTransform(cmsHPROFILE Input, + DWORD InputFormat, + cmsHPROFILE Output, + DWORD OutputFormat, + int Intent, + DWORD dwFlags); + +LCMSAPI cmsHTRANSFORM LCMSEXPORT cmsCreateProofingTransform(cmsHPROFILE Input, + DWORD InputFormat, + cmsHPROFILE Output, + DWORD OutputFormat, + cmsHPROFILE Proofing, + int Intent, + int ProofingIntent, + DWORD dwFlags); + +LCMSAPI cmsHTRANSFORM LCMSEXPORT cmsCreateMultiprofileTransform(cmsHPROFILE hProfiles[], + int nProfiles, + DWORD InputFormat, + DWORD OutputFormat, + int Intent, + DWORD dwFlags); + +LCMSAPI void LCMSEXPORT cmsDeleteTransform(cmsHTRANSFORM hTransform); + +LCMSAPI void LCMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform, + LPVOID InputBuffer, + LPVOID OutputBuffer, + unsigned int Size); + +LCMSAPI void LCMSEXPORT cmsChangeBuffersFormat(cmsHTRANSFORM hTransform, DWORD InputFormat, DWORD dwOutputFormat); + +LCMSAPI void LCMSEXPORT cmsSetAlarmCodes(int r, int g, int b); +LCMSAPI void LCMSEXPORT cmsGetAlarmCodes(int *r, int *g, int *b); + + +// Adaptation state for absolute colorimetric intent + +LCMSAPI double LCMSEXPORT cmsSetAdaptationState(double d); + + +// Primary preservation strategy + +#define LCMS_PRESERVE_PURE_K 0 +#define LCMS_PRESERVE_K_PLANE 1 + +LCMSAPI int LCMSEXPORT cmsSetCMYKPreservationStrategy(int n); + +// Named color support +typedef struct { + char Name[MAX_PATH]; + WORD PCS[3]; + WORD DeviceColorant[MAXCHANNELS]; + + + } cmsNAMEDCOLOR, FAR* LPcmsNAMEDCOLOR; + +typedef struct { + int nColors; + int Allocated; + int ColorantCount; + char Prefix[33]; + char Suffix[33]; + + cmsNAMEDCOLOR List[1]; + + } cmsNAMEDCOLORLIST, FAR* LPcmsNAMEDCOLORLIST; + +// Named color support + +LCMSAPI int LCMSEXPORT cmsNamedColorCount(cmsHTRANSFORM xform); +LCMSAPI BOOL LCMSEXPORT cmsNamedColorInfo(cmsHTRANSFORM xform, int nColor, char* Name, char* Prefix, char* Suffix); +LCMSAPI int LCMSEXPORT cmsNamedColorIndex(cmsHTRANSFORM xform, const char* Name); + +// Colorant tables + +LCMSAPI LPcmsNAMEDCOLORLIST LCMSEXPORT cmsReadColorantTable(cmsHPROFILE hProfile, icTagSignature sig); + +// Profile creation + +LCMSAPI BOOL LCMSEXPORT cmsAddTag(cmsHPROFILE hProfile, icTagSignature sig, const void* data); + +// Converts a transform to a devicelink profile +LCMSAPI cmsHPROFILE LCMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, DWORD dwFlags); + +// Set the 'save as 8-bit' flag +LCMSAPI void LCMSEXPORT _cmsSetLUTdepth(cmsHPROFILE hProfile, int depth); + + +// Save profile +LCMSAPI BOOL LCMSEXPORT _cmsSaveProfile(cmsHPROFILE hProfile, const char* FileName); +LCMSAPI BOOL LCMSEXPORT _cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr, + size_t* BytesNeeded); + + + +// PostScript ColorRenderingDictionary and ColorSpaceArray + +LCMSAPI DWORD LCMSEXPORT cmsGetPostScriptCSA(cmsHPROFILE hProfile, int Intent, LPVOID Buffer, DWORD dwBufferLen); +LCMSAPI DWORD LCMSEXPORT cmsGetPostScriptCRD(cmsHPROFILE hProfile, int Intent, LPVOID Buffer, DWORD dwBufferLen); +LCMSAPI DWORD LCMSEXPORT cmsGetPostScriptCRDEx(cmsHPROFILE hProfile, int Intent, DWORD dwFlags, LPVOID Buffer, DWORD dwBufferLen); + + +// Error handling + +#define LCMS_ERROR_ABORT 0 +#define LCMS_ERROR_SHOW 1 +#define LCMS_ERROR_IGNORE 2 + +LCMSAPI int LCMSEXPORT cmsErrorAction(int nAction); + +#define LCMS_ERRC_WARNING 0x1000 +#define LCMS_ERRC_RECOVERABLE 0x2000 +#define LCMS_ERRC_ABORTED 0x3000 + +typedef int (* cmsErrorHandlerFunction)(int ErrorCode, const char *ErrorText); + +LCMSAPI void LCMSEXPORT cmsSetErrorHandler(cmsErrorHandlerFunction Fn); + + +// LUT manipulation + + +typedef struct _lcms_LUT_struc LUT, FAR* LPLUT; // opaque pointer + +LCMSAPI LPLUT LCMSEXPORT cmsAllocLUT(void); +LCMSAPI LPLUT LCMSEXPORT cmsAllocLinearTable(LPLUT NewLUT, LPGAMMATABLE Tables[], int nTable); +LCMSAPI LPLUT LCMSEXPORT cmsAlloc3DGrid(LPLUT Lut, int clutPoints, int inputChan, int outputChan); +LCMSAPI LPLUT LCMSEXPORT cmsSetMatrixLUT(LPLUT Lut, LPMAT3 M); +LCMSAPI LPLUT LCMSEXPORT cmsSetMatrixLUT4(LPLUT Lut, LPMAT3 M, LPVEC3 off, DWORD dwFlags); +LCMSAPI void LCMSEXPORT cmsFreeLUT(LPLUT Lut); +LCMSAPI void LCMSEXPORT cmsEvalLUT(LPLUT Lut, WORD In[], WORD Out[]); +LCMSAPI double LCMSEXPORT cmsEvalLUTreverse(LPLUT Lut, WORD Target[], WORD Result[], LPWORD Hint); +LCMSAPI LPLUT LCMSEXPORT cmsReadICCLut(cmsHPROFILE hProfile, icTagSignature sig); +LCMSAPI LPLUT LCMSEXPORT cmsDupLUT(LPLUT Orig); + +// LUT Sampling + +typedef int (* _cmsSAMPLER)(register WORD In[], + register WORD Out[], + register LPVOID Cargo); + +#define SAMPLER_HASTL1 LUT_HASTL1 +#define SAMPLER_HASTL2 LUT_HASTL2 +#define SAMPLER_INSPECT 0x01000000 + +LCMSAPI int LCMSEXPORT cmsSample3DGrid(LPLUT Lut, _cmsSAMPLER Sampler, LPVOID Cargo, DWORD dwFlags); + +// Formatters + +typedef unsigned char* (* cmsFORMATTER)(register void* CMMcargo, + register WORD ToUnroll[], + register LPBYTE Buffer); + +LCMSAPI void LCMSEXPORT cmsSetUserFormatters(cmsHTRANSFORM hTransform, DWORD dwInput, cmsFORMATTER Input, + DWORD dwOutput, cmsFORMATTER Output); + +LCMSAPI void LCMSEXPORT cmsGetUserFormatters(cmsHTRANSFORM hTransform, + LPDWORD InputFormat, cmsFORMATTER* Input, + LPDWORD OutputFormat, cmsFORMATTER* Output); + + +// IT8.7 / CGATS.17-200x handling + +LCMSAPI LCMSHANDLE LCMSEXPORT cmsIT8Alloc(void); +LCMSAPI void LCMSEXPORT cmsIT8Free(LCMSHANDLE IT8); + +// Tables + +LCMSAPI int LCMSEXPORT cmsIT8TableCount(LCMSHANDLE IT8); +LCMSAPI int LCMSEXPORT cmsIT8SetTable(LCMSHANDLE IT8, int nTable); + +// Persistence +LCMSAPI LCMSHANDLE LCMSEXPORT cmsIT8LoadFromFile(const char* cFileName); +LCMSAPI LCMSHANDLE LCMSEXPORT cmsIT8LoadFromMem(void *Ptr, size_t len); +LCMSAPI BOOL LCMSEXPORT cmsIT8SaveToFile(LCMSHANDLE IT8, const char* cFileName); +LCMSAPI BOOL LCMSEXPORT cmsIT8SaveToMem(LCMSHANDLE hIT8, void *MemPtr, size_t* BytesNeeded); + +// Properties +LCMSAPI const char* LCMSEXPORT cmsIT8GetSheetType(LCMSHANDLE hIT8); +LCMSAPI BOOL LCMSEXPORT cmsIT8SetSheetType(LCMSHANDLE hIT8, const char* Type); + +LCMSAPI BOOL LCMSEXPORT cmsIT8SetComment(LCMSHANDLE hIT8, const char* cComment); + +LCMSAPI BOOL LCMSEXPORT cmsIT8SetPropertyStr(LCMSHANDLE hIT8, const char* cProp, const char *Str); +LCMSAPI BOOL LCMSEXPORT cmsIT8SetPropertyDbl(LCMSHANDLE hIT8, const char* cProp, double Val); +LCMSAPI BOOL LCMSEXPORT cmsIT8SetPropertyHex(LCMSHANDLE hIT8, const char* cProp, int Val); + +LCMSAPI BOOL LCMSEXPORT cmsIT8SetPropertyUncooked(LCMSHANDLE hIT8, const char* Key, const char* Buffer); + + +LCMSAPI const char* LCMSEXPORT cmsIT8GetProperty(LCMSHANDLE hIT8, const char* cProp); +LCMSAPI double LCMSEXPORT cmsIT8GetPropertyDbl(LCMSHANDLE hIT8, const char* cProp); +LCMSAPI int LCMSEXPORT cmsIT8EnumProperties(LCMSHANDLE IT8, char ***PropertyNames); + +// Datasets + +LCMSAPI const char* LCMSEXPORT cmsIT8GetDataRowCol(LCMSHANDLE IT8, int row, int col); +LCMSAPI double LCMSEXPORT cmsIT8GetDataRowColDbl(LCMSHANDLE IT8, int row, int col); + +LCMSAPI BOOL LCMSEXPORT cmsIT8SetDataRowCol(LCMSHANDLE hIT8, int row, int col, + const char* Val); + +LCMSAPI BOOL LCMSEXPORT cmsIT8SetDataRowColDbl(LCMSHANDLE hIT8, int row, int col, + double Val); + +LCMSAPI const char* LCMSEXPORT cmsIT8GetData(LCMSHANDLE IT8, const char* cPatch, const char* cSample); + + +LCMSAPI double LCMSEXPORT cmsIT8GetDataDbl(LCMSHANDLE IT8, const char* cPatch, const char* cSample); + +LCMSAPI BOOL LCMSEXPORT cmsIT8SetData(LCMSHANDLE IT8, const char* cPatch, + const char* cSample, + const char *Val); + +LCMSAPI BOOL LCMSEXPORT cmsIT8SetDataDbl(LCMSHANDLE hIT8, const char* cPatch, + const char* cSample, + double Val); + +LCMSAPI int LCMSEXPORT cmsIT8GetDataFormat(LCMSHANDLE hIT8, const char* cSample); +LCMSAPI BOOL LCMSEXPORT cmsIT8SetDataFormat(LCMSHANDLE IT8, int n, const char *Sample); +LCMSAPI int LCMSEXPORT cmsIT8EnumDataFormat(LCMSHANDLE IT8, char ***SampleNames); + + +LCMSAPI const char* LCMSEXPORT cmsIT8GetPatchName(LCMSHANDLE hIT8, int nPatch, char* buffer); + +// The LABEL extension + +LCMSAPI int LCMSEXPORT cmsIT8SetTableByLabel(LCMSHANDLE hIT8, const char* cSet, const char* cField, const char* ExpectedType); + +// Formatter for double +LCMSAPI void LCMSEXPORT cmsIT8DefineDblFormat(LCMSHANDLE IT8, const char* Formatter); + + +// *************************************************************************** +// End of Little cms API From here functions are private +// You can use them only if using static libraries, and at your own risk of +// be stripped or changed at futures releases. + +#ifndef LCMS_APIONLY + + +// Compatibility with anterior versions-- not needed anymore +// -- Morge + +LCMSAPI void LCMSEXPORT cmsLabEncoded2Float(LPcmsCIELab Lab, const WORD wLab[3]); +LCMSAPI void LCMSEXPORT cmsLabEncoded2Float4(LPcmsCIELab Lab, const WORD wLab[3]); +LCMSAPI void LCMSEXPORT cmsFloat2LabEncoded(WORD wLab[3], const cmsCIELab* Lab); +LCMSAPI void LCMSEXPORT cmsFloat2LabEncoded4(WORD wLab[3], const cmsCIELab* Lab); +LCMSAPI void LCMSEXPORT cmsXYZEncoded2Float(LPcmsCIEXYZ fxyz, const WORD XYZ[3]); +LCMSAPI void LCMSEXPORT cmsFloat2XYZEncoded(WORD XYZ[3], const cmsCIEXYZ* fXYZ); + + +// Profiling Extensions --- Would be removed from API in future revisions + +LCMSAPI BOOL LCMSEXPORT _cmsAddTextTag(cmsHPROFILE hProfile, icTagSignature sig, const char* Text); +LCMSAPI BOOL LCMSEXPORT _cmsAddXYZTag(cmsHPROFILE hProfile, icTagSignature sig, const cmsCIEXYZ* XYZ); +LCMSAPI BOOL LCMSEXPORT _cmsAddLUTTag(cmsHPROFILE hProfile, icTagSignature sig, const void* lut); +LCMSAPI BOOL LCMSEXPORT _cmsAddGammaTag(cmsHPROFILE hProfile, icTagSignature sig, LPGAMMATABLE TransferFunction); +LCMSAPI BOOL LCMSEXPORT _cmsAddChromaticityTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsCIExyYTRIPLE Chrm); +LCMSAPI BOOL LCMSEXPORT _cmsAddSequenceDescriptionTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsSEQ PSeq); +LCMSAPI BOOL LCMSEXPORT _cmsAddNamedColorTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsNAMEDCOLORLIST nc); +LCMSAPI BOOL LCMSEXPORT _cmsAddDateTimeTag(cmsHPROFILE hProfile, icTagSignature sig, struct tm *DateTime); +LCMSAPI BOOL LCMSEXPORT _cmsAddColorantTableTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsNAMEDCOLORLIST nc); + +// --------------------------------------------------------------------------------------------------- Inline functions + +// Fast floor conversion logic. Thanks to Sree Kotay and Stuart Nixon +// note than this only works in the range ..-32767...+32767 because +// mantissa is interpreted as 15.16 fixed point. +// The union is to avoid pointer aliasing overoptimization. + +LCMS_INLINE int _cmsQuickFloor(double val) +{ +#ifdef USE_DEFAULT_FLOOR_CONVERSION + return (int) floor(val); +#else + const double _lcms_double2fixmagic = 68719476736.0 * 1.5; // 2^36 * 1.5, (52-16=36) uses limited precision to floor + union { + double val; + int halves[2]; + } temp; + + temp.val = val + _lcms_double2fixmagic; + + +#ifdef USE_BIG_ENDIAN + return temp.halves[1] >> 16; +#else + return temp.halves[0] >> 16; +#endif +#endif +} + + + +// Clamp with saturation + +LCMS_INLINE WORD _cmsClampWord(int in) +{ + if (in < 0) return 0; + if (in > 0xFFFF) return 0xFFFFU; // Including marker + return (WORD) in; +} + +// ------------------------------------------------------------------------------------------- end of inline functions + +// Signal error from inside lcms code + +void cdecl cmsSignalError(int ErrorCode, const char *ErrorText, ...); + +// Alignment handling (needed in ReadLUT16 and ReadLUT8) + +typedef struct { + icS15Fixed16Number a; + icUInt16Number b; + + } _cmsTestAlign16; + +#define SIZEOF_UINT16_ALIGNED (sizeof(_cmsTestAlign16) - sizeof(icS15Fixed16Number)) + +typedef struct { + icS15Fixed16Number a; + icUInt8Number b; + + } _cmsTestAlign8; + +#define SIZEOF_UINT8_ALIGNED (sizeof(_cmsTestAlign8) - sizeof(icS15Fixed16Number)) + + +// Fixed point + + +typedef icInt32Number Fixed32; // Fixed 15.16 whith sign + +#define INT_TO_FIXED(x) ((x)<<16) +#define DOUBLE_TO_FIXED(x) ((Fixed32) ((x)*65536.0+0.5)) +#define FIXED_TO_INT(x) ((x)>>16) +#define FIXED_REST_TO_INT(x) ((x)& 0xFFFFU) +#define FIXED_TO_DOUBLE(x) (((double)x)/65536.0) +#define ROUND_FIXED_TO_INT(x) (((x)+0x8000)>>16) + + +Fixed32 cdecl FixedMul(Fixed32 a, Fixed32 b); +Fixed32 cdecl FixedSquare(Fixed32 a); + + +#ifdef USE_INLINE + +LCMS_INLINE Fixed32 ToFixedDomain(int a) { return a + ((a + 0x7fff) / 0xffff); } +LCMS_INLINE int FromFixedDomain(Fixed32 a) { return a - ((a + 0x7fff) >> 16); } + +#else + +Fixed32 cdecl ToFixedDomain(int a); // (a * 65536.0 / 65535.0) +int cdecl FromFixedDomain(Fixed32 a); // (a * 65535.0 + .5) + +#endif + +Fixed32 cdecl FixedLERP(Fixed32 a, Fixed32 l, Fixed32 h); +WORD cdecl FixedScale(WORD a, Fixed32 s); + +// Vector & Matrix operations. I'm using the notation frequently found in +// literature. Mostly 'Graphic Gems' samples. Not to be same routines. + +// Vector members + +#define VX 0 +#define VY 1 +#define VZ 2 + +typedef struct { // Fixed 15.16 bits vector + Fixed32 n[3]; + } WVEC3, FAR* LPWVEC3; + +typedef struct { // Matrix (Fixed 15.16) + WVEC3 v[3]; + } WMAT3, FAR* LPWMAT3; + + + +void cdecl VEC3init(LPVEC3 r, double x, double y, double z); // double version +void cdecl VEC3initF(LPWVEC3 r, double x, double y, double z); // Fix32 version +void cdecl VEC3toFix(LPWVEC3 r, LPVEC3 v); +void cdecl VEC3fromFix(LPVEC3 r, LPWVEC3 v); +void cdecl VEC3scaleFix(LPWORD r, LPWVEC3 Scale); +void cdecl VEC3swap(LPVEC3 a, LPVEC3 b); +void cdecl VEC3divK(LPVEC3 r, LPVEC3 v, double d); +void cdecl VEC3perK(LPVEC3 r, LPVEC3 v, double d); +void cdecl VEC3minus(LPVEC3 r, LPVEC3 a, LPVEC3 b); +void cdecl VEC3perComp(LPVEC3 r, LPVEC3 a, LPVEC3 b); +BOOL cdecl VEC3equal(LPWVEC3 a, LPWVEC3 b, double Tolerance); +BOOL cdecl VEC3equalF(LPVEC3 a, LPVEC3 b, double Tolerance); +void cdecl VEC3scaleAndCut(LPWVEC3 r, LPVEC3 v, double d); +void cdecl VEC3cross(LPVEC3 r, LPVEC3 u, LPVEC3 v); +void cdecl VEC3saturate(LPVEC3 v); +double cdecl VEC3distance(LPVEC3 a, LPVEC3 b); +double cdecl VEC3length(LPVEC3 a); + +void cdecl MAT3identity(LPMAT3 a); +void cdecl MAT3per(LPMAT3 r, LPMAT3 a, LPMAT3 b); +void cdecl MAT3perK(LPMAT3 r, LPMAT3 v, double d); +int cdecl MAT3inverse(LPMAT3 a, LPMAT3 b); +BOOL cdecl MAT3solve(LPVEC3 x, LPMAT3 a, LPVEC3 b); +double cdecl MAT3det(LPMAT3 m); +void cdecl MAT3eval(LPVEC3 r, LPMAT3 a, LPVEC3 v); +void cdecl MAT3toFix(LPWMAT3 r, LPMAT3 v); +void cdecl MAT3fromFix(LPMAT3 r, LPWMAT3 v); +void cdecl MAT3evalW(LPWVEC3 r, LPWMAT3 a, LPWVEC3 v); +BOOL cdecl MAT3isIdentity(LPWMAT3 a, double Tolerance); +void cdecl MAT3scaleAndCut(LPWMAT3 r, LPMAT3 v, double d); + +// Is a table linear? + +int cdecl cmsIsLinear(WORD Table[], int nEntries); + +// I hold this structures describing domain +// details mainly for optimization purposes. + +struct _lcms_l16params_struc; + +typedef void (* _cms3DLERP)(WORD Input[], + WORD Output[], + WORD LutTable[], + struct _lcms_l16params_struc* p); + + + +typedef struct _lcms_l8opt_struc { // Used on 8 bit interpolations + + unsigned int X0[256], Y0[256], Z0[256]; + WORD rx[256], ry[256], rz[256]; + + } L8PARAMS, FAR* LPL8PARAMS; + +typedef struct _lcms_l16params_struc { // Used on 16 bits interpolations + + int nSamples; // Valid on all kinds of tables + int nInputs; // != 1 only in 3D interpolation + int nOutputs; // != 1 only in 3D interpolation + + WORD Domain; + + int opta1, opta2; + int opta3, opta4; // Optimization for 3D LUT + int opta5, opta6; + int opta7, opta8; + + _cms3DLERP Interp3D; // The interpolation routine + + LPL8PARAMS p8; // Points to some tables for 8-bit speedup + + } L16PARAMS, *LPL16PARAMS; + + +void cdecl cmsCalcL16Params(int nSamples, LPL16PARAMS p); +void cdecl cmsCalcCLUT16Params(int nSamples, int InputChan, int OutputChan, LPL16PARAMS p); +void cdecl cmsCalcCLUT16ParamsEx(int nSamples, int InputChan, int OutputChan, + BOOL lUseTetrahedral, LPL16PARAMS p); + +WORD cdecl cmsLinearInterpLUT16(WORD Value, WORD LutTable[], LPL16PARAMS p); +Fixed32 cdecl cmsLinearInterpFixed(WORD Value1, WORD LutTable[], LPL16PARAMS p); +WORD cdecl cmsReverseLinearInterpLUT16(WORD Value, WORD LutTable[], LPL16PARAMS p); + +void cdecl cmsTrilinearInterp16(WORD Input[], + WORD Output[], + WORD LutTable[], + LPL16PARAMS p); + +void cdecl cmsTetrahedralInterp16(WORD Input[], + WORD Output[], + WORD LutTable[], LPL16PARAMS p); + +void cdecl cmsTetrahedralInterp8(WORD Input[], + WORD Output[], + WORD LutTable[], LPL16PARAMS p); + +// LUT handling + +#define LUT_HASMATRIX 0x0001 // Do-op Flags +#define LUT_HASTL1 0x0002 +#define LUT_HASTL2 0x0008 +#define LUT_HAS3DGRID 0x0010 + +// New in rev 4.0 of ICC spec + +#define LUT_HASMATRIX3 0x0020 // Matrix + offset for LutAToB +#define LUT_HASMATRIX4 0x0040 // Matrix + offset for LutBToA + +#define LUT_HASTL3 0x0100 // '3' curves for LutAToB +#define LUT_HASTL4 0x0200 // '4' curves for LutBToA + +// V4 emulation + +#define LUT_V4_OUTPUT_EMULATE_V2 0x10000 // Is a V4 output LUT, emulating V2 +#define LUT_V4_INPUT_EMULATE_V2 0x20000 // Is a V4 input LUT, emulating V2 +#define LUT_V2_OUTPUT_EMULATE_V4 0x40000 // Is a V2 output LUT, emulating V4 +#define LUT_V2_INPUT_EMULATE_V4 0x80000 // Is a V2 input LUT, emulating V4 + + +struct _lcms_LUT_struc { + + DWORD wFlags; + WMAT3 Matrix; // 15fixed16 matrix + + unsigned int InputChan; + unsigned int OutputChan; + unsigned int InputEntries; + unsigned int OutputEntries; + unsigned int cLutPoints; + + + LPWORD L1[MAXCHANNELS]; // First linearization + LPWORD L2[MAXCHANNELS]; // Last linearization + + LPWORD T; // 3D CLUT + unsigned int Tsize; // CLUT size in bytes + + // Parameters & Optimizations + + L16PARAMS In16params; + L16PARAMS Out16params; + L16PARAMS CLut16params; + + int Intent; // Accomplished intent + + // New for Rev 4.0 of spec (reserved) + + WMAT3 Mat3; + WVEC3 Ofs3; + LPWORD L3[MAXCHANNELS]; + L16PARAMS L3params; + unsigned int L3Entries; + + WMAT3 Mat4; + WVEC3 Ofs4; + LPWORD L4[MAXCHANNELS]; + L16PARAMS L4params; + unsigned int L4Entries; + + // Gray axes fixup. Only on v2 8-bit Lab LUT + + BOOL FixGrayAxes; + + + // Parameters used for curve creation + + LCMSGAMMAPARAMS LCurvesSeed[4][MAXCHANNELS]; + + + }; // LUT, FAR* LPLUT; + + +BOOL cdecl _cmsSmoothEndpoints(LPWORD Table, int nEntries); + + +// CRC of gamma tables + +unsigned int _cmsCrc32OfGammaTable(LPGAMMATABLE Table); + +// Sampled curves + +LPSAMPLEDCURVE cdecl cmsAllocSampledCurve(int nItems); +void cdecl cmsFreeSampledCurve(LPSAMPLEDCURVE p); +LPSAMPLEDCURVE cdecl cmsDupSampledCurve(LPSAMPLEDCURVE p); + +LPSAMPLEDCURVE cdecl cmsConvertGammaToSampledCurve(LPGAMMATABLE Gamma, int nPoints); +LPGAMMATABLE cdecl cmsConvertSampledCurveToGamma(LPSAMPLEDCURVE Sampled, double Max); + +void cdecl cmsEndpointsOfSampledCurve(LPSAMPLEDCURVE p, double* Min, double* Max); +void cdecl cmsClampSampledCurve(LPSAMPLEDCURVE p, double Min, double Max); +BOOL cdecl cmsSmoothSampledCurve(LPSAMPLEDCURVE Tab, double SmoothingLambda); +void cdecl cmsRescaleSampledCurve(LPSAMPLEDCURVE p, double Min, double Max, int nPoints); + +LPSAMPLEDCURVE cdecl cmsJoinSampledCurves(LPSAMPLEDCURVE X, LPSAMPLEDCURVE Y, int nResultingPoints); + +// Shaper/Matrix handling + +#define MATSHAPER_HASMATRIX 0x0001 // Do-ops flags +#define MATSHAPER_HASSHAPER 0x0002 +#define MATSHAPER_INPUT 0x0004 // Behaviour +#define MATSHAPER_OUTPUT 0x0008 +#define MATSHAPER_HASINPSHAPER 0x0010 +#define MATSHAPER_ALLSMELTED (MATSHAPER_INPUT|MATSHAPER_OUTPUT) + + +typedef struct { + DWORD dwFlags; + + WMAT3 Matrix; + + L16PARAMS p16; // Primary curve + LPWORD L[3]; + + L16PARAMS p2_16; // Secondary curve (used as input in smelted ones) + LPWORD L2[3]; + + } MATSHAPER, FAR* LPMATSHAPER; + +LPMATSHAPER cdecl cmsAllocMatShaper(LPMAT3 matrix, LPGAMMATABLE Shaper[], DWORD Behaviour); +LPMATSHAPER cdecl cmsAllocMatShaper2(LPMAT3 matrix, LPGAMMATABLE In[], LPGAMMATABLE Out[], DWORD Behaviour); + +void cdecl cmsFreeMatShaper(LPMATSHAPER MatShaper); +void cdecl cmsEvalMatShaper(LPMATSHAPER MatShaper, WORD In[], WORD Out[]); + +BOOL cdecl cmsReadICCMatrixRGB2XYZ(LPMAT3 r, cmsHPROFILE hProfile); + +LPMATSHAPER cdecl cmsBuildInputMatrixShaper(cmsHPROFILE InputProfile); +LPMATSHAPER cdecl cmsBuildOutputMatrixShaper(cmsHPROFILE OutputProfile); + + + +// White Point & Primary chromas handling +BOOL cdecl cmsAdaptationMatrix(LPMAT3 r, LPMAT3 ConeMatrix, LPcmsCIEXYZ FromIll, LPcmsCIEXYZ ToIll); +BOOL cdecl cmsAdaptMatrixToD50(LPMAT3 r, LPcmsCIExyY SourceWhitePt); +BOOL cdecl cmsAdaptMatrixFromD50(LPMAT3 r, LPcmsCIExyY DestWhitePt); + +BOOL cdecl cmsReadChromaticAdaptationMatrix(LPMAT3 r, cmsHPROFILE hProfile); + +// Inter-PCS conversion routines. They assume D50 as white point. +void cdecl cmsXYZ2LabEncoded(WORD XYZ[3], WORD Lab[3]); +void cdecl cmsLab2XYZEncoded(WORD Lab[3], WORD XYZ[3]); + +// Retrieve text representation of WP +void cdecl _cmsIdentifyWhitePoint(char *Buffer, LPcmsCIEXYZ WhitePt); + +// Quantize to WORD in a (MaxSamples - 1) domain +WORD cdecl _cmsQuantizeVal(double i, int MaxSamples); + +LPcmsNAMEDCOLORLIST cdecl cmsAllocNamedColorList(int n); +int cdecl cmsReadICCnamedColorList(cmsHTRANSFORM xform, cmsHPROFILE hProfile, icTagSignature sig); +void cdecl cmsFreeNamedColorList(LPcmsNAMEDCOLORLIST List); +BOOL cdecl cmsAppendNamedColor(cmsHTRANSFORM xform, const char* Name, WORD PCS[3], WORD Colorant[MAXCHANNELS]); + + +// I/O + +#define MAX_TABLE_TAG 100 + +// This is the internal struct holding profile details. + +typedef struct _lcms_iccprofile_struct { + + void* stream; // Associated stream. If NULL, + // tags are supposed to be in + // memory rather than in a file. + + // Only most important items found in ICC profile + + icProfileClassSignature DeviceClass; + icColorSpaceSignature ColorSpace; + icColorSpaceSignature PCS; + icRenderingIntent RenderingIntent; + icUInt32Number flags; + icUInt32Number attributes; + cmsCIEXYZ Illuminant; + + // Additions for V4 profiles + + icUInt32Number Version; + MAT3 ChromaticAdaptation; + cmsCIEXYZ MediaWhitePoint; + cmsCIEXYZ MediaBlackPoint; + BYTE ProfileID[16]; + + + // Dictionary + + icInt32Number TagCount; + icTagSignature TagNames[MAX_TABLE_TAG]; + size_t TagSizes[MAX_TABLE_TAG]; + size_t TagOffsets[MAX_TABLE_TAG]; + LPVOID TagPtrs[MAX_TABLE_TAG]; + + char PhysicalFile[MAX_PATH]; + + BOOL IsWrite; + BOOL SaveAs8Bits; + + struct tm Created; + + // I/O handlers + + size_t (* Read)(void *buffer, size_t size, size_t count, struct _lcms_iccprofile_struct* Icc); + + BOOL (* Seek)(struct _lcms_iccprofile_struct* Icc, size_t offset); + BOOL (* Close)(struct _lcms_iccprofile_struct* Icc); + size_t (* Tell)(struct _lcms_iccprofile_struct* Icc); + + // Writting + + BOOL (* Write)(struct _lcms_iccprofile_struct* Icc, size_t size, LPVOID Ptr); + + size_t UsedSpace; + + + } LCMSICCPROFILE, FAR* LPLCMSICCPROFILE; + + +// Create an empty template for virtual profiles +cmsHPROFILE cdecl _cmsCreateProfilePlaceholder(void); + +// Search into tag dictionary +icInt32Number cdecl _cmsSearchTag(LPLCMSICCPROFILE Profile, icTagSignature sig, BOOL lSignalError); + +// Search for a particular tag, replace if found or add new one else +LPVOID _cmsInitTag(LPLCMSICCPROFILE Icc, icTagSignature sig, size_t size, const void* Init); + + +LPLCMSICCPROFILE cdecl _cmsCreateProfileFromFilePlaceholder(const char* FileName); +LPLCMSICCPROFILE cdecl _cmsCreateProfileFromMemPlaceholder(LPVOID MemPtr, DWORD dwSize); + +void _cmsSetSaveToDisk(LPLCMSICCPROFILE Icc, const char* FileName); +void _cmsSetSaveToMemory(LPLCMSICCPROFILE Icc, LPVOID MemPtr, size_t dwSize); + + + +// These macros unpack format specifiers into integers + +#define T_COLORSPACE(s) (((s)>>16)&31) +#define T_SWAPFIRST(s) (((s)>>14)&1) +#define T_FLAVOR(s) (((s)>>13)&1) +#define T_PLANAR(p) (((p)>>12)&1) +#define T_ENDIAN16(e) (((e)>>11)&1) +#define T_DOSWAP(e) (((e)>>10)&1) +#define T_EXTRA(e) (((e)>>7)&7) +#define T_CHANNELS(c) (((c)>>3)&15) +#define T_BYTES(b) ((b)&7) + + + +// Internal XFORM struct +struct _cmstransform_struct; + +// Full xform +typedef void (* _cmsCOLORCALLBACKFN)(struct _cmstransform_struct *Transform, + LPVOID InputBuffer, + LPVOID OutputBuffer, unsigned int Size); + +// intermediate pass, from WORD[] to WORD[] + +typedef void (* _cmsADJFN)(WORD In[], WORD Out[], LPWMAT3 m, LPWVEC3 b); + +typedef void (* _cmsTRANSFN)(struct _cmstransform_struct *Transform, + WORD In[], WORD Out[]); + +typedef void (* _cmsCNVRT)(WORD In[], WORD Out[]); + +typedef LPBYTE (* _cmsFIXFN)(register struct _cmstransform_struct *info, + register WORD ToUnroll[], + register LPBYTE Buffer); + + + +// Transformation +typedef struct _cmstransform_struct { + + // Keep formats for further reference + DWORD InputFormat, OutputFormat; + + DWORD StrideIn, StrideOut; // Planar support + + int Intent, ProofIntent; + int DoGamutCheck; + + + cmsHPROFILE InputProfile; + cmsHPROFILE OutputProfile; + cmsHPROFILE PreviewProfile; + + icColorSpaceSignature EntryColorSpace; + icColorSpaceSignature ExitColorSpace; + + DWORD dwOriginalFlags; // Flags as specified by user + + WMAT3 m1, m2; // Matrix holding inter PCS operation + WVEC3 of1, of2; // Offset terms + + _cmsCOLORCALLBACKFN xform; + + // Steps in xFORM + + _cmsFIXFN FromInput; + _cmsTRANSFN FromDevice; + _cmsADJFN Stage1; + _cmsADJFN Stage2; + _cmsTRANSFN ToDevice; + _cmsFIXFN ToOutput; + + // LUTs + + LPLUT Device2PCS; + LPLUT PCS2Device; + LPLUT Gamut; // Gamut check + LPLUT Preview; // Preview (Proof) + + LPLUT DeviceLink; // Precalculated grid - device link profile + LPLUT GamutCheck; // Precalculated device -> gamut check + + // Matrix/Shapers + + LPMATSHAPER InMatShaper; + LPMATSHAPER OutMatShaper; + LPMATSHAPER SmeltMatShaper; + + // Phase of Lab/XYZ, Abs/Rel + + int Phase1, Phase2, Phase3; + + // Named color table + + LPcmsNAMEDCOLORLIST NamedColorList; + + // Flag for transform involving v4 profiles + + BOOL lInputV4Lab, lOutputV4Lab; + + + // 1-pixel cache + + WORD CacheIn[MAXCHANNELS]; + WORD CacheOut[MAXCHANNELS]; + + double AdaptationState; // Figure for v4 incomplete state of adaptation + + LCMS_RWLOCK_T rwlock; + + } _cmsTRANSFORM,FAR *_LPcmsTRANSFORM; + + + +// Packing & Unpacking + +_cmsFIXFN cdecl _cmsIdentifyInputFormat(_LPcmsTRANSFORM xform, DWORD dwInput); +_cmsFIXFN cdecl _cmsIdentifyOutputFormat(_LPcmsTRANSFORM xform, DWORD dwOutput); + + +// Conversion + +#define XYZRel 0 +#define LabRel 1 + + +int cdecl cmsChooseCnvrt(int Absolute, + int Phase1, LPcmsCIEXYZ BlackPointIn, + LPcmsCIEXYZ WhitePointIn, + LPcmsCIEXYZ IlluminantIn, + LPMAT3 ChromaticAdaptationMatrixIn, + + int Phase2, LPcmsCIEXYZ BlackPointOut, + LPcmsCIEXYZ WhitePointOut, + LPcmsCIEXYZ IlluminantOut, + LPMAT3 ChromaticAdaptationMatrixOut, + int DoBPC, + double AdaptationState, + _cmsADJFN *fn1, + LPWMAT3 wm, LPWVEC3 wof); + + + +// Clamping & Gamut handling + +BOOL cdecl _cmsEndPointsBySpace(icColorSpaceSignature Space, + WORD **White, WORD **Black, int *nOutputs); + +WORD * cdecl _cmsWhiteBySpace(icColorSpaceSignature Space); + + + +WORD cdecl Clamp_L(Fixed32 in); +WORD cdecl Clamp_ab(Fixed32 in); + +// Detection of black point + +#define LCMS_BPFLAGS_D50_ADAPTED 0x0001 + +int cdecl cmsDetectBlackPoint(LPcmsCIEXYZ BlackPoint, cmsHPROFILE hProfile, int Intent, DWORD dwFlags); + +// choose reasonable resolution +int cdecl _cmsReasonableGridpointsByColorspace(icColorSpaceSignature Colorspace, DWORD dwFlags); + +// Precalculate device link +LPLUT cdecl _cmsPrecalculateDeviceLink(cmsHTRANSFORM h, DWORD dwFlags); + +// Precalculate black preserving device link +LPLUT _cmsPrecalculateBlackPreservingDeviceLink(cmsHTRANSFORM hCMYK2CMYK, DWORD dwFlags); + +// Precalculate gamut check +LPLUT cdecl _cmsPrecalculateGamutCheck(cmsHTRANSFORM h); + +// Hot fixes bad profiles +BOOL cdecl _cmsFixWhiteMisalignment(_LPcmsTRANSFORM p); + +// Marks LUT as 8 bit on input +LPLUT cdecl _cmsBlessLUT8(LPLUT Lut); + +// Compute gamut boundary +LPLUT cdecl _cmsComputeGamutLUT(cmsHPROFILE hProfile, int Intent); + +// Compute softproof +LPLUT cdecl _cmsComputeSoftProofLUT(cmsHPROFILE hProfile, int nIntent); + +// Find a suitable prelinearization tables, matching the given transform +void cdecl _cmsComputePrelinearizationTablesFromXFORM(cmsHTRANSFORM h[], int nTransforms, LPLUT Grid); + + +// Build a tone curve for K->K' if possible (only works on CMYK) +LPGAMMATABLE _cmsBuildKToneCurve(cmsHTRANSFORM hCMYK2CMYK, int nPoints); + +// These are two VITAL macros, from converting between 8 and 16 bit +// representation. + +#define RGB_8_TO_16(rgb) (WORD) ((((WORD) (rgb)) << 8)|(rgb)) +#define RGB_16_TO_8(rgb) (BYTE) ((((rgb) * 65281 + 8388608) >> 24) & 0xFF) + + +#endif // LCMS_APIONLY + + +#define __cms_H + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/winclude/libiptcdata/_stdint.h b/winclude/libiptcdata/_stdint.h new file mode 100755 index 000000000..80ecf419b --- /dev/null +++ b/winclude/libiptcdata/_stdint.h @@ -0,0 +1,2 @@ +/* This file is generated automatically by configure */ +#include diff --git a/winclude/libiptcdata/iptc-data.h b/winclude/libiptcdata/iptc-data.h new file mode 100755 index 000000000..a7ab8efa9 --- /dev/null +++ b/winclude/libiptcdata/iptc-data.h @@ -0,0 +1,106 @@ +/* iptc-data.h + * + * Copyright © 2005 David Moore + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __IPTC_DATA_H__ +#define __IPTC_DATA_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct _IptcData IptcData; +typedef struct _IptcDataPrivate IptcDataPrivate; + +#include +#include +#include +#include +#include + +typedef enum { + IPTC_ENCODING_UNKNOWN = 0, + IPTC_ENCODING_UNSPECIFIED = 1, + IPTC_ENCODING_UTF8 = 2 +} IptcEncoding; + +/* The version of the spec implemented by this library */ +#define IPTC_IIM_VERSION 4 + +struct _IptcData +{ + IptcDataSet **datasets; + unsigned int count; + + IptcDataPrivate *priv; +}; + +/* Lifecycle */ +IptcData *iptc_data_new (void); +IptcData *iptc_data_new_mem (IptcMem *mem); +IptcData *iptc_data_new_from_jpeg (const char *path); +IptcData *iptc_data_new_from_jpeg_file (FILE* infile); +IptcData *iptc_data_new_from_data (const unsigned char *buf, + unsigned int size); +void iptc_data_ref (IptcData *data); +void iptc_data_unref (IptcData *data); +void iptc_data_free (IptcData *data); + +int iptc_data_load (IptcData *data, const unsigned char *buf, + unsigned int size); +int iptc_data_save (IptcData *data, unsigned char **buf, + unsigned int *size); +void iptc_data_free_buf (IptcData *data, unsigned char *buf); + +int iptc_data_add_dataset (IptcData *data, IptcDataSet *ds); +int iptc_data_add_dataset_before (IptcData *data, IptcDataSet *ds, + IptcDataSet *newds); +int iptc_data_add_dataset_after (IptcData *data, IptcDataSet *ds, + IptcDataSet *newds); +int iptc_data_remove_dataset (IptcData *data, IptcDataSet *ds); +IptcDataSet *iptc_data_get_dataset (IptcData *data, IptcRecord record, + IptcTag tag); +IptcDataSet *iptc_data_get_next_dataset (IptcData *data, IptcDataSet *ds, + IptcRecord record, IptcTag tag); + +typedef void (* IptcDataForeachDataSetFunc) (IptcDataSet *dataset, + void *user_data); +void iptc_data_foreach_dataset (IptcData *data, + IptcDataForeachDataSetFunc func, + void *user_data); +void iptc_data_sort (IptcData *data); +IptcEncoding iptc_data_get_encoding (IptcData *data); +int iptc_data_set_encoding_utf8 (IptcData *data); + +int iptc_data_set_version (IptcData *data, unsigned int version); + +int iptc_data_add_dataset_with_value (IptcData *data, IptcRecord record, + IptcTag tag, unsigned int value, IptcValidate validate); +int iptc_data_add_dataset_with_contents (IptcData *data, IptcRecord record, + IptcTag tag, const unsigned char * buf, + unsigned int size, IptcValidate validate); + +void iptc_data_dump (IptcData *data, unsigned int indent); +void iptc_data_log (IptcData *data, IptcLog *log); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __IPTC_DATA_H__ */ diff --git a/winclude/libiptcdata/iptc-dataset.h b/winclude/libiptcdata/iptc-dataset.h new file mode 100755 index 000000000..1ad8abbb6 --- /dev/null +++ b/winclude/libiptcdata/iptc-dataset.h @@ -0,0 +1,92 @@ +/* iptc-dataset.h + * + * Copyright © 2005 David Moore + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __IPTC_DATASET_H__ +#define __IPTC_DATASET_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct _IptcDataSet IptcDataSet; +typedef struct _IptcDataSetPrivate IptcDataSetPrivate; + +typedef enum { + IPTC_DONT_VALIDATE = 0, + IPTC_VALIDATE = 1 +} IptcValidate; + +#include +#include + +struct _IptcDataSet { + IptcRecord record; + IptcTag tag; + const IptcTagInfo * info; + + unsigned char *data; + unsigned int size; + + /* Data containing this dataset */ + IptcData *parent; + + IptcDataSetPrivate *priv; +}; + + +/* Lifecycle */ +IptcDataSet *iptc_dataset_new (void); +IptcDataSet *iptc_dataset_new_mem (IptcMem * mem); +IptcDataSet *iptc_dataset_copy (IptcDataSet *dataset); +void iptc_dataset_ref (IptcDataSet *dataset); +void iptc_dataset_unref (IptcDataSet *dataset); +void iptc_dataset_free (IptcDataSet *dataset); + +void iptc_dataset_set_tag (IptcDataSet *dataset, IptcRecord record, IptcTag tag); +IptcFormat iptc_dataset_get_format (IptcDataSet *dataset); + +int iptc_dataset_get_data (IptcDataSet *dataset, unsigned char * buf, + unsigned int size); +unsigned int iptc_dataset_get_value (IptcDataSet *dataset); +int iptc_dataset_get_date (IptcDataSet *dataset, int *year, int *month, int *day); +int iptc_dataset_get_time (IptcDataSet *dataset, int *hour, int *min, int *sec, + int *tz); + +int iptc_dataset_set_data (IptcDataSet *dataset, const unsigned char * buf, + unsigned int size, IptcValidate validate); +int iptc_dataset_set_value (IptcDataSet *dataset, unsigned int value, + IptcValidate validate); +int iptc_dataset_set_date (IptcDataSet *dataset, int year, int month, int day, + IptcValidate validate); +int iptc_dataset_set_time (IptcDataSet *dataset, int hour, int min, int sec, + int tz, IptcValidate validate); + + +/* For your convenience */ +const char *iptc_dataset_get_as_str (IptcDataSet *dataset, char *buf, + unsigned int size); + +void iptc_dataset_dump (IptcDataSet *dataset, unsigned int indent); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __IPTC_DATASET_H__ */ diff --git a/winclude/libiptcdata/iptc-jpeg.h b/winclude/libiptcdata/iptc-jpeg.h new file mode 100755 index 000000000..cef3806e8 --- /dev/null +++ b/winclude/libiptcdata/iptc-jpeg.h @@ -0,0 +1,45 @@ +/* iptc-jpeg.h + * + * Copyright © 2005 David Moore + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __IPTC_JPEG_H__ +#define __IPTC_JPEG_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include +#include + +int iptc_jpeg_read_ps3 (FILE * infile, unsigned char * buf, unsigned int size); +int iptc_jpeg_ps3_find_iptc (const unsigned char * ps3, + unsigned int ps3_size, unsigned int * iptc_len); + +int iptc_jpeg_ps3_save_iptc (const unsigned char * ps3, unsigned int ps3_size, + const unsigned char * iptc, unsigned int iptc_size, + unsigned char * buf, unsigned int size); +int iptc_jpeg_save_with_ps3 (FILE * infile, FILE * outfile, + const unsigned char * ps3, unsigned int ps3_size); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __IPTC_JPEG_H__ */ diff --git a/winclude/libiptcdata/iptc-log.h b/winclude/libiptcdata/iptc-log.h new file mode 100755 index 000000000..58f4ff255 --- /dev/null +++ b/winclude/libiptcdata/iptc-log.h @@ -0,0 +1,70 @@ +/* iptc-log.h + * + * Copyright © 2005 David Moore + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __IPTC_LOG_H__ +#define __IPTC_LOG_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include +#include + +typedef struct _IptcLog IptcLog; + +IptcLog *iptc_log_new (void); +IptcLog *iptc_log_new_mem (IptcMem *); +void iptc_log_ref (IptcLog *log); +void iptc_log_unref (IptcLog *log); +void iptc_log_free (IptcLog *log); + +typedef enum { + IPTC_LOG_CODE_NONE, + IPTC_LOG_CODE_DEBUG, + IPTC_LOG_CODE_NO_MEMORY, + IPTC_LOG_CODE_CORRUPT_DATA +} IptcLogCode; +const char *iptc_log_code_get_title (IptcLogCode); /* Title for dialog */ +const char *iptc_log_code_get_message (IptcLogCode); /* Message for dialog */ + +typedef void (* IptcLogFunc) (IptcLog *log, IptcLogCode, const char *domain, + const char *format, va_list args, void *data); + +void iptc_log_set_func (IptcLog *log, IptcLogFunc func, void *data); + +void iptc_log (IptcLog *log, IptcLogCode, const char *domain, + const char *format, ...) +#ifdef __GNUC__ + __attribute__((__format__(printf,4,5))) +#endif +; + +void iptc_logv (IptcLog *log, IptcLogCode, const char *domain, + const char *format, va_list args); + +/* For your convenience */ +#define IPTC_LOG_NO_MEMORY(l,d,s) iptc_log (l, IPTC_LOG_CODE_NO_MEMORY, d, "Could not allocate %i byte(s).", s) + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __IPTC_LOG_H__ */ diff --git a/winclude/libiptcdata/iptc-mem.h b/winclude/libiptcdata/iptc-mem.h new file mode 100755 index 000000000..8f884fe0d --- /dev/null +++ b/winclude/libiptcdata/iptc-mem.h @@ -0,0 +1,54 @@ +/* iptc-mem.h + * + * Copyright © 2005 David Moore + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __IPTC_MEM_H__ +#define __IPTC_MEM_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Should work like calloc: Needs to return initialized memory. */ +typedef void * (* IptcMemAllocFunc) (IptcLong); + +typedef void * (* IptcMemReallocFunc) (void *, IptcLong); +typedef void (* IptcMemFreeFunc) (void *); + +typedef struct _IptcMem IptcMem; + +IptcMem *iptc_mem_new (IptcMemAllocFunc, IptcMemReallocFunc, + IptcMemFreeFunc); +void iptc_mem_ref (IptcMem *); +void iptc_mem_unref (IptcMem *); + +void *iptc_mem_alloc (IptcMem *, IptcLong); +void *iptc_mem_realloc (IptcMem *, void *, IptcLong); +void iptc_mem_free (IptcMem *, void *); + +/* For your convenience */ +IptcMem *iptc_mem_new_default (void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __IPTC_MEM_H__ */ diff --git a/winclude/libiptcdata/iptc-tag.h b/winclude/libiptcdata/iptc-tag.h new file mode 100755 index 000000000..160673921 --- /dev/null +++ b/winclude/libiptcdata/iptc-tag.h @@ -0,0 +1,171 @@ +/* iptc-tag.h + * + * Copyright © 2001 David Moore + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __IPTC_TAG_H__ +#define __IPTC_TAG_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +typedef enum { + IPTC_RECORD_OBJECT_ENV = 1, + IPTC_RECORD_APP_2 = 2, + IPTC_RECORD_APP_3 = 3, + IPTC_RECORD_APP_4 = 4, + IPTC_RECORD_APP_5 = 5, + IPTC_RECORD_APP_6 = 6, + IPTC_RECORD_PREOBJ_DATA = 7, + IPTC_RECORD_OBJ_DATA = 8, + IPTC_RECORD_POSTOBJ_DATA = 9 +} IptcRecord; + +typedef enum { + IPTC_TAG_MODEL_VERSION = 0, /* Begin record 1 tags */ + IPTC_TAG_DESTINATION = 5, + IPTC_TAG_FILE_FORMAT = 20, + IPTC_TAG_FILE_VERSION = 22, + IPTC_TAG_SERVICE_ID = 30, + IPTC_TAG_ENVELOPE_NUM = 40, + IPTC_TAG_PRODUCT_ID = 50, + IPTC_TAG_ENVELOPE_PRIORITY = 60, + IPTC_TAG_DATE_SENT = 70, + IPTC_TAG_TIME_SENT = 80, + IPTC_TAG_CHARACTER_SET = 90, + IPTC_TAG_UNO = 100, + IPTC_TAG_ARM_ID = 120, + IPTC_TAG_ARM_VERSION = 122, /* End record 1 tags */ + IPTC_TAG_RECORD_VERSION = 0, /* Begin record 2 tags */ + IPTC_TAG_OBJECT_TYPE = 3, + IPTC_TAG_OBJECT_ATTRIBUTE = 4, + IPTC_TAG_OBJECT_NAME = 5, + IPTC_TAG_EDIT_STATUS = 7, + IPTC_TAG_EDITORIAL_UPDATE = 8, + IPTC_TAG_URGENCY = 10, + IPTC_TAG_SUBJECT_REFERENCE = 12, + IPTC_TAG_CATEGORY = 15, + IPTC_TAG_SUPPL_CATEGORY = 20, + IPTC_TAG_FIXTURE_ID = 22, + IPTC_TAG_KEYWORDS = 25, + IPTC_TAG_CONTENT_LOC_CODE = 26, + IPTC_TAG_CONTENT_LOC_NAME = 27, + IPTC_TAG_RELEASE_DATE = 30, + IPTC_TAG_RELEASE_TIME = 35, + IPTC_TAG_EXPIRATION_DATE = 37, + IPTC_TAG_EXPIRATION_TIME = 38, + IPTC_TAG_SPECIAL_INSTRUCTIONS = 40, + IPTC_TAG_ACTION_ADVISED = 42, + IPTC_TAG_REFERENCE_SERVICE = 45, + IPTC_TAG_REFERENCE_DATE = 47, + IPTC_TAG_REFERENCE_NUMBER = 50, + IPTC_TAG_DATE_CREATED = 55, + IPTC_TAG_TIME_CREATED = 60, + IPTC_TAG_DIGITAL_CREATION_DATE = 62, + IPTC_TAG_DIGITAL_CREATION_TIME = 63, + IPTC_TAG_ORIGINATING_PROGRAM = 65, + IPTC_TAG_PROGRAM_VERSION = 70, + IPTC_TAG_OBJECT_CYCLE = 75, + IPTC_TAG_BYLINE = 80, + IPTC_TAG_BYLINE_TITLE = 85, + IPTC_TAG_CITY = 90, + IPTC_TAG_SUBLOCATION = 92, + IPTC_TAG_STATE = 95, + IPTC_TAG_COUNTRY_CODE = 100, + IPTC_TAG_COUNTRY_NAME = 101, + IPTC_TAG_ORIG_TRANS_REF = 103, + IPTC_TAG_HEADLINE = 105, + IPTC_TAG_CREDIT = 110, + IPTC_TAG_SOURCE = 115, + IPTC_TAG_COPYRIGHT_NOTICE = 116, + IPTC_TAG_PICASA_UNKNOWN = 117, + IPTC_TAG_CONTACT = 118, + IPTC_TAG_CAPTION = 120, + IPTC_TAG_WRITER_EDITOR = 122, + IPTC_TAG_RASTERIZED_CAPTION = 125, + IPTC_TAG_IMAGE_TYPE = 130, + IPTC_TAG_IMAGE_ORIENTATION = 131, + IPTC_TAG_LANGUAGE_ID = 135, + IPTC_TAG_AUDIO_TYPE = 150, + IPTC_TAG_AUDIO_SAMPLING_RATE = 151, + IPTC_TAG_AUDIO_SAMPLING_RES = 152, + IPTC_TAG_AUDIO_DURATION = 153, + IPTC_TAG_AUDIO_OUTCUE = 154, + IPTC_TAG_PREVIEW_FORMAT = 200, + IPTC_TAG_PREVIEW_FORMAT_VER = 201, + IPTC_TAG_PREVIEW_DATA = 202, /* End record 2 tags */ + IPTC_TAG_SIZE_MODE = 10, /* Begin record 7 tags */ + IPTC_TAG_MAX_SUBFILE_SIZE = 20, + IPTC_TAG_SIZE_ANNOUNCED = 90, + IPTC_TAG_MAX_OBJECT_SIZE = 95, /* End record 7 tags */ + IPTC_TAG_SUBFILE = 10, /* Record 8 tags */ + IPTC_TAG_CONFIRMED_DATA_SIZE = 10 /* Record 9 tags */ +} IptcTag; + +typedef enum { + IPTC_OPTIONAL = 0, + IPTC_MANDATORY = 1 +} IptcMandatory; + +typedef enum { + IPTC_NOT_REPEATABLE = 0, + IPTC_REPEATABLE = 1 +} IptcRepeatable; + +typedef enum { + IPTC_FORMAT_UNKNOWN, + IPTC_FORMAT_BINARY, + IPTC_FORMAT_BYTE, + IPTC_FORMAT_SHORT, + IPTC_FORMAT_LONG, + IPTC_FORMAT_STRING, + IPTC_FORMAT_NUMERIC_STRING, + IPTC_FORMAT_DATE, + IPTC_FORMAT_TIME +} IptcFormat; + +typedef struct _IptcTagInfo IptcTagInfo; + +struct _IptcTagInfo { + IptcRecord record; + IptcTag tag; + const char *name; + const char *title; + const char *description; + IptcFormat format; + IptcMandatory mandatory; + IptcRepeatable repeatable; + unsigned int minbytes; + unsigned int maxbytes; +}; + +const char *iptc_tag_get_name (IptcRecord record, IptcTag tag); +char *iptc_tag_get_title (IptcRecord record, IptcTag tag); +char *iptc_tag_get_description (IptcRecord record, IptcTag tag); +const IptcTagInfo *iptc_tag_get_info (IptcRecord record, IptcTag tag); +char *iptc_format_get_name (IptcFormat format); + +int iptc_tag_find_by_name (const char * name, IptcRecord * record, IptcTag * tag); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __IPTC_TAG_H__ */ diff --git a/winclude/libiptcdata/iptc-utils.h b/winclude/libiptcdata/iptc-utils.h new file mode 100755 index 000000000..53091a0a2 --- /dev/null +++ b/winclude/libiptcdata/iptc-utils.h @@ -0,0 +1,66 @@ +/* iptc-utils.h + * + * Copyright © 2005 David Moore + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __IPTC_UTILS_H__ +#define __IPTC_UTILS_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include + +typedef enum { + IPTC_BYTE_ORDER_MOTOROLA, + IPTC_BYTE_ORDER_INTEL +} IptcByteOrder; + + +/* If these definitions don't work for you, please let us fix the + * macro generating _stdint.h */ + +typedef char IptcByte; /* 1 byte */ +typedef uint16_t IptcShort; /* 2 bytes */ +typedef uint32_t IptcLong; /* 4 bytes */ +typedef int32_t IptcSLong; /* 4 bytes */ + + +IptcShort iptc_get_short (const unsigned char *b, IptcByteOrder order); +IptcLong iptc_get_long (const unsigned char *b, IptcByteOrder order); +IptcSLong iptc_get_slong (const unsigned char *b, IptcByteOrder order); + +void iptc_set_short (unsigned char *b, IptcByteOrder order, + IptcShort value); +void iptc_set_long (unsigned char *b, IptcByteOrder order, + IptcLong value); +void iptc_set_slong (unsigned char *b, IptcByteOrder order, + IptcSLong value); + +#undef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +/* For compatibility with older versions */ +#define IPTC_TAG_SUBSEC_TIME IPTC_TAG_SUB_SEC_TIME + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __IPTC_UTILS_H__ */ diff --git a/winclude/png.h b/winclude/png.h new file mode 100755 index 000000000..71cfcdd0b --- /dev/null +++ b/winclude/png.h @@ -0,0 +1,3283 @@ +/* png.h - header file for PNG reference library + * + * libpng version 1.2.5 - October 3, 2002 + * Copyright (c) 1998-2002 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * Authors and maintainers: + * libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat + * libpng versions 0.89c, June 1996, through 0.96, May 1997: Andreas Dilger + * libpng versions 0.97, January 1998, through 1.2.5 - October 3, 2002: Glenn + * See also "Contributing Authors", below. + * + * Note about libpng version numbers: + * + * Due to various miscommunications, unforeseen code incompatibilities + * and occasional factors outside the authors' control, version numbering + * on the library has not always been consistent and straightforward. + * The following table summarizes matters since version 0.89c, which was + * the first widely used release: + * + * source png.h png.h shared-lib + * version string int version + * ------- ------ ----- ---------- + * 0.89c "1.0 beta 3" 0.89 89 1.0.89 + * 0.90 "1.0 beta 4" 0.90 90 0.90 [should have been 2.0.90] + * 0.95 "1.0 beta 5" 0.95 95 0.95 [should have been 2.0.95] + * 0.96 "1.0 beta 6" 0.96 96 0.96 [should have been 2.0.96] + * 0.97b "1.00.97 beta 7" 1.00.97 97 1.0.1 [should have been 2.0.97] + * 0.97c 0.97 97 2.0.97 + * 0.98 0.98 98 2.0.98 + * 0.99 0.99 98 2.0.99 + * 0.99a-m 0.99 99 2.0.99 + * 1.00 1.00 100 2.1.0 [100 should be 10000] + * 1.0.0 (from here on, the 100 2.1.0 [100 should be 10000] + * 1.0.1 png.h string is 10001 2.1.0 + * 1.0.1a-e identical to the 10002 from here on, the shared library + * 1.0.2 source version) 10002 is 2.V where V is the source code + * 1.0.2a-b 10003 version, except as noted. + * 1.0.3 10003 + * 1.0.3a-d 10004 + * 1.0.4 10004 + * 1.0.4a-f 10005 + * 1.0.5 (+ 2 patches) 10005 + * 1.0.5a-d 10006 + * 1.0.5e-r 10100 (not source compatible) + * 1.0.5s-v 10006 (not binary compatible) + * 1.0.6 (+ 3 patches) 10006 (still binary incompatible) + * 1.0.6d-f 10007 (still binary incompatible) + * 1.0.6g 10007 + * 1.0.6h 10007 10.6h (testing xy.z so-numbering) + * 1.0.6i 10007 10.6i + * 1.0.6j 10007 2.1.0.6j (incompatible with 1.0.0) + * 1.0.7beta11-14 DLLNUM 10007 2.1.0.7beta11-14 (binary compatible) + * 1.0.7beta15-18 1 10007 2.1.0.7beta15-18 (binary compatible) + * 1.0.7rc1-2 1 10007 2.1.0.7rc1-2 (binary compatible) + * 1.0.7 1 10007 (still compatible) + * 1.0.8beta1-4 1 10008 2.1.0.8beta1-4 + * 1.0.8rc1 1 10008 2.1.0.8rc1 + * 1.0.8 1 10008 2.1.0.8 + * 1.0.9beta1-6 1 10009 2.1.0.9beta1-6 + * 1.0.9rc1 1 10009 2.1.0.9rc1 + * 1.0.9beta7-10 1 10009 2.1.0.9beta7-10 + * 1.0.9rc2 1 10009 2.1.0.9rc2 + * 1.0.9 1 10009 2.1.0.9 + * 1.0.10beta1 1 10010 2.1.0.10beta1 + * 1.0.10rc1 1 10010 2.1.0.10rc1 + * 1.0.10 1 10010 2.1.0.10 + * 1.0.11beta1-3 1 10011 2.1.0.11beta1-3 + * 1.0.11rc1 1 10011 2.1.0.11rc1 + * 1.0.11 1 10011 2.1.0.11 + * 1.0.12beta1-2 2 10012 2.1.0.12beta1-2 + * 1.0.12rc1 2 10012 2.1.0.12rc1 + * 1.0.12 2 10012 2.1.0.12 + * 1.1.0a-f - 10100 2.1.1.0a-f (branch abandoned) + * 1.2.0beta1-2 2 10200 2.1.2.0beta1-2 + * 1.2.0beta3-5 3 10200 3.1.2.0beta3-5 + * 1.2.0rc1 3 10200 3.1.2.0rc1 + * 1.2.0 3 10200 3.1.2.0 + * 1.2.1beta1-4 3 10201 3.1.2.1beta1-4 + * 1.2.1rc1-2 3 10201 3.1.2.1rc1-2 + * 1.2.1 3 10201 3.1.2.1 + * 1.2.2beta1-6 12 10202 12.so.0.1.2.2beta1-6 + * 1.0.13beta1 10 10013 10.so.0.1.0.13beta1 + * 1.0.13rc1 10 10013 10.so.0.1.0.13rc1 + * 1.2.2rc1 12 10202 12.so.0.1.2.2rc1 + * 1.0.13 10 10013 10.so.0.1.0.13 + * 1.2.2 12 10202 12.so.0.1.2.2 + * 1.2.3rc1-6 12 10203 12.so.0.1.2.3rc1-6 + * 1.2.3 12 10203 12.so.0.1.2.3 + * 1.2.4beta1-3 13 10204 12.so.0.1.2.4beta1-3 + * 1.0.14rc1 13 10014 10.so.0.1.0.14rc1 + * 1.2.4rc1 13 10204 12.so.0.1.2.4rc1 + * 1.0.14 10 10014 10.so.0.1.0.14 + * 1.2.4 13 10204 12.so.0.1.2.4 + * 1.2.5beta1-2 13 10205 12.so.0.1.2.5beta1-2 + * 1.0.15rc1-3 10 10015 10.so.0.1.0.15rc1-3 + * 1.2.5rc1-3 13 10205 12.so.0.1.2.5rc1-3 + * 1.0.15 10 10015 10.so.0.1.0.15 + * 1.2.5 13 10205 12.so.0.1.2.5 + * + * Henceforth the source version will match the shared-library major + * and minor numbers; the shared-library major version number will be + * used for changes in backward compatibility, as it is intended. The + * PNG_LIBPNG_VER macro, which is not used within libpng but is available + * for applications, is an unsigned integer of the form xyyzz corresponding + * to the source version x.y.z (leading zeros in y and z). Beta versions + * were given the previous public release number plus a letter, until + * version 1.0.6j; from then on they were given the upcoming public + * release number plus "betaNN" or "rcN". + * + * Binary incompatibility exists only when applications make direct access + * to the info_ptr or png_ptr members through png.h, and the compiled + * application is loaded with a different version of the library. + * + * DLLNUM will change each time there are forward or backward changes + * in binary compatibility (e.g., when a new feature is added). + * + * See libpng.txt or libpng.3 for more information. The PNG specification + * is available as RFC 2083 + * and as a W3C Recommendation + */ + +/* + * COPYRIGHT NOTICE, DISCLAIMER, and LICENSE: + * + * If you modify libpng you may insert additional notices immediately following + * this sentence. + * + * libpng versions 1.0.7, July 1, 2000, through 1.2.5, October 3, 2002, are + * Copyright (c) 2000-2002 Glenn Randers-Pehrson, and are + * distributed according to the same disclaimer and license as libpng-1.0.6 + * with the following individuals added to the list of Contributing Authors + * + * Simon-Pierre Cadieux + * Eric S. Raymond + * Gilles Vollant + * + * and with the following additions to the disclaimer: + * + * There is no warranty against interference with your enjoyment of the + * library or against infringement. There is no warranty that our + * efforts or the library will fulfill any of your particular purposes + * or needs. This library is provided with all faults, and the entire + * risk of satisfactory quality, performance, accuracy, and effort is with + * the user. + * + * libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are + * Copyright (c) 1998, 1999, 2000 Glenn Randers-Pehrson + * Distributed according to the same disclaimer and license as libpng-0.96, + * with the following individuals added to the list of Contributing Authors: + * + * Tom Lane + * Glenn Randers-Pehrson + * Willem van Schaik + * + * libpng versions 0.89, June 1996, through 0.96, May 1997, are + * Copyright (c) 1996, 1997 Andreas Dilger + * Distributed according to the same disclaimer and license as libpng-0.88, + * with the following individuals added to the list of Contributing Authors: + * + * John Bowler + * Kevin Bracey + * Sam Bushell + * Magnus Holmgren + * Greg Roelofs + * Tom Tanner + * + * libpng versions 0.5, May 1995, through 0.88, January 1996, are + * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. + * + * For the purposes of this copyright and license, "Contributing Authors" + * is defined as the following set of individuals: + * + * Andreas Dilger + * Dave Martindale + * Guy Eric Schalnat + * Paul Schmidt + * Tim Wegner + * + * The PNG Reference Library is supplied "AS IS". The Contributing Authors + * and Group 42, Inc. disclaim all warranties, expressed or implied, + * including, without limitation, the warranties of merchantability and of + * fitness for any purpose. The Contributing Authors and Group 42, Inc. + * assume no liability for direct, indirect, incidental, special, exemplary, + * or consequential damages, which may result from the use of the PNG + * Reference Library, even if advised of the possibility of such damage. + * + * Permission is hereby granted to use, copy, modify, and distribute this + * source code, or portions hereof, for any purpose, without fee, subject + * to the following restrictions: + * + * 1. The origin of this source code must not be misrepresented. + * + * 2. Altered versions must be plainly marked as such and + * must not be misrepresented as being the original source. + * + * 3. This Copyright notice may not be removed or altered from + * any source or altered source distribution. + * + * The Contributing Authors and Group 42, Inc. specifically permit, without + * fee, and encourage the use of this source code as a component to + * supporting the PNG file format in commercial products. If you use this + * source code in a product, acknowledgment is not required but would be + * appreciated. + */ + +/* + * A "png_get_copyright" function is available, for convenient use in "about" + * boxes and the like: + * + * printf("%s",png_get_copyright(NULL)); + * + * Also, the PNG logo (in PNG format, of course) is supplied in the + * files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31). + */ + +/* + * Libpng is OSI Certified Open Source Software. OSI Certified is a + * certification mark of the Open Source Initiative. + */ + +/* + * The contributing authors would like to thank all those who helped + * with testing, bug fixes, and patience. This wouldn't have been + * possible without all of you. + * + * Thanks to Frank J. T. Wojcik for helping with the documentation. + */ + +/* + * Y2K compliance in libpng: + * ========================= + * + * October 3, 2002 + * + * Since the PNG Development group is an ad-hoc body, we can't make + * an official declaration. + * + * This is your unofficial assurance that libpng from version 0.71 and + * upward through 1.2.5 are Y2K compliant. It is my belief that earlier + * versions were also Y2K compliant. + * + * Libpng only has three year fields. One is a 2-byte unsigned integer + * that will hold years up to 65535. The other two hold the date in text + * format, and will hold years up to 9999. + * + * The integer is + * "png_uint_16 year" in png_time_struct. + * + * The strings are + * "png_charp time_buffer" in png_struct and + * "near_time_buffer", which is a local character string in png.c. + * + * There are seven time-related functions: + * png.c: png_convert_to_rfc_1123() in png.c + * (formerly png_convert_to_rfc_1152() in error) + * png_convert_from_struct_tm() in pngwrite.c, called in pngwrite.c + * png_convert_from_time_t() in pngwrite.c + * png_get_tIME() in pngget.c + * png_handle_tIME() in pngrutil.c, called in pngread.c + * png_set_tIME() in pngset.c + * png_write_tIME() in pngwutil.c, called in pngwrite.c + * + * All handle dates properly in a Y2K environment. The + * png_convert_from_time_t() function calls gmtime() to convert from system + * clock time, which returns (year - 1900), which we properly convert to + * the full 4-digit year. There is a possibility that applications using + * libpng are not passing 4-digit years into the png_convert_to_rfc_1123() + * function, or that they are incorrectly passing only a 2-digit year + * instead of "year - 1900" into the png_convert_from_struct_tm() function, + * but this is not under our control. The libpng documentation has always + * stated that it works with 4-digit years, and the APIs have been + * documented as such. + * + * The tIME chunk itself is also Y2K compliant. It uses a 2-byte unsigned + * integer to hold the year, and can hold years as large as 65535. + * + * zlib, upon which libpng depends, is also Y2K compliant. It contains + * no date-related code. + * + * Glenn Randers-Pehrson + * libpng maintainer + * PNG Development Group + */ + +#ifndef PNG_H +#define PNG_H + +/* This is not the place to learn how to use libpng. The file libpng.txt + * describes how to use libpng, and the file example.c summarizes it + * with some code on which to build. This file is useful for looking + * at the actual function definitions and structure components. + */ + +/* Version information for png.h - this should match the version in png.c */ +#define PNG_LIBPNG_VER_STRING "1.2.5" + +#define PNG_LIBPNG_VER_SONUM 0 +#define PNG_LIBPNG_VER_DLLNUM %DLLNUM% + +/* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */ +#define PNG_LIBPNG_VER_MAJOR 1 +#define PNG_LIBPNG_VER_MINOR 2 +#define PNG_LIBPNG_VER_RELEASE 5 +/* This should match the numeric part of the final component of + * PNG_LIBPNG_VER_STRING, omitting any leading zero: */ + +#define PNG_LIBPNG_VER_BUILD 0 + +#define PNG_LIBPNG_BUILD_ALPHA 1 +#define PNG_LIBPNG_BUILD_BETA 2 +#define PNG_LIBPNG_BUILD_RC 3 +#define PNG_LIBPNG_BUILD_STABLE 4 +#define PNG_LIBPNG_BUILD_TYPEMASK 7 +#define PNG_LIBPNG_BUILD_PATCH 8 /* Can be OR'ed with STABLE only */ +#define PNG_LIBPNG_BUILD_TYPE 4 + +/* Careful here. At one time, Guy wanted to use 082, but that would be octal. + * We must not include leading zeros. + * Versions 0.7 through 1.0.0 were in the range 0 to 100 here (only + * version 1.0.0 was mis-numbered 100 instead of 10000). From + * version 1.0.1 it's xxyyzz, where x=major, y=minor, z=release */ +#define PNG_LIBPNG_VER 10205 /* 1.2.5 */ + +#ifndef PNG_VERSION_INFO_ONLY + +/* include the compression library's header */ +#include "zlib.h" + +/* include all user configurable info, including optional assembler routines */ +#include "pngconf.h" + +/* Inhibit C++ name-mangling for libpng functions but not for system calls. */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* This file is arranged in several sections. The first section contains + * structure and type definitions. The second section contains the external + * library functions, while the third has the internal library functions, + * which applications aren't expected to use directly. + */ + +#ifndef PNG_NO_TYPECAST_NULL +#define int_p_NULL (int *)NULL +#define png_bytep_NULL (png_bytep)NULL +#define png_bytepp_NULL (png_bytepp)NULL +#define png_doublep_NULL (png_doublep)NULL +#define png_error_ptr_NULL (png_error_ptr)NULL +#define png_flush_ptr_NULL (png_flush_ptr)NULL +#define png_free_ptr_NULL (png_free_ptr)NULL +#define png_infopp_NULL (png_infopp)NULL +#define png_malloc_ptr_NULL (png_malloc_ptr)NULL +#define png_read_status_ptr_NULL (png_read_status_ptr)NULL +#define png_rw_ptr_NULL (png_rw_ptr)NULL +#define png_structp_NULL (png_structp)NULL +#define png_uint_16p_NULL (png_uint_16p)NULL +#define png_voidp_NULL (png_voidp)NULL +#define png_write_status_ptr_NULL (png_write_status_ptr)NULL +#else +#define int_p_NULL NULL +#define png_bytep_NULL NULL +#define png_bytepp_NULL NULL +#define png_doublep_NULL NULL +#define png_error_ptr_NULL NULL +#define png_flush_ptr_NULL NULL +#define png_free_ptr_NULL NULL +#define png_infopp_NULL NULL +#define png_malloc_ptr_NULL NULL +#define png_read_status_ptr_NULL NULL +#define png_rw_ptr_NULL NULL +#define png_structp_NULL NULL +#define png_uint_16p_NULL NULL +#define png_voidp_NULL NULL +#define png_write_status_ptr_NULL NULL +#endif + +/* variables declared in png.c - only it needs to define PNG_NO_EXTERN */ +#if !defined(PNG_NO_EXTERN) || defined(PNG_ALWAYS_EXTERN) +/* Version information for C files, stored in png.c. This had better match + * the version above. + */ +#ifdef PNG_USE_GLOBAL_ARRAYS +PNG_EXPORT_VAR (const char) png_libpng_ver[18]; + /* need room for 99.99.99beta99z */ +#else +#define png_libpng_ver png_get_header_ver(NULL) +#endif + +#ifdef PNG_USE_GLOBAL_ARRAYS +/* This was removed in version 1.0.5c */ +/* Structures to facilitate easy interlacing. See png.c for more details */ +PNG_EXPORT_VAR (const int FARDATA) png_pass_start[7]; +PNG_EXPORT_VAR (const int FARDATA) png_pass_inc[7]; +PNG_EXPORT_VAR (const int FARDATA) png_pass_ystart[7]; +PNG_EXPORT_VAR (const int FARDATA) png_pass_yinc[7]; +PNG_EXPORT_VAR (const int FARDATA) png_pass_mask[7]; +PNG_EXPORT_VAR (const int FARDATA) png_pass_dsp_mask[7]; +#ifdef PNG_HAVE_ASSEMBLER_COMBINE_ROW +PNG_EXPORT_VAR (const int FARDATA) png_pass_width[7]; +#endif +/* This isn't currently used. If you need it, see png.c for more details. +PNG_EXPORT_VAR (const int FARDATA) png_pass_height[7]; +*/ +#endif + +#endif /* PNG_NO_EXTERN */ + +/* Three color definitions. The order of the red, green, and blue, (and the + * exact size) is not important, although the size of the fields need to + * be png_byte or png_uint_16 (as defined below). + */ +typedef struct png_color_struct +{ + png_byte red; + png_byte green; + png_byte blue; +} png_color; +typedef png_color FAR * png_colorp; +typedef png_color FAR * FAR * png_colorpp; + +typedef struct png_color_16_struct +{ + png_byte index; /* used for palette files */ + png_uint_16 red; /* for use in red green blue files */ + png_uint_16 green; + png_uint_16 blue; + png_uint_16 gray; /* for use in grayscale files */ +} png_color_16; +typedef png_color_16 FAR * png_color_16p; +typedef png_color_16 FAR * FAR * png_color_16pp; + +typedef struct png_color_8_struct +{ + png_byte red; /* for use in red green blue files */ + png_byte green; + png_byte blue; + png_byte gray; /* for use in grayscale files */ + png_byte alpha; /* for alpha channel files */ +} png_color_8; +typedef png_color_8 FAR * png_color_8p; +typedef png_color_8 FAR * FAR * png_color_8pp; + +/* + * The following two structures are used for the in-core representation + * of sPLT chunks. + */ +typedef struct png_sPLT_entry_struct +{ + png_uint_16 red; + png_uint_16 green; + png_uint_16 blue; + png_uint_16 alpha; + png_uint_16 frequency; +} png_sPLT_entry; +typedef png_sPLT_entry FAR * png_sPLT_entryp; +typedef png_sPLT_entry FAR * FAR * png_sPLT_entrypp; + +/* When the depth of the sPLT palette is 8 bits, the color and alpha samples + * occupy the LSB of their respective members, and the MSB of each member + * is zero-filled. The frequency member always occupies the full 16 bits. + */ + +typedef struct png_sPLT_struct +{ + png_charp name; /* palette name */ + png_byte depth; /* depth of palette samples */ + png_sPLT_entryp entries; /* palette entries */ + png_int_32 nentries; /* number of palette entries */ +} png_sPLT_t; +typedef png_sPLT_t FAR * png_sPLT_tp; +typedef png_sPLT_t FAR * FAR * png_sPLT_tpp; + +#ifdef PNG_TEXT_SUPPORTED +/* png_text holds the contents of a text/ztxt/itxt chunk in a PNG file, + * and whether that contents is compressed or not. The "key" field + * points to a regular zero-terminated C string. The "text", "lang", and + * "lang_key" fields can be regular C strings, empty strings, or NULL pointers. + * However, the * structure returned by png_get_text() will always contain + * regular zero-terminated C strings (possibly empty), never NULL pointers, + * so they can be safely used in printf() and other string-handling functions. + */ +typedef struct png_text_struct +{ + int compression; /* compression value: + -1: tEXt, none + 0: zTXt, deflate + 1: iTXt, none + 2: iTXt, deflate */ + png_charp key; /* keyword, 1-79 character description of "text" */ + png_charp text; /* comment, may be an empty string (ie "") + or a NULL pointer */ + png_size_t text_length; /* length of the text string */ +#ifdef PNG_iTXt_SUPPORTED + png_size_t itxt_length; /* length of the itxt string */ + png_charp lang; /* language code, 0-79 characters + or a NULL pointer */ + png_charp lang_key; /* keyword translated UTF-8 string, 0 or more + chars or a NULL pointer */ +#endif +} png_text; +typedef png_text FAR * png_textp; +typedef png_text FAR * FAR * png_textpp; +#endif + +/* Supported compression types for text in PNG files (tEXt, and zTXt). + * The values of the PNG_TEXT_COMPRESSION_ defines should NOT be changed. */ +#define PNG_TEXT_COMPRESSION_NONE_WR -3 +#define PNG_TEXT_COMPRESSION_zTXt_WR -2 +#define PNG_TEXT_COMPRESSION_NONE -1 +#define PNG_TEXT_COMPRESSION_zTXt 0 +#define PNG_ITXT_COMPRESSION_NONE 1 +#define PNG_ITXT_COMPRESSION_zTXt 2 +#define PNG_TEXT_COMPRESSION_LAST 3 /* Not a valid value */ + +/* png_time is a way to hold the time in an machine independent way. + * Two conversions are provided, both from time_t and struct tm. There + * is no portable way to convert to either of these structures, as far + * as I know. If you know of a portable way, send it to me. As a side + * note - PNG has always been Year 2000 compliant! + */ +typedef struct png_time_struct +{ + png_uint_16 year; /* full year, as in, 1995 */ + png_byte month; /* month of year, 1 - 12 */ + png_byte day; /* day of month, 1 - 31 */ + png_byte hour; /* hour of day, 0 - 23 */ + png_byte minute; /* minute of hour, 0 - 59 */ + png_byte second; /* second of minute, 0 - 60 (for leap seconds) */ +} png_time; +typedef png_time FAR * png_timep; +typedef png_time FAR * FAR * png_timepp; + +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) +/* png_unknown_chunk is a structure to hold queued chunks for which there is + * no specific support. The idea is that we can use this to queue + * up private chunks for output even though the library doesn't actually + * know about their semantics. + */ +typedef struct png_unknown_chunk_t +{ + png_byte name[5]; + png_byte *data; + png_size_t size; + + /* libpng-using applications should NOT directly modify this byte. */ + png_byte location; /* mode of operation at read time */ +} +png_unknown_chunk; +typedef png_unknown_chunk FAR * png_unknown_chunkp; +typedef png_unknown_chunk FAR * FAR * png_unknown_chunkpp; +#endif + +/* png_info is a structure that holds the information in a PNG file so + * that the application can find out the characteristics of the image. + * If you are reading the file, this structure will tell you what is + * in the PNG file. If you are writing the file, fill in the information + * you want to put into the PNG file, then call png_write_info(). + * The names chosen should be very close to the PNG specification, so + * consult that document for information about the meaning of each field. + * + * With libpng < 0.95, it was only possible to directly set and read the + * the values in the png_info_struct, which meant that the contents and + * order of the values had to remain fixed. With libpng 0.95 and later, + * however, there are now functions that abstract the contents of + * png_info_struct from the application, so this makes it easier to use + * libpng with dynamic libraries, and even makes it possible to use + * libraries that don't have all of the libpng ancillary chunk-handing + * functionality. + * + * In any case, the order of the parameters in png_info_struct should NOT + * be changed for as long as possible to keep compatibility with applications + * that use the old direct-access method with png_info_struct. + * + * The following members may have allocated storage attached that should be + * cleaned up before the structure is discarded: palette, trans, text, + * pcal_purpose, pcal_units, pcal_params, hist, iccp_name, iccp_profile, + * splt_palettes, scal_unit, row_pointers, and unknowns. By default, these + * are automatically freed when the info structure is deallocated, if they were + * allocated internally by libpng. This behavior can be changed by means + * of the png_data_freer() function. + * + * More allocation details: all the chunk-reading functions that + * change these members go through the corresponding png_set_* + * functions. A function to clear these members is available: see + * png_free_data(). The png_set_* functions do not depend on being + * able to point info structure members to any of the storage they are + * passed (they make their own copies), EXCEPT that the png_set_text + * functions use the same storage passed to them in the text_ptr or + * itxt_ptr structure argument, and the png_set_rows and png_set_unknowns + * functions do not make their own copies. + */ +typedef struct png_info_struct +{ + /* the following are necessary for every PNG file */ + png_uint_32 width; /* width of image in pixels (from IHDR) */ + png_uint_32 height; /* height of image in pixels (from IHDR) */ + png_uint_32 valid; /* valid chunk data (see PNG_INFO_ below) */ + png_uint_32 rowbytes; /* bytes needed to hold an untransformed row */ + png_colorp palette; /* array of color values (valid & PNG_INFO_PLTE) */ + png_uint_16 num_palette; /* number of color entries in "palette" (PLTE) */ + png_uint_16 num_trans; /* number of transparent palette color (tRNS) */ + png_byte bit_depth; /* 1, 2, 4, 8, or 16 bits/channel (from IHDR) */ + png_byte color_type; /* see PNG_COLOR_TYPE_ below (from IHDR) */ + /* The following three should have been named *_method not *_type */ + png_byte compression_type; /* must be PNG_COMPRESSION_TYPE_BASE (IHDR) */ + png_byte filter_type; /* must be PNG_FILTER_TYPE_BASE (from IHDR) */ + png_byte interlace_type; /* One of PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */ + + /* The following is informational only on read, and not used on writes. */ + png_byte channels; /* number of data channels per pixel (1, 2, 3, 4) */ + png_byte pixel_depth; /* number of bits per pixel */ + png_byte spare_byte; /* to align the data, and for future use */ + png_byte signature[8]; /* magic bytes read by libpng from start of file */ + + /* The rest of the data is optional. If you are reading, check the + * valid field to see if the information in these are valid. If you + * are writing, set the valid field to those chunks you want written, + * and initialize the appropriate fields below. + */ + +#if defined(PNG_gAMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED) + /* The gAMA chunk describes the gamma characteristics of the system + * on which the image was created, normally in the range [1.0, 2.5]. + * Data is valid if (valid & PNG_INFO_gAMA) is non-zero. + */ + float gamma; /* gamma value of image, if (valid & PNG_INFO_gAMA) */ +#endif + +#if defined(PNG_sRGB_SUPPORTED) + /* GR-P, 0.96a */ + /* Data valid if (valid & PNG_INFO_sRGB) non-zero. */ + png_byte srgb_intent; /* sRGB rendering intent [0, 1, 2, or 3] */ +#endif + +#if defined(PNG_TEXT_SUPPORTED) + /* The tEXt, and zTXt chunks contain human-readable textual data in + * uncompressed, compressed, and optionally compressed forms, respectively. + * The data in "text" is an array of pointers to uncompressed, + * null-terminated C strings. Each chunk has a keyword that describes the + * textual data contained in that chunk. Keywords are not required to be + * unique, and the text string may be empty. Any number of text chunks may + * be in an image. + */ + int num_text; /* number of comments read/to write */ + int max_text; /* current size of text array */ + png_textp text; /* array of comments read/to write */ +#endif /* PNG_TEXT_SUPPORTED */ + +#if defined(PNG_tIME_SUPPORTED) + /* The tIME chunk holds the last time the displayed image data was + * modified. See the png_time struct for the contents of this struct. + */ + png_time mod_time; +#endif + +#if defined(PNG_sBIT_SUPPORTED) + /* The sBIT chunk specifies the number of significant high-order bits + * in the pixel data. Values are in the range [1, bit_depth], and are + * only specified for the channels in the pixel data. The contents of + * the low-order bits is not specified. Data is valid if + * (valid & PNG_INFO_sBIT) is non-zero. + */ + png_color_8 sig_bit; /* significant bits in color channels */ +#endif + +#if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_EXPAND_SUPPORTED) || \ +defined(PNG_READ_BACKGROUND_SUPPORTED) + /* The tRNS chunk supplies transparency data for paletted images and + * other image types that don't need a full alpha channel. There are + * "num_trans" transparency values for a paletted image, stored in the + * same order as the palette colors, starting from index 0. Values + * for the data are in the range [0, 255], ranging from fully transparent + * to fully opaque, respectively. For non-paletted images, there is a + * single color specified that should be treated as fully transparent. + * Data is valid if (valid & PNG_INFO_tRNS) is non-zero. + */ + png_bytep trans; /* transparent values for paletted image */ + png_color_16 trans_values; /* transparent color for non-palette image */ +#endif + +#if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + /* The bKGD chunk gives the suggested image background color if the + * display program does not have its own background color and the image + * is needs to composited onto a background before display. The colors + * in "background" are normally in the same color space/depth as the + * pixel data. Data is valid if (valid & PNG_INFO_bKGD) is non-zero. + */ + png_color_16 background; +#endif + +#if defined(PNG_oFFs_SUPPORTED) + /* The oFFs chunk gives the offset in "offset_unit_type" units rightwards + * and downwards from the top-left corner of the display, page, or other + * application-specific co-ordinate space. See the PNG_OFFSET_ defines + * below for the unit types. Valid if (valid & PNG_INFO_oFFs) non-zero. + */ + png_int_32 x_offset; /* x offset on page */ + png_int_32 y_offset; /* y offset on page */ + png_byte offset_unit_type; /* offset units type */ +#endif + +#if defined(PNG_pHYs_SUPPORTED) + /* The pHYs chunk gives the physical pixel density of the image for + * display or printing in "phys_unit_type" units (see PNG_RESOLUTION_ + * defines below). Data is valid if (valid & PNG_INFO_pHYs) is non-zero. + */ + png_uint_32 x_pixels_per_unit; /* horizontal pixel density */ + png_uint_32 y_pixels_per_unit; /* vertical pixel density */ + png_byte phys_unit_type; /* resolution type (see PNG_RESOLUTION_ below) */ +#endif + +#if defined(PNG_hIST_SUPPORTED) + /* The hIST chunk contains the relative frequency or importance of the + * various palette entries, so that a viewer can intelligently select a + * reduced-color palette, if required. Data is an array of "num_palette" + * values in the range [0,65535]. Data valid if (valid & PNG_INFO_hIST) + * is non-zero. + */ + png_uint_16p hist; +#endif + +#ifdef PNG_cHRM_SUPPORTED + /* The cHRM chunk describes the CIE color characteristics of the monitor + * on which the PNG was created. This data allows the viewer to do gamut + * mapping of the input image to ensure that the viewer sees the same + * colors in the image as the creator. Values are in the range + * [0.0, 0.8]. Data valid if (valid & PNG_INFO_cHRM) non-zero. + */ +#ifdef PNG_FLOATING_POINT_SUPPORTED + float x_white; + float y_white; + float x_red; + float y_red; + float x_green; + float y_green; + float x_blue; + float y_blue; +#endif +#endif + +#if defined(PNG_pCAL_SUPPORTED) + /* The pCAL chunk describes a transformation between the stored pixel + * values and original physical data values used to create the image. + * The integer range [0, 2^bit_depth - 1] maps to the floating-point + * range given by [pcal_X0, pcal_X1], and are further transformed by a + * (possibly non-linear) transformation function given by "pcal_type" + * and "pcal_params" into "pcal_units". Please see the PNG_EQUATION_ + * defines below, and the PNG-Group's PNG extensions document for a + * complete description of the transformations and how they should be + * implemented, and for a description of the ASCII parameter strings. + * Data values are valid if (valid & PNG_INFO_pCAL) non-zero. + */ + png_charp pcal_purpose; /* pCAL chunk description string */ + png_int_32 pcal_X0; /* minimum value */ + png_int_32 pcal_X1; /* maximum value */ + png_charp pcal_units; /* Latin-1 string giving physical units */ + png_charpp pcal_params; /* ASCII strings containing parameter values */ + png_byte pcal_type; /* equation type (see PNG_EQUATION_ below) */ + png_byte pcal_nparams; /* number of parameters given in pcal_params */ +#endif + +/* New members added in libpng-1.0.6 */ +#ifdef PNG_FREE_ME_SUPPORTED + png_uint_32 free_me; /* flags items libpng is responsible for freeing */ +#endif + +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) + /* storage for unknown chunks that the library doesn't recognize. */ + png_unknown_chunkp unknown_chunks; + png_size_t unknown_chunks_num; +#endif + +#if defined(PNG_iCCP_SUPPORTED) + /* iCCP chunk data. */ + png_charp iccp_name; /* profile name */ + png_charp iccp_profile; /* International Color Consortium profile data */ + /* Note to maintainer: should be png_bytep */ + png_uint_32 iccp_proflen; /* ICC profile data length */ + png_byte iccp_compression; /* Always zero */ +#endif + +#if defined(PNG_sPLT_SUPPORTED) + /* data on sPLT chunks (there may be more than one). */ + png_sPLT_tp splt_palettes; + png_uint_32 splt_palettes_num; +#endif + +#if defined(PNG_sCAL_SUPPORTED) + /* The sCAL chunk describes the actual physical dimensions of the + * subject matter of the graphic. The chunk contains a unit specification + * a byte value, and two ASCII strings representing floating-point + * values. The values are width and height corresponsing to one pixel + * in the image. This external representation is converted to double + * here. Data values are valid if (valid & PNG_INFO_sCAL) is non-zero. + */ + png_byte scal_unit; /* unit of physical scale */ +#ifdef PNG_FLOATING_POINT_SUPPORTED + double scal_pixel_width; /* width of one pixel */ + double scal_pixel_height; /* height of one pixel */ +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + png_charp scal_s_width; /* string containing height */ + png_charp scal_s_height; /* string containing width */ +#endif +#endif + +#if defined(PNG_INFO_IMAGE_SUPPORTED) + /* Memory has been allocated if (valid & PNG_ALLOCATED_INFO_ROWS) non-zero */ + /* Data valid if (valid & PNG_INFO_IDAT) non-zero */ + png_bytepp row_pointers; /* the image bits */ +#endif + +#if defined(PNG_FIXED_POINT_SUPPORTED) && defined(PNG_gAMA_SUPPORTED) + png_fixed_point int_gamma; /* gamma of image, if (valid & PNG_INFO_gAMA) */ +#endif + +#if defined(PNG_cHRM_SUPPORTED) && defined(PNG_FIXED_POINT_SUPPORTED) + png_fixed_point int_x_white; + png_fixed_point int_y_white; + png_fixed_point int_x_red; + png_fixed_point int_y_red; + png_fixed_point int_x_green; + png_fixed_point int_y_green; + png_fixed_point int_x_blue; + png_fixed_point int_y_blue; +#endif + +} png_info; + +typedef png_info FAR * png_infop; +typedef png_info FAR * FAR * png_infopp; + +/* Maximum positive integer used in PNG is (2^31)-1 */ +#define PNG_MAX_UINT ((png_uint_32)0x7fffffffL) + +/* These describe the color_type field in png_info. */ +/* color type masks */ +#define PNG_COLOR_MASK_PALETTE 1 +#define PNG_COLOR_MASK_COLOR 2 +#define PNG_COLOR_MASK_ALPHA 4 + +/* color types. Note that not all combinations are legal */ +#define PNG_COLOR_TYPE_GRAY 0 +#define PNG_COLOR_TYPE_PALETTE (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_PALETTE) +#define PNG_COLOR_TYPE_RGB (PNG_COLOR_MASK_COLOR) +#define PNG_COLOR_TYPE_RGB_ALPHA (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_ALPHA) +#define PNG_COLOR_TYPE_GRAY_ALPHA (PNG_COLOR_MASK_ALPHA) +/* aliases */ +#define PNG_COLOR_TYPE_RGBA PNG_COLOR_TYPE_RGB_ALPHA +#define PNG_COLOR_TYPE_GA PNG_COLOR_TYPE_GRAY_ALPHA + +/* This is for compression type. PNG 1.0-1.2 only define the single type. */ +#define PNG_COMPRESSION_TYPE_BASE 0 /* Deflate method 8, 32K window */ +#define PNG_COMPRESSION_TYPE_DEFAULT PNG_COMPRESSION_TYPE_BASE + +/* This is for filter type. PNG 1.0-1.2 only define the single type. */ +#define PNG_FILTER_TYPE_BASE 0 /* Single row per-byte filtering */ +#define PNG_INTRAPIXEL_DIFFERENCING 64 /* Used only in MNG datastreams */ +#define PNG_FILTER_TYPE_DEFAULT PNG_FILTER_TYPE_BASE + +/* These are for the interlacing type. These values should NOT be changed. */ +#define PNG_INTERLACE_NONE 0 /* Non-interlaced image */ +#define PNG_INTERLACE_ADAM7 1 /* Adam7 interlacing */ +#define PNG_INTERLACE_LAST 2 /* Not a valid value */ + +/* These are for the oFFs chunk. These values should NOT be changed. */ +#define PNG_OFFSET_PIXEL 0 /* Offset in pixels */ +#define PNG_OFFSET_MICROMETER 1 /* Offset in micrometers (1/10^6 meter) */ +#define PNG_OFFSET_LAST 2 /* Not a valid value */ + +/* These are for the pCAL chunk. These values should NOT be changed. */ +#define PNG_EQUATION_LINEAR 0 /* Linear transformation */ +#define PNG_EQUATION_BASE_E 1 /* Exponential base e transform */ +#define PNG_EQUATION_ARBITRARY 2 /* Arbitrary base exponential transform */ +#define PNG_EQUATION_HYPERBOLIC 3 /* Hyperbolic sine transformation */ +#define PNG_EQUATION_LAST 4 /* Not a valid value */ + +/* These are for the sCAL chunk. These values should NOT be changed. */ +#define PNG_SCALE_UNKNOWN 0 /* unknown unit (image scale) */ +#define PNG_SCALE_METER 1 /* meters per pixel */ +#define PNG_SCALE_RADIAN 2 /* radians per pixel */ +#define PNG_SCALE_LAST 3 /* Not a valid value */ + +/* These are for the pHYs chunk. These values should NOT be changed. */ +#define PNG_RESOLUTION_UNKNOWN 0 /* pixels/unknown unit (aspect ratio) */ +#define PNG_RESOLUTION_METER 1 /* pixels/meter */ +#define PNG_RESOLUTION_LAST 2 /* Not a valid value */ + +/* These are for the sRGB chunk. These values should NOT be changed. */ +#define PNG_sRGB_INTENT_PERCEPTUAL 0 +#define PNG_sRGB_INTENT_RELATIVE 1 +#define PNG_sRGB_INTENT_SATURATION 2 +#define PNG_sRGB_INTENT_ABSOLUTE 3 +#define PNG_sRGB_INTENT_LAST 4 /* Not a valid value */ + +/* This is for text chunks */ +#define PNG_KEYWORD_MAX_LENGTH 79 + +/* Maximum number of entries in PLTE/sPLT/tRNS arrays */ +#define PNG_MAX_PALETTE_LENGTH 256 + +/* These determine if an ancillary chunk's data has been successfully read + * from the PNG header, or if the application has filled in the corresponding + * data in the info_struct to be written into the output file. The values + * of the PNG_INFO_ defines should NOT be changed. + */ +#define PNG_INFO_gAMA 0x0001 +#define PNG_INFO_sBIT 0x0002 +#define PNG_INFO_cHRM 0x0004 +#define PNG_INFO_PLTE 0x0008 +#define PNG_INFO_tRNS 0x0010 +#define PNG_INFO_bKGD 0x0020 +#define PNG_INFO_hIST 0x0040 +#define PNG_INFO_pHYs 0x0080 +#define PNG_INFO_oFFs 0x0100 +#define PNG_INFO_tIME 0x0200 +#define PNG_INFO_pCAL 0x0400 +#define PNG_INFO_sRGB 0x0800 /* GR-P, 0.96a */ +#define PNG_INFO_iCCP 0x1000 /* ESR, 1.0.6 */ +#define PNG_INFO_sPLT 0x2000 /* ESR, 1.0.6 */ +#define PNG_INFO_sCAL 0x4000 /* ESR, 1.0.6 */ +#define PNG_INFO_IDAT 0x8000L /* ESR, 1.0.6 */ + +/* This is used for the transformation routines, as some of them + * change these values for the row. It also should enable using + * the routines for other purposes. + */ +typedef struct png_row_info_struct +{ + png_uint_32 width; /* width of row */ + png_uint_32 rowbytes; /* number of bytes in row */ + png_byte color_type; /* color type of row */ + png_byte bit_depth; /* bit depth of row */ + png_byte channels; /* number of channels (1, 2, 3, or 4) */ + png_byte pixel_depth; /* bits per pixel (depth * channels) */ +} png_row_info; + +typedef png_row_info FAR * png_row_infop; +typedef png_row_info FAR * FAR * png_row_infopp; + +/* These are the function types for the I/O functions and for the functions + * that allow the user to override the default I/O functions with his or her + * own. The png_error_ptr type should match that of user-supplied warning + * and error functions, while the png_rw_ptr type should match that of the + * user read/write data functions. + */ +typedef struct png_struct_def png_struct; +typedef png_struct FAR * png_structp; + +typedef void (PNGAPI *png_error_ptr) PNGARG((png_structp, png_const_charp)); +typedef void (PNGAPI *png_rw_ptr) PNGARG((png_structp, png_bytep, png_size_t)); +typedef void (PNGAPI *png_flush_ptr) PNGARG((png_structp)); +typedef void (PNGAPI *png_read_status_ptr) PNGARG((png_structp, png_uint_32, + int)); +typedef void (PNGAPI *png_write_status_ptr) PNGARG((png_structp, png_uint_32, + int)); + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +typedef void (PNGAPI *png_progressive_info_ptr) PNGARG((png_structp, png_infop)); +typedef void (PNGAPI *png_progressive_end_ptr) PNGARG((png_structp, png_infop)); +typedef void (PNGAPI *png_progressive_row_ptr) PNGARG((png_structp, png_bytep, + png_uint_32, int)); +#endif + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_LEGACY_SUPPORTED) +typedef void (PNGAPI *png_user_transform_ptr) PNGARG((png_structp, + png_row_infop, png_bytep)); +#endif + +#if defined(PNG_USER_CHUNKS_SUPPORTED) +typedef int (PNGAPI *png_user_chunk_ptr) PNGARG((png_structp, png_unknown_chunkp)); +#endif +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) +typedef void (PNGAPI *png_unknown_chunk_ptr) PNGARG((png_structp)); +#endif + +/* Transform masks for the high-level interface */ +#define PNG_TRANSFORM_IDENTITY 0x0000 /* read and write */ +#define PNG_TRANSFORM_STRIP_16 0x0001 /* read only */ +#define PNG_TRANSFORM_STRIP_ALPHA 0x0002 /* read only */ +#define PNG_TRANSFORM_PACKING 0x0004 /* read and write */ +#define PNG_TRANSFORM_PACKSWAP 0x0008 /* read and write */ +#define PNG_TRANSFORM_EXPAND 0x0010 /* read only */ +#define PNG_TRANSFORM_INVERT_MONO 0x0020 /* read and write */ +#define PNG_TRANSFORM_SHIFT 0x0040 /* read and write */ +#define PNG_TRANSFORM_BGR 0x0080 /* read and write */ +#define PNG_TRANSFORM_SWAP_ALPHA 0x0100 /* read and write */ +#define PNG_TRANSFORM_SWAP_ENDIAN 0x0200 /* read and write */ +#define PNG_TRANSFORM_INVERT_ALPHA 0x0400 /* read and write */ +#define PNG_TRANSFORM_STRIP_FILLER 0x0800 /* WRITE only */ + +/* Flags for MNG supported features */ +#define PNG_FLAG_MNG_EMPTY_PLTE 0x01 +#define PNG_FLAG_MNG_FILTER_64 0x04 +#define PNG_ALL_MNG_FEATURES 0x05 + +typedef png_voidp (*png_malloc_ptr) PNGARG((png_structp, png_size_t)); +typedef void (*png_free_ptr) PNGARG((png_structp, png_voidp)); + +/* The structure that holds the information to read and write PNG files. + * The only people who need to care about what is inside of this are the + * people who will be modifying the library for their own special needs. + * It should NOT be accessed directly by an application, except to store + * the jmp_buf. + */ + +struct png_struct_def +{ +#ifdef PNG_SETJMP_SUPPORTED + jmp_buf jmpbuf; /* used in png_error */ +#endif + png_error_ptr error_fn; /* function for printing errors and aborting */ + png_error_ptr warning_fn; /* function for printing warnings */ + png_voidp error_ptr; /* user supplied struct for error functions */ + png_rw_ptr write_data_fn; /* function for writing output data */ + png_rw_ptr read_data_fn; /* function for reading input data */ + png_voidp io_ptr; /* ptr to application struct for I/O functions */ + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) + png_user_transform_ptr read_user_transform_fn; /* user read transform */ +#endif + +#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) + png_user_transform_ptr write_user_transform_fn; /* user write transform */ +#endif + +/* These were added in libpng-1.0.2 */ +#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) + png_voidp user_transform_ptr; /* user supplied struct for user transform */ + png_byte user_transform_depth; /* bit depth of user transformed pixels */ + png_byte user_transform_channels; /* channels in user transformed pixels */ +#endif +#endif + + png_uint_32 mode; /* tells us where we are in the PNG file */ + png_uint_32 flags; /* flags indicating various things to libpng */ + png_uint_32 transformations; /* which transformations to perform */ + + z_stream zstream; /* pointer to decompression structure (below) */ + png_bytep zbuf; /* buffer for zlib */ + png_size_t zbuf_size; /* size of zbuf */ + int zlib_level; /* holds zlib compression level */ + int zlib_method; /* holds zlib compression method */ + int zlib_window_bits; /* holds zlib compression window bits */ + int zlib_mem_level; /* holds zlib compression memory level */ + int zlib_strategy; /* holds zlib compression strategy */ + + png_uint_32 width; /* width of image in pixels */ + png_uint_32 height; /* height of image in pixels */ + png_uint_32 num_rows; /* number of rows in current pass */ + png_uint_32 usr_width; /* width of row at start of write */ + png_uint_32 rowbytes; /* size of row in bytes */ + png_uint_32 irowbytes; /* size of current interlaced row in bytes */ + png_uint_32 iwidth; /* width of current interlaced row in pixels */ + png_uint_32 row_number; /* current row in interlace pass */ + png_bytep prev_row; /* buffer to save previous (unfiltered) row */ + png_bytep row_buf; /* buffer to save current (unfiltered) row */ + png_bytep sub_row; /* buffer to save "sub" row when filtering */ + png_bytep up_row; /* buffer to save "up" row when filtering */ + png_bytep avg_row; /* buffer to save "avg" row when filtering */ + png_bytep paeth_row; /* buffer to save "Paeth" row when filtering */ + png_row_info row_info; /* used for transformation routines */ + + png_uint_32 idat_size; /* current IDAT size for read */ + png_uint_32 crc; /* current chunk CRC value */ + png_colorp palette; /* palette from the input file */ + png_uint_16 num_palette; /* number of color entries in palette */ + png_uint_16 num_trans; /* number of transparency values */ + png_byte chunk_name[5]; /* null-terminated name of current chunk */ + png_byte compression; /* file compression type (always 0) */ + png_byte filter; /* file filter type (always 0) */ + png_byte interlaced; /* PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */ + png_byte pass; /* current interlace pass (0 - 6) */ + png_byte do_filter; /* row filter flags (see PNG_FILTER_ below ) */ + png_byte color_type; /* color type of file */ + png_byte bit_depth; /* bit depth of file */ + png_byte usr_bit_depth; /* bit depth of users row */ + png_byte pixel_depth; /* number of bits per pixel */ + png_byte channels; /* number of channels in file */ + png_byte usr_channels; /* channels at start of write */ + png_byte sig_bytes; /* magic bytes read/written from start of file */ + +#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) +#ifdef PNG_LEGACY_SUPPORTED + png_byte filler; /* filler byte for pixel expansion */ +#else + png_uint_16 filler; /* filler bytes for pixel expansion */ +#endif +#endif + +#if defined(PNG_bKGD_SUPPORTED) + png_byte background_gamma_type; +# ifdef PNG_FLOATING_POINT_SUPPORTED + float background_gamma; +# endif + png_color_16 background; /* background color in screen gamma space */ +#if defined(PNG_READ_GAMMA_SUPPORTED) + png_color_16 background_1; /* background normalized to gamma 1.0 */ +#endif +#endif /* PNG_bKGD_SUPPORTED */ + +#if defined(PNG_WRITE_FLUSH_SUPPORTED) + png_flush_ptr output_flush_fn;/* Function for flushing output */ + png_uint_32 flush_dist; /* how many rows apart to flush, 0 - no flush */ + png_uint_32 flush_rows; /* number of rows written since last flush */ +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + int gamma_shift; /* number of "insignificant" bits 16-bit gamma */ +#ifdef PNG_FLOATING_POINT_SUPPORTED + float gamma; /* file gamma value */ + float screen_gamma; /* screen gamma value (display_exponent) */ +#endif +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + png_bytep gamma_table; /* gamma table for 8-bit depth files */ + png_bytep gamma_from_1; /* converts from 1.0 to screen */ + png_bytep gamma_to_1; /* converts from file to 1.0 */ + png_uint_16pp gamma_16_table; /* gamma table for 16-bit depth files */ + png_uint_16pp gamma_16_from_1; /* converts from 1.0 to screen */ + png_uint_16pp gamma_16_to_1; /* converts from file to 1.0 */ +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_sBIT_SUPPORTED) + png_color_8 sig_bit; /* significant bits in each available channel */ +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) + png_color_8 shift; /* shift for significant bit tranformation */ +#endif + +#if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) \ + || defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + png_bytep trans; /* transparency values for paletted files */ + png_color_16 trans_values; /* transparency values for non-paletted files */ +#endif + + png_read_status_ptr read_row_fn; /* called after each row is decoded */ + png_write_status_ptr write_row_fn; /* called after each row is encoded */ +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED + png_progressive_info_ptr info_fn; /* called after header data fully read */ + png_progressive_row_ptr row_fn; /* called after each prog. row is decoded */ + png_progressive_end_ptr end_fn; /* called after image is complete */ + png_bytep save_buffer_ptr; /* current location in save_buffer */ + png_bytep save_buffer; /* buffer for previously read data */ + png_bytep current_buffer_ptr; /* current location in current_buffer */ + png_bytep current_buffer; /* buffer for recently used data */ + png_uint_32 push_length; /* size of current input chunk */ + png_uint_32 skip_length; /* bytes to skip in input data */ + png_size_t save_buffer_size; /* amount of data now in save_buffer */ + png_size_t save_buffer_max; /* total size of save_buffer */ + png_size_t buffer_size; /* total amount of available input data */ + png_size_t current_buffer_size; /* amount of data now in current_buffer */ + int process_mode; /* what push library is currently doing */ + int cur_palette; /* current push library palette index */ + +# if defined(PNG_TEXT_SUPPORTED) + png_size_t current_text_size; /* current size of text input data */ + png_size_t current_text_left; /* how much text left to read in input */ + png_charp current_text; /* current text chunk buffer */ + png_charp current_text_ptr; /* current location in current_text */ +# endif /* PNG_PROGRESSIVE_READ_SUPPORTED && PNG_TEXT_SUPPORTED */ + +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ + +#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__) +/* for the Borland special 64K segment handler */ + png_bytepp offset_table_ptr; + png_bytep offset_table; + png_uint_16 offset_table_number; + png_uint_16 offset_table_count; + png_uint_16 offset_table_count_free; +#endif + +#if defined(PNG_READ_DITHER_SUPPORTED) + png_bytep palette_lookup; /* lookup table for dithering */ + png_bytep dither_index; /* index translation for palette files */ +#endif + +#if defined(PNG_READ_DITHER_SUPPORTED) || defined(PNG_hIST_SUPPORTED) + png_uint_16p hist; /* histogram */ +#endif + +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) + png_byte heuristic_method; /* heuristic for row filter selection */ + png_byte num_prev_filters; /* number of weights for previous rows */ + png_bytep prev_filters; /* filter type(s) of previous row(s) */ + png_uint_16p filter_weights; /* weight(s) for previous line(s) */ + png_uint_16p inv_filter_weights; /* 1/weight(s) for previous line(s) */ + png_uint_16p filter_costs; /* relative filter calculation cost */ + png_uint_16p inv_filter_costs; /* 1/relative filter calculation cost */ +#endif + +#if defined(PNG_TIME_RFC1123_SUPPORTED) + png_charp time_buffer; /* String to hold RFC 1123 time text */ +#endif + +/* New members added in libpng-1.0.6 */ + +#ifdef PNG_FREE_ME_SUPPORTED + png_uint_32 free_me; /* flags items libpng is responsible for freeing */ +#endif + +#if defined(PNG_USER_CHUNKS_SUPPORTED) + png_voidp user_chunk_ptr; + png_user_chunk_ptr read_user_chunk_fn; /* user read chunk handler */ +#endif + +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) + int num_chunk_list; + png_bytep chunk_list; +#endif + +/* New members added in libpng-1.0.3 */ +#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) + png_byte rgb_to_gray_status; + /* These were changed from png_byte in libpng-1.0.6 */ + png_uint_16 rgb_to_gray_red_coeff; + png_uint_16 rgb_to_gray_green_coeff; + png_uint_16 rgb_to_gray_blue_coeff; +#endif + +/* New member added in libpng-1.0.4 (renamed in 1.0.9) */ +#if defined(PNG_MNG_FEATURES_SUPPORTED) || \ + defined(PNG_READ_EMPTY_PLTE_SUPPORTED) || \ + defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) +/* changed from png_byte to png_uint_32 at version 1.2.0 */ +#ifdef PNG_1_0_X + png_byte mng_features_permitted; +#else + png_uint_32 mng_features_permitted; +#endif /* PNG_1_0_X */ +#endif + +/* New member added in libpng-1.0.7 */ +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + png_fixed_point int_gamma; +#endif + +/* New member added in libpng-1.0.9, ifdef'ed out in 1.0.12, enabled in 1.2.0 */ +#if defined(PNG_MNG_FEATURES_SUPPORTED) + png_byte filter_type; +#endif + +#if defined(PNG_1_0_X) || (defined(PNG_DEBUG) && defined(PNG_USE_PNGGCCRD)) +/* New member added in libpng-1.0.10, ifdef'ed out in 1.2.0 */ + png_uint_32 row_buf_size; +#endif + +/* New members added in libpng-1.2.0 */ +#if !defined(PNG_1_0_X) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) + png_byte mmx_bitdepth_threshold; + png_uint_32 mmx_rowbytes_threshold; + png_uint_32 asm_flags; +#endif + +/* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */ +#ifdef PNG_USER_MEM_SUPPORTED + png_voidp mem_ptr; /* user supplied struct for mem functions */ + png_malloc_ptr malloc_fn; /* function for allocating memory */ + png_free_ptr free_fn; /* function for freeing memory */ +#endif + +/* New member added in libpng-1.0.13 and 1.2.0 */ + png_bytep big_row_buf; /* buffer to save current (unfiltered) row */ + +#if defined(PNG_READ_DITHER_SUPPORTED) +/* The following three members were added at version 1.0.14 and 1.2.4 */ + png_bytep dither_sort; /* working sort array */ + png_bytep index_to_palette; /* where the original index currently is */ + /* in the palette */ + png_bytep palette_to_index; /* which original index points to this */ + /* palette color */ +#endif + +}; + + +/* This prevents a compiler error in png.c if png.c and png.h are both at + version 1.2.5 + */ +typedef png_structp version_1_2_5; + +typedef png_struct FAR * FAR * png_structpp; + +/* Here are the function definitions most commonly used. This is not + * the place to find out how to use libpng. See libpng.txt for the + * full explanation, see example.c for the summary. This just provides + * a simple one line description of the use of each function. + */ + +/* Returns the version number of the library */ +extern PNG_EXPORT(png_uint_32,png_access_version_number) PNGARG((void)); + +/* Tell lib we have already handled the first magic bytes. + * Handling more than 8 bytes from the beginning of the file is an error. + */ +extern PNG_EXPORT(void,png_set_sig_bytes) PNGARG((png_structp png_ptr, + int num_bytes)); + +/* Check sig[start] through sig[start + num_to_check - 1] to see if it's a + * PNG file. Returns zero if the supplied bytes match the 8-byte PNG + * signature, and non-zero otherwise. Having num_to_check == 0 or + * start > 7 will always fail (ie return non-zero). + */ +extern PNG_EXPORT(int,png_sig_cmp) PNGARG((png_bytep sig, png_size_t start, + png_size_t num_to_check)); + +/* Simple signature checking function. This is the same as calling + * png_check_sig(sig, n) := !png_sig_cmp(sig, 0, n). + */ +extern PNG_EXPORT(int,png_check_sig) PNGARG((png_bytep sig, int num)); + +/* Allocate and initialize png_ptr struct for reading, and any other memory. */ +extern PNG_EXPORT(png_structp,png_create_read_struct) + PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn)); + +/* Allocate and initialize png_ptr struct for writing, and any other memory */ +extern PNG_EXPORT(png_structp,png_create_write_struct) + PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn)); + +extern PNG_EXPORT(png_uint_32,png_get_compression_buffer_size) + PNGARG((png_structp png_ptr)); + +extern PNG_EXPORT(void,png_set_compression_buffer_size) + PNGARG((png_structp png_ptr, png_uint_32 size)); + +/* Reset the compression stream */ +extern PNG_EXPORT(int,png_reset_zstream) PNGARG((png_structp png_ptr)); + +/* New functions added in libpng-1.0.2 (not enabled by default until 1.2.0) */ +#ifdef PNG_USER_MEM_SUPPORTED +extern PNG_EXPORT(png_structp,png_create_read_struct_2) + PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn)); +extern PNG_EXPORT(png_structp,png_create_write_struct_2) + PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn)); +#endif + +/* Write a PNG chunk - size, type, (optional) data, CRC. */ +extern PNG_EXPORT(void,png_write_chunk) PNGARG((png_structp png_ptr, + png_bytep chunk_name, png_bytep data, png_size_t length)); + +/* Write the start of a PNG chunk - length and chunk name. */ +extern PNG_EXPORT(void,png_write_chunk_start) PNGARG((png_structp png_ptr, + png_bytep chunk_name, png_uint_32 length)); + +/* Write the data of a PNG chunk started with png_write_chunk_start(). */ +extern PNG_EXPORT(void,png_write_chunk_data) PNGARG((png_structp png_ptr, + png_bytep data, png_size_t length)); + +/* Finish a chunk started with png_write_chunk_start() (includes CRC). */ +extern PNG_EXPORT(void,png_write_chunk_end) PNGARG((png_structp png_ptr)); + +/* Allocate and initialize the info structure */ +extern PNG_EXPORT(png_infop,png_create_info_struct) + PNGARG((png_structp png_ptr)); + +/* Initialize the info structure (old interface - DEPRECATED) */ +extern PNG_EXPORT(void,png_info_init) PNGARG((png_infop info_ptr)); +#undef png_info_init +#define png_info_init(info_ptr) png_info_init_3(&info_ptr, sizeof(png_info)); +extern PNG_EXPORT(void,png_info_init_3) PNGARG((png_infopp info_ptr, + png_size_t png_info_struct_size)); + +/* Writes all the PNG information before the image. */ +extern PNG_EXPORT(void,png_write_info_before_PLTE) PNGARG((png_structp png_ptr, + png_infop info_ptr)); +extern PNG_EXPORT(void,png_write_info) PNGARG((png_structp png_ptr, + png_infop info_ptr)); + +/* read the information before the actual image data. */ +extern PNG_EXPORT(void,png_read_info) PNGARG((png_structp png_ptr, + png_infop info_ptr)); + +#if defined(PNG_TIME_RFC1123_SUPPORTED) +extern PNG_EXPORT(png_charp,png_convert_to_rfc1123) + PNGARG((png_structp png_ptr, png_timep ptime)); +#endif + +#if !defined(_WIN32_WCE) +/* "time.h" functions are not supported on WindowsCE */ +#if defined(PNG_WRITE_tIME_SUPPORTED) +/* convert from a struct tm to png_time */ +extern PNG_EXPORT(void,png_convert_from_struct_tm) PNGARG((png_timep ptime, + struct tm FAR * ttime)); + +/* convert from time_t to png_time. Uses gmtime() */ +extern PNG_EXPORT(void,png_convert_from_time_t) PNGARG((png_timep ptime, + time_t ttime)); +#endif /* PNG_WRITE_tIME_SUPPORTED */ +#endif /* _WIN32_WCE */ + +#if defined(PNG_READ_EXPAND_SUPPORTED) +/* Expand data to 24-bit RGB, or 8-bit grayscale, with alpha if available. */ +extern PNG_EXPORT(void,png_set_expand) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(void,png_set_gray_1_2_4_to_8) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(void,png_set_palette_to_rgb) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(void,png_set_tRNS_to_alpha) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) +/* Use blue, green, red order for pixels. */ +extern PNG_EXPORT(void,png_set_bgr) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) +/* Expand the grayscale to 24-bit RGB if necessary. */ +extern PNG_EXPORT(void,png_set_gray_to_rgb) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) +/* Reduce RGB to grayscale. */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_rgb_to_gray) PNGARG((png_structp png_ptr, + int error_action, double red, double green )); +#endif +extern PNG_EXPORT(void,png_set_rgb_to_gray_fixed) PNGARG((png_structp png_ptr, + int error_action, png_fixed_point red, png_fixed_point green )); +extern PNG_EXPORT(png_byte,png_get_rgb_to_gray_status) PNGARG((png_structp + png_ptr)); +#endif + +extern PNG_EXPORT(void,png_build_grayscale_palette) PNGARG((int bit_depth, + png_colorp palette)); + +#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED) +extern PNG_EXPORT(void,png_set_strip_alpha) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) +extern PNG_EXPORT(void,png_set_swap_alpha) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) +extern PNG_EXPORT(void,png_set_invert_alpha) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) +/* Add a filler byte to 24-bit RGB images. */ +extern PNG_EXPORT(void,png_set_filler) PNGARG((png_structp png_ptr, + png_uint_32 filler, int flags)); +/* The values of the PNG_FILLER_ defines should NOT be changed */ +#define PNG_FILLER_BEFORE 0 +#define PNG_FILLER_AFTER 1 +#endif /* PNG_READ_FILLER_SUPPORTED || PNG_WRITE_FILLER_SUPPORTED */ + +#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) +/* Swap bytes in 16-bit depth files. */ +extern PNG_EXPORT(void,png_set_swap) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED) +/* Use 1 byte per pixel in 1, 2, or 4-bit depth files. */ +extern PNG_EXPORT(void,png_set_packing) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) || defined(PNG_WRITE_PACKSWAP_SUPPORTED) +/* Swap packing order of pixels in bytes. */ +extern PNG_EXPORT(void,png_set_packswap) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) +/* Converts files to legal bit depths. */ +extern PNG_EXPORT(void,png_set_shift) PNGARG((png_structp png_ptr, + png_color_8p true_bits)); +#endif + +#if defined(PNG_READ_INTERLACING_SUPPORTED) || \ + defined(PNG_WRITE_INTERLACING_SUPPORTED) +/* Have the code handle the interlacing. Returns the number of passes. */ +extern PNG_EXPORT(int,png_set_interlace_handling) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) +/* Invert monochrome files */ +extern PNG_EXPORT(void,png_set_invert_mono) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) +/* Handle alpha and tRNS by replacing with a background color. */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_background) PNGARG((png_structp png_ptr, + png_color_16p background_color, int background_gamma_code, + int need_expand, double background_gamma)); +#endif +#define PNG_BACKGROUND_GAMMA_UNKNOWN 0 +#define PNG_BACKGROUND_GAMMA_SCREEN 1 +#define PNG_BACKGROUND_GAMMA_FILE 2 +#define PNG_BACKGROUND_GAMMA_UNIQUE 3 +#endif + +#if defined(PNG_READ_16_TO_8_SUPPORTED) +/* strip the second byte of information from a 16-bit depth file. */ +extern PNG_EXPORT(void,png_set_strip_16) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_DITHER_SUPPORTED) +/* Turn on dithering, and reduce the palette to the number of colors available. */ +extern PNG_EXPORT(void,png_set_dither) PNGARG((png_structp png_ptr, + png_colorp palette, int num_palette, int maximum_colors, + png_uint_16p histogram, int full_dither)); +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) +/* Handle gamma correction. Screen_gamma=(display_exponent) */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_gamma) PNGARG((png_structp png_ptr, + double screen_gamma, double default_file_gamma)); +#endif +#endif + +#if defined(PNG_READ_EMPTY_PLTE_SUPPORTED) || \ + defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) +/* Permit or disallow empty PLTE (0: not permitted, 1: permitted) */ +/* Deprecated and will be removed. Use png_permit_mng_features() instead. */ +extern PNG_EXPORT(void,png_permit_empty_plte) PNGARG((png_structp png_ptr, + int empty_plte_permitted)); +#endif + +#if defined(PNG_WRITE_FLUSH_SUPPORTED) +/* Set how many lines between output flushes - 0 for no flushing */ +extern PNG_EXPORT(void,png_set_flush) PNGARG((png_structp png_ptr, int nrows)); +/* Flush the current PNG output buffer */ +extern PNG_EXPORT(void,png_write_flush) PNGARG((png_structp png_ptr)); +#endif + +/* optional update palette with requested transformations */ +extern PNG_EXPORT(void,png_start_read_image) PNGARG((png_structp png_ptr)); + +/* optional call to update the users info structure */ +extern PNG_EXPORT(void,png_read_update_info) PNGARG((png_structp png_ptr, + png_infop info_ptr)); + +/* read one or more rows of image data. */ +extern PNG_EXPORT(void,png_read_rows) PNGARG((png_structp png_ptr, + png_bytepp row, png_bytepp display_row, png_uint_32 num_rows)); + +/* read a row of data. */ +extern PNG_EXPORT(void,png_read_row) PNGARG((png_structp png_ptr, + png_bytep row, + png_bytep display_row)); + +/* read the whole image into memory at once. */ +extern PNG_EXPORT(void,png_read_image) PNGARG((png_structp png_ptr, + png_bytepp image)); + +/* write a row of image data */ +extern PNG_EXPORT(void,png_write_row) PNGARG((png_structp png_ptr, + png_bytep row)); + +/* write a few rows of image data */ +extern PNG_EXPORT(void,png_write_rows) PNGARG((png_structp png_ptr, + png_bytepp row, png_uint_32 num_rows)); + +/* write the image data */ +extern PNG_EXPORT(void,png_write_image) PNGARG((png_structp png_ptr, + png_bytepp image)); + +/* writes the end of the PNG file. */ +extern PNG_EXPORT(void,png_write_end) PNGARG((png_structp png_ptr, + png_infop info_ptr)); + +/* read the end of the PNG file. */ +extern PNG_EXPORT(void,png_read_end) PNGARG((png_structp png_ptr, + png_infop info_ptr)); + +/* free any memory associated with the png_info_struct */ +extern PNG_EXPORT(void,png_destroy_info_struct) PNGARG((png_structp png_ptr, + png_infopp info_ptr_ptr)); + +/* free any memory associated with the png_struct and the png_info_structs */ +extern PNG_EXPORT(void,png_destroy_read_struct) PNGARG((png_structpp + png_ptr_ptr, png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr)); + +/* free all memory used by the read (old method - NOT DLL EXPORTED) */ +extern void png_read_destroy PNGARG((png_structp png_ptr, png_infop info_ptr, + png_infop end_info_ptr)); + +/* free any memory associated with the png_struct and the png_info_structs */ +extern PNG_EXPORT(void,png_destroy_write_struct) + PNGARG((png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)); + +/* free any memory used in png_ptr struct (old method - NOT DLL EXPORTED) */ +extern void png_write_destroy PNGARG((png_structp png_ptr)); + +/* set the libpng method of handling chunk CRC errors */ +extern PNG_EXPORT(void,png_set_crc_action) PNGARG((png_structp png_ptr, + int crit_action, int ancil_action)); + +/* Values for png_set_crc_action() to say how to handle CRC errors in + * ancillary and critical chunks, and whether to use the data contained + * therein. Note that it is impossible to "discard" data in a critical + * chunk. For versions prior to 0.90, the action was always error/quit, + * whereas in version 0.90 and later, the action for CRC errors in ancillary + * chunks is warn/discard. These values should NOT be changed. + * + * value action:critical action:ancillary + */ +#define PNG_CRC_DEFAULT 0 /* error/quit warn/discard data */ +#define PNG_CRC_ERROR_QUIT 1 /* error/quit error/quit */ +#define PNG_CRC_WARN_DISCARD 2 /* (INVALID) warn/discard data */ +#define PNG_CRC_WARN_USE 3 /* warn/use data warn/use data */ +#define PNG_CRC_QUIET_USE 4 /* quiet/use data quiet/use data */ +#define PNG_CRC_NO_CHANGE 5 /* use current value use current value */ + +/* These functions give the user control over the scan-line filtering in + * libpng and the compression methods used by zlib. These functions are + * mainly useful for testing, as the defaults should work with most users. + * Those users who are tight on memory or want faster performance at the + * expense of compression can modify them. See the compression library + * header file (zlib.h) for an explination of the compression functions. + */ + +/* set the filtering method(s) used by libpng. Currently, the only valid + * value for "method" is 0. + */ +extern PNG_EXPORT(void,png_set_filter) PNGARG((png_structp png_ptr, int method, + int filters)); + +/* Flags for png_set_filter() to say which filters to use. The flags + * are chosen so that they don't conflict with real filter types + * below, in case they are supplied instead of the #defined constants. + * These values should NOT be changed. + */ +#define PNG_NO_FILTERS 0x00 +#define PNG_FILTER_NONE 0x08 +#define PNG_FILTER_SUB 0x10 +#define PNG_FILTER_UP 0x20 +#define PNG_FILTER_AVG 0x40 +#define PNG_FILTER_PAETH 0x80 +#define PNG_ALL_FILTERS (PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP | \ + PNG_FILTER_AVG | PNG_FILTER_PAETH) + +/* Filter values (not flags) - used in pngwrite.c, pngwutil.c for now. + * These defines should NOT be changed. + */ +#define PNG_FILTER_VALUE_NONE 0 +#define PNG_FILTER_VALUE_SUB 1 +#define PNG_FILTER_VALUE_UP 2 +#define PNG_FILTER_VALUE_AVG 3 +#define PNG_FILTER_VALUE_PAETH 4 +#define PNG_FILTER_VALUE_LAST 5 + +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) /* EXPERIMENTAL */ +/* The "heuristic_method" is given by one of the PNG_FILTER_HEURISTIC_ + * defines, either the default (minimum-sum-of-absolute-differences), or + * the experimental method (weighted-minimum-sum-of-absolute-differences). + * + * Weights are factors >= 1.0, indicating how important it is to keep the + * filter type consistent between rows. Larger numbers mean the current + * filter is that many times as likely to be the same as the "num_weights" + * previous filters. This is cumulative for each previous row with a weight. + * There needs to be "num_weights" values in "filter_weights", or it can be + * NULL if the weights aren't being specified. Weights have no influence on + * the selection of the first row filter. Well chosen weights can (in theory) + * improve the compression for a given image. + * + * Costs are factors >= 1.0 indicating the relative decoding costs of a + * filter type. Higher costs indicate more decoding expense, and are + * therefore less likely to be selected over a filter with lower computational + * costs. There needs to be a value in "filter_costs" for each valid filter + * type (given by PNG_FILTER_VALUE_LAST), or it can be NULL if you aren't + * setting the costs. Costs try to improve the speed of decompression without + * unduly increasing the compressed image size. + * + * A negative weight or cost indicates the default value is to be used, and + * values in the range [0.0, 1.0) indicate the value is to remain unchanged. + * The default values for both weights and costs are currently 1.0, but may + * change if good general weighting/cost heuristics can be found. If both + * the weights and costs are set to 1.0, this degenerates the WEIGHTED method + * to the UNWEIGHTED method, but with added encoding time/computation. + */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_filter_heuristics) PNGARG((png_structp png_ptr, + int heuristic_method, int num_weights, png_doublep filter_weights, + png_doublep filter_costs)); +#endif +#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */ + +/* Heuristic used for row filter selection. These defines should NOT be + * changed. + */ +#define PNG_FILTER_HEURISTIC_DEFAULT 0 /* Currently "UNWEIGHTED" */ +#define PNG_FILTER_HEURISTIC_UNWEIGHTED 1 /* Used by libpng < 0.95 */ +#define PNG_FILTER_HEURISTIC_WEIGHTED 2 /* Experimental feature */ +#define PNG_FILTER_HEURISTIC_LAST 3 /* Not a valid value */ + +/* Set the library compression level. Currently, valid values range from + * 0 - 9, corresponding directly to the zlib compression levels 0 - 9 + * (0 - no compression, 9 - "maximal" compression). Note that tests have + * shown that zlib compression levels 3-6 usually perform as well as level 9 + * for PNG images, and do considerably fewer caclulations. In the future, + * these values may not correspond directly to the zlib compression levels. + */ +extern PNG_EXPORT(void,png_set_compression_level) PNGARG((png_structp png_ptr, + int level)); + +extern PNG_EXPORT(void,png_set_compression_mem_level) + PNGARG((png_structp png_ptr, int mem_level)); + +extern PNG_EXPORT(void,png_set_compression_strategy) + PNGARG((png_structp png_ptr, int strategy)); + +extern PNG_EXPORT(void,png_set_compression_window_bits) + PNGARG((png_structp png_ptr, int window_bits)); + +extern PNG_EXPORT(void,png_set_compression_method) PNGARG((png_structp png_ptr, + int method)); + +/* These next functions are called for input/output, memory, and error + * handling. They are in the file pngrio.c, pngwio.c, and pngerror.c, + * and call standard C I/O routines such as fread(), fwrite(), and + * fprintf(). These functions can be made to use other I/O routines + * at run time for those applications that need to handle I/O in a + * different manner by calling png_set_???_fn(). See libpng.txt for + * more information. + */ + +#if !defined(PNG_NO_STDIO) +/* Initialize the input/output for the PNG file to the default functions. */ +extern PNG_EXPORT(void,png_init_io) PNGARG((png_structp png_ptr, png_FILE_p fp)); +#endif + +/* Replace the (error and abort), and warning functions with user + * supplied functions. If no messages are to be printed you must still + * write and use replacement functions. The replacement error_fn should + * still do a longjmp to the last setjmp location if you are using this + * method of error handling. If error_fn or warning_fn is NULL, the + * default function will be used. + */ + +extern PNG_EXPORT(void,png_set_error_fn) PNGARG((png_structp png_ptr, + png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warning_fn)); + +/* Return the user pointer associated with the error functions */ +extern PNG_EXPORT(png_voidp,png_get_error_ptr) PNGARG((png_structp png_ptr)); + +/* Replace the default data output functions with a user supplied one(s). + * If buffered output is not used, then output_flush_fn can be set to NULL. + * If PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile time + * output_flush_fn will be ignored (and thus can be NULL). + */ +extern PNG_EXPORT(void,png_set_write_fn) PNGARG((png_structp png_ptr, + png_voidp io_ptr, png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn)); + +/* Replace the default data input function with a user supplied one. */ +extern PNG_EXPORT(void,png_set_read_fn) PNGARG((png_structp png_ptr, + png_voidp io_ptr, png_rw_ptr read_data_fn)); + +/* Return the user pointer associated with the I/O functions */ +extern PNG_EXPORT(png_voidp,png_get_io_ptr) PNGARG((png_structp png_ptr)); + +extern PNG_EXPORT(void,png_set_read_status_fn) PNGARG((png_structp png_ptr, + png_read_status_ptr read_row_fn)); + +extern PNG_EXPORT(void,png_set_write_status_fn) PNGARG((png_structp png_ptr, + png_write_status_ptr write_row_fn)); + +#ifdef PNG_USER_MEM_SUPPORTED +/* Replace the default memory allocation functions with user supplied one(s). */ +extern PNG_EXPORT(void,png_set_mem_fn) PNGARG((png_structp png_ptr, + png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn)); +/* Return the user pointer associated with the memory functions */ +extern PNG_EXPORT(png_voidp,png_get_mem_ptr) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_LEGACY_SUPPORTED) +extern PNG_EXPORT(void,png_set_read_user_transform_fn) PNGARG((png_structp + png_ptr, png_user_transform_ptr read_user_transform_fn)); +#endif + +#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_LEGACY_SUPPORTED) +extern PNG_EXPORT(void,png_set_write_user_transform_fn) PNGARG((png_structp + png_ptr, png_user_transform_ptr write_user_transform_fn)); +#endif + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_LEGACY_SUPPORTED) +extern PNG_EXPORT(void,png_set_user_transform_info) PNGARG((png_structp + png_ptr, png_voidp user_transform_ptr, int user_transform_depth, + int user_transform_channels)); +/* Return the user pointer associated with the user transform functions */ +extern PNG_EXPORT(png_voidp,png_get_user_transform_ptr) + PNGARG((png_structp png_ptr)); +#endif + +#ifdef PNG_USER_CHUNKS_SUPPORTED +extern PNG_EXPORT(void,png_set_read_user_chunk_fn) PNGARG((png_structp png_ptr, + png_voidp user_chunk_ptr, png_user_chunk_ptr read_user_chunk_fn)); +extern PNG_EXPORT(png_voidp,png_get_user_chunk_ptr) PNGARG((png_structp + png_ptr)); +#endif + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +/* Sets the function callbacks for the push reader, and a pointer to a + * user-defined structure available to the callback functions. + */ +extern PNG_EXPORT(void,png_set_progressive_read_fn) PNGARG((png_structp png_ptr, + png_voidp progressive_ptr, + png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn, + png_progressive_end_ptr end_fn)); + +/* returns the user pointer associated with the push read functions */ +extern PNG_EXPORT(png_voidp,png_get_progressive_ptr) + PNGARG((png_structp png_ptr)); + +/* function to be called when data becomes available */ +extern PNG_EXPORT(void,png_process_data) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_bytep buffer, png_size_t buffer_size)); + +/* function that combines rows. Not very much different than the + * png_combine_row() call. Is this even used????? + */ +extern PNG_EXPORT(void,png_progressive_combine_row) PNGARG((png_structp png_ptr, + png_bytep old_row, png_bytep new_row)); +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ + +extern PNG_EXPORT(png_voidp,png_malloc) PNGARG((png_structp png_ptr, + png_uint_32 size)); + +#if defined(PNG_1_0_X) +# define png_malloc_warn png_malloc +#else +/* Added at libpng version 1.2.4 */ +extern PNG_EXPORT(png_voidp,png_malloc_warn) PNGARG((png_structp png_ptr, + png_uint_32 size)); +#endif + +/* frees a pointer allocated by png_malloc() */ +extern PNG_EXPORT(void,png_free) PNGARG((png_structp png_ptr, png_voidp ptr)); + +#if defined(PNG_1_0_X) +/* Function to allocate memory for zlib. */ +extern PNG_EXPORT(voidpf,png_zalloc) PNGARG((voidpf png_ptr, uInt items, + uInt size)); + +/* Function to free memory for zlib */ +extern PNG_EXPORT(void,png_zfree) PNGARG((voidpf png_ptr, voidpf ptr)); +#endif + +/* Free data that was allocated internally */ +extern PNG_EXPORT(void,png_free_data) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 free_me, int num)); +#ifdef PNG_FREE_ME_SUPPORTED +/* Reassign responsibility for freeing existing data, whether allocated + * by libpng or by the application */ +extern PNG_EXPORT(void,png_data_freer) PNGARG((png_structp png_ptr, + png_infop info_ptr, int freer, png_uint_32 mask)); +#endif +/* assignments for png_data_freer */ +#define PNG_DESTROY_WILL_FREE_DATA 1 +#define PNG_SET_WILL_FREE_DATA 1 +#define PNG_USER_WILL_FREE_DATA 2 +/* Flags for png_ptr->free_me and info_ptr->free_me */ +#define PNG_FREE_HIST 0x0008 +#define PNG_FREE_ICCP 0x0010 +#define PNG_FREE_SPLT 0x0020 +#define PNG_FREE_ROWS 0x0040 +#define PNG_FREE_PCAL 0x0080 +#define PNG_FREE_SCAL 0x0100 +#define PNG_FREE_UNKN 0x0200 +#define PNG_FREE_LIST 0x0400 +#define PNG_FREE_PLTE 0x1000 +#define PNG_FREE_TRNS 0x2000 +#define PNG_FREE_TEXT 0x4000 +#define PNG_FREE_ALL 0x7fff +#define PNG_FREE_MUL 0x4220 /* PNG_FREE_SPLT|PNG_FREE_TEXT|PNG_FREE_UNKN */ + +#ifdef PNG_USER_MEM_SUPPORTED +extern PNG_EXPORT(png_voidp,png_malloc_default) PNGARG((png_structp png_ptr, + png_uint_32 size)); +extern PNG_EXPORT(void,png_free_default) PNGARG((png_structp png_ptr, + png_voidp ptr)); +#endif + +extern PNG_EXPORT(png_voidp,png_memcpy_check) PNGARG((png_structp png_ptr, + png_voidp s1, png_voidp s2, png_uint_32 size)); + +extern PNG_EXPORT(png_voidp,png_memset_check) PNGARG((png_structp png_ptr, + png_voidp s1, int value, png_uint_32 size)); + +#if defined(USE_FAR_KEYWORD) /* memory model conversion function */ +extern void *png_far_to_near PNGARG((png_structp png_ptr,png_voidp ptr, + int check)); +#endif /* USE_FAR_KEYWORD */ + +/* Fatal error in PNG image of libpng - can't continue */ +extern PNG_EXPORT(void,png_error) PNGARG((png_structp png_ptr, + png_const_charp error_message)); + +/* The same, but the chunk name is prepended to the error string. */ +extern PNG_EXPORT(void,png_chunk_error) PNGARG((png_structp png_ptr, + png_const_charp error_message)); + +/* Non-fatal error in libpng. Can continue, but may have a problem. */ +extern PNG_EXPORT(void,png_warning) PNGARG((png_structp png_ptr, + png_const_charp warning_message)); + +/* Non-fatal error in libpng, chunk name is prepended to message. */ +extern PNG_EXPORT(void,png_chunk_warning) PNGARG((png_structp png_ptr, + png_const_charp warning_message)); + +/* The png_set_ functions are for storing values in the png_info_struct. + * Similarly, the png_get_ calls are used to read values from the + * png_info_struct, either storing the parameters in the passed variables, or + * setting pointers into the png_info_struct where the data is stored. The + * png_get_ functions return a non-zero value if the data was available + * in info_ptr, or return zero and do not change any of the parameters if the + * data was not available. + * + * These functions should be used instead of directly accessing png_info + * to avoid problems with future changes in the size and internal layout of + * png_info_struct. + */ +/* Returns "flag" if chunk data is valid in info_ptr. */ +extern PNG_EXPORT(png_uint_32,png_get_valid) PNGARG((png_structp png_ptr, +png_infop info_ptr, png_uint_32 flag)); + +/* Returns number of bytes needed to hold a transformed row. */ +extern PNG_EXPORT(png_uint_32,png_get_rowbytes) PNGARG((png_structp png_ptr, +png_infop info_ptr)); + +#if defined(PNG_INFO_IMAGE_SUPPORTED) +/* Returns row_pointers, which is an array of pointers to scanlines that was +returned from png_read_png(). */ +extern PNG_EXPORT(png_bytepp,png_get_rows) PNGARG((png_structp png_ptr, +png_infop info_ptr)); +/* Set row_pointers, which is an array of pointers to scanlines for use +by png_write_png(). */ +extern PNG_EXPORT(void,png_set_rows) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_bytepp row_pointers)); +#endif + +/* Returns number of color channels in image. */ +extern PNG_EXPORT(png_byte,png_get_channels) PNGARG((png_structp png_ptr, +png_infop info_ptr)); + +#ifdef PNG_EASY_ACCESS_SUPPORTED +/* Returns image width in pixels. */ +extern PNG_EXPORT(png_uint_32, png_get_image_width) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image height in pixels. */ +extern PNG_EXPORT(png_uint_32, png_get_image_height) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image bit_depth. */ +extern PNG_EXPORT(png_byte, png_get_bit_depth) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image color_type. */ +extern PNG_EXPORT(png_byte, png_get_color_type) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image filter_type. */ +extern PNG_EXPORT(png_byte, png_get_filter_type) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image interlace_type. */ +extern PNG_EXPORT(png_byte, png_get_interlace_type) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image compression_type. */ +extern PNG_EXPORT(png_byte, png_get_compression_type) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image resolution in pixels per meter, from pHYs chunk data. */ +extern PNG_EXPORT(png_uint_32, png_get_pixels_per_meter) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +extern PNG_EXPORT(png_uint_32, png_get_x_pixels_per_meter) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +extern PNG_EXPORT(png_uint_32, png_get_y_pixels_per_meter) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns pixel aspect ratio, computed from pHYs chunk data. */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(float, png_get_pixel_aspect_ratio) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +#endif + +/* Returns image x, y offset in pixels or microns, from oFFs chunk data. */ +extern PNG_EXPORT(png_int_32, png_get_x_offset_pixels) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +extern PNG_EXPORT(png_int_32, png_get_y_offset_pixels) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +extern PNG_EXPORT(png_int_32, png_get_x_offset_microns) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +extern PNG_EXPORT(png_int_32, png_get_y_offset_microns) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +#endif /* PNG_EASY_ACCESS_SUPPORTED */ + +/* Returns pointer to signature string read from PNG header */ +extern PNG_EXPORT(png_bytep,png_get_signature) PNGARG((png_structp png_ptr, +png_infop info_ptr)); + +#if defined(PNG_bKGD_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_bKGD) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_color_16p *background)); +#endif + +#if defined(PNG_bKGD_SUPPORTED) +extern PNG_EXPORT(void,png_set_bKGD) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_color_16p background)); +#endif + +#if defined(PNG_cHRM_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_cHRM) PNGARG((png_structp png_ptr, + png_infop info_ptr, double *white_x, double *white_y, double *red_x, + double *red_y, double *green_x, double *green_y, double *blue_x, + double *blue_y)); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_cHRM_fixed) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_fixed_point *int_white_x, png_fixed_point + *int_white_y, png_fixed_point *int_red_x, png_fixed_point *int_red_y, + png_fixed_point *int_green_x, png_fixed_point *int_green_y, png_fixed_point + *int_blue_x, png_fixed_point *int_blue_y)); +#endif +#endif + +#if defined(PNG_cHRM_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_cHRM) PNGARG((png_structp png_ptr, + png_infop info_ptr, double white_x, double white_y, double red_x, + double red_y, double green_x, double green_y, double blue_x, double blue_y)); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_cHRM_fixed) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_fixed_point int_white_x, png_fixed_point int_white_y, + png_fixed_point int_red_x, png_fixed_point int_red_y, png_fixed_point + int_green_x, png_fixed_point int_green_y, png_fixed_point int_blue_x, + png_fixed_point int_blue_y)); +#endif +#endif + +#if defined(PNG_gAMA_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_gAMA) PNGARG((png_structp png_ptr, + png_infop info_ptr, double *file_gamma)); +#endif +extern PNG_EXPORT(png_uint_32,png_get_gAMA_fixed) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_fixed_point *int_file_gamma)); +#endif + +#if defined(PNG_gAMA_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_gAMA) PNGARG((png_structp png_ptr, + png_infop info_ptr, double file_gamma)); +#endif +extern PNG_EXPORT(void,png_set_gAMA_fixed) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_fixed_point int_file_gamma)); +#endif + +#if defined(PNG_hIST_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_hIST) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_16p *hist)); +#endif + +#if defined(PNG_hIST_SUPPORTED) +extern PNG_EXPORT(void,png_set_hIST) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_16p hist)); +#endif + +extern PNG_EXPORT(png_uint_32,png_get_IHDR) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 *width, png_uint_32 *height, + int *bit_depth, int *color_type, int *interlace_method, + int *compression_method, int *filter_method)); + +extern PNG_EXPORT(void,png_set_IHDR) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 width, png_uint_32 height, int bit_depth, + int color_type, int interlace_method, int compression_method, + int filter_method)); + +#if defined(PNG_oFFs_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_oFFs) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_int_32 *offset_x, png_int_32 *offset_y, + int *unit_type)); +#endif + +#if defined(PNG_oFFs_SUPPORTED) +extern PNG_EXPORT(void,png_set_oFFs) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_int_32 offset_x, png_int_32 offset_y, + int unit_type)); +#endif + +#if defined(PNG_pCAL_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_pCAL) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_charp *purpose, png_int_32 *X0, png_int_32 *X1, + int *type, int *nparams, png_charp *units, png_charpp *params)); +#endif + +#if defined(PNG_pCAL_SUPPORTED) +extern PNG_EXPORT(void,png_set_pCAL) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_charp purpose, png_int_32 X0, png_int_32 X1, + int type, int nparams, png_charp units, png_charpp params)); +#endif + +#if defined(PNG_pHYs_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_pHYs) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)); +#endif + +#if defined(PNG_pHYs_SUPPORTED) +extern PNG_EXPORT(void,png_set_pHYs) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 res_x, png_uint_32 res_y, int unit_type)); +#endif + +extern PNG_EXPORT(png_uint_32,png_get_PLTE) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_colorp *palette, int *num_palette)); + +extern PNG_EXPORT(void,png_set_PLTE) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_colorp palette, int num_palette)); + +#if defined(PNG_sBIT_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_sBIT) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_color_8p *sig_bit)); +#endif + +#if defined(PNG_sBIT_SUPPORTED) +extern PNG_EXPORT(void,png_set_sBIT) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_color_8p sig_bit)); +#endif + +#if defined(PNG_sRGB_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_sRGB) PNGARG((png_structp png_ptr, + png_infop info_ptr, int *intent)); +#endif + +#if defined(PNG_sRGB_SUPPORTED) +extern PNG_EXPORT(void,png_set_sRGB) PNGARG((png_structp png_ptr, + png_infop info_ptr, int intent)); +extern PNG_EXPORT(void,png_set_sRGB_gAMA_and_cHRM) PNGARG((png_structp png_ptr, + png_infop info_ptr, int intent)); +#endif + +#if defined(PNG_iCCP_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_iCCP) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_charpp name, int *compression_type, + png_charpp profile, png_uint_32 *proflen)); + /* Note to maintainer: profile should be png_bytepp */ +#endif + +#if defined(PNG_iCCP_SUPPORTED) +extern PNG_EXPORT(void,png_set_iCCP) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_charp name, int compression_type, + png_charp profile, png_uint_32 proflen)); + /* Note to maintainer: profile should be png_bytep */ +#endif + +#if defined(PNG_sPLT_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_sPLT) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_sPLT_tpp entries)); +#endif + +#if defined(PNG_sPLT_SUPPORTED) +extern PNG_EXPORT(void,png_set_sPLT) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_sPLT_tp entries, int nentries)); +#endif + +#if defined(PNG_TEXT_SUPPORTED) +/* png_get_text also returns the number of text chunks in *num_text */ +extern PNG_EXPORT(png_uint_32,png_get_text) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_textp *text_ptr, int *num_text)); +#endif + +/* + * Note while png_set_text() will accept a structure whose text, + * language, and translated keywords are NULL pointers, the structure + * returned by png_get_text will always contain regular + * zero-terminated C strings. They might be empty strings but + * they will never be NULL pointers. + */ + +#if defined(PNG_TEXT_SUPPORTED) +extern PNG_EXPORT(void,png_set_text) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_textp text_ptr, int num_text)); +#endif + +#if defined(PNG_tIME_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_tIME) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_timep *mod_time)); +#endif + +#if defined(PNG_tIME_SUPPORTED) +extern PNG_EXPORT(void,png_set_tIME) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_timep mod_time)); +#endif + +#if defined(PNG_tRNS_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_tRNS) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_bytep *trans, int *num_trans, + png_color_16p *trans_values)); +#endif + +#if defined(PNG_tRNS_SUPPORTED) +extern PNG_EXPORT(void,png_set_tRNS) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_bytep trans, int num_trans, + png_color_16p trans_values)); +#endif + +#if defined(PNG_tRNS_SUPPORTED) +#endif + +#if defined(PNG_sCAL_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_sCAL) PNGARG((png_structp png_ptr, + png_infop info_ptr, int *unit, double *width, double *height)); +#else +#ifdef PNG_FIXED_POINT_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_sCAL_s) PNGARG((png_structp png_ptr, + png_infop info_ptr, int *unit, png_charpp swidth, png_charpp sheight)); +#endif +#endif +#endif /* PNG_sCAL_SUPPORTED */ + +#if defined(PNG_sCAL_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_sCAL) PNGARG((png_structp png_ptr, + png_infop info_ptr, int unit, double width, double height)); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_sCAL_s) PNGARG((png_structp png_ptr, + png_infop info_ptr, int unit, png_charp swidth, png_charp sheight)); +#endif +#endif /* PNG_sCAL_SUPPORTED || PNG_WRITE_sCAL_SUPPORTED */ + +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) +/* provide a list of chunks and how they are to be handled, if the built-in + handling or default unknown chunk handling is not desired. Any chunks not + listed will be handled in the default manner. The IHDR and IEND chunks + must not be listed. + keep = 0: follow default behavour + = 1: do not keep + = 2: keep only if safe-to-copy + = 3: keep even if unsafe-to-copy +*/ +extern PNG_EXPORT(void, png_set_keep_unknown_chunks) PNGARG((png_structp + png_ptr, int keep, png_bytep chunk_list, int num_chunks)); +extern PNG_EXPORT(void, png_set_unknown_chunks) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_unknown_chunkp unknowns, int num_unknowns)); +extern PNG_EXPORT(void, png_set_unknown_chunk_location) + PNGARG((png_structp png_ptr, png_infop info_ptr, int chunk, int location)); +extern PNG_EXPORT(png_uint_32,png_get_unknown_chunks) PNGARG((png_structp + png_ptr, png_infop info_ptr, png_unknown_chunkpp entries)); +#endif +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +PNG_EXPORT(int,png_handle_as_unknown) PNGARG((png_structp png_ptr, png_bytep + chunk_name)); +#endif + +/* Png_free_data() will turn off the "valid" flag for anything it frees. + If you need to turn it off for a chunk that your application has freed, + you can use png_set_invalid(png_ptr, info_ptr, PNG_INFO_CHNK); */ +extern PNG_EXPORT(void, png_set_invalid) PNGARG((png_structp png_ptr, + png_infop info_ptr, int mask)); + +#if defined(PNG_INFO_IMAGE_SUPPORTED) +/* The "params" pointer is currently not used and is for future expansion. */ +extern PNG_EXPORT(void, png_read_png) PNGARG((png_structp png_ptr, + png_infop info_ptr, + int transforms, + png_voidp params)); +extern PNG_EXPORT(void, png_write_png) PNGARG((png_structp png_ptr, + png_infop info_ptr, + int transforms, + png_voidp params)); +#endif + +/* Define PNG_DEBUG at compile time for debugging information. Higher + * numbers for PNG_DEBUG mean more debugging information. This has + * only been added since version 0.95 so it is not implemented throughout + * libpng yet, but more support will be added as needed. + */ +#ifdef PNG_DEBUG +#if (PNG_DEBUG > 0) +#if !defined(PNG_DEBUG_FILE) && defined(_MSC_VER) +#include +#if (PNG_DEBUG > 1) +#define png_debug(l,m) _RPT0(_CRT_WARN,m) +#define png_debug1(l,m,p1) _RPT1(_CRT_WARN,m,p1) +#define png_debug2(l,m,p1,p2) _RPT2(_CRT_WARN,m,p1,p2) +#endif +#else /* PNG_DEBUG_FILE || !_MSC_VER */ +#ifndef PNG_DEBUG_FILE +#define PNG_DEBUG_FILE stderr +#endif /* PNG_DEBUG_FILE */ +#if (PNG_DEBUG > 1) +#define png_debug(l,m) \ +{ \ + int num_tabs=l; \ + fprintf(PNG_DEBUG_FILE,"%s"m,(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":"")))); \ +} +#define png_debug1(l,m,p1) \ +{ \ + int num_tabs=l; \ + fprintf(PNG_DEBUG_FILE,"%s"m,(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1); \ +} +#define png_debug2(l,m,p1,p2) \ +{ \ + int num_tabs=l; \ + fprintf(PNG_DEBUG_FILE,"%s"m,(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1,p2); \ +} +#endif /* (PNG_DEBUG > 1) */ +#endif /* _MSC_VER */ +#endif /* (PNG_DEBUG > 0) */ +#endif /* PNG_DEBUG */ +#ifndef png_debug +#define png_debug(l, m) +#endif +#ifndef png_debug1 +#define png_debug1(l, m, p1) +#endif +#ifndef png_debug2 +#define png_debug2(l, m, p1, p2) +#endif + +extern PNG_EXPORT(png_bytep,png_sig_bytes) PNGARG((void)); + +extern PNG_EXPORT(png_charp,png_get_copyright) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(png_charp,png_get_header_ver) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(png_charp,png_get_header_version) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(png_charp,png_get_libpng_ver) PNGARG((png_structp png_ptr)); + +#ifdef PNG_MNG_FEATURES_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_permit_mng_features) PNGARG((png_structp + png_ptr, png_uint_32 mng_features_permitted)); +#endif + +/* Added to version 1.2.0 */ +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) +#define PNG_ASM_FLAG_MMX_SUPPORT_COMPILED 0x01 /* not user-settable */ +#define PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU 0x02 /* not user-settable */ +#define PNG_ASM_FLAG_MMX_READ_COMBINE_ROW 0x04 +#define PNG_ASM_FLAG_MMX_READ_INTERLACE 0x08 +#define PNG_ASM_FLAG_MMX_READ_FILTER_SUB 0x10 +#define PNG_ASM_FLAG_MMX_READ_FILTER_UP 0x20 +#define PNG_ASM_FLAG_MMX_READ_FILTER_AVG 0x40 +#define PNG_ASM_FLAG_MMX_READ_FILTER_PAETH 0x80 +#define PNG_ASM_FLAGS_INITIALIZED 0x80000000 /* not user-settable */ + +#define PNG_MMX_READ_FLAGS ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \ + | PNG_ASM_FLAG_MMX_READ_INTERLACE \ + | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \ + | PNG_ASM_FLAG_MMX_READ_FILTER_UP \ + | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \ + | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH ) +#define PNG_MMX_WRITE_FLAGS ( 0 ) + +#define PNG_MMX_FLAGS ( PNG_ASM_FLAG_MMX_SUPPORT_COMPILED \ + | PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU \ + | PNG_MMX_READ_FLAGS \ + | PNG_MMX_WRITE_FLAGS ) + +#define PNG_SELECT_READ 1 +#define PNG_SELECT_WRITE 2 + + +#if !defined(PNG_1_0_X) +/* pngget.c */ +extern PNG_EXPORT(png_uint_32,png_get_mmx_flagmask) + PNGARG((int flag_select, int *compilerID)); + +/* pngget.c */ +extern PNG_EXPORT(png_uint_32,png_get_asm_flagmask) + PNGARG((int flag_select)); + +/* pngget.c */ +extern PNG_EXPORT(png_uint_32,png_get_asm_flags) + PNGARG((png_structp png_ptr)); + +/* pngget.c */ +extern PNG_EXPORT(png_byte,png_get_mmx_bitdepth_threshold) + PNGARG((png_structp png_ptr)); + +/* pngget.c */ +extern PNG_EXPORT(png_uint_32,png_get_mmx_rowbytes_threshold) + PNGARG((png_structp png_ptr)); + +/* pngset.c */ +extern PNG_EXPORT(void,png_set_asm_flags) + PNGARG((png_structp png_ptr, png_uint_32 asm_flags)); + +/* pngset.c */ +extern PNG_EXPORT(void,png_set_mmx_thresholds) + PNGARG((png_structp png_ptr, png_byte mmx_bitdepth_threshold, + png_uint_32 mmx_rowbytes_threshold)); + +#endif /* PNG_1_0_X */ +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ + +#if !defined(PNG_1_0_X) +/* png.c, pnggccrd.c, or pngvcrd.c */ +extern PNG_EXPORT(int,png_mmx_support) PNGARG((void)); + +/* Strip the prepended error numbers ("#nnn ") from error and warning + * messages before passing them to the error or warning handler. */ +#ifdef PNG_ERROR_NUMBERS_SUPPORTED +extern PNG_EXPORT(void,png_set_strip_error_numbers) PNGARG((png_structp + png_ptr, png_uint_32 strip_mode)); +#endif +#endif /* PNG_1_0_X */ + +/* Maintainer: Put new public prototypes here ^, in libpng.3, and project defs */ + +#define PNG_HEADER_VERSION_STRING \ + " libpng version 1.2.5 - October 3, 2002 (header)\n" + +#ifdef PNG_READ_COMPOSITE_NODIV_SUPPORTED +/* With these routines we avoid an integer divide, which will be slower on + * most machines. However, it does take more operations than the corresponding + * divide method, so it may be slower on a few RISC systems. There are two + * shifts (by 8 or 16 bits) and an addition, versus a single integer divide. + * + * Note that the rounding factors are NOT supposed to be the same! 128 and + * 32768 are correct for the NODIV code; 127 and 32767 are correct for the + * standard method. + * + * [Optimized code by Greg Roelofs and Mark Adler...blame us for bugs. :-) ] + */ + + /* fg and bg should be in `gamma 1.0' space; alpha is the opacity */ + +# define png_composite(composite, fg, alpha, bg) \ + { png_uint_16 temp = (png_uint_16)((png_uint_16)(fg) * (png_uint_16)(alpha) \ + + (png_uint_16)(bg)*(png_uint_16)(255 - \ + (png_uint_16)(alpha)) + (png_uint_16)128); \ + (composite) = (png_byte)((temp + (temp >> 8)) >> 8); } + +# define png_composite_16(composite, fg, alpha, bg) \ + { png_uint_32 temp = (png_uint_32)((png_uint_32)(fg) * (png_uint_32)(alpha) \ + + (png_uint_32)(bg)*(png_uint_32)(65535L - \ + (png_uint_32)(alpha)) + (png_uint_32)32768L); \ + (composite) = (png_uint_16)((temp + (temp >> 16)) >> 16); } + +#else /* standard method using integer division */ + +# define png_composite(composite, fg, alpha, bg) \ + (composite) = (png_byte)(((png_uint_16)(fg) * (png_uint_16)(alpha) + \ + (png_uint_16)(bg) * (png_uint_16)(255 - (png_uint_16)(alpha)) + \ + (png_uint_16)127) / 255) + +# define png_composite_16(composite, fg, alpha, bg) \ + (composite) = (png_uint_16)(((png_uint_32)(fg) * (png_uint_32)(alpha) + \ + (png_uint_32)(bg)*(png_uint_32)(65535L - (png_uint_32)(alpha)) + \ + (png_uint_32)32767) / (png_uint_32)65535L) + +#endif /* PNG_READ_COMPOSITE_NODIV_SUPPORTED */ + +/* These next functions are used internally in the code. They generally + * shouldn't be used unless you are writing code to add or replace some + * functionality in libpng. More information about most functions can + * be found in the files where the functions are located. + */ + +#if defined(PNG_INTERNAL) + +/* Various modes of operation. Note that after an init, mode is set to + * zero automatically when the structure is created. + */ +#define PNG_HAVE_IHDR 0x01 +#define PNG_HAVE_PLTE 0x02 +#define PNG_HAVE_IDAT 0x04 +#define PNG_AFTER_IDAT 0x08 +#define PNG_HAVE_IEND 0x10 +#define PNG_HAVE_gAMA 0x20 +#define PNG_HAVE_cHRM 0x40 +#define PNG_HAVE_sRGB 0x80 +#define PNG_HAVE_CHUNK_HEADER 0x100 +#define PNG_WROTE_tIME 0x200 +#define PNG_WROTE_INFO_BEFORE_PLTE 0x400 +#define PNG_BACKGROUND_IS_GRAY 0x800 +#define PNG_HAVE_PNG_SIGNATURE 0x1000 + +/* flags for the transformations the PNG library does on the image data */ +#define PNG_BGR 0x0001 +#define PNG_INTERLACE 0x0002 +#define PNG_PACK 0x0004 +#define PNG_SHIFT 0x0008 +#define PNG_SWAP_BYTES 0x0010 +#define PNG_INVERT_MONO 0x0020 +#define PNG_DITHER 0x0040 +#define PNG_BACKGROUND 0x0080 +#define PNG_BACKGROUND_EXPAND 0x0100 + /* 0x0200 unused */ +#define PNG_16_TO_8 0x0400 +#define PNG_RGBA 0x0800 +#define PNG_EXPAND 0x1000 +#define PNG_GAMMA 0x2000 +#define PNG_GRAY_TO_RGB 0x4000 +#define PNG_FILLER 0x8000L +#define PNG_PACKSWAP 0x10000L +#define PNG_SWAP_ALPHA 0x20000L +#define PNG_STRIP_ALPHA 0x40000L +#define PNG_INVERT_ALPHA 0x80000L +#define PNG_USER_TRANSFORM 0x100000L +#define PNG_RGB_TO_GRAY_ERR 0x200000L +#define PNG_RGB_TO_GRAY_WARN 0x400000L +#define PNG_RGB_TO_GRAY 0x600000L /* two bits, RGB_TO_GRAY_ERR|WARN */ + +/* flags for png_create_struct */ +#define PNG_STRUCT_PNG 0x0001 +#define PNG_STRUCT_INFO 0x0002 + +/* Scaling factor for filter heuristic weighting calculations */ +#define PNG_WEIGHT_SHIFT 8 +#define PNG_WEIGHT_FACTOR (1<<(PNG_WEIGHT_SHIFT)) +#define PNG_COST_SHIFT 3 +#define PNG_COST_FACTOR (1<<(PNG_COST_SHIFT)) + +/* flags for the png_ptr->flags rather than declaring a byte for each one */ +#define PNG_FLAG_ZLIB_CUSTOM_STRATEGY 0x0001 +#define PNG_FLAG_ZLIB_CUSTOM_LEVEL 0x0002 +#define PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL 0x0004 +#define PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS 0x0008 +#define PNG_FLAG_ZLIB_CUSTOM_METHOD 0x0010 +#define PNG_FLAG_ZLIB_FINISHED 0x0020 +#define PNG_FLAG_ROW_INIT 0x0040 +#define PNG_FLAG_FILLER_AFTER 0x0080 +#define PNG_FLAG_CRC_ANCILLARY_USE 0x0100 +#define PNG_FLAG_CRC_ANCILLARY_NOWARN 0x0200 +#define PNG_FLAG_CRC_CRITICAL_USE 0x0400 +#define PNG_FLAG_CRC_CRITICAL_IGNORE 0x0800 +#define PNG_FLAG_FREE_PLTE 0x1000 +#define PNG_FLAG_FREE_TRNS 0x2000 +#define PNG_FLAG_FREE_HIST 0x4000 +#define PNG_FLAG_KEEP_UNKNOWN_CHUNKS 0x8000L +#define PNG_FLAG_KEEP_UNSAFE_CHUNKS 0x10000L +#define PNG_FLAG_LIBRARY_MISMATCH 0x20000L +#define PNG_FLAG_STRIP_ERROR_NUMBERS 0x40000L +#define PNG_FLAG_STRIP_ERROR_TEXT 0x80000L +#define PNG_FLAG_MALLOC_NULL_MEM_OK 0x100000L + +/* For use in png_set_keep_unknown, png_handle_as_unknown */ +#define HANDLE_CHUNK_AS_DEFAULT 0 +#define HANDLE_CHUNK_NEVER 1 +#define HANDLE_CHUNK_IF_SAFE 2 +#define HANDLE_CHUNK_ALWAYS 3 + +#define PNG_FLAG_CRC_ANCILLARY_MASK (PNG_FLAG_CRC_ANCILLARY_USE | \ + PNG_FLAG_CRC_ANCILLARY_NOWARN) + +#define PNG_FLAG_CRC_CRITICAL_MASK (PNG_FLAG_CRC_CRITICAL_USE | \ + PNG_FLAG_CRC_CRITICAL_IGNORE) + +#define PNG_FLAG_CRC_MASK (PNG_FLAG_CRC_ANCILLARY_MASK | \ + PNG_FLAG_CRC_CRITICAL_MASK) + +/* save typing and make code easier to understand */ +#define PNG_COLOR_DIST(c1, c2) (abs((int)((c1).red) - (int)((c2).red)) + \ + abs((int)((c1).green) - (int)((c2).green)) + \ + abs((int)((c1).blue) - (int)((c2).blue))) + +/* variables declared in png.c - only it needs to define PNG_NO_EXTERN */ +#if !defined(PNG_NO_EXTERN) || defined(PNG_ALWAYS_EXTERN) +/* place to hold the signature string for a PNG file. */ +#ifdef PNG_USE_GLOBAL_ARRAYS + PNG_EXPORT_VAR (const png_byte FARDATA) png_sig[8]; +#else +#define png_sig png_sig_bytes(NULL) +#endif +#endif /* PNG_NO_EXTERN */ + +/* Constant strings for known chunk types. If you need to add a chunk, + * define the name here, and add an invocation of the macro in png.c and + * wherever it's needed. + */ +#define PNG_IHDR const png_byte png_IHDR[5] = { 73, 72, 68, 82, '\0'} +#define PNG_IDAT const png_byte png_IDAT[5] = { 73, 68, 65, 84, '\0'} +#define PNG_IEND const png_byte png_IEND[5] = { 73, 69, 78, 68, '\0'} +#define PNG_PLTE const png_byte png_PLTE[5] = { 80, 76, 84, 69, '\0'} +#define PNG_bKGD const png_byte png_bKGD[5] = { 98, 75, 71, 68, '\0'} +#define PNG_cHRM const png_byte png_cHRM[5] = { 99, 72, 82, 77, '\0'} +#define PNG_gAMA const png_byte png_gAMA[5] = {103, 65, 77, 65, '\0'} +#define PNG_hIST const png_byte png_hIST[5] = {104, 73, 83, 84, '\0'} +#define PNG_iCCP const png_byte png_iCCP[5] = {105, 67, 67, 80, '\0'} +#define PNG_iTXt const png_byte png_iTXt[5] = {105, 84, 88, 116, '\0'} +#define PNG_oFFs const png_byte png_oFFs[5] = {111, 70, 70, 115, '\0'} +#define PNG_pCAL const png_byte png_pCAL[5] = {112, 67, 65, 76, '\0'} +#define PNG_sCAL const png_byte png_sCAL[5] = {115, 67, 65, 76, '\0'} +#define PNG_pHYs const png_byte png_pHYs[5] = {112, 72, 89, 115, '\0'} +#define PNG_sBIT const png_byte png_sBIT[5] = {115, 66, 73, 84, '\0'} +#define PNG_sPLT const png_byte png_sPLT[5] = {115, 80, 76, 84, '\0'} +#define PNG_sRGB const png_byte png_sRGB[5] = {115, 82, 71, 66, '\0'} +#define PNG_tEXt const png_byte png_tEXt[5] = {116, 69, 88, 116, '\0'} +#define PNG_tIME const png_byte png_tIME[5] = {116, 73, 77, 69, '\0'} +#define PNG_tRNS const png_byte png_tRNS[5] = {116, 82, 78, 83, '\0'} +#define PNG_zTXt const png_byte png_zTXt[5] = {122, 84, 88, 116, '\0'} + +#ifdef PNG_USE_GLOBAL_ARRAYS +PNG_EXPORT_VAR (const png_byte FARDATA) png_IHDR[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_IDAT[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_IEND[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_PLTE[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_bKGD[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_cHRM[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_gAMA[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_hIST[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_iCCP[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_iTXt[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_oFFs[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_pCAL[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_sCAL[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_pHYs[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_sBIT[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_sPLT[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_sRGB[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_tEXt[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_tIME[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_tRNS[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_zTXt[5]; +#endif /* PNG_USE_GLOBAL_ARRAYS */ + + +/* Inline macros to do direct reads of bytes from the input buffer. These + * require that you are using an architecture that uses PNG byte ordering + * (MSB first) and supports unaligned data storage. I think that PowerPC + * in big-endian mode and 680x0 are the only ones that will support this. + * The x86 line of processors definitely do not. The png_get_int_32() + * routine also assumes we are using two's complement format for negative + * values, which is almost certainly true. + */ +#if defined(PNG_READ_BIG_ENDIAN_SUPPORTED) +# if defined(PNG_pCAL_SUPPORTED) || defined(PNG_oFFs_SUPPORTED) +# define png_get_int_32(buf) ( *((png_int_32p) (buf))) +# endif +# define png_get_uint_32(buf) ( *((png_uint_32p) (buf))) +# define png_get_uint_16(buf) ( *((png_uint_16p) (buf))) +#else +# if defined(PNG_pCAL_SUPPORTED) || defined(PNG_oFFs_SUPPORTED) +PNG_EXTERN png_int_32 png_get_int_32 PNGARG((png_bytep buf)); +# endif +PNG_EXTERN png_uint_32 png_get_uint_32 PNGARG((png_bytep buf)); +PNG_EXTERN png_uint_16 png_get_uint_16 PNGARG((png_bytep buf)); +#endif /* !PNG_READ_BIG_ENDIAN_SUPPORTED */ + +/* Initialize png_ptr struct for reading, and allocate any other memory. + * (old interface - DEPRECATED - use png_create_read_struct instead). + */ +extern PNG_EXPORT(void,png_read_init) PNGARG((png_structp png_ptr)); +#undef png_read_init +#define png_read_init(png_ptr) png_read_init_3(&png_ptr, \ + PNG_LIBPNG_VER_STRING, sizeof(png_struct)); +extern PNG_EXPORT(void,png_read_init_3) PNGARG((png_structpp ptr_ptr, + png_const_charp user_png_ver, png_size_t png_struct_size)); +extern PNG_EXPORT(void,png_read_init_2) PNGARG((png_structp png_ptr, + png_const_charp user_png_ver, png_size_t png_struct_size, png_size_t + png_info_size)); + +/* Initialize png_ptr struct for writing, and allocate any other memory. + * (old interface - DEPRECATED - use png_create_write_struct instead). + */ +extern PNG_EXPORT(void,png_write_init) PNGARG((png_structp png_ptr)); +#undef png_write_init +#define png_write_init(png_ptr) png_write_init_3(&png_ptr, \ + PNG_LIBPNG_VER_STRING, sizeof(png_struct)); +extern PNG_EXPORT(void,png_write_init_3) PNGARG((png_structpp ptr_ptr, + png_const_charp user_png_ver, png_size_t png_struct_size)); +extern PNG_EXPORT(void,png_write_init_2) PNGARG((png_structp png_ptr, + png_const_charp user_png_ver, png_size_t png_struct_size, png_size_t + png_info_size)); + +/* Allocate memory for an internal libpng struct */ +PNG_EXTERN png_voidp png_create_struct PNGARG((int type)); + +/* Free memory from internal libpng struct */ +PNG_EXTERN void png_destroy_struct PNGARG((png_voidp struct_ptr)); + +PNG_EXTERN png_voidp png_create_struct_2 PNGARG((int type, png_malloc_ptr + malloc_fn, png_voidp mem_ptr)); +PNG_EXTERN void png_destroy_struct_2 PNGARG((png_voidp struct_ptr, + png_free_ptr free_fn, png_voidp mem_ptr)); + +/* Free any memory that info_ptr points to and reset struct. */ +PNG_EXTERN void png_info_destroy PNGARG((png_structp png_ptr, + png_infop info_ptr)); + +#ifndef PNG_1_0_X +/* Function to allocate memory for zlib. */ +PNG_EXTERN voidpf png_zalloc PNGARG((voidpf png_ptr, uInt items, uInt size)); + +/* Function to free memory for zlib */ +PNG_EXTERN void png_zfree PNGARG((voidpf png_ptr, voidpf ptr)); + +/* Next four functions are used internally as callbacks. PNGAPI is required + * but not PNG_EXPORT. PNGAPI added at libpng version 1.2.3. */ + +PNG_EXTERN void PNGAPI png_default_read_data PNGARG((png_structp png_ptr, + png_bytep data, png_size_t length)); + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +PNG_EXTERN void PNGAPI png_push_fill_buffer PNGARG((png_structp png_ptr, + png_bytep buffer, png_size_t length)); +#endif + +PNG_EXTERN void PNGAPI png_default_write_data PNGARG((png_structp png_ptr, + png_bytep data, png_size_t length)); + +#if defined(PNG_WRITE_FLUSH_SUPPORTED) +#if !defined(PNG_NO_STDIO) +PNG_EXTERN void PNGAPI png_default_flush PNGARG((png_structp png_ptr)); +#endif +#endif +#else /* PNG_1_0_X */ +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +PNG_EXTERN void png_push_fill_buffer PNGARG((png_structp png_ptr, + png_bytep buffer, png_size_t length)); +#endif +#endif /* PNG_1_0_X */ + +/* Reset the CRC variable */ +PNG_EXTERN void png_reset_crc PNGARG((png_structp png_ptr)); + +/* Write the "data" buffer to whatever output you are using. */ +PNG_EXTERN void png_write_data PNGARG((png_structp png_ptr, png_bytep data, + png_size_t length)); + +/* Read data from whatever input you are using into the "data" buffer */ +PNG_EXTERN void png_read_data PNGARG((png_structp png_ptr, png_bytep data, + png_size_t length)); + +/* Read bytes into buf, and update png_ptr->crc */ +PNG_EXTERN void png_crc_read PNGARG((png_structp png_ptr, png_bytep buf, + png_size_t length)); + +/* Decompress data in a chunk that uses compression */ +#if defined(PNG_zTXt_SUPPORTED) || defined(PNG_iTXt_SUPPORTED) || \ + defined(PNG_iCCP_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) +PNG_EXTERN png_charp png_decompress_chunk PNGARG((png_structp png_ptr, + int comp_type, png_charp chunkdata, png_size_t chunklength, + png_size_t prefix_length, png_size_t *data_length)); +#endif + +/* Read "skip" bytes, read the file crc, and (optionally) verify png_ptr->crc */ +PNG_EXTERN int png_crc_finish PNGARG((png_structp png_ptr, png_uint_32 skip)); + +/* Read the CRC from the file and compare it to the libpng calculated CRC */ +PNG_EXTERN int png_crc_error PNGARG((png_structp png_ptr)); + +/* Calculate the CRC over a section of data. Note that we are only + * passing a maximum of 64K on systems that have this as a memory limit, + * since this is the maximum buffer size we can specify. + */ +PNG_EXTERN void png_calculate_crc PNGARG((png_structp png_ptr, png_bytep ptr, + png_size_t length)); + +#if defined(PNG_WRITE_FLUSH_SUPPORTED) +PNG_EXTERN void png_flush PNGARG((png_structp png_ptr)); +#endif + + +/* Place a 32-bit number into a buffer in PNG byte order (big-endian). + * The only currently known PNG chunks that use signed numbers are + * the ancillary extension chunks, oFFs and pCAL. + */ +PNG_EXTERN void png_save_uint_32 PNGARG((png_bytep buf, png_uint_32 i)); + +#if defined(PNG_WRITE_pCAL_SUPPORTED) || defined(PNG_WRITE_oFFs_SUPPORTED) +PNG_EXTERN void png_save_int_32 PNGARG((png_bytep buf, png_int_32 i)); +#endif + +/* Place a 16-bit number into a buffer in PNG byte order. + * The parameter is declared unsigned int, not png_uint_16, + * just to avoid potential problems on pre-ANSI C compilers. + */ +PNG_EXTERN void png_save_uint_16 PNGARG((png_bytep buf, unsigned int i)); + +/* simple function to write the signature */ +PNG_EXTERN void png_write_sig PNGARG((png_structp png_ptr)); + +/* write various chunks */ + +/* Write the IHDR chunk, and update the png_struct with the necessary + * information. + */ +PNG_EXTERN void png_write_IHDR PNGARG((png_structp png_ptr, png_uint_32 width, + png_uint_32 height, + int bit_depth, int color_type, int compression_method, int filter_method, + int interlace_method)); + +PNG_EXTERN void png_write_PLTE PNGARG((png_structp png_ptr, png_colorp palette, + png_uint_32 num_pal)); + +PNG_EXTERN void png_write_IDAT PNGARG((png_structp png_ptr, png_bytep data, + png_size_t length)); + +PNG_EXTERN void png_write_IEND PNGARG((png_structp png_ptr)); + +#if defined(PNG_WRITE_gAMA_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +PNG_EXTERN void png_write_gAMA PNGARG((png_structp png_ptr, double file_gamma)); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +PNG_EXTERN void png_write_gAMA_fixed PNGARG((png_structp png_ptr, png_fixed_point + file_gamma)); +#endif +#endif + +#if defined(PNG_WRITE_sBIT_SUPPORTED) +PNG_EXTERN void png_write_sBIT PNGARG((png_structp png_ptr, png_color_8p sbit, + int color_type)); +#endif + +#if defined(PNG_WRITE_cHRM_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +PNG_EXTERN void png_write_cHRM PNGARG((png_structp png_ptr, + double white_x, double white_y, + double red_x, double red_y, double green_x, double green_y, + double blue_x, double blue_y)); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +PNG_EXTERN void png_write_cHRM_fixed PNGARG((png_structp png_ptr, + png_fixed_point int_white_x, png_fixed_point int_white_y, + png_fixed_point int_red_x, png_fixed_point int_red_y, png_fixed_point + int_green_x, png_fixed_point int_green_y, png_fixed_point int_blue_x, + png_fixed_point int_blue_y)); +#endif +#endif + +#if defined(PNG_WRITE_sRGB_SUPPORTED) +PNG_EXTERN void png_write_sRGB PNGARG((png_structp png_ptr, + int intent)); +#endif + +#if defined(PNG_WRITE_iCCP_SUPPORTED) +PNG_EXTERN void png_write_iCCP PNGARG((png_structp png_ptr, + png_charp name, int compression_type, + png_charp profile, int proflen)); + /* Note to maintainer: profile should be png_bytep */ +#endif + +#if defined(PNG_WRITE_sPLT_SUPPORTED) +PNG_EXTERN void png_write_sPLT PNGARG((png_structp png_ptr, + png_sPLT_tp palette)); +#endif + +#if defined(PNG_WRITE_tRNS_SUPPORTED) +PNG_EXTERN void png_write_tRNS PNGARG((png_structp png_ptr, png_bytep trans, + png_color_16p values, int number, int color_type)); +#endif + +#if defined(PNG_WRITE_bKGD_SUPPORTED) +PNG_EXTERN void png_write_bKGD PNGARG((png_structp png_ptr, + png_color_16p values, int color_type)); +#endif + +#if defined(PNG_WRITE_hIST_SUPPORTED) +PNG_EXTERN void png_write_hIST PNGARG((png_structp png_ptr, png_uint_16p hist, + int num_hist)); +#endif + +#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \ + defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) +PNG_EXTERN png_size_t png_check_keyword PNGARG((png_structp png_ptr, + png_charp key, png_charpp new_key)); +#endif + +#if defined(PNG_WRITE_tEXt_SUPPORTED) +PNG_EXTERN void png_write_tEXt PNGARG((png_structp png_ptr, png_charp key, + png_charp text, png_size_t text_len)); +#endif + +#if defined(PNG_WRITE_zTXt_SUPPORTED) +PNG_EXTERN void png_write_zTXt PNGARG((png_structp png_ptr, png_charp key, + png_charp text, png_size_t text_len, int compression)); +#endif + +#if defined(PNG_WRITE_iTXt_SUPPORTED) +PNG_EXTERN void png_write_iTXt PNGARG((png_structp png_ptr, + int compression, png_charp key, png_charp lang, png_charp lang_key, + png_charp text)); +#endif + +#if defined(PNG_TEXT_SUPPORTED) /* Added at version 1.0.14 and 1.2.4 */ +PNG_EXTERN int png_set_text_2 PNGARG((png_structp png_ptr, + png_infop info_ptr, png_textp text_ptr, int num_text)); +#endif + +#if defined(PNG_WRITE_oFFs_SUPPORTED) +PNG_EXTERN void png_write_oFFs PNGARG((png_structp png_ptr, + png_int_32 x_offset, png_int_32 y_offset, int unit_type)); +#endif + +#if defined(PNG_WRITE_pCAL_SUPPORTED) +PNG_EXTERN void png_write_pCAL PNGARG((png_structp png_ptr, png_charp purpose, + png_int_32 X0, png_int_32 X1, int type, int nparams, + png_charp units, png_charpp params)); +#endif + +#if defined(PNG_WRITE_pHYs_SUPPORTED) +PNG_EXTERN void png_write_pHYs PNGARG((png_structp png_ptr, + png_uint_32 x_pixels_per_unit, png_uint_32 y_pixels_per_unit, + int unit_type)); +#endif + +#if defined(PNG_WRITE_tIME_SUPPORTED) +PNG_EXTERN void png_write_tIME PNGARG((png_structp png_ptr, + png_timep mod_time)); +#endif + +#if defined(PNG_WRITE_sCAL_SUPPORTED) +#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO) +PNG_EXTERN void png_write_sCAL PNGARG((png_structp png_ptr, + int unit, double width, double height)); +#else +#ifdef PNG_FIXED_POINT_SUPPORTED +PNG_EXTERN void png_write_sCAL_s PNGARG((png_structp png_ptr, + int unit, png_charp width, png_charp height)); +#endif +#endif +#endif + +/* Called when finished processing a row of data */ +PNG_EXTERN void png_write_finish_row PNGARG((png_structp png_ptr)); + +/* Internal use only. Called before first row of data */ +PNG_EXTERN void png_write_start_row PNGARG((png_structp png_ptr)); + +#if defined(PNG_READ_GAMMA_SUPPORTED) +PNG_EXTERN void png_build_gamma_table PNGARG((png_structp png_ptr)); +#endif + +/* combine a row of data, dealing with alpha, etc. if requested */ +PNG_EXTERN void png_combine_row PNGARG((png_structp png_ptr, png_bytep row, + int mask)); + +#if defined(PNG_READ_INTERLACING_SUPPORTED) +/* expand an interlaced row */ +/* OLD pre-1.0.9 interface: +PNG_EXTERN void png_do_read_interlace PNGARG((png_row_infop row_info, + png_bytep row, int pass, png_uint_32 transformations)); + */ +PNG_EXTERN void png_do_read_interlace PNGARG((png_structp png_ptr)); +#endif + +/* GRR TO DO (2.0 or whenever): simplify other internal calling interfaces */ + +#if defined(PNG_WRITE_INTERLACING_SUPPORTED) +/* grab pixels out of a row for an interlaced pass */ +PNG_EXTERN void png_do_write_interlace PNGARG((png_row_infop row_info, + png_bytep row, int pass)); +#endif + +/* unfilter a row */ +PNG_EXTERN void png_read_filter_row PNGARG((png_structp png_ptr, + png_row_infop row_info, png_bytep row, png_bytep prev_row, int filter)); + +/* Choose the best filter to use and filter the row data */ +PNG_EXTERN void png_write_find_filter PNGARG((png_structp png_ptr, + png_row_infop row_info)); + +/* Write out the filtered row. */ +PNG_EXTERN void png_write_filtered_row PNGARG((png_structp png_ptr, + png_bytep filtered_row)); +/* finish a row while reading, dealing with interlacing passes, etc. */ +PNG_EXTERN void png_read_finish_row PNGARG((png_structp png_ptr)); + +/* initialize the row buffers, etc. */ +PNG_EXTERN void png_read_start_row PNGARG((png_structp png_ptr)); +/* optional call to update the users info structure */ +PNG_EXTERN void png_read_transform_info PNGARG((png_structp png_ptr, + png_infop info_ptr)); + +/* these are the functions that do the transformations */ +#if defined(PNG_READ_FILLER_SUPPORTED) +PNG_EXTERN void png_do_read_filler PNGARG((png_row_infop row_info, + png_bytep row, png_uint_32 filler, png_uint_32 flags)); +#endif + +#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) +PNG_EXTERN void png_do_read_swap_alpha PNGARG((png_row_infop row_info, + png_bytep row)); +#endif + +#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) +PNG_EXTERN void png_do_write_swap_alpha PNGARG((png_row_infop row_info, + png_bytep row)); +#endif + +#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) +PNG_EXTERN void png_do_read_invert_alpha PNGARG((png_row_infop row_info, + png_bytep row)); +#endif + +#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) +PNG_EXTERN void png_do_write_invert_alpha PNGARG((png_row_infop row_info, + png_bytep row)); +#endif + +#if defined(PNG_WRITE_FILLER_SUPPORTED) || \ + defined(PNG_READ_STRIP_ALPHA_SUPPORTED) +PNG_EXTERN void png_do_strip_filler PNGARG((png_row_infop row_info, + png_bytep row, png_uint_32 flags)); +#endif + +#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) +PNG_EXTERN void png_do_swap PNGARG((png_row_infop row_info, png_bytep row)); +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) || defined(PNG_WRITE_PACKSWAP_SUPPORTED) +PNG_EXTERN void png_do_packswap PNGARG((png_row_infop row_info, png_bytep row)); +#endif + +#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) +PNG_EXTERN int png_do_rgb_to_gray PNGARG((png_structp png_ptr, png_row_infop + row_info, png_bytep row)); +#endif + +#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) +PNG_EXTERN void png_do_gray_to_rgb PNGARG((png_row_infop row_info, + png_bytep row)); +#endif + +#if defined(PNG_READ_PACK_SUPPORTED) +PNG_EXTERN void png_do_unpack PNGARG((png_row_infop row_info, png_bytep row)); +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) +PNG_EXTERN void png_do_unshift PNGARG((png_row_infop row_info, png_bytep row, + png_color_8p sig_bits)); +#endif + +#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) +PNG_EXTERN void png_do_invert PNGARG((png_row_infop row_info, png_bytep row)); +#endif + +#if defined(PNG_READ_16_TO_8_SUPPORTED) +PNG_EXTERN void png_do_chop PNGARG((png_row_infop row_info, png_bytep row)); +#endif + +#if defined(PNG_READ_DITHER_SUPPORTED) +PNG_EXTERN void png_do_dither PNGARG((png_row_infop row_info, + png_bytep row, png_bytep palette_lookup, png_bytep dither_lookup)); + +# if defined(PNG_CORRECT_PALETTE_SUPPORTED) +PNG_EXTERN void png_correct_palette PNGARG((png_structp png_ptr, + png_colorp palette, int num_palette)); +# endif +#endif + +#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) +PNG_EXTERN void png_do_bgr PNGARG((png_row_infop row_info, png_bytep row)); +#endif + +#if defined(PNG_WRITE_PACK_SUPPORTED) +PNG_EXTERN void png_do_pack PNGARG((png_row_infop row_info, + png_bytep row, png_uint_32 bit_depth)); +#endif + +#if defined(PNG_WRITE_SHIFT_SUPPORTED) +PNG_EXTERN void png_do_shift PNGARG((png_row_infop row_info, png_bytep row, + png_color_8p bit_depth)); +#endif + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) +#if defined(PNG_READ_GAMMA_SUPPORTED) +PNG_EXTERN void png_do_background PNGARG((png_row_infop row_info, png_bytep row, + png_color_16p trans_values, png_color_16p background, + png_color_16p background_1, + png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1, + png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1, + png_uint_16pp gamma_16_to_1, int gamma_shift)); +#else +PNG_EXTERN void png_do_background PNGARG((png_row_infop row_info, png_bytep row, + png_color_16p trans_values, png_color_16p background)); +#endif +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) +PNG_EXTERN void png_do_gamma PNGARG((png_row_infop row_info, png_bytep row, + png_bytep gamma_table, png_uint_16pp gamma_16_table, + int gamma_shift)); +#endif + +#if defined(PNG_READ_EXPAND_SUPPORTED) +PNG_EXTERN void png_do_expand_palette PNGARG((png_row_infop row_info, + png_bytep row, png_colorp palette, png_bytep trans, int num_trans)); +PNG_EXTERN void png_do_expand PNGARG((png_row_infop row_info, + png_bytep row, png_color_16p trans_value)); +#endif + +/* The following decodes the appropriate chunks, and does error correction, + * then calls the appropriate callback for the chunk if it is valid. + */ + +/* decode the IHDR chunk */ +PNG_EXTERN void png_handle_IHDR PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +PNG_EXTERN void png_handle_PLTE PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +PNG_EXTERN void png_handle_IEND PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); + +#if defined(PNG_READ_bKGD_SUPPORTED) +PNG_EXTERN void png_handle_bKGD PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_cHRM_SUPPORTED) +PNG_EXTERN void png_handle_cHRM PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_gAMA_SUPPORTED) +PNG_EXTERN void png_handle_gAMA PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_hIST_SUPPORTED) +PNG_EXTERN void png_handle_hIST PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_iCCP_SUPPORTED) +extern void png_handle_iCCP PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif /* PNG_READ_iCCP_SUPPORTED */ + +#if defined(PNG_READ_iTXt_SUPPORTED) +PNG_EXTERN void png_handle_iTXt PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_oFFs_SUPPORTED) +PNG_EXTERN void png_handle_oFFs PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_pCAL_SUPPORTED) +PNG_EXTERN void png_handle_pCAL PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_pHYs_SUPPORTED) +PNG_EXTERN void png_handle_pHYs PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_sBIT_SUPPORTED) +PNG_EXTERN void png_handle_sBIT PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_sCAL_SUPPORTED) +PNG_EXTERN void png_handle_sCAL PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_sPLT_SUPPORTED) +extern void png_handle_sPLT PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif /* PNG_READ_sPLT_SUPPORTED */ + +#if defined(PNG_READ_sRGB_SUPPORTED) +PNG_EXTERN void png_handle_sRGB PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_tEXt_SUPPORTED) +PNG_EXTERN void png_handle_tEXt PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_tIME_SUPPORTED) +PNG_EXTERN void png_handle_tIME PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_tRNS_SUPPORTED) +PNG_EXTERN void png_handle_tRNS PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_zTXt_SUPPORTED) +PNG_EXTERN void png_handle_zTXt PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +PNG_EXTERN void png_handle_unknown PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 length)); + +PNG_EXTERN void png_check_chunk_name PNGARG((png_structp png_ptr, + png_bytep chunk_name)); + +/* handle the transformations for reading and writing */ +PNG_EXTERN void png_do_read_transformations PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_do_write_transformations PNGARG((png_structp png_ptr)); + +PNG_EXTERN void png_init_read_transformations PNGARG((png_structp png_ptr)); + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +PNG_EXTERN void png_push_read_chunk PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_push_read_sig PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_push_check_crc PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_push_crc_skip PNGARG((png_structp png_ptr, + png_uint_32 length)); +PNG_EXTERN void png_push_crc_finish PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_push_save_buffer PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_push_restore_buffer PNGARG((png_structp png_ptr, + png_bytep buffer, png_size_t buffer_length)); +PNG_EXTERN void png_push_read_IDAT PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_process_IDAT_data PNGARG((png_structp png_ptr, + png_bytep buffer, png_size_t buffer_length)); +PNG_EXTERN void png_push_process_row PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_push_handle_unknown PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_push_have_info PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_push_have_end PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_push_have_row PNGARG((png_structp png_ptr, png_bytep row)); +PNG_EXTERN void png_push_read_end PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_process_some_data PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_read_push_finish_row PNGARG((png_structp png_ptr)); +#if defined(PNG_READ_tEXt_SUPPORTED) +PNG_EXTERN void png_push_handle_tEXt PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_push_read_tEXt PNGARG((png_structp png_ptr, + png_infop info_ptr)); +#endif +#if defined(PNG_READ_zTXt_SUPPORTED) +PNG_EXTERN void png_push_handle_zTXt PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_push_read_zTXt PNGARG((png_structp png_ptr, + png_infop info_ptr)); +#endif +#if defined(PNG_READ_iTXt_SUPPORTED) +PNG_EXTERN void png_push_handle_iTXt PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_push_read_iTXt PNGARG((png_structp png_ptr, + png_infop info_ptr)); +#endif + +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ + +#ifdef PNG_MNG_FEATURES_SUPPORTED +PNG_EXTERN void png_do_read_intrapixel PNGARG((png_row_infop row_info, + png_bytep row)); +PNG_EXTERN void png_do_write_intrapixel PNGARG((png_row_infop row_info, + png_bytep row)); +#endif + +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) +/* png.c */ /* PRIVATE */ +PNG_EXTERN void png_init_mmx_flags PNGARG((png_structp png_ptr)); +#endif +/* Maintainer: Put new private prototypes here ^ and in libpngpf.3 */ + +#endif /* PNG_INTERNAL */ + +#ifdef __cplusplus +} +#endif + +#endif /* PNG_VERSION_INFO_ONLY */ +/* do not put anything past this line */ +#endif /* PNG_H */ diff --git a/winclude/pngasmrd.h b/winclude/pngasmrd.h new file mode 100755 index 000000000..ca4c12bcc --- /dev/null +++ b/winclude/pngasmrd.h @@ -0,0 +1,11 @@ +/* pngasmrd.h - assembler version of utilities to read a PNG file + * + * libpng 1.2.5 - October 3, 2002 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 2002 Glenn Randers-Pehrson + * + */ + +/* This file is obsolete in libpng-1.0.9 and later; its contents now appear + * at the end of pngconf.h. + */ diff --git a/winclude/pngconf.h b/winclude/pngconf.h new file mode 100755 index 000000000..e17202968 --- /dev/null +++ b/winclude/pngconf.h @@ -0,0 +1,1348 @@ +/* pngconf.h - machine configurable file for libpng + * + * libpng 1.2.5 - October 3, 2002 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2002 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + */ + +/* Any machine specific code is near the front of this file, so if you + * are configuring libpng for a machine, you may want to read the section + * starting here down to where it starts to typedef png_color, png_text, + * and png_info. + */ + +#ifndef PNGCONF_H +#define PNGCONF_H + +/* This is the size of the compression buffer, and thus the size of + * an IDAT chunk. Make this whatever size you feel is best for your + * machine. One of these will be allocated per png_struct. When this + * is full, it writes the data to the disk, and does some other + * calculations. Making this an extremely small size will slow + * the library down, but you may want to experiment to determine + * where it becomes significant, if you are concerned with memory + * usage. Note that zlib allocates at least 32Kb also. For readers, + * this describes the size of the buffer available to read the data in. + * Unless this gets smaller than the size of a row (compressed), + * it should not make much difference how big this is. + */ + +#ifndef PNG_ZBUF_SIZE +# define PNG_ZBUF_SIZE 8192 +#endif + +/* Enable if you want a write-only libpng */ + +#ifndef PNG_NO_READ_SUPPORTED +# define PNG_READ_SUPPORTED +#endif + +/* Enable if you want a read-only libpng */ + +#ifndef PNG_NO_WRITE_SUPPORTED +# define PNG_WRITE_SUPPORTED +#endif + +/* Enabled by default in 1.2.0. You can disable this if you don't need to + support PNGs that are embedded in MNG datastreams */ +#if !defined(PNG_1_0_X) && !defined(PNG_NO_MNG_FEATURES) +# ifndef PNG_MNG_FEATURES_SUPPORTED +# define PNG_MNG_FEATURES_SUPPORTED +# endif +#endif + +#ifndef PNG_NO_FLOATING_POINT_SUPPORTED +# ifndef PNG_FLOATING_POINT_SUPPORTED +# define PNG_FLOATING_POINT_SUPPORTED +# endif +#endif + +/* If you are running on a machine where you cannot allocate more + * than 64K of memory at once, uncomment this. While libpng will not + * normally need that much memory in a chunk (unless you load up a very + * large file), zlib needs to know how big of a chunk it can use, and + * libpng thus makes sure to check any memory allocation to verify it + * will fit into memory. +#define PNG_MAX_MALLOC_64K + */ +#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K) +# define PNG_MAX_MALLOC_64K +#endif + +/* Special munging to support doing things the 'cygwin' way: + * 'Normal' png-on-win32 defines/defaults: + * PNG_BUILD_DLL -- building dll + * PNG_USE_DLL -- building an application, linking to dll + * (no define) -- building static library, or building an + * application and linking to the static lib + * 'Cygwin' defines/defaults: + * PNG_BUILD_DLL -- (ignored) building the dll + * (no define) -- (ignored) building an application, linking to the dll + * PNG_STATIC -- (ignored) building the static lib, or building an + * application that links to the static lib. + * ALL_STATIC -- (ignored) building various static libs, or building an + * application that links to the static libs. + * Thus, + * a cygwin user should define either PNG_BUILD_DLL or PNG_STATIC, and + * this bit of #ifdefs will define the 'correct' config variables based on + * that. If a cygwin user *wants* to define 'PNG_USE_DLL' that's okay, but + * unnecessary. + * + * Also, the precedence order is: + * ALL_STATIC (since we can't #undef something outside our namespace) + * PNG_BUILD_DLL + * PNG_STATIC + * (nothing) == PNG_USE_DLL + * + * CYGWIN (2002-01-20): The preceding is now obsolete. With the advent + * of auto-import in binutils, we no longer need to worry about + * __declspec(dllexport) / __declspec(dllimport) and friends. Therefore, + * we don't need to worry about PNG_STATIC or ALL_STATIC when it comes + * to __declspec() stuff. However, we DO need to worry about + * PNG_BUILD_DLL and PNG_STATIC because those change some defaults + * such as CONSOLE_IO and whether GLOBAL_ARRAYS are allowed. + */ +#if defined(__CYGWIN__) +# if defined(ALL_STATIC) +# if defined(PNG_BUILD_DLL) +# undef PNG_BUILD_DLL +# endif +# if defined(PNG_USE_DLL) +# undef PNG_USE_DLL +# endif +# if defined(PNG_DLL) +# undef PNG_DLL +# endif +# if !defined(PNG_STATIC) +# define PNG_STATIC +# endif +# else +# if defined (PNG_BUILD_DLL) +# if defined(PNG_STATIC) +# undef PNG_STATIC +# endif +# if defined(PNG_USE_DLL) +# undef PNG_USE_DLL +# endif +# if !defined(PNG_DLL) +# define PNG_DLL +# endif +# else +# if defined(PNG_STATIC) +# if defined(PNG_USE_DLL) +# undef PNG_USE_DLL +# endif +# if defined(PNG_DLL) +# undef PNG_DLL +# endif +# else +# if !defined(PNG_USE_DLL) +# define PNG_USE_DLL +# endif +# if !defined(PNG_DLL) +# define PNG_DLL +# endif +# endif +# endif +# endif +#endif + +/* This protects us against compilers that run on a windowing system + * and thus don't have or would rather us not use the stdio types: + * stdin, stdout, and stderr. The only one currently used is stderr + * in png_error() and png_warning(). #defining PNG_NO_CONSOLE_IO will + * prevent these from being compiled and used. #defining PNG_NO_STDIO + * will also prevent these, plus will prevent the entire set of stdio + * macros and functions (FILE *, printf, etc.) from being compiled and used, + * unless (PNG_DEBUG > 0) has been #defined. + * + * #define PNG_NO_CONSOLE_IO + * #define PNG_NO_STDIO + */ + +#if defined(_WIN32_WCE) +# include + /* Console I/O functions are not supported on WindowsCE */ +# define PNG_NO_CONSOLE_IO +# ifdef PNG_DEBUG +# undef PNG_DEBUG +# endif +#endif + +#ifdef PNG_BUILD_DLL +# ifndef PNG_CONSOLE_IO_SUPPORTED +# ifndef PNG_NO_CONSOLE_IO +# define PNG_NO_CONSOLE_IO +# endif +# endif +#endif + +# ifdef PNG_NO_STDIO +# ifndef PNG_NO_CONSOLE_IO +# define PNG_NO_CONSOLE_IO +# endif +# ifdef PNG_DEBUG +# if (PNG_DEBUG > 0) +# include +# endif +# endif +# else +# if !defined(_WIN32_WCE) +/* "stdio.h" functions are not supported on WindowsCE */ +# include +# endif +# endif + +/* This macro protects us against machines that don't have function + * prototypes (ie K&R style headers). If your compiler does not handle + * function prototypes, define this macro and use the included ansi2knr. + * I've always been able to use _NO_PROTO as the indicator, but you may + * need to drag the empty declaration out in front of here, or change the + * ifdef to suit your own needs. + */ +#ifndef PNGARG + +#ifdef OF /* zlib prototype munger */ +# define PNGARG(arglist) OF(arglist) +#else + +#ifdef _NO_PROTO +# define PNGARG(arglist) () +# ifndef PNG_TYPECAST_NULL +# define PNG_TYPECAST_NULL +# endif +#else +# define PNGARG(arglist) arglist +#endif /* _NO_PROTO */ + +#endif /* OF */ + +#endif /* PNGARG */ + +/* Try to determine if we are compiling on a Mac. Note that testing for + * just __MWERKS__ is not good enough, because the Codewarrior is now used + * on non-Mac platforms. + */ +#ifndef MACOS +# if (defined(__MWERKS__) && defined(macintosh)) || defined(applec) || \ + defined(THINK_C) || defined(__SC__) || defined(TARGET_OS_MAC) +# define MACOS +# endif +#endif + +/* enough people need this for various reasons to include it here */ +#if !defined(MACOS) && !defined(RISCOS) && !defined(_WIN32_WCE) +# include +#endif + +#if !defined(PNG_SETJMP_NOT_SUPPORTED) && !defined(PNG_NO_SETJMP_SUPPORTED) +# define PNG_SETJMP_SUPPORTED +#endif + +#ifdef PNG_SETJMP_SUPPORTED +/* This is an attempt to force a single setjmp behaviour on Linux. If + * the X config stuff didn't define _BSD_SOURCE we wouldn't need this. + */ + +# ifdef __linux__ +# ifdef _BSD_SOURCE +# define PNG_SAVE_BSD_SOURCE +# undef _BSD_SOURCE +# endif +# ifdef _SETJMP_H + __png.h__ already includes setjmp.h; + __dont__ include it again.; +# endif +# endif /* __linux__ */ + + /* include setjmp.h for error handling */ +# include + +# ifdef __linux__ +# ifdef PNG_SAVE_BSD_SOURCE +# define _BSD_SOURCE +# undef PNG_SAVE_BSD_SOURCE +# endif +# endif /* __linux__ */ +#endif /* PNG_SETJMP_SUPPORTED */ + +#ifdef BSD +# include +#else +# include +#endif + +/* Other defines for things like memory and the like can go here. */ +#ifdef PNG_INTERNAL + +#include + +/* The functions exported by PNG_EXTERN are PNG_INTERNAL functions, which + * aren't usually used outside the library (as far as I know), so it is + * debatable if they should be exported at all. In the future, when it is + * possible to have run-time registry of chunk-handling functions, some of + * these will be made available again. +#define PNG_EXTERN extern + */ +#define PNG_EXTERN + +/* Other defines specific to compilers can go here. Try to keep + * them inside an appropriate ifdef/endif pair for portability. + */ + +#if defined(PNG_FLOATING_POINT_SUPPORTED) +# if defined(MACOS) + /* We need to check that hasn't already been included earlier + * as it seems it doesn't agree with , yet we should really use + * if possible. + */ +# if !defined(__MATH_H__) && !defined(__MATH_H) && !defined(__cmath__) +# include +# endif +# else +# include +# endif +# if defined(_AMIGA) && defined(__SASC) && defined(_M68881) + /* Amiga SAS/C: We must include builtin FPU functions when compiling using + * MATH=68881 + */ +# include +# endif +#endif + +/* Codewarrior on NT has linking problems without this. */ +#if (defined(__MWERKS__) && defined(WIN32)) || defined(__STDC__) +# define PNG_ALWAYS_EXTERN +#endif + +/* For some reason, Borland C++ defines memcmp, etc. in mem.h, not + * stdlib.h like it should (I think). Or perhaps this is a C++ + * "feature"? + */ +#ifdef __TURBOC__ +# include +# include "alloc.h" +#endif + +#if defined(_MSC_VER) && (defined(WIN32) || defined(_Windows) || \ + defined(_WINDOWS) || defined(_WIN32) || defined(__WIN32__)) +# include +#endif + +/* This controls how fine the dithering gets. As this allocates + * a largish chunk of memory (32K), those who are not as concerned + * with dithering quality can decrease some or all of these. + */ +#ifndef PNG_DITHER_RED_BITS +# define PNG_DITHER_RED_BITS 5 +#endif +#ifndef PNG_DITHER_GREEN_BITS +# define PNG_DITHER_GREEN_BITS 5 +#endif +#ifndef PNG_DITHER_BLUE_BITS +# define PNG_DITHER_BLUE_BITS 5 +#endif + +/* This controls how fine the gamma correction becomes when you + * are only interested in 8 bits anyway. Increasing this value + * results in more memory being used, and more pow() functions + * being called to fill in the gamma tables. Don't set this value + * less then 8, and even that may not work (I haven't tested it). + */ + +#ifndef PNG_MAX_GAMMA_8 +# define PNG_MAX_GAMMA_8 11 +#endif + +/* This controls how much a difference in gamma we can tolerate before + * we actually start doing gamma conversion. + */ +#ifndef PNG_GAMMA_THRESHOLD +# define PNG_GAMMA_THRESHOLD 0.05 +#endif + +#endif /* PNG_INTERNAL */ + +/* The following uses const char * instead of char * for error + * and warning message functions, so some compilers won't complain. + * If you do not want to use const, define PNG_NO_CONST here. + */ + +#ifndef PNG_NO_CONST +# define PNG_CONST const +#else +# define PNG_CONST +#endif + +/* The following defines give you the ability to remove code from the + * library that you will not be using. I wish I could figure out how to + * automate this, but I can't do that without making it seriously hard + * on the users. So if you are not using an ability, change the #define + * to and #undef, and that part of the library will not be compiled. If + * your linker can't find a function, you may want to make sure the + * ability is defined here. Some of these depend upon some others being + * defined. I haven't figured out all the interactions here, so you may + * have to experiment awhile to get everything to compile. If you are + * creating or using a shared library, you probably shouldn't touch this, + * as it will affect the size of the structures, and this will cause bad + * things to happen if the library and/or application ever change. + */ + +/* Any features you will not be using can be undef'ed here */ + +/* GR-P, 0.96a: Set "*TRANSFORMS_SUPPORTED as default but allow user + * to turn it off with "*TRANSFORMS_NOT_SUPPORTED" or *PNG_NO_*_TRANSFORMS + * on the compile line, then pick and choose which ones to define without + * having to edit this file. It is safe to use the *TRANSFORMS_NOT_SUPPORTED + * if you only want to have a png-compliant reader/writer but don't need + * any of the extra transformations. This saves about 80 kbytes in a + * typical installation of the library. (PNG_NO_* form added in version + * 1.0.1c, for consistency) + */ + +/* The size of the png_text structure changed in libpng-1.0.6 when + * iTXt is supported. It is turned off by default, to support old apps + * that malloc the png_text structure instead of calling png_set_text() + * and letting libpng malloc it. It will be turned on by default in + * libpng-1.3.0. + */ + +#ifndef PNG_iTXt_SUPPORTED +# if !defined(PNG_READ_iTXt_SUPPORTED) && !defined(PNG_NO_READ_iTXt) +# define PNG_NO_READ_iTXt +# endif +# if !defined(PNG_WRITE_iTXt_SUPPORTED) && !defined(PNG_NO_WRITE_iTXt) +# define PNG_NO_WRITE_iTXt +# endif +#endif + +/* The following support, added after version 1.0.0, can be turned off here en + * masse by defining PNG_LEGACY_SUPPORTED in case you need binary compatibility + * with old applications that require the length of png_struct and png_info + * to remain unchanged. + */ + +#ifdef PNG_LEGACY_SUPPORTED +# define PNG_NO_FREE_ME +# define PNG_NO_READ_UNKNOWN_CHUNKS +# define PNG_NO_WRITE_UNKNOWN_CHUNKS +# define PNG_NO_READ_USER_CHUNKS +# define PNG_NO_READ_iCCP +# define PNG_NO_WRITE_iCCP +# define PNG_NO_READ_iTXt +# define PNG_NO_WRITE_iTXt +# define PNG_NO_READ_sCAL +# define PNG_NO_WRITE_sCAL +# define PNG_NO_READ_sPLT +# define PNG_NO_WRITE_sPLT +# define PNG_NO_INFO_IMAGE +# define PNG_NO_READ_RGB_TO_GRAY +# define PNG_NO_READ_USER_TRANSFORM +# define PNG_NO_WRITE_USER_TRANSFORM +# define PNG_NO_USER_MEM +# define PNG_NO_READ_EMPTY_PLTE +# define PNG_NO_MNG_FEATURES +# define PNG_NO_FIXED_POINT_SUPPORTED +#endif + +/* Ignore attempt to turn off both floating and fixed point support */ +#if !defined(PNG_FLOATING_POINT_SUPPORTED) || \ + !defined(PNG_NO_FIXED_POINT_SUPPORTED) +# define PNG_FIXED_POINT_SUPPORTED +#endif + +#ifndef PNG_NO_FREE_ME +# define PNG_FREE_ME_SUPPORTED +#endif + +#if defined(PNG_READ_SUPPORTED) + +#if !defined(PNG_READ_TRANSFORMS_NOT_SUPPORTED) && \ + !defined(PNG_NO_READ_TRANSFORMS) +# define PNG_READ_TRANSFORMS_SUPPORTED +#endif + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +# ifndef PNG_NO_READ_EXPAND +# define PNG_READ_EXPAND_SUPPORTED +# endif +# ifndef PNG_NO_READ_SHIFT +# define PNG_READ_SHIFT_SUPPORTED +# endif +# ifndef PNG_NO_READ_PACK +# define PNG_READ_PACK_SUPPORTED +# endif +# ifndef PNG_NO_READ_BGR +# define PNG_READ_BGR_SUPPORTED +# endif +# ifndef PNG_NO_READ_SWAP +# define PNG_READ_SWAP_SUPPORTED +# endif +# ifndef PNG_NO_READ_PACKSWAP +# define PNG_READ_PACKSWAP_SUPPORTED +# endif +# ifndef PNG_NO_READ_INVERT +# define PNG_READ_INVERT_SUPPORTED +# endif +# ifndef PNG_NO_READ_DITHER +# define PNG_READ_DITHER_SUPPORTED +# endif +# ifndef PNG_NO_READ_BACKGROUND +# define PNG_READ_BACKGROUND_SUPPORTED +# endif +# ifndef PNG_NO_READ_16_TO_8 +# define PNG_READ_16_TO_8_SUPPORTED +# endif +# ifndef PNG_NO_READ_FILLER +# define PNG_READ_FILLER_SUPPORTED +# endif +# ifndef PNG_NO_READ_GAMMA +# define PNG_READ_GAMMA_SUPPORTED +# endif +# ifndef PNG_NO_READ_GRAY_TO_RGB +# define PNG_READ_GRAY_TO_RGB_SUPPORTED +# endif +# ifndef PNG_NO_READ_SWAP_ALPHA +# define PNG_READ_SWAP_ALPHA_SUPPORTED +# endif +# ifndef PNG_NO_READ_INVERT_ALPHA +# define PNG_READ_INVERT_ALPHA_SUPPORTED +# endif +# ifndef PNG_NO_READ_STRIP_ALPHA +# define PNG_READ_STRIP_ALPHA_SUPPORTED +# endif +# ifndef PNG_NO_READ_USER_TRANSFORM +# define PNG_READ_USER_TRANSFORM_SUPPORTED +# endif +# ifndef PNG_NO_READ_RGB_TO_GRAY +# define PNG_READ_RGB_TO_GRAY_SUPPORTED +# endif +#endif /* PNG_READ_TRANSFORMS_SUPPORTED */ + +#if !defined(PNG_NO_PROGRESSIVE_READ) && \ + !defined(PNG_PROGRESSIVE_READ_NOT_SUPPORTED) /* if you don't do progressive */ +# define PNG_PROGRESSIVE_READ_SUPPORTED /* reading. This is not talking */ +#endif /* about interlacing capability! You'll */ + /* still have interlacing unless you change the following line: */ + +#define PNG_READ_INTERLACING_SUPPORTED /* required for PNG-compliant decoders */ + +#ifndef PNG_NO_READ_COMPOSITE_NODIV +# ifndef PNG_NO_READ_COMPOSITED_NODIV /* libpng-1.0.x misspelling */ +# define PNG_READ_COMPOSITE_NODIV_SUPPORTED /* well tested on Intel, SGI */ +# endif +#endif + +/* Deprecated, will be removed from version 2.0.0. + Use PNG_MNG_FEATURES_SUPPORTED instead. */ +#ifndef PNG_NO_READ_EMPTY_PLTE +# define PNG_READ_EMPTY_PLTE_SUPPORTED +#endif + +#endif /* PNG_READ_SUPPORTED */ + +#if defined(PNG_WRITE_SUPPORTED) + +# if !defined(PNG_WRITE_TRANSFORMS_NOT_SUPPORTED) && \ + !defined(PNG_NO_WRITE_TRANSFORMS) +# define PNG_WRITE_TRANSFORMS_SUPPORTED +#endif + +#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED +# ifndef PNG_NO_WRITE_SHIFT +# define PNG_WRITE_SHIFT_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_PACK +# define PNG_WRITE_PACK_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_BGR +# define PNG_WRITE_BGR_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_SWAP +# define PNG_WRITE_SWAP_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_PACKSWAP +# define PNG_WRITE_PACKSWAP_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_INVERT +# define PNG_WRITE_INVERT_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_FILLER +# define PNG_WRITE_FILLER_SUPPORTED /* same as WRITE_STRIP_ALPHA */ +# endif +# ifndef PNG_NO_WRITE_SWAP_ALPHA +# define PNG_WRITE_SWAP_ALPHA_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_INVERT_ALPHA +# define PNG_WRITE_INVERT_ALPHA_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_USER_TRANSFORM +# define PNG_WRITE_USER_TRANSFORM_SUPPORTED +# endif +#endif /* PNG_WRITE_TRANSFORMS_SUPPORTED */ + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) +# ifndef PNG_NO_USER_TRANSFORM_PTR +# define PNG_USER_TRANSFORM_PTR_SUPPORTED +# endif +#endif + +#define PNG_WRITE_INTERLACING_SUPPORTED /* not required for PNG-compliant + encoders, but can cause trouble + if left undefined */ + +#if !defined(PNG_NO_WRITE_WEIGHTED_FILTER) && \ + defined(PNG_FLOATING_POINT_SUPPORTED) +# define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED +#endif + +#ifndef PNG_1_0_X +#ifndef PNG_NO_ERROR_NUMBERS +#define PNG_ERROR_NUMBERS_SUPPORTED +#endif +#endif /* PNG_1_0_X */ + +#ifndef PNG_NO_WRITE_FLUSH +# define PNG_WRITE_FLUSH_SUPPORTED +#endif + +/* Deprecated, see PNG_MNG_FEATURES_SUPPORTED, above */ +#ifndef PNG_NO_WRITE_EMPTY_PLTE +# define PNG_WRITE_EMPTY_PLTE_SUPPORTED +#endif + +#endif /* PNG_WRITE_SUPPORTED */ + +#ifndef PNG_NO_STDIO +# define PNG_TIME_RFC1123_SUPPORTED +#endif + +/* This adds extra functions in pngget.c for accessing data from the + * info pointer (added in version 0.99) + * png_get_image_width() + * png_get_image_height() + * png_get_bit_depth() + * png_get_color_type() + * png_get_compression_type() + * png_get_filter_type() + * png_get_interlace_type() + * png_get_pixel_aspect_ratio() + * png_get_pixels_per_meter() + * png_get_x_offset_pixels() + * png_get_y_offset_pixels() + * png_get_x_offset_microns() + * png_get_y_offset_microns() + */ +#if !defined(PNG_NO_EASY_ACCESS) && !defined(PNG_EASY_ACCESS_SUPPORTED) +# define PNG_EASY_ACCESS_SUPPORTED +#endif + +/* PNG_ASSEMBLER_CODE was enabled by default in version 1.2.0 + even when PNG_USE_PNGVCRD or PNG_USE_PNGGCCRD is not defined */ +#if defined(PNG_READ_SUPPORTED) && !defined(PNG_NO_ASSEMBLER_CODE) +# ifndef PNG_ASSEMBLER_CODE_SUPPORTED +# define PNG_ASSEMBLER_CODE_SUPPORTED +# endif +# if !defined(PNG_MMX_CODE_SUPPORTED) && !defined(PNG_NO_MMX_CODE) +# define PNG_MMX_CODE_SUPPORTED +# endif +#endif + +/* If you are sure that you don't need thread safety and you are compiling + with PNG_USE_PNGCCRD for an MMX application, you can define this for + faster execution. See pnggccrd.c. +#define PNG_THREAD_UNSAFE_OK +*/ + +#if !defined(PNG_1_0_X) +#if !defined(PNG_NO_USER_MEM) && !defined(PNG_USER_MEM_SUPPORTED) +# define PNG_USER_MEM_SUPPORTED +#endif +#endif /* PNG_1_0_X */ + +/* These are currently experimental features, define them if you want */ + +/* very little testing */ +/* +#ifdef PNG_READ_SUPPORTED +# ifndef PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED +# define PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED +# endif +#endif +*/ + +/* This is only for PowerPC big-endian and 680x0 systems */ +/* some testing */ +/* +#ifdef PNG_READ_SUPPORTED +# ifndef PNG_PNG_READ_BIG_ENDIAN_SUPPORTED +# define PNG_READ_BIG_ENDIAN_SUPPORTED +# endif +#endif +*/ + +/* Buggy compilers (e.g., gcc 2.7.2.2) need this */ +/* +#define PNG_NO_POINTER_INDEXING +*/ + +/* These functions are turned off by default, as they will be phased out. */ +/* +#define PNG_USELESS_TESTS_SUPPORTED +#define PNG_CORRECT_PALETTE_SUPPORTED +*/ + +/* Any chunks you are not interested in, you can undef here. The + * ones that allocate memory may be expecially important (hIST, + * tEXt, zTXt, tRNS, pCAL). Others will just save time and make png_info + * a bit smaller. + */ + +#if defined(PNG_READ_SUPPORTED) && \ + !defined(PNG_READ_ANCILLARY_CHUNKS_NOT_SUPPORTED) && \ + !defined(PNG_NO_READ_ANCILLARY_CHUNKS) +# define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED +#endif + +#if defined(PNG_WRITE_SUPPORTED) && \ + !defined(PNG_WRITE_ANCILLARY_CHUNKS_NOT_SUPPORTED) && \ + !defined(PNG_NO_WRITE_ANCILLARY_CHUNKS) +# define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED +#endif + +#ifdef PNG_READ_ANCILLARY_CHUNKS_SUPPORTED + +#ifdef PNG_NO_READ_TEXT +# define PNG_NO_READ_iTXt +# define PNG_NO_READ_tEXt +# define PNG_NO_READ_zTXt +#endif +#ifndef PNG_NO_READ_bKGD +# define PNG_READ_bKGD_SUPPORTED +# define PNG_bKGD_SUPPORTED +#endif +#ifndef PNG_NO_READ_cHRM +# define PNG_READ_cHRM_SUPPORTED +# define PNG_cHRM_SUPPORTED +#endif +#ifndef PNG_NO_READ_gAMA +# define PNG_READ_gAMA_SUPPORTED +# define PNG_gAMA_SUPPORTED +#endif +#ifndef PNG_NO_READ_hIST +# define PNG_READ_hIST_SUPPORTED +# define PNG_hIST_SUPPORTED +#endif +#ifndef PNG_NO_READ_iCCP +# define PNG_READ_iCCP_SUPPORTED +# define PNG_iCCP_SUPPORTED +#endif +#ifndef PNG_NO_READ_iTXt +# ifndef PNG_READ_iTXt_SUPPORTED +# define PNG_READ_iTXt_SUPPORTED +# endif +# ifndef PNG_iTXt_SUPPORTED +# define PNG_iTXt_SUPPORTED +# endif +#endif +#ifndef PNG_NO_READ_oFFs +# define PNG_READ_oFFs_SUPPORTED +# define PNG_oFFs_SUPPORTED +#endif +#ifndef PNG_NO_READ_pCAL +# define PNG_READ_pCAL_SUPPORTED +# define PNG_pCAL_SUPPORTED +#endif +#ifndef PNG_NO_READ_sCAL +# define PNG_READ_sCAL_SUPPORTED +# define PNG_sCAL_SUPPORTED +#endif +#ifndef PNG_NO_READ_pHYs +# define PNG_READ_pHYs_SUPPORTED +# define PNG_pHYs_SUPPORTED +#endif +#ifndef PNG_NO_READ_sBIT +# define PNG_READ_sBIT_SUPPORTED +# define PNG_sBIT_SUPPORTED +#endif +#ifndef PNG_NO_READ_sPLT +# define PNG_READ_sPLT_SUPPORTED +# define PNG_sPLT_SUPPORTED +#endif +#ifndef PNG_NO_READ_sRGB +# define PNG_READ_sRGB_SUPPORTED +# define PNG_sRGB_SUPPORTED +#endif +#ifndef PNG_NO_READ_tEXt +# define PNG_READ_tEXt_SUPPORTED +# define PNG_tEXt_SUPPORTED +#endif +#ifndef PNG_NO_READ_tIME +# define PNG_READ_tIME_SUPPORTED +# define PNG_tIME_SUPPORTED +#endif +#ifndef PNG_NO_READ_tRNS +# define PNG_READ_tRNS_SUPPORTED +# define PNG_tRNS_SUPPORTED +#endif +#ifndef PNG_NO_READ_zTXt +# define PNG_READ_zTXt_SUPPORTED +# define PNG_zTXt_SUPPORTED +#endif +#ifndef PNG_NO_READ_UNKNOWN_CHUNKS +# define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED +# ifndef PNG_UNKNOWN_CHUNKS_SUPPORTED +# define PNG_UNKNOWN_CHUNKS_SUPPORTED +# endif +# ifndef PNG_NO_HANDLE_AS_UNKNOWN +# define PNG_HANDLE_AS_UNKNOWN_SUPPORTED +# endif +#endif +#if !defined(PNG_NO_READ_USER_CHUNKS) && \ + defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) +# define PNG_READ_USER_CHUNKS_SUPPORTED +# define PNG_USER_CHUNKS_SUPPORTED +# ifdef PNG_NO_READ_UNKNOWN_CHUNKS +# undef PNG_NO_READ_UNKNOWN_CHUNKS +# endif +# ifdef PNG_NO_HANDLE_AS_UNKNOWN +# undef PNG_NO_HANDLE_AS_UNKNOWN +# endif +#endif +#ifndef PNG_NO_READ_OPT_PLTE +# define PNG_READ_OPT_PLTE_SUPPORTED /* only affects support of the */ +#endif /* optional PLTE chunk in RGB and RGBA images */ +#if defined(PNG_READ_iTXt_SUPPORTED) || defined(PNG_READ_tEXt_SUPPORTED) || \ + defined(PNG_READ_zTXt_SUPPORTED) +# define PNG_READ_TEXT_SUPPORTED +# define PNG_TEXT_SUPPORTED +#endif + +#endif /* PNG_READ_ANCILLARY_CHUNKS_SUPPORTED */ + +#ifdef PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED + +#ifdef PNG_NO_WRITE_TEXT +# define PNG_NO_WRITE_iTXt +# define PNG_NO_WRITE_tEXt +# define PNG_NO_WRITE_zTXt +#endif +#ifndef PNG_NO_WRITE_bKGD +# define PNG_WRITE_bKGD_SUPPORTED +# ifndef PNG_bKGD_SUPPORTED +# define PNG_bKGD_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_cHRM +# define PNG_WRITE_cHRM_SUPPORTED +# ifndef PNG_cHRM_SUPPORTED +# define PNG_cHRM_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_gAMA +# define PNG_WRITE_gAMA_SUPPORTED +# ifndef PNG_gAMA_SUPPORTED +# define PNG_gAMA_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_hIST +# define PNG_WRITE_hIST_SUPPORTED +# ifndef PNG_hIST_SUPPORTED +# define PNG_hIST_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_iCCP +# define PNG_WRITE_iCCP_SUPPORTED +# ifndef PNG_iCCP_SUPPORTED +# define PNG_iCCP_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_iTXt +# ifndef PNG_WRITE_iTXt_SUPPORTED +# define PNG_WRITE_iTXt_SUPPORTED +# endif +# ifndef PNG_iTXt_SUPPORTED +# define PNG_iTXt_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_oFFs +# define PNG_WRITE_oFFs_SUPPORTED +# ifndef PNG_oFFs_SUPPORTED +# define PNG_oFFs_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_pCAL +# define PNG_WRITE_pCAL_SUPPORTED +# ifndef PNG_pCAL_SUPPORTED +# define PNG_pCAL_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_sCAL +# define PNG_WRITE_sCAL_SUPPORTED +# ifndef PNG_sCAL_SUPPORTED +# define PNG_sCAL_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_pHYs +# define PNG_WRITE_pHYs_SUPPORTED +# ifndef PNG_pHYs_SUPPORTED +# define PNG_pHYs_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_sBIT +# define PNG_WRITE_sBIT_SUPPORTED +# ifndef PNG_sBIT_SUPPORTED +# define PNG_sBIT_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_sPLT +# define PNG_WRITE_sPLT_SUPPORTED +# ifndef PNG_sPLT_SUPPORTED +# define PNG_sPLT_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_sRGB +# define PNG_WRITE_sRGB_SUPPORTED +# ifndef PNG_sRGB_SUPPORTED +# define PNG_sRGB_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_tEXt +# define PNG_WRITE_tEXt_SUPPORTED +# ifndef PNG_tEXt_SUPPORTED +# define PNG_tEXt_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_tIME +# define PNG_WRITE_tIME_SUPPORTED +# ifndef PNG_tIME_SUPPORTED +# define PNG_tIME_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_tRNS +# define PNG_WRITE_tRNS_SUPPORTED +# ifndef PNG_tRNS_SUPPORTED +# define PNG_tRNS_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_zTXt +# define PNG_WRITE_zTXt_SUPPORTED +# ifndef PNG_zTXt_SUPPORTED +# define PNG_zTXt_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_UNKNOWN_CHUNKS +# define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED +# ifndef PNG_UNKNOWN_CHUNKS_SUPPORTED +# define PNG_UNKNOWN_CHUNKS_SUPPORTED +# endif +# ifndef PNG_NO_HANDLE_AS_UNKNOWN +# ifndef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +# define PNG_HANDLE_AS_UNKNOWN_SUPPORTED +# endif +# endif +#endif +#if defined(PNG_WRITE_iTXt_SUPPORTED) || defined(PNG_WRITE_tEXt_SUPPORTED) || \ + defined(PNG_WRITE_zTXt_SUPPORTED) +# define PNG_WRITE_TEXT_SUPPORTED +# ifndef PNG_TEXT_SUPPORTED +# define PNG_TEXT_SUPPORTED +# endif +#endif + +#endif /* PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED */ + +/* Turn this off to disable png_read_png() and + * png_write_png() and leave the row_pointers member + * out of the info structure. + */ +#ifndef PNG_NO_INFO_IMAGE +# define PNG_INFO_IMAGE_SUPPORTED +#endif + +/* need the time information for reading tIME chunks */ +#if defined(PNG_tIME_SUPPORTED) +# if !defined(_WIN32_WCE) + /* "time.h" functions are not supported on WindowsCE */ +# include +# endif +#endif + +/* Some typedefs to get us started. These should be safe on most of the + * common platforms. The typedefs should be at least as large as the + * numbers suggest (a png_uint_32 must be at least 32 bits long), but they + * don't have to be exactly that size. Some compilers dislike passing + * unsigned shorts as function parameters, so you may be better off using + * unsigned int for png_uint_16. Likewise, for 64-bit systems, you may + * want to have unsigned int for png_uint_32 instead of unsigned long. + */ + +typedef unsigned long png_uint_32; +typedef long png_int_32; +typedef unsigned short png_uint_16; +typedef short png_int_16; +typedef unsigned char png_byte; + +/* This is usually size_t. It is typedef'ed just in case you need it to + change (I'm not sure if you will or not, so I thought I'd be safe) */ +typedef size_t png_size_t; + +/* The following is needed for medium model support. It cannot be in the + * PNG_INTERNAL section. Needs modification for other compilers besides + * MSC. Model independent support declares all arrays and pointers to be + * large using the far keyword. The zlib version used must also support + * model independent data. As of version zlib 1.0.4, the necessary changes + * have been made in zlib. The USE_FAR_KEYWORD define triggers other + * changes that are needed. (Tim Wegner) + */ + +/* Separate compiler dependencies (problem here is that zlib.h always + defines FAR. (SJT) */ +#ifdef __BORLANDC__ +# if defined(__LARGE__) || defined(__HUGE__) || defined(__COMPACT__) +# define LDATA 1 +# else +# define LDATA 0 +# endif + /* GRR: why is Cygwin in here? Cygwin is not Borland C... */ +# if !defined(__WIN32__) && !defined(__FLAT__) && !defined(__CYGWIN__) +# define PNG_MAX_MALLOC_64K +# if (LDATA != 1) +# ifndef FAR +# define FAR __far +# endif +# define USE_FAR_KEYWORD +# endif /* LDATA != 1 */ + /* Possibly useful for moving data out of default segment. + * Uncomment it if you want. Could also define FARDATA as + * const if your compiler supports it. (SJT) +# define FARDATA FAR + */ +# endif /* __WIN32__, __FLAT__, __CYGWIN__ */ +#endif /* __BORLANDC__ */ + + +/* Suggest testing for specific compiler first before testing for + * FAR. The Watcom compiler defines both __MEDIUM__ and M_I86MM, + * making reliance oncertain keywords suspect. (SJT) + */ + +/* MSC Medium model */ +#if defined(FAR) +# if defined(M_I86MM) +# define USE_FAR_KEYWORD +# define FARDATA FAR +# include +# endif +#endif + +/* SJT: default case */ +#ifndef FAR +# define FAR +#endif + +/* At this point FAR is always defined */ +#ifndef FARDATA +# define FARDATA +#endif + +/* Typedef for floating-point numbers that are converted + to fixed-point with a multiple of 100,000, e.g., int_gamma */ +typedef png_int_32 png_fixed_point; + +/* Add typedefs for pointers */ +typedef void FAR * png_voidp; +typedef png_byte FAR * png_bytep; +typedef png_uint_32 FAR * png_uint_32p; +typedef png_int_32 FAR * png_int_32p; +typedef png_uint_16 FAR * png_uint_16p; +typedef png_int_16 FAR * png_int_16p; +typedef PNG_CONST char FAR * png_const_charp; +typedef char FAR * png_charp; +typedef png_fixed_point FAR * png_fixed_point_p; + +#ifndef PNG_NO_STDIO +#if defined(_WIN32_WCE) +typedef HANDLE png_FILE_p; +#else +typedef FILE * png_FILE_p; +#endif +#endif + +#ifdef PNG_FLOATING_POINT_SUPPORTED +typedef double FAR * png_doublep; +#endif + +/* Pointers to pointers; i.e. arrays */ +typedef png_byte FAR * FAR * png_bytepp; +typedef png_uint_32 FAR * FAR * png_uint_32pp; +typedef png_int_32 FAR * FAR * png_int_32pp; +typedef png_uint_16 FAR * FAR * png_uint_16pp; +typedef png_int_16 FAR * FAR * png_int_16pp; +typedef PNG_CONST char FAR * FAR * png_const_charpp; +typedef char FAR * FAR * png_charpp; +typedef png_fixed_point FAR * FAR * png_fixed_point_pp; +#ifdef PNG_FLOATING_POINT_SUPPORTED +typedef double FAR * FAR * png_doublepp; +#endif + +/* Pointers to pointers to pointers; i.e., pointer to array */ +typedef char FAR * FAR * FAR * png_charppp; + +/* libpng typedefs for types in zlib. If zlib changes + * or another compression library is used, then change these. + * Eliminates need to change all the source files. + */ +typedef charf * png_zcharp; +typedef charf * FAR * png_zcharpp; +typedef z_stream FAR * png_zstreamp; + +/* + * Define PNG_BUILD_DLL if the module being built is a Windows + * LIBPNG DLL. + * + * Define PNG_USE_DLL if you want to *link* to the Windows LIBPNG DLL. + * It is equivalent to Microsoft predefined macro _DLL that is + * automatically defined when you compile using the share + * version of the CRT (C Run-Time library) + * + * The cygwin mods make this behavior a little different: + * Define PNG_BUILD_DLL if you are building a dll for use with cygwin + * Define PNG_STATIC if you are building a static library for use with cygwin, + * -or- if you are building an application that you want to link to the + * static library. + * PNG_USE_DLL is defined by default (no user action needed) unless one of + * the other flags is defined. + */ + +#if !defined(PNG_DLL) && (defined(PNG_BUILD_DLL) || defined(PNG_USE_DLL)) +# define PNG_DLL +#endif +/* If CYGWIN, then disallow GLOBAL ARRAYS unless building a static lib. + * When building a static lib, default to no GLOBAL ARRAYS, but allow + * command-line override + */ +#if defined(__CYGWIN__) +# if !defined(PNG_STATIC) +# if defined(PNG_USE_GLOBAL_ARRAYS) +# undef PNG_USE_GLOBAL_ARRAYS +# endif +# if !defined(PNG_USE_LOCAL_ARRAYS) +# define PNG_USE_LOCAL_ARRAYS +# endif +# else +# if defined(PNG_USE_LOCAL_ARRAYS) || defined(PNG_NO_GLOBAL_ARRAYS) +# if defined(PNG_USE_GLOBAL_ARRAYS) +# undef PNG_USE_GLOBAL_ARRAYS +# endif +# endif +# endif +# if !defined(PNG_USE_LOCAL_ARRAYS) && !defined(PNG_USE_GLOBAL_ARRAYS) +# define PNG_USE_LOCAL_ARRAYS +# endif +#endif + +/* Do not use global arrays (helps with building DLL's) + * They are no longer used in libpng itself, since version 1.0.5c, + * but might be required for some pre-1.0.5c applications. + */ +#if !defined(PNG_USE_LOCAL_ARRAYS) && !defined(PNG_USE_GLOBAL_ARRAYS) +# if defined(PNG_NO_GLOBAL_ARRAYS) || (defined(__GNUC__) && defined(PNG_DLL)) +# define PNG_USE_LOCAL_ARRAYS +# else +# define PNG_USE_GLOBAL_ARRAYS +# endif +#endif + +#if defined(__CYGWIN__) +# undef PNGAPI +# define PNGAPI __cdecl +# undef PNG_IMPEXP +# define PNG_IMPEXP +#endif + +/* If you define PNGAPI, e.g., with compiler option "-DPNGAPI=__stdcall", + * you may get warnings regarding the linkage of png_zalloc and png_zfree. + * Don't ignore those warnings; you must also reset the default calling + * convention in your compiler to match your PNGAPI, and you must build + * zlib and your applications the same way you build libpng. + */ + +#ifndef PNGAPI + +#if defined(__MINGW32__) && !defined(PNG_MODULEDEF) +# ifndef PNG_NO_MODULEDEF +# define PNG_NO_MODULEDEF +# endif +#endif + +#if !defined(PNG_IMPEXP) && defined(PNG_BUILD_DLL) && !defined(PNG_NO_MODULEDEF) +# define PNG_IMPEXP +#endif + +#if defined(PNG_DLL) || defined(_DLL) || defined(__DLL__ ) || \ + (( defined(_Windows) || defined(_WINDOWS) || \ + defined(WIN32) || defined(_WIN32) || defined(__WIN32__) )) + +# if defined(__GNUC__) || (defined (_MSC_VER) && (_MSC_VER >= 800)) +# define PNGAPI __cdecl +# else +# define PNGAPI _cdecl +# endif + +# if !defined(PNG_IMPEXP) && (!defined(PNG_DLL) || \ + 0 /* WINCOMPILER_WITH_NO_SUPPORT_FOR_DECLIMPEXP */) +# define PNG_IMPEXP +# endif + +# if !defined(PNG_IMPEXP) + +# define PNG_EXPORT_TYPE1(type,symbol) PNG_IMPEXP type PNGAPI symbol +# define PNG_EXPORT_TYPE2(type,symbol) type PNG_IMPEXP PNGAPI symbol + + /* Borland/Microsoft */ +# if defined(_MSC_VER) || defined(__BORLANDC__) +# if (_MSC_VER >= 800) || (__BORLANDC__ >= 0x500) +# define PNG_EXPORT PNG_EXPORT_TYPE1 +# else +# define PNG_EXPORT PNG_EXPORT_TYPE2 +# if defined(PNG_BUILD_DLL) +# define PNG_IMPEXP __export +# else +# define PNG_IMPEXP /*__import */ /* doesn't exist AFAIK in + VC++ */ +# endif /* Exists in Borland C++ for + C++ classes (== huge) */ +# endif +# endif + +# if !defined(PNG_IMPEXP) +# if defined(PNG_BUILD_DLL) +# define PNG_IMPEXP __declspec(dllexport) +# else +# define PNG_IMPEXP __declspec(dllimport) +# endif +# endif +# endif /* PNG_IMPEXP */ +#else /* !(DLL || non-cygwin WINDOWS) */ +# if (defined(__IBMC__) || defined(IBMCPP__)) && defined(__OS2__) +# define PNGAPI _System +# define PNG_IMPEXP +# else +# if 0 /* ... other platforms, with other meanings */ +# else +# define PNGAPI +# define PNG_IMPEXP +# endif +# endif +#endif +#endif + +#ifndef PNGAPI +# define PNGAPI +#endif +#ifndef PNG_IMPEXP +# define PNG_IMPEXP +#endif + +#ifndef PNG_EXPORT +# define PNG_EXPORT(type,symbol) PNG_IMPEXP type PNGAPI symbol +#endif + +#ifdef PNG_USE_GLOBAL_ARRAYS +# ifndef PNG_EXPORT_VAR +# define PNG_EXPORT_VAR(type) extern PNG_IMPEXP type +# endif +#endif + +/* User may want to use these so they are not in PNG_INTERNAL. Any library + * functions that are passed far data must be model independent. + */ + +#ifndef PNG_ABORT +# define PNG_ABORT() abort() +#endif + +#ifdef PNG_SETJMP_SUPPORTED +# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) +#else +# define png_jmpbuf(png_ptr) \ + (LIBPNG_WAS_COMPILED_WITH__PNG_SETJMP_NOT_SUPPORTED) +#endif + +#if defined(USE_FAR_KEYWORD) /* memory model independent fns */ +/* use this to make far-to-near assignments */ +# define CHECK 1 +# define NOCHECK 0 +# define CVT_PTR(ptr) (png_far_to_near(png_ptr,ptr,CHECK)) +# define CVT_PTR_NOCHECK(ptr) (png_far_to_near(png_ptr,ptr,NOCHECK)) +# define png_strcpy _fstrcpy +# define png_strlen _fstrlen +# define png_memcmp _fmemcmp /* SJT: added */ +# define png_memcpy _fmemcpy +# define png_memset _fmemset +#else /* use the usual functions */ +# define CVT_PTR(ptr) (ptr) +# define CVT_PTR_NOCHECK(ptr) (ptr) +# define png_strcpy strcpy +# define png_strlen strlen +# define png_memcmp memcmp /* SJT: added */ +# define png_memcpy memcpy +# define png_memset memset +#endif +/* End of memory model independent support */ + +/* Just a little check that someone hasn't tried to define something + * contradictory. + */ +#if (PNG_ZBUF_SIZE > 65536) && defined(PNG_MAX_MALLOC_64K) +# undef PNG_ZBUF_SIZE +# define PNG_ZBUF_SIZE 65536 +#endif + +#ifdef PNG_READ_SUPPORTED +/* Prior to libpng-1.0.9, this block was in pngasmrd.h */ +#if defined(PNG_INTERNAL) + +/* These are the default thresholds before the MMX code kicks in; if either + * rowbytes or bitdepth is below the threshold, plain C code is used. These + * can be overridden at runtime via the png_set_mmx_thresholds() call in + * libpng 1.2.0 and later. The values below were chosen by Intel. + */ + +#ifndef PNG_MMX_ROWBYTES_THRESHOLD_DEFAULT +# define PNG_MMX_ROWBYTES_THRESHOLD_DEFAULT 128 /* >= */ +#endif +#ifndef PNG_MMX_BITDEPTH_THRESHOLD_DEFAULT +# define PNG_MMX_BITDEPTH_THRESHOLD_DEFAULT 9 /* >= */ +#endif + +/* Set this in the makefile for VC++ on Pentium, not here. */ +/* Platform must be Pentium. Makefile must assemble and load pngvcrd.c . + * MMX will be detected at run time and used if present. + */ +#ifdef PNG_USE_PNGVCRD +# define PNG_HAVE_ASSEMBLER_COMBINE_ROW +# define PNG_HAVE_ASSEMBLER_READ_INTERLACE +# define PNG_HAVE_ASSEMBLER_READ_FILTER_ROW +#endif + +/* Set this in the makefile for gcc/as on Pentium, not here. */ +/* Platform must be Pentium. Makefile must assemble and load pnggccrd.c . + * MMX will be detected at run time and used if present. + */ +#ifdef PNG_USE_PNGGCCRD +# define PNG_HAVE_ASSEMBLER_COMBINE_ROW +# define PNG_HAVE_ASSEMBLER_READ_INTERLACE +# define PNG_HAVE_ASSEMBLER_READ_FILTER_ROW +#endif +/* - see pnggccrd.c for info about what is currently enabled */ + +#endif /* PNG_INTERNAL */ +#endif /* PNG_READ_SUPPORTED */ + +#endif /* PNGCONF_H */ + diff --git a/winclude/tiff.h b/winclude/tiff.h new file mode 100755 index 000000000..6330795b6 --- /dev/null +++ b/winclude/tiff.h @@ -0,0 +1,647 @@ +/* $Id: tiff.h,v 1.42 2005/12/23 15:10:45 dron Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _TIFF_ +#define _TIFF_ + +#include "tiffconf.h" + +/* + * Tag Image File Format (TIFF) + * + * Based on Rev 6.0 from: + * Developer's Desk + * Aldus Corporation + * 411 First Ave. South + * Suite 200 + * Seattle, WA 98104 + * 206-622-5500 + * + * (http://partners.adobe.com/asn/developer/PDFS/TN/TIFF6.pdf) + * + * For Big TIFF design notes see the following link + * http://gdal.maptools.org/twiki/bin/view/libtiff/BigTIFFDesign + */ +#define TIFF_VERSION 42 +#define TIFF_BIGTIFF_VERSION 43 + +#define TIFF_BIGENDIAN 0x4d4d +#define TIFF_LITTLEENDIAN 0x4949 +#define MDI_LITTLEENDIAN 0x5045 +#define MDI_BIGENDIAN 0x4550 +/* + * Intrinsic data types required by the file format: + * + * 8-bit quantities int8/uint8 + * 16-bit quantities int16/uint16 + * 32-bit quantities int32/uint32 + * strings unsigned char* + */ + +#ifndef HAVE_INT8 +typedef signed char int8; /* NB: non-ANSI compilers may not grok */ +#endif +typedef unsigned char uint8; +#ifndef HAVE_INT16 +typedef short int16; +#endif +typedef unsigned short uint16; /* sizeof (uint16) must == 2 */ +#if SIZEOF_INT == 4 +#ifndef HAVE_INT32 +typedef int int32; +#endif +typedef unsigned int uint32; /* sizeof (uint32) must == 4 */ +#elif SIZEOF_LONG == 4 +#ifndef HAVE_INT32 +typedef long int32; +#endif +typedef unsigned long uint32; /* sizeof (uint32) must == 4 */ +#endif + +/* For TIFFReassignTagToIgnore */ +enum TIFFIgnoreSense /* IGNORE tag table */ +{ + TIS_STORE, + TIS_EXTRACT, + TIS_EMPTY +}; + +/* + * TIFF header. + */ +typedef struct { + uint16 tiff_magic; /* magic number (defines byte order) */ +#define TIFF_MAGIC_SIZE 2 + uint16 tiff_version; /* TIFF version number */ +#define TIFF_VERSION_SIZE 2 + uint32 tiff_diroff; /* byte offset to first directory */ +#define TIFF_DIROFFSET_SIZE 4 +} TIFFHeader; + + +/* + * TIFF Image File Directories are comprised of a table of field + * descriptors of the form shown below. The table is sorted in + * ascending order by tag. The values associated with each entry are + * disjoint and may appear anywhere in the file (so long as they are + * placed on a word boundary). + * + * If the value is 4 bytes or less, then it is placed in the offset + * field to save space. If the value is less than 4 bytes, it is + * left-justified in the offset field. + */ +typedef struct { + uint16 tdir_tag; /* see below */ + uint16 tdir_type; /* data type; see below */ + uint32 tdir_count; /* number of items; length in spec */ + uint32 tdir_offset; /* byte offset to field data */ +} TIFFDirEntry; + +/* + * NB: In the comments below, + * - items marked with a + are obsoleted by revision 5.0, + * - items marked with a ! are introduced in revision 6.0. + * - items marked with a % are introduced post revision 6.0. + * - items marked with a $ are obsoleted by revision 6.0. + * - items marked with a & are introduced by Adobe DNG specification. + */ + +/* + * Tag data type information. + * + * Note: RATIONALs are the ratio of two 32-bit integer values. + */ +typedef enum { + TIFF_NOTYPE = 0, /* placeholder */ + TIFF_BYTE = 1, /* 8-bit unsigned integer */ + TIFF_ASCII = 2, /* 8-bit bytes w/ last byte null */ + TIFF_SHORT = 3, /* 16-bit unsigned integer */ + TIFF_LONG = 4, /* 32-bit unsigned integer */ + TIFF_RATIONAL = 5, /* 64-bit unsigned fraction */ + TIFF_SBYTE = 6, /* !8-bit signed integer */ + TIFF_UNDEFINED = 7, /* !8-bit untyped data */ + TIFF_SSHORT = 8, /* !16-bit signed integer */ + TIFF_SLONG = 9, /* !32-bit signed integer */ + TIFF_SRATIONAL = 10, /* !64-bit signed fraction */ + TIFF_FLOAT = 11, /* !32-bit IEEE floating point */ + TIFF_DOUBLE = 12, /* !64-bit IEEE floating point */ + TIFF_IFD = 13 /* %32-bit unsigned integer (offset) */ +} TIFFDataType; + +/* + * TIFF Tag Definitions. + */ +#define TIFFTAG_SUBFILETYPE 254 /* subfile data descriptor */ +#define FILETYPE_REDUCEDIMAGE 0x1 /* reduced resolution version */ +#define FILETYPE_PAGE 0x2 /* one page of many */ +#define FILETYPE_MASK 0x4 /* transparency mask */ +#define TIFFTAG_OSUBFILETYPE 255 /* +kind of data in subfile */ +#define OFILETYPE_IMAGE 1 /* full resolution image data */ +#define OFILETYPE_REDUCEDIMAGE 2 /* reduced size image data */ +#define OFILETYPE_PAGE 3 /* one page of many */ +#define TIFFTAG_IMAGEWIDTH 256 /* image width in pixels */ +#define TIFFTAG_IMAGELENGTH 257 /* image height in pixels */ +#define TIFFTAG_BITSPERSAMPLE 258 /* bits per channel (sample) */ +#define TIFFTAG_COMPRESSION 259 /* data compression technique */ +#define COMPRESSION_NONE 1 /* dump mode */ +#define COMPRESSION_CCITTRLE 2 /* CCITT modified Huffman RLE */ +#define COMPRESSION_CCITTFAX3 3 /* CCITT Group 3 fax encoding */ +#define COMPRESSION_CCITT_T4 3 /* CCITT T.4 (TIFF 6 name) */ +#define COMPRESSION_CCITTFAX4 4 /* CCITT Group 4 fax encoding */ +#define COMPRESSION_CCITT_T6 4 /* CCITT T.6 (TIFF 6 name) */ +#define COMPRESSION_LZW 5 /* Lempel-Ziv & Welch */ +#define COMPRESSION_OJPEG 6 /* !6.0 JPEG */ +#define COMPRESSION_JPEG 7 /* %JPEG DCT compression */ +#define COMPRESSION_NEXT 32766 /* NeXT 2-bit RLE */ +#define COMPRESSION_CCITTRLEW 32771 /* #1 w/ word alignment */ +#define COMPRESSION_PACKBITS 32773 /* Macintosh RLE */ +#define COMPRESSION_THUNDERSCAN 32809 /* ThunderScan RLE */ +/* codes 32895-32898 are reserved for ANSI IT8 TIFF/IT */ +#define COMPRESSION_DCS 32947 /* Kodak DCS encoding */ +#define COMPRESSION_JBIG 34661 /* ISO JBIG */ +#define COMPRESSION_SGILOG 34676 /* SGI Log Luminance RLE */ +#define COMPRESSION_SGILOG24 34677 /* SGI Log 24-bit packed */ +#define COMPRESSION_JP2000 34712 /* Leadtools JPEG2000 */ +#define TIFFTAG_PHOTOMETRIC 262 /* photometric interpretation */ +#define PHOTOMETRIC_MINISWHITE 0 /* min value is white */ +#define PHOTOMETRIC_MINISBLACK 1 /* min value is black */ +#define PHOTOMETRIC_RGB 2 /* RGB color model */ +#define PHOTOMETRIC_PALETTE 3 /* color map indexed */ +#define PHOTOMETRIC_MASK 4 /* $holdout mask */ +#define PHOTOMETRIC_SEPARATED 5 /* !color separations */ +#define PHOTOMETRIC_YCBCR 6 /* !CCIR 601 */ +#define PHOTOMETRIC_CIELAB 8 /* !1976 CIE L*a*b* */ +#define PHOTOMETRIC_ICCLAB 9 /* ICC L*a*b* [Adobe TIFF Technote 4] */ +#define PHOTOMETRIC_ITULAB 10 /* ITU L*a*b* */ +#define PHOTOMETRIC_LOGL 32844 /* CIE Log2(L) */ +#define PHOTOMETRIC_LOGLUV 32845 /* CIE Log2(L) (u',v') */ +#define TIFFTAG_THRESHHOLDING 263 /* +thresholding used on data */ +#define THRESHHOLD_BILEVEL 1 /* b&w art scan */ +#define THRESHHOLD_HALFTONE 2 /* or dithered scan */ +#define THRESHHOLD_ERRORDIFFUSE 3 /* usually floyd-steinberg */ +#define TIFFTAG_CELLWIDTH 264 /* +dithering matrix width */ +#define TIFFTAG_CELLLENGTH 265 /* +dithering matrix height */ +#define TIFFTAG_FILLORDER 266 /* data order within a byte */ +#define FILLORDER_MSB2LSB 1 /* most significant -> least */ +#define FILLORDER_LSB2MSB 2 /* least significant -> most */ +#define TIFFTAG_DOCUMENTNAME 269 /* name of doc. image is from */ +#define TIFFTAG_IMAGEDESCRIPTION 270 /* info about image */ +#define TIFFTAG_MAKE 271 /* scanner manufacturer name */ +#define TIFFTAG_MODEL 272 /* scanner model name/number */ +#define TIFFTAG_STRIPOFFSETS 273 /* offsets to data strips */ +#define TIFFTAG_ORIENTATION 274 /* +image orientation */ +#define ORIENTATION_TOPLEFT 1 /* row 0 top, col 0 lhs */ +#define ORIENTATION_TOPRIGHT 2 /* row 0 top, col 0 rhs */ +#define ORIENTATION_BOTRIGHT 3 /* row 0 bottom, col 0 rhs */ +#define ORIENTATION_BOTLEFT 4 /* row 0 bottom, col 0 lhs */ +#define ORIENTATION_LEFTTOP 5 /* row 0 lhs, col 0 top */ +#define ORIENTATION_RIGHTTOP 6 /* row 0 rhs, col 0 top */ +#define ORIENTATION_RIGHTBOT 7 /* row 0 rhs, col 0 bottom */ +#define ORIENTATION_LEFTBOT 8 /* row 0 lhs, col 0 bottom */ +#define TIFFTAG_SAMPLESPERPIXEL 277 /* samples per pixel */ +#define TIFFTAG_ROWSPERSTRIP 278 /* rows per strip of data */ +#define TIFFTAG_STRIPBYTECOUNTS 279 /* bytes counts for strips */ +#define TIFFTAG_MINSAMPLEVALUE 280 /* +minimum sample value */ +#define TIFFTAG_MAXSAMPLEVALUE 281 /* +maximum sample value */ +#define TIFFTAG_XRESOLUTION 282 /* pixels/resolution in x */ +#define TIFFTAG_YRESOLUTION 283 /* pixels/resolution in y */ +#define TIFFTAG_PLANARCONFIG 284 /* storage organization */ +#define PLANARCONFIG_CONTIG 1 /* single image plane */ +#define PLANARCONFIG_SEPARATE 2 /* separate planes of data */ +#define TIFFTAG_PAGENAME 285 /* page name image is from */ +#define TIFFTAG_XPOSITION 286 /* x page offset of image lhs */ +#define TIFFTAG_YPOSITION 287 /* y page offset of image lhs */ +#define TIFFTAG_FREEOFFSETS 288 /* +byte offset to free block */ +#define TIFFTAG_FREEBYTECOUNTS 289 /* +sizes of free blocks */ +#define TIFFTAG_GRAYRESPONSEUNIT 290 /* $gray scale curve accuracy */ +#define GRAYRESPONSEUNIT_10S 1 /* tenths of a unit */ +#define GRAYRESPONSEUNIT_100S 2 /* hundredths of a unit */ +#define GRAYRESPONSEUNIT_1000S 3 /* thousandths of a unit */ +#define GRAYRESPONSEUNIT_10000S 4 /* ten-thousandths of a unit */ +#define GRAYRESPONSEUNIT_100000S 5 /* hundred-thousandths */ +#define TIFFTAG_GRAYRESPONSECURVE 291 /* $gray scale response curve */ +#define TIFFTAG_GROUP3OPTIONS 292 /* 32 flag bits */ +#define TIFFTAG_T4OPTIONS 292 /* TIFF 6.0 proper name alias */ +#define GROUP3OPT_2DENCODING 0x1 /* 2-dimensional coding */ +#define GROUP3OPT_UNCOMPRESSED 0x2 /* data not compressed */ +#define GROUP3OPT_FILLBITS 0x4 /* fill to byte boundary */ +#define TIFFTAG_GROUP4OPTIONS 293 /* 32 flag bits */ +#define TIFFTAG_T6OPTIONS 293 /* TIFF 6.0 proper name */ +#define GROUP4OPT_UNCOMPRESSED 0x2 /* data not compressed */ +#define TIFFTAG_RESOLUTIONUNIT 296 /* units of resolutions */ +#define RESUNIT_NONE 1 /* no meaningful units */ +#define RESUNIT_INCH 2 /* english */ +#define RESUNIT_CENTIMETER 3 /* metric */ +#define TIFFTAG_PAGENUMBER 297 /* page numbers of multi-page */ +#define TIFFTAG_COLORRESPONSEUNIT 300 /* $color curve accuracy */ +#define COLORRESPONSEUNIT_10S 1 /* tenths of a unit */ +#define COLORRESPONSEUNIT_100S 2 /* hundredths of a unit */ +#define COLORRESPONSEUNIT_1000S 3 /* thousandths of a unit */ +#define COLORRESPONSEUNIT_10000S 4 /* ten-thousandths of a unit */ +#define COLORRESPONSEUNIT_100000S 5 /* hundred-thousandths */ +#define TIFFTAG_TRANSFERFUNCTION 301 /* !colorimetry info */ +#define TIFFTAG_SOFTWARE 305 /* name & release */ +#define TIFFTAG_DATETIME 306 /* creation date and time */ +#define TIFFTAG_ARTIST 315 /* creator of image */ +#define TIFFTAG_HOSTCOMPUTER 316 /* machine where created */ +#define TIFFTAG_PREDICTOR 317 /* prediction scheme w/ LZW */ +#define PREDICTOR_NONE 1 /* no prediction scheme used */ +#define PREDICTOR_HORIZONTAL 2 /* horizontal differencing */ +#define PREDICTOR_FLOATINGPOINT 3 /* floating point predictor */ +#define TIFFTAG_WHITEPOINT 318 /* image white point */ +#define TIFFTAG_PRIMARYCHROMATICITIES 319 /* !primary chromaticities */ +#define TIFFTAG_COLORMAP 320 /* RGB map for pallette image */ +#define TIFFTAG_HALFTONEHINTS 321 /* !highlight+shadow info */ +#define TIFFTAG_TILEWIDTH 322 /* !tile width in pixels */ +#define TIFFTAG_TILELENGTH 323 /* !tile height in pixels */ +#define TIFFTAG_TILEOFFSETS 324 /* !offsets to data tiles */ +#define TIFFTAG_TILEBYTECOUNTS 325 /* !byte counts for tiles */ +#define TIFFTAG_BADFAXLINES 326 /* lines w/ wrong pixel count */ +#define TIFFTAG_CLEANFAXDATA 327 /* regenerated line info */ +#define CLEANFAXDATA_CLEAN 0 /* no errors detected */ +#define CLEANFAXDATA_REGENERATED 1 /* receiver regenerated lines */ +#define CLEANFAXDATA_UNCLEAN 2 /* uncorrected errors exist */ +#define TIFFTAG_CONSECUTIVEBADFAXLINES 328 /* max consecutive bad lines */ +#define TIFFTAG_SUBIFD 330 /* subimage descriptors */ +#define TIFFTAG_INKSET 332 /* !inks in separated image */ +#define INKSET_CMYK 1 /* !cyan-magenta-yellow-black color */ +#define INKSET_MULTIINK 2 /* !multi-ink or hi-fi color */ +#define TIFFTAG_INKNAMES 333 /* !ascii names of inks */ +#define TIFFTAG_NUMBEROFINKS 334 /* !number of inks */ +#define TIFFTAG_DOTRANGE 336 /* !0% and 100% dot codes */ +#define TIFFTAG_TARGETPRINTER 337 /* !separation target */ +#define TIFFTAG_EXTRASAMPLES 338 /* !info about extra samples */ +#define EXTRASAMPLE_UNSPECIFIED 0 /* !unspecified data */ +#define EXTRASAMPLE_ASSOCALPHA 1 /* !associated alpha data */ +#define EXTRASAMPLE_UNASSALPHA 2 /* !unassociated alpha data */ +#define TIFFTAG_SAMPLEFORMAT 339 /* !data sample format */ +#define SAMPLEFORMAT_UINT 1 /* !unsigned integer data */ +#define SAMPLEFORMAT_INT 2 /* !signed integer data */ +#define SAMPLEFORMAT_IEEEFP 3 /* !IEEE floating point data */ +#define SAMPLEFORMAT_VOID 4 /* !untyped data */ +#define SAMPLEFORMAT_COMPLEXINT 5 /* !complex signed int */ +#define SAMPLEFORMAT_COMPLEXIEEEFP 6 /* !complex ieee floating */ +#define TIFFTAG_SMINSAMPLEVALUE 340 /* !variable MinSampleValue */ +#define TIFFTAG_SMAXSAMPLEVALUE 341 /* !variable MaxSampleValue */ +#define TIFFTAG_CLIPPATH 343 /* %ClipPath + [Adobe TIFF technote 2] */ +#define TIFFTAG_XCLIPPATHUNITS 344 /* %XClipPathUnits + [Adobe TIFF technote 2] */ +#define TIFFTAG_YCLIPPATHUNITS 345 /* %YClipPathUnits + [Adobe TIFF technote 2] */ +#define TIFFTAG_INDEXED 346 /* %Indexed + [Adobe TIFF Technote 3] */ +#define TIFFTAG_JPEGTABLES 347 /* %JPEG table stream */ +#define TIFFTAG_OPIPROXY 351 /* %OPI Proxy [Adobe TIFF technote] */ +/* + * Tags 512-521 are obsoleted by Technical Note #2 which specifies a + * revised JPEG-in-TIFF scheme. + */ +#define TIFFTAG_JPEGPROC 512 /* !JPEG processing algorithm */ +#define JPEGPROC_BASELINE 1 /* !baseline sequential */ +#define JPEGPROC_LOSSLESS 14 /* !Huffman coded lossless */ +#define TIFFTAG_JPEGIFOFFSET 513 /* !pointer to SOI marker */ +#define TIFFTAG_JPEGIFBYTECOUNT 514 /* !JFIF stream length */ +#define TIFFTAG_JPEGRESTARTINTERVAL 515 /* !restart interval length */ +#define TIFFTAG_JPEGLOSSLESSPREDICTORS 517 /* !lossless proc predictor */ +#define TIFFTAG_JPEGPOINTTRANSFORM 518 /* !lossless point transform */ +#define TIFFTAG_JPEGQTABLES 519 /* !Q matrice offsets */ +#define TIFFTAG_JPEGDCTABLES 520 /* !DCT table offsets */ +#define TIFFTAG_JPEGACTABLES 521 /* !AC coefficient offsets */ +#define TIFFTAG_YCBCRCOEFFICIENTS 529 /* !RGB -> YCbCr transform */ +#define TIFFTAG_YCBCRSUBSAMPLING 530 /* !YCbCr subsampling factors */ +#define TIFFTAG_YCBCRPOSITIONING 531 /* !subsample positioning */ +#define YCBCRPOSITION_CENTERED 1 /* !as in PostScript Level 2 */ +#define YCBCRPOSITION_COSITED 2 /* !as in CCIR 601-1 */ +#define TIFFTAG_REFERENCEBLACKWHITE 532 /* !colorimetry info */ +#define TIFFTAG_XMLPACKET 700 /* %XML packet + [Adobe XMP Specification, + January 2004 */ +#define TIFFTAG_OPIIMAGEID 32781 /* %OPI ImageID + [Adobe TIFF technote] */ +/* tags 32952-32956 are private tags registered to Island Graphics */ +#define TIFFTAG_REFPTS 32953 /* image reference points */ +#define TIFFTAG_REGIONTACKPOINT 32954 /* region-xform tack point */ +#define TIFFTAG_REGIONWARPCORNERS 32955 /* warp quadrilateral */ +#define TIFFTAG_REGIONAFFINE 32956 /* affine transformation mat */ +/* tags 32995-32999 are private tags registered to SGI */ +#define TIFFTAG_MATTEING 32995 /* $use ExtraSamples */ +#define TIFFTAG_DATATYPE 32996 /* $use SampleFormat */ +#define TIFFTAG_IMAGEDEPTH 32997 /* z depth of image */ +#define TIFFTAG_TILEDEPTH 32998 /* z depth/data tile */ +/* tags 33300-33309 are private tags registered to Pixar */ +/* + * TIFFTAG_PIXAR_IMAGEFULLWIDTH and TIFFTAG_PIXAR_IMAGEFULLLENGTH + * are set when an image has been cropped out of a larger image. + * They reflect the size of the original uncropped image. + * The TIFFTAG_XPOSITION and TIFFTAG_YPOSITION can be used + * to determine the position of the smaller image in the larger one. + */ +#define TIFFTAG_PIXAR_IMAGEFULLWIDTH 33300 /* full image size in x */ +#define TIFFTAG_PIXAR_IMAGEFULLLENGTH 33301 /* full image size in y */ + /* Tags 33302-33306 are used to identify special image modes and data + * used by Pixar's texture formats. + */ +#define TIFFTAG_PIXAR_TEXTUREFORMAT 33302 /* texture map format */ +#define TIFFTAG_PIXAR_WRAPMODES 33303 /* s & t wrap modes */ +#define TIFFTAG_PIXAR_FOVCOT 33304 /* cotan(fov) for env. maps */ +#define TIFFTAG_PIXAR_MATRIX_WORLDTOSCREEN 33305 +#define TIFFTAG_PIXAR_MATRIX_WORLDTOCAMERA 33306 +/* tag 33405 is a private tag registered to Eastman Kodak */ +#define TIFFTAG_WRITERSERIALNUMBER 33405 /* device serial number */ +/* tag 33432 is listed in the 6.0 spec w/ unknown ownership */ +#define TIFFTAG_COPYRIGHT 33432 /* copyright string */ +/* IPTC TAG from RichTIFF specifications */ +#define TIFFTAG_RICHTIFFIPTC 33723 +/* 34016-34029 are reserved for ANSI IT8 TIFF/IT */ +#define TIFFTAG_STONITS 37439 /* Sample value to Nits */ +/* tag 34929 is a private tag registered to FedEx */ +#define TIFFTAG_FEDEX_EDR 34929 /* unknown use */ +#define TIFFTAG_INTEROPERABILITYIFD 40965 /* Pointer to Interoperability private directory */ +/* Adobe Digital Negative (DNG) format tags */ +#define TIFFTAG_DNGVERSION 50706 /* &DNG version number */ +#define TIFFTAG_DNGBACKWARDVERSION 50707 /* &DNG compatibility version */ +#define TIFFTAG_UNIQUECAMERAMODEL 50708 /* &name for the camera model */ +#define TIFFTAG_LOCALIZEDCAMERAMODEL 50709 /* &localized camera model + name */ +#define TIFFTAG_CFAPLANECOLOR 50710 /* &CFAPattern->LinearRaw space + mapping */ +#define TIFFTAG_CFALAYOUT 50711 /* &spatial layout of the CFA */ +#define TIFFTAG_LINEARIZATIONTABLE 50712 /* &lookup table description */ +#define TIFFTAG_BLACKLEVELREPEATDIM 50713 /* &repeat pattern size for + the BlackLevel tag */ +#define TIFFTAG_BLACKLEVEL 50714 /* &zero light encoding level */ +#define TIFFTAG_BLACKLEVELDELTAH 50715 /* &zero light encoding level + differences (columns) */ +#define TIFFTAG_BLACKLEVELDELTAV 50716 /* &zero light encoding level + differences (rows) */ +#define TIFFTAG_WHITELEVEL 50717 /* &fully saturated encoding + level */ +#define TIFFTAG_DEFAULTSCALE 50718 /* &default scale factors */ +#define TIFFTAG_DEFAULTCROPORIGIN 50719 /* &origin of the final image + area */ +#define TIFFTAG_DEFAULTCROPSIZE 50720 /* &size of the final image + area */ +#define TIFFTAG_COLORMATRIX1 50721 /* &XYZ->reference color space + transformation matrix 1 */ +#define TIFFTAG_COLORMATRIX2 50722 /* &XYZ->reference color space + transformation matrix 2 */ +#define TIFFTAG_CAMERACALIBRATION1 50723 /* &calibration matrix 1 */ +#define TIFFTAG_CAMERACALIBRATION2 50724 /* &calibration matrix 2 */ +#define TIFFTAG_REDUCTIONMATRIX1 50725 /* &dimensionality reduction + matrix 1 */ +#define TIFFTAG_REDUCTIONMATRIX2 50726 /* &dimensionality reduction + matrix 2 */ +#define TIFFTAG_ANALOGBALANCE 50727 /* &gain applied the stored raw + values*/ +#define TIFFTAG_ASSHOTNEUTRAL 50728 /* &selected white balance in + linear reference space */ +#define TIFFTAG_ASSHOTWHITEXY 50729 /* &selected white balance in + x-y chromaticity + coordinates */ +#define TIFFTAG_BASELINEEXPOSURE 50730 /* &how much to move the zero + point */ +#define TIFFTAG_BASELINENOISE 50731 /* &relative noise level */ +#define TIFFTAG_BASELINESHARPNESS 50732 /* &relative amount of + sharpening */ +#define TIFFTAG_BAYERGREENSPLIT 50733 /* &how closely the values of + the green pixels in the + blue/green rows track the + values of the green pixels + in the red/green rows */ +#define TIFFTAG_LINEARRESPONSELIMIT 50734 /* &non-linear encoding range */ +#define TIFFTAG_CAMERASERIALNUMBER 50735 /* &camera's serial number */ +#define TIFFTAG_LENSINFO 50736 /* info about the lens */ +#define TIFFTAG_CHROMABLURRADIUS 50737 /* &chroma blur radius */ +#define TIFFTAG_ANTIALIASSTRENGTH 50738 /* &relative strength of the + camera's anti-alias filter */ +#define TIFFTAG_SHADOWSCALE 50739 /* &used by Adobe Camera Raw */ +#define TIFFTAG_DNGPRIVATEDATA 50740 /* &manufacturer's private data */ +#define TIFFTAG_MAKERNOTESAFETY 50741 /* &whether the EXIF MakerNote + tag is safe to preserve + along with the rest of the + EXIF data */ +#define TIFFTAG_CALIBRATIONILLUMINANT1 50778 /* &illuminant 1 */ +#define TIFFTAG_CALIBRATIONILLUMINANT2 50779 /* &illuminant 2 */ +#define TIFFTAG_BESTQUALITYSCALE 50780 /* &best quality multiplier */ +#define TIFFTAG_RAWDATAUNIQUEID 50781 /* &unique identifier for + the raw image data */ +#define TIFFTAG_ORIGINALRAWFILENAME 50827 /* &file name of the original + raw file */ +#define TIFFTAG_ORIGINALRAWFILEDATA 50828 /* &contents of the original + raw file */ +#define TIFFTAG_ACTIVEAREA 50829 /* &active (non-masked) pixels + of the sensor */ +#define TIFFTAG_MASKEDAREAS 50830 /* &list of coordinates + of fully masked pixels */ +#define TIFFTAG_ASSHOTICCPROFILE 50831 /* &these two tags used to */ +#define TIFFTAG_ASSHOTPREPROFILEMATRIX 50832 /* map cameras's color space + into ICC profile space */ +#define TIFFTAG_CURRENTICCPROFILE 50833 /* & */ +#define TIFFTAG_CURRENTPREPROFILEMATRIX 50834 /* & */ +/* tag 65535 is an undefined tag used by Eastman Kodak */ +#define TIFFTAG_DCSHUESHIFTVALUES 65535 /* hue shift correction data */ + +/* + * The following are ``pseudo tags'' that can be used to control + * codec-specific functionality. These tags are not written to file. + * Note that these values start at 0xffff+1 so that they'll never + * collide with Aldus-assigned tags. + * + * If you want your private pseudo tags ``registered'' (i.e. added to + * this file), please post a bug report via the tracking system at + * http://www.remotesensing.org/libtiff/bugs.html with the appropriate + * C definitions to add. + */ +#define TIFFTAG_FAXMODE 65536 /* Group 3/4 format control */ +#define FAXMODE_CLASSIC 0x0000 /* default, include RTC */ +#define FAXMODE_NORTC 0x0001 /* no RTC at end of data */ +#define FAXMODE_NOEOL 0x0002 /* no EOL code at end of row */ +#define FAXMODE_BYTEALIGN 0x0004 /* byte align row */ +#define FAXMODE_WORDALIGN 0x0008 /* word align row */ +#define FAXMODE_CLASSF FAXMODE_NORTC /* TIFF Class F */ +#define TIFFTAG_JPEGQUALITY 65537 /* Compression quality level */ +/* Note: quality level is on the IJG 0-100 scale. Default value is 75 */ +#define TIFFTAG_JPEGCOLORMODE 65538 /* Auto RGB<=>YCbCr convert? */ +#define JPEGCOLORMODE_RAW 0x0000 /* no conversion (default) */ +#define JPEGCOLORMODE_RGB 0x0001 /* do auto conversion */ +#define TIFFTAG_JPEGTABLESMODE 65539 /* What to put in JPEGTables */ +#define JPEGTABLESMODE_QUANT 0x0001 /* include quantization tbls */ +#define JPEGTABLESMODE_HUFF 0x0002 /* include Huffman tbls */ +/* Note: default is JPEGTABLESMODE_QUANT | JPEGTABLESMODE_HUFF */ +#define TIFFTAG_FAXFILLFUNC 65540 /* G3/G4 fill function */ +#define TIFFTAG_PIXARLOGDATAFMT 65549 /* PixarLogCodec I/O data sz */ +#define PIXARLOGDATAFMT_8BIT 0 /* regular u_char samples */ +#define PIXARLOGDATAFMT_8BITABGR 1 /* ABGR-order u_chars */ +#define PIXARLOGDATAFMT_11BITLOG 2 /* 11-bit log-encoded (raw) */ +#define PIXARLOGDATAFMT_12BITPICIO 3 /* as per PICIO (1.0==2048) */ +#define PIXARLOGDATAFMT_16BIT 4 /* signed short samples */ +#define PIXARLOGDATAFMT_FLOAT 5 /* IEEE float samples */ +/* 65550-65556 are allocated to Oceana Matrix */ +#define TIFFTAG_DCSIMAGERTYPE 65550 /* imager model & filter */ +#define DCSIMAGERMODEL_M3 0 /* M3 chip (1280 x 1024) */ +#define DCSIMAGERMODEL_M5 1 /* M5 chip (1536 x 1024) */ +#define DCSIMAGERMODEL_M6 2 /* M6 chip (3072 x 2048) */ +#define DCSIMAGERFILTER_IR 0 /* infrared filter */ +#define DCSIMAGERFILTER_MONO 1 /* monochrome filter */ +#define DCSIMAGERFILTER_CFA 2 /* color filter array */ +#define DCSIMAGERFILTER_OTHER 3 /* other filter */ +#define TIFFTAG_DCSINTERPMODE 65551 /* interpolation mode */ +#define DCSINTERPMODE_NORMAL 0x0 /* whole image, default */ +#define DCSINTERPMODE_PREVIEW 0x1 /* preview of image (384x256) */ +#define TIFFTAG_DCSBALANCEARRAY 65552 /* color balance values */ +#define TIFFTAG_DCSCORRECTMATRIX 65553 /* color correction values */ +#define TIFFTAG_DCSGAMMA 65554 /* gamma value */ +#define TIFFTAG_DCSTOESHOULDERPTS 65555 /* toe & shoulder points */ +#define TIFFTAG_DCSCALIBRATIONFD 65556 /* calibration file desc */ +/* Note: quality level is on the ZLIB 1-9 scale. Default value is -1 */ +#define TIFFTAG_ZIPQUALITY 65557 /* compression quality level */ +#define TIFFTAG_PIXARLOGQUALITY 65558 /* PixarLog uses same scale */ +/* 65559 is allocated to Oceana Matrix */ +#define TIFFTAG_DCSCLIPRECTANGLE 65559 /* area of image to acquire */ +#define TIFFTAG_SGILOGDATAFMT 65560 /* SGILog user data format */ +#define SGILOGDATAFMT_FLOAT 0 /* IEEE float samples */ +#define SGILOGDATAFMT_16BIT 1 /* 16-bit samples */ +#define SGILOGDATAFMT_RAW 2 /* uninterpreted data */ +#define SGILOGDATAFMT_8BIT 3 /* 8-bit RGB monitor values */ +#define TIFFTAG_SGILOGENCODE 65561 /* SGILog data encoding control*/ +#define SGILOGENCODE_NODITHER 0 /* do not dither encoded values*/ +#define SGILOGENCODE_RANDITHER 1 /* randomly dither encd values */ + +/* + * EXIF tags + */ +#define EXIFTAG_EXPOSURETIME 33434 /* Exposure time */ +#define EXIFTAG_FNUMBER 33437 /* F number */ +#define EXIFTAG_EXPOSUREPROGRAM 34850 /* Exposure program */ +#define EXIFTAG_SPECTRALSENSITIVITY 34852 /* Spectral sensitivity */ +#define EXIFTAG_ISOSPEEDRATINGS 34855 /* ISO speed rating */ +#define EXIFTAG_OECF 34856 /* Optoelectric conversion + factor */ +#define EXIFTAG_EXIFVERSION 36864 /* Exif version */ +#define EXIFTAG_DATETIMEORIGINAL 36867 /* Date and time of original + data generation */ +#define EXIFTAG_DATETIMEDIGITIZED 36868 /* Date and time of digital + data generation */ +#define EXIFTAG_COMPONENTSCONFIGURATION 37121 /* Meaning of each component */ +#define EXIFTAG_COMPRESSEDBITSPERPIXEL 37122 /* Image compression mode */ +#define EXIFTAG_SHUTTERSPEEDVALUE 37377 /* Shutter speed */ +#define EXIFTAG_APERTUREVALUE 37378 /* Aperture */ +#define EXIFTAG_BRIGHTNESSVALUE 37379 /* Brightness */ +#define EXIFTAG_EXPOSUREBIASVALUE 37380 /* Exposure bias */ +#define EXIFTAG_MAXAPERTUREVALUE 37381 /* Maximum lens aperture */ +#define EXIFTAG_SUBJECTDISTANCE 37382 /* Subject distance */ +#define EXIFTAG_METERINGMODE 37383 /* Metering mode */ +#define EXIFTAG_LIGHTSOURCE 37384 /* Light source */ +#define EXIFTAG_FLASH 37385 /* Flash */ +#define EXIFTAG_FOCALLENGTH 37386 /* Lens focal length */ +#define EXIFTAG_SUBJECTAREA 37396 /* Subject area */ +#define EXIFTAG_MAKERNOTE 37500 /* Manufacturer notes */ +#define EXIFTAG_USERCOMMENT 37510 /* User comments */ +#define EXIFTAG_SUBSECTIME 37520 /* DateTime subseconds */ +#define EXIFTAG_SUBSECTIMEORIGINAL 37521 /* DateTimeOriginal subseconds */ +#define EXIFTAG_SUBSECTIMEDIGITIZED 37522 /* DateTimeDigitized subseconds */ +#define EXIFTAG_FLASHPIXVERSION 40960 /* Supported Flashpix version */ +#define EXIFTAG_COLORSPACE 40961 /* Color space information */ +#define EXIFTAG_PIXELXDIMENSION 40962 /* Valid image width */ +#define EXIFTAG_PIXELYDIMENSION 40963 /* Valid image height */ +#define EXIFTAG_RELATEDSOUNDFILE 40964 /* Related audio file */ +#define EXIFTAG_FLASHENERGY 41483 /* Flash energy */ +#define EXIFTAG_SPATIALFREQUENCYRESPONSE 41484 /* Spatial frequency response */ +#define EXIFTAG_FOCALPLANEXRESOLUTION 41486 /* Focal plane X resolution */ +#define EXIFTAG_FOCALPLANEYRESOLUTION 41487 /* Focal plane Y resolution */ +#define EXIFTAG_FOCALPLANERESOLUTIONUNIT 41488 /* Focal plane resolution unit */ +#define EXIFTAG_SUBJECTLOCATION 41492 /* Subject location */ +#define EXIFTAG_EXPOSUREINDEX 41493 /* Exposure index */ +#define EXIFTAG_SENSINGMETHOD 41495 /* Sensing method */ +#define EXIFTAG_FILESOURCE 41728 /* File source */ +#define EXIFTAG_SCENETYPE 41729 /* Scene type */ +#define EXIFTAG_CFAPATTERN 41730 /* CFA pattern */ +#define EXIFTAG_CUSTOMRENDERED 41985 /* Custom image processing */ +#define EXIFTAG_EXPOSUREMODE 41986 /* Exposure mode */ +#define EXIFTAG_WHITEBALANCE 41987 /* White balance */ +#define EXIFTAG_DIGITALZOOMRATIO 41988 /* Digital zoom ratio */ +#define EXIFTAG_FOCALLENGTHIN35MMFILM 41989 /* Focal length in 35 mm film */ +#define EXIFTAG_SCENECAPTURETYPE 41990 /* Scene capture type */ +#define EXIFTAG_GAINCONTROL 41991 /* Gain control */ +#define EXIFTAG_CONTRAST 41992 /* Contrast */ +#define EXIFTAG_SATURATION 41993 /* Saturation */ +#define EXIFTAG_SHARPNESS 41994 /* Sharpness */ +#define EXIFTAG_DEVICESETTINGDESCRIPTION 41995 /* Device settings description */ +#define EXIFTAG_SUBJECTDISTANCERANGE 41996 /* Subject distance range */ +#define EXIFTAG_GAINCONTROL 41991 /* Gain control */ +#define EXIFTAG_GAINCONTROL 41991 /* Gain control */ +#define EXIFTAG_IMAGEUNIQUEID 42016 /* Unique image ID */ + +#endif /* _TIFF_ */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ diff --git a/winclude/tiffconf.h b/winclude/tiffconf.h new file mode 100755 index 000000000..1b7a4d511 --- /dev/null +++ b/winclude/tiffconf.h @@ -0,0 +1,101 @@ +/* libtiff/tiffconf.h. Generated by configure. */ +/* + Configuration defines for installed libtiff. + This file maintained for backward compatibility. Do not use definitions + from this file in your programs. +*/ + +#ifndef _TIFFCONF_ +#define _TIFFCONF_ + +/* Define to 1 if the system has the type `int16'. */ +/* #undef HAVE_INT16 */ + +/* Define to 1 if the system has the type `int32'. */ +/* #undef HAVE_INT32 */ + +/* Define to 1 if the system has the type `int8'. */ +/* #undef HAVE_INT8 */ + +/* The size of a `int', as computed by sizeof. */ +#define SIZEOF_INT 4 + +/* The size of a `long', as computed by sizeof. */ +#define SIZEOF_LONG 4 + +/* Compatibility stuff. */ + +/* Define as 0 or 1 according to the floating point format suported by the + machine */ +#define HAVE_IEEEFP 1 + +/* Set the native cpu bit order (FILLORDER_LSB2MSB or FILLORDER_MSB2LSB) */ +#define HOST_FILLORDER FILLORDER_LSB2MSB + +/* Native cpu byte order: 1 if big-endian (Motorola) or 0 if little-endian + (Intel) */ +#define HOST_BIGENDIAN 0 + +/* Support CCITT Group 3 & 4 algorithms */ +#define CCITT_SUPPORT 1 + +/* Support JPEG compression (requires IJG JPEG library) */ +/* #undef JPEG_SUPPORT */ + +/* Support LogLuv high dynamic range encoding */ +#define LOGLUV_SUPPORT 1 + +/* Support LZW algorithm */ +#define LZW_SUPPORT 1 + +/* Support NeXT 2-bit RLE algorithm */ +#define NEXT_SUPPORT 1 + +/* Support Old JPEG compresson (read contrib/ojpeg/README first! Compilation + fails with unpatched IJG JPEG library) */ +/* #undef OJPEG_SUPPORT */ + +/* Support Macintosh PackBits algorithm */ +#define PACKBITS_SUPPORT 1 + +/* Support Pixar log-format algorithm (requires Zlib) */ +#define PIXARLOG_SUPPORT 1 + +/* Support ThunderScan 4-bit RLE algorithm */ +#define THUNDER_SUPPORT 1 + +/* Support Deflate compression */ +#define ZIP_SUPPORT 1 + +/* Support strip chopping (whether or not to convert single-strip uncompressed + images to mutiple strips of ~8Kb to reduce memory usage) */ +#define STRIPCHOP_DEFAULT TIFF_STRIPCHOP + +/* Enable SubIFD tag (330) support */ +#define SUBIFD_SUPPORT 1 + +/* Treat extra sample as alpha (default enabled). The RGBA interface will + treat a fourth sample with no EXTRASAMPLE_ value as being ASSOCALPHA. Many + packages produce RGBA files but don't mark the alpha properly. */ +#define DEFAULT_EXTRASAMPLE_AS_ALPHA 1 + +/* Pick up YCbCr subsampling info from the JPEG data stream to support files + lacking the tag (default enabled). */ +#define CHECK_JPEG_YCBCR_SUBSAMPLING 1 + +/* Support MS MDI magic number files as TIFF */ +#define MDI_SUPPORT 1 + +/* + * Feature support definitions. + * XXX: These macros are obsoleted. Don't use them in your apps! + * Macros stays here for backward compatibility and should be always defined. + */ +#define COLORIMETRY_SUPPORT +#define YCBCR_SUPPORT +#define CMYK_SUPPORT +#define ICC_SUPPORT +#define PHOTOSHOP_SUPPORT +#define IPTC_SUPPORT + +#endif /* _TIFFCONF_ */ diff --git a/winclude/tiffio.h b/winclude/tiffio.h new file mode 100755 index 000000000..61c3d642a --- /dev/null +++ b/winclude/tiffio.h @@ -0,0 +1,516 @@ +/* $Id: tiffio.h,v 1.49 2005/12/27 11:13:58 dron Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _TIFFIO_ +#define _TIFFIO_ + +/* + * TIFF I/O Library Definitions. + */ +#include "tiff.h" +#include "tiffvers.h" + +/* + * TIFF is defined as an incomplete type to hide the + * library's internal data structures from clients. + */ +typedef struct tiff TIFF; + +/* + * The following typedefs define the intrinsic size of + * data types used in the *exported* interfaces. These + * definitions depend on the proper definition of types + * in tiff.h. Note also that the varargs interface used + * to pass tag types and values uses the types defined in + * tiff.h directly. + * + * NB: ttag_t is unsigned int and not unsigned short because + * ANSI C requires that the type before the ellipsis be a + * promoted type (i.e. one of int, unsigned int, pointer, + * or double) and because we defined pseudo-tags that are + * outside the range of legal Aldus-assigned tags. + * NB: tsize_t is int32 and not uint32 because some functions + * return -1. + * NB: toff_t is not off_t for many reasons; TIFFs max out at + * 32-bit file offsets being the most important, and to ensure + * that it is unsigned, rather than signed. + */ +typedef uint32 ttag_t; /* directory tag */ +typedef uint16 tdir_t; /* directory index */ +typedef uint16 tsample_t; /* sample number */ +typedef uint32 tstrip_t; /* strip number */ +typedef uint32 ttile_t; /* tile number */ +typedef int32 tsize_t; /* i/o size in bytes */ +typedef void* tdata_t; /* image data ref */ +typedef uint32 toff_t; /* file offset */ + +#if !defined(__WIN32__) && (defined(_WIN32) || defined(WIN32)) +#define __WIN32__ +#endif + +/* + * On windows you should define USE_WIN32_FILEIO if you are using tif_win32.c + * or AVOID_WIN32_FILEIO if you are using something else (like tif_unix.c). + * + * By default tif_win32.c is assumed on windows if not using the cygwin + * environment. + */ + +#if defined(_WINDOWS) || defined(__WIN32__) || defined(_Windows) +# if !defined(__CYGWIN) && !defined(AVOID_WIN32_FILEIO) && !defined(USE_WIN32_FILEIO) +# define USE_WIN32_FILEIO +# endif +#endif + +#if defined(USE_WIN32_FILEIO) +# define VC_EXTRALEAN +# include +# ifdef __WIN32__ +DECLARE_HANDLE(thandle_t); /* Win32 file handle */ +# else +typedef HFILE thandle_t; /* client data handle */ +# endif /* __WIN32__ */ +#else +typedef void* thandle_t; /* client data handle */ +#endif /* USE_WIN32_FILEIO */ + +#ifndef NULL +# define NULL (void *)0 +#endif + +/* + * Flags to pass to TIFFPrintDirectory to control + * printing of data structures that are potentially + * very large. Bit-or these flags to enable printing + * multiple items. + */ +#define TIFFPRINT_NONE 0x0 /* no extra info */ +#define TIFFPRINT_STRIPS 0x1 /* strips/tiles info */ +#define TIFFPRINT_CURVES 0x2 /* color/gray response curves */ +#define TIFFPRINT_COLORMAP 0x4 /* colormap */ +#define TIFFPRINT_JPEGQTABLES 0x100 /* JPEG Q matrices */ +#define TIFFPRINT_JPEGACTABLES 0x200 /* JPEG AC tables */ +#define TIFFPRINT_JPEGDCTABLES 0x200 /* JPEG DC tables */ + +/* + * Colour conversion stuff + */ + +/* reference white */ +#define D65_X0 (95.0470F) +#define D65_Y0 (100.0F) +#define D65_Z0 (108.8827F) + +#define D50_X0 (96.4250F) +#define D50_Y0 (100.0F) +#define D50_Z0 (82.4680F) + +/* Structure for holding information about a display device. */ + +typedef unsigned char TIFFRGBValue; /* 8-bit samples */ + +typedef struct { + float d_mat[3][3]; /* XYZ -> luminance matrix */ + float d_YCR; /* Light o/p for reference white */ + float d_YCG; + float d_YCB; + uint32 d_Vrwr; /* Pixel values for ref. white */ + uint32 d_Vrwg; + uint32 d_Vrwb; + float d_Y0R; /* Residual light for black pixel */ + float d_Y0G; + float d_Y0B; + float d_gammaR; /* Gamma values for the three guns */ + float d_gammaG; + float d_gammaB; +} TIFFDisplay; + +typedef struct { /* YCbCr->RGB support */ + TIFFRGBValue* clamptab; /* range clamping table */ + int* Cr_r_tab; + int* Cb_b_tab; + int32* Cr_g_tab; + int32* Cb_g_tab; + int32* Y_tab; +} TIFFYCbCrToRGB; + +typedef struct { /* CIE Lab 1976->RGB support */ + int range; /* Size of conversion table */ +#define CIELABTORGB_TABLE_RANGE 1500 + float rstep, gstep, bstep; + float X0, Y0, Z0; /* Reference white point */ + TIFFDisplay display; + float Yr2r[CIELABTORGB_TABLE_RANGE + 1]; /* Conversion of Yr to r */ + float Yg2g[CIELABTORGB_TABLE_RANGE + 1]; /* Conversion of Yg to g */ + float Yb2b[CIELABTORGB_TABLE_RANGE + 1]; /* Conversion of Yb to b */ +} TIFFCIELabToRGB; + +/* + * RGBA-style image support. + */ +typedef struct _TIFFRGBAImage TIFFRGBAImage; +/* + * The image reading and conversion routines invoke + * ``put routines'' to copy/image/whatever tiles of + * raw image data. A default set of routines are + * provided to convert/copy raw image data to 8-bit + * packed ABGR format rasters. Applications can supply + * alternate routines that unpack the data into a + * different format or, for example, unpack the data + * and draw the unpacked raster on the display. + */ +typedef void (*tileContigRoutine) + (TIFFRGBAImage*, uint32*, uint32, uint32, uint32, uint32, int32, int32, + unsigned char*); +typedef void (*tileSeparateRoutine) + (TIFFRGBAImage*, uint32*, uint32, uint32, uint32, uint32, int32, int32, + unsigned char*, unsigned char*, unsigned char*, unsigned char*); +/* + * RGBA-reader state. + */ +struct _TIFFRGBAImage { + TIFF* tif; /* image handle */ + int stoponerr; /* stop on read error */ + int isContig; /* data is packed/separate */ + int alpha; /* type of alpha data present */ + uint32 width; /* image width */ + uint32 height; /* image height */ + uint16 bitspersample; /* image bits/sample */ + uint16 samplesperpixel; /* image samples/pixel */ + uint16 orientation; /* image orientation */ + uint16 req_orientation; /* requested orientation */ + uint16 photometric; /* image photometric interp */ + uint16* redcmap; /* colormap pallete */ + uint16* greencmap; + uint16* bluecmap; + /* get image data routine */ + int (*get)(TIFFRGBAImage*, uint32*, uint32, uint32); + union { + void (*any)(TIFFRGBAImage*); + tileContigRoutine contig; + tileSeparateRoutine separate; + } put; /* put decoded strip/tile */ + TIFFRGBValue* Map; /* sample mapping array */ + uint32** BWmap; /* black&white map */ + uint32** PALmap; /* palette image map */ + TIFFYCbCrToRGB* ycbcr; /* YCbCr conversion state */ + TIFFCIELabToRGB* cielab; /* CIE L*a*b conversion state */ + + int row_offset; + int col_offset; +}; + +/* + * Macros for extracting components from the + * packed ABGR form returned by TIFFReadRGBAImage. + */ +#define TIFFGetR(abgr) ((abgr) & 0xff) +#define TIFFGetG(abgr) (((abgr) >> 8) & 0xff) +#define TIFFGetB(abgr) (((abgr) >> 16) & 0xff) +#define TIFFGetA(abgr) (((abgr) >> 24) & 0xff) + +/* + * A CODEC is a software package that implements decoding, + * encoding, or decoding+encoding of a compression algorithm. + * The library provides a collection of builtin codecs. + * More codecs may be registered through calls to the library + * and/or the builtin implementations may be overridden. + */ +typedef int (*TIFFInitMethod)(TIFF*, int); +typedef struct { + char* name; + uint16 scheme; + TIFFInitMethod init; +} TIFFCodec; + +#include +#include + +/* share internal LogLuv conversion routines? */ +#ifndef LOGLUV_PUBLIC +#define LOGLUV_PUBLIC 1 +#endif + +#if defined(c_plusplus) || defined(__cplusplus) +extern "C" { +#endif +typedef void (*TIFFErrorHandler)(const char*, const char*, va_list); +typedef void (*TIFFErrorHandlerExt)(thandle_t, const char*, const char*, va_list); +typedef tsize_t (*TIFFReadWriteProc)(thandle_t, tdata_t, tsize_t); +typedef toff_t (*TIFFSeekProc)(thandle_t, toff_t, int); +typedef int (*TIFFCloseProc)(thandle_t); +typedef toff_t (*TIFFSizeProc)(thandle_t); +typedef int (*TIFFMapFileProc)(thandle_t, tdata_t*, toff_t*); +typedef void (*TIFFUnmapFileProc)(thandle_t, tdata_t, toff_t); +typedef void (*TIFFExtendProc)(TIFF*); + +extern const char* TIFFGetVersion(void); + +extern const TIFFCodec* TIFFFindCODEC(uint16); +extern TIFFCodec* TIFFRegisterCODEC(uint16, const char*, TIFFInitMethod); +extern void TIFFUnRegisterCODEC(TIFFCodec*); +extern int TIFFIsCODECConfigured(uint16); +extern TIFFCodec* TIFFGetConfiguredCODECs(void); + +/* + * Auxiliary functions. + */ + +extern tdata_t _TIFFmalloc(tsize_t); +extern tdata_t _TIFFrealloc(tdata_t, tsize_t); +extern void _TIFFmemset(tdata_t, int, tsize_t); +extern void _TIFFmemcpy(tdata_t, const tdata_t, tsize_t); +extern int _TIFFmemcmp(const tdata_t, const tdata_t, tsize_t); +extern void _TIFFfree(tdata_t); + +/* +** Stuff, related to tag handling and creating custom tags. +*/ +extern int TIFFGetTagListCount( TIFF * ); +extern ttag_t TIFFGetTagListEntry( TIFF *, int tag_index ); + +#define TIFF_ANY TIFF_NOTYPE /* for field descriptor searching */ +#define TIFF_VARIABLE -1 /* marker for variable length tags */ +#define TIFF_SPP -2 /* marker for SamplesPerPixel tags */ +#define TIFF_VARIABLE2 -3 /* marker for uint32 var-length tags */ + +#define FIELD_CUSTOM 65 + +typedef struct { + ttag_t field_tag; /* field's tag */ + short field_readcount; /* read count/TIFF_VARIABLE/TIFF_SPP */ + short field_writecount; /* write count/TIFF_VARIABLE */ + TIFFDataType field_type; /* type of associated data */ + unsigned short field_bit; /* bit in fieldsset bit vector */ + unsigned char field_oktochange; /* if true, can change while writing */ + unsigned char field_passcount; /* if true, pass dir count on set */ + char *field_name; /* ASCII name */ +} TIFFFieldInfo; + +typedef struct _TIFFTagValue { + const TIFFFieldInfo *info; + int count; + void *value; +} TIFFTagValue; + +extern void TIFFMergeFieldInfo(TIFF*, const TIFFFieldInfo[], int); +extern const TIFFFieldInfo* TIFFFindFieldInfo(TIFF*, ttag_t, TIFFDataType); +extern const TIFFFieldInfo* TIFFFindFieldInfoByName(TIFF* , const char *, + TIFFDataType); +extern const TIFFFieldInfo* TIFFFieldWithTag(TIFF*, ttag_t); +extern const TIFFFieldInfo* TIFFFieldWithName(TIFF*, const char *); + +typedef int (*TIFFVSetMethod)(TIFF*, ttag_t, va_list); +typedef int (*TIFFVGetMethod)(TIFF*, ttag_t, va_list); +typedef void (*TIFFPrintMethod)(TIFF*, FILE*, long); + +typedef struct { + TIFFVSetMethod vsetfield; /* tag set routine */ + TIFFVGetMethod vgetfield; /* tag get routine */ + TIFFPrintMethod printdir; /* directory print routine */ +} TIFFTagMethods; + +extern TIFFTagMethods *TIFFAccessTagMethods( TIFF * ); +extern void *TIFFGetClientInfo( TIFF *, const char * ); +extern void TIFFSetClientInfo( TIFF *, void *, const char * ); + +extern void TIFFCleanup(TIFF*); +extern void TIFFClose(TIFF*); +extern int TIFFFlush(TIFF*); +extern int TIFFFlushData(TIFF*); +extern int TIFFGetField(TIFF*, ttag_t, ...); +extern int TIFFVGetField(TIFF*, ttag_t, va_list); +extern int TIFFGetFieldDefaulted(TIFF*, ttag_t, ...); +extern int TIFFVGetFieldDefaulted(TIFF*, ttag_t, va_list); +extern int TIFFReadDirectory(TIFF*); +extern int TIFFReadCustomDirectory(TIFF*, toff_t, const TIFFFieldInfo[], + size_t); +extern int TIFFReadEXIFDirectory(TIFF*, toff_t); +extern tsize_t TIFFScanlineSize(TIFF*); +extern tsize_t TIFFRasterScanlineSize(TIFF*); +extern tsize_t TIFFStripSize(TIFF*); +extern tsize_t TIFFRawStripSize(TIFF*, tstrip_t); +extern tsize_t TIFFVStripSize(TIFF*, uint32); +extern tsize_t TIFFTileRowSize(TIFF*); +extern tsize_t TIFFTileSize(TIFF*); +extern tsize_t TIFFVTileSize(TIFF*, uint32); +extern uint32 TIFFDefaultStripSize(TIFF*, uint32); +extern void TIFFDefaultTileSize(TIFF*, uint32*, uint32*); +extern int TIFFFileno(TIFF*); +extern int TIFFSetFileno(TIFF*, int); +extern thandle_t TIFFClientdata(TIFF*); +extern thandle_t TIFFSetClientdata(TIFF*, thandle_t); +extern int TIFFGetMode(TIFF*); +extern int TIFFSetMode(TIFF*, int); +extern int TIFFIsTiled(TIFF*); +extern int TIFFIsByteSwapped(TIFF*); +extern int TIFFIsUpSampled(TIFF*); +extern int TIFFIsMSB2LSB(TIFF*); +extern int TIFFIsBigEndian(TIFF*); +extern TIFFReadWriteProc TIFFGetReadProc(TIFF*); +extern TIFFReadWriteProc TIFFGetWriteProc(TIFF*); +extern TIFFSeekProc TIFFGetSeekProc(TIFF*); +extern TIFFCloseProc TIFFGetCloseProc(TIFF*); +extern TIFFSizeProc TIFFGetSizeProc(TIFF*); +extern TIFFMapFileProc TIFFGetMapFileProc(TIFF*); +extern TIFFUnmapFileProc TIFFGetUnmapFileProc(TIFF*); +extern uint32 TIFFCurrentRow(TIFF*); +extern tdir_t TIFFCurrentDirectory(TIFF*); +extern tdir_t TIFFNumberOfDirectories(TIFF*); +extern uint32 TIFFCurrentDirOffset(TIFF*); +extern tstrip_t TIFFCurrentStrip(TIFF*); +extern ttile_t TIFFCurrentTile(TIFF*); +extern int TIFFReadBufferSetup(TIFF*, tdata_t, tsize_t); +extern int TIFFWriteBufferSetup(TIFF*, tdata_t, tsize_t); +extern int TIFFSetupStrips(TIFF *); +extern int TIFFWriteCheck(TIFF*, int, const char *); +extern void TIFFFreeDirectory(TIFF*); +extern int TIFFCreateDirectory(TIFF*); +extern int TIFFLastDirectory(TIFF*); +extern int TIFFSetDirectory(TIFF*, tdir_t); +extern int TIFFSetSubDirectory(TIFF*, uint32); +extern int TIFFUnlinkDirectory(TIFF*, tdir_t); +extern int TIFFSetField(TIFF*, ttag_t, ...); +extern int TIFFVSetField(TIFF*, ttag_t, va_list); +extern int TIFFWriteDirectory(TIFF *); +extern int TIFFCheckpointDirectory(TIFF *); +extern int TIFFRewriteDirectory(TIFF *); +extern int TIFFReassignTagToIgnore(enum TIFFIgnoreSense, int); + +#if defined(c_plusplus) || defined(__cplusplus) +extern void TIFFPrintDirectory(TIFF*, FILE*, long = 0); +extern int TIFFReadScanline(TIFF*, tdata_t, uint32, tsample_t = 0); +extern int TIFFWriteScanline(TIFF*, tdata_t, uint32, tsample_t = 0); +extern int TIFFReadRGBAImage(TIFF*, uint32, uint32, uint32*, int = 0); +extern int TIFFReadRGBAImageOriented(TIFF*, uint32, uint32, uint32*, + int = ORIENTATION_BOTLEFT, int = 0); +#else +extern void TIFFPrintDirectory(TIFF*, FILE*, long); +extern int TIFFReadScanline(TIFF*, tdata_t, uint32, tsample_t); +extern int TIFFWriteScanline(TIFF*, tdata_t, uint32, tsample_t); +extern int TIFFReadRGBAImage(TIFF*, uint32, uint32, uint32*, int); +extern int TIFFReadRGBAImageOriented(TIFF*, uint32, uint32, uint32*, int, int); +#endif + +extern int TIFFReadRGBAStrip(TIFF*, tstrip_t, uint32 * ); +extern int TIFFReadRGBATile(TIFF*, uint32, uint32, uint32 * ); +extern int TIFFRGBAImageOK(TIFF*, char [1024]); +extern int TIFFRGBAImageBegin(TIFFRGBAImage*, TIFF*, int, char [1024]); +extern int TIFFRGBAImageGet(TIFFRGBAImage*, uint32*, uint32, uint32); +extern void TIFFRGBAImageEnd(TIFFRGBAImage*); +extern TIFF* TIFFOpen(const char*, const char*); +# ifdef __WIN32__ +extern TIFF* TIFFOpenW(const wchar_t*, const char*); +# endif /* __WIN32__ */ +extern TIFF* TIFFFdOpen(int, const char*, const char*); +extern TIFF* TIFFClientOpen(const char*, const char*, + thandle_t, + TIFFReadWriteProc, TIFFReadWriteProc, + TIFFSeekProc, TIFFCloseProc, + TIFFSizeProc, + TIFFMapFileProc, TIFFUnmapFileProc); +extern const char* TIFFFileName(TIFF*); +extern const char* TIFFSetFileName(TIFF*, const char *); +extern void TIFFError(const char*, const char*, ...); +extern void TIFFErrorExt(thandle_t, const char*, const char*, ...); +extern void TIFFWarning(const char*, const char*, ...); +extern void TIFFWarningExt(thandle_t, const char*, const char*, ...); +extern TIFFErrorHandler TIFFSetErrorHandler(TIFFErrorHandler); +extern TIFFErrorHandlerExt TIFFSetErrorHandlerExt(TIFFErrorHandlerExt); +extern TIFFErrorHandler TIFFSetWarningHandler(TIFFErrorHandler); +extern TIFFErrorHandlerExt TIFFSetWarningHandlerExt(TIFFErrorHandlerExt); +extern TIFFExtendProc TIFFSetTagExtender(TIFFExtendProc); +extern ttile_t TIFFComputeTile(TIFF*, uint32, uint32, uint32, tsample_t); +extern int TIFFCheckTile(TIFF*, uint32, uint32, uint32, tsample_t); +extern ttile_t TIFFNumberOfTiles(TIFF*); +extern tsize_t TIFFReadTile(TIFF*, + tdata_t, uint32, uint32, uint32, tsample_t); +extern tsize_t TIFFWriteTile(TIFF*, + tdata_t, uint32, uint32, uint32, tsample_t); +extern tstrip_t TIFFComputeStrip(TIFF*, uint32, tsample_t); +extern tstrip_t TIFFNumberOfStrips(TIFF*); +extern tsize_t TIFFReadEncodedStrip(TIFF*, tstrip_t, tdata_t, tsize_t); +extern tsize_t TIFFReadRawStrip(TIFF*, tstrip_t, tdata_t, tsize_t); +extern tsize_t TIFFReadEncodedTile(TIFF*, ttile_t, tdata_t, tsize_t); +extern tsize_t TIFFReadRawTile(TIFF*, ttile_t, tdata_t, tsize_t); +extern tsize_t TIFFWriteEncodedStrip(TIFF*, tstrip_t, tdata_t, tsize_t); +extern tsize_t TIFFWriteRawStrip(TIFF*, tstrip_t, tdata_t, tsize_t); +extern tsize_t TIFFWriteEncodedTile(TIFF*, ttile_t, tdata_t, tsize_t); +extern tsize_t TIFFWriteRawTile(TIFF*, ttile_t, tdata_t, tsize_t); +extern int TIFFDataWidth(TIFFDataType); /* table of tag datatype widths */ +extern void TIFFSetWriteOffset(TIFF*, toff_t); +extern void TIFFSwabShort(uint16*); +extern void TIFFSwabLong(uint32*); +extern void TIFFSwabDouble(double*); +extern void TIFFSwabArrayOfShort(uint16*, unsigned long); +extern void TIFFSwabArrayOfTriples(uint8*, unsigned long); +extern void TIFFSwabArrayOfLong(uint32*, unsigned long); +extern void TIFFSwabArrayOfDouble(double*, unsigned long); +extern void TIFFReverseBits(unsigned char *, unsigned long); +extern const unsigned char* TIFFGetBitRevTable(int); + +#ifdef LOGLUV_PUBLIC +#define U_NEU 0.210526316 +#define V_NEU 0.473684211 +#define UVSCALE 410. +extern double LogL16toY(int); +extern double LogL10toY(int); +extern void XYZtoRGB24(float*, uint8*); +extern int uv_decode(double*, double*, int); +extern void LogLuv24toXYZ(uint32, float*); +extern void LogLuv32toXYZ(uint32, float*); +#if defined(c_plusplus) || defined(__cplusplus) +extern int LogL16fromY(double, int = SGILOGENCODE_NODITHER); +extern int LogL10fromY(double, int = SGILOGENCODE_NODITHER); +extern int uv_encode(double, double, int = SGILOGENCODE_NODITHER); +extern uint32 LogLuv24fromXYZ(float*, int = SGILOGENCODE_NODITHER); +extern uint32 LogLuv32fromXYZ(float*, int = SGILOGENCODE_NODITHER); +#else +extern int LogL16fromY(double, int); +extern int LogL10fromY(double, int); +extern int uv_encode(double, double, int); +extern uint32 LogLuv24fromXYZ(float*, int); +extern uint32 LogLuv32fromXYZ(float*, int); +#endif +#endif /* LOGLUV_PUBLIC */ + +extern int TIFFCIELabToRGBInit(TIFFCIELabToRGB*, TIFFDisplay *, float*); +extern void TIFFCIELabToXYZ(TIFFCIELabToRGB *, uint32, int32, int32, + float *, float *, float *); +extern void TIFFXYZToRGB(TIFFCIELabToRGB *, float, float, float, + uint32 *, uint32 *, uint32 *); + +extern int TIFFYCbCrToRGBInit(TIFFYCbCrToRGB*, float*, float*); +extern void TIFFYCbCrtoRGB(TIFFYCbCrToRGB *, uint32, int32, int32, + uint32 *, uint32 *, uint32 *); + +#if defined(c_plusplus) || defined(__cplusplus) +} +#endif + +#endif /* _TIFFIO_ */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ diff --git a/winclude/tiffiop.h b/winclude/tiffiop.h new file mode 100755 index 000000000..5e8d0dacc --- /dev/null +++ b/winclude/tiffiop.h @@ -0,0 +1,322 @@ +/* $Id: tiffiop.h,v 1.44 2005/12/21 13:05:32 joris Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _TIFFIOP_ +#define _TIFFIOP_ +/* + * ``Library-private'' definitions. + */ + +#include "tif_config.h" + +#ifdef HAVE_FCNTL_H +# include +#endif + +#ifdef HAVE_SYS_TYPES_H +# include +#endif + +#ifdef HAVE_STRING_H +# include +#endif + +#ifdef HAVE_ASSERT_H +# include +#else +# define assert(x) +#endif + +#ifdef HAVE_SEARCH_H +# include +#else +extern void *lfind(const void *, const void *, size_t *, size_t, + int (*)(const void *, const void *)); +#endif + +#include "tiffio.h" +#include "tif_dir.h" + +typedef double dblparam_t; + +#define GLOBALDATA(TYPE,NAME) extern TYPE NAME + +#define streq(a,b) (strcmp(a,b) == 0) + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +typedef struct client_info { + struct client_info *next; + void *data; + char *name; +} TIFFClientInfoLink; + +/* + * Typedefs for ``method pointers'' used internally. + */ +typedef unsigned char tidataval_t; /* internal image data value type */ +typedef tidataval_t* tidata_t; /* reference to internal image data */ + +typedef void (*TIFFVoidMethod)(TIFF*); +typedef int (*TIFFBoolMethod)(TIFF*); +typedef int (*TIFFPreMethod)(TIFF*, tsample_t); +typedef int (*TIFFCodeMethod)(TIFF*, tidata_t, tsize_t, tsample_t); +typedef int (*TIFFSeekMethod)(TIFF*, uint32); +typedef void (*TIFFPostMethod)(TIFF*, tidata_t, tsize_t); +typedef uint32 (*TIFFStripMethod)(TIFF*, uint32); +typedef void (*TIFFTileMethod)(TIFF*, uint32*, uint32*); + +struct tiff { + char* tif_name; /* name of open file */ + int tif_fd; /* open file descriptor */ + int tif_mode; /* open mode (O_*) */ + uint32 tif_flags; +#define TIFF_FILLORDER 0x0003 /* natural bit fill order for machine */ +#define TIFF_DIRTYHEADER 0x0004 /* header must be written on close */ +#define TIFF_DIRTYDIRECT 0x0008 /* current directory must be written */ +#define TIFF_BUFFERSETUP 0x0010 /* data buffers setup */ +#define TIFF_CODERSETUP 0x0020 /* encoder/decoder setup done */ +#define TIFF_BEENWRITING 0x0040 /* written 1+ scanlines to file */ +#define TIFF_SWAB 0x0080 /* byte swap file information */ +#define TIFF_NOBITREV 0x0100 /* inhibit bit reversal logic */ +#define TIFF_MYBUFFER 0x0200 /* my raw data buffer; free on close */ +#define TIFF_ISTILED 0x0400 /* file is tile, not strip- based */ +#define TIFF_MAPPED 0x0800 /* file is mapped into memory */ +#define TIFF_POSTENCODE 0x1000 /* need call to postencode routine */ +#define TIFF_INSUBIFD 0x2000 /* currently writing a subifd */ +#define TIFF_UPSAMPLED 0x4000 /* library is doing data up-sampling */ +#define TIFF_STRIPCHOP 0x8000 /* enable strip chopping support */ +#define TIFF_HEADERONLY 0x10000 /* read header only, do not process */ + /* the first directory */ + toff_t tif_diroff; /* file offset of current directory */ + toff_t tif_nextdiroff; /* file offset of following directory */ + toff_t* tif_dirlist; /* list of offsets to already seen */ + /* directories to prevent IFD looping */ + uint16 tif_dirnumber; /* number of already seen directories */ + TIFFDirectory tif_dir; /* internal rep of current directory */ + TIFFHeader tif_header; /* file's header block */ + const int* tif_typeshift; /* data type shift counts */ + const long* tif_typemask; /* data type masks */ + uint32 tif_row; /* current scanline */ + tdir_t tif_curdir; /* current directory (index) */ + tstrip_t tif_curstrip; /* current strip for read/write */ + toff_t tif_curoff; /* current offset for read/write */ + toff_t tif_dataoff; /* current offset for writing dir */ +/* SubIFD support */ + uint16 tif_nsubifd; /* remaining subifds to write */ + toff_t tif_subifdoff; /* offset for patching SubIFD link */ +/* tiling support */ + uint32 tif_col; /* current column (offset by row too) */ + ttile_t tif_curtile; /* current tile for read/write */ + tsize_t tif_tilesize; /* # of bytes in a tile */ +/* compression scheme hooks */ + int tif_decodestatus; + TIFFBoolMethod tif_setupdecode;/* called once before predecode */ + TIFFPreMethod tif_predecode; /* pre- row/strip/tile decoding */ + TIFFBoolMethod tif_setupencode;/* called once before preencode */ + int tif_encodestatus; + TIFFPreMethod tif_preencode; /* pre- row/strip/tile encoding */ + TIFFBoolMethod tif_postencode; /* post- row/strip/tile encoding */ + TIFFCodeMethod tif_decoderow; /* scanline decoding routine */ + TIFFCodeMethod tif_encoderow; /* scanline encoding routine */ + TIFFCodeMethod tif_decodestrip;/* strip decoding routine */ + TIFFCodeMethod tif_encodestrip;/* strip encoding routine */ + TIFFCodeMethod tif_decodetile; /* tile decoding routine */ + TIFFCodeMethod tif_encodetile; /* tile encoding routine */ + TIFFVoidMethod tif_close; /* cleanup-on-close routine */ + TIFFSeekMethod tif_seek; /* position within a strip routine */ + TIFFVoidMethod tif_cleanup; /* cleanup state routine */ + TIFFStripMethod tif_defstripsize;/* calculate/constrain strip size */ + TIFFTileMethod tif_deftilesize;/* calculate/constrain tile size */ + tidata_t tif_data; /* compression scheme private data */ +/* input/output buffering */ + tsize_t tif_scanlinesize;/* # of bytes in a scanline */ + tsize_t tif_scanlineskew;/* scanline skew for reading strips */ + tidata_t tif_rawdata; /* raw data buffer */ + tsize_t tif_rawdatasize;/* # of bytes in raw data buffer */ + tidata_t tif_rawcp; /* current spot in raw buffer */ + tsize_t tif_rawcc; /* bytes unread from raw buffer */ +/* memory-mapped file support */ + tidata_t tif_base; /* base of mapped file */ + toff_t tif_size; /* size of mapped file region (bytes) */ + TIFFMapFileProc tif_mapproc; /* map file method */ + TIFFUnmapFileProc tif_unmapproc;/* unmap file method */ +/* input/output callback methods */ + thandle_t tif_clientdata; /* callback parameter */ + TIFFReadWriteProc tif_readproc; /* read method */ + TIFFReadWriteProc tif_writeproc;/* write method */ + TIFFSeekProc tif_seekproc; /* lseek method */ + TIFFCloseProc tif_closeproc; /* close method */ + TIFFSizeProc tif_sizeproc; /* filesize method */ +/* post-decoding support */ + TIFFPostMethod tif_postdecode; /* post decoding routine */ +/* tag support */ + TIFFFieldInfo** tif_fieldinfo; /* sorted table of registered tags */ + size_t tif_nfields; /* # entries in registered tag table */ + const TIFFFieldInfo *tif_foundfield;/* cached pointer to already found tag */ + TIFFTagMethods tif_tagmethods; /* tag get/set/print routines */ + TIFFClientInfoLink *tif_clientinfo; /* extra client information. */ +}; + +#define isPseudoTag(t) (t > 0xffff) /* is tag value normal or pseudo */ + +#define isTiled(tif) (((tif)->tif_flags & TIFF_ISTILED) != 0) +#define isMapped(tif) (((tif)->tif_flags & TIFF_MAPPED) != 0) +#define isFillOrder(tif, o) (((tif)->tif_flags & (o)) != 0) +#define isUpSampled(tif) (((tif)->tif_flags & TIFF_UPSAMPLED) != 0) +#define TIFFReadFile(tif, buf, size) \ + ((*(tif)->tif_readproc)((tif)->tif_clientdata,buf,size)) +#define TIFFWriteFile(tif, buf, size) \ + ((*(tif)->tif_writeproc)((tif)->tif_clientdata,buf,size)) +#define TIFFSeekFile(tif, off, whence) \ + ((*(tif)->tif_seekproc)((tif)->tif_clientdata,(toff_t)(off),whence)) +#define TIFFCloseFile(tif) \ + ((*(tif)->tif_closeproc)((tif)->tif_clientdata)) +#define TIFFGetFileSize(tif) \ + ((*(tif)->tif_sizeproc)((tif)->tif_clientdata)) +#define TIFFMapFileContents(tif, paddr, psize) \ + ((*(tif)->tif_mapproc)((tif)->tif_clientdata,paddr,psize)) +#define TIFFUnmapFileContents(tif, addr, size) \ + ((*(tif)->tif_unmapproc)((tif)->tif_clientdata,addr,size)) + +/* + * Default Read/Seek/Write definitions. + */ +#ifndef ReadOK +#define ReadOK(tif, buf, size) \ + (TIFFReadFile(tif, (tdata_t) buf, (tsize_t)(size)) == (tsize_t)(size)) +#endif +#ifndef SeekOK +#define SeekOK(tif, off) \ + (TIFFSeekFile(tif, (toff_t) off, SEEK_SET) == (toff_t) off) +#endif +#ifndef WriteOK +#define WriteOK(tif, buf, size) \ + (TIFFWriteFile(tif, (tdata_t) buf, (tsize_t) size) == (tsize_t) size) +#endif + +/* NB: the uint32 casts are to silence certain ANSI-C compilers */ +#define TIFFhowmany(x, y) ((((uint32)(x))+(((uint32)(y))-1))/((uint32)(y))) +#define TIFFhowmany8(x) (((x)&0x07)?((uint32)(x)>>3)+1:(uint32)(x)>>3) +#define TIFFroundup(x, y) (TIFFhowmany(x,y)*(y)) + +#define TIFFmax(A,B) ((A)>(B)?(A):(B)) +#define TIFFmin(A,B) ((A)<(B)?(A):(B)) + +#define TIFFArrayCount(a) (sizeof (a) / sizeof ((a)[0])) + +#if defined(__cplusplus) +extern "C" { +#endif +extern int _TIFFgetMode(const char*, const char*); +extern int _TIFFNoRowEncode(TIFF*, tidata_t, tsize_t, tsample_t); +extern int _TIFFNoStripEncode(TIFF*, tidata_t, tsize_t, tsample_t); +extern int _TIFFNoTileEncode(TIFF*, tidata_t, tsize_t, tsample_t); +extern int _TIFFNoRowDecode(TIFF*, tidata_t, tsize_t, tsample_t); +extern int _TIFFNoStripDecode(TIFF*, tidata_t, tsize_t, tsample_t); +extern int _TIFFNoTileDecode(TIFF*, tidata_t, tsize_t, tsample_t); +extern void _TIFFNoPostDecode(TIFF*, tidata_t, tsize_t); +extern int _TIFFNoPreCode (TIFF*, tsample_t); +extern int _TIFFNoSeek(TIFF*, uint32); +extern void _TIFFSwab16BitData(TIFF*, tidata_t, tsize_t); +extern void _TIFFSwab24BitData(TIFF*, tidata_t, tsize_t); +extern void _TIFFSwab32BitData(TIFF*, tidata_t, tsize_t); +extern void _TIFFSwab64BitData(TIFF*, tidata_t, tsize_t); +extern int TIFFFlushData1(TIFF*); +extern int TIFFDefaultDirectory(TIFF*); +extern int TIFFSetCompressionScheme(TIFF*, int); +extern int TIFFSetDefaultCompressionState(TIFF*); +extern uint32 _TIFFDefaultStripSize(TIFF*, uint32); +extern void _TIFFDefaultTileSize(TIFF*, uint32*, uint32*); +extern int _TIFFDataSize(TIFFDataType); + +extern void _TIFFsetByteArray(void**, void*, uint32); +extern void _TIFFsetString(char**, char*); +extern void _TIFFsetShortArray(uint16**, uint16*, uint32); +extern void _TIFFsetLongArray(uint32**, uint32*, uint32); +extern void _TIFFsetFloatArray(float**, float*, uint32); +extern void _TIFFsetDoubleArray(double**, double*, uint32); + +extern void _TIFFprintAscii(FILE*, const char*); +extern void _TIFFprintAsciiTag(FILE*, const char*, const char*); + +GLOBALDATA(TIFFErrorHandler,_TIFFwarningHandler); +GLOBALDATA(TIFFErrorHandler,_TIFFerrorHandler); +GLOBALDATA(TIFFErrorHandlerExt,_TIFFwarningHandlerExt); +GLOBALDATA(TIFFErrorHandlerExt,_TIFFerrorHandlerExt); + +extern tdata_t _TIFFCheckMalloc(TIFF*, size_t, size_t, const char*); + +extern int TIFFInitDumpMode(TIFF*, int); +#ifdef PACKBITS_SUPPORT +extern int TIFFInitPackBits(TIFF*, int); +#endif +#ifdef CCITT_SUPPORT +extern int TIFFInitCCITTRLE(TIFF*, int), TIFFInitCCITTRLEW(TIFF*, int); +extern int TIFFInitCCITTFax3(TIFF*, int), TIFFInitCCITTFax4(TIFF*, int); +#endif +#ifdef THUNDER_SUPPORT +extern int TIFFInitThunderScan(TIFF*, int); +#endif +#ifdef NEXT_SUPPORT +extern int TIFFInitNeXT(TIFF*, int); +#endif +#ifdef LZW_SUPPORT +extern int TIFFInitLZW(TIFF*, int); +#endif +#ifdef OJPEG_SUPPORT +extern int TIFFInitOJPEG(TIFF*, int); +#endif +#ifdef JPEG_SUPPORT +extern int TIFFInitJPEG(TIFF*, int); +#endif +#ifdef JBIG_SUPPORT +extern int TIFFInitJBIG(TIFF*, int); +#endif +#ifdef ZIP_SUPPORT +extern int TIFFInitZIP(TIFF*, int); +#endif +#ifdef PIXARLOG_SUPPORT +extern int TIFFInitPixarLog(TIFF*, int); +#endif +#ifdef LOGLUV_SUPPORT +extern int TIFFInitSGILog(TIFF*, int); +#endif +#ifdef VMS +extern const TIFFCodec _TIFFBuiltinCODECS[]; +#else +extern TIFFCodec _TIFFBuiltinCODECS[]; +#endif + +#if defined(__cplusplus) +} +#endif +#endif /* _TIFFIOP_ */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ diff --git a/winclude/tiffvers.h b/winclude/tiffvers.h new file mode 100755 index 000000000..afefd74bb --- /dev/null +++ b/winclude/tiffvers.h @@ -0,0 +1,9 @@ +#define TIFFLIB_VERSION_STR "LIBTIFF, Version 3.8.0\nCopyright (c) 1988-1996 Sam Leffler\nCopyright (c) 1991-1996 Silicon Graphics, Inc." +/* + * This define can be used in code that requires + * compilation-related definitions specific to a + * version or versions of the library. Runtime + * version checking should be done based on the + * string returned by TIFFGetVersion. + */ +#define TIFFLIB_VERSION 20051230 diff --git a/winclude/transupp.h b/winclude/transupp.h new file mode 100755 index 000000000..f8cdb0014 --- /dev/null +++ b/winclude/transupp.h @@ -0,0 +1,135 @@ +/* + * transupp.h + * + * Copyright (C) 1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains declarations for image transformation routines and + * other utility code used by the jpegtran sample application. These are + * NOT part of the core JPEG library. But we keep these routines separate + * from jpegtran.c to ease the task of maintaining jpegtran-like programs + * that have other user interfaces. + * + * NOTE: all the routines declared here have very specific requirements + * about when they are to be executed during the reading and writing of the + * source and destination files. See the comments in transupp.c, or see + * jpegtran.c for an example of correct usage. + */ + +/* If you happen not to want the image transform support, disable it here */ +#ifndef TRANSFORMS_SUPPORTED +#define TRANSFORMS_SUPPORTED 1 /* 0 disables transform code */ +#endif + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jtransform_request_workspace jTrRequest +#define jtransform_adjust_parameters jTrAdjust +#define jtransform_execute_transformation jTrExec +#define jcopy_markers_setup jCMrkSetup +#define jcopy_markers_execute jCMrkExec +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* + * Codes for supported types of image transformations. + */ + +typedef enum { + JXFORM_NONE, /* no transformation */ + JXFORM_FLIP_H, /* horizontal flip */ + JXFORM_FLIP_V, /* vertical flip */ + JXFORM_TRANSPOSE, /* transpose across UL-to-LR axis */ + JXFORM_TRANSVERSE, /* transpose across UR-to-LL axis */ + JXFORM_ROT_90, /* 90-degree clockwise rotation */ + JXFORM_ROT_180, /* 180-degree rotation */ + JXFORM_ROT_270 /* 270-degree clockwise (or 90 ccw) */ +} JXFORM_CODE; + +/* + * Although rotating and flipping data expressed as DCT coefficients is not + * hard, there is an asymmetry in the JPEG format specification for images + * whose dimensions aren't multiples of the iMCU size. The right and bottom + * image edges are padded out to the next iMCU boundary with junk data; but + * no padding is possible at the top and left edges. If we were to flip + * the whole image including the pad data, then pad garbage would become + * visible at the top and/or left, and real pixels would disappear into the + * pad margins --- perhaps permanently, since encoders & decoders may not + * bother to preserve DCT blocks that appear to be completely outside the + * nominal image area. So, we have to exclude any partial iMCUs from the + * basic transformation. + * + * Transpose is the only transformation that can handle partial iMCUs at the + * right and bottom edges completely cleanly. flip_h can flip partial iMCUs + * at the bottom, but leaves any partial iMCUs at the right edge untouched. + * Similarly flip_v leaves any partial iMCUs at the bottom edge untouched. + * The other transforms are defined as combinations of these basic transforms + * and process edge blocks in a way that preserves the equivalence. + * + * The "trim" option causes untransformable partial iMCUs to be dropped; + * this is not strictly lossless, but it usually gives the best-looking + * result for odd-size images. Note that when this option is active, + * the expected mathematical equivalences between the transforms may not hold. + * (For example, -rot 270 -trim trims only the bottom edge, but -rot 90 -trim + * followed by -rot 180 -trim trims both edges.) + * + * We also offer a "force to grayscale" option, which simply discards the + * chrominance channels of a YCbCr image. This is lossless in the sense that + * the luminance channel is preserved exactly. It's not the same kind of + * thing as the rotate/flip transformations, but it's convenient to handle it + * as part of this package, mainly because the transformation routines have to + * be aware of the option to know how many components to work on. + */ + +typedef struct { + /* Options: set by caller */ + JXFORM_CODE transform; /* image transform operator */ + jboolean trim; /* if TRUE, trim partial MCUs as needed */ + jboolean force_grayscale; /* if TRUE, convert color image to grayscale */ + + /* Internal workspace: caller should not touch these */ + int num_components; /* # of components in workspace */ + jvirt_barray_ptr * workspace_coef_arrays; /* workspace for transformations */ +} jpeg_transform_info; + + +#if TRANSFORMS_SUPPORTED + +/* Request any required workspace */ +EXTERN(void) jtransform_request_workspace + JPP((j_decompress_ptr srcinfo, jpeg_transform_info *info)); +/* Adjust output image parameters */ +EXTERN(jvirt_barray_ptr *) jtransform_adjust_parameters + JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jpeg_transform_info *info)); +/* Execute the actual transformation, if any */ +EXTERN(void) jtransform_execute_transformation + JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jpeg_transform_info *info)); + +#endif /* TRANSFORMS_SUPPORTED */ + + +/* + * Support for copying optional markers from source to destination file. + */ + +typedef enum { + JCOPYOPT_NONE, /* copy no optional markers */ + JCOPYOPT_COMMENTS, /* copy only comment (COM) markers */ + JCOPYOPT_ALL /* copy all optional markers */ +} JCOPY_OPTION; + +#define JCOPYOPT_DEFAULT JCOPYOPT_COMMENTS /* recommended default */ + +/* Setup decompression object to save desired markers in memory */ +EXTERN(void) jcopy_markers_setup + JPP((j_decompress_ptr srcinfo, JCOPY_OPTION option)); +/* Copy markers saved in the given source object to the destination object */ +EXTERN(void) jcopy_markers_execute + JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JCOPY_OPTION option)); diff --git a/winclude/trees.h b/winclude/trees.h new file mode 100755 index 000000000..1ca868b84 --- /dev/null +++ b/winclude/trees.h @@ -0,0 +1,128 @@ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/winclude/zconf.h b/winclude/zconf.h new file mode 100755 index 000000000..f404cefa8 --- /dev/null +++ b/winclude/zconf.h @@ -0,0 +1,279 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2002 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef _ZCONF_H +#define _ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflateParams z_deflateParams +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateReset z_inflateReset +# define compress z_compress +# define compress2 z_compress2 +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table + +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) +# define WIN32 +#endif +#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386) +# ifndef __32BIT__ +# define __32BIT__ +# endif +#endif +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#if defined(MSDOS) && !defined(__32BIT__) +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32)) && !defined(STDC) +# define STDC +#endif +#if defined(__STDC__) || defined(__cplusplus) || defined(__OS2__) +# ifndef STDC +# define STDC +# endif +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Old Borland C incorrectly complains about missing returns: */ +#if defined(__BORLANDC__) && (__BORLANDC__ < 0x500) +# define NEED_DUMMY_RETURN +#endif + + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +#endif +#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__)) +# ifndef __32BIT__ +# define SMALL_MEDIUM +# define FAR _far +# endif +#endif + +/* Compile with -DZLIB_DLL for Windows DLL support */ +#if defined(ZLIB_DLL) +# if defined(_WINDOWS) || defined(WINDOWS) +# ifdef FAR +# undef FAR +# endif +# include +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR _cdecl _export +# endif +# endif +# if defined (__BORLANDC__) +# if (__BORLANDC__ >= 0x0500) && defined (WIN32) +# include +# define ZEXPORT __declspec(dllexport) WINAPI +# define ZEXPORTRVA __declspec(dllexport) WINAPIV +# else +# if defined (_Windows) && defined (__DLL__) +# define ZEXPORT _export +# define ZEXPORTVA _export +# endif +# endif +# endif +#endif + +#if defined (__BEOS__) +# if defined (ZLIB_DLL) +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +#endif + +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif +#ifndef ZEXTERN +# define ZEXTERN extern +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(MACOS) && !defined(TARGET_OS_MAC) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#ifdef HAVE_UNISTD_H +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(inflate_blocks,"INBL") +# pragma map(inflate_blocks_new,"INBLNE") +# pragma map(inflate_blocks_free,"INBLFR") +# pragma map(inflate_blocks_reset,"INBLRE") +# pragma map(inflate_codes_free,"INCOFR") +# pragma map(inflate_codes,"INCO") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_flush,"INFLU") +# pragma map(inflate_mask,"INMA") +# pragma map(inflate_set_dictionary,"INSEDI2") +# pragma map(inflate_copyright,"INCOPY") +# pragma map(inflate_trees_bits,"INTRBI") +# pragma map(inflate_trees_dynamic,"INTRDY") +# pragma map(inflate_trees_fixed,"INTRFI") +# pragma map(inflate_trees_free,"INTRFR") +#endif + +#endif /* _ZCONF_H */ diff --git a/winclude/zlib.h b/winclude/zlib.h new file mode 100755 index 000000000..5979f040c --- /dev/null +++ b/winclude/zlib.h @@ -0,0 +1,893 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.1.4, March 11th, 2002 + + Copyright (C) 1995-2002 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef _ZLIB_H +#define _ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.1.4" + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: ascii or binary */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +/* Allowed flush values; see deflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_ASCII 1 +#define Z_UNKNOWN 2 +/* Possible values of the data_type field */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + the compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + 0.1% larger than avail_in plus 12 bytes. If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update data_type if it can make a good guess about + the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may some + introduce some output latency (reading input without producing any output) + except when forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much + output as possible to the output buffer. The flushing behavior of inflate is + not specified for values of the flush parameter other than Z_SYNC_FLUSH + and Z_FINISH, but the current implementation actually flushes as much output + as possible anyway. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster routine + may be used for the single inflate() call. + + If a preset dictionary is needed at this point (see inflateSetDictionary + below), inflate sets strm-adler to the adler32 checksum of the + dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise + it sets strm->adler to the adler32 checksum of all output produced + so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or + an error code as described below. At the end of the stream, inflate() + checks that its computed adler32 checksum is equal to that saved by the + compressor and returns Z_STREAM_END only if the checksum is correct. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect + adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent + (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if no progress is possible or if there was not + enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR + case, the application may then call inflateSync to look for a good + compression block. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match). Filtered data consists mostly of small values with a + somewhat random distribution. In this case, the compression algorithm is + tuned to compress them better. The effect of Z_FILTERED is to force more + Huffman coding and less string matching; it is somewhat intermediate + between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects + the compression ratio but not the correctness of the compressed output even + if it is not set appropriately. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. + + Upon return of this function, strm->adler is set to the Adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The Adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. If a compressed stream with a larger window size is given as + input, inflate() will return with the error code Z_DATA_ERROR instead of + trying to allocate a larger window. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative + memLevel). msg is set to null if there is no error message. inflateInit2 + does not perform any decompression apart from reading the zlib header if + present: this will be done by inflate(). (So next_in and avail_in may be + modified, but next_out and avail_out are unchanged.) +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate + if this call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the Adler32 value returned by this call of + inflate. The compressor and decompressor must use exactly the same + dictionary (see deflateSetDictionary). + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect Adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least 0.1% larger than + sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ + + +typedef voidp gzFile; + +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h". (See the description + of deflateInit2 for more information about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + const voidp buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); + +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running crc with the bytes buf[0..len-1] and return the updated + crc. If buf is NULL, this function returns the required initial value + for the crc. Pre- and post-conditioning (one's complement) is performed + within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) + + +#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int err)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* _ZLIB_H */ diff --git a/winclude/zutil.h b/winclude/zutil.h new file mode 100755 index 000000000..2e06fcfd3 --- /dev/null +++ b/winclude/zutil.h @@ -0,0 +1,220 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2002 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef _Z_UTIL_H +#define _Z_UTIL_H + +#include "zlib.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#ifdef MSDOS +# define OS_CODE 0x00 +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +#endif + +#ifdef WIN32 /* Window 95 & Windows NT */ +# define OS_CODE 0x0b +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0F +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) +# define fdopen(fd,type) _fdopen(fd,type) +#endif + + + /* Common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#ifdef HAVE_STRERROR + extern char *strerror OF((int)); +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + extern void zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include + extern int z_verbose; + extern void z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +typedef uLong (ZEXPORT *check_func) OF((uLong check, const Bytef *buf, + uInt len)); +voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); +void zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* _Z_UTIL_H */

    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